summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist')
-rw-r--r--src/lib/netlist/analog/nld_bjt.cpp632
-rw-r--r--src/lib/netlist/analog/nld_bjt.h2
-rw-r--r--src/lib/netlist/analog/nld_fourterm.h2
-rw-r--r--src/lib/netlist/analog/nld_mosfet.cpp488
-rw-r--r--src/lib/netlist/analog/nld_mosfet.h21
-rw-r--r--src/lib/netlist/analog/nld_opamps.cpp30
-rw-r--r--src/lib/netlist/analog/nld_opamps.h2
-rw-r--r--src/lib/netlist/analog/nld_switches.cpp49
-rw-r--r--src/lib/netlist/analog/nld_switches.h2
-rw-r--r--src/lib/netlist/analog/nld_twoterm.h2
-rw-r--r--src/lib/netlist/analog/nlid_fourterm.cpp52
-rw-r--r--src/lib/netlist/analog/nlid_fourterm.h60
-rw-r--r--src/lib/netlist/analog/nlid_twoterm.cpp233
-rw-r--r--src/lib/netlist/analog/nlid_twoterm.h338
-rw-r--r--src/lib/netlist/build/makefile75
-rw-r--r--src/lib/netlist/devices/net_lib.cpp281
-rw-r--r--src/lib/netlist/devices/net_lib.h46
-rw-r--r--src/lib/netlist/devices/nld_2102A.cpp8
-rw-r--r--src/lib/netlist/devices/nld_2102A.h2
-rw-r--r--src/lib/netlist/devices/nld_2716.cpp6
-rw-r--r--src/lib/netlist/devices/nld_2716.h2
-rw-r--r--src/lib/netlist/devices/nld_4020.cpp7
-rw-r--r--src/lib/netlist/devices/nld_4020.h2
-rw-r--r--src/lib/netlist/devices/nld_4066.cpp37
-rw-r--r--src/lib/netlist/devices/nld_4066.h2
-rw-r--r--src/lib/netlist/devices/nld_4316.cpp18
-rw-r--r--src/lib/netlist/devices/nld_4316.h2
-rw-r--r--src/lib/netlist/devices/nld_74107.cpp20
-rw-r--r--src/lib/netlist/devices/nld_74107.h2
-rw-r--r--src/lib/netlist/devices/nld_74123.cpp26
-rw-r--r--src/lib/netlist/devices/nld_74123.h2
-rw-r--r--src/lib/netlist/devices/nld_74153.cpp12
-rw-r--r--src/lib/netlist/devices/nld_74153.h2
-rw-r--r--src/lib/netlist/devices/nld_74161.cpp8
-rw-r--r--src/lib/netlist/devices/nld_74161.h2
-rw-r--r--src/lib/netlist/devices/nld_74164.cpp6
-rw-r--r--src/lib/netlist/devices/nld_74164.h2
-rw-r--r--src/lib/netlist/devices/nld_74165.cpp7
-rw-r--r--src/lib/netlist/devices/nld_74165.h2
-rw-r--r--src/lib/netlist/devices/nld_74166.cpp6
-rw-r--r--src/lib/netlist/devices/nld_74166.h2
-rw-r--r--src/lib/netlist/devices/nld_74174.cpp6
-rw-r--r--src/lib/netlist/devices/nld_74174.h2
-rw-r--r--src/lib/netlist/devices/nld_74175.cpp6
-rw-r--r--src/lib/netlist/devices/nld_74175.h2
-rw-r--r--src/lib/netlist/devices/nld_74192.cpp8
-rw-r--r--src/lib/netlist/devices/nld_74192.h2
-rw-r--r--src/lib/netlist/devices/nld_74193.cpp8
-rw-r--r--src/lib/netlist/devices/nld_74193.h2
-rw-r--r--src/lib/netlist/devices/nld_74194.cpp6
-rw-r--r--src/lib/netlist/devices/nld_74194.h2
-rw-r--r--src/lib/netlist/devices/nld_74365.cpp14
-rw-r--r--src/lib/netlist/devices/nld_74365.h2
-rw-r--r--src/lib/netlist/devices/nld_7448.cpp24
-rw-r--r--src/lib/netlist/devices/nld_7448.h2
-rw-r--r--src/lib/netlist/devices/nld_7450.cpp18
-rw-r--r--src/lib/netlist/devices/nld_7450.h2
-rw-r--r--src/lib/netlist/devices/nld_7473.cpp10
-rw-r--r--src/lib/netlist/devices/nld_7473.h2
-rw-r--r--src/lib/netlist/devices/nld_7474.cpp132
-rw-r--r--src/lib/netlist/devices/nld_7474.h2
-rw-r--r--src/lib/netlist/devices/nld_7475.cpp12
-rw-r--r--src/lib/netlist/devices/nld_7475.h2
-rw-r--r--src/lib/netlist/devices/nld_7483.cpp47
-rw-r--r--src/lib/netlist/devices/nld_7483.h2
-rw-r--r--src/lib/netlist/devices/nld_7485.cpp6
-rw-r--r--src/lib/netlist/devices/nld_7485.h2
-rw-r--r--src/lib/netlist/devices/nld_7490.cpp35
-rw-r--r--src/lib/netlist/devices/nld_7490.h2
-rw-r--r--src/lib/netlist/devices/nld_7493.cpp87
-rw-r--r--src/lib/netlist/devices/nld_7493.h2
-rw-r--r--src/lib/netlist/devices/nld_7497.cpp174
-rw-r--r--src/lib/netlist/devices/nld_7497.h57
-rw-r--r--src/lib/netlist/devices/nld_74ls629.cpp19
-rw-r--r--src/lib/netlist/devices/nld_74ls629.h2
-rw-r--r--src/lib/netlist/devices/nld_82S115.cpp6
-rw-r--r--src/lib/netlist/devices/nld_82S115.h2
-rw-r--r--src/lib/netlist/devices/nld_82S123.cpp6
-rw-r--r--src/lib/netlist/devices/nld_82S123.h2
-rw-r--r--src/lib/netlist/devices/nld_82S126.cpp6
-rw-r--r--src/lib/netlist/devices/nld_82S126.h2
-rw-r--r--src/lib/netlist/devices/nld_82S16.cpp73
-rw-r--r--src/lib/netlist/devices/nld_82S16.h2
-rw-r--r--src/lib/netlist/devices/nld_9310.cpp42
-rw-r--r--src/lib/netlist/devices/nld_9310.h2
-rw-r--r--src/lib/netlist/devices/nld_9316.cpp138
-rw-r--r--src/lib/netlist/devices/nld_9316.h2
-rw-r--r--src/lib/netlist/devices/nld_9322.cpp14
-rw-r--r--src/lib/netlist/devices/nld_9322.h2
-rw-r--r--src/lib/netlist/devices/nld_am2847.cpp10
-rw-r--r--src/lib/netlist/devices/nld_am2847.h2
-rw-r--r--src/lib/netlist/devices/nld_dm9314.cpp6
-rw-r--r--src/lib/netlist/devices/nld_dm9314.h2
-rw-r--r--src/lib/netlist/devices/nld_dm9334.cpp6
-rw-r--r--src/lib/netlist/devices/nld_dm9334.h2
-rw-r--r--src/lib/netlist/devices/nld_legacy.cpp10
-rw-r--r--src/lib/netlist/devices/nld_legacy.h2
-rw-r--r--src/lib/netlist/devices/nld_log.cpp18
-rw-r--r--src/lib/netlist/devices/nld_log.h4
-rw-r--r--src/lib/netlist/devices/nld_mm5837.cpp16
-rw-r--r--src/lib/netlist/devices/nld_mm5837.h2
-rw-r--r--src/lib/netlist/devices/nld_ne555.cpp101
-rw-r--r--src/lib/netlist/devices/nld_ne555.h8
-rw-r--r--src/lib/netlist/devices/nld_r2r_dac.cpp14
-rw-r--r--src/lib/netlist/devices/nld_r2r_dac.h2
-rw-r--r--src/lib/netlist/devices/nld_schmitt.cpp30
-rw-r--r--src/lib/netlist/devices/nld_schmitt.h2
-rw-r--r--src/lib/netlist/devices/nld_system.cpp95
-rw-r--r--src/lib/netlist/devices/nld_system.h2
-rw-r--r--src/lib/netlist/devices/nld_tms4800.cpp10
-rw-r--r--src/lib/netlist/devices/nld_tms4800.h2
-rw-r--r--src/lib/netlist/devices/nld_tristate.cpp6
-rw-r--r--src/lib/netlist/devices/nld_tristate.h2
-rw-r--r--src/lib/netlist/devices/nlid_cmos.h4
-rw-r--r--src/lib/netlist/devices/nlid_proxy.cpp54
-rw-r--r--src/lib/netlist/devices/nlid_proxy.h24
-rw-r--r--src/lib/netlist/devices/nlid_system.h92
-rw-r--r--src/lib/netlist/devices/nlid_truthtable.cpp141
-rw-r--r--src/lib/netlist/devices/nlid_truthtable.h175
-rw-r--r--src/lib/netlist/macro/nlm_base.cpp39
-rw-r--r--src/lib/netlist/macro/nlm_base.h2
-rw-r--r--src/lib/netlist/macro/nlm_cd4xxx.cpp8
-rw-r--r--src/lib/netlist/macro/nlm_cd4xxx.h2
-rw-r--r--src/lib/netlist/macro/nlm_opamp.cpp2
-rw-r--r--src/lib/netlist/macro/nlm_opamp.h2
-rw-r--r--src/lib/netlist/macro/nlm_other.cpp2
-rw-r--r--src/lib/netlist/macro/nlm_other.h2
-rw-r--r--src/lib/netlist/macro/nlm_ttl74xx.cpp9
-rw-r--r--src/lib/netlist/macro/nlm_ttl74xx.h2
-rw-r--r--src/lib/netlist/netlist_types.h54
-rw-r--r--src/lib/netlist/nl_base.cpp765
-rw-r--r--src/lib/netlist/nl_base.h1307
-rw-r--r--src/lib/netlist/nl_config.h46
-rw-r--r--src/lib/netlist/nl_dice_compat.h17
-rw-r--r--src/lib/netlist/nl_errstr.h3
-rw-r--r--src/lib/netlist/nl_factory.cpp140
-rw-r--r--src/lib/netlist/nl_factory.h87
-rw-r--r--src/lib/netlist/nl_lists.h163
-rw-r--r--src/lib/netlist/nl_parser.cpp43
-rw-r--r--src/lib/netlist/nl_parser.h18
-rw-r--r--src/lib/netlist/nl_setup.cpp838
-rw-r--r--src/lib/netlist/nl_setup.h309
-rw-r--r--src/lib/netlist/nl_time.h145
-rw-r--r--src/lib/netlist/nltypes.h147
-rw-r--r--src/lib/netlist/plib/gmres.h450
-rw-r--r--src/lib/netlist/plib/mat_cr.h530
-rw-r--r--src/lib/netlist/plib/palloc.cpp105
-rw-r--r--src/lib/netlist/plib/palloc.h513
-rw-r--r--src/lib/netlist/plib/parray.h126
-rw-r--r--src/lib/netlist/plib/pchrono.cpp4
-rw-r--r--src/lib/netlist/plib/pchrono.h52
-rw-r--r--src/lib/netlist/plib/pconfig.h51
-rw-r--r--src/lib/netlist/plib/pdynlib.cpp18
-rw-r--r--src/lib/netlist/plib/pdynlib.h15
-rw-r--r--src/lib/netlist/plib/pexception.cpp215
-rw-r--r--src/lib/netlist/plib/pexception.h214
-rw-r--r--src/lib/netlist/plib/pfmtlog.cpp121
-rw-r--r--src/lib/netlist/plib/pfmtlog.h50
-rw-r--r--src/lib/netlist/plib/pfunction.cpp32
-rw-r--r--src/lib/netlist/plib/pfunction.h4
-rw-r--r--src/lib/netlist/plib/plists.h122
-rw-r--r--src/lib/netlist/plib/pmain.cpp13
-rw-r--r--src/lib/netlist/plib/pmain.h20
-rw-r--r--src/lib/netlist/plib/pmatrix2d.h85
-rw-r--r--src/lib/netlist/plib/pmempool.h187
-rw-r--r--src/lib/netlist/plib/pomp.h28
-rw-r--r--src/lib/netlist/plib/poptions.cpp154
-rw-r--r--src/lib/netlist/plib/poptions.h161
-rw-r--r--src/lib/netlist/plib/pparser.cpp278
-rw-r--r--src/lib/netlist/plib/pparser.h107
-rw-r--r--src/lib/netlist/plib/ppmf.h28
-rw-r--r--src/lib/netlist/plib/pstate.cpp35
-rw-r--r--src/lib/netlist/plib/pstate.h67
-rw-r--r--src/lib/netlist/plib/pstream.cpp131
-rw-r--r--src/lib/netlist/plib/pstream.h408
-rw-r--r--src/lib/netlist/plib/pstring.cpp131
-rw-r--r--src/lib/netlist/plib/pstring.h457
-rw-r--r--src/lib/netlist/plib/ptime.h136
-rw-r--r--src/lib/netlist/plib/ptypes.h124
-rw-r--r--src/lib/netlist/plib/putil.cpp75
-rw-r--r--src/lib/netlist/plib/putil.h103
-rw-r--r--src/lib/netlist/plib/vector_ops.h151
-rw-r--r--src/lib/netlist/prg/nltool.cpp374
-rw-r--r--src/lib/netlist/prg/nlwav.cpp591
-rw-r--r--src/lib/netlist/solver/mat_cr.h175
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.cpp937
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.h471
-rw-r--r--src/lib/netlist/solver/nld_ms_direct.h386
-rw-r--r--src/lib/netlist/solver/nld_ms_direct1.h50
-rw-r--r--src/lib/netlist/solver/nld_ms_direct2.h59
-rw-r--r--src/lib/netlist/solver/nld_ms_direct_lu.h26
-rw-r--r--src/lib/netlist/solver/nld_ms_gcr.h562
-rw-r--r--src/lib/netlist/solver/nld_ms_gmres.h412
-rw-r--r--src/lib/netlist/solver/nld_ms_sm.h416
-rw-r--r--src/lib/netlist/solver/nld_ms_sor.h112
-rw-r--r--src/lib/netlist/solver/nld_ms_sor_mat.h338
-rw-r--r--src/lib/netlist/solver/nld_ms_w.h165
-rw-r--r--src/lib/netlist/solver/nld_solver.cpp641
-rw-r--r--src/lib/netlist/solver/nld_solver.h178
-rw-r--r--src/lib/netlist/solver/vector_base.h144
-rw-r--r--src/lib/netlist/tools/nl_convert.cpp117
-rw-r--r--src/lib/netlist/tools/nl_convert.h69
202 files changed, 11668 insertions, 8552 deletions
diff --git a/src/lib/netlist/analog/nld_bjt.cpp b/src/lib/netlist/analog/nld_bjt.cpp
index 6f4a2db86bf..aef920635fe 100644
--- a/src/lib/netlist/analog/nld_bjt.cpp
+++ b/src/lib/netlist/analog/nld_bjt.cpp
@@ -5,47 +5,49 @@
*
*/
-#include "../solver/nld_solver.h"
+#include "netlist/solver/nld_solver.h"
+#include "netlist/nl_setup.h"
#include "nlid_twoterm.h"
-#include "../nl_setup.h"
+
#include <cmath>
namespace netlist
{
- namespace analog
- {
-
-class diode
+namespace analog
{
-public:
- diode() : m_Is(1e-15), m_VT(0.0258), m_VT_inv(1.0 / m_VT) {}
- diode(const nl_double Is, const nl_double n)
- {
- m_Is = Is;
- m_VT = 0.0258 * n;
- m_VT_inv = 1.0 / m_VT;
- }
- void set(const nl_double Is, const nl_double n)
- {
- m_Is = Is;
- m_VT = 0.0258 * n;
- m_VT_inv = 1.0 / m_VT;
- }
- nl_double I(const nl_double V) const { return m_Is * std::exp(V * m_VT_inv) - m_Is; }
- nl_double g(const nl_double V) const { return m_Is * m_VT_inv * std::exp(V * m_VT_inv); }
- nl_double V(const nl_double I) const { return std::log1p(I / m_Is) * m_VT; } // log1p(x)=log(1.0 + x)
- nl_double gI(const nl_double I) const { return m_VT_inv * (I + m_Is); }
+ using constants = plib::constants<nl_double>;
-private:
- nl_double m_Is;
- nl_double m_VT;
- nl_double m_VT_inv;
-};
+ class diode
+ {
+ public:
+ diode() : m_Is(1e-15), m_VT(0.0258), m_VT_inv(1.0 / m_VT) {}
+ diode(const nl_double Is, const nl_double n)
+ {
+ m_Is = Is;
+ m_VT = 0.0258 * n;
+ m_VT_inv = 1.0 / m_VT;
+ }
+ void set(const nl_double Is, const nl_double n)
+ {
+ m_Is = Is;
+ m_VT = 0.0258 * n;
+ m_VT_inv = 1.0 / m_VT;
+ }
+ nl_double I(const nl_double V) const { return m_Is * std::exp(V * m_VT_inv) - m_Is; }
+ nl_double g(const nl_double V) const { return m_Is * m_VT_inv * std::exp(V * m_VT_inv); }
+ nl_double V(const nl_double I) const { return std::log1p(I / m_Is) * m_VT; } // log1p(x)=log(1.0 + x)
+ nl_double gI(const nl_double I) const { return m_VT_inv * (I + m_Is); }
+
+ private:
+ nl_double m_Is;
+ nl_double m_VT;
+ nl_double m_VT_inv;
+ };
-// -----------------------------------------------------------------------------
-// nld_Q - Base classes
-// -----------------------------------------------------------------------------
+ // -----------------------------------------------------------------------------
+ // nld_Q - Base classes
+ // -----------------------------------------------------------------------------
/*! Class representing the bjt model paramers.
*
@@ -73,7 +75,7 @@ private:
* | | RBM | minimum base resistance at high currents | | RB | 10 | * |
* | | RE | emitter resistance | | 0 | 1 | * |
* | | RC | collector resistance | | 0 | 10 | * |
- * | | CJE | B-E zero-bias depletion capacitance | F | 0 | 2pF | * |
+ * | Y | CJE | B-E zero-bias depletion capacitance | F | 0 | 2pF | * |
* | | VJE | B-E built-in potential | V | 0.75 | 0.6 | |
* | | MJE | B-E junction exponential factor | - | 0.33 | 0.33 | |
* | | TF | ideal forward transit time | sec | 0 | 0.1ns | |
@@ -81,7 +83,7 @@ private:
* | | VTF | voltage describing VBC dependence of TF | V | infinite | | |
* | | ITF | high-current parameter for effect on TF | A | 0 | | * |
* | | PTF | excess phase at freq=1.0/(TF*2PI) Hz | deg | 0 | | |
- * | | CJC | B-C zero-bias depletion capacitance | F | 0 | 2pF | * |
+ * | Y | CJC | B-C zero-bias depletion capacitance | F | 0 | 2pF | * |
* | | VJC | B-C built-in potential | V | 0.75 | 0.5 | |
* | | MJC | B-C junction exponential factor | - | 0.33 | 0.5 | |
* | | XCJC | fraction of B-C depletion capacitance connected to internal base node | - | 1 | | |
@@ -95,343 +97,369 @@ private:
* | | KF | flicker-noise coefficient | - | 0 | | |
* | | AF | flicker-noise exponent | - | 1 | | |
* | | FC | coefficient for forward-bias depletion capacitance formula | - | 0.5 | | |
- * | | TNOM | Parameter measurement temperature | C | 27 | 50 | | */
+ * | | TNOM | Parameter measurement temperature | C | 27 | 50 | |
+ * */
class bjt_model_t : public param_model_t
{
public:
bjt_model_t(device_t &device, const pstring &name, const pstring &val)
: param_model_t(device, name, val)
- , m_IS(*this, "IS")
- , m_BF(*this, "BF")
- , m_NF(*this, "NF")
- , m_BR(*this, "BR")
- , m_NR(*this, "NR")
+ , m_IS (*this, "IS")
+ , m_BF (*this, "BF")
+ , m_NF (*this, "NF")
+ , m_BR (*this, "BR")
+ , m_NR (*this, "NR")
+ , m_CJE(*this, "CJE")
+ , m_CJC(*this, "CJC")
{}
- value_t m_IS; //!< transport saturation current
- value_t m_BF; //!< ideal maximum forward beta
- value_t m_NF; //!< forward current emission coefficient
- value_t m_BR; //!< ideal maximum reverse beta
- value_t m_NR; //!< reverse current emission coefficient
+ value_t m_IS; //!< transport saturation current
+ value_t m_BF; //!< ideal maximum forward beta
+ value_t m_NF; //!< forward current emission coefficient
+ value_t m_BR; //!< ideal maximum reverse beta
+ value_t m_NR; //!< reverse current emission coefficient
+ value_t m_CJE; //!< B-E zero-bias depletion capacitance
+ value_t m_CJC; //!< B-C zero-bias depletion capacitance
+
};
// Have a common start for transistors
-NETLIB_OBJECT(Q)
-{
-public:
- enum q_type {
- BJT_NPN,
- BJT_PNP
+ NETLIB_OBJECT(Q)
+ {
+ public:
+ enum q_type {
+ BJT_NPN,
+ BJT_PNP
+ };
+
+ NETLIB_CONSTRUCTOR(Q)
+ , m_model(*this, "MODEL", "NPN")
+ , m_qtype(BJT_NPN)
+ {
+ }
+
+ 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:
+
+ bjt_model_t m_model;
+ private:
+ q_type m_qtype;
};
- NETLIB_CONSTRUCTOR(Q)
- , m_model(*this, "MODEL", "NPN")
- , m_qtype(BJT_NPN)
+ NETLIB_OBJECT_DERIVED(QBJT, Q)
{
- }
-
- NETLIB_IS_DYNAMIC(true)
-
- //NETLIB_RESETI();
- NETLIB_UPDATEI();
+ public:
+ NETLIB_CONSTRUCTOR_DERIVED(QBJT, Q)
+ { }
- inline q_type qtype() const { return m_qtype; }
- inline bool is_qtype(q_type atype) const { return m_qtype == atype; }
- inline void set_qtype(q_type atype) { m_qtype = atype; }
-protected:
+ protected:
- bjt_model_t m_model;
-private:
- q_type m_qtype;
-};
+ private:
+ };
-NETLIB_OBJECT_DERIVED(QBJT, Q)
-{
-public:
- NETLIB_CONSTRUCTOR_DERIVED(QBJT, Q)
- { }
-protected:
-private:
-};
+ // -----------------------------------------------------------------------------
+ // nld_QBJT_switch
+ // -----------------------------------------------------------------------------
+ /*
+ * + - C
+ * B ----VVV----+ |
+ * | |
+ * Rb Rc
+ * Rb Rc
+ * Rb Rc
+ * | |
+ * +----+----+
+ * |
+ * E
+ */
-// -----------------------------------------------------------------------------
-// nld_QBJT_switch
-// -----------------------------------------------------------------------------
+ NETLIB_OBJECT_DERIVED(QBJT_switch, QBJT)
+ {
+ NETLIB_CONSTRUCTOR_DERIVED(QBJT_switch, QBJT)
+ , m_RB(*this, "m_RB", true)
+ , m_RC(*this, "m_RC", true)
+ , m_BC_dummy(*this, "m_BC", true)
+ , m_gB(1e-9)
+ , m_gC(1e-9)
+ , m_V(0.0)
+ , m_state_on(*this, "m_state_on", 0)
+ {
+ register_subalias("B", m_RB.m_P);
+ register_subalias("E", m_RB.m_N);
+ register_subalias("C", m_RC.m_P);
+ //register_term("_E1", m_RC.m_N);
+
+ //register_term("_B1", m_BC_dummy.m_P);
+ //register_term("_C1", m_BC_dummy.m_N);
+
+ connect(m_RB.m_N, m_RC.m_N);
+
+ connect(m_RB.m_P, m_BC_dummy.m_P);
+ connect(m_RC.m_P, m_BC_dummy.m_N);
+ }
+
+ NETLIB_RESETI();
+ NETLIB_UPDATEI();
+ NETLIB_UPDATE_PARAMI();
+ NETLIB_UPDATE_TERMINALSI();
+
+ private:
+ nld_twoterm m_RB;
+ nld_twoterm m_RC;
+
+ // FIXME: this is needed so we have all terminals belong to one net list
+
+ nld_twoterm m_BC_dummy;
+
+ nl_double m_gB; // base conductance / switch on
+ nl_double m_gC; // collector conductance / switch on
+ nl_double m_V; // internal voltage source
+ state_var<unsigned> m_state_on;
+
+ private:
+ };
+ // -----------------------------------------------------------------------------
+ // nld_QBJT_EB
+ // -----------------------------------------------------------------------------
-/*
- * + - C
- * B ----VVV----+ |
- * | |
- * Rb Rc
- * Rb Rc
- * Rb Rc
- * | |
- * +----+----+
- * |
- * E
- */
-NETLIB_OBJECT_DERIVED(QBJT_switch, QBJT)
-{
- NETLIB_CONSTRUCTOR_DERIVED(QBJT_switch, QBJT)
- , m_RB(*this, "m_RB", true)
- , m_RC(*this, "m_RC", true)
- , m_BC_dummy(*this, "m_BC", true)
- , m_gB(NETLIST_GMIN_DEFAULT)
- , m_gC(NETLIST_GMIN_DEFAULT)
- , m_V(0.0)
- , m_state_on(*this, "m_state_on", 0)
+ NETLIB_OBJECT_DERIVED(QBJT_EB, QBJT)
{
- register_subalias("B", m_RB.m_P);
- register_subalias("E", m_RB.m_N);
- register_subalias("C", m_RC.m_P);
- //register_term("_E1", m_RC.m_N);
+ public:
+ NETLIB_CONSTRUCTOR_DERIVED(QBJT_EB, QBJT)
+ , m_gD_BC(*this, "m_D_BC")
+ , m_gD_BE(*this, "m_D_BE")
+ , m_D_CB(*this, "m_D_CB", true)
+ , m_D_EB(*this, "m_D_EB", true)
+ , m_D_EC(*this, "m_D_EC", true)
+ , m_alpha_f(0)
+ , m_alpha_r(0)
+ {
+ register_subalias("E", m_D_EB.m_P); // Cathode
+ register_subalias("B", m_D_EB.m_N); // Anode
+
+ register_subalias("C", m_D_CB.m_P); // Cathode
+
+ connect(m_D_EB.m_P, m_D_EC.m_P);
+ connect(m_D_EB.m_N, m_D_CB.m_N);
+ connect(m_D_CB.m_P, m_D_EC.m_N);
+
+ if (m_model.m_CJE > 0.0)
+ {
+ create_and_register_subdevice("m_CJE", m_CJE);
+ connect("B", "m_CJE.1");
+ connect("E", "m_CJE.2");
+ }
+ if (m_model.m_CJC > 0.0)
+ {
+ create_and_register_subdevice("m_CJC", m_CJC);
+ connect("B", "m_CJC.1");
+ connect("C", "m_CJC.2");
+ }
+ }
+
+ protected:
+
+ NETLIB_RESETI();
+ NETLIB_UPDATEI();
+ NETLIB_UPDATE_PARAMI();
+ NETLIB_UPDATE_TERMINALSI();
+
+ private:
+ generic_diode<diode_e::BIPOLAR> m_gD_BC;
+ generic_diode<diode_e::BIPOLAR> m_gD_BE;
+
+ nld_twoterm m_D_CB; // gcc, gce - gcc, gec - gcc, gcc - gce | Ic
+ nld_twoterm m_D_EB; // gee, gec - gee, gce - gee, gee - gec | Ie
+ nld_twoterm m_D_EC; // 0, -gec, -gcc, 0 | 0
+
+ nl_double m_alpha_f;
+ nl_double m_alpha_r;
+
+ NETLIB_SUBXX(analog, C) m_CJE;
+ NETLIB_SUBXX(analog, C) m_CJC;
+ };
- //register_term("_B1", m_BC_dummy.m_P);
- //register_term("_C1", m_BC_dummy.m_N);
- connect(m_RB.m_N, m_RC.m_N);
+ // ----------------------------------------------------------------------------------------
+ // nld_Q
+ // ----------------------------------------------------------------------------------------
- connect(m_RB.m_P, m_BC_dummy.m_P);
- connect(m_RC.m_P, m_BC_dummy.m_N);
+ NETLIB_UPDATE(Q)
+ {
+ // netlist().solver()->schedule1();
}
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- NETLIB_UPDATE_PARAMI();
- NETLIB_UPDATE_TERMINALSI();
-
- nld_twoterm m_RB;
- nld_twoterm m_RC;
-
- // FIXME: this is needed so we have all terminals belong to one net list
+ // ----------------------------------------------------------------------------------------
+ // nld_QBJT_switch
+ // ----------------------------------------------------------------------------------------
- nld_twoterm m_BC_dummy;
-
-protected:
+ NETLIB_RESET(QBJT_switch)
+ {
+ NETLIB_NAME(Q)::reset();
- nl_double m_gB; // base conductance / switch on
- nl_double m_gC; // collector conductance / switch on
- nl_double m_V; // internal voltage source
- state_var<unsigned> m_state_on;
+ m_state_on = 0;
-private:
-};
+ m_RB.set_G_V_I(exec().gmin(), 0.0, 0.0);
+ m_RC.set_G_V_I(exec().gmin(), 0.0, 0.0);
-// -----------------------------------------------------------------------------
-// nld_QBJT_EB
-// -----------------------------------------------------------------------------
+ m_BC_dummy.set_G_V_I(exec().gmin() / 10.0, 0.0, 0.0);
+ }
-NETLIB_OBJECT_DERIVED(QBJT_EB, QBJT)
-{
-public:
- NETLIB_CONSTRUCTOR_DERIVED(QBJT_EB, QBJT)
- , m_gD_BC(*this, "m_D_BC")
- , m_gD_BE(*this, "m_D_BE")
- , m_D_CB(*this, "m_D_CB", true)
- , m_D_EB(*this, "m_D_EB", true)
- , m_D_EC(*this, "m_D_EC", true)
- , m_alpha_f(0)
- , m_alpha_r(0)
+ NETLIB_UPDATE(QBJT_switch)
{
- register_subalias("E", m_D_EB.m_P); // Cathode
- register_subalias("B", m_D_EB.m_N); // Anode
-
- register_subalias("C", m_D_CB.m_P); // Cathode
- //register_term("_B1", m_D_CB.m_N); // Anode
-
- //register_term("_E1", m_D_EC.m_P);
- //register_term("_C1", m_D_EC.m_N);
-
- connect(m_D_EB.m_P, m_D_EC.m_P);
- connect(m_D_EB.m_N, m_D_CB.m_N);
- connect(m_D_CB.m_P, m_D_EC.m_N);
+ if (!m_RB.m_P.net().isRailNet())
+ m_RB.m_P.solve_now(); // Basis
+ else if (!m_RB.m_N.net().isRailNet())
+ m_RB.m_N.solve_now(); // Emitter
+ else if (!m_RC.m_P.net().isRailNet())
+ m_RC.m_P.solve_now(); // Collector
}
-protected:
-
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- NETLIB_UPDATE_PARAMI();
- NETLIB_UPDATE_TERMINALSI();
-
- generic_diode m_gD_BC;
- generic_diode m_gD_BE;
-
-private:
- nld_twoterm m_D_CB; // gcc, gce - gcc, gec - gcc, gcc - gce | Ic
- nld_twoterm m_D_EB; // gee, gec - gee, gce - gee, gee - gec | Ie
- nld_twoterm m_D_EC; // 0, -gec, -gcc, 0 | 0
-
- nl_double m_alpha_f;
- nl_double m_alpha_r;
-
-};
-
-
-// ----------------------------------------------------------------------------------------
-// nld_Q
-// ----------------------------------------------------------------------------------------
-
-NETLIB_UPDATE(Q)
-{
-// netlist().solver()->schedule1();
-}
-
-// ----------------------------------------------------------------------------------------
-// nld_QBJT_switch
-// ----------------------------------------------------------------------------------------
-
-
-NETLIB_RESET(QBJT_switch)
-{
- NETLIB_NAME(Q)::reset();
- m_state_on = 0;
-
- m_RB.set(netlist().gmin(), 0.0, 0.0);
- m_RC.set(netlist().gmin(), 0.0, 0.0);
-
- m_BC_dummy.set(netlist().gmin() / 10.0, 0.0, 0.0);
-
-}
+ NETLIB_UPDATE_PARAM(QBJT_switch)
+ {
+ nl_double IS = m_model.m_IS;
+ nl_double BF = m_model.m_BF;
+ nl_double NF = m_model.m_NF;
+ //nl_double VJE = m_model.dValue("VJE", 0.75);
-NETLIB_UPDATE(QBJT_switch)
-{
- if (!m_RB.m_P.net().isRailNet())
- m_RB.m_P.solve_now(); // Basis
- else if (!m_RB.m_N.net().isRailNet())
- m_RB.m_N.solve_now(); // Emitter
- else if (!m_RC.m_P.net().isRailNet())
- m_RC.m_P.solve_now(); // Collector
-}
+ set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
+ nl_double alpha = BF / (1.0 + BF);
-NETLIB_UPDATE_PARAM(QBJT_switch)
-{
- nl_double IS = m_model.m_IS;
- nl_double BF = m_model.m_BF;
- nl_double NF = m_model.m_NF;
- //nl_double VJE = m_model.dValue("VJE", 0.75);
+ diode d(IS, NF);
- set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
+ // Assume 5mA Collector current for switch operation
- nl_double alpha = BF / (1.0 + BF);
+ m_V = d.V(0.005 / alpha);
- diode d(IS, NF);
+ /* Base current is 0.005 / beta
+ * as a rough estimate, we just scale the conductance down */
- // Assume 5mA Collector current for switch operation
+ m_gB = 1.0 / (m_V/(0.005 / BF));
- m_V = d.V(0.005 / alpha);
+ //m_gB = d.gI(0.005 / alpha);
- /* Base current is 0.005 / beta
- * as a rough estimate, we just scale the conductance down */
+ if (m_gB < exec().gmin())
+ m_gB = exec().gmin();
+ m_gC = d.gI(0.005); // very rough estimate
+ }
- m_gB = 1.0 / (m_V/(0.005 / BF));
+ NETLIB_UPDATE_TERMINALS(QBJT_switch)
+ {
+ const nl_double m = (is_qtype( BJT_NPN) ? 1 : -1);
+
+ const unsigned new_state = (m_RB.deltaV() * m > m_V ) ? 1 : 0;
+ if (m_state_on ^ new_state)
+ {
+ const nl_double gb = new_state ? m_gB : exec().gmin();
+ const nl_double gc = new_state ? m_gC : exec().gmin();
+ const nl_double v = new_state ? m_V * m : 0;
+
+ m_RB.set_G_V_I(gb, v, 0.0);
+ m_RC.set_G_V_I(gc, 0.0, 0.0);
+ m_state_on = new_state;
+ }
+ }
- //m_gB = d.gI(0.005 / alpha);
- if (m_gB < netlist().gmin())
- m_gB = netlist().gmin();
- m_gC = d.gI(0.005); // very rough estimate
-}
+ // ----------------------------------------------------------------------------------------
+ // nld_Q - Ebers Moll
+ // ----------------------------------------------------------------------------------------
-NETLIB_UPDATE_TERMINALS(QBJT_switch)
-{
- const nl_double m = (is_qtype( BJT_NPN) ? 1 : -1);
- const unsigned new_state = (m_RB.deltaV() * m > m_V ) ? 1 : 0;
- if (m_state_on ^ new_state)
+ NETLIB_UPDATE(QBJT_EB)
{
- const nl_double gb = new_state ? m_gB : netlist().gmin();
- const nl_double gc = new_state ? m_gC : netlist().gmin();
- const nl_double v = new_state ? m_V * m : 0;
-
- m_RB.set(gb, v, 0.0);
- m_RC.set(gc, 0.0, 0.0);
- m_state_on = new_state;
+ if (!m_D_EB.m_P.net().isRailNet())
+ m_D_EB.m_P.solve_now(); // Basis
+ else if (!m_D_EB.m_N.net().isRailNet())
+ m_D_EB.m_N.solve_now(); // Emitter
+ else
+ m_D_CB.m_N.solve_now(); // Collector
}
-}
+ NETLIB_RESET(QBJT_EB)
+ {
+ NETLIB_NAME(Q)::reset();
+ 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);
+ }
-// ----------------------------------------------------------------------------------------
-// nld_Q - Ebers Moll
-// ----------------------------------------------------------------------------------------
+ }
+ NETLIB_UPDATE_TERMINALS(QBJT_EB)
+ {
+ const nl_double polarity = (qtype() == BJT_NPN ? 1.0 : -1.0);
+
+ m_gD_BE.update_diode(-m_D_EB.deltaV() * polarity);
+ m_gD_BC.update_diode(-m_D_CB.deltaV() * polarity);
+
+ const nl_double gee = m_gD_BE.G();
+ const nl_double gcc = m_gD_BC.G();
+ const nl_double gec = m_alpha_r * gcc;
+ const nl_double gce = m_alpha_f * gee;
+ const nl_double sIe = -m_gD_BE.I() + m_alpha_r * m_gD_BC.I();
+ const nl_double sIc = m_alpha_f * m_gD_BE.I() - m_gD_BC.I();
+ const nl_double Ie = (sIe + gee * m_gD_BE.Vd() - gec * m_gD_BC.Vd()) * polarity;
+ const nl_double Ic = (sIc - gce * m_gD_BE.Vd() + gcc * m_gD_BC.Vd()) * polarity;
+
+ m_D_EB.set_mat( gee, gec - gee, -Ie,
+ gce - gee, gee - gec, Ie);
+ m_D_CB.set_mat( gcc, gce - gcc, -Ic,
+ gec - gcc, gcc - gce, Ic);
+ m_D_EC.set_mat( 0, -gec, 0,
+ -gce, 0, 0);
+ }
-NETLIB_UPDATE(QBJT_EB)
-{
- if (!m_D_EB.m_P.net().isRailNet())
- m_D_EB.m_P.solve_now(); // Basis
- else if (!m_D_EB.m_N.net().isRailNet())
- m_D_EB.m_N.solve_now(); // Emitter
- else
- m_D_CB.m_N.solve_now(); // Collector
-}
-
-NETLIB_RESET(QBJT_EB)
-{
- NETLIB_NAME(Q)::reset();
-}
-NETLIB_UPDATE_TERMINALS(QBJT_EB)
-{
- const nl_double polarity = (qtype() == BJT_NPN ? 1.0 : -1.0);
-
- m_gD_BE.update_diode(-m_D_EB.deltaV() * polarity);
- m_gD_BC.update_diode(-m_D_CB.deltaV() * polarity);
-
- const nl_double gee = m_gD_BE.G();
- const nl_double gcc = m_gD_BC.G();
- const nl_double gec = m_alpha_r * gcc;
- const nl_double gce = m_alpha_f * gee;
- const nl_double sIe = -m_gD_BE.I() + m_alpha_r * m_gD_BC.I();
- const nl_double sIc = m_alpha_f * m_gD_BE.I() - m_gD_BC.I();
- const nl_double Ie = (sIe + gee * m_gD_BE.Vd() - gec * m_gD_BC.Vd()) * polarity;
- const nl_double Ic = (sIc - gce * m_gD_BE.Vd() + gcc * m_gD_BC.Vd()) * polarity;
-
- m_D_EB.set_mat( gee, gec - gee, -Ie,
- gce - gee, gee - gec, Ie);
- m_D_CB.set_mat( gcc, gce - gcc, -Ic,
- gec - gcc, gcc - gce, Ic);
- m_D_EC.set_mat( 0, -gec, 0,
- -gce, 0, 0);
-}
-
-
-NETLIB_UPDATE_PARAM(QBJT_EB)
-{
- nl_double IS = m_model.m_IS;
- nl_double BF = m_model.m_BF;
- nl_double NF = m_model.m_NF;
- nl_double BR = m_model.m_BR;
- nl_double NR = m_model.m_NR;
- //nl_double VJE = m_model.dValue("VJE", 0.75);
+ NETLIB_UPDATE_PARAM(QBJT_EB)
+ {
+ nl_double IS = m_model.m_IS;
+ nl_double BF = m_model.m_BF;
+ nl_double NF = m_model.m_NF;
+ nl_double BR = m_model.m_BR;
+ nl_double NR = m_model.m_NR;
+ //nl_double VJE = m_model.dValue("VJE", 0.75);
- set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
+ set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
- m_alpha_f = BF / (1.0 + BF);
- m_alpha_r = BR / (1.0 + BR);
+ m_alpha_f = BF / (1.0 + BF);
+ m_alpha_r = BR / (1.0 + BR);
- m_gD_BE.set_param(IS / m_alpha_f, NF, netlist().gmin());
- m_gD_BC.set_param(IS / m_alpha_r, NR, netlist().gmin());
-}
+ m_gD_BE.set_param(IS / m_alpha_f, NF, exec().gmin(), constants::T0());
+ m_gD_BC.set_param(IS / m_alpha_r, NR, exec().gmin(), constants::T0());
+ }
- } //namespace analog
+} // namespace analog
- namespace devices {
- NETLIB_DEVICE_IMPL_NS(analog, QBJT_EB)
- NETLIB_DEVICE_IMPL_NS(analog, QBJT_switch)
- }
+namespace devices {
+ NETLIB_DEVICE_IMPL_NS(analog, QBJT_EB, "QBJT_EB", "MODEL")
+ NETLIB_DEVICE_IMPL_NS(analog, QBJT_switch, "QBJT_SW", "MODEL")
+} // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/analog/nld_bjt.h b/src/lib/netlist/analog/nld_bjt.h
index 9e1f82afbaa..3a8478f19f7 100644
--- a/src/lib/netlist/analog/nld_bjt.h
+++ b/src/lib/netlist/analog/nld_bjt.h
@@ -8,7 +8,7 @@
#ifndef NLD_BJT_H_
#define NLD_BJT_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// -----------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/analog/nld_fourterm.h b/src/lib/netlist/analog/nld_fourterm.h
index b4bb5db1059..66c47c0be29 100644
--- a/src/lib/netlist/analog/nld_fourterm.h
+++ b/src/lib/netlist/analog/nld_fourterm.h
@@ -9,7 +9,7 @@
#define NLD_FOURTERM_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// ----------------------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp
new file mode 100644
index 00000000000..ea717fdefee
--- /dev/null
+++ b/src/lib/netlist/analog/nld_mosfet.cpp
@@ -0,0 +1,488 @@
+// license:GPL-2.0+
+// 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"
+#include "nlid_twoterm.h"
+
+#include <cmath>
+
+#define BODY_CONNECTED_TO_SOURCE (1)
+
+namespace netlist
+{
+namespace analog
+{
+
+ using constants = plib::constants<nl_double>;
+
+ // -----------------------------------------------------------------------------
+ // nld_FET - Base classes
+ // -----------------------------------------------------------------------------
+
+ /*! Class representing the nmos model paramers.
+ *
+ * This is the model representation of the nmos 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|
+ * | |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|*
+ * | |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 |-|1.0||
+ * | Y |W | Width scaling |-|1.0||
+ * */
+
+ class fet_model_t : public param_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")
+ {}
+
+ 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
+ };
+
+ // 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)
+ {
+ }
+
+ 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;
+ };
+
+ // -----------------------------------------------------------------------------
+ // nld_QBJT_EB
+ // -----------------------------------------------------------------------------
+
+
+ NETLIB_OBJECT_DERIVED(MOSFET, FET)
+ {
+ public:
+ NETLIB_CONSTRUCTOR_DERIVED(MOSFET, FET)
+ , m_DG(*this, "m_DG", true)
+ , m_SG(*this, "m_SG", true)
+ , m_SD(*this, "m_SD", true)
+ , m_D_BD(*this, "m_D_BD")
+#if (!BODY_CONNECTED_TO_SOURCE)
+ , m_D_BS(*this, "m_D_BS")
+#endif
+ , 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)
+ {
+ register_subalias("S", m_SG.m_P); // Source
+ register_subalias("G", m_SG.m_N); // Gate
+
+ register_subalias("D", m_DG.m_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);
+
+#if 0
+ if (m_model.m_CJE > 0.0)
+ {
+ create_and_register_subdevice("m_CJE", m_CJE);
+ connect("B", "m_CJE.1");
+ connect("E", "m_CJE.2");
+ }
+ if (m_model.m_CJC > 0.0)
+ {
+ create_and_register_subdevice("m_CJC", m_CJC);
+ connect("B", "m_CJC.1");
+ connect("C", "m_CJC.2");
+ }
+#endif
+ }
+
+ protected:
+
+ NETLIB_RESETI();
+ NETLIB_UPDATEI();
+ NETLIB_UPDATE_PARAMI();
+ NETLIB_UPDATE_TERMINALSI();
+
+ private:
+
+ nld_twoterm m_DG;
+ nld_twoterm m_SG;
+ nld_twoterm m_SD;
+
+ generic_diode<diode_e::MOS> m_D_BD;
+#if (!BODY_CONNECTED_TO_SOURCE)
+ generic_diode<diode_e::MOS> m_D_BS;
+#endif
+
+ nl_double m_phi;
+ nl_double m_gamma;
+ nl_double m_vto;
+ nl_double m_beta;
+ nl_double m_lambda;
+
+ /* used in capacitance calculation */
+ nl_double m_Leff;
+ nl_double m_Cox;
+
+ //NETLIB_SUBXX(analog, C) m_CJE;
+ //NETLIB_SUBXX(analog, C) m_CJC;
+ };
+
+
+
+ // ----------------------------------------------------------------------------------------
+ // nld_Q - Ebers Moll
+ // ----------------------------------------------------------------------------------------
+
+
+ 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_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;
+
+#if (!BODY_CONNECTED_TO_SOURCE)
+ m_D_BS.update_diode(Ubs);
+#endif
+ m_D_BD.update_diode(Ubd);
+
+ // Are we in forward mode ?
+ const bool is_forward = Uds >= 0;
+
+ // calculate Vth
+ const nl_double Vbulk = is_forward ? Ubs : Ubd;
+ 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 Vctrl = (is_forward ? Ugs : Ugd) - Vth;
+
+ nl_double Ids, gm, gds, gmb;
+
+ if (Vctrl <= 0.0)
+ {
+ // cutoff region
+ Ids = 0.0;
+ gm = 0.0;
+ gds = 0.0;
+ gmb = 0.0;
+ }
+ else
+ {
+ const nl_double Vds = std::abs(Uds);
+ const nl_double b = m_beta * (1.0 + m_lambda * Vds);
+ if (Vctrl <= Vds)
+ {
+ // saturation region
+ Ids = b * Vctrl * Vctrl / 2.0;
+ gm = b * 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);
+ }
+
+ // backgate transconductance
+ const nl_double bgtc = (phi_m_Vbulk != 0.0) ? (m_gamma / phi_m_Vbulk / 2.0) : 0.0;
+ gmb = gm * bgtc;
+ }
+
+ // FIXME: these are needed to compute capacitance
+ // nl_double 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();
+#if 0
+ const nl_double IeqBS = m_D_BS.Ieq();
+ const nl_double gbs = m_D_BS.G();
+#else
+ const nl_double IeqBS = 0.0;
+ const nl_double gbs = 0.0;
+#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_double IeqDS = (is_forward) ?
+ Ids - gm * Ugs - gmb * Ubs - gds * Uds
+ : -Ids - gm * Ugd - gmb * Ubd - gds * Uds;
+
+ // 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
+ const nl_double gSB = -gbs - gmb;
+
+ const nl_double gBG = 0.0; // ok
+ const nl_double gBD = -gbd; // ok
+ const nl_double gBS = -gbs;
+ const nl_double gBB = gbs + gbd; // ok
+
+ // Source connected to body, Diode S-B shorted!
+ const nl_double gSSBB = gSS + gBB + gBS + gSB;
+
+ // S 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
+ // 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);
+
+ /*
+ * 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
+
+ // 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;
+
+ // 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
+ m_beta = 2e-5 * m_model.m_W / m_Leff;
+
+ // 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
+
+ //FIXME::UT can disappear
+ const double 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)
+ {
+ 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());
+ }
+ else
+ m_phi = 0.6;
+
+ // calculate bulk threshold if not given
+ if (m_model.m_GAMMA > 0.0)
+ 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;
+ else
+ m_gamma = 0.0;
+ }
+
+ m_vto = m_model.m_VTO;
+ nl_assert_always(m_vto != 0.0, "Threshold voltage not specified for " + m_model.name());
+
+ /* FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
+ * specify VTO so skip this here.
+ */
+
+ m_Cox = m_Cox * m_model.m_W * m_Leff;
+
+ }
+
+} // namespace analog
+
+namespace devices {
+ NETLIB_DEVICE_IMPL_NS(analog, MOSFET, "MOSFET", "MODEL")
+} // namespace devices
+
+} // namespace netlist
diff --git a/src/lib/netlist/analog/nld_mosfet.h b/src/lib/netlist/analog/nld_mosfet.h
new file mode 100644
index 00000000000..32011d709d8
--- /dev/null
+++ b/src/lib/netlist/analog/nld_mosfet.h
@@ -0,0 +1,21 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * nld_mosfet.h
+ *
+ */
+
+#ifndef NLD_MOSFET_H_
+#define NLD_MOSFET_H_
+
+#include "netlist/nl_setup.h"
+
+// -----------------------------------------------------------------------------
+// Macros
+// -----------------------------------------------------------------------------
+
+#define MOSFET(name, model) \
+ NET_REGISTER_DEV(MOSFET, name) \
+ NETDEV_PARAMI(name, MODEL, model)
+
+#endif /* NLD_MOSFET_H_ */
diff --git a/src/lib/netlist/analog/nld_opamps.cpp b/src/lib/netlist/analog/nld_opamps.cpp
index 5f55a26f5d0..8c3c655bfa9 100644
--- a/src/lib/netlist/analog/nld_opamps.cpp
+++ b/src/lib/netlist/analog/nld_opamps.cpp
@@ -6,10 +6,10 @@
*/
#include "nld_opamps.h"
-#include "../nl_base.h"
-#include "../nl_errstr.h"
-#include "nlid_twoterm.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_errstr.h"
#include "nlid_fourterm.h"
+#include "nlid_twoterm.h"
#include <cmath>
@@ -129,10 +129,10 @@ namespace netlist
}
else if (m_type == 3)
{
- register_sub("CP1", m_CP);
- register_sub("EBUF", m_EBUF);
- register_sub("DN", m_DN, "D(IS=1e-15 N=1)");
- register_sub("DP", m_DP, "D(IS=1e-15 N=1)");
+ create_and_register_subdevice("CP1", m_CP);
+ create_and_register_subdevice("EBUF", m_EBUF);
+ create_and_register_subdevice("DN", m_DN, "D(IS=1e-15 N=1)");
+ create_and_register_subdevice("DP", m_DP, "D(IS=1e-15 N=1)");
//m_DP->m_model.setTo("D(IS=1e-15 N=1)");
//m_DN->m_model.setTo("D(IS=1e-15 N=1)");
@@ -201,7 +201,7 @@ namespace netlist
NETLIB_RESET(opamp)
{
- m_G1.do_reset();
+ m_G1.reset();
m_G1.m_RI.setTo(m_model.m_RI);
if (m_type == 1)
@@ -213,11 +213,11 @@ namespace netlist
}
else if (m_type == 3)
{
- m_EBUF->do_reset();
- m_DP->do_reset();
- m_DN->do_reset();
- m_CP->do_reset();
- m_RP.do_reset();
+ m_EBUF->reset();
+ m_DP->reset();
+ m_DN->reset();
+ m_CP->reset();
+ m_RP.reset();
m_EBUF->m_G.setTo(1.0);
m_EBUF->m_RO.setTo(m_model.m_RO);
@@ -239,6 +239,6 @@ namespace netlist
} //namespace analog
namespace devices {
- NETLIB_DEVICE_IMPL_NS(analog, opamp)
- }
+ NETLIB_DEVICE_IMPL_NS(analog, opamp, "OPAMP", "MODEL")
+ } // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/analog/nld_opamps.h b/src/lib/netlist/analog/nld_opamps.h
index d05a19aa3dc..4a07f646587 100644
--- a/src/lib/netlist/analog/nld_opamps.h
+++ b/src/lib/netlist/analog/nld_opamps.h
@@ -10,7 +10,7 @@
#ifndef NLD_OPAMPS_H_
#define NLD_OPAMPS_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// ----------------------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/analog/nld_switches.cpp b/src/lib/netlist/analog/nld_switches.cpp
index 1575551f260..0e62fe13952 100644
--- a/src/lib/netlist/analog/nld_switches.cpp
+++ b/src/lib/netlist/analog/nld_switches.cpp
@@ -6,10 +6,13 @@
*/
#include "nlid_twoterm.h"
-#include "../nl_base.h"
-#include "../nl_factory.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_factory.h"
+#include "netlist/solver/nld_solver.h"
-#define R_OFF (1.0 / netlist().gmin())
+/* FIXME : convert to parameters */
+
+#define R_OFF (1.0 / exec().gmin())
#define R_ON 0.01
namespace netlist
@@ -24,7 +27,7 @@ namespace netlist
{
NETLIB_CONSTRUCTOR(switch1)
, m_R(*this, "R")
- , m_POS(*this, "POS", 0)
+ , m_POS(*this, "POS", false)
{
register_subalias("1", m_R.m_P);
register_subalias("2", m_R.m_N);
@@ -46,6 +49,11 @@ namespace netlist
NETLIB_UPDATE(switch1)
{
+ }
+
+ NETLIB_UPDATE_PARAM(switch1)
+ {
+ m_R.solve_now();
if (!m_POS())
{
m_R.set_R(R_OFF);
@@ -54,13 +62,8 @@ namespace netlist
{
m_R.set_R(R_ON);
}
+ m_R.solve_later();
- m_R.update_dev();
- }
-
- NETLIB_UPDATE_PARAM(switch1)
- {
- update();
}
// ----------------------------------------------------------------------------------------
@@ -72,7 +75,7 @@ namespace netlist
NETLIB_CONSTRUCTOR(switch2)
, m_R1(*this, "R1")
, m_R2(*this, "R2")
- , m_POS(*this, "POS", 0)
+ , m_POS(*this, "POS", false)
{
connect(m_R1.m_N, m_R2.m_N);
@@ -110,19 +113,31 @@ namespace netlist
m_R2.set_R(R_ON);
}
- m_R1.update_dev();
- m_R2.update_dev();
+ //m_R1.update_dev(time);
+ //m_R2.update_dev(time);
}
NETLIB_UPDATE_PARAM(switch2)
{
- update();
+ if (!m_POS())
+ {
+ m_R1.set_R(R_ON);
+ m_R2.set_R(R_OFF);
+ }
+ else
+ {
+ m_R1.set_R(R_OFF);
+ m_R2.set_R(R_ON);
+ }
+
+ m_R1.solve_now();
+ m_R2.solve_now();
}
} //namespace analog
namespace devices {
- NETLIB_DEVICE_IMPL_NS(analog, switch1)
- NETLIB_DEVICE_IMPL_NS(analog, switch2)
- }
+ NETLIB_DEVICE_IMPL_NS(analog, switch1, "SWITCH", "")
+ NETLIB_DEVICE_IMPL_NS(analog, switch2, "SWITCH2", "")
+ } // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/analog/nld_switches.h b/src/lib/netlist/analog/nld_switches.h
index 3cd561f84b1..7aa31c925ae 100644
--- a/src/lib/netlist/analog/nld_switches.h
+++ b/src/lib/netlist/analog/nld_switches.h
@@ -10,7 +10,7 @@
#ifndef NLD_SWITCHES_H_
#define NLD_SWITCHES_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// ----------------------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/analog/nld_twoterm.h b/src/lib/netlist/analog/nld_twoterm.h
index d5cf6f6d228..b175f40af97 100644
--- a/src/lib/netlist/analog/nld_twoterm.h
+++ b/src/lib/netlist/analog/nld_twoterm.h
@@ -4,7 +4,7 @@
#ifndef NLD_TWOTERM_H_
#define NLD_TWOTERM_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// -----------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/analog/nlid_fourterm.cpp b/src/lib/netlist/analog/nlid_fourterm.cpp
index aa2723fe8e1..7fa6a2f3809 100644
--- a/src/lib/netlist/analog/nlid_fourterm.cpp
+++ b/src/lib/netlist/analog/nlid_fourterm.cpp
@@ -5,8 +5,8 @@
*
*/
-#include "../solver/nld_solver.h"
-#include "../nl_factory.h"
+#include "netlist/solver/nld_solver.h"
+#include "netlist/nl_factory.h"
#include "nlid_fourterm.h"
#include <cmath>
@@ -24,16 +24,16 @@ namespace netlist
NETLIB_RESET(VCCS)
{
const nl_double m_mult = m_G() * m_gfac; // 1.0 ==> 1V ==> 1A
- const nl_double GI = NL_FCONST(1.0) / m_RI();
+ const nl_double GI = plib::constants<nl_double>::one() / m_RI();
- m_IP.set(GI);
- m_IN.set(GI);
+ m_IP.set_conductivity(GI);
+ m_IN.set_conductivity(GI);
- m_OP.set(m_mult, NL_FCONST(0.0));
- m_OP1.set(-m_mult, NL_FCONST(0.0));
+ m_OP.set_go_gt(-m_mult, plib::constants<nl_double>::zero());
+ m_OP1.set_go_gt(m_mult, plib::constants<nl_double>::zero());
- m_ON.set(-m_mult, NL_FCONST(0.0));
- m_ON1.set(m_mult, NL_FCONST(0.0));
+ m_ON.set_go_gt(m_mult, plib::constants<nl_double>::zero());
+ m_ON1.set_go_gt(-m_mult, plib::constants<nl_double>::zero());
}
NETLIB_UPDATE(VCCS)
@@ -63,11 +63,6 @@ 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() * m_gfac; // 1.0 ==> 1V ==> 1A
@@ -84,11 +79,11 @@ NETLIB_UPDATE_TERMINALS(LVCCS)
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_OP.set_go_gt_I(-beta, plib::constants<nl_double>::zero(), I);
+ m_OP1.set_go_gt(beta, plib::constants<nl_double>::zero());
- m_ON.set(-beta, NL_FCONST(0.0), -I);
- m_ON1.set(beta, NL_FCONST(0.0));
+ m_ON.set_go_gt_I(beta, plib::constants<nl_double>::zero(), -I);
+ m_ON1.set_go_gt(-beta, plib::constants<nl_double>::zero());
}
// ----------------------------------------------------------------------------------------
@@ -105,30 +100,25 @@ NETLIB_UPDATE_PARAM(CCCS)
NETLIB_NAME(VCCS)::update_param();
}
-NETLIB_UPDATE(CCCS)
-{
- NETLIB_NAME(VCCS)::update();
-}
-
// ----------------------------------------------------------------------------------------
// nld_VCVS
// ----------------------------------------------------------------------------------------
NETLIB_RESET(VCVS)
{
- m_gfac = NL_FCONST(1.0) / m_RO();
+ m_gfac = plib::constants<nl_double>::one() / m_RO();
NETLIB_NAME(VCCS)::reset();
- m_OP2.set(NL_FCONST(1.0) / m_RO());
- m_ON2.set(NL_FCONST(1.0) / m_RO());
+ m_OP2.set_conductivity(plib::constants<nl_double>::one() / m_RO());
+ m_ON2.set_conductivity(plib::constants<nl_double>::one() / m_RO());
}
} //namespace analog
namespace devices {
- NETLIB_DEVICE_IMPL_NS(analog, VCVS)
- NETLIB_DEVICE_IMPL_NS(analog, VCCS)
- NETLIB_DEVICE_IMPL_NS(analog, CCCS)
- NETLIB_DEVICE_IMPL_NS(analog, LVCCS)
- }
+ NETLIB_DEVICE_IMPL_NS(analog, VCVS, "VCVS", "")
+ NETLIB_DEVICE_IMPL_NS(analog, VCCS, "VCCS", "")
+ NETLIB_DEVICE_IMPL_NS(analog, CCCS, "CCCS", "")
+ NETLIB_DEVICE_IMPL_NS(analog, LVCCS, "LVCCS", "")
+ } // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/analog/nlid_fourterm.h b/src/lib/netlist/analog/nlid_fourterm.h
index 641fc72427b..5ca6a747116 100644
--- a/src/lib/netlist/analog/nlid_fourterm.h
+++ b/src/lib/netlist/analog/nlid_fourterm.h
@@ -8,7 +8,8 @@
#ifndef NLID_FOURTERM_H_
#define NLID_FOURTERM_H_
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
+#include "plib/putil.h"
namespace netlist {
namespace analog {
@@ -40,39 +41,32 @@ namespace netlist {
NETLIB_CONSTRUCTOR(VCCS)
, m_G(*this, "G", 1.0)
, m_RI(*this, "RI", 1e9)
- , m_OP(*this, "OP")
- , m_ON(*this, "ON")
- , m_IP(*this, "IP")
- , m_IN(*this, "IN")
- , m_OP1(*this, "_OP1")
- , m_ON1(*this, "_ON1")
+ , m_OP(*this, "OP", &m_IP)
+ , m_ON(*this, "ON", &m_IP)
+ , m_IP(*this, "IP", &m_IN) // <= this should be NULL and terminal be filtered out prior to solving...
+ , m_IN(*this, "IN", &m_IP) // <= this should be NULL and terminal be filtered out prior to solving...
+ , m_OP1(*this, "_OP1", &m_IN)
+ , m_ON1(*this, "_ON1", &m_IN)
, m_gfac(1.0)
{
- m_IP.m_otherterm = &m_IN; // <= this should be NULL and terminal be filtered out prior to solving...
- m_IN.m_otherterm = &m_IP; // <= this should be NULL and terminal be filtered out prior to solving...
-
- m_OP.m_otherterm = &m_IP;
- m_OP1.m_otherterm = &m_IN;
-
- m_ON.m_otherterm = &m_IP;
- m_ON1.m_otherterm = &m_IN;
-
connect(m_OP, m_OP1);
connect(m_ON, m_ON1);
- m_gfac = NL_FCONST(1.0);
+ m_gfac = plib::constants<nl_double>::one();
}
+ NETLIB_RESETI();
+
param_double_t m_G;
param_double_t m_RI;
protected:
- NETLIB_RESETI();
NETLIB_UPDATEI();
NETLIB_UPDATE_PARAMI()
{
NETLIB_NAME(VCCS)::reset();
}
+
terminal_t m_OP;
terminal_t m_ON;
@@ -98,14 +92,14 @@ namespace netlist {
NETLIB_IS_DYNAMIC(true)
- param_double_t m_cur_limit; /* current limit */
-
protected:
- NETLIB_UPDATEI();
+ //NETLIB_UPDATEI();
NETLIB_RESETI();
NETLIB_UPDATE_PARAMI();
NETLIB_UPDATE_TERMINALSI();
+ private:
+ param_double_t m_cur_limit; /* current limit */
nl_double m_vi;
};
@@ -137,12 +131,13 @@ namespace netlist {
public:
NETLIB_CONSTRUCTOR_DERIVED(CCCS, VCCS)
{
- m_gfac = NL_FCONST(1.0) / m_RI();
+ m_gfac = plib::constants<nl_double>::one() / m_RI();
}
- protected:
- NETLIB_UPDATEI();
NETLIB_RESETI();
+
+ protected:
+ //NETLIB_UPDATEI();
NETLIB_UPDATE_PARAMI();
};
@@ -180,29 +175,28 @@ namespace netlist {
public:
NETLIB_CONSTRUCTOR_DERIVED(VCVS, VCCS)
, m_RO(*this, "RO", 1.0)
- , m_OP2(*this, "_OP2")
- , m_ON2(*this, "_ON2")
+ , m_OP2(*this, "_OP2", &m_ON2)
+ , m_ON2(*this, "_ON2", &m_OP2)
{
- m_OP2.m_otherterm = &m_ON2;
- m_ON2.m_otherterm = &m_OP2;
-
connect(m_OP2, m_OP1);
connect(m_ON2, m_ON1);
}
+ NETLIB_RESETI();
+
param_double_t m_RO;
- protected:
+ private:
//NETLIB_UPDATEI();
- NETLIB_RESETI();
//NETLIB_UPDATE_PARAMI();
terminal_t m_OP2;
terminal_t m_ON2;
+
};
- }
-}
+ } // namespace analog
+} // namespace netlist
#endif /* NLD_FOURTERM_H_ */
diff --git a/src/lib/netlist/analog/nlid_twoterm.cpp b/src/lib/netlist/analog/nlid_twoterm.cpp
index f54c2b3e68f..5019c98c0e4 100644
--- a/src/lib/netlist/analog/nlid_twoterm.cpp
+++ b/src/lib/netlist/analog/nlid_twoterm.cpp
@@ -5,10 +5,10 @@
*
*/
-#include "../solver/nld_solver.h"
+#include "netlist/solver/nld_solver.h"
+#include "netlist/nl_factory.h"
#include "nlid_twoterm.h"
-#include "../nl_factory.h"
#include <cmath>
@@ -16,81 +16,34 @@ namespace netlist
{
namespace analog
{
+
// ----------------------------------------------------------------------------------------
-// generic_diode
+// nld_twoterm
// ----------------------------------------------------------------------------------------
-generic_diode::generic_diode(device_t &dev, pstring name)
- : m_Vd(dev, name + ".m_Vd", 0.7)
- , m_Id(dev, name + ".m_Id", 0.0)
- , m_G(dev, name + ".m_G", 1e-15)
- , m_Vt(0.0)
- , m_Vmin(0.0)
- , m_Is(0.0)
- , m_logIs(0.0)
- , m_n(0.0)
- , m_gmin(1e-15)
- , m_VtInv(0.0)
- , m_Vcrit(0.0)
-{
- set_param(1e-15, 1, 1e-15);
-}
-
-void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double gmin)
+void NETLIB_NAME(twoterm)::solve_now()
{
- static constexpr double csqrt2 = 1.414213562373095048801688724209; //std::sqrt(2.0);
- m_Is = Is;
- m_logIs = std::log(Is);
- m_n = n;
- m_gmin = gmin;
-
- m_Vt = 0.0258 * m_n;
- m_Vmin = -5.0 * m_Vt;
-
- m_Vcrit = m_Vt * std::log(m_Vt / m_Is / csqrt2);
- m_VtInv = 1.0 / m_Vt;
+ /* we only need to call the non-rail terminal */
+ if (m_P.has_net() && !m_P.net().isRailNet())
+ m_P.solve_now();
+ else if (m_N.has_net() && !m_N.net().isRailNet())
+ m_N.solve_now();
}
-void generic_diode::update_diode(const nl_double nVd)
+void NETLIB_NAME(twoterm)::solve_later(netlist_time delay)
{
- if (nVd < m_Vmin)
- {
- m_Vd = nVd;
- m_G = m_gmin;
- m_Id = - m_Is;
- }
- else if (nVd < m_Vcrit)
- {
- m_Vd = nVd;
- //m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt);
- //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv);
- const double IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv);
- m_Id = IseVDVt - m_Is;
- m_G = IseVDVt * m_VtInv + m_gmin;
- }
- else
- {
- const double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(-0.99));
- m_Vd = m_Vd + std::log1p(a) * m_Vt;
- //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv);
- const double IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv);
- m_Id = IseVDVt - m_Is;
- m_G = IseVDVt * m_VtInv + m_gmin;
- }
+ /* we only need to call the non-rail terminal */
+ if (m_P.has_net() && !m_P.net().isRailNet())
+ m_P.schedule_solve_after(delay);
+ else if (m_N.has_net() && !m_N.net().isRailNet())
+ m_N.schedule_solve_after(delay);
}
-// ----------------------------------------------------------------------------------------
-// nld_twoterm
-// ----------------------------------------------------------------------------------------
NETLIB_UPDATE(twoterm)
{
/* only called if connected to a rail net ==> notify the solver to recalculate */
- /* we only need to call the non-rail terminal */
- if (m_P.has_net() && !m_P.net().isRailNet())
- m_P.solve_now();
- else if (m_N.has_net() && !m_N.net().isRailNet())
- m_N.solve_now();
+ solve_now();
}
// ----------------------------------------------------------------------------------------
@@ -100,12 +53,7 @@ NETLIB_UPDATE(twoterm)
NETLIB_RESET(R_base)
{
NETLIB_NAME(twoterm)::reset();
- set_R(1.0 / netlist().gmin());
-}
-
-NETLIB_UPDATE(R_base)
-{
- NETLIB_NAME(twoterm)::update();
+ set_R(1.0 / exec().gmin());
}
// ----------------------------------------------------------------------------------------
@@ -114,14 +62,14 @@ NETLIB_UPDATE(R_base)
NETLIB_UPDATE_PARAM(R)
{
- update_dev();
- set_R(std::max(m_R(), netlist().gmin()));
+ solve_now();
+ set_R(std::max(m_R(), exec().gmin()));
}
NETLIB_RESET(R)
{
NETLIB_NAME(twoterm)::reset();
- set_R(std::max(m_R(), netlist().gmin()));
+ set_R(std::max(m_R(), exec().gmin()));
}
// ----------------------------------------------------------------------------------------
@@ -134,21 +82,22 @@ NETLIB_RESET(POT)
if (m_DialIsLog())
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
- m_R1.set_R(std::max(m_R() * v, netlist().gmin()));
- m_R2.set_R(std::max(m_R() * (NL_FCONST(1.0) - v), netlist().gmin()));
+ m_R1.set_R(std::max(m_R() * v, exec().gmin()));
+ m_R2.set_R(std::max(m_R() * (plib::constants<nl_double>::one() - v), exec().gmin()));
}
NETLIB_UPDATE_PARAM(POT)
{
- m_R1.update_dev();
- m_R2.update_dev();
+ m_R1.solve_now();
+ m_R2.solve_now();
nl_double v = m_Dial();
if (m_DialIsLog())
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
-
- m_R1.set_R(std::max(m_R() * v, netlist().gmin()));
- m_R2.set_R(std::max(m_R() * (NL_FCONST(1.0) - v), netlist().gmin()));
+ if (m_Reverse())
+ v = 1.0 - v;
+ m_R1.set_R(std::max(m_R() * v, exec().gmin()));
+ m_R2.set_R(std::max(m_R() * (plib::constants<nl_double>::one() - v), exec().gmin()));
}
@@ -164,13 +113,13 @@ NETLIB_RESET(POT2)
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
if (m_Reverse())
v = 1.0 - v;
- m_R1.set_R(std::max(m_R() * v, netlist().gmin()));
+ m_R1.set_R(std::max(m_R() * v, exec().gmin()));
}
NETLIB_UPDATE_PARAM(POT2)
{
- m_R1.update_dev();
+ m_R1.solve_now();
nl_double v = m_Dial();
@@ -178,38 +127,7 @@ NETLIB_UPDATE_PARAM(POT2)
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
if (m_Reverse())
v = 1.0 - v;
- m_R1.set_R(std::max(m_R() * v, netlist().gmin()));
-}
-
-// ----------------------------------------------------------------------------------------
-// nld_C
-// ----------------------------------------------------------------------------------------
-
-NETLIB_RESET(C)
-{
- // FIXME: Startup conditions
- set(netlist().gmin(), 0.0, -5.0 / netlist().gmin());
- //set(netlist().gmin(), 0.0, 0.0);
-}
-
-NETLIB_UPDATE_PARAM(C)
-{
- m_GParallel = netlist().gmin();
-}
-
-NETLIB_UPDATE(C)
-{
- NETLIB_NAME(twoterm)::update();
-}
-
-NETLIB_TIMESTEP(C)
-{
- /* Gpar should support convergence */
- const nl_double G = m_C() / step + m_GParallel;
- const nl_double I = -G * deltaV();
- set_mat( G, -G, -I,
- -G, G, I);
- //set(G, 0.0, I);
+ m_R1.set_R(std::max(m_R() * v, exec().gmin()));
}
// ----------------------------------------------------------------------------------------
@@ -218,9 +136,9 @@ NETLIB_TIMESTEP(C)
NETLIB_RESET(L)
{
- m_GParallel = netlist().gmin();
+ m_gmin = exec().gmin();
m_I = 0.0;
- m_G = m_GParallel;
+ m_G = m_gmin;
set_mat( m_G, -m_G, -m_I,
-m_G, m_G, m_I);
//set(1.0/NETLIST_GMIN, 0.0, -5.0 * NETLIST_GMIN);
@@ -230,16 +148,11 @@ NETLIB_UPDATE_PARAM(L)
{
}
-NETLIB_UPDATE(L)
-{
- NETLIB_NAME(twoterm)::update();
-}
-
NETLIB_TIMESTEP(L)
{
/* Gpar should support convergence */
m_I += m_I + m_G * deltaV();
- m_G = step / m_L() + m_GParallel;
+ m_G = step / m_L() + m_gmin;
set_mat( m_G, -m_G, -m_I,
-m_G, m_G, m_I);
//set(m_G, 0.0, m_I);
@@ -254,8 +167,8 @@ NETLIB_RESET(D)
nl_double Is = m_model.m_IS;
nl_double n = m_model.m_N;
- m_D.set_param(Is, n, netlist().gmin());
- set(m_D.G(), 0.0, m_D.Ieq());
+ m_D.set_param(Is, n, exec().gmin(), constants::T0());
+ set_G_V_I(m_D.G(), 0.0, m_D.Ieq());
}
NETLIB_UPDATE_PARAM(D)
@@ -263,12 +176,7 @@ NETLIB_UPDATE_PARAM(D)
nl_double Is = m_model.m_IS;
nl_double n = m_model.m_N;
- m_D.set_param(Is, n, netlist().gmin());
-}
-
-NETLIB_UPDATE(D)
-{
- NETLIB_NAME(twoterm)::update();
+ m_D.set_param(Is, n, exec().gmin(), constants::T0());
}
NETLIB_UPDATE_TERMINALS(D)
@@ -281,65 +189,18 @@ NETLIB_UPDATE_TERMINALS(D)
//set(m_D.G(), 0.0, m_D.Ieq());
}
-// ----------------------------------------------------------------------------------------
-// nld_VS
-// ----------------------------------------------------------------------------------------
-
-NETLIB_RESET(VS)
-{
- NETLIB_NAME(twoterm)::reset();
- this->set(1.0 / m_R(), m_V(), 0.0);
-}
-
-NETLIB_UPDATE(VS)
-{
- NETLIB_NAME(twoterm)::update();
-}
-
-NETLIB_TIMESTEP(VS)
-{
- this->set(1.0 / m_R(),
- m_compiled.evaluate(std::vector<double>({netlist().time().as_double()})),
- 0.0);
-}
-
-// ----------------------------------------------------------------------------------------
-// nld_CS
-// ----------------------------------------------------------------------------------------
-
-NETLIB_RESET(CS)
-{
- NETLIB_NAME(twoterm)::reset();
- const nl_double I = m_I();
-
- set_mat(0.0, 0.0, -I,
- 0.0, 0.0, I);
- //this->set(0.0, 0.0, m_I());
-}
-
-NETLIB_UPDATE(CS)
-{
- NETLIB_NAME(twoterm)::update();
-}
-
-NETLIB_TIMESTEP(CS)
-{
- const double I = m_compiled.evaluate(std::vector<double>({netlist().time().as_double()}));
- set_mat(0.0, 0.0, -I,
- 0.0, 0.0, I);
-}
} //namespace analog
namespace devices {
- NETLIB_DEVICE_IMPL_NS(analog, R)
- NETLIB_DEVICE_IMPL_NS(analog, POT)
- NETLIB_DEVICE_IMPL_NS(analog, POT2)
- NETLIB_DEVICE_IMPL_NS(analog, C)
- NETLIB_DEVICE_IMPL_NS(analog, L)
- NETLIB_DEVICE_IMPL_NS(analog, D)
- NETLIB_DEVICE_IMPL_NS(analog, VS)
- NETLIB_DEVICE_IMPL_NS(analog, CS)
- }
+ NETLIB_DEVICE_IMPL_NS(analog, R, "RES", "R")
+ NETLIB_DEVICE_IMPL_NS(analog, POT, "POT", "R")
+ NETLIB_DEVICE_IMPL_NS(analog, POT2, "POT2", "R")
+ NETLIB_DEVICE_IMPL_NS(analog, C, "CAP", "C")
+ NETLIB_DEVICE_IMPL_NS(analog, L, "IND", "L")
+ NETLIB_DEVICE_IMPL_NS(analog, D, "DIODE", "MODEL")
+ NETLIB_DEVICE_IMPL_NS(analog, VS, "VS", "V")
+ NETLIB_DEVICE_IMPL_NS(analog, CS, "CS", "I")
+ } // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h
index 7778f5f4585..470fb35c96e 100644
--- a/src/lib/netlist/analog/nlid_twoterm.h
+++ b/src/lib/netlist/analog/nlid_twoterm.h
@@ -33,8 +33,12 @@
#ifndef NLID_TWOTERM_H_
#define NLID_TWOTERM_H_
-#include "../nl_base.h"
-#include "../plib/pfunction.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_setup.h"
+#include "netlist/solver/nld_solver.h"
+#include "plib/pfunction.h"
+
+#include <cmath>
// -----------------------------------------------------------------------------
// Implementation
@@ -48,14 +52,27 @@ namespace netlist
// nld_twoterm
// -----------------------------------------------------------------------------
+ template <class C>
+ inline core_device_t &bselect(bool b, C &d1, core_device_t &d2)
+ {
+ auto *h = dynamic_cast<core_device_t *>(&d1);
+ return b ? *h : d2;
+ }
+ template<>
+ inline core_device_t &bselect(bool b, netlist_state_t &d1, core_device_t &d2)
+ {
+ plib::unused_var(d1);
+ if (b)
+ throw nl_exception("bselect with netlist and b==true");
+ return d2;
+ }
+
NETLIB_OBJECT(twoterm)
{
NETLIB_CONSTRUCTOR_EX(twoterm, bool terminals_owned = false)
- , m_P(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "1")
- , m_N(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "2")
+ , m_P(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "1", &m_N)
+ , m_N(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "2", &m_P)
{
- m_P.m_otherterm = &m_N;
- m_N.m_otherterm = &m_P;
}
terminal_t m_P;
@@ -63,36 +80,36 @@ NETLIB_OBJECT(twoterm)
//NETLIB_UPDATE_TERMINALSI() { }
//NETLIB_RESETI() { }
- NETLIB_UPDATEI();
public:
- /* inline */ void set(const nl_double G, const nl_double V, const nl_double I)
+
+ NETLIB_UPDATEI();
+
+ void solve_now();
+
+ void solve_later(netlist_time delay = netlist_time::from_nsec(1));
+
+ void set_G_V_I(const nl_double G, const nl_double V, const nl_double I)
{
/* GO, GT, I */
- m_P.set( G, G, ( V) * G - I);
- m_N.set( G, G, ( -V) * G + I);
+ m_P.set_go_gt_I( -G, G, ( V) * G - I);
+ m_N.set_go_gt_I( -G, G, ( -V) * G + I);
}
- /* inline */ nl_double deltaV() const
+ nl_double deltaV() const
{
return m_P.net().Q_Analog() - m_N.net().Q_Analog();
}
- void set_mat(const nl_double a11, const nl_double a12, const nl_double r1,
- const nl_double a21, const nl_double a22, const nl_double r2)
+ void set_mat(const nl_double a11, const nl_double a12, const nl_double rhs1,
+ const nl_double a21, const nl_double a22, const nl_double rhs2)
{
/* GO, GT, I */
- m_P.set(-a12, a11, r1);
- m_N.set(-a21, a22, r2);
+ m_P.set_go_gt_I(a12, a11, rhs1);
+ m_N.set_go_gt_I(a21, a22, rhs2);
}
private:
- template <class C>
- static core_device_t &bselect(bool b, C &d1, core_device_t &d2)
- {
- core_device_t *h = dynamic_cast<core_device_t *>(&d1);
- return b ? *h : d2;
- }
};
@@ -106,17 +123,17 @@ NETLIB_OBJECT_DERIVED(R_base, twoterm)
{
}
-public:
- inline void set_R(const nl_double R)
+ void set_R(const nl_double R)
{
- const nl_double G = NL_FCONST(1.0) / R;
+ const nl_double G = plib::constants<nl_double>::one() / R;
set_mat( G, -G, 0.0,
-G, G, 0.0);
}
-protected:
NETLIB_RESETI();
- NETLIB_UPDATEI();
+
+protected:
+ //NETLIB_UPDATEI();
};
@@ -127,7 +144,6 @@ NETLIB_OBJECT_DERIVED(R, R_base)
{
}
- param_double_t m_R;
protected:
@@ -136,6 +152,7 @@ protected:
NETLIB_UPDATE_PARAMI();
private:
+ param_double_t m_R;
/* protect set_R ... it's a recipe to desaster when used to bypass the parameter */
using NETLIB_NAME(R_base)::set_R;
};
@@ -151,7 +168,8 @@ NETLIB_OBJECT(POT)
, m_R2(*this, "_R2")
, m_R(*this, "R", 10000)
, m_Dial(*this, "DIAL", 0.5)
- , m_DialIsLog(*this, "DIALLOG", 0)
+ , m_DialIsLog(*this, "DIALLOG", false)
+ , m_Reverse(*this, "REVERSE", false)
{
register_subalias("1", m_R1.m_P);
register_subalias("2", m_R1.m_N);
@@ -172,6 +190,7 @@ private:
param_double_t m_R;
param_double_t m_Dial;
param_logic_t m_DialIsLog;
+ param_logic_t m_Reverse;
};
NETLIB_OBJECT(POT2)
@@ -180,8 +199,8 @@ NETLIB_OBJECT(POT2)
, m_R1(*this, "_R1")
, m_R(*this, "R", 10000)
, m_Dial(*this, "DIAL", 0.5)
- , m_DialIsLog(*this, "DIALLOG", 0)
- , m_Reverse(*this, "REVERSE", 0)
+ , m_DialIsLog(*this, "DIALLOG", false)
+ , m_Reverse(*this, "REVERSE", false)
{
register_subalias("1", m_R1.m_P);
register_subalias("2", m_R1.m_N);
@@ -201,6 +220,83 @@ private:
param_logic_t m_Reverse;
};
+// -----------------------------------------------------------------------------
+// A generic capacitor model
+// -----------------------------------------------------------------------------
+
+enum class capacitor_e
+{
+ CHARGE_CONSERVING,
+ CONSTANT_CAPACITY
+};
+
+template <capacitor_e TYPE>
+class generic_capacitor
+{
+};
+
+
+template <>
+class generic_capacitor<capacitor_e::CHARGE_CONSERVING>
+{
+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_gmin(0.0)
+ {
+ }
+
+ constexpr capacitor_e type() const { return capacitor_e::CHARGE_CONSERVING; }
+
+ 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 m_h * (cap * v - m_charge) - G(cap) * v;
+ }
+
+ void timestep(nl_double cap, nl_double v, nl_double step)
+ {
+ m_h = 1.0 / step;
+ m_charge = cap * v;
+ }
+
+ void setparams(nl_double gmin) { m_gmin = gmin; }
+
+private:
+ state_var<double> m_h;
+ state_var<double> m_charge;
+ nl_double m_gmin;
+};
+
+template <>
+class generic_capacitor<capacitor_e::CONSTANT_CAPACITY>
+{
+public:
+ generic_capacitor(device_t &dev, const pstring &name)
+ : m_h(dev, name + ".m_h", 0.0)
+ , m_gmin(0.0)
+ {
+ }
+
+ 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; }
+
+ void timestep(nl_double cap, nl_double v, nl_double step)
+ {
+ plib::unused_var(cap, v);
+ m_h = 1.0 / step;
+ }
+ void setparams(nl_double gmin) { m_gmin = gmin; }
+private:
+ state_var<nl_double> m_h;
+ nl_double m_gmin;
+};
// -----------------------------------------------------------------------------
// nld_C
@@ -211,25 +307,45 @@ NETLIB_OBJECT_DERIVED(C, twoterm)
public:
NETLIB_CONSTRUCTOR_DERIVED(C, twoterm)
, m_C(*this, "C", 1e-6)
- , m_GParallel(0.0)
+ , m_cap(*this, "m_cap")
{
- //register_term("1", m_P);
- //register_term("2", m_N);
}
NETLIB_IS_TIMESTEP(true)
- NETLIB_TIMESTEPI();
+ NETLIB_TIMESTEPI()
+ {
+ m_cap.timestep(m_C(), deltaV(), step);
+ if (m_cap.type() == capacitor_e::CONSTANT_CAPACITY)
+ {
+ const nl_double I = m_cap.Ieq(m_C(), deltaV());
+ const nl_double G = m_cap.G(m_C());
+ set_mat( G, -G, -I,
+ -G, G, I);
+ }
+ }
+
+ NETLIB_IS_DYNAMIC(m_cap.type() == capacitor_e::CHARGE_CONSERVING)
+ NETLIB_UPDATE_TERMINALSI()
+ {
+ const nl_double I = m_cap.Ieq(m_C(), deltaV());
+ const nl_double G = m_cap.G(m_C());
+ set_mat( G, -G, -I,
+ -G, G, I);
+ }
param_double_t m_C;
+ NETLIB_RESETI()
+ {
+ m_cap.setparams(exec().gmin());
+ }
protected:
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- NETLIB_UPDATE_PARAMI();
+ //NETLIB_UPDATEI();
+ NETLIB_UPDATE_PARAMI() { }
private:
- nl_double m_GParallel;
-
+ generic_capacitor<capacitor_e::CHARGE_CONSERVING> m_cap;
+ //generic_capacitor<capacitor_e::CONSTANT_CAPACITY> m_cap;
};
// -----------------------------------------------------------------------------
@@ -241,7 +357,7 @@ NETLIB_OBJECT_DERIVED(L, twoterm)
public:
NETLIB_CONSTRUCTOR_DERIVED(L, twoterm)
, m_L(*this, "L", 1e-6)
- , m_GParallel(0.0)
+ , m_gmin(0.0)
, m_G(0.0)
, m_I(0.0)
{
@@ -251,16 +367,16 @@ public:
NETLIB_IS_TIMESTEP(true)
NETLIB_TIMESTEPI();
-
- param_double_t m_L;
+ NETLIB_RESETI();
protected:
- NETLIB_RESETI();
- NETLIB_UPDATEI();
+ //NETLIB_UPDATEI();
NETLIB_UPDATE_PARAMI();
private:
- nl_double m_GParallel;
+ param_double_t m_L;
+
+ nl_double m_gmin;
nl_double m_G;
nl_double m_I;
};
@@ -269,14 +385,82 @@ private:
// A generic diode model to be used in other devices (Diode, BJT ...)
// -----------------------------------------------------------------------------
+enum class diode_e
+{
+ BIPOLAR,
+ MOS
+};
+
+template <diode_e TYPE>
class generic_diode
{
public:
- generic_diode(device_t &dev, pstring name);
+ generic_diode(device_t &dev, const pstring &name)
+ : m_Vd(dev, name + ".m_Vd", 0.7)
+ , m_Id(dev, name + ".m_Id", 0.0)
+ , m_G(dev, name + ".m_G", 1e-15)
+ , m_Vt(0.0)
+ , m_Vmin(0.0) // not used in MOS model
+ , m_Is(0.0)
+ , m_logIs(0.0)
+ , m_n(0.0)
+ , m_gmin(1e-15)
+ , m_VtInv(0.0)
+ , m_Vcrit(0.0)
+ {
+ set_param(1e-15, 1, 1e-15, 300.0);
+ }
+
+ void update_diode(const double nVd)
+ {
+ if (TYPE == diode_e::BIPOLAR && nVd < m_Vmin)
+ {
+ m_Vd = nVd;
+ m_G = m_gmin;
+ m_Id = - m_Is;
+ }
+ else if (TYPE == diode_e::MOS && nVd < constants::zero())
+ {
+ m_Vd = nVd;
+ m_G = m_Is * m_VtInv + m_gmin;
+ m_Id = m_G * m_Vd;
+ }
+ // FIXME: For MOS, stop here, the critical code path will not converge
+ 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));
+ m_Id = IseVDVt - m_Is;
+ m_G = IseVDVt * m_VtInv + m_gmin;
+ }
+ else
+ {
+ const double a = std::max((nVd - m_Vd) * m_VtInv, constants::cast(-0.99));
+ m_Vd = m_Vd + std::log1p(a) * m_Vt;
+ //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv);
+ const double IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv);
+ m_Id = IseVDVt - m_Is;
+ m_G = IseVDVt * m_VtInv + m_gmin;
+ }
+ }
+
+
+ void set_param(const double Is, const double n, double gmin, double temp)
+ {
+ static constexpr double csqrt2 = 1.414213562373095048801688724209; //std::sqrt(2.0);
+ m_Is = Is;
+ m_logIs = std::log(Is);
+ m_n = n;
+ m_gmin = gmin;
- void update_diode(const double nVd);
+ m_Vt = m_n * temp * constants::k_b() / constants::Q_e();
+
+ m_Vmin = -5.0 * m_Vt;
+
+ m_Vcrit = m_Vt * std::log(m_Vt / m_Is / csqrt2);
+ m_VtInv = 1.0 / m_Vt;
+ }
- void set_param(const double Is, const double n, double gmin);
double I() const { return m_Id; }
double G() const { return m_G; }
@@ -367,15 +551,15 @@ public:
NETLIB_IS_DYNAMIC(true)
NETLIB_UPDATE_TERMINALSI();
-
- diode_model_t m_model;
+ NETLIB_RESETI();
protected:
- NETLIB_RESETI();
- NETLIB_UPDATEI();
+ //NETLIB_UPDATEI();
NETLIB_UPDATE_PARAMI();
- generic_diode m_D;
+private:
+ diode_model_t m_model;
+ generic_diode<diode_e::BIPOLAR> m_D;
};
@@ -389,10 +573,11 @@ NETLIB_OBJECT_DERIVED(VS, twoterm)
{
public:
NETLIB_CONSTRUCTOR_DERIVED(VS, twoterm)
+ , m_t(*this, "m_t", 0.0)
, m_R(*this, "R", 0.1)
, m_V(*this, "V", 0.0)
, m_func(*this,"FUNC", "")
- , m_compiled(this->name() + ".FUNCC", this, this->netlist().state())
+ , m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
{
register_subalias("P", m_P);
register_subalias("N", m_N);
@@ -401,12 +586,26 @@ public:
}
NETLIB_IS_TIMESTEP(m_func() != "")
- NETLIB_TIMESTEPI();
+
+ NETLIB_TIMESTEPI()
+ {
+ m_t += step;
+ this->set_G_V_I(1.0 / m_R(),
+ m_compiled.evaluate(std::vector<double>({m_t})),
+ 0.0);
+ }
protected:
- NETLIB_UPDATEI();
- NETLIB_RESETI();
+ // NETLIB_UPDATEI() { NETLIB_NAME(twoterm)::update(time); }
+
+ NETLIB_RESETI()
+ {
+ NETLIB_NAME(twoterm)::reset();
+ this->set_G_V_I(1.0 / m_R(), m_V(), 0.0);
+ }
+private:
+ state_var<double> m_t;
param_double_t m_R;
param_double_t m_V;
param_str_t m_func;
@@ -421,9 +620,10 @@ NETLIB_OBJECT_DERIVED(CS, twoterm)
{
public:
NETLIB_CONSTRUCTOR_DERIVED(CS, twoterm)
+ , m_t(*this, "m_t", 0.0)
, m_I(*this, "I", 1.0)
, m_func(*this,"FUNC", "")
- , m_compiled(this->name() + ".FUNCC", this, this->netlist().state())
+ , m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
{
register_subalias("P", m_P);
register_subalias("N", m_N);
@@ -432,19 +632,33 @@ public:
}
NETLIB_IS_TIMESTEP(m_func() != "")
- NETLIB_TIMESTEPI();
+ NETLIB_TIMESTEPI()
+ {
+ m_t += step;
+ const double I = m_compiled.evaluate(std::vector<double>({m_t}));
+ set_mat(0.0, 0.0, -I,
+ 0.0, 0.0, I);
+ }
+
protected:
- NETLIB_UPDATEI();
- NETLIB_RESETI();
+ //NETLIB_UPDATEI() { NETLIB_NAME(twoterm)::update(time); }
+ NETLIB_RESETI()
+ {
+ NETLIB_NAME(twoterm)::reset();
+ set_mat(0.0, 0.0, -m_I(),
+ 0.0, 0.0, m_I());
+ }
+private:
+ state_var<double> m_t;
param_double_t m_I;
param_str_t m_func;
plib::pfunction m_compiled;
};
- } //namespace devices
+ } // namespace analog
} // namespace netlist
#endif /* NLD_TWOTERM_H_ */
diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile
index 807ddbd6c7a..647c7df6f12 100644
--- a/src/lib/netlist/build/makefile
+++ b/src/lib/netlist/build/makefile
@@ -12,6 +12,27 @@
SRC = ..
VSBUILD = $(SRC)/buildVS
DOC = $(SRC)/documentation
+TIDY_DB = ../compile_commands.json
+
+TIDY_FLAGSX = -checks=*,-google*,-hicpp*,-readability*,-fuchsia*,cert-*,-android-*,
+TIDY_FLAGSX += -llvm-header-guard,-cppcoreguidelines-pro-type-reinterpret-cast,
+TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-owning-memory,
+TIDY_FLAGSX += -modernize-use-default-member-init,-cppcoreguidelines-pro-bounds-constant-array-index,
+TIDY_FLAGSX += -modernize-pass-by-value,-cppcoreguidelines-pro-type-static-cast-downcast,
+TIDY_FLAGSX += -cppcoreguidelines-avoid-magic-numbers,
+TIDY_FLAGSX += -cppcoreguidelines-macro-usage,
+TIDY_FLAGSX += -cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,
+TIDY_FLAGSX += -bugprone-macro-parentheses,-misc-macro-parentheses
+
+space :=
+space +=
+TIDY_FLAGS = $(subst $(space),,$(TIDY_FLAGSX))
+
+TIDY_FLAGS = -checks=llvm-include-order,llvm-namespace-comment,modernize-use-override,modernize-use-using -fix
+#TIDY_FLAGS = -checks=llvm-include-order -fix
+#TIDY_FLAGS = -checks=llvm-namespace-comment -fix
+#TIDY_FLAGS = -checks=modernize-use-override -fix
+#TIDY_FLAGS = -checks=modernize-use-using -fix
ifeq ($(subst Windows_NT,windows,$(OS)),windows)
OBJ = obj/mingw
@@ -23,7 +44,7 @@ endif
# LTO = -flto=4 -fuse-linker-plugin -flto-partition=balanced -Wodr
-CFLAGS = $(LTO) -g -O3 -std=c++11 -march=native -I../.. -Wall -Wpedantic -Wsign-compare -Wextra -Wno-unused-parameter $(CEXTRAFLAGS)
+CFLAGS = $(LTO) -g -O3 -std=c++11 -I$(CURDIR)/.. -I$(CURDIR)/../.. $(CEXTRAFLAGS)
LDFLAGS = $(LTO) -g -O3 -std=c++11 $(LDEXTRAFLAGS)
LIBS = -lpthread -ldl
@@ -32,6 +53,7 @@ LD = @g++
MD = @mkdir
RM = @rm
DOXYGEN = @doxygen
+CLANG_TIDY = clang-tidy-9
TARGETS = nltool nlwav
@@ -53,7 +75,6 @@ OBJS = $(POBJS) $(NLOBJS)
POBJS := \
$(POBJ)/pstring.o \
- $(POBJ)/palloc.o \
$(POBJ)/pchrono.o \
$(POBJ)/pdynlib.o \
$(POBJ)/pexception.o \
@@ -73,6 +94,7 @@ NLOBJS := \
$(NLOBJ)/nl_setup.o \
$(NLOBJ)/nl_factory.o \
$(NLOBJ)/analog/nld_bjt.o \
+ $(NLOBJ)/analog/nld_mosfet.o \
$(NLOBJ)/analog/nlid_fourterm.o \
$(NLOBJ)/analog/nld_switches.o \
$(NLOBJ)/analog/nlid_twoterm.o \
@@ -92,6 +114,7 @@ NLOBJS := \
$(NLOBJ)/devices/nld_7485.o \
$(NLOBJ)/devices/nld_7490.o \
$(NLOBJ)/devices/nld_7493.o \
+ $(NLOBJ)/devices/nld_7497.o \
$(NLOBJ)/devices/nld_74107.o \
$(NLOBJ)/devices/nld_74123.o \
$(NLOBJ)/devices/nld_74153.o \
@@ -153,10 +176,12 @@ DOCS = \
$(DOC)/test1-50r.svg \
ALL_OBJS = $(OBJS) $(PMAIN) $(NLOBJ)/prg/nltool.o $(NLOBJ)/prg/nlwav.o
+
+ALL_TIDY_FILES = $(ALL_OBJS:.o=.json)
SOURCES = $(patsubst $(OBJ)%, $(SRC)%, $(ALL_OBJS:.o=.cpp))
ALLFILES = $(SOURCES) $(VSBUILDS) $(DOCS)
-MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean doc clang mingw
+MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean doc clang mingw nvcc
# git archive HEAD --prefix=project-name-version/ \
@@ -200,19 +225,33 @@ maketree: $(sort $(OBJDIRS))
# Special targets
#-------------------------------------------------
-.PHONY: clang clang-5 mingw doc
+.PHONY: clang clang-5 mingw doc native
+
+native:
+ $(MAKE) CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra "
clang:
- $(MAKE) CC=clang++ LD=clang++ CEXTRAFLAGS="-march=native -Weverything -Werror -override -Wno-unreachable-code -Wno-padded -Wno-weak-vtables -Wno-missing-variable-declarations -Wconversion -Wno-c++98-compat -Wno-float-equal -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-weak-template-vtables -Wno-exit-time-destructors"
+ $(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"
clang-5:
$(MAKE) CC=clang++-5.0 LD=clang++-5.0 CEXTRAFLAGS="-march=native -Weverything -Werror -Wno-inconsistent-missing-destructor-override -Wno-unreachable-code -Wno-padded -Wno-weak-vtables -Wno-missing-variable-declarations -Wconversion -Wno-c++98-compat -Wno-float-equal -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-weak-template-vtables -Wno-exit-time-destructors"
+nvcc:
+ $(MAKE) CC=/usr/local/cuda-9.0/bin/nvcc LD=/usr/local/cuda-9.2/bin/nvcc \
+ CEXTRAFLAGS="-x cu -DNVCCBUILD=1 --expt-extended-lambda --expt-relaxed-constexpr --default-stream per-thread --restrict"
+
+tidy_db: compile_commands_prefix $(ALL_TIDY_FILES) compile_commands_postfix
+
#
+# -Wno-c++11-narrowing : seems a bit broken
# Mostly done: -Wno-weak-vtables -Wno-cast-align
# FIXME: -Wno-weak-vtables -Wno-missing-variable-declarations -Wno-conversion -Wno-exit-time-destructors
# FIXME: -Winconsistent-missing-destructor-override : c++ community has diverging opinions on this https://github.com/isocpp/CppCoreGuidelines/issues/721
# FIXME: -Wunreachable-code : False warnings, this a documented clang bug: https://llvm.org/bugs/show_bug.cgi?id=28994
+# -Wweak-template-vtables
+#
+# These have to be given:
+# -Wno-missing-variable-declarations : Device factory code, on purpose
mingw:
$(MAKE) CEXTRAFLAGS="-DUNICODE -D_UNICODE -D_WIN32_WINNT=0x0501 -DWIN32_LEAN_AND_MEAN" \
@@ -237,7 +276,7 @@ doc: nltool
@echo creating .depend
@rm -f ./.depend
@for i in $(SOURCES); do \
- $(CC) $(CFLAGS) -MM $$i -MT `echo $$i | sed -e 's+$(SRC)+$(OBJ)+' -e 's+.cpp+.o+' ` >>./.depend; \
+ $(CC) $(CFLAGS) -MM $$i -MT `echo $$i | sed -e 's+$(SRC)+$(OBJ)+' -e 's+.cpp+.o+' ` >> ./.depend; \
done
depend: .depend
@@ -248,6 +287,18 @@ ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),)
endif
#-------------------------------------------------
+# clang tidy
+#-------------------------------------------------
+tidy: tidy_db
+ @echo running tidy
+ @for i in $(SOURCES); do \
+ $(CLANG_TIDY) $$i $(TIDY_FLAGS) -header-filter=.*; \
+ done
+
+tidy_db: compile_commands_prefix $(ALL_TIDY_FILES) compile_commands_postfix
+
+
+#-------------------------------------------------
# generic rules
#-------------------------------------------------
@@ -268,3 +319,15 @@ $(OBJ)/%.a:
$(RM) $@
$(AR) $(ARFLAGS) $@ $^
+$(OBJ)/%.json: $(SRC)/%.cpp
+ @echo Building compile database entry for $< ...
+ @echo { \"directory\": \".\", >> $(TIDY_DB)
+ @echo \"command\": \"$(CC) $(CDEFS) $(CFLAGS) -c $< -o dummy.o\", >> $(TIDY_DB)
+ @echo \"file\": \"$(CURDIR)/$<\" } >> $(TIDY_DB)
+ @echo "," >> $(TIDY_DB)
+
+compile_commands_prefix:
+ @echo "[" > $(TIDY_DB)
+
+compile_commands_postfix:
+ @echo "]" >> $(TIDY_DB)
diff --git a/src/lib/netlist/devices/net_lib.cpp b/src/lib/netlist/devices/net_lib.cpp
index e0f0277daac..c0353f2489a 100644
--- a/src/lib/netlist/devices/net_lib.cpp
+++ b/src/lib/netlist/devices/net_lib.cpp
@@ -9,152 +9,159 @@
****************************************************************************/
#include "net_lib.h"
-#include "../nl_factory.h"
-#include "../solver/nld_solver.h"
+#include "netlist/nl_factory.h"
+#include "netlist/solver/nld_solver.h"
#define xstr(s) # s
-#define NETLIB_DEVICE_DECL(chip) extern factory::constructor_ptr_t decl_ ## chip;
+#define NETLIB_DEVICE_DECL(chip) extern factory::constructor_ptr_t decl_ ## chip
-#define ENTRYX1(nic, name, defparam, decl) factory.register_device( decl (pstring(# name), pstring(xstr(nic)), pstring(defparam)) );
-#define ENTRYX(nic, name, defparam) { NETLIB_DEVICE_DECL(nic) ENTRYX1(NETLIB_NAME(nic), name, defparam, decl_ ## nic) }
+#define LIB_DECL(nic, decl) factory.register_device( decl ( pstring(xstr(nic))) );
+#define LIB_ENTRY(nic) { NETLIB_DEVICE_DECL(nic); LIB_DECL(NETLIB_NAME(nic), decl_ ## nic) }
namespace netlist
{
- namespace devices
- {
- void initialize_factory(factory::list_t &factory)
+namespace devices
{
- ENTRYX(R, RES, "R")
- ENTRYX(POT, POT, "R")
- ENTRYX(POT2, POT2, "R")
- ENTRYX(C, CAP, "C")
- ENTRYX(L, IND, "L")
- ENTRYX(D, DIODE, "MODEL")
- ENTRYX(VS, VS, "V")
- ENTRYX(CS, CS, "I")
- ENTRYX(VCVS, VCVS, "")
- ENTRYX(VCCS, VCCS, "")
- ENTRYX(CCCS, CCCS, "")
- ENTRYX(LVCCS, LVCCS, "")
- ENTRYX(opamp, OPAMP, "MODEL")
- ENTRYX(dummy_input, DUMMY_INPUT, "")
- ENTRYX(frontier, FRONTIER_DEV, "+I,+G,+Q") // not intended to be used directly
- ENTRYX(function, AFUNC, "N,FUNC") // only for macro devices - NO FEEDBACK loops
- ENTRYX(QBJT_EB, QBJT_EB, "MODEL")
- ENTRYX(QBJT_switch, QBJT_SW, "MODEL")
- ENTRYX(logic_input, TTL_INPUT, "IN")
- ENTRYX(logic_input, LOGIC_INPUT, "IN,FAMILY")
- ENTRYX(analog_input, ANALOG_INPUT, "IN")
- ENTRYX(log, LOG, "+I")
- ENTRYX(logD, LOGD, "+I,+I2")
- ENTRYX(clock, CLOCK, "FREQ")
- ENTRYX(extclock, EXTCLOCK, "FREQ,PATTERN")
- ENTRYX(mainclock, MAINCLOCK, "FREQ")
- ENTRYX(gnd, GND, "")
- ENTRYX(netlistparams, PARAMETER, "")
- ENTRYX(solver, SOLVER, "FREQ")
- ENTRYX(res_sw, RES_SWITCH, "+IN,+P1,+P2")
- ENTRYX(switch1, SWITCH, "")
- ENTRYX(switch2, SWITCH2, "")
- ENTRYX(nicRSFF, NETDEV_RSFF, "")
- ENTRYX(nicDelay, NETDEV_DELAY, "")
- ENTRYX(2716, EPROM_2716, "+GQ,+EPQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10")
- ENTRYX(TMS4800, ROM_TMS4800, "+AR,+OE1,+OE2,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10")
- ENTRYX(2102A, RAM_2102A, "+CEQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+RWQ,+DI")
- ENTRYX(7450, TTL_7450_ANDORINVERT, "+A,+B,+C,+D")
- ENTRYX(7448, TTL_7448, "+A,+B,+C,+D,+LTQ,+BIQ,+RBIQ")
- ENTRYX(7473, TTL_7473, "+CLK,+J,+K,+CLRQ")
- ENTRYX(7473A, TTL_7473A, "+CLK,+J,+K,+CLRQ")
- ENTRYX(7474, TTL_7474, "+CLK,+D,+CLRQ,+PREQ")
- ENTRYX(7475, TTL_7475, "")
- ENTRYX(7477, TTL_7477, "")
- ENTRYX(7483, TTL_7483, "+A1,+A2,+A3,+A4,+B1,+B2,+B3,+B4,+C0")
- ENTRYX(7485, TTL_7485, "+A0,+A1,+A2,+A3,+B0,+B1,+B2,+B3,+LTIN,+EQIN,+GTIN")
- ENTRYX(7490, TTL_7490, "+A,+B,+R1,+R2,+R91,+R92")
- ENTRYX(7493, TTL_7493, "+CLKA,+CLKB,+R1,+R2")
- ENTRYX(74107, TTL_74107, "+CLK,+J,+K,+CLRQ")
- ENTRYX(74107A, TTL_74107A, "+CLK,+J,+K,+CLRQ")
- ENTRYX(74123, TTL_74123, "")
- ENTRYX(74153, TTL_74153, "+C0,+C1,+C2,+C3,+A,+B,+G")
- ENTRYX(74161, TTL_74161, "+A,+B,+C,+D,+CLRQ,+LOADQ,+CLK,+ENABLEP,+ENABLET")
- ENTRYX(74164, TTL_74164, "+A,+B,+CLRQ,+CLK")
- ENTRYX(74165, TTL_74165, "+CLK,+CLKINH,+SH_LDQ,+SER,+A,+B,+C,+D,+E,+F,+G,+H")
- ENTRYX(74166, TTL_74166, "+CLK,+CLKINH,+SH_LDQ,+SER,+A,+B,+C,+D,+E,+F,+G,+H,+CLRQ")
- ENTRYX(74174, TTL_74174, "+CLK,+D1,+D2,+D3,+D4,+D5,+D6,+CLRQ")
- ENTRYX(74175, TTL_74175, "+CLK,+D1,+D2,+D3,+D4,+CLRQ")
- ENTRYX(74192, TTL_74192, "+A,+B,+C,+D,+CLEAR,+LOADQ,+CU,+CD")
- ENTRYX(74193, TTL_74193, "+A,+B,+C,+D,+CLEAR,+LOADQ,+CU,+CD")
- ENTRYX(74194, TTL_74194, "+CLK,+S0,+S1,+SRIN,+A,+B,+C,+D,+SLIN,+CLRQ")
- ENTRYX(74365, TTL_74365, "+G1Q,+G2Q,+A1,+A2,+A3,+A4,+A5,+A6")
- //ENTRY(74279, TTL_74279, "") // only dip available
- ENTRYX(SN74LS629, SN74LS629, "CAP")
- ENTRYX(82S16, TTL_82S16, "")
- ENTRYX(82S115, PROM_82S115, "+CE1Q,+CE2,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+STROBE")
- ENTRYX(82S123, PROM_82S123, "+CEQ,+A0,+A1,+A2,+A3,+A4")
- ENTRYX(82S126, PROM_82S126, "+CE1Q,+CE2Q,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7")
- ENTRYX(9310, TTL_9310, "")
- ENTRYX(9314, TTL_9314, "+EQ,+MRQ,+S0Q,+S1Q,+S2Q,+S3Q,+D0,+D1,+D2,+D3")
- ENTRYX(9316, TTL_9316, "+CLK,+ENP,+ENT,+CLRQ,+LOADQ,+A,+B,+C,+D")
- ENTRYX(9322, TTL_9322, "+SELECT,+A1,+B1,+A2,+B2,+A3,+B3,+A4,+B4,+STROBE")
- ENTRYX(9334, TTL_9334, "+CQ,+EQ,+D,+A0,+A1,+A2")
- ENTRYX(AM2847, TTL_AM2847, "+CP,+INA,+INB,+INC,+IND,+RCA,+RCB,+RCC,+RCD")
- ENTRYX(CD4020, CD4020, "")
- ENTRYX(CD4066_GATE, CD4066_GATE, "")
- ENTRYX(CD4316_GATE, CD4316_GATE, "")
- ENTRYX(schmitt_trigger, SCHMITT_TRIGGER, "MODEL")
- /* entries with suffix WI are legacy only */
- ENTRYX(CD4020, CD4020_WI, "+IP,+RESET,+VDD,+VSS")
- //ENTRY(4066, CD_4066, "+A,B")
- ENTRYX(NE555, NE555, "")
- ENTRYX(r2r_dac, R2R_DAC, "VIN,R,N")
- ENTRYX(tristate, TTL_TRISTATE, "+CEQ1,+D1,+CEQ2,+D2")
- ENTRYX(tristate3, TTL_TRISTATE3, "")
- ENTRYX(2102A_dip, RAM_2102A_DIP, "")
- ENTRYX(2716_dip, EPROM_2716_DIP, "")
- ENTRYX(tms4800_dip, ROM_TMS4800_DIP, "")
- ENTRYX(4538_dip, CD4538_DIP, "")
- ENTRYX(7448_dip, TTL_7448_DIP, "")
- ENTRYX(7450_dip, TTL_7450_DIP, "")
- ENTRYX(7473_dip, TTL_7473_DIP, "")
- ENTRYX(7473A_dip, TTL_7473A_DIP, "")
- ENTRYX(7474_dip, TTL_7474_DIP, "")
- ENTRYX(7475_dip, TTL_7475_DIP, "")
- ENTRYX(7477_dip, TTL_7477_DIP, "")
- ENTRYX(7483_dip, TTL_7483_DIP, "")
- ENTRYX(7485_dip, TTL_7485_DIP, "")
- ENTRYX(7490_dip, TTL_7490_DIP, "")
- ENTRYX(7493_dip, TTL_7493_DIP, "")
- ENTRYX(74107_dip, TTL_74107_DIP, "")
- ENTRYX(74123_dip, TTL_74123_DIP, "")
- ENTRYX(74153_dip, TTL_74153_DIP, "")
- ENTRYX(74161_dip, TTL_74161_DIP, "")
- ENTRYX(74164_dip, TTL_74164_DIP, "")
- ENTRYX(74165_dip, TTL_74165_DIP, "")
- ENTRYX(74166_dip, TTL_74166_DIP, "")
- ENTRYX(74174_dip, TTL_74174_DIP, "")
- ENTRYX(74175_dip, TTL_74175_DIP, "")
- ENTRYX(74192_dip, TTL_74192_DIP, "")
- ENTRYX(74193_dip, TTL_74193_DIP, "")
- ENTRYX(74194_dip, TTL_74194_DIP, "")
- ENTRYX(74365_dip, TTL_74365_DIP, "")
- ENTRYX(82S16_dip, TTL_82S16_DIP, "")
- ENTRYX(82S115_dip, PROM_82S115_DIP, "")
- ENTRYX(82S123_dip, PROM_82S123_DIP, "")
- ENTRYX(82S126_dip, PROM_82S126_DIP, "")
- ENTRYX(9602_dip, TTL_9602_DIP, "")
- ENTRYX(9310_dip, TTL_9310_DIP, "")
- ENTRYX(9314_dip, TTL_9314_DIP, "")
- ENTRYX(9316_dip, TTL_9316_DIP, "")
- ENTRYX(9322_dip, TTL_9322_DIP, "")
- ENTRYX(9334_dip, TTL_9334_DIP, "")
- ENTRYX(AM2847_dip, TTL_AM2847_DIP, "")
- ENTRYX(SN74LS629_dip, SN74LS629_DIP, "1.CAP1,2.CAP2")
- ENTRYX(NE555_dip, NE555_DIP, "")
- ENTRYX(MM5837_dip, MM5837_DIP, "")
-}
- } //namespace devices
+ void initialize_factory(factory::list_t &factory)
+ {
+ LIB_ENTRY(R)
+ LIB_ENTRY(POT)
+ LIB_ENTRY(POT2)
+ LIB_ENTRY(C)
+ LIB_ENTRY(L)
+ LIB_ENTRY(D)
+ LIB_ENTRY(VS)
+ LIB_ENTRY(CS)
+ LIB_ENTRY(VCVS)
+ LIB_ENTRY(VCCS)
+ LIB_ENTRY(CCCS)
+ LIB_ENTRY(LVCCS)
+ LIB_ENTRY(opamp)
+ LIB_ENTRY(dummy_input)
+ LIB_ENTRY(frontier) // not intended to be used directly
+ LIB_ENTRY(function) // only for macro devices - NO FEEDBACK loops
+ LIB_ENTRY(QBJT_EB)
+ LIB_ENTRY(QBJT_switch)
+ LIB_ENTRY(MOSFET)
+ LIB_ENTRY(logic_input_ttl)
+ LIB_ENTRY(logic_input)
+ LIB_ENTRY(analog_input)
+ LIB_ENTRY(log)
+ LIB_ENTRY(logD)
+ LIB_ENTRY(clock)
+ LIB_ENTRY(extclock)
+ LIB_ENTRY(mainclock)
+ LIB_ENTRY(gnd)
+ LIB_ENTRY(netlistparams)
+ LIB_ENTRY(solver)
+ LIB_ENTRY(res_sw)
+ LIB_ENTRY(switch1)
+ LIB_ENTRY(switch2)
+ LIB_ENTRY(nicRSFF)
+ LIB_ENTRY(nicDelay)
+ LIB_ENTRY(2102A)
+ LIB_ENTRY(2102A_dip)
+ LIB_ENTRY(2716)
+ LIB_ENTRY(2716_dip)
+ LIB_ENTRY(7448)
+ LIB_ENTRY(7448_dip)
+ LIB_ENTRY(7450)
+ LIB_ENTRY(7450_dip)
+ LIB_ENTRY(7473)
+ LIB_ENTRY(7473_dip)
+ LIB_ENTRY(7473A)
+ LIB_ENTRY(7473A_dip)
+ LIB_ENTRY(7474)
+ LIB_ENTRY(7474_dip)
+ LIB_ENTRY(7475)
+ LIB_ENTRY(7475_dip)
+ LIB_ENTRY(7477)
+ LIB_ENTRY(7477_dip)
+ LIB_ENTRY(7483)
+ LIB_ENTRY(7483_dip)
+ LIB_ENTRY(7485)
+ LIB_ENTRY(7485_dip)
+ LIB_ENTRY(7490)
+ LIB_ENTRY(7490_dip)
+ LIB_ENTRY(7493)
+ LIB_ENTRY(7493_dip)
+ LIB_ENTRY(7497)
+ LIB_ENTRY(7497_dip)
+ LIB_ENTRY(74107)
+ LIB_ENTRY(74107_dip)
+ LIB_ENTRY(74107A) // FIXME: implement missing DIP
+ LIB_ENTRY(74123)
+ LIB_ENTRY(74123_dip)
+ LIB_ENTRY(74153)
+ LIB_ENTRY(74153_dip)
+ LIB_ENTRY(74161)
+ LIB_ENTRY(74161_dip)
+ LIB_ENTRY(74164)
+ LIB_ENTRY(74164_dip)
+ LIB_ENTRY(74165)
+ LIB_ENTRY(74165_dip)
+ LIB_ENTRY(74166)
+ LIB_ENTRY(74166_dip)
+ LIB_ENTRY(74174)
+ LIB_ENTRY(74175)
+ LIB_ENTRY(74192)
+ LIB_ENTRY(74193)
+ LIB_ENTRY(74194)
+ LIB_ENTRY(74365)
+ //ENTRY(74279, TTL_74279, "") // only dip available
+ LIB_ENTRY(SN74LS629)
+ LIB_ENTRY(82S16)
+ LIB_ENTRY(82S115)
+ LIB_ENTRY(82S123)
+ LIB_ENTRY(82S126)
+ LIB_ENTRY(9310)
+ LIB_ENTRY(9314)
+ LIB_ENTRY(9316)
+ LIB_ENTRY(9322)
+ LIB_ENTRY(9334)
+ LIB_ENTRY(AM2847)
+ // FIXME: duplicate?
+ LIB_ENTRY(CD4020_WI)
+ LIB_ENTRY(CD4020)
+ LIB_ENTRY(CD4066_GATE)
+ LIB_ENTRY(CD4316_GATE)
+ LIB_ENTRY(4538_dip)
+ LIB_ENTRY(schmitt_trigger)
+ /* entries with suffix WI are legacy only */
+ //ENTRY(4066, CD_4066, "+A,B")
+ LIB_ENTRY(NE555)
+ LIB_ENTRY(NE555_dip)
+ LIB_ENTRY(MC1455P)
+ LIB_ENTRY(MC1455P_dip)
+ LIB_ENTRY(TMS4800)
+ LIB_ENTRY(TMS4800_dip)
+ LIB_ENTRY(r2r_dac)
+ LIB_ENTRY(tristate)
+ LIB_ENTRY(tristate3)
+ LIB_ENTRY(74174_dip)
+ LIB_ENTRY(74175_dip)
+ LIB_ENTRY(74192_dip)
+ LIB_ENTRY(74193_dip)
+ LIB_ENTRY(74194_dip)
+ LIB_ENTRY(74365_dip)
+ LIB_ENTRY(82S16_dip)
+ LIB_ENTRY(82S115_dip)
+ LIB_ENTRY(82S123_dip)
+ LIB_ENTRY(82S126_dip)
+ LIB_ENTRY(9602_dip)
+ LIB_ENTRY(9310_dip)
+ LIB_ENTRY(9314_dip)
+ LIB_ENTRY(9316_dip)
+ LIB_ENTRY(9322_dip)
+ LIB_ENTRY(9334_dip)
+ LIB_ENTRY(AM2847_dip)
+ LIB_ENTRY(SN74LS629_dip)
+ LIB_ENTRY(MM5837_dip)
+ }
+
+} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/net_lib.h b/src/lib/netlist/devices/net_lib.h
index 4dead624fc2..abf58ccee16 100644
--- a/src/lib/netlist/devices/net_lib.h
+++ b/src/lib/netlist/devices/net_lib.h
@@ -35,18 +35,8 @@
#include "nld_2102A.h"
#include "nld_2716.h"
-#include "nld_tms4800.h"
#include "nld_4020.h"
#include "nld_4066.h"
-#include "nld_7448.h"
-#include "nld_7450.h"
-#include "nld_7473.h"
-#include "nld_7474.h"
-#include "nld_7475.h"
-#include "nld_7483.h"
-#include "nld_7485.h"
-#include "nld_7490.h"
-#include "nld_7493.h"
#include "nld_74107.h"
#include "nld_74123.h"
#include "nld_74153.h"
@@ -60,21 +50,32 @@
#include "nld_74193.h"
#include "nld_74194.h"
#include "nld_74365.h"
+#include "nld_7448.h"
+#include "nld_7450.h"
+#include "nld_7473.h"
+#include "nld_7474.h"
+#include "nld_7475.h"
+#include "nld_7483.h"
+#include "nld_7485.h"
+#include "nld_7490.h"
+#include "nld_7493.h"
+#include "nld_7497.h"
#include "nld_74ls629.h"
-#include "nld_82S16.h"
#include "nld_82S115.h"
#include "nld_82S123.h"
#include "nld_82S126.h"
+#include "nld_82S16.h"
#include "nld_9310.h"
#include "nld_9316.h"
#include "nld_9322.h"
+#include "nld_tms4800.h"
#include "nld_am2847.h"
#include "nld_dm9314.h"
#include "nld_dm9334.h"
-#include "nld_ne555.h"
#include "nld_mm5837.h"
+#include "nld_ne555.h"
#include "nld_r2r_dac.h"
@@ -84,16 +85,17 @@
#include "nld_log.h"
-#include "../macro/nlm_cd4xxx.h"
-#include "../macro/nlm_ttl74xx.h"
-#include "../macro/nlm_opamp.h"
-#include "../macro/nlm_other.h"
-
-#include "../analog/nld_bjt.h"
-#include "../analog/nld_fourterm.h"
-#include "../analog/nld_switches.h"
-#include "../analog/nld_twoterm.h"
-#include "../analog/nld_opamps.h"
+#include "netlist/macro/nlm_cd4xxx.h"
+#include "netlist/macro/nlm_opamp.h"
+#include "netlist/macro/nlm_other.h"
+#include "netlist/macro/nlm_ttl74xx.h"
+
+#include "netlist/analog/nld_bjt.h"
+#include "netlist/analog/nld_fourterm.h"
+#include "netlist/analog/nld_mosfet.h"
+#include "netlist/analog/nld_opamps.h"
+#include "netlist/analog/nld_switches.h"
+#include "netlist/analog/nld_twoterm.h"
#include "nld_legacy.h"
#endif
diff --git a/src/lib/netlist/devices/nld_2102A.cpp b/src/lib/netlist/devices/nld_2102A.cpp
index 5296bf2d029..0ec7132b401 100644
--- a/src/lib/netlist/devices/nld_2102A.cpp
+++ b/src/lib/netlist/devices/nld_2102A.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_2102A.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
#define ADDR2BYTE(a) ((a) >> 3)
#define ADDR2BIT(a) ((a) & 0x7)
@@ -39,7 +39,7 @@ namespace netlist
logic_output_t m_DO;
- state_var<uint8_t[128]> m_ram; // 1024x1 bits
+ state_array<uint8_t, 128> m_ram; // 1024x1 bits
param_ptr_t m_RAM;
};
@@ -97,8 +97,8 @@ namespace netlist
m_ram[i] = 0;
}
- NETLIB_DEVICE_IMPL(2102A)
- NETLIB_DEVICE_IMPL(2102A_dip)
+ NETLIB_DEVICE_IMPL(2102A, "RAM_2102A", "+CEQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+RWQ,+DI")
+ NETLIB_DEVICE_IMPL(2102A_dip,"RAM_2102A_DIP","")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_2102A.h b/src/lib/netlist/devices/nld_2102A.h
index 52d892d4d40..aa53efde47d 100644
--- a/src/lib/netlist/devices/nld_2102A.h
+++ b/src/lib/netlist/devices/nld_2102A.h
@@ -24,7 +24,7 @@
#ifndef NLD_2102A_H_
#define NLD_2102A_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define RAM_2102A(name, cCEQ, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7, cA8, cA9, cRWQ, cDI) \
NET_REGISTER_DEV(RAM_2102A, name) \
diff --git a/src/lib/netlist/devices/nld_2716.cpp b/src/lib/netlist/devices/nld_2716.cpp
index cb53d60e205..b021bc95003 100644
--- a/src/lib/netlist/devices/nld_2716.cpp
+++ b/src/lib/netlist/devices/nld_2716.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_2716.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -92,8 +92,8 @@ namespace netlist
m_D[i].push((d >> i) & 1, delay);
}
- NETLIB_DEVICE_IMPL(2716)
- NETLIB_DEVICE_IMPL(2716_dip)
+ NETLIB_DEVICE_IMPL(2716, "EPROM_2716", "+GQ,+EPQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10")
+ NETLIB_DEVICE_IMPL(2716_dip, "EPROM_2716_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_2716.h b/src/lib/netlist/devices/nld_2716.h
index f4776242e6a..363086d6a37 100644
--- a/src/lib/netlist/devices/nld_2716.h
+++ b/src/lib/netlist/devices/nld_2716.h
@@ -28,7 +28,7 @@
#ifndef NLD_2716_H_
#define NLD_2716_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define EPROM_2716(name, cGQ, cEPQ, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7, cA8, cA9, cA10) \
NET_REGISTER_DEV(EPROM_2716, name) \
diff --git a/src/lib/netlist/devices/nld_4020.cpp b/src/lib/netlist/devices/nld_4020.cpp
index 8403d42bef2..13518f9d3cb 100644
--- a/src/lib/netlist/devices/nld_4020.cpp
+++ b/src/lib/netlist/devices/nld_4020.cpp
@@ -96,9 +96,9 @@ namespace netlist
m_sub.m_IP.activate_hl();
}
- inline NETLIB_FUNC_VOID(CD4020_sub, update_outputs, (const unsigned cnt))
+ NETLIB_FUNC_VOID(CD4020_sub, update_outputs, (const unsigned cnt))
{
- /* static */ const netlist_time out_delayQn[14] = {
+ static constexpr const std::array<netlist_time, 14> out_delayQn = {
NLTIME_FROM_NS(180), NLTIME_FROM_NS(280),
NLTIME_FROM_NS(380), NLTIME_FROM_NS(480),
NLTIME_FROM_NS(580), NLTIME_FROM_NS(680),
@@ -113,7 +113,8 @@ namespace netlist
m_Q[i].push((cnt >> i) & 1, out_delayQn[i]);
}
- NETLIB_DEVICE_IMPL(CD4020)
+ NETLIB_DEVICE_IMPL(CD4020, "CD4020", "")
+ NETLIB_DEVICE_IMPL_ALIAS(CD4020_WI, CD4020, "CD4020_WI", "+IP,+RESET,+VDD,+VSS")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_4020.h b/src/lib/netlist/devices/nld_4020.h
index fd6b234da46..f24251fb1dc 100644
--- a/src/lib/netlist/devices/nld_4020.h
+++ b/src/lib/netlist/devices/nld_4020.h
@@ -27,7 +27,7 @@
#ifndef NLD_4020_H_
#define NLD_4020_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
/* FIXME: only used in mario.c */
#define CD4020_WI(name, cIP, cRESET, cVDD, cVSS) \
diff --git a/src/lib/netlist/devices/nld_4066.cpp b/src/lib/netlist/devices/nld_4066.cpp
index ebd269a023a..0c7511ca438 100644
--- a/src/lib/netlist/devices/nld_4066.cpp
+++ b/src/lib/netlist/devices/nld_4066.cpp
@@ -5,10 +5,12 @@
*
*/
-#include "nlid_cmos.h"
-#include "../analog/nlid_twoterm.h"
#include "nld_4066.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/solver/nld_solver.h"
+#include "nlid_cmos.h"
+
namespace netlist
{
namespace devices
@@ -27,7 +29,7 @@ namespace netlist
NETLIB_RESETI();
NETLIB_UPDATEI();
- public:
+ private:
NETLIB_SUB(vdd_vss) m_supply;
analog::NETLIB_SUB(R_base) m_R;
@@ -39,45 +41,36 @@ namespace netlist
{
// Start in off condition
// FIXME: is ROFF correct?
- m_R.set_R(NL_FCONST(1.0) / netlist().gmin());
+ m_R.set_R(plib::constants<nl_double>::one() / exec().gmin());
}
NETLIB_UPDATE(CD4066_GATE)
{
nl_double sup = (m_supply.vdd() - m_supply.vss());
- nl_double low = NL_FCONST(0.45) * sup;
- nl_double high = NL_FCONST(0.55) * sup;
+ nl_double low = plib::constants<nl_double>::cast(0.45) * sup;
+ nl_double high = plib::constants<nl_double>::cast(0.55) * sup;
nl_double in = m_control() - m_supply.vss();
- nl_double rON = m_base_r() * NL_FCONST(5.0) / sup;
+ nl_double rON = m_base_r() * plib::constants<nl_double>::cast(5.0) / sup;
nl_double R = -1.0;
if (in < low)
{
- R = NL_FCONST(1.0) / netlist().gmin();
+ R = plib::constants<nl_double>::one() / exec().gmin();
}
else if (in > high)
{
R = rON;
}
- if (R > NL_FCONST(0.0))
+ if (R > plib::constants<nl_double>::zero())
{
- // We only need to update the net first if this is a time stepping net
- if ((1)) // m_R.m_P.net().as_analog().solver().is_timestep())
- {
- m_R.update_dev();
- m_R.set_R(R);
- m_R.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
- }
- else
- {
- m_R.set_R(R);
- m_R.update_dev();
- }
+ m_R.update();
+ m_R.set_R(R);
+ m_R.solve_later();
}
}
- NETLIB_DEVICE_IMPL(CD4066_GATE)
+ NETLIB_DEVICE_IMPL(CD4066_GATE, "CD4066_GATE", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_4066.h b/src/lib/netlist/devices/nld_4066.h
index e9fd579496c..d339464a108 100644
--- a/src/lib/netlist/devices/nld_4066.h
+++ b/src/lib/netlist/devices/nld_4066.h
@@ -24,7 +24,7 @@
#ifndef NLD_4066_H_
#define NLD_4066_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define CD4066_GATE(name) \
NET_REGISTER_DEV(CD4066_GATE, name)
diff --git a/src/lib/netlist/devices/nld_4316.cpp b/src/lib/netlist/devices/nld_4316.cpp
index b9758ff036b..c8ee1a90643 100644
--- a/src/lib/netlist/devices/nld_4316.cpp
+++ b/src/lib/netlist/devices/nld_4316.cpp
@@ -5,9 +5,10 @@
*
*/
-#include "nlid_cmos.h"
-#include "../analog/nlid_twoterm.h"
#include "nld_4316.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/solver/nld_solver.h"
+#include "nlid_cmos.h"
namespace netlist { namespace devices {
@@ -37,19 +38,20 @@ namespace netlist { namespace devices {
NETLIB_RESET(CD4316_GATE)
{
- m_R.set_R(NL_FCONST(1.0) / netlist().gmin());
+ m_R.set_R(plib::constants<nl_double>::one() / exec().gmin());
}
NETLIB_UPDATE(CD4316_GATE)
{
- m_R.update_dev();
+ m_R.update();
if (m_S() && !m_E())
m_R.set_R(m_base_r());
else
- m_R.set_R(NL_FCONST(1.0) / netlist().gmin());
- m_R.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
+ m_R.set_R(plib::constants<nl_double>::one() / exec().gmin());
+ m_R.solve_later(NLTIME_FROM_NS(1));
}
- NETLIB_DEVICE_IMPL(CD4316_GATE)
+ NETLIB_DEVICE_IMPL(CD4316_GATE, "CD4316_GATE", "")
-} } // namesapce netlist::devices
+} // namespace devices
+ } // namespace netlist
diff --git a/src/lib/netlist/devices/nld_4316.h b/src/lib/netlist/devices/nld_4316.h
index eb1d13f5542..278a2793a6f 100644
--- a/src/lib/netlist/devices/nld_4316.h
+++ b/src/lib/netlist/devices/nld_4316.h
@@ -25,7 +25,7 @@
#ifndef NLD_4316_H_
#define NLD_4316_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define CD4316_GATE(name) \
NET_REGISTER_DEV(CD4316_GATE, name)
diff --git a/src/lib/netlist/devices/nld_74107.cpp b/src/lib/netlist/devices/nld_74107.cpp
index c5a12a15fb4..763760e2c6a 100644
--- a/src/lib/netlist/devices/nld_74107.cpp
+++ b/src/lib/netlist/devices/nld_74107.cpp
@@ -6,15 +6,15 @@
*/
#include "nld_74107.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
namespace devices
{
- static constexpr netlist_time delay_107[2] = { NLTIME_FROM_NS(16), NLTIME_FROM_NS(25) };
- static constexpr netlist_time delay_107A[2] = { NLTIME_FROM_NS(15), NLTIME_FROM_NS(15) };
+ static constexpr const netlist_time delay_107[2] = { NLTIME_FROM_NS(16), NLTIME_FROM_NS(25) };
+ static constexpr const netlist_time delay_107A[2] = { NLTIME_FROM_NS(15), NLTIME_FROM_NS(15) };
NETLIB_OBJECT(74107A)
{
@@ -22,11 +22,12 @@ namespace netlist
, m_clk(*this, "CLK", NETLIB_DELEGATE(74107A, clk))
, m_Q(*this, "Q")
, m_QQ(*this, "QQ")
- , m_delay(delay_107A)
, m_J(*this, "J")
, m_K(*this, "K")
, m_clrQ(*this, "CLRQ")
{
+ m_delay[0] = delay_107A[0];
+ m_delay[1] = delay_107A[1];
}
friend class NETLIB_NAME(74107_dip);
@@ -43,7 +44,7 @@ namespace netlist
logic_output_t m_Q;
logic_output_t m_QQ;
- const netlist_time *m_delay;
+ netlist_time m_delay[2];
logic_input_t m_J;
logic_input_t m_K;
@@ -61,7 +62,8 @@ namespace netlist
public:
NETLIB_CONSTRUCTOR_DERIVED(74107, 74107A)
{
- m_delay = delay_107;
+ m_delay[0] = delay_107[0];
+ m_delay[1] = delay_107[1];
}
};
@@ -137,9 +139,9 @@ namespace netlist
m_clk.activate_hl();
}
- NETLIB_DEVICE_IMPL(74107)
- NETLIB_DEVICE_IMPL(74107A)
- NETLIB_DEVICE_IMPL(74107_dip)
+ NETLIB_DEVICE_IMPL(74107, "TTL_74107", "+CLK,+J,+K,+CLRQ")
+ NETLIB_DEVICE_IMPL(74107A, "TTL_74107A", "+CLK,+J,+K,+CLRQ")
+ NETLIB_DEVICE_IMPL(74107_dip, "TTL_74107_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74107.h b/src/lib/netlist/devices/nld_74107.h
index b59848cbb05..c6f8864610a 100644
--- a/src/lib/netlist/devices/nld_74107.h
+++ b/src/lib/netlist/devices/nld_74107.h
@@ -64,7 +64,7 @@
#ifndef NLD_74107_H_
#define NLD_74107_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74107A(name, cCLK, cJ, cK, cCLRQ) \
NET_REGISTER_DEV(TTL_74107A, name) \
diff --git a/src/lib/netlist/devices/nld_74123.cpp b/src/lib/netlist/devices/nld_74123.cpp
index 9055c5ce140..32e47a47ef2 100644
--- a/src/lib/netlist/devices/nld_74123.cpp
+++ b/src/lib/netlist/devices/nld_74123.cpp
@@ -6,7 +6,7 @@
*/
#include "nlid_system.h"
-#include "../analog/nlid_twoterm.h"
+#include "netlist/analog/nlid_twoterm.h"
#include <cmath>
@@ -257,8 +257,8 @@ namespace netlist
{
m_KP = 1.0 / (1.0 + exp(m_K()));
- m_RP.do_reset();
- m_RN.do_reset();
+ m_RP.reset();
+ m_RN.reset();
//m_RP.set_R(R_OFF);
//m_RN.set_R(R_OFF);
@@ -276,8 +276,8 @@ namespace netlist
NETLIB_RESET(74123_dip)
{
- //m_1.do_reset();
- //m_2.do_reset();
+ //m_1.reset();
+ //m_2.reset();
}
NETLIB_UPDATE(9602_dip)
@@ -289,8 +289,8 @@ namespace netlist
NETLIB_RESET(9602_dip)
{
- //m_1.do_reset();
- //m_2.do_reset();
+ //m_1.reset();
+ //m_2.reset();
}
NETLIB_UPDATE(4538_dip)
@@ -302,14 +302,14 @@ namespace netlist
NETLIB_RESET(4538_dip)
{
- m_1.do_reset();
- m_2.do_reset();
+ m_1.reset();
+ m_2.reset();
}
- NETLIB_DEVICE_IMPL(74123)
- NETLIB_DEVICE_IMPL(74123_dip)
- NETLIB_DEVICE_IMPL(4538_dip)
- NETLIB_DEVICE_IMPL(9602_dip)
+ NETLIB_DEVICE_IMPL(74123, "TTL_74123", "")
+ NETLIB_DEVICE_IMPL(74123_dip, "TTL_74123_DIP", "")
+ NETLIB_DEVICE_IMPL(4538_dip, "CD4538_DIP", "")
+ NETLIB_DEVICE_IMPL(9602_dip, "TTL_9602_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74123.h b/src/lib/netlist/devices/nld_74123.h
index dfd75f746c7..3eca141b613 100644
--- a/src/lib/netlist/devices/nld_74123.h
+++ b/src/lib/netlist/devices/nld_74123.h
@@ -49,7 +49,7 @@
#ifndef NLD_74123_H_
#define NLD_74123_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74123(name) \
NET_REGISTER_DEV(TTL_74123, name)
diff --git a/src/lib/netlist/devices/nld_74153.cpp b/src/lib/netlist/devices/nld_74153.cpp
index b74c09f8cc0..136fe61520b 100644
--- a/src/lib/netlist/devices/nld_74153.cpp
+++ b/src/lib/netlist/devices/nld_74153.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74153.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -120,19 +120,19 @@ namespace netlist
NETLIB_UPDATE(74153)
{
m_sub.m_chan = (m_A() | (m_B()<<1));
- m_sub.update_dev();
+ m_sub.update();
}
NETLIB_UPDATE(74153_dip)
{
m_2.m_chan = m_1.m_chan = (m_A() | (m_B()<<1));
- m_1.update_dev();
- m_2.update_dev();
+ m_1.update();
+ m_2.update();
}
- NETLIB_DEVICE_IMPL(74153)
- NETLIB_DEVICE_IMPL(74153_dip)
+ NETLIB_DEVICE_IMPL(74153, "TTL_74153", "+C0,+C1,+C2,+C3,+A,+B,+G")
+ NETLIB_DEVICE_IMPL(74153_dip, "TTL_74153_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74153.h b/src/lib/netlist/devices/nld_74153.h
index ee77d4224ce..f1c0f056cf7 100644
--- a/src/lib/netlist/devices/nld_74153.h
+++ b/src/lib/netlist/devices/nld_74153.h
@@ -45,7 +45,7 @@
#ifndef NLD_74153_H_
#define NLD_74153_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74153(name, cC0, cC1, cC2, cC3, cA, cB, cG) \
NET_REGISTER_DEV(TTL_74153, name) \
diff --git a/src/lib/netlist/devices/nld_74161.cpp b/src/lib/netlist/devices/nld_74161.cpp
index 5eb711fb456..7a3b54d6368 100644
--- a/src/lib/netlist/devices/nld_74161.cpp
+++ b/src/lib/netlist/devices/nld_74161.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74161.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -85,7 +85,7 @@ namespace netlist
}
// FIXME: Timing
- static constexpr netlist_time delay[4] =
+ static constexpr const netlist_time delay[4] =
{
NLTIME_FROM_NS(40),
NLTIME_FROM_NS(40),
@@ -126,8 +126,8 @@ namespace netlist
m_RCO.push(tRippleCarryOut, NLTIME_FROM_NS(20)); //FIXME
}
- NETLIB_DEVICE_IMPL(74161)
- NETLIB_DEVICE_IMPL(74161_dip)
+ NETLIB_DEVICE_IMPL(74161, "TTL_74161", "+A,+B,+C,+D,+CLRQ,+LOADQ,+CLK,+ENABLEP,+ENABLET")
+ NETLIB_DEVICE_IMPL(74161_dip, "TTL_74161_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74161.h b/src/lib/netlist/devices/nld_74161.h
index 363bc3c7f0d..f3fa3eab043 100644
--- a/src/lib/netlist/devices/nld_74161.h
+++ b/src/lib/netlist/devices/nld_74161.h
@@ -25,7 +25,7 @@
#ifndef NLD_74161_H_
#define NLD_74161_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74161(name, cA, cB, cC, cD, cCLRQ, cLOADQ, cCLK, cENABLEP, cENABLET) \
NET_REGISTER_DEV(TTL_74161, name) \
diff --git a/src/lib/netlist/devices/nld_74164.cpp b/src/lib/netlist/devices/nld_74164.cpp
index 5b2b1d8d080..b1eb30bb1ba 100644
--- a/src/lib/netlist/devices/nld_74164.cpp
+++ b/src/lib/netlist/devices/nld_74164.cpp
@@ -9,7 +9,7 @@
*/
#include "nld_74164.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -97,8 +97,8 @@ namespace netlist
}
}
- NETLIB_DEVICE_IMPL(74164)
- NETLIB_DEVICE_IMPL(74164_dip)
+ NETLIB_DEVICE_IMPL(74164, "TTL_74164", "+A,+B,+CLRQ,+CLK")
+ NETLIB_DEVICE_IMPL(74164_dip, "TTL_74164_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74164.h b/src/lib/netlist/devices/nld_74164.h
index d7f29d386de..dd4e6bd1303 100644
--- a/src/lib/netlist/devices/nld_74164.h
+++ b/src/lib/netlist/devices/nld_74164.h
@@ -42,7 +42,7 @@
#ifndef NLD_74164_H_
#define NLD_74164_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74164(name, cA, cB, cCLRQ, cCLK) \
NET_REGISTER_DEV(TTL_74164, name) \
diff --git a/src/lib/netlist/devices/nld_74165.cpp b/src/lib/netlist/devices/nld_74165.cpp
index 678c1b1782e..521bf4d63d2 100644
--- a/src/lib/netlist/devices/nld_74165.cpp
+++ b/src/lib/netlist/devices/nld_74165.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74165.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -86,6 +86,7 @@ namespace netlist
}
else if (!m_CLK() || m_CLKINH())
{
+ // FIXME: qh is overwritten below?
qh = old_qh;
}
else if (!m_last_CLK)
@@ -101,8 +102,8 @@ namespace netlist
m_QH.push(qh, NLTIME_FROM_NS(20)); // FIXME: Timing
}
- NETLIB_DEVICE_IMPL(74165)
- NETLIB_DEVICE_IMPL(74165_dip)
+ NETLIB_DEVICE_IMPL(74165, "TTL_74165", "+CLK,+CLKINH,+SH_LDQ,+SER,+A,+B,+C,+D,+E,+F,+G,+H")
+ NETLIB_DEVICE_IMPL(74165_dip, "TTL_74165_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74165.h b/src/lib/netlist/devices/nld_74165.h
index e38ca7bab86..d282bab622b 100644
--- a/src/lib/netlist/devices/nld_74165.h
+++ b/src/lib/netlist/devices/nld_74165.h
@@ -27,7 +27,7 @@
#ifndef NLD_74165_H_
#define NLD_74165_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74165(name, cCLK, cCLKINH, cSH_LDQ, cSER, cA, cB, cC, cD, cE, cF, cG, cH) \
NET_REGISTER_DEV(TTL_74165, name) \
diff --git a/src/lib/netlist/devices/nld_74166.cpp b/src/lib/netlist/devices/nld_74166.cpp
index 32f075c4da5..a5049014576 100644
--- a/src/lib/netlist/devices/nld_74166.cpp
+++ b/src/lib/netlist/devices/nld_74166.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74166.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -121,8 +121,8 @@ namespace netlist
m_QH.push(qh, delay); //FIXME
}
- NETLIB_DEVICE_IMPL(74166)
- NETLIB_DEVICE_IMPL(74166_dip)
+ NETLIB_DEVICE_IMPL(74166, "TTL_74166", "+CLK,+CLKINH,+SH_LDQ,+SER,+A,+B,+C,+D,+E,+F,+G,+H,+CLRQ")
+ NETLIB_DEVICE_IMPL(74166_dip,"TTL_74166_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74166.h b/src/lib/netlist/devices/nld_74166.h
index b8a8a204374..80c86bb3422 100644
--- a/src/lib/netlist/devices/nld_74166.h
+++ b/src/lib/netlist/devices/nld_74166.h
@@ -27,7 +27,7 @@
#ifndef NLD_74166_H_
#define NLD_74166_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74166(name, cCLK, cCLKINH, cSH_LDQ, cSER, cA, cB, cC, cD, cE, cF, cG, cH, cCLRQ) \
NET_REGISTER_DEV(TTL_74166, name) \
diff --git a/src/lib/netlist/devices/nld_74174.cpp b/src/lib/netlist/devices/nld_74174.cpp
index 5f4573942bd..83369075db6 100644
--- a/src/lib/netlist/devices/nld_74174.cpp
+++ b/src/lib/netlist/devices/nld_74174.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74174.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -134,8 +134,8 @@ namespace netlist
//m_sub.do_reset();
}
- NETLIB_DEVICE_IMPL(74174)
- NETLIB_DEVICE_IMPL(74174_dip)
+ NETLIB_DEVICE_IMPL(74174, "TTL_74174", "+CLK,+D1,+D2,+D3,+D4,+D5,+D6,+CLRQ")
+ NETLIB_DEVICE_IMPL(74174_dip,"TTL_74174_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74174.h b/src/lib/netlist/devices/nld_74174.h
index 66824abb7aa..f1854801291 100644
--- a/src/lib/netlist/devices/nld_74174.h
+++ b/src/lib/netlist/devices/nld_74174.h
@@ -36,7 +36,7 @@
#ifndef NLD_74174_H_
#define NLD_74174_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74174(name, cCLK, cD1, cD2, cD3, cD4, cD5, cD6, cCLRQ) \
NET_REGISTER_DEV(TTL_74174, name) \
diff --git a/src/lib/netlist/devices/nld_74175.cpp b/src/lib/netlist/devices/nld_74175.cpp
index 5955bcb389e..a15adb5c60f 100644
--- a/src/lib/netlist/devices/nld_74175.cpp
+++ b/src/lib/netlist/devices/nld_74175.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74175.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -111,8 +111,8 @@ namespace netlist
m_data = 0xFF;
}
- NETLIB_DEVICE_IMPL(74175)
- NETLIB_DEVICE_IMPL(74175_dip)
+ NETLIB_DEVICE_IMPL(74175, "TTL_74175", "+CLK,+D1,+D2,+D3,+D4,+CLRQ")
+ NETLIB_DEVICE_IMPL(74175_dip,"TTL_74175_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74175.h b/src/lib/netlist/devices/nld_74175.h
index 27e01b55b05..4bc8c1175ba 100644
--- a/src/lib/netlist/devices/nld_74175.h
+++ b/src/lib/netlist/devices/nld_74175.h
@@ -36,7 +36,7 @@
#ifndef NLD_74175_H_
#define NLD_74175_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74175(name, cCLK, cD1, cD2, cD3, cD4, cCLRQ) \
NET_REGISTER_DEV(TTL_74175, name) \
diff --git a/src/lib/netlist/devices/nld_74192.cpp b/src/lib/netlist/devices/nld_74192.cpp
index 1af605d4776..954fc351179 100644
--- a/src/lib/netlist/devices/nld_74192.cpp
+++ b/src/lib/netlist/devices/nld_74192.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74192.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -110,7 +110,7 @@ namespace netlist
}
// FIXME: Timing
- static constexpr netlist_time delay[4] =
+ static constexpr const netlist_time delay[4] =
{
NLTIME_FROM_NS(40),
NLTIME_FROM_NS(40),
@@ -162,8 +162,8 @@ namespace netlist
m_CARRYQ.push(tCarry, NLTIME_FROM_NS(20)); //FIXME
}
- NETLIB_DEVICE_IMPL(74192)
- NETLIB_DEVICE_IMPL(74192_dip)
+ NETLIB_DEVICE_IMPL(74192, "TTL_74192", "+A,+B,+C,+D,+CLEAR,+LOADQ,+CU,+CD")
+ NETLIB_DEVICE_IMPL(74192_dip,"TTL_74192_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74192.h b/src/lib/netlist/devices/nld_74192.h
index 613d463cf47..9b0139070b8 100644
--- a/src/lib/netlist/devices/nld_74192.h
+++ b/src/lib/netlist/devices/nld_74192.h
@@ -29,7 +29,7 @@
#ifndef NLD_74192_H_
#define NLD_74192_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74192(name, cA, cB, cC, cD, cCLEAR, cLOADQ, cCU, cCD) \
NET_REGISTER_DEV(TTL_74192, name) \
diff --git a/src/lib/netlist/devices/nld_74193.cpp b/src/lib/netlist/devices/nld_74193.cpp
index 55d18f3dc1b..16d7438d799 100644
--- a/src/lib/netlist/devices/nld_74193.cpp
+++ b/src/lib/netlist/devices/nld_74193.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74193.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -87,7 +87,7 @@ namespace netlist
}
// FIXME: Timing
- static constexpr netlist_time delay[4] =
+ static constexpr const netlist_time delay[4] =
{
NLTIME_FROM_NS(40),
NLTIME_FROM_NS(40),
@@ -139,8 +139,8 @@ namespace netlist
m_CARRYQ.push(tCarry, NLTIME_FROM_NS(20)); //FIXME timing
}
- NETLIB_DEVICE_IMPL(74193)
- NETLIB_DEVICE_IMPL(74193_dip)
+ NETLIB_DEVICE_IMPL(74193, "TTL_74193", "+A,+B,+C,+D,+CLEAR,+LOADQ,+CU,+CD")
+ NETLIB_DEVICE_IMPL(74193_dip, "TTL_74193_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74193.h b/src/lib/netlist/devices/nld_74193.h
index bb14a301f38..a4c745d5386 100644
--- a/src/lib/netlist/devices/nld_74193.h
+++ b/src/lib/netlist/devices/nld_74193.h
@@ -26,7 +26,7 @@
#ifndef NLD_74193_H_
#define NLD_74193_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74193(name, cA, cB, cC, cD, cCLEAR, cLOADQ, cCU, cCD) \
NET_REGISTER_DEV(TTL_74193, name) \
diff --git a/src/lib/netlist/devices/nld_74194.cpp b/src/lib/netlist/devices/nld_74194.cpp
index d531e792885..9876aa6b170 100644
--- a/src/lib/netlist/devices/nld_74194.cpp
+++ b/src/lib/netlist/devices/nld_74194.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_74194.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -116,8 +116,8 @@ namespace netlist
m_Q[i].push((q >> i) & 1, NLTIME_FROM_NS(26)); // FIXME: Timing
}
- NETLIB_DEVICE_IMPL(74194)
- NETLIB_DEVICE_IMPL(74194_dip)
+ NETLIB_DEVICE_IMPL(74194, "TTL_74194", "+CLK,+S0,+S1,+SRIN,+A,+B,+C,+D,+SLIN,+CLRQ")
+ NETLIB_DEVICE_IMPL(74194_dip, "TTL_74194_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74194.h b/src/lib/netlist/devices/nld_74194.h
index 5124a66bcc0..5a507982b81 100644
--- a/src/lib/netlist/devices/nld_74194.h
+++ b/src/lib/netlist/devices/nld_74194.h
@@ -26,7 +26,7 @@
#ifndef NLD_74194_H_
#define NLD_74194_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74194(name, cCLK, cS0, cS1, cSRIN, cA, cB, cC, cD, cSLIN, cCLRQ) \
NET_REGISTER_DEV(TTL_74194, name) \
diff --git a/src/lib/netlist/devices/nld_74365.cpp b/src/lib/netlist/devices/nld_74365.cpp
index 10456ebbc21..753f16bfd22 100644
--- a/src/lib/netlist/devices/nld_74365.cpp
+++ b/src/lib/netlist/devices/nld_74365.cpp
@@ -6,12 +6,20 @@
*/
#include "nld_74365.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
namespace devices
{
+
+ /* FIXME: This should be a single device, i.e. one tristate buffer only.
+ *
+ * FIXME: Implement tristate output.
+ *
+ */
+
+
NETLIB_OBJECT(74365)
{
NETLIB_CONSTRUCTOR(74365)
@@ -68,8 +76,8 @@ namespace netlist
}
}
- NETLIB_DEVICE_IMPL(74365)
- NETLIB_DEVICE_IMPL(74365_dip)
+ NETLIB_DEVICE_IMPL(74365, "TTL_74365", "+G1Q,+G2Q,+A1,+A2,+A3,+A4,+A5,+A6")
+ NETLIB_DEVICE_IMPL(74365_dip, "TTL_74365_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74365.h b/src/lib/netlist/devices/nld_74365.h
index ca0eacf6ba1..a50b535383f 100644
--- a/src/lib/netlist/devices/nld_74365.h
+++ b/src/lib/netlist/devices/nld_74365.h
@@ -25,7 +25,7 @@
#ifndef NLD_74365_H_
#define NLD_74365_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_74365(name, cG1Q, cG2Q, cA1, cA2, cA3, cA4, cA5, cA6) \
NET_REGISTER_DEV(TTL_74365, name) \
diff --git a/src/lib/netlist/devices/nld_7448.cpp b/src/lib/netlist/devices/nld_7448.cpp
index cc2e60f23b7..4500229a1c5 100644
--- a/src/lib/netlist/devices/nld_7448.cpp
+++ b/src/lib/netlist/devices/nld_7448.cpp
@@ -5,8 +5,10 @@
*
*/
-#include "nlid_truthtable.h"
#include "nld_7448.h"
+#include "nlid_truthtable.h"
+
+#include <array>
namespace netlist
{
@@ -133,9 +135,9 @@ namespace netlist
#else
-#define BITS7(b6,b5,b4,b3,b2,b1,b0) (b6<<6) | (b5<<5) | (b4<<4) | (b3<<3) | (b2<<2) | (b1<<1) | (b0<<0)
+#define BITS7(b6,b5,b4,b3,b2,b1,b0) ((b6)<<6) | ((b5)<<5) | ((b4)<<4) | ((b3)<<3) | ((b2)<<2) | ((b1)<<1) | ((b0)<<0)
- static constexpr uint8_t tab7448[16] =
+ static constexpr const std::array<uint8_t, 16> tab7448 =
{
BITS7( 1, 1, 1, 1, 1, 1, 0 ), /* 00 - not blanked ! */
BITS7( 0, 1, 1, 0, 0, 0, 0 ), /* 01 */
@@ -188,11 +190,13 @@ namespace netlist
NETLIB_RESET(7448)
{
m_state = 0;
- m_A.inactivate();
- m_B.inactivate();
- m_C.inactivate();
- m_D.inactivate();
- m_RBIQ.inactivate();
+#if 0
+ m_A.set_state(logic_t::STATE_INP_PASSIVE);
+ m_B.set_state(logic_t::STATE_INP_PASSIVE);
+ m_C.set_state(logic_t::STATE_INP_PASSIVE);
+ m_D.set_state(logic_t::STATE_INP_PASSIVE);
+ m_RBIQ.set_state(logic_t::STATE_INP_PASSIVE);
+#endif
}
NETLIB_FUNC_VOID(7448, update_outputs, (unsigned v))
@@ -211,8 +215,8 @@ namespace netlist
#endif
- NETLIB_DEVICE_IMPL(7448)
- NETLIB_DEVICE_IMPL(7448_dip)
+ NETLIB_DEVICE_IMPL(7448, "TTL_7448", "+A,+B,+C,+D,+LTQ,+BIQ,+RBIQ")
+ NETLIB_DEVICE_IMPL(7448_dip, "TTL_7448_DIP", "")
} //namespace devices
diff --git a/src/lib/netlist/devices/nld_7448.h b/src/lib/netlist/devices/nld_7448.h
index 89528707bc1..b9c03ae6360 100644
--- a/src/lib/netlist/devices/nld_7448.h
+++ b/src/lib/netlist/devices/nld_7448.h
@@ -24,7 +24,7 @@
#ifndef NLD_7448_H_
#define NLD_7448_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#ifndef NL_AUTO_DEVICES
diff --git a/src/lib/netlist/devices/nld_7450.cpp b/src/lib/netlist/devices/nld_7450.cpp
index af9b9afada1..aacab46a021 100644
--- a/src/lib/netlist/devices/nld_7450.cpp
+++ b/src/lib/netlist/devices/nld_7450.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_7450.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -68,10 +68,10 @@ namespace netlist
m_B.activate();
m_C.activate();
m_D.activate();
- unsigned t1 = m_A() & m_B();
- unsigned t2 = m_C() & m_D();
+ auto t1 = m_A() & m_B();
+ auto t2 = m_C() & m_D();
- const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) };
+ const netlist_time times[2] = { NLTIME_FROM_NS(15), NLTIME_FROM_NS(22) };
uint_fast8_t res = 0;
if (t1 ^ 1)
@@ -85,18 +85,20 @@ namespace netlist
m_A.inactivate();
m_B.inactivate();
}
- } else {
+ }
+ else
+ {
if (t2 ^ 1)
{
m_C.inactivate();
m_D.inactivate();
}
}
- m_Q.push(res, times[1 - res]);// ? 22000 : 15000);
+ m_Q.push(res, times[res]);// ? 22000 : 15000);
}
- NETLIB_DEVICE_IMPL(7450)
- NETLIB_DEVICE_IMPL(7450_dip)
+ NETLIB_DEVICE_IMPL(7450, "TTL_7450_ANDORINVERT", "+A,+B,+C,+D")
+ NETLIB_DEVICE_IMPL(7450_dip, "TTL_7450_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7450.h b/src/lib/netlist/devices/nld_7450.h
index 652516758ad..6718afd8f9e 100644
--- a/src/lib/netlist/devices/nld_7450.h
+++ b/src/lib/netlist/devices/nld_7450.h
@@ -24,7 +24,7 @@
#ifndef NLD_7450_H_
#define NLD_7450_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7450_ANDORINVERT(name, cI1, cI2, cI3, cI4) \
NET_REGISTER_DEV(TTL_7450_ANDORINVERT, name) \
diff --git a/src/lib/netlist/devices/nld_7473.cpp b/src/lib/netlist/devices/nld_7473.cpp
index d9efb9fb710..c8abd829264 100644
--- a/src/lib/netlist/devices/nld_7473.cpp
+++ b/src/lib/netlist/devices/nld_7473.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_7473.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -142,10 +142,10 @@ namespace netlist
m_QQ.push(m_q ^ 1, NLTIME_FROM_NS(20)); // FIXME: timing
}
- NETLIB_DEVICE_IMPL(7473)
- NETLIB_DEVICE_IMPL(7473A)
- NETLIB_DEVICE_IMPL(7473_dip)
- NETLIB_DEVICE_IMPL(7473A_dip)
+ NETLIB_DEVICE_IMPL(7473, "TTL_7473", "+CLK,+J,+K,+CLRQ")
+ NETLIB_DEVICE_IMPL(7473A, "TTL_7473A", "+CLK,+J,+K,+CLRQ")
+ NETLIB_DEVICE_IMPL(7473_dip, "TTL_7473_DIP", "")
+ NETLIB_DEVICE_IMPL(7473A_dip, "TTL_7473A_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7473.h b/src/lib/netlist/devices/nld_7473.h
index 5313d18570c..3fbaaf4efbc 100644
--- a/src/lib/netlist/devices/nld_7473.h
+++ b/src/lib/netlist/devices/nld_7473.h
@@ -60,7 +60,7 @@
#ifndef NLD_7473_H_
#define NLD_7473_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7473(name, cCLK, cJ, cK, cCLRQ) \
NET_REGISTER_DEV(TTL_7473, name) \
diff --git a/src/lib/netlist/devices/nld_7474.cpp b/src/lib/netlist/devices/nld_7474.cpp
index 9d020663f46..740af6ad3c1 100644
--- a/src/lib/netlist/devices/nld_7474.cpp
+++ b/src/lib/netlist/devices/nld_7474.cpp
@@ -1,3 +1,4 @@
+
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
@@ -6,60 +7,47 @@
*/
#include "nld_7474.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
namespace devices
{
- NETLIB_OBJECT(7474sub)
+
+ NETLIB_OBJECT(7474)
{
- NETLIB_CONSTRUCTOR(7474sub)
- , m_CLK(*this, "CLK")
+ NETLIB_CONSTRUCTOR(7474)
+ , m_D(*this, "D")
+ , m_CLRQ(*this, "CLRQ")
+ , m_PREQ(*this, "PREQ")
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(7474, clk))
, m_Q(*this, "Q")
, m_QQ(*this, "QQ")
, m_nextD(*this, "m_nextD", 0)
{
}
+ private:
NETLIB_RESETI();
NETLIB_UPDATEI();
+ NETLIB_HANDLERI(clk);
- public:
+ logic_input_t m_D;
+ logic_input_t m_CLRQ;
+ logic_input_t m_PREQ;
logic_input_t m_CLK;
logic_output_t m_Q;
logic_output_t m_QQ;
- state_var<unsigned> m_nextD;
-
- inline void newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ);
- private:
-
- };
+ state_var<netlist_sig_t> m_nextD;
- NETLIB_OBJECT(7474)
- {
- NETLIB_CONSTRUCTOR(7474)
- , sub(*this, "sub")
- , m_D(*this, "D")
- , m_CLRQ(*this, "CLRQ")
- , m_PREQ(*this, "PREQ")
+ void newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ)
{
- register_subalias("CLK", sub.m_CLK);
-
- register_subalias("Q", sub.m_Q);
- register_subalias("QQ", sub.m_QQ);
+ // 0: High-to-low 40 ns, 1: Low-to-high 25 ns
+ static constexpr const netlist_time delay[2] = { NLTIME_FROM_NS(40), NLTIME_FROM_NS(25) };
+ m_Q.push(stateQ, delay[stateQ]);
+ m_QQ.push(stateQQ, delay[stateQQ]);
}
-
- NETLIB_RESETI();
- NETLIB_UPDATEI();
-
- public:
- NETLIB_SUB(7474sub) sub;
-
- logic_input_t m_D;
- logic_input_t m_CLRQ;
- logic_input_t m_PREQ;
};
NETLIB_OBJECT(7474_dip)
@@ -68,20 +56,20 @@ namespace netlist
, m_1(*this, "1")
, m_2(*this, "2")
{
- register_subalias("1", m_1.m_CLRQ);
- register_subalias("2", m_1.m_D);
- register_subalias("3", m_1.sub.m_CLK);
- register_subalias("4", m_1.m_PREQ);
- register_subalias("5", m_1.sub.m_Q);
- register_subalias("6", m_1.sub.m_QQ);
+ register_subalias("1", "1.CLRQ");
+ register_subalias("2", "1.D");
+ register_subalias("3", "1.CLK");
+ register_subalias("4", "1.PREQ");
+ register_subalias("5", "1.Q");
+ register_subalias("6", "1.QQ");
// register_subalias("7", ); ==> GND
- register_subalias("8", m_2.sub.m_QQ);
- register_subalias("9", m_2.sub.m_Q);
- register_subalias("10", m_2.m_PREQ);
- register_subalias("11", m_2.sub.m_CLK);
- register_subalias("12", m_2.m_D);
- register_subalias("13", m_2.m_CLRQ);
+ register_subalias("8", "2.QQ");
+ register_subalias("9", "2.Q");
+ register_subalias("10", "2.PREQ");
+ register_subalias("11", "2.CLK");
+ register_subalias("12", "2.D");
+ register_subalias("13", "2.CLRQ");
// register_subalias("14", ); ==> VCC
}
NETLIB_UPDATEI();
@@ -92,77 +80,47 @@ namespace netlist
NETLIB_SUB(7474) m_2;
};
- inline void NETLIB_NAME(7474sub)::newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ)
+ NETLIB_HANDLER(7474, clk)
{
- // 0: High-to-low 40 ns, 1: Low-to-high 25 ns
- const netlist_time delay[2] = { NLTIME_FROM_NS(40), NLTIME_FROM_NS(25) };
- m_Q.push(stateQ, delay[stateQ]);
- m_QQ.push(stateQQ, delay[stateQQ]);
- }
-
- NETLIB_UPDATE(7474sub)
- {
- //if (INP_LH(m_CLK))
- {
- newstate(m_nextD, !m_nextD);
- m_CLK.inactivate();
- }
+ newstate(m_nextD, !m_nextD);
+ m_CLK.inactivate();
}
NETLIB_UPDATE(7474)
{
- if (m_PREQ() && m_CLRQ())
+ const auto preq(m_PREQ());
+ const auto clrq(m_CLRQ());
+ if (preq & clrq)
{
m_D.activate();
- sub.m_nextD = m_D();
- sub.m_CLK.activate_lh();
- }
- else if (!m_PREQ())
- {
- sub.newstate(1, 0);
- sub.m_CLK.inactivate();
- m_D.inactivate();
- }
- else if (!m_CLRQ())
- {
- sub.newstate(0, 1);
- sub.m_CLK.inactivate();
- m_D.inactivate();
+ m_nextD = m_D();
+ m_CLK.activate_lh();
}
else
{
- sub.newstate(1, 1);
- sub.m_CLK.inactivate();
+ newstate(preq ^ 1, clrq ^ 1);
+ m_CLK.inactivate();
m_D.inactivate();
}
}
NETLIB_RESET(7474)
{
- sub.do_reset();
- }
-
- NETLIB_RESET(7474sub)
- {
m_CLK.set_state(logic_t::STATE_INP_LH);
-
+ m_D.set_state(logic_t::STATE_INP_ACTIVE);
m_nextD = 0;
}
NETLIB_RESET(7474_dip)
{
- // m_1.do_reset();
- //m_2.do_reset();
}
NETLIB_UPDATE(7474_dip)
{
- //m_1.update_dev();
- //m_2.update_dev();
}
- NETLIB_DEVICE_IMPL(7474)
- NETLIB_DEVICE_IMPL(7474_dip)
+ NETLIB_DEVICE_IMPL(7474, "TTL_7474", "+CLK,+D,+CLRQ,+PREQ")
+ NETLIB_DEVICE_IMPL(7474_dip, "TTL_7474_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7474.h b/src/lib/netlist/devices/nld_7474.h
index aa48e240387..48fd4f3d842 100644
--- a/src/lib/netlist/devices/nld_7474.h
+++ b/src/lib/netlist/devices/nld_7474.h
@@ -42,7 +42,7 @@
#ifndef NLD_7474_H_
#define NLD_7474_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7474(name, cCLK, cD, cCLRQ, cPREQ) \
NET_REGISTER_DEV(TTL_7474, name) \
diff --git a/src/lib/netlist/devices/nld_7475.cpp b/src/lib/netlist/devices/nld_7475.cpp
index b2d28048513..63fd355d406 100644
--- a/src/lib/netlist/devices/nld_7475.cpp
+++ b/src/lib/netlist/devices/nld_7475.cpp
@@ -7,7 +7,7 @@
*/
#include "nld_7475.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -101,7 +101,7 @@ namespace netlist
{
unsigned start_q = m_last_Q;
- NETLIB_PARENT_UPDATE(7477);
+ NETLIB_NAME(7477)::update();
for (std::size_t i=0; i<4; i++)
{
@@ -148,10 +148,10 @@ namespace netlist
}
- NETLIB_DEVICE_IMPL(7475)
- NETLIB_DEVICE_IMPL(7475_dip)
- NETLIB_DEVICE_IMPL(7477)
- NETLIB_DEVICE_IMPL(7477_dip)
+ NETLIB_DEVICE_IMPL(7475, "TTL_7475", "")
+ NETLIB_DEVICE_IMPL(7475_dip, "TTL_7475_DIP", "")
+ NETLIB_DEVICE_IMPL(7477, "TTL_7477", "")
+ NETLIB_DEVICE_IMPL(7477_dip, "TTL_7477_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7475.h b/src/lib/netlist/devices/nld_7475.h
index 51d09e75a66..b16fabe61b6 100644
--- a/src/lib/netlist/devices/nld_7475.h
+++ b/src/lib/netlist/devices/nld_7475.h
@@ -35,7 +35,7 @@
#ifndef NLD_7475_H_
#define NLD_7475_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define PARAMS_7475_7477(name, cC1C2, cC3C4, cD1, cD2, cD3, cD4) \
NET_CONNECT(name, C1C2, cC1C2) \
diff --git a/src/lib/netlist/devices/nld_7483.cpp b/src/lib/netlist/devices/nld_7483.cpp
index 72c86c003d5..5f820162209 100644
--- a/src/lib/netlist/devices/nld_7483.cpp
+++ b/src/lib/netlist/devices/nld_7483.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_7483.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -16,14 +16,16 @@ namespace netlist
{
NETLIB_CONSTRUCTOR(7483)
, m_C0(*this, "C0")
- , m_A1(*this, "A1")
- , m_A2(*this, "A2")
- , m_A3(*this, "A3")
- , m_A4(*this, "A4")
- , m_B1(*this, "B1")
- , m_B2(*this, "B2")
- , m_B3(*this, "B3")
- , m_B4(*this, "B4")
+ , m_A1(*this, "A1", NETLIB_DELEGATE(7483, upd_a))
+ , m_A2(*this, "A2", NETLIB_DELEGATE(7483, upd_a))
+ , m_A3(*this, "A3", NETLIB_DELEGATE(7483, upd_a))
+ , m_A4(*this, "A4", NETLIB_DELEGATE(7483, upd_a))
+ , m_B1(*this, "B1", NETLIB_DELEGATE(7483, upd_b))
+ , m_B2(*this, "B2", NETLIB_DELEGATE(7483, upd_b))
+ , m_B3(*this, "B3", NETLIB_DELEGATE(7483, upd_b))
+ , m_B4(*this, "B4", NETLIB_DELEGATE(7483, upd_b))
+ , m_a(*this, "m_a", 0)
+ , m_b(*this, "m_b", 0)
, m_lastr(*this, "m_lastr", 0)
, m_S1(*this, "S1")
, m_S2(*this, "S2")
@@ -34,6 +36,8 @@ namespace netlist
}
NETLIB_RESETI();
NETLIB_UPDATEI();
+ NETLIB_HANDLERI(upd_a);
+ NETLIB_HANDLERI(upd_b);
protected:
logic_input_t m_C0;
@@ -46,7 +50,9 @@ namespace netlist
logic_input_t m_B3;
logic_input_t m_B4;
- state_var<unsigned> m_lastr;
+ state_var_u8 m_a;
+ state_var_u8 m_b;
+ state_var_u8 m_lastr;
logic_output_t m_S1;
logic_output_t m_S2;
@@ -87,12 +93,21 @@ namespace netlist
m_lastr = 0;
}
- NETLIB_UPDATE(7483)
+ NETLIB_HANDLER(7483, upd_a)
{
- netlist_sig_t a = (m_A1() << 0) | (m_A2() << 1) | (m_A3() << 2) | (m_A4() << 3);
- netlist_sig_t b = (m_B1() << 0) | (m_B2() << 1) | (m_B3() << 2) | (m_B4() << 3);
+ m_a = static_cast<uint8_t>((m_A1() << 0) | (m_A2() << 1) | (m_A3() << 2) | (m_A4() << 3));
+ NETLIB_NAME(7483)::update();
+ }
- unsigned r = a + b + m_C0();
+ NETLIB_HANDLER(7483, upd_b)
+ {
+ m_b = static_cast<uint8_t>((m_B1() << 0) | (m_B2() << 1) | (m_B3() << 2) | (m_B4() << 3));
+ NETLIB_NAME(7483)::update();
+ }
+
+ NETLIB_UPDATE(7483)
+ {
+ auto r = static_cast<uint8_t>(m_a + m_b + m_C0());
if (r != m_lastr)
{
@@ -105,8 +120,8 @@ namespace netlist
}
}
- NETLIB_DEVICE_IMPL(7483)
- NETLIB_DEVICE_IMPL(7483_dip)
+ NETLIB_DEVICE_IMPL(7483, "TTL_7483", "+A1,+A2,+A3,+A4,+B1,+B2,+B3,+B4,+C0")
+ NETLIB_DEVICE_IMPL(7483_dip, "TTL_7483_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7483.h b/src/lib/netlist/devices/nld_7483.h
index 24952bf0501..ba82d5bbb9c 100644
--- a/src/lib/netlist/devices/nld_7483.h
+++ b/src/lib/netlist/devices/nld_7483.h
@@ -27,7 +27,7 @@
#ifndef NLD_7483_H_
#define NLD_7483_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7483(name, cA1, cA2, cA3, cA4, cB1, cB2, cB3, cB4, cCI) \
NET_REGISTER_DEV(TTL_7483, name) \
diff --git a/src/lib/netlist/devices/nld_7485.cpp b/src/lib/netlist/devices/nld_7485.cpp
index 320cf762f26..cadb73000ff 100644
--- a/src/lib/netlist/devices/nld_7485.cpp
+++ b/src/lib/netlist/devices/nld_7485.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_7485.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -101,8 +101,8 @@ namespace netlist
update_outputs(1, 1, 0);
}
- NETLIB_DEVICE_IMPL(7485)
- NETLIB_DEVICE_IMPL(7485_dip)
+ NETLIB_DEVICE_IMPL(7485, "TTL_7485", "+A0,+A1,+A2,+A3,+B0,+B1,+B2,+B3,+LTIN,+EQIN,+GTIN")
+ NETLIB_DEVICE_IMPL(7485_dip, "TTL_7485_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7485.h b/src/lib/netlist/devices/nld_7485.h
index 61b87c37ba3..7890f4dbd2a 100644
--- a/src/lib/netlist/devices/nld_7485.h
+++ b/src/lib/netlist/devices/nld_7485.h
@@ -23,7 +23,7 @@
#ifndef NLD_7485_H_
#define NLD_7485_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7485(name, cA0, cA1, cA2, cA3, cB0, cB1, cB2, cB3, cLTIN, cEQIN, cGTIN) \
NET_REGISTER_DEV(TTL_7485, name) \
diff --git a/src/lib/netlist/devices/nld_7490.cpp b/src/lib/netlist/devices/nld_7490.cpp
index 13e69c6aa31..acbe0fa4d7a 100644
--- a/src/lib/netlist/devices/nld_7490.cpp
+++ b/src/lib/netlist/devices/nld_7490.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_7490.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -28,10 +28,10 @@ namespace netlist
{
}
+ private:
NETLIB_UPDATEI();
NETLIB_RESETI();
- protected:
void update_outputs();
logic_input_t m_A;
@@ -52,22 +52,22 @@ namespace netlist
{
NETLIB_CONSTRUCTOR_DERIVED(7490_dip, 7490)
{
- register_subalias("1", m_B);
- register_subalias("2", m_R1);
- register_subalias("3", m_R2);
+ register_subalias("1", "B");
+ register_subalias("2", "R1");
+ register_subalias("3", "R2");
// register_subalias("4", ); --> NC
// register_subalias("5", ); --> VCC
- register_subalias("6", m_R91);
- register_subalias("7", m_R92);
+ register_subalias("6", "R91");
+ register_subalias("7", "R92");
- register_subalias("8", m_Q[2]);
- register_subalias("9", m_Q[1]);
+ register_subalias("8", "QC");
+ register_subalias("9", "QB");
// register_subalias("10", ); --> GND
- register_subalias("11", m_Q[3]);
- register_subalias("12", m_Q[0]);
+ register_subalias("11", "QD");
+ register_subalias("12", "QA");
// register_subalias("13", ); --> NC
- register_subalias("14", m_A);
+ register_subalias("14", "A");
}
};
@@ -78,12 +78,13 @@ namespace netlist
m_last_B = 0;
}
- static C14CONSTEXPR const netlist_time delay[4] =
+ static constexpr const netlist_time delay[4] =
{
NLTIME_FROM_NS(18),
NLTIME_FROM_NS(36) - NLTIME_FROM_NS(18),
NLTIME_FROM_NS(54) - NLTIME_FROM_NS(18),
- NLTIME_FROM_NS(72) - NLTIME_FROM_NS(18)};
+ NLTIME_FROM_NS(72) - NLTIME_FROM_NS(18)
+ };
NETLIB_UPDATE(7490)
{
@@ -119,14 +120,14 @@ namespace netlist
m_last_B = new_B;
}
- NETLIB_FUNC_VOID(7490, update_outputs, (void))
+ NETLIB_FUNC_VOID(7490, update_outputs, ())
{
for (std::size_t i=0; i<4; i++)
m_Q[i].push((m_cnt >> i) & 1, delay[i]);
}
- NETLIB_DEVICE_IMPL(7490)
- NETLIB_DEVICE_IMPL(7490_dip)
+ NETLIB_DEVICE_IMPL(7490, "TTL_7490", "+A,+B,+R1,+R2,+R91,+R92")
+ NETLIB_DEVICE_IMPL(7490_dip, "TTL_7490_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7490.h b/src/lib/netlist/devices/nld_7490.h
index 5ff18543b03..e2fa5094911 100644
--- a/src/lib/netlist/devices/nld_7490.h
+++ b/src/lib/netlist/devices/nld_7490.h
@@ -55,7 +55,7 @@
#ifndef NLD_7490_H_
#define NLD_7490_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7490(name, cA, cB, cR1, cR2, cR91, cR92) \
NET_REGISTER_DEV(TTL_7490, name) \
diff --git a/src/lib/netlist/devices/nld_7493.cpp b/src/lib/netlist/devices/nld_7493.cpp
index f3c68f7a5c2..f26e1c237d5 100644
--- a/src/lib/netlist/devices/nld_7493.cpp
+++ b/src/lib/netlist/devices/nld_7493.cpp
@@ -6,23 +6,22 @@
*/
#include "nld_7493.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
namespace devices
{
- static constexpr netlist_time out_delay = NLTIME_FROM_NS(18);
- static constexpr netlist_time out_delay2 = NLTIME_FROM_NS(36);
- static constexpr netlist_time out_delay3 = NLTIME_FROM_NS(54);
+ static constexpr const netlist_time out_delay = NLTIME_FROM_NS(18);
+ static constexpr const netlist_time out_delay2 = NLTIME_FROM_NS(36);
+ static constexpr const netlist_time out_delay3 = NLTIME_FROM_NS(54);
NETLIB_OBJECT(7493)
{
NETLIB_CONSTRUCTOR(7493)
, m_R1(*this, "R1")
, m_R2(*this, "R2")
- , m_reset(*this, "_m_reset", 0)
, m_a(*this, "_m_a", 0)
, m_bcd(*this, "_m_b", 0)
, m_CLKA(*this, "CLKA", NETLIB_DELEGATE(7493, updA))
@@ -35,35 +34,51 @@ namespace netlist
}
private:
- NETLIB_RESETI();
- NETLIB_UPDATEI();
+ NETLIB_RESETI()
+ {
+ m_a = m_bcd = 0;
+ m_CLKA.set_state(logic_t::STATE_INP_HL);
+ m_CLKB.set_state(logic_t::STATE_INP_HL);
+ }
- NETLIB_HANDLERI(updA)
+ NETLIB_UPDATEI()
{
- if (m_reset)
+ if (!(m_R1() & m_R2()))
+ {
+ m_CLKA.activate_hl();
+ m_CLKB.activate_hl();
+ }
+ else
{
- m_a ^= 1;
- m_QA.push(m_a, out_delay);
+ m_CLKA.inactivate();
+ m_CLKB.inactivate();
+ m_QA.push(0, NLTIME_FROM_NS(40));
+ m_QB.push(0, NLTIME_FROM_NS(40));
+ m_QC.push(0, NLTIME_FROM_NS(40));
+ m_QD.push(0, NLTIME_FROM_NS(40));
+ m_a = m_bcd = 0;
}
}
+ NETLIB_HANDLERI(updA)
+ {
+ m_a ^= 1;
+ m_QA.push(m_a, out_delay);
+ }
+
NETLIB_HANDLERI(updB)
{
- if (m_reset)
- {
- ++m_bcd &= static_cast<std::uint8_t>(0x07);
- m_QD.push((m_bcd >> 2) & 1, out_delay3);
- m_QC.push((m_bcd >> 1) & 1, out_delay2);
- m_QB.push(m_bcd & 1, out_delay);
- }
+ auto cnt = (++m_bcd &= 0x07);
+ m_QD.push((cnt >> 2) & 1, out_delay3);
+ m_QC.push((cnt >> 1) & 1, out_delay2);
+ m_QB.push(cnt & 1, out_delay);
}
logic_input_t m_R1;
logic_input_t m_R2;
- state_var_sig m_reset;
state_var_sig m_a;
- state_var_sig m_bcd;
+ state_var_u8 m_bcd;
logic_input_t m_CLKA;
logic_input_t m_CLKB;
@@ -97,37 +112,9 @@ namespace netlist
}
};
- NETLIB_RESET(7493)
- {
- m_reset = 1;
- m_a = m_bcd = 0;
- m_CLKA.set_state(logic_t::STATE_INP_HL);
- m_CLKB.set_state(logic_t::STATE_INP_HL);
- }
-
- NETLIB_UPDATE(7493)
- {
- m_reset = (m_R1() & m_R2()) ^ 1;
-
- if (m_reset)
- {
- m_CLKA.activate_hl();
- m_CLKB.activate_hl();
- }
- else
- {
- m_CLKA.inactivate();
- m_CLKB.inactivate();
- m_QA.push_force(0, NLTIME_FROM_NS(40));
- m_QB.push_force(0, NLTIME_FROM_NS(40));
- m_QC.push_force(0, NLTIME_FROM_NS(40));
- m_QD.push_force(0, NLTIME_FROM_NS(40));
- m_a = m_bcd = 0;
- }
- }
- NETLIB_DEVICE_IMPL(7493)
- NETLIB_DEVICE_IMPL(7493_dip)
+ NETLIB_DEVICE_IMPL(7493, "TTL_7493", "+CLKA,+CLKB,+R1,+R2")
+ NETLIB_DEVICE_IMPL(7493_dip, "TTL_7493_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7493.h b/src/lib/netlist/devices/nld_7493.h
index ce9566aa28f..68ad90885ec 100644
--- a/src/lib/netlist/devices/nld_7493.h
+++ b/src/lib/netlist/devices/nld_7493.h
@@ -57,7 +57,7 @@
#ifndef NLD_7493_H_
#define NLD_7493_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_7493(name, cCLKA, cCLKB, cR1, cR2) \
NET_REGISTER_DEV(TTL_7493, name) \
diff --git a/src/lib/netlist/devices/nld_7497.cpp b/src/lib/netlist/devices/nld_7497.cpp
new file mode 100644
index 00000000000..1432884b8dd
--- /dev/null
+++ b/src/lib/netlist/devices/nld_7497.cpp
@@ -0,0 +1,174 @@
+// license:GPL-2.0+
+// copyright-holders:Sergey Svishchev
+/*
+ * nld_7497.cpp
+ *
+ * To do:
+ *
+ * - STRB and EN
+ * - Timing
+ */
+
+#include "nld_7497.h"
+#include "netlist/nl_base.h"
+
+namespace netlist
+{
+ namespace devices
+ {
+
+ static constexpr const netlist_time out_delay_CLK_Y[2] = { NLTIME_FROM_NS(20), NLTIME_FROM_NS(26) }; // tPHL, tPLH
+ static constexpr const netlist_time out_delay_CLK_Z[2] = { NLTIME_FROM_NS(17), NLTIME_FROM_NS(12) };
+
+ NETLIB_OBJECT(7497)
+ {
+ NETLIB_CONSTRUCTOR(7497)
+ , m_B(*this, {{"B5", "B4", "B3", "B2", "B1", "B0"}})
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(7497, clk_strb))
+ , m_STRBQ(*this, "STRBQ", NETLIB_DELEGATE(7497, clk_strb))
+ , m_ENQ(*this, "ENQ")
+ , m_UNITYQ(*this, "UNITYQ", NETLIB_DELEGATE(7497, unity))
+ , m_CLR(*this, "CLR", NETLIB_DELEGATE(7497, clr))
+ , m_Y(*this, "Y")
+ , m_ZQ(*this, "ZQ")
+ , m_ENOUTQ(*this, "ENOUTQ")
+ , m_cnt(*this, "_m_cnt", 0)
+ , m_rate(*this, "_m_rate", 0)
+ , m_state(*this, "_m_state", 0)
+ , m_lastclock(*this, "_m_lastclock", 0)
+ {
+ }
+
+ private:
+ NETLIB_RESETI();
+ NETLIB_UPDATEI();
+
+ NETLIB_HANDLERI(noop) { }
+ NETLIB_HANDLERI(unity);
+ NETLIB_HANDLERI(clr);
+ NETLIB_HANDLERI(clk_strb);
+
+ protected:
+ object_array_t<logic_input_t, 6> m_B;
+ logic_input_t m_CLK;
+ logic_input_t m_STRBQ;
+ logic_input_t m_ENQ;
+ logic_input_t m_UNITYQ;
+ logic_input_t m_CLR;
+
+ logic_output_t m_Y;
+ logic_output_t m_ZQ;
+ logic_output_t m_ENOUTQ;
+
+ state_var_u8 m_cnt;
+ state_var_u8 m_rate;
+ state_var_sig m_state;
+ state_var_sig m_lastclock;
+
+ void newstate(const netlist_sig_t state)
+ {
+ m_state = state;
+ m_ZQ.push(state, out_delay_CLK_Z[state]);
+ //netlist_sig_t y = (state ^ 1) | (m_UNITY() ^ 1); // OR with negated inputs == NAND
+ netlist_sig_t y = (state & m_UNITYQ()) ^ 1; // OR with negated inputs == NAND
+ m_Y.push(y, out_delay_CLK_Y[y]);
+ }
+
+ uint8_t rate()
+ {
+ uint8_t a = 0;
+
+ for (std::size_t i = 0; i < 6; i++)
+ a |= (m_B[i]() << i);
+
+ return a;
+ }
+ };
+
+ NETLIB_RESET(7497)
+ {
+ m_cnt = 0;
+ m_rate = 0;
+ m_lastclock = 0;
+ }
+
+ NETLIB_UPDATE(7497)
+ {
+ m_rate = rate();
+ clk_strb();
+ }
+
+ NETLIB_HANDLER(7497, unity)
+ {
+ newstate (m_state);
+ }
+
+ NETLIB_HANDLER(7497, clr)
+ {
+ m_cnt = 0;
+ clk_strb();
+ }
+
+ NETLIB_HANDLER(7497, clk_strb)
+ {
+ netlist_sig_t clk = m_CLK();
+
+ if (!m_lastclock && clk && !m_ENQ() && !m_CLR())
+ {
+ m_cnt++;
+ m_cnt &= 63;
+ }
+ m_lastclock = clk;
+
+ const netlist_sig_t clk_strb = (clk ^ 1) & (m_STRBQ() ^ 1);
+
+ const netlist_sig_t cntQ = m_cnt;
+
+ // NOR GATE
+ netlist_sig_t p1 = ((cntQ & 63) == 31 && (m_rate & 32)) ||
+ ((cntQ & 31) == 15 && (m_rate & 16)) ||
+ ((cntQ & 15) == 7 && (m_rate & 8)) ||
+ ((cntQ & 7) == 3 && (m_rate & 4)) ||
+ ((cntQ & 3) == 1 && (m_rate & 2)) ||
+ ((cntQ & 1) == 0 && (m_rate & 1));
+
+ p1 = (p1 & clk_strb) ^ 1;
+
+ newstate(p1);
+
+ // NAND gate
+ if ((m_cnt == 63) && !m_ENQ())
+ m_ENOUTQ.push(0, out_delay_CLK_Y[0]); // XXX timing
+ else
+ m_ENOUTQ.push(1, out_delay_CLK_Y[1]);
+
+ }
+
+ NETLIB_OBJECT_DERIVED(7497_dip, 7497)
+ {
+ NETLIB_CONSTRUCTOR_DERIVED(7497_dip, 7497)
+ {
+ register_subalias("1", m_B[4]); // B0
+ register_subalias("2", m_B[1]); // B4
+ register_subalias("3", m_B[0]); // B5
+ register_subalias("4", m_B[5]); // B0
+ register_subalias("5", m_ZQ);
+ register_subalias("6", m_Y);
+ register_subalias("7", m_ENOUTQ);
+
+ register_subalias("9", m_CLK);
+ register_subalias("10", m_STRBQ);
+ register_subalias("11", m_UNITYQ);
+ register_subalias("12", m_ENQ);
+ register_subalias("13", m_CLR);
+ register_subalias("14", m_B[3]); // B2
+ register_subalias("15", m_B[2]); // B3
+ }
+ };
+
+
+ NETLIB_DEVICE_IMPL(7497, "TTL_7497", "+CLK,+STRBQ,+ENQ,+UNITYQ,+CLR,+B0,+B1,+B2,+B3,+B4,+B5")
+ NETLIB_DEVICE_IMPL(7497_dip, "TTL_7497_DIP", "")
+
+ } //namespace devices
+} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7497.h b/src/lib/netlist/devices/nld_7497.h
new file mode 100644
index 00000000000..8d14e08a49b
--- /dev/null
+++ b/src/lib/netlist/devices/nld_7497.h
@@ -0,0 +1,57 @@
+// license:GPL-2.0+
+// copyright-holders:Sergey Svishchev
+/*
+ * nld_7497.h
+ *
+ * SN7497: Synchronous 6-Bit Binary Rate Multiplier
+ *
+ * +--------------+
+ * B1 |1 16| VCC
+ * B4 |2 15| B3
+ * B5 |3 14| B2
+ * B0 |4 7497 13| CLR
+ * Z |5 12| UNITY/CAS
+ * Y |6 11| ENin (EN)
+ * ENout |7 10| STRB
+ * GND |8 9| CLK
+ * +--------------+
+ *
+ * Naming conventions follow TI datasheet
+ *
+ * The counter is enabled when the clear, strobe, and enable inputs are low.
+ *
+ * When the rate input is binary 0 (all rate inputs low), Z remains high [and Y low].
+ *
+ * The unity/cascade input, when connected to the clock input, passes
+ * clock frequency (inverted) to the Y output when the rate input/decoding
+ * gates are inhibited by the strobe.
+ *
+ * When CLR is H, states of CLK and STRB can affect Y and Z. Default are
+ * Y L, Z H, ENout H.
+ *
+ * Unity/cascade is used to inhibit output Y (UNITY L -> Y H)
+ */
+
+#ifndef NLD_7497_H_
+#define NLD_7497_H_
+
+#include "netlist/nl_setup.h"
+
+#define TTL_7497(name, cCLK, cSTRB, cEN, cUNITY, cCLR, cB0, cB1, cB2, cB3, cB4, cB5) \
+ NET_REGISTER_DEV(TTL_7497, name) \
+ NET_CONNECT(name, CLK, cCLK) \
+ NET_CONNECT(name, STRBQ, cSTRB) \
+ NET_CONNECT(name, ENQ, cEN) \
+ NET_CONNECT(name, UNITYQ,cUNITY) \
+ NET_CONNECT(name, CLR, cCLR) \
+ NET_CONNECT(name, B0, cB0) \
+ NET_CONNECT(name, B1, cB1) \
+ NET_CONNECT(name, B2, cB2) \
+ NET_CONNECT(name, B3, cB3) \
+ NET_CONNECT(name, B4, cB4) \
+ NET_CONNECT(name, B5, cB5)
+
+#define TTL_7497_DIP(name) \
+ NET_REGISTER_DEV(TTL_7497_DIP, name)
+
+#endif /* NLD_7497_H_ */
diff --git a/src/lib/netlist/devices/nld_74ls629.cpp b/src/lib/netlist/devices/nld_74ls629.cpp
index d6dc268ed28..b7bb729b334 100644
--- a/src/lib/netlist/devices/nld_74ls629.cpp
+++ b/src/lib/netlist/devices/nld_74ls629.cpp
@@ -40,7 +40,7 @@
#include "nld_74ls629.h"
-#include "../analog/nlid_twoterm.h"
+#include "netlist/analog/nlid_twoterm.h"
namespace netlist
{
@@ -100,11 +100,14 @@ namespace netlist
{
m_R_FC.set_R(90000.0);
m_R_RNG.set_R(90000.0);
- m_clock.do_reset();
+ m_clock.reset();
}
NETLIB_UPDATEI();
- NETLIB_UPDATE_PARAMI() { update_dev(); }
+ NETLIB_UPDATE_PARAMI()
+ {
+ /* update param may be called from anywhere, update_dev(time) is not a good idea */
+ }
public:
NETLIB_SUB(SN74LS629clk) m_clock;
@@ -145,8 +148,8 @@ namespace netlist
NETLIB_RESETI()
{
- m_1.do_reset();
- m_2.do_reset();
+ m_1.reset();
+ m_2.reset();
}
private:
@@ -207,7 +210,7 @@ namespace netlist
freq += k9 * v_rng * v_freq_3;
freq += k10 * v_rng * v_freq_4;
- freq *= NL_FCONST(0.1e-6) / m_CAP();
+ freq *= plib::constants<nl_double>::cast(0.1e-6) / m_CAP();
// FIXME: we need a possibility to remove entries from queue ...
// or an exact model ...
@@ -231,8 +234,8 @@ namespace netlist
}
}
- NETLIB_DEVICE_IMPL(SN74LS629)
- NETLIB_DEVICE_IMPL(SN74LS629_dip)
+ NETLIB_DEVICE_IMPL(SN74LS629, "SN74LS629", "CAP")
+ NETLIB_DEVICE_IMPL(SN74LS629_dip, "SN74LS629_DIP", "1.CAP1,2.CAP2")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_74ls629.h b/src/lib/netlist/devices/nld_74ls629.h
index 3351524a60b..30d15d70865 100644
--- a/src/lib/netlist/devices/nld_74ls629.h
+++ b/src/lib/netlist/devices/nld_74ls629.h
@@ -28,7 +28,7 @@
#ifndef NLD_74LS629_H_
#define NLD_74LS629_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define SN74LS629(name, p_cap) \
NET_REGISTER_DEV(SN74LS629, name) \
diff --git a/src/lib/netlist/devices/nld_82S115.cpp b/src/lib/netlist/devices/nld_82S115.cpp
index 2e24bbf9fed..8ae6cbb6097 100644
--- a/src/lib/netlist/devices/nld_82S115.cpp
+++ b/src/lib/netlist/devices/nld_82S115.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_82S115.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -106,8 +106,8 @@ namespace netlist
m_O[i].push((o >> i) & 1, NLTIME_FROM_NS(40)); // FIXME: Timing
}
- NETLIB_DEVICE_IMPL(82S115)
- NETLIB_DEVICE_IMPL(82S115_dip)
+ NETLIB_DEVICE_IMPL(82S115, "PROM_82S115", "+CE1Q,+CE2,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+STROBE")
+ NETLIB_DEVICE_IMPL(82S115_dip, "PROM_82S115_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_82S115.h b/src/lib/netlist/devices/nld_82S115.h
index ef7f1ec3910..8c13fd8b51e 100644
--- a/src/lib/netlist/devices/nld_82S115.h
+++ b/src/lib/netlist/devices/nld_82S115.h
@@ -28,7 +28,7 @@
#ifndef NLD_82S115_H_
#define NLD_82S115_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define PROM_82S115(name, cCE1Q, cCE2, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7, cA8, cSTROBE) \
NET_REGISTER_DEV(PROM_82S115, name) \
diff --git a/src/lib/netlist/devices/nld_82S123.cpp b/src/lib/netlist/devices/nld_82S123.cpp
index a8a6bfc9b57..4a80b57e349 100644
--- a/src/lib/netlist/devices/nld_82S123.cpp
+++ b/src/lib/netlist/devices/nld_82S123.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_82S123.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -77,8 +77,8 @@ namespace netlist
m_O[i].push((o >> i) & 1, delay);
}
- NETLIB_DEVICE_IMPL(82S123)
- NETLIB_DEVICE_IMPL(82S123_dip)
+ NETLIB_DEVICE_IMPL(82S123, "PROM_82S123", "+CEQ,+A0,+A1,+A2,+A3,+A4")
+ NETLIB_DEVICE_IMPL(82S123_dip, "PROM_82S123_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_82S123.h b/src/lib/netlist/devices/nld_82S123.h
index dbf6bf63180..2c18377934d 100644
--- a/src/lib/netlist/devices/nld_82S123.h
+++ b/src/lib/netlist/devices/nld_82S123.h
@@ -25,7 +25,7 @@
#ifndef NLD_82S123_H_
#define NLD_82S123_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define PROM_82S123(name, cCEQ, cA0, cA1, cA2, cA3, cA4) \
NET_REGISTER_DEV(PROM_82S123, name) \
diff --git a/src/lib/netlist/devices/nld_82S126.cpp b/src/lib/netlist/devices/nld_82S126.cpp
index dcacd1ec876..b1752908645 100644
--- a/src/lib/netlist/devices/nld_82S126.cpp
+++ b/src/lib/netlist/devices/nld_82S126.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_82S126.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -79,8 +79,8 @@ namespace netlist
m_O[i].push((o >> i) & 1, delay);
}
- NETLIB_DEVICE_IMPL(82S126)
- NETLIB_DEVICE_IMPL(82S126_dip)
+ NETLIB_DEVICE_IMPL(82S126, "PROM_82S126", "+CE1Q,+CE2Q,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7")
+ NETLIB_DEVICE_IMPL(82S126_dip, "PROM_82S126_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_82S126.h b/src/lib/netlist/devices/nld_82S126.h
index 3079bb8e2e0..ed7aa131819 100644
--- a/src/lib/netlist/devices/nld_82S126.h
+++ b/src/lib/netlist/devices/nld_82S126.h
@@ -24,7 +24,7 @@
#ifndef NLD_82S126_H_
#define NLD_82S126_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define PROM_82S126(name, cCE1Q, cCE2Q, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7) \
NET_REGISTER_DEV(PROM_82S126, name) \
diff --git a/src/lib/netlist/devices/nld_82S16.cpp b/src/lib/netlist/devices/nld_82S16.cpp
index 7441f6c677e..e3176c7b30f 100644
--- a/src/lib/netlist/devices/nld_82S16.cpp
+++ b/src/lib/netlist/devices/nld_82S16.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_82S16.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -15,19 +15,55 @@ namespace netlist
NETLIB_OBJECT(82S16)
{
NETLIB_CONSTRUCTOR(82S16)
- , m_A(*this, {{"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7" }})
- , m_CE1Q(*this, "CE1Q")
- , m_CE2Q(*this, "CE2Q")
- , m_CE3Q(*this, "CE3Q")
+ , m_A(*this, {{"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7" }}, NETLIB_DELEGATE(82S16, addr))
+ , m_CE1Q(*this, "CE1Q", NETLIB_DELEGATE(82S16, enq))
+ , m_CE2Q(*this, "CE2Q", NETLIB_DELEGATE(82S16, enq))
+ , m_CE3Q(*this, "CE3Q", NETLIB_DELEGATE(82S16, enq))
, m_WEQ(*this, "WEQ")
, m_DIN(*this, "DIN")
, m_DOUTQ(*this, "DOUTQ")
, m_ram(*this, "m_ram", 0)
+ , m_addr(*this, "m_addr", 0)
+ , m_enq(*this, "m_enq", 0)
{
}
NETLIB_RESETI();
NETLIB_UPDATEI();
+ NETLIB_HANDLERI(addr)
+ {
+ uint8_t adr = 0;
+ for (std::size_t i=0; i<8; i++)
+ {
+ //m_A[i].activate();
+ adr |= (m_A[i]() << i);
+ }
+ m_addr = adr;
+ NETLIB_NAME(82S16)::update();
+ }
+ NETLIB_HANDLERI(enq)
+ {
+ const auto last = m_enq;
+ m_enq = m_CE1Q() || m_CE2Q() || m_CE3Q();
+ if (!last && m_enq)
+ {
+ // FIXME: Outputs are tristate. This needs to be properly implemented
+ m_DOUTQ.push(1, NLTIME_FROM_NS(20));
+ for (std::size_t i=0; i<8; i++)
+ m_A[i].inactivate();
+ m_WEQ.inactivate();
+ m_DIN.inactivate();
+ }
+ else if (last && !m_enq)
+ {
+ for (std::size_t i=0; i<8; i++)
+ m_A[i].activate();
+ m_WEQ.activate();
+ m_DIN.activate();
+ NETLIB_NAME(82S16)::update();
+ }
+ }
+
protected:
object_array_t<logic_input_t, 8> m_A;
@@ -38,7 +74,9 @@ namespace netlist
logic_input_t m_DIN;
logic_output_t m_DOUTQ;
- state_var<uint64_t[4]> m_ram; // 256 bits
+ state_array<uint64_t, 4> m_ram; // 256 bits
+ state_var_u8 m_addr; // 256 bits
+ state_var_sig m_enq;
};
NETLIB_OBJECT_DERIVED(82S16_dip, 82S16)
@@ -69,22 +107,9 @@ namespace netlist
// FIXME: optimize device (separate address decoder!)
NETLIB_UPDATE(82S16)
{
- if (m_CE1Q() || m_CE2Q() || m_CE3Q())
+ if (!m_enq)
{
- // FIXME: Outputs are tristate. This needs to be properly implemented
- m_DOUTQ.push(1, NLTIME_FROM_NS(20));
- //for (int i=0; i<8; i++)
- //m_A[i].inactivate();
- }
- else
- {
- unsigned int adr = 0;
- for (std::size_t i=0; i<8; i++)
- {
- //m_A[i].activate();
- adr |= (m_A[i]() << i);
- }
-
+ const auto adr(m_addr);
if (!m_WEQ())
{
m_ram[adr >> 6] = (m_ram[adr >> 6]
@@ -101,10 +126,12 @@ namespace netlist
{
m_ram[i] = 0;
}
+ m_addr = 0;
+ m_enq = 0;
}
- NETLIB_DEVICE_IMPL(82S16)
- NETLIB_DEVICE_IMPL(82S16_dip)
+ NETLIB_DEVICE_IMPL(82S16, "TTL_82S16", "")
+ NETLIB_DEVICE_IMPL(82S16_dip, "TTL_82S16_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_82S16.h b/src/lib/netlist/devices/nld_82S16.h
index d1117246d87..47d6189a79b 100644
--- a/src/lib/netlist/devices/nld_82S16.h
+++ b/src/lib/netlist/devices/nld_82S16.h
@@ -24,7 +24,7 @@
#ifndef NLD_82S16_H_
#define NLD_82S16_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_82S16(name) \
NET_REGISTER_DEV(TTL_82S16, name)
diff --git a/src/lib/netlist/devices/nld_9310.cpp b/src/lib/netlist/devices/nld_9310.cpp
index ad752adb605..b416015df24 100644
--- a/src/lib/netlist/devices/nld_9310.cpp
+++ b/src/lib/netlist/devices/nld_9310.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_9310.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
#define MAXCNT 9
@@ -14,6 +14,7 @@ namespace netlist
{
namespace devices
{
+ //FIXME: Convert sub devices into NETDEV_DELEGATE logic
NETLIB_OBJECT(9310_subABCD)
{
NETLIB_CONSTRUCTOR(9310_subABCD)
@@ -139,8 +140,8 @@ namespace netlist
NETLIB_RESET(9310)
{
- sub.do_reset();
- subABCD.do_reset();
+ sub.reset();
+ subABCD.reset();
}
NETLIB_RESET(9310_subABCD)
@@ -157,32 +158,35 @@ namespace netlist
NETLIB_UPDATE(9310_sub)
{
+ auto cnt(m_cnt);
+
if (m_loadq)
{
- if (m_cnt < MAXCNT - 1)
+ if (cnt < MAXCNT - 1)
{
- ++m_cnt;
- update_outputs(m_cnt);
+ ++cnt;
+ update_outputs(cnt);
}
- else if (m_cnt == MAXCNT - 1)
+ else if (cnt == MAXCNT - 1)
{
- m_cnt = MAXCNT;
+ cnt = MAXCNT;
m_RC.push(m_ent, NLTIME_FROM_NS(20));
m_QA.push(1, NLTIME_FROM_NS(20));
}
else // MAXCNT
{
m_RC.push(0, NLTIME_FROM_NS(20));
- m_cnt = 0;
- update_outputs_all(m_cnt, NLTIME_FROM_NS(20));
+ cnt = 0;
+ update_outputs_all(cnt, NLTIME_FROM_NS(20));
}
}
else
{
- m_cnt = m_ABCD->read_ABCD();
- m_RC.push(m_ent & (m_cnt == MAXCNT), NLTIME_FROM_NS(27));
- update_outputs_all(m_cnt, NLTIME_FROM_NS(22));
+ cnt = m_ABCD->read_ABCD();
+ m_RC.push(m_ent & (cnt == MAXCNT), NLTIME_FROM_NS(27));
+ update_outputs_all(cnt, NLTIME_FROM_NS(22));
}
+ m_cnt = cnt;
}
NETLIB_UPDATE(9310)
@@ -223,10 +227,10 @@ namespace netlist
#if 0
// for (int i=0; i<4; i++)
// m_Q[i], (cnt >> i) & 1, delay[i]);
- m_QA, (cnt >> 0) & 1, out_delay);
- m_QB, (cnt >> 1) & 1, out_delay);
- m_QC, (cnt >> 2) & 1, out_delay);
- m_QD, (cnt >> 3) & 1, out_delay);
+ m_QA.push((cnt >> 0) & 1, out_delay);
+ m_QB.push((cnt >> 1) & 1, out_delay);
+ m_QC.push((cnt >> 2) & 1, out_delay);
+ m_QD.push((cnt >> 3) & 1, out_delay);
#else
if ((cnt & 1) == 1)
m_QA.push(1, out_delay);
@@ -262,8 +266,8 @@ namespace netlist
#endif
}
- NETLIB_DEVICE_IMPL(9310)
- NETLIB_DEVICE_IMPL(9310_dip)
+ NETLIB_DEVICE_IMPL(9310, "TTL_9310", "")
+ NETLIB_DEVICE_IMPL(9310_dip, "TTL_9310_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_9310.h b/src/lib/netlist/devices/nld_9310.h
index 02cb45b2d86..65df9c04ce4 100644
--- a/src/lib/netlist/devices/nld_9310.h
+++ b/src/lib/netlist/devices/nld_9310.h
@@ -45,7 +45,7 @@
#ifndef NLD_9310_H_
#define NLD_9310_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_9310(name, cCLK, cENP, cENT, cCLRQ, cLOADQ, cA, cB, cC, cD) \
NET_REGISTER_DEV(TTL_9310, name) \
diff --git a/src/lib/netlist/devices/nld_9316.cpp b/src/lib/netlist/devices/nld_9316.cpp
index 7c478fd4b05..2b17eabb3ec 100644
--- a/src/lib/netlist/devices/nld_9316.cpp
+++ b/src/lib/netlist/devices/nld_9316.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_9316.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -20,31 +20,72 @@ namespace netlist
NETLIB_CONSTRUCTOR(9316)
, m_CLK(*this, "CLK", NETLIB_DELEGATE(9316, clk))
, m_ENT(*this, "ENT")
+ , m_RC(*this, "RC")
, m_LOADQ(*this, "LOADQ")
- , m_cnt(*this, "m_cnt", 0)
, m_ENP(*this, "ENP")
, m_CLRQ(*this, "CLRQ")
- , m_A(*this, "A", NETLIB_DELEGATE(9316, noop))
- , m_B(*this, "B", NETLIB_DELEGATE(9316, noop))
- , m_C(*this, "C", NETLIB_DELEGATE(9316, noop))
- , m_D(*this, "D", NETLIB_DELEGATE(9316, noop))
+ , m_A(*this, "A", NETLIB_DELEGATE(9316, abcd))
+ , m_B(*this, "B", NETLIB_DELEGATE(9316, abcd))
+ , m_C(*this, "C", NETLIB_DELEGATE(9316, abcd))
+ , m_D(*this, "D", NETLIB_DELEGATE(9316, abcd))
, m_Q(*this, {{ "QA", "QB", "QC", "QD" }})
- , m_RC(*this, "RC")
+ , m_cnt(*this, "m_cnt", 0)
+ , m_abcd(*this, "m_abcd", 0)
+ , m_loadq(*this, "m_loadq", 0)
+ , m_ent(*this, "m_ent", 0)
{
}
private:
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- NETLIB_HANDLERI(clk);
- NETLIB_HANDLERI(noop) { }
+ NETLIB_RESETI()
+ {
+ m_CLK.set_state(logic_t::STATE_INP_LH);
+ m_cnt = 0;
+ m_abcd = 0;
+ }
- logic_input_t m_CLK;
+ NETLIB_UPDATEI()
+ {
+ const auto CLRQ(m_CLRQ());
+ m_ent = m_ENT();
+ m_loadq = m_LOADQ();
+ if (((m_loadq ^ 1) || (m_ent && m_ENP())) && CLRQ)
+ {
+ m_CLK.activate_lh();
+ }
+ else
+ {
+ m_CLK.inactivate();
+ if (!CLRQ && (m_cnt>0))
+ {
+ m_cnt = 0;
+ update_outputs_all(m_cnt, NLTIME_FROM_NS(36));
+ }
+ }
+ m_RC.push(m_ent && (m_cnt == MAXCNT), NLTIME_FROM_NS(27));
+ }
+
+
+ NETLIB_HANDLERI(clk)
+ {
+ auto cnt = (m_loadq ? m_cnt + 1 : m_abcd) & MAXCNT;
+ m_RC.push(m_ent && (cnt == MAXCNT), NLTIME_FROM_NS(27));
+ update_outputs_all(cnt, NLTIME_FROM_NS(20));
+ m_cnt = cnt;
+ }
+
+ NETLIB_HANDLERI(abcd)
+ {
+ m_abcd = static_cast<uint8_t>((m_D() << 3) | (m_C() << 2) | (m_B() << 1) | (m_A() << 0));
+ }
+
+ logic_input_t m_CLK;
logic_input_t m_ENT;
- logic_input_t m_LOADQ;
- state_var<unsigned> m_cnt;
+ logic_output_t m_RC;
+
+ logic_input_t m_LOADQ;
logic_input_t m_ENP;
logic_input_t m_CLRQ;
@@ -55,12 +96,15 @@ namespace netlist
logic_input_t m_D;
object_array_t<logic_output_t, 4> m_Q;
- logic_output_t m_RC;
+ /* counter state */
+ state_var<unsigned> m_cnt;
+ /* cached pins */
+ state_var_u8 m_abcd;
+ state_var_sig m_loadq;
+ state_var_sig m_ent;
- private:
- //inline void update_outputs_all(const unsigned &cnt, const netlist_time &out_delay) noexcept
- inline void update_outputs_all(const unsigned &cnt, const netlist_time &out_delay) noexcept
+ void update_outputs_all(unsigned cnt, netlist_time out_delay) noexcept
{
m_Q[0].push((cnt >> 0) & 1, out_delay);
m_Q[1].push((cnt >> 1) & 1, out_delay);
@@ -93,63 +137,9 @@ namespace netlist
}
};
- NETLIB_RESET(9316)
- {
- m_CLK.set_state(logic_t::STATE_INP_LH);
- m_cnt = 0;
- }
-
- NETLIB_HANDLER(9316, clk)
- {
- if (m_LOADQ())
- {
- ++m_cnt &= MAXCNT;
- //m_RC.push(m_ENT() && (m_cnt == MAXCNT), NLTIME_FROM_NS(27));
- if (m_cnt == MAXCNT)
- {
- m_RC.push(m_ENT(), NLTIME_FROM_NS(27));
- update_outputs_all(MAXCNT, NLTIME_FROM_NS(20));
- }
- else if (m_cnt == 0)
- {
- m_RC.push(0, NLTIME_FROM_NS(27));
- update_outputs_all(0, NLTIME_FROM_NS(20));
- }
- else
- update_outputs_all(m_cnt, NLTIME_FROM_NS(20));
- }
- else
- {
- m_cnt = (m_D() << 3) | (m_C() << 2) | (m_B() << 1) | (m_A() << 0);
- m_RC.push(m_ENT() && (m_cnt == MAXCNT), NLTIME_FROM_NS(27));
- update_outputs_all(m_cnt, NLTIME_FROM_NS(22));
- }
- }
-
- NETLIB_UPDATE(9316)
- {
- const netlist_sig_t CLRQ(m_CLRQ());
- const netlist_sig_t ENT(m_ENT());
-
- if (((m_LOADQ() ^ 1) || (ENT && m_ENP())) && CLRQ)
- {
- m_CLK.activate_lh();
- }
- else
- {
- m_CLK.inactivate();
- if (!CLRQ && (m_cnt>0))
- {
- m_cnt = 0;
- update_outputs_all(m_cnt, NLTIME_FROM_NS(36));
- }
- }
- m_RC.push(ENT && (m_cnt == MAXCNT), NLTIME_FROM_NS(27));
- }
-
- NETLIB_DEVICE_IMPL(9316)
- NETLIB_DEVICE_IMPL(9316_dip)
+ NETLIB_DEVICE_IMPL(9316, "TTL_9316", "+CLK,+ENP,+ENT,+CLRQ,+LOADQ,+A,+B,+C,+D")
+ NETLIB_DEVICE_IMPL(9316_dip, "TTL_9316_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_9316.h b/src/lib/netlist/devices/nld_9316.h
index 8deb21dfccd..8ab1789d7c7 100644
--- a/src/lib/netlist/devices/nld_9316.h
+++ b/src/lib/netlist/devices/nld_9316.h
@@ -51,7 +51,7 @@
#ifndef NLD_9316_H_
#define NLD_9316_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_9316(name, cCLK, cENP, cENT, cCLRQ, cLOADQ, cA, cB, cC, cD) \
NET_REGISTER_DEV(TTL_9316, name) \
diff --git a/src/lib/netlist/devices/nld_9322.cpp b/src/lib/netlist/devices/nld_9322.cpp
index 6c408498be7..abf9bf9f6ef 100644
--- a/src/lib/netlist/devices/nld_9322.cpp
+++ b/src/lib/netlist/devices/nld_9322.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_9322.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -105,14 +105,14 @@ namespace netlist
NETLIB_UPDATE(9322)
{
- m_1.update_dev();
- m_2.update_dev();
- m_3.update_dev();
- m_4.update_dev();
+ m_1.update();
+ m_2.update();
+ m_3.update();
+ m_4.update();
}
- NETLIB_DEVICE_IMPL(9322)
- NETLIB_DEVICE_IMPL(9322_dip)
+ NETLIB_DEVICE_IMPL(9322, "TTL_9322", "+SELECT,+A1,+B1,+A2,+B2,+A3,+B3,+A4,+B4,+STROBE")
+ NETLIB_DEVICE_IMPL(9322_dip, "TTL_9322_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_9322.h b/src/lib/netlist/devices/nld_9322.h
index 7de0f053b05..986c6b9e7f7 100644
--- a/src/lib/netlist/devices/nld_9322.h
+++ b/src/lib/netlist/devices/nld_9322.h
@@ -21,7 +21,7 @@
#ifndef NLD_9322_H_
#define NLD_9322_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_9322(name, cSELECT, cA1, cB1, cA2, cB2, cA3, cB3, cA4, cB4, cSTROBE) \
NET_REGISTER_DEV(TTL_9322, name) \
diff --git a/src/lib/netlist/devices/nld_am2847.cpp b/src/lib/netlist/devices/nld_am2847.cpp
index 5d0c5cb71a3..825696f0938 100644
--- a/src/lib/netlist/devices/nld_am2847.cpp
+++ b/src/lib/netlist/devices/nld_am2847.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_am2847.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -30,7 +30,7 @@ namespace netlist
logic_input_t m_RC;
logic_input_t m_IN;
- state_var<uint16_t[5]> m_buffer;
+ state_array<uint16_t, 5> m_buffer;
logic_output_t m_OUT;
};
@@ -116,7 +116,7 @@ namespace netlist
/* do nothing */
}
- inline NETLIB_FUNC_VOID(Am2847_shifter, shift, (void))
+ NETLIB_FUNC_VOID(Am2847_shifter, shift, ())
{
uint32_t out = m_buffer[0] & 1;
uint32_t in = (m_RC() ? out : m_IN());
@@ -130,8 +130,8 @@ namespace netlist
m_OUT.push(out, NLTIME_FROM_NS(200));
}
- NETLIB_DEVICE_IMPL(AM2847)
- NETLIB_DEVICE_IMPL(AM2847_dip)
+ NETLIB_DEVICE_IMPL(AM2847, "TTL_AM2847", "+CP,+INA,+INB,+INC,+IND,+RCA,+RCB,+RCC,+RCD")
+ NETLIB_DEVICE_IMPL(AM2847_dip, "TTL_AM2847_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_am2847.h b/src/lib/netlist/devices/nld_am2847.h
index 70d288d3eec..ff4a95b8e81 100644
--- a/src/lib/netlist/devices/nld_am2847.h
+++ b/src/lib/netlist/devices/nld_am2847.h
@@ -21,7 +21,7 @@
#ifndef NLD_AM2847_H_
#define NLD_AM2847_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_AM2847(name, cCP, cINA, cINB, cINC, cIND, cRCA, cRCB, cRCC, cRCD) \
NET_REGISTER_DEV(TTL_AM2847, name) \
diff --git a/src/lib/netlist/devices/nld_dm9314.cpp b/src/lib/netlist/devices/nld_dm9314.cpp
index fd3b8666078..93b958de539 100644
--- a/src/lib/netlist/devices/nld_dm9314.cpp
+++ b/src/lib/netlist/devices/nld_dm9314.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_dm9314.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -107,8 +107,8 @@ namespace netlist
}
}
- NETLIB_DEVICE_IMPL(9314)
- NETLIB_DEVICE_IMPL(9314_dip)
+ NETLIB_DEVICE_IMPL(9314, "TTL_9314", "+EQ,+MRQ,+S0Q,+S1Q,+S2Q,+S3Q,+D0,+D1,+D2,+D3")
+ NETLIB_DEVICE_IMPL(9314_dip, "TTL_9314_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_dm9314.h b/src/lib/netlist/devices/nld_dm9314.h
index 6188bbef42f..59c60591ce7 100644
--- a/src/lib/netlist/devices/nld_dm9314.h
+++ b/src/lib/netlist/devices/nld_dm9314.h
@@ -21,7 +21,7 @@
#ifndef NLD_DM9314_H_
#define NLD_DM9314_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_9314(name, cEQ, cMRQ, cS0Q, cS1Q, cS2Q, cS3Q, cD0, cD1, cD2, cD3) \
NET_REGISTER_DEV(TTL_9314, name) \
diff --git a/src/lib/netlist/devices/nld_dm9334.cpp b/src/lib/netlist/devices/nld_dm9334.cpp
index 8dceded5390..c08ce53efed 100644
--- a/src/lib/netlist/devices/nld_dm9334.cpp
+++ b/src/lib/netlist/devices/nld_dm9334.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_dm9334.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -143,8 +143,8 @@ namespace netlist
m_Q[i].push((q >> i) & 1, delay);
}
- NETLIB_DEVICE_IMPL(9334)
- NETLIB_DEVICE_IMPL(9334_dip)
+ NETLIB_DEVICE_IMPL(9334, "TTL_9334", "+CQ,+EQ,+D,+A0,+A1,+A2")
+ NETLIB_DEVICE_IMPL(9334_dip, "TTL_9334_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_dm9334.h b/src/lib/netlist/devices/nld_dm9334.h
index 1a07e051333..e54208e3ba4 100644
--- a/src/lib/netlist/devices/nld_dm9334.h
+++ b/src/lib/netlist/devices/nld_dm9334.h
@@ -65,7 +65,7 @@
#ifndef NLD_DM9334_H_
#define NLD_DM9334_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_9334(name, cCQ, cEQ, cD, cA0, cA1, cA2) \
NET_REGISTER_DEV(TTL_9334, name) \
diff --git a/src/lib/netlist/devices/nld_legacy.cpp b/src/lib/netlist/devices/nld_legacy.cpp
index 28fe0ad8188..738230646e0 100644
--- a/src/lib/netlist/devices/nld_legacy.cpp
+++ b/src/lib/netlist/devices/nld_legacy.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_legacy.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -25,7 +25,7 @@ namespace netlist
NETLIB_RESETI();
NETLIB_UPDATEI();
- protected:
+ private:
logic_input_t m_S;
logic_input_t m_R;
@@ -49,7 +49,7 @@ namespace netlist
NETLIB_RESETI();
NETLIB_UPDATEI();
- protected:
+ private:
logic_input_t m_I;
logic_output_t m_Q;
@@ -100,8 +100,8 @@ namespace netlist
m_last = nval;
}
- NETLIB_DEVICE_IMPL(nicRSFF)
- NETLIB_DEVICE_IMPL(nicDelay)
+ NETLIB_DEVICE_IMPL(nicRSFF, "NETDEV_RSFF", "")
+ NETLIB_DEVICE_IMPL(nicDelay, "NETDEV_DELAY", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_legacy.h b/src/lib/netlist/devices/nld_legacy.h
index 33f7d0caaf8..aa3aec6f147 100644
--- a/src/lib/netlist/devices/nld_legacy.h
+++ b/src/lib/netlist/devices/nld_legacy.h
@@ -13,7 +13,7 @@
#ifndef NLD_LEGACY_H_
#define NLD_LEGACY_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// ----------------------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/devices/nld_log.cpp b/src/lib/netlist/devices/nld_log.cpp
index 29218aaa09a..6b1b3d8efc1 100644
--- a/src/lib/netlist/devices/nld_log.cpp
+++ b/src/lib/netlist/devices/nld_log.cpp
@@ -5,10 +5,10 @@
*
*/
-#include "../nl_base.h"
-#include "../plib/pstream.h"
-#include "../plib/pfmtlog.h"
+#include "netlist/nl_base.h"
#include "nld_log.h"
+#include "plib/pfmtlog.h"
+#include "plib/pstream.h"
//#include "sound/wavwrite.h"
namespace netlist
@@ -19,15 +19,15 @@ namespace netlist
{
NETLIB_CONSTRUCTOR(log)
, m_I(*this, "I")
- , m_strm(plib::pfmt("{1}.log")(this->name()))
- , m_writer(m_strm)
+ , m_strm(pstring(plib::pfmt("{1}.log")(this->name())))
+ , m_writer(&m_strm)
{
}
NETLIB_UPDATEI()
{
/* use pstring::sprintf, it is a LOT faster */
- m_writer.writeline(plib::pfmt("{1:.9} {2}").e(netlist().time().as_double()).e(static_cast<double>(m_I())));
+ m_writer.writeline(plib::pfmt("{1:.9} {2}").e(exec().time().as_double()).e(static_cast<double>(m_I())));
}
NETLIB_RESETI() { }
@@ -46,7 +46,7 @@ namespace netlist
NETLIB_UPDATEI()
{
- m_writer.writeline(plib::pfmt("{1:.9} {2}").e(netlist().time().as_double()).e(static_cast<double>(m_I() - m_I2())));
+ m_writer.writeline(plib::pfmt("{1:.9} {2}").e(exec().time().as_double()).e(static_cast<double>(m_I() - m_I2())));
}
NETLIB_RESETI() { }
@@ -89,8 +89,8 @@ namespace netlist
#endif
- NETLIB_DEVICE_IMPL(log)
- NETLIB_DEVICE_IMPL(logD)
+ NETLIB_DEVICE_IMPL(log, "LOG", "+I")
+ NETLIB_DEVICE_IMPL(logD, "LOGD", "+I,+I2")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_log.h b/src/lib/netlist/devices/nld_log.h
index 6364022cea2..13c71ea7257 100644
--- a/src/lib/netlist/devices/nld_log.h
+++ b/src/lib/netlist/devices/nld_log.h
@@ -18,10 +18,10 @@
#ifndef NLD_LOG_H_
#define NLD_LOG_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define LOG(name, cI) \
- NET_REGISTER_DEV(??PG, name) \
+ NET_REGISTER_DEV(LOG, name) \
NET_CONNECT(name, I, cI)
#define LOGD(name, cI, cI2) \
diff --git a/src/lib/netlist/devices/nld_mm5837.cpp b/src/lib/netlist/devices/nld_mm5837.cpp
index e97ae41e437..f6c2566bd43 100644
--- a/src/lib/netlist/devices/nld_mm5837.cpp
+++ b/src/lib/netlist/devices/nld_mm5837.cpp
@@ -6,8 +6,8 @@
*/
#include "nld_mm5837.h"
-#include "../solver/nld_matrix_solver.h"
-#include "../analog/nlid_twoterm.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/solver/nld_matrix_solver.h"
#define R_LOW (1000.0)
#define R_HIGH (1000.0)
@@ -69,13 +69,13 @@ namespace netlist
{
//m_V0.initial(0.0);
//m_RV.do_reset();
- m_RV.set(NL_FCONST(1.0) / R_LOW, 0.0, 0.0);
+ m_RV.set_G_V_I(plib::constants<nl_double>::one() / R_LOW, 0.0, 0.0);
m_inc = netlist_time::from_double(1.0 / m_FREQ());
if (m_FREQ() < 24000 || m_FREQ() > 56000)
log().warning(MW_1_FREQUENCY_OUTSIDE_OF_SPECS_1, m_FREQ());
m_shift = 0x1ffff;
- m_is_timestep = m_RV.m_P.net().solver()->is_timestep();
+ m_is_timestep = m_RV.m_P.net().solver()->has_timestep_devices();
}
NETLIB_UPDATE_PARAM(MM5837_dip)
@@ -107,14 +107,14 @@ namespace netlist
// We only need to update the net first if this is a time stepping net
if (m_is_timestep)
- m_RV.update_dev();
- m_RV.set(NL_FCONST(1.0) / R, V, 0.0);
- m_RV.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
+ m_RV.update();
+ m_RV.set_G_V_I(plib::constants<nl_double>::one() / R, V, plib::constants<nl_double>::zero());
+ m_RV.solve_later(NLTIME_FROM_NS(1));
}
}
- NETLIB_DEVICE_IMPL(MM5837_dip)
+ NETLIB_DEVICE_IMPL(MM5837_dip, "MM5837_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_mm5837.h b/src/lib/netlist/devices/nld_mm5837.h
index 4af397d9965..8f764aa651f 100644
--- a/src/lib/netlist/devices/nld_mm5837.h
+++ b/src/lib/netlist/devices/nld_mm5837.h
@@ -19,7 +19,7 @@
#ifndef NLD_MM5837_H_
#define NLD_MM5837_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define MM5837_DIP(name) \
NET_REGISTER_DEV(MM5837_DIP, name)
diff --git a/src/lib/netlist/devices/nld_ne555.cpp b/src/lib/netlist/devices/nld_ne555.cpp
index 8795197bd57..5e990d2e974 100644
--- a/src/lib/netlist/devices/nld_ne555.cpp
+++ b/src/lib/netlist/devices/nld_ne555.cpp
@@ -46,8 +46,8 @@
*/
#include "nld_ne555.h"
-#include "../analog/nlid_twoterm.h"
-#include "../solver/nld_solver.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/solver/nld_solver.h"
#define R_OFF (1E20)
#define R_ON (25) // Datasheet states a maximum discharge of 200mA, R = 5V / 0.2
@@ -62,31 +62,37 @@ namespace netlist
, m_R1(*this, "R1")
, m_R2(*this, "R2")
, m_R3(*this, "R3")
+ , m_ROUT(*this, "ROUT")
, m_RDIS(*this, "RDIS")
, m_RESET(*this, "RESET") // Pin 4
, m_THRES(*this, "THRESH") // Pin 6
, m_TRIG(*this, "TRIG") // Pin 2
- , m_OUT(*this, "OUT") // Pin 3
+ , m_OUT(*this, "_OUT") // to Pin 3 via ROUT
, m_last_out(*this, "m_last_out", false)
, m_ff(*this, "m_ff", false)
+ , m_last_reset(*this, "m_last_reset", false)
{
register_subalias("GND", m_R3.m_N); // Pin 1
register_subalias("CONT", m_R1.m_N); // Pin 5
register_subalias("DISCH", m_RDIS.m_P); // Pin 7
register_subalias("VCC", m_R1.m_P); // Pin 8
+ register_subalias("OUT", m_ROUT.m_P); // Pin 3
connect(m_R1.m_N, m_R2.m_P);
+ connect(m_R1.m_N, m_R2.m_P);
connect(m_R2.m_N, m_R3.m_P);
connect(m_RDIS.m_N, m_R3.m_N);
+ connect(m_OUT, m_ROUT.m_N);
}
NETLIB_UPDATEI();
NETLIB_RESETI();
- protected:
+ private:
analog::NETLIB_SUB(R_base) m_R1;
analog::NETLIB_SUB(R_base) m_R2;
analog::NETLIB_SUB(R_base) m_R3;
+ analog::NETLIB_SUB(R_base) m_ROUT;
analog::NETLIB_SUB(R_base) m_RDIS;
logic_input_t m_RESET;
@@ -94,52 +100,51 @@ namespace netlist
analog_input_t m_TRIG;
analog_output_t m_OUT;
- private:
state_var<bool> m_last_out;
state_var<bool> m_ff;
+ state_var<bool> m_last_reset;
- inline nl_double clamp(const nl_double v, const nl_double a, const nl_double b);
-
+ nl_double clamp(const nl_double v, const nl_double a, const nl_double b)
+ {
+ nl_double ret = v;
+ nl_double vcc = m_R1.m_P();
+
+ if (ret > vcc - a)
+ ret = vcc - a;
+ if (ret < b)
+ ret = b;
+ return ret;
+ }
};
NETLIB_OBJECT_DERIVED(NE555_dip, NE555)
{
NETLIB_CONSTRUCTOR_DERIVED(NE555_dip, NE555)
{
- register_subalias("1", m_R3.m_N); // Pin 1
- register_subalias("2", m_TRIG); // Pin 2
- register_subalias("3", m_OUT); // Pin 3
- register_subalias("4", m_RESET); // Pin 4
- register_subalias("5", m_R1.m_N); // Pin 5
- register_subalias("6", m_THRES); // Pin 6
- register_subalias("7", m_RDIS.m_P); // Pin 7
- register_subalias("8", m_R1.m_P); // Pin 8
+ register_subalias("1", "GND"); // Pin 1
+ register_subalias("2", "TRIG"); // Pin 2
+ register_subalias("3", "OUT"); // Pin 3
+ register_subalias("4", "RESET"); // Pin 4
+ register_subalias("5", "CONT"); // Pin 5
+ register_subalias("6", "THRESH"); // Pin 6
+ register_subalias("7", "DISCH"); // Pin 7
+ register_subalias("8", "VCC"); // Pin 8
}
};
- inline nl_double NETLIB_NAME(NE555)::clamp(const nl_double v, const nl_double a, const nl_double b)
- {
- nl_double ret = v;
- nl_double vcc = m_R1.m_P();
-
- if (ret > vcc - a)
- ret = vcc - a;
- if (ret < b)
- ret = b;
- return ret;
- }
-
NETLIB_RESET(NE555)
{
- m_R1.do_reset();
- m_R2.do_reset();
- m_R3.do_reset();
- m_RDIS.do_reset();
+ m_R1.reset();
+ m_R2.reset();
+ m_R3.reset();
+ m_ROUT.reset();
+ m_RDIS.reset();
- /* FIXME make resistance a parameter, properly model other variants */
+ /* FIXME make resistances a parameter, properly model other variants */
m_R1.set_R(5000);
m_R2.set_R(5000);
m_R3.set_R(5000);
+ m_ROUT.set_R(20);
m_RDIS.set_R(R_OFF);
m_last_out = true;
@@ -149,39 +154,47 @@ namespace netlist
{
// FIXME: assumes GND is connected to 0V.
- nl_double vt = clamp(m_R2.m_P(), 0.7, 1.4);
- bool bthresh = (m_THRES() > vt);
- bool btrig = (m_TRIG() > clamp(m_R2.m_N(), 0.7, 1.4));
+ const auto reset = m_RESET();
- if (!btrig)
+ if (!reset && m_last_reset)
{
- m_ff = true;
+ m_ff = false;
}
- else if (bthresh)
+ else
{
- m_ff = false;
+ const nl_double vt = clamp(m_R2.m_P(), 0.7, 1.4);
+ const bool bthresh = (m_THRES() > vt);
+ const bool btrig = (m_TRIG() > clamp(m_R2.m_N(), 0.7, 1.4));
+
+ if (!btrig)
+ m_ff = true;
+ else if (bthresh)
+ m_ff = false;
}
- bool out = (!m_RESET() ? false : m_ff);
+ const bool out = (!reset ? false : m_ff);
if (m_last_out && !out)
{
- m_RDIS.update_dev();
+ m_RDIS.update();
m_OUT.push(m_R3.m_N());
m_RDIS.set_R(R_ON);
}
else if (!m_last_out && out)
{
- m_RDIS.update_dev();
+ m_RDIS.update();
// FIXME: Should be delayed by 100ns
m_OUT.push(m_R1.m_P());
m_RDIS.set_R(R_OFF);
}
+ m_last_reset = reset;
m_last_out = out;
}
- NETLIB_DEVICE_IMPL(NE555)
- NETLIB_DEVICE_IMPL(NE555_dip)
+ NETLIB_DEVICE_IMPL(NE555, "NE555", "")
+ NETLIB_DEVICE_IMPL(NE555_dip, "NE555_DIP", "")
+ NETLIB_DEVICE_IMPL_ALIAS(MC1455P, NE555, "MC1455P", "")
+ NETLIB_DEVICE_IMPL_ALIAS(MC1455P_dip, NE555_dip, "MC1455P_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_ne555.h b/src/lib/netlist/devices/nld_ne555.h
index c629253f08f..fc575d914b7 100644
--- a/src/lib/netlist/devices/nld_ne555.h
+++ b/src/lib/netlist/devices/nld_ne555.h
@@ -4,7 +4,7 @@
#ifndef NLD_NE555_H_
#define NLD_NE555_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define NE555(name) \
NET_REGISTER_DEV(NE555, name)
@@ -12,4 +12,10 @@
#define NE555_DIP(name) \
NET_REGISTER_DEV(NE555_DIP, name)
+#define MC1455P(name) \
+ NET_REGISTER_DEV(MC1455P, name)
+
+#define MC1455P_DIP(name) \
+ NET_REGISTER_DEV(MC1455P_DIP, name)
+
#endif /* NLD_NE555_H_ */
diff --git a/src/lib/netlist/devices/nld_r2r_dac.cpp b/src/lib/netlist/devices/nld_r2r_dac.cpp
index 4c29389d491..284b6673f76 100644
--- a/src/lib/netlist/devices/nld_r2r_dac.cpp
+++ b/src/lib/netlist/devices/nld_r2r_dac.cpp
@@ -5,9 +5,9 @@
*
*/
-#include "../nl_base.h"
-#include "../nl_factory.h"
-#include "../analog/nlid_twoterm.h"
+#include "netlist/nl_base.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/nl_factory.h"
namespace netlist
{
@@ -39,17 +39,17 @@ namespace netlist
NETLIB_UPDATE_PARAM(r2r_dac)
{
- update_dev();
+ solve_now();
double V = m_VIN() / static_cast<double>(1 << m_num())
* static_cast<double>(m_val());
- this->set(1.0 / m_R(), V, 0.0);
+ this->set_G_V_I(1.0 / m_R(), V, 0.0);
}
} //namespace analog
namespace devices {
- NETLIB_DEVICE_IMPL_NS(analog, r2r_dac)
- }
+ NETLIB_DEVICE_IMPL_NS(analog, r2r_dac, "R2R_DAC", "VIN,R,N")
+ } // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_r2r_dac.h b/src/lib/netlist/devices/nld_r2r_dac.h
index 18e5bddc053..8a4257a3cbf 100644
--- a/src/lib/netlist/devices/nld_r2r_dac.h
+++ b/src/lib/netlist/devices/nld_r2r_dac.h
@@ -46,7 +46,7 @@
#ifndef NLD_R2R_DAC_H_
#define NLD_R2R_DAC_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define R2R_DAC(name, p_VIN, p_R, p_N) \
NET_REGISTER_DEV(R2R_DAC, name) \
diff --git a/src/lib/netlist/devices/nld_schmitt.cpp b/src/lib/netlist/devices/nld_schmitt.cpp
index 4bc41075f89..f219d215520 100644
--- a/src/lib/netlist/devices/nld_schmitt.cpp
+++ b/src/lib/netlist/devices/nld_schmitt.cpp
@@ -7,10 +7,10 @@
#include "nld_schmitt.h"
-#include "../nl_base.h"
-#include "../nl_errstr.h"
-#include "../analog/nlid_twoterm.h"
-#include "../solver/nld_solver.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_errstr.h"
+#include "netlist/solver/nld_solver.h"
#include <cmath>
@@ -82,11 +82,11 @@ namespace netlist
NETLIB_RESETI()
{
m_last_state = 1;
- m_RVI.do_reset();
- m_RVO.do_reset();
+ m_RVI.reset();
+ m_RVO.reset();
m_is_timestep = m_RVO.m_P.net().solver()->has_timestep_devices();
- m_RVI.set(NL_FCONST(1.0) / m_model.m_RI, m_model.m_VI, 0.0);
- m_RVO.set(NL_FCONST(1.0) / m_model.m_ROL, m_model.m_VOL, 0.0);
+ m_RVI.set_G_V_I(plib::constants<nl_double>::one() / m_model.m_RI, m_model.m_VI, 0.0);
+ m_RVO.set_G_V_I(plib::constants<nl_double>::one() / m_model.m_ROL, m_model.m_VOL, 0.0);
}
NETLIB_UPDATEI()
@@ -97,9 +97,9 @@ namespace netlist
{
m_last_state = 0;
if (m_is_timestep)
- m_RVO.update_dev();
- m_RVO.set(NL_FCONST(1.0) / m_model.m_ROH, m_model.m_VOH, 0.0);
- m_RVO.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
+ m_RVO.update();
+ m_RVO.set_G_V_I(plib::constants<nl_double>::one() / m_model.m_ROH, m_model.m_VOH, 0.0);
+ m_RVO.solve_later();
}
}
else
@@ -108,9 +108,9 @@ namespace netlist
{
m_last_state = 1;
if (m_is_timestep)
- m_RVO.update_dev();
- m_RVO.set(NL_FCONST(1.0) / m_model.m_ROL, m_model.m_VOL, 0.0);
- m_RVO.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
+ m_RVO.update();
+ m_RVO.set_G_V_I(plib::constants<nl_double>::one() / m_model.m_ROL, m_model.m_VOL, 0.0);
+ m_RVO.solve_later();
}
}
}
@@ -125,7 +125,7 @@ namespace netlist
bool m_is_timestep;
};
- NETLIB_DEVICE_IMPL(schmitt_trigger)
+ NETLIB_DEVICE_IMPL(schmitt_trigger, "SCHMITT_TRIGGER", "MODEL")
} // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_schmitt.h b/src/lib/netlist/devices/nld_schmitt.h
index ecce59be616..20666b29cf7 100644
--- a/src/lib/netlist/devices/nld_schmitt.h
+++ b/src/lib/netlist/devices/nld_schmitt.h
@@ -11,7 +11,7 @@
#define NLD_SCHMITT_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// ----------------------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp
index eabc4b4fbff..03aa5c678f1 100644
--- a/src/lib/netlist/devices/nld_system.cpp
+++ b/src/lib/netlist/devices/nld_system.cpp
@@ -5,8 +5,8 @@
*
*/
-#include "../solver/nld_solver.h"
-#include "../solver/nld_matrix_solver.h"
+#include "netlist/solver/nld_solver.h"
+#include "netlist/solver/nld_matrix_solver.h"
#include "nlid_system.h"
namespace netlist
@@ -40,54 +40,40 @@ namespace netlist
{
m_cnt = 0;
m_off = netlist_time::from_double(m_offset());
+ m_feedback.m_delegate = NETLIB_DELEGATE(extclock, update);
+
+ //m_feedback.m_delegate .set(&NETLIB_NAME(extclock)::update, this);
//m_Q.initial(0);
}
- NETLIB_UPDATE(extclock)
+ NETLIB_HANDLER(extclock, clk2)
{
- m_Q.push((m_cnt & 1) ^ 1, m_inc[m_cnt] + m_off);
- m_off = netlist_time::zero();
+ m_Q.push((m_cnt & 1) ^ 1, m_inc[m_cnt]);
if (++m_cnt >= m_size)
m_cnt = 0;
}
- // ----------------------------------------------------------------------------------------
- // logic_input
- // ----------------------------------------------------------------------------------------
-
- NETLIB_RESET(logic_input)
- {
- m_Q.initial(0);
- }
-
- NETLIB_UPDATE(logic_input)
+ NETLIB_HANDLER(extclock, clk2_pow2)
{
- m_Q.push(m_IN() & 1, netlist_time::from_nsec(1));
+ m_Q.push((m_cnt & 1) ^ 1, m_inc[m_cnt]);
+ m_cnt = (++m_cnt) & (m_size-1);
}
- NETLIB_UPDATE_PARAM(logic_input)
- {
- }
-
- // ----------------------------------------------------------------------------------------
- // analog_input
- // ----------------------------------------------------------------------------------------
-
- NETLIB_RESET(analog_input)
+ NETLIB_UPDATE(extclock)
{
- m_Q.initial(0.0);
- }
+ m_Q.push((m_cnt & 1) ^ 1, m_inc[m_cnt] + m_off);
+ m_off = netlist_time::zero();
+ if (++m_cnt >= m_size)
+ m_cnt = 0;
- NETLIB_UPDATE(analog_input)
- {
- m_Q.push(m_IN());
- }
+ // continue with optimized clock handlers ....
- NETLIB_UPDATE_PARAM(analog_input)
- {
+ if ((m_size & (m_size-1)) == 0) // power of 2?
+ m_feedback.m_delegate.set(&NETLIB_NAME(extclock)::clk2_pow2, this);
+ else
+ m_feedback.m_delegate.set(&NETLIB_NAME(extclock)::clk2, this);
}
-
// -----------------------------------------------------------------------------
// nld_res_sw
// -----------------------------------------------------------------------------
@@ -106,19 +92,10 @@ namespace netlist
m_last_state = state;
const nl_double R = state ? m_RON() : m_ROFF();
- // We only need to update the net first if this is a time stepping net
- if ((0)) // m_R->m_P.net().as_analog().solver()->is_timestep())
- {
- m_R.update_dev();
- m_R.set_R(R);
- m_R.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
- }
- else
- {
- m_R.set_R(R);
- m_R.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
- //m_R->update_dev();
- }
+ // FIXME: We only need to update the net first if this is a time stepping net
+ m_R.update();
+ m_R.set_R(R);
+ m_R.solve_later();
}
}
@@ -141,17 +118,19 @@ namespace netlist
}
- NETLIB_DEVICE_IMPL(dummy_input)
- NETLIB_DEVICE_IMPL(frontier)
- NETLIB_DEVICE_IMPL(function)
- NETLIB_DEVICE_IMPL(logic_input)
- NETLIB_DEVICE_IMPL(analog_input)
- NETLIB_DEVICE_IMPL(clock)
- NETLIB_DEVICE_IMPL(extclock)
- NETLIB_DEVICE_IMPL(res_sw)
- NETLIB_DEVICE_IMPL(mainclock)
- NETLIB_DEVICE_IMPL(gnd)
- NETLIB_DEVICE_IMPL(netlistparams)
+ NETLIB_DEVICE_IMPL(dummy_input, "DUMMY_INPUT", "")
+ NETLIB_DEVICE_IMPL(frontier, "FRONTIER_DEV", "+I,+G,+Q")
+ NETLIB_DEVICE_IMPL(function, "AFUNC", "N,FUNC")
+ NETLIB_DEVICE_IMPL(analog_input, "ANALOG_INPUT", "IN")
+ NETLIB_DEVICE_IMPL(clock, "CLOCK", "FREQ")
+ NETLIB_DEVICE_IMPL(extclock, "EXTCLOCK", "FREQ,PATTERN")
+ NETLIB_DEVICE_IMPL(res_sw, "RES_SWITCH", "+IN,+P1,+P2")
+ NETLIB_DEVICE_IMPL(mainclock, "MAINCLOCK", "FREQ")
+ NETLIB_DEVICE_IMPL(gnd, "GND", "")
+ NETLIB_DEVICE_IMPL(netlistparams, "PARAMETER", "")
+
+ NETLIB_DEVICE_IMPL(logic_input, "LOGIC_INPUT", "IN,FAMILY")
+ NETLIB_DEVICE_IMPL_ALIAS(logic_input_ttl, logic_input, "TTL_INPUT", "IN")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_system.h b/src/lib/netlist/devices/nld_system.h
index 69a7c75dbf3..5158e098cfa 100644
--- a/src/lib/netlist/devices/nld_system.h
+++ b/src/lib/netlist/devices/nld_system.h
@@ -9,7 +9,7 @@
#ifndef NLD_SYSTEM_H_
#define NLD_SYSTEM_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
// -----------------------------------------------------------------------------
// Macros
diff --git a/src/lib/netlist/devices/nld_tms4800.cpp b/src/lib/netlist/devices/nld_tms4800.cpp
index 29a9bd836ab..24729b10e72 100644
--- a/src/lib/netlist/devices/nld_tms4800.cpp
+++ b/src/lib/netlist/devices/nld_tms4800.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_tms4800.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -39,9 +39,9 @@ namespace netlist
param_rom_t<uint8_t, 11, 8> m_ROM; // 16 Kbits, used as 2 Kbit x 8
};
- NETLIB_OBJECT_DERIVED(tms4800_dip, TMS4800)
+ NETLIB_OBJECT_DERIVED(TMS4800_dip, TMS4800)
{
- NETLIB_CONSTRUCTOR_DERIVED(tms4800_dip, TMS4800)
+ NETLIB_CONSTRUCTOR_DERIVED(TMS4800_dip, TMS4800)
{
register_subalias("2", m_A[0]);
register_subalias("3", m_A[1]);
@@ -97,8 +97,8 @@ namespace netlist
}
}
- NETLIB_DEVICE_IMPL(TMS4800)
- NETLIB_DEVICE_IMPL(tms4800_dip)
+ NETLIB_DEVICE_IMPL(TMS4800, "ROM_TMS4800", "+AR,+OE1,+OE2,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10")
+ NETLIB_DEVICE_IMPL(TMS4800_dip, "ROM_TMS4800_DIP", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_tms4800.h b/src/lib/netlist/devices/nld_tms4800.h
index dc72354cb03..c5bcd1337f0 100644
--- a/src/lib/netlist/devices/nld_tms4800.h
+++ b/src/lib/netlist/devices/nld_tms4800.h
@@ -28,7 +28,7 @@
#ifndef NLD_TMS4800_H_
#define NLD_TMS4800_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define ROM_TMS4800(name, cAR, cOE1, cOE2, cA0, cA1, cA2, cA3, cA4, cA5, cA6, cA7, cA8, cA9, cA10) \
NET_REGISTER_DEV(ROM_TMS4800, name) \
diff --git a/src/lib/netlist/devices/nld_tristate.cpp b/src/lib/netlist/devices/nld_tristate.cpp
index 74fbb206feb..b05d09ea71e 100644
--- a/src/lib/netlist/devices/nld_tristate.cpp
+++ b/src/lib/netlist/devices/nld_tristate.cpp
@@ -6,7 +6,7 @@
*/
#include "nld_tristate.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
namespace netlist
{
@@ -70,8 +70,8 @@ namespace netlist
m_Q.push(q, NLTIME_FROM_NS(1));
}
- NETLIB_DEVICE_IMPL(tristate)
- NETLIB_DEVICE_IMPL(tristate3)
+ NETLIB_DEVICE_IMPL(tristate, "TTL_TRISTATE", "+CEQ1,+D1,+CEQ2,+D2")
+ NETLIB_DEVICE_IMPL(tristate3, "TTL_TRISTATE3", "")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_tristate.h b/src/lib/netlist/devices/nld_tristate.h
index a5ff22fac96..71f97d9812d 100644
--- a/src/lib/netlist/devices/nld_tristate.h
+++ b/src/lib/netlist/devices/nld_tristate.h
@@ -10,7 +10,7 @@
#ifndef NLD_TRISTATE_H_
#define NLD_TRISTATE_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#define TTL_TRISTATE(name, cCEQ1, cD1, cCEQ2, cD2) \
NET_REGISTER_DEV(TTL_TRISTATE, name) \
diff --git a/src/lib/netlist/devices/nlid_cmos.h b/src/lib/netlist/devices/nlid_cmos.h
index f9999aebcc0..d91d691453a 100644
--- a/src/lib/netlist/devices/nlid_cmos.h
+++ b/src/lib/netlist/devices/nlid_cmos.h
@@ -8,8 +8,8 @@
#ifndef NLID_CMOS_H_
#define NLID_CMOS_H_
-#include "../nl_setup.h"
-#include "../nl_base.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_setup.h"
namespace netlist
{
diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp
index 4c3ec6f67aa..a2fd18e85a7 100644
--- a/src/lib/netlist/devices/nlid_proxy.cpp
+++ b/src/lib/netlist/devices/nlid_proxy.cpp
@@ -6,7 +6,7 @@
*/
#include "nlid_proxy.h"
-#include "../solver/nld_solver.h"
+#include "netlist/solver/nld_solver.h"
//#include "plib/pstream.h"
//#include "plib/pfmtlog.h"
//#include "nld_log.h"
@@ -20,7 +20,7 @@ namespace netlist
// nld_base_proxy
// -----------------------------------------------------------------------------
- nld_base_proxy::nld_base_proxy(netlist_t &anetlist, const pstring &name,
+ nld_base_proxy::nld_base_proxy(netlist_state_t &anetlist, const pstring &name,
logic_t *inout_proxied, detail::core_terminal_t *proxy_inout)
: device_t(anetlist, name)
{
@@ -29,33 +29,23 @@ namespace netlist
m_proxy_term = proxy_inout;
}
- nld_base_proxy::~nld_base_proxy()
- {
- }
-
// ----------------------------------------------------------------------------------------
// nld_a_to_d_proxy
// ----------------------------------------------------------------------------------------
- nld_base_a_to_d_proxy::nld_base_a_to_d_proxy(netlist_t &anetlist, const pstring &name,
+ nld_base_a_to_d_proxy::nld_base_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name,
logic_input_t *in_proxied, detail::core_terminal_t *in_proxy)
: nld_base_proxy(anetlist, name, in_proxied, in_proxy)
, m_Q(*this, "Q")
{
}
- nld_base_a_to_d_proxy::~nld_base_a_to_d_proxy() {}
-
- nld_a_to_d_proxy::nld_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied)
+ nld_a_to_d_proxy::nld_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *in_proxied)
: nld_base_a_to_d_proxy(anetlist, name, in_proxied, &m_I)
, m_I(*this, "I")
{
}
- nld_a_to_d_proxy::~nld_a_to_d_proxy()
- {
- }
-
NETLIB_RESET(a_to_d_proxy)
{
}
@@ -81,39 +71,32 @@ namespace netlist
// nld_d_to_a_proxy
// ----------------------------------------------------------------------------------------
- nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(netlist_t &anetlist, const pstring &name,
+ nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name,
logic_output_t *out_proxied, detail::core_terminal_t &proxy_out)
: nld_base_proxy(anetlist, name, out_proxied, &proxy_out)
, m_I(*this, "I")
{
}
- nld_base_d_to_a_proxy::~nld_base_d_to_a_proxy()
- {
- }
-
- nld_d_to_a_proxy::nld_d_to_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *out_proxied)
+ nld_d_to_a_proxy::nld_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *out_proxied)
: nld_base_d_to_a_proxy(anetlist, name, out_proxied, m_RV.m_P)
, m_GNDHack(*this, "_Q")
, m_RV(*this, "RV")
, m_last_state(*this, "m_last_var", -1)
, m_is_timestep(false)
{
- const pstring power_syms[3][2] ={ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}};
- //register_sub(m_RV);
- //register_term("1", m_RV.m_P);
- //register_term("2", m_RV.m_N);
+ const std::vector<std::pair<pstring, pstring>> power_syms = { {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}};
register_subalias("Q", m_RV.m_P);
connect(m_RV.m_N, m_GNDHack);
bool f = false;
- for (int i = 0; i < 3; i++)
+ for (auto & pwr_sym : power_syms)
{
pstring devname = out_proxied->device().name();
- auto tp = netlist().setup().find_terminal(devname + "." + power_syms[i][0],
+ auto tp = setup().find_terminal(devname + "." + pwr_sym.first,
detail::terminal_type::INPUT, false);
- auto tn = netlist().setup().find_terminal(devname + "." + power_syms[i][1],
+ auto tn = setup().find_terminal(devname + "." + pwr_sym.second,
detail::terminal_type::INPUT, false);
if (tp != nullptr && tn != nullptr)
{
@@ -126,11 +109,6 @@ namespace netlist
log().warning(MW_1_NO_POWER_TERMINALS_ON_DEVICE_1, out_proxied->device().name());
else
log().verbose("D/A Proxy: Found power terminals on device {1}", out_proxied->device().name());
-#if (0)
- printf("%s %s\n", out_proxied->name().c_str(), out_proxied->device().name().c_str());
- auto x = netlist().setup().find_terminal(out_proxied->name(), detail::device_object_t::terminal_type::OUTPUT, false);
- if (x) printf("==> %s\n", x->name().c_str());
-#endif
}
@@ -142,15 +120,15 @@ namespace netlist
//m_Q.initial(0.0);
m_last_state = -1;
- m_RV.do_reset();
+ m_RV.reset();
m_is_timestep = m_RV.m_P.net().solver()->has_timestep_devices();
- m_RV.set(NL_FCONST(1.0) / logic_family()->R_low(),
+ m_RV.set_G_V_I(plib::constants<nl_double>::one() / logic_family()->R_low(),
logic_family()->low_V(0.0, supply_V), 0.0);
}
NETLIB_UPDATE(d_to_a_proxy)
{
- const int state = static_cast<int>(m_I());
+ const auto state = static_cast<int>(m_I());
if (state != m_last_state)
{
// FIXME: Variable voltage
@@ -163,10 +141,10 @@ namespace netlist
// We only need to update the net first if this is a time stepping net
if (m_is_timestep)
{
- m_RV.update_dev();
+ m_RV.update();
}
- m_RV.set(NL_FCONST(1.0) / R, V, 0.0);
- m_RV.m_P.schedule_solve_after(NLTIME_FROM_NS(1));
+ m_RV.set_G_V_I(plib::constants<nl_double>::one() / R, V, 0.0);
+ m_RV.solve_later();
}
}
diff --git a/src/lib/netlist/devices/nlid_proxy.h b/src/lib/netlist/devices/nlid_proxy.h
index 821cfa56d9d..9543b8db234 100644
--- a/src/lib/netlist/devices/nlid_proxy.h
+++ b/src/lib/netlist/devices/nlid_proxy.h
@@ -11,8 +11,8 @@
#ifndef NLID_PROXY_H_
#define NLID_PROXY_H_
-#include "../nl_setup.h"
-#include "../analog/nlid_twoterm.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/nl_setup.h"
namespace netlist
{
@@ -26,11 +26,9 @@ namespace netlist
NETLIB_OBJECT(base_proxy)
{
public:
- nld_base_proxy(netlist_t &anetlist, const pstring &name,
+ nld_base_proxy(netlist_state_t &anetlist, const pstring &name,
logic_t *inout_proxied, detail::core_terminal_t *proxy_inout);
- virtual ~nld_base_proxy();
-
logic_t &term_proxied() const { return *m_term_proxied; }
detail::core_terminal_t &proxy_term() const { return *m_proxy_term; }
@@ -49,13 +47,11 @@ namespace netlist
{
public:
- virtual ~nld_base_a_to_d_proxy();
-
virtual logic_output_t &out() { return m_Q; }
protected:
- nld_base_a_to_d_proxy(netlist_t &anetlist, const pstring &name,
+ nld_base_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name,
logic_input_t *in_proxied, detail::core_terminal_t *in_proxy);
private:
@@ -67,9 +63,7 @@ namespace netlist
NETLIB_OBJECT_DERIVED(a_to_d_proxy, base_a_to_d_proxy)
{
public:
- nld_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied);
-
- virtual ~nld_a_to_d_proxy() override;
+ nld_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *in_proxied);
analog_input_t m_I;
@@ -88,24 +82,20 @@ namespace netlist
NETLIB_OBJECT_DERIVED(base_d_to_a_proxy, base_proxy)
{
public:
- virtual ~nld_base_d_to_a_proxy();
virtual logic_input_t &in() { return m_I; }
protected:
- nld_base_d_to_a_proxy(netlist_t &anetlist, const pstring &name,
+ nld_base_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name,
logic_output_t *out_proxied, detail::core_terminal_t &proxy_out);
logic_input_t m_I;
-
- private:
};
NETLIB_OBJECT_DERIVED(d_to_a_proxy, base_d_to_a_proxy)
{
public:
- nld_d_to_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *out_proxied);
- virtual ~nld_d_to_a_proxy() override {}
+ nld_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *out_proxied);
protected:
diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h
index 326cd3dbf2c..f1f2af1b31e 100644
--- a/src/lib/netlist/devices/nlid_system.h
+++ b/src/lib/netlist/devices/nlid_system.h
@@ -11,10 +11,10 @@
#ifndef NLID_SYSTEM_H_
#define NLID_SYSTEM_H_
-#include "../nl_base.h"
-#include "../nl_setup.h"
-#include "../analog/nlid_twoterm.h"
-#include "../plib/putil.h"
+#include "netlist/analog/nlid_twoterm.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_setup.h"
+#include "plib/putil.h"
namespace netlist
{
@@ -27,7 +27,8 @@ namespace netlist
NETLIB_OBJECT(netlistparams)
{
NETLIB_CONSTRUCTOR(netlistparams)
- , m_use_deactivate(*this, "USE_DEACTIVATE", 0)
+ , m_use_deactivate(*this, "USE_DEACTIVATE", false)
+ , m_startup_strategy(*this, "STARTUP_STRATEGY", 1)
{
}
NETLIB_UPDATEI() { }
@@ -35,6 +36,7 @@ namespace netlist
//NETLIB_UPDATE_PARAMI() { }
public:
param_logic_t m_use_deactivate;
+ param_int_t m_startup_strategy;
};
// -----------------------------------------------------------------------------
@@ -52,7 +54,7 @@ namespace netlist
NETLIB_RESETI()
{
- m_Q.net().set_time(netlist_time::zero());
+ m_Q.net().set_next_scheduled_time(netlist_time::zero());
}
NETLIB_UPDATE_PARAMI()
@@ -65,16 +67,14 @@ namespace netlist
logic_net_t &net = m_Q.net();
// this is only called during setup ...
net.toggle_new_Q();
- net.set_time(netlist().time() + m_inc);
+ net.set_next_scheduled_time(exec().time() + m_inc);
}
public:
logic_output_t m_Q;
-
- param_double_t m_freq;
netlist_time m_inc;
-
- inline static void mc_update(logic_net_t &net);
+ private:
+ param_double_t m_freq;
};
// -----------------------------------------------------------------------------
@@ -96,7 +96,7 @@ namespace netlist
//NETLIB_RESETI();
NETLIB_UPDATE_PARAMI();
- protected:
+ private:
logic_input_t m_feedback;
logic_output_t m_Q;
@@ -127,31 +127,35 @@ namespace netlist
std::vector<pstring> pat(plib::psplit(m_pattern(),","));
m_off = netlist_time::from_double(m_offset());
- unsigned long pati[32];
- for (int pI = 0; pI < 32; pI++)
- {
- pati[pI] = 0;
- }
+ std::array<std::int64_t, 32> pati = { 0 };
+
m_size = static_cast<std::uint8_t>(pat.size());
- unsigned long total = 0;
+ netlist_time::mult_type total = 0;
for (unsigned i=0; i<m_size; i++)
{
- pati[i] = static_cast<unsigned long>(pat[i].as_long());
+ // FIXME: use pstonum_ne
+ //pati[i] = plib::pstonum<decltype(pati[i])>(pat[i]);
+ pati[i] = plib::pstonum<std::int64_t>(pat[i]);
total += pati[i];
}
netlist_time ttotal = netlist_time::zero();
- for (unsigned i=0; i<m_size - 1; i++)
+ auto sm1 = static_cast<uint8_t>(m_size - 1);
+ for (unsigned i=0; i < sm1; i++)
{
m_inc[i] = base * pati[i];
ttotal += m_inc[i];
}
- m_inc[m_size - 1] = base * total - ttotal;
+ m_inc[sm1] = base * total - ttotal;
}
}
NETLIB_UPDATEI();
NETLIB_RESETI();
//NETLIB_UPDATE_PARAMI();
- protected:
+
+ NETLIB_HANDLERI(clk2);
+ NETLIB_HANDLERI(clk2_pow2);
+
+ private:
param_double_t m_freq;
param_str_t m_pattern;
@@ -162,7 +166,7 @@ namespace netlist
state_var_u8 m_cnt;
std::uint8_t m_size;
state_var<netlist_time> m_off;
- netlist_time m_inc[32];
+ std::array<netlist_time, 32> m_inc;
};
// -----------------------------------------------------------------------------
@@ -173,20 +177,19 @@ namespace netlist
{
NETLIB_CONSTRUCTOR(logic_input)
, m_Q(*this, "Q")
- , m_IN(*this, "IN", 0)
+ , m_IN(*this, "IN", false)
/* make sure we get the family first */
, m_FAMILY(*this, "FAMILY", "FAMILY(TYPE=TTL)")
{
set_logic_family(setup().family_from_model(m_FAMILY()));
+ m_Q.set_logic_family(this->logic_family());
}
- NETLIB_UPDATE_AFTER_PARAM_CHANGE()
-
- NETLIB_UPDATEI();
- NETLIB_RESETI();
- NETLIB_UPDATE_PARAMI();
+ NETLIB_UPDATEI() { }
+ NETLIB_RESETI() { m_Q.initial(0); }
+ NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN() & 1, netlist_time::from_nsec(1)); }
- protected:
+ private:
logic_output_t m_Q;
param_logic_t m_IN;
@@ -200,12 +203,12 @@ namespace netlist
, m_IN(*this, "IN", 0.0)
{
}
- NETLIB_UPDATE_AFTER_PARAM_CHANGE()
- NETLIB_UPDATEI();
- NETLIB_RESETI();
- NETLIB_UPDATE_PARAMI();
- protected:
+ NETLIB_UPDATEI() { }
+ NETLIB_RESETI() { m_Q.initial(0.0); }
+ NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN()); }
+
+ private:
analog_output_t m_Q;
param_double_t m_IN;
};
@@ -278,8 +281,8 @@ namespace netlist
NETLIB_RESETI()
{
- m_RIN.set(1.0 / m_p_RIN(),0,0);
- m_ROUT.set(1.0 / m_p_ROUT(),0,0);
+ m_RIN.set_G_V_I(1.0 / m_p_RIN(),0,0);
+ m_ROUT.set_G_V_I(1.0 / m_p_ROUT(),0,0);
}
NETLIB_UPDATEI()
@@ -310,13 +313,13 @@ namespace netlist
, m_N(*this, "N", 1)
, m_func(*this, "FUNC", "A0")
, m_Q(*this, "Q")
- , m_compiled(this->name() + ".FUNCC", this, this->netlist().state())
+ , m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
{
std::vector<pstring> inps;
for (int i=0; i < m_N(); i++)
{
pstring n = plib::pfmt("A{1}")(i);
- m_I.push_back(plib::make_unique<analog_input_t>(*this, n));
+ m_I.push_back(pool().make_poolptr<analog_input_t>(*this, n));
inps.push_back(n);
m_vals.push_back(0.0);
}
@@ -333,7 +336,7 @@ namespace netlist
param_int_t m_N;
param_str_t m_func;
analog_output_t m_Q;
- std::vector<std::unique_ptr<analog_input_t>> m_I;
+ std::vector<pool_owned_ptr<analog_input_t>> m_I;
std::vector<double> m_vals;
plib::pfunction m_compiled;
@@ -357,16 +360,17 @@ namespace netlist
register_subalias("2", m_R.m_N);
}
+ NETLIB_RESETI();
+ //NETLIB_UPDATE_PARAMI();
+ NETLIB_UPDATEI();
+
analog::NETLIB_SUB(R_base) m_R;
logic_input_t m_I;
param_double_t m_RON;
param_double_t m_ROFF;
- NETLIB_RESETI();
- //NETLIB_UPDATE_PARAMI();
- NETLIB_UPDATEI();
-
private:
+
state_var<netlist_sig_t> m_last_state;
};
diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp
index bf7d03fe3d7..2221d855880 100644
--- a/src/lib/netlist/devices/nlid_truthtable.cpp
+++ b/src/lib/netlist/devices/nlid_truthtable.cpp
@@ -6,9 +6,9 @@
*/
#include "nlid_truthtable.h"
-#include "../plib/plists.h"
-#include "../nl_setup.h"
-#include "../plib/palloc.h"
+#include "netlist/nl_setup.h"
+#include "plib/palloc.h"
+#include "plib/plists.h"
#include <bitset>
@@ -24,7 +24,7 @@ namespace netlist
template <typename T>
struct sbitset
{
- typedef T type;
+ using type = T;
sbitset() : m_bs(0) { }
/* explicit */ sbitset(T v) : m_bs(v) { }
@@ -77,8 +77,8 @@ namespace netlist
return ret;
}
- static constexpr sbitset all_bits() { return sbitset(~static_cast<T>(0)); }
- static constexpr sbitset no_bits() { return sbitset(static_cast<T>(0)); }
+ static constexpr const sbitset all_bits() noexcept { return sbitset(~static_cast<T>(0)); }
+ static constexpr const sbitset no_bits() noexcept{ return sbitset(static_cast<T>(0)); }
private:
T m_bs;
};
@@ -122,8 +122,18 @@ namespace netlist
}
}
- uint_least64_t mask() const { return static_cast<uint_least64_t>(-1); }
-
+ uint_least64_t mask() const
+ {
+ switch (m_size)
+ {
+ case 8: return static_cast<uint_least8_t>(-1);
+ case 16: return static_cast<uint_least16_t>(-1);
+ case 32: return static_cast<uint_least32_t>(-1);
+ case 64: return static_cast<uint_least64_t>(-1);
+ default:
+ return 0; //should never happen
+ }
+ }
private:
void *m_data;
size_t m_size;
@@ -134,7 +144,7 @@ namespace netlist
truthtable_parser(unsigned NO, unsigned NI, bool *initialized,
packed_int outs, uint_least8_t *timing, netlist_time *timing_nt)
: m_NO(NO), m_NI(NI), m_initialized(initialized),
- m_outs(outs), m_timing(timing), m_timing_nt(timing_nt),
+ m_out_state(outs), m_timing(timing), m_timing_nt(timing_nt),
m_num_bits(m_NI),
m_size(1 << (m_num_bits))
{
@@ -151,7 +161,7 @@ namespace netlist
unsigned m_NO;
unsigned m_NI;
bool *m_initialized;
- packed_int m_outs;
+ packed_int m_out_state;
uint_least8_t *m_timing;
netlist_time *m_timing_nt;
@@ -178,51 +188,27 @@ namespace netlist
nl_assert_always(io.size() == 2, "too many '|'");
std::vector<pstring> inout(plib::psplit(io[0], ","));
nl_assert_always(inout.size() == m_num_bits, "bitcount wrong");
- std::vector<pstring> out(plib::psplit(io[1], ","));
- nl_assert_always(out.size() == m_NO, "output count wrong");
+ std::vector<pstring> outputs(plib::psplit(io[1], ","));
+ nl_assert_always(outputs.size() == m_NO, "output count wrong");
for (std::size_t i=0; i < m_NI; i++)
{
- inout[i] = inout[i].trim();
+ inout[i] = plib::trim(inout[i]);
m_I.emplace(i, *this, inout[i]);
}
for (std::size_t i=0; i < m_NO; i++)
{
- out[i] = out[i].trim();
- m_Q.emplace(i, *this, out[i]);
- }
- // Connect output "Q" to input "_Q" if this exists
- // This enables timed state without having explicit state ....
- tt_bitset disabled_ignore = 0;
- for (std::size_t i=0; i < m_NO; i++)
- {
- pstring tmp = "_" + out[i];
+ outputs[i] = plib::trim(outputs[i]);
+ m_Q.emplace(i, *this, outputs[i]);
+ // Connect output "Q" to input "_Q" if this exists
+ // This enables timed state without having explicit state ....
+ pstring tmp = "_" + outputs[i];
const std::size_t idx = plib::container::indexof(inout, tmp);
if (idx != plib::container::npos)
- {
connect(m_Q[i], m_I[idx]);
- // disable ignore for theses inputs altogether.
- // FIXME: This shouldn't be necessary
- disabled_ignore.set(idx);
- }
}
m_ign = 0;
-
-#if 0
- for (size_t i=0; i<m_size; i++)
- {
- m_ttp.m_outs[i] &= ~(disabled_ignore << m_NO);
- }
-#endif
-#if 0
- printf("%s\n", name().c_str());
- for (int j=0; j < m_size; j++)
- printf("%05x %04x %04x %04x\n", j, m_ttp->m_outs[j] & ((1 << m_NO)-1),
- m_ttp->m_outs[j] >> m_NO, m_ttp->m_timing[j * m_NO + 0]);
- for (int k=0; m_ttp->m_timing_nt[k] != netlist_time::zero(); k++)
- printf("%d %f\n", k, m_ttp->m_timing_nt[k].as_double() * 1000000.0);
-#endif
}
// ----------------------------------------------------------------------------------------
@@ -238,15 +224,20 @@ namespace netlist
: netlist_base_factory_truthtable_t(name, classname, def_param, sourcefile)
{ }
- plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override
+ pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) override
{
- typedef nld_truthtable_t<m_NI, m_NO> tt_type;
+ using tt_type = nld_truthtable_t<m_NI, m_NO>;
truthtable_parser desc_s(m_NO, m_NI, &m_ttbl.m_initialized,
- packed_int(m_ttbl.m_outs, sizeof(m_ttbl.m_outs[0]) * 8),
- m_ttbl.m_timing, m_ttbl.m_timing_nt);
+ packed_int(m_ttbl.m_out_state.data(), sizeof(m_ttbl.m_out_state[0]) * 8),
+ m_ttbl.m_timing_index.data(), m_ttbl.m_timing_nt.data());
desc_s.parse(m_desc);
- return plib::owned_ptr<device_t>::Create<tt_type>(anetlist, name, m_family, m_ttbl, m_desc);
+
+ /* update truthtable family definitions */
+ if (m_family_name != "")
+ m_family_desc = anetlist.setup().family_from_model(m_family_name);
+
+ return pool().make_poolptr<tt_type>(anetlist, name, m_family_desc, m_ttbl, m_desc);
}
private:
typename nld_truthtable_t<m_NI, m_NO>::truthtable_t m_ttbl;
@@ -259,7 +250,7 @@ namespace netlist
for (std::size_t j=0; j<m_NI; j++)
{
// if changing the input directly doesn't change outputs we can ignore
- if (m_outs[state] == m_outs[tt_bitset(state).set(j)])
+ if (m_out_state[state] == m_out_state[tt_bitset(state).set(j)])
ignore.set(j);
}
@@ -285,7 +276,7 @@ namespace netlist
{
tt_bitset b = tign.expand_and(k);
// will any of the inputs ignored change the output if changed?
- if (m_outs[state] != m_outs[(state & tign.invert()) | b])
+ if (m_out_state[state] != m_out_state[(state & tign.invert()) | b])
{
t[j] = true;
break;
@@ -318,21 +309,21 @@ namespace netlist
void truthtable_parser::parseline(unsigned cur, std::vector<pstring> list,
tt_bitset state, uint_least64_t val, std::vector<uint_least8_t> &timing_index)
{
- pstring elem = list[cur].trim();
+ pstring elem = plib::trim(list[cur]);
uint_least64_t start = 0;
uint_least64_t end = 0;
- if (elem.equals("0"))
+ if (elem == "0")
{
start = 0;
end = 0;
}
- else if (elem.equals("1"))
+ else if (elem == "1")
{
start = 1;
end = 1;
}
- else if (elem.equals("X"))
+ else if (elem == "X")
{
start = 0;
end = 1;
@@ -352,10 +343,10 @@ void truthtable_parser::parseline(unsigned cur, std::vector<pstring> list,
else
{
// cutoff previous inputs and outputs for ignore
- if (m_outs[nstate] != m_outs.mask() && m_outs[nstate] != val)
- nl_exception(plib::pfmt("Error in truthtable: State {1:04} already set, {2} != {3}\n")
- .x(nstate.as_uint())(m_outs[nstate])(val) );
- m_outs.set(nstate, val);
+ if (m_out_state[nstate] != m_out_state.mask() && m_out_state[nstate] != val)
+ throw nl_exception(plib::pfmt("Error in truthtable: State {1:04} already set, {2} != {3}\n")
+ .x(nstate.as_uint())(m_out_state[nstate])(val) );
+ m_out_state.set(nstate, val);
for (std::size_t j=0; j<m_NO; j++)
m_timing[nstate * m_NO + j] = timing_index[j];
}
@@ -375,12 +366,12 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable)
line++;
for (unsigned j=0; j < m_size; j++)
- m_outs.set(j, tt_bitset::all_bits());
+ m_out_state.set(j, tt_bitset::all_bits());
for (int j=0; j < 16; j++)
m_timing_nt[j] = netlist_time::zero();
- while (!ttline.equals(""))
+ while (!(ttline == ""))
{
std::vector<pstring> io(plib::psplit(ttline,"|"));
// checks
@@ -402,12 +393,13 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable)
*/
for (unsigned j=0; j<m_NO; j++)
{
- pstring outs = out[j].trim();
- if (outs.equals("1"))
+ pstring outs = plib::trim(out[j]);
+ if (outs == "1")
val.set(j);
else
- nl_assert_always(outs.equals("0"), "Unknown value (not 0 or 1");
- netlist_time t = netlist_time::from_nsec(static_cast<unsigned long>(times[j].trim().as_long()));
+ nl_assert_always(outs == "0", "Unknown value (not 0 or 1");
+ // FIXME: error handling
+ netlist_time t = netlist_time::from_nsec(plib::pstonum<std::int64_t>(plib::trim(times[j])));
uint_least8_t k=0;
while (m_timing_nt[k] != netlist_time::zero() && m_timing_nt[k] != t)
k++;
@@ -450,9 +442,9 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable)
}
for (size_t i=0; i<m_size; i++)
{
- if (m_outs[i] == m_outs.mask())
+ if (m_out_state[i] == m_out_state.mask())
throw nl_exception(plib::pfmt("truthtable: found element not set {1}\n").x(i) );
- m_outs.set(i, m_outs[i] | (ign[i] << m_NO));;
+ m_out_state.set(i, m_out_state[i] | (ign[i] << m_NO));
}
*m_initialized = true;
@@ -460,26 +452,21 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable)
netlist_base_factory_truthtable_t::netlist_base_factory_truthtable_t(const pstring &name, const pstring &classname,
const pstring &def_param, const pstring &sourcefile)
-: factory::element_t(name, classname, def_param, sourcefile), m_family(family_TTL())
-{
-}
-
-netlist_base_factory_truthtable_t::~netlist_base_factory_truthtable_t()
+: factory::element_t(name, classname, def_param, sourcefile), m_family_desc(family_TTL())
{
}
-
#define ENTRYY(n, m, s) case (n * 100 + m): \
{ using xtype = netlist_factory_truthtable_t<n, m>; \
- ret = plib::palloc<xtype>(desc.name, desc.classname, desc.def_param, s); } break
+ ret = plib::make_unique<xtype>(desc.name, desc.classname, desc.def_param, s); } break
#define ENTRY(n, s) ENTRYY(n, 1, s); ENTRYY(n, 2, s); ENTRYY(n, 3, s); \
ENTRYY(n, 4, s); ENTRYY(n, 5, s); ENTRYY(n, 6, s); \
ENTRYY(n, 7, s); ENTRYY(n, 8, s)
-void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile)
+plib::unique_ptr<netlist_base_factory_truthtable_t> tt_factory_create(tt_desc &desc, const pstring &sourcefile)
{
- netlist_base_factory_truthtable_t *ret;
+ plib::unique_ptr<netlist_base_factory_truthtable_t> ret;
switch (desc.ni * 100 + desc.no)
{
@@ -500,9 +487,9 @@ void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile)
nl_assert_always(false, msg);
}
ret->m_desc = desc.desc;
- if (desc.family != "")
- ret->m_family = setup.family_from_model(desc.family);
- setup.factory().register_device(std::unique_ptr<netlist_base_factory_truthtable_t>(ret));
+ ret->m_family_name = desc.family;
+
+ return ret;
}
} //namespace devices
diff --git a/src/lib/netlist/devices/nlid_truthtable.h b/src/lib/netlist/devices/nlid_truthtable.h
index 311f5ebd8ca..1217d7ee873 100644
--- a/src/lib/netlist/devices/nlid_truthtable.h
+++ b/src/lib/netlist/devices/nlid_truthtable.h
@@ -10,9 +10,9 @@
#ifndef NLID_TRUTHTABLE_H_
#define NLID_TRUTHTABLE_H_
-#include "../nl_setup.h"
-#include "../nl_base.h"
-#include "../plib/putil.h"
+#include "netlist/nl_base.h"
+#include "netlist/nl_setup.h"
+#include "plib/putil.h"
#define NETLIB_TRUTHTABLE(cname, nIN, nOUT) \
class NETLIB_NAME(cname) : public nld_truthtable_t<nIN, nOUT> \
@@ -29,17 +29,9 @@
namespace netlist
{
- namespace devices
- {
+namespace devices
+{
-#if 0
- template<unsigned bits> struct uint_for_size { typedef uint_least32_t type; };
- template<unsigned bits>
- struct need_bytes_for_bits
- {
- enum { value = 4 };
- };
-#else
template<unsigned bits>
struct need_bytes_for_bits
{
@@ -52,11 +44,35 @@ namespace netlist
};
template<unsigned bits> struct uint_for_size;
- template<> struct uint_for_size<1> { typedef uint_least8_t type; };
- template<> struct uint_for_size<2> { typedef uint_least16_t type; };
- template<> struct uint_for_size<4> { typedef uint_least32_t type; };
- template<> struct uint_for_size<8> { typedef uint_least64_t type; };
-#endif
+ template<> struct uint_for_size<1> { using type = uint_least8_t; };
+ template<> struct uint_for_size<2> { using type = uint_least16_t; };
+ template<> struct uint_for_size<4> { using type = uint_least32_t; };
+ template<> struct uint_for_size<8> { using type = uint_least64_t; };
+
+ template<std::size_t NUM, typename R>
+ struct aa
+ {
+ template<typename T>
+ R f(T &arr, const R ign)
+ {
+ R r = aa<NUM-1, R>().f(arr, ign);
+ if (ign & (1 << (NUM-1)))
+ arr[NUM-1].activate();
+ return r | (arr[NUM-1]() << (NUM-1));
+ }
+ };
+
+ template<typename R>
+ struct aa<1, R>
+ {
+ template<typename T>
+ R f(T &arr, const R ign)
+ {
+ if ((ign & 1))
+ arr[0].activate();
+ return arr[0]();
+ }
+ };
template<std::size_t m_NI, std::size_t m_NO>
NETLIB_OBJECT(truthtable_t)
@@ -65,22 +81,23 @@ namespace netlist
detail::family_setter_t m_fam;
public:
- typedef typename uint_for_size<need_bytes_for_bits<m_NO + m_NI>::value>::type type_t;
+ using type_t = typename uint_for_size<need_bytes_for_bits<m_NO + m_NI>::value>::type;
static constexpr const std::size_t m_num_bits = m_NI;
static constexpr const std::size_t m_size = (1 << (m_num_bits));
static constexpr const type_t m_outmask = ((1 << m_NO) - 1);
- static constexpr const std::size_t m_min_devices_for_deactivate = 2;
struct truthtable_t
{
truthtable_t()
- : m_initialized(false)
+ : m_timing_index{0}
+ , m_initialized(false)
{}
+
+ std::array<type_t, m_size> m_out_state;
+ std::array<uint_least8_t, m_size * m_NO> m_timing_index;
+ std::array<netlist_time, 16> m_timing_nt;
bool m_initialized;
- type_t m_outs[m_size];
- uint_least8_t m_timing[m_size * m_NO];
- netlist_time m_timing_nt[16];
};
template <class C>
@@ -90,7 +107,6 @@ namespace netlist
: device_t(owner, name)
, m_fam(*this, fam)
, m_ign(*this, "m_ign", 0)
- , m_active(*this, "m_active", 1)
, m_ttp(ttp)
{
init(desc);
@@ -100,13 +116,14 @@ namespace netlist
NETLIB_RESETI()
{
- m_active = 0;
+ int active_outputs = 0;
m_ign = 0;
for (auto &i : m_I)
i.activate();
for (auto &q : m_Q)
if (q.has_net() && q.net().num_cons() > 0)
- m_active++;
+ active_outputs++;
+ set_active_outputs(active_outputs);
}
NETLIB_UPDATEI()
@@ -116,28 +133,14 @@ namespace netlist
void inc_active() NL_NOEXCEPT override
{
- if (m_NI >= m_min_devices_for_deactivate)
- if (++m_active == 1)
- {
- process<false>();
- }
+ process<false>();
}
void dec_active() NL_NOEXCEPT override
{
- /* FIXME:
- * Based on current measurements there is no point to disable
- * 1 input devices. This should actually be a parameter so that we
- * can decide for each individual gate whether it is beneficial to
- * ignore deactivation.
- */
- if (m_NI >= m_min_devices_for_deactivate)
- if (--m_active == 0)
- {
- for (std::size_t i = 0; i< m_NI; i++)
- m_I[i].inactivate();
- m_ign = (1<<m_NI)-1;
- }
+ for (std::size_t i = 0; i< m_NI; i++)
+ m_I[i].inactivate();
+ m_ign = (1<<m_NI)-1;
}
plib::uninitialised_array_t<logic_input_t, m_NI> m_I;
@@ -153,46 +156,44 @@ namespace netlist
netlist_time mt(netlist_time::zero());
type_t nstate(0);
- if (m_NI >= m_min_devices_for_deactivate)
- {
- type_t ign(m_ign);
- if (!doOUT)
- for (std::size_t i = 0; i < m_NI; i++)
- {
- m_I[i].activate();
- nstate |= (m_I[i]() ? (1 << i) : 0);
- mt = std::max(this->m_I[i].net().time(), mt);
- }
- else
- for (std::size_t i = 0; i < m_NI; i++)
- {
- if ((ign & 1))
- m_I[i].activate();
- nstate |= (m_I[i]() ? (1 << i) : 0);
- ign >>= 1;
- }
- }
+ type_t ign(m_ign);
+#if 1
+ if (!doOUT)
+ for (std::size_t i = 0; i < m_NI; i++)
+ {
+ m_I[i].activate();
+ //nstate |= (m_I[i]() ? (1 << i) : 0);
+ nstate |= (m_I[i]() << i);
+ mt = std::max(this->m_I[i].net().next_scheduled_time(), mt);
+ }
else
+ for (std::size_t i = 0; i < m_NI; i++)
+ {
+ if ((ign & 1))
+ m_I[i].activate();
+ //nstate |= (m_I[i]() ? (1 << i) : 0);
+ nstate |= (m_I[i]() << i);
+ ign >>= 1;
+ }
+#else
+ if (!doOUT)
{
- if (!doOUT)
- for (std::size_t i = 0; i < m_NI; i++)
- {
- nstate |= (m_I[i]() ? (1 << i) : 0);
- mt = std::max(this->m_I[i].net().time(), mt);
- }
- else
- for (std::size_t i = 0; i < m_NI; i++)
- nstate |= (m_I[i]() ? (1 << i) : 0);
+ nstate = aa<m_NI, type_t>().f(m_I, ~0);
+ for (std::size_t i = 0; i < m_NI; i++)
+ mt = std::max(this->m_I[i].net().time(), mt);
}
+ else
+ nstate = aa<m_NI, type_t>().f(m_I, ign);
+#endif
- const type_t outstate(m_ttp.m_outs[nstate]);
+ const type_t outstate(m_ttp.m_out_state[nstate]);
type_t out(outstate & m_outmask);
m_ign = outstate >> m_NO;
const std::size_t timebase(nstate * m_NO);
- const auto *t(&m_ttp.m_timing[timebase]);
- const auto *tim = m_ttp.m_timing_nt;
+ const auto *t(&m_ttp.m_timing_index[timebase]);
+ const auto *tim = m_ttp.m_timing_nt.data();
if (doOUT)
for (std::size_t i = 0; i < m_NO; out >>= 1, ++i)
@@ -201,18 +202,14 @@ namespace netlist
for (std::size_t i = 0; i < m_NO; out >>= 1, ++i)
m_Q[i].set_Q_time(out & 1, mt + tim[t[i]]);
- if (m_NI >= m_min_devices_for_deactivate)
- {
- type_t ign(m_ign);
- for (auto I = m_I.begin(); ign != 0; ign >>= 1, ++I)
- if (ign & 1)
- I->inactivate();
- }
+ ign = m_ign;
+ for (auto I = m_I.begin(); ign != 0; ign >>= 1, ++I)
+ if (ign & 1)
+ I->inactivate();
}
/* FIXME: check width */
state_var<type_t> m_ign;
- state_var_s32 m_active;
const truthtable_t &m_ttp;
};
@@ -222,15 +219,15 @@ namespace netlist
netlist_base_factory_truthtable_t(const pstring &name, const pstring &classname,
const pstring &def_param, const pstring &sourcefile);
- virtual ~netlist_base_factory_truthtable_t();
-
std::vector<pstring> m_desc;
- const logic_family_desc_t *m_family;
+ pstring m_family_name;
+ const logic_family_desc_t *m_family_desc;
};
- void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile);
+ /* the returned element is still missing a pointer to the family ... */
+ plib::unique_ptr<netlist_base_factory_truthtable_t> tt_factory_create(tt_desc &desc, const pstring &sourcefile);
- } //namespace devices
+} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/macro/nlm_base.cpp b/src/lib/netlist/macro/nlm_base.cpp
index 8ea6f148864..86f2450d301 100644
--- a/src/lib/netlist/macro/nlm_base.cpp
+++ b/src/lib/netlist/macro/nlm_base.cpp
@@ -1,7 +1,7 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
-#include "../nl_setup.h"
-#include "../devices/net_lib.h"
+#include "netlist/nl_setup.h"
+#include "netlist/devices/net_lib.h"
#include "nlm_base.h"
/* ----------------------------------------------------------------------------
@@ -12,9 +12,14 @@ static NETLIST_START(diode_models)
NET_MODEL("D _(IS=1e-15 N=1)")
NET_MODEL("1N914 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon)")
+ // FIXME: 1N916 currently only a copy of 1N914!
+ NET_MODEL("1N916 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon)")
NET_MODEL("1N4001 D(Is=14.11n N=1.984 Rs=33.89m Ikf=94.81 Xti=3 Eg=1.11 Cjo=25.89p M=.44 Vj=.3245 Fc=.5 Bv=75 Ibv=10u Tt=5.7u Iave=1 Vpk=50 mfg=GI type=silicon)")
NET_MODEL("1N4148 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon)")
NET_MODEL("1S1588 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75)")
+
+ NET_MODEL("1N34A D( Bv=75 Cjo=0.5e-12 Eg=0.67 Ibv=18e-3 Is=2e-7 Rs=7 N=1.3 Vj=0.1 M=0.27 type=germanium)")
+
NET_MODEL("LedRed D(IS=93.2p RS=42M N=3.73 BV=4 IBV=10U CJO=2.97P VJ=.75 M=.333 TT=4.32U Iave=40m Vpk=4 type=LED)")
NET_MODEL("LedGreen D(IS=93.2p RS=42M N=4.61 BV=4 IBV=10U CJO=2.97P VJ=.75 M=.333 TT=4.32U Iave=40m Vpk=4 type=LED)")
NET_MODEL("LedBlue D(IS=93.2p RS=42M N=7.47 BV=5 IBV=10U CJO=2.97P VJ=.75 M=.333 TT=4.32U Iave=40m Vpk=5 type=LED)")
@@ -26,9 +31,16 @@ NETLIST_END()
* BJT Models
* ---------------------------------------------------------------------------*/
+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)")
+NETLIST_END()
+
static NETLIST_START(bjt_models)
- NET_MODEL("NPN _(IS=1e-15 BF=100 NF=1 BR=1 NR=1)")
- NET_MODEL("PNP _(IS=1e-15 BF=100 NF=1 BR=1 NR=1)")
+ NET_MODEL("NPN _(IS=1e-15 BF=100 NF=1 BR=1 NR=1 CJE=0 CJC=0)")
+ NET_MODEL("PNP _(IS=1e-15 BF=100 NF=1 BR=1 NR=1 CJE=0 CJC=0)")
NET_MODEL("2SA1015 PNP(Is=295.1E-18 Xti=3 Eg=1.11 Vaf=100 Bf=110 Xtb=1.5 Br=10.45 Rc=15 Cjc=66.2p Mjc=1.054 Vjc=.75 Fc=.5 Cje=5p Mje=.3333 Vje=.75 Tr=10n Tf=1.661n VCEO=45V ICrating=150M MFG=Toshiba)")
NET_MODEL("2SC1815 NPN(Is=2.04f Xti=3 Eg=1.11 Vaf=6 Bf=400 Ikf=20m Xtb=1.5 Br=3.377 Rc=1 Cjc=1p Mjc=.3333 Vjc=.75 Fc=.5 Cje=25p Mje=.3333 Vje=.75 Tr=450n Tf=20n Itf=0 Vtf=0 Xtf=0 VCEO=45V ICrating=150M MFG=Toshiba)")
@@ -46,6 +58,8 @@ static NETLIST_START(bjt_models)
NET_MODEL("BC556B PNP(IS=3.83E-14 NF=1.008 ISE=1.22E-14 NE=1.528 BF=344.4 IKF=0.08039 VAF=21.11 NR=1.005 ISC=2.85E-13 NC=1.28 BR=14.84 IKR=0.047 VAR=32.02 RB=1 IRB=1.00E-06 RBM=1 RE=0.6202 RC=0.5713 XTB=0 EG=1.11 XTI=3 CJE=1.23E-11 VJE=0.6106 MJE=0.378 TF=5.60E-10 XTF=3.414 VTF=5.23 ITF=0.1483 PTF=0 CJC=1.08E-11 VJC=0.1022 MJC=0.3563 XCJC=0.6288 TR=1.00E-32 CJS=0 VJS=0.75 MJS=0.333 FC=0.8027 Vceo=65 Icrating=100m mfg=Philips)")
NET_MODEL("BC548C NPN(IS=1.95E-14 ISE=1.31E-15 ISC=1.0E-13 XTI=3 BF=466 BR=2.42 IKF=0.18 IKR=1 XTB=1.5 VAF=91.7 VAR=24.7 VJE=0.632 VJC=0.339 RE=1 RC=1.73 RB=26.5 RBM=10 IRB=10 CJE=1.33E-11 CJC=5.17E-12 XCJC=1 FC=0.9 NF=0.993 NR=1.2 NE=1.32 NC=2.00 MJE=0.326 MJC=0.319 TF=6.52E-10 TR=0 PTF=0 ITF=1.03 VTF=1.65 XTF=100 EG=1.11 KF=1E-9 AF=1 VCEO=40 ICrating=800M MFG=Siemens)")
NET_MODEL("BC817-25 NPN(IS=9.198E-14 NF=1.003 ISE=4.468E-16 NE=1.65 BF=338.8 IKF=0.4913 VAF=107.9 NR=1.002 ISC=5.109E-15 NC=1.071 BR=29.48 IKR=0.193 VAR=25 RB=1 IRB=1000 RBM=1 RE=0.2126 RC=0.143 XTB=0 EG=1.11 XTI=3 CJE=3.825E-11 VJE=0.7004 MJE=0.364 TF=5.229E-10 XTF=219.7 VTF=3.502 ITF=7.257 PTF=0 CJC=1.27E-11 VJC=0.4431 MJC=0.3983 XCJC=0.4555 TR=7E-11 CJS=0 VJS=0.75 MJS=0.333 FC=0.905 Vceo=45 Icrating=500m mfg=Philips)")
+
+ NET_MODEL("9013 NPN(IS=3.40675E-14 BF=166 VAF=67 IKF=1.164 ISE=12.37e-15 NE=2 BR=15.17 VAR=40.84 IKR=0.261352 ISC=1.905E-15 NC=1.066 RB=63.2 IRB=5.62E-6 RBM=22.1 RE=0.02 RC=0.7426 CJE=3.53E-11 VJE=0.808 MJE=0.372 CJC=1.74E-11 VJC=0.614 MJC=0.388 XCJC=0.349 XTB=1.4025 EG=1.0999 XTI=3 VC=0.5 VCEO=20)")
NETLIST_END()
/* ----------------------------------------------------------------------------
@@ -74,19 +88,22 @@ NETLIST_START(base)
LOCAL_SOURCE(diode_models)
LOCAL_SOURCE(bjt_models)
+ LOCAL_SOURCE(mosfet_models)
LOCAL_SOURCE(family_models)
+
LOCAL_SOURCE(TTL74XX_lib)
LOCAL_SOURCE(CD4XXX_lib)
LOCAL_SOURCE(OPAMP_lib)
LOCAL_SOURCE(otheric_lib)
- INCLUDE(diode_models);
- INCLUDE(bjt_models);
- INCLUDE(family_models);
- INCLUDE(TTL74XX_lib);
- INCLUDE(CD4XXX_lib);
- INCLUDE(OPAMP_lib);
- INCLUDE(otheric_lib);
+ INCLUDE(diode_models)
+ INCLUDE(bjt_models)
+ INCLUDE(mosfet_models)
+ INCLUDE(family_models)
+ INCLUDE(TTL74XX_lib)
+ INCLUDE(CD4XXX_lib)
+ INCLUDE(OPAMP_lib)
+ INCLUDE(otheric_lib)
NETLIST_END()
diff --git a/src/lib/netlist/macro/nlm_base.h b/src/lib/netlist/macro/nlm_base.h
index 5ecf8071e98..6a88ad5a1be 100644
--- a/src/lib/netlist/macro/nlm_base.h
+++ b/src/lib/netlist/macro/nlm_base.h
@@ -10,7 +10,7 @@
#ifndef __PLIB_PREPROCESSOR__
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
/* ----------------------------------------------------------------------------
* Netlist Macros
diff --git a/src/lib/netlist/macro/nlm_cd4xxx.cpp b/src/lib/netlist/macro/nlm_cd4xxx.cpp
index 9ce786ca85e..5ebd5593123 100644
--- a/src/lib/netlist/macro/nlm_cd4xxx.cpp
+++ b/src/lib/netlist/macro/nlm_cd4xxx.cpp
@@ -2,10 +2,10 @@
// copyright-holders:Couriersud
#include "nlm_cd4xxx.h"
-#include "../devices/nld_system.h"
-#include "../devices/nld_4020.h"
-#include "../devices/nld_4066.h"
-#include "../devices/nld_4316.h"
+#include "netlist/devices/nld_4020.h"
+#include "netlist/devices/nld_4066.h"
+#include "netlist/devices/nld_4316.h"
+#include "netlist/devices/nld_system.h"
/*
* CD4001BC: Quad 2-Input NOR Buffered B Series Gate
diff --git a/src/lib/netlist/macro/nlm_cd4xxx.h b/src/lib/netlist/macro/nlm_cd4xxx.h
index 527336c1e8e..d4d9c97fdc2 100644
--- a/src/lib/netlist/macro/nlm_cd4xxx.h
+++ b/src/lib/netlist/macro/nlm_cd4xxx.h
@@ -3,7 +3,7 @@
#ifndef NLD_CD4XXX_H_
#define NLD_CD4XXX_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
/*
* Devices:
diff --git a/src/lib/netlist/macro/nlm_opamp.cpp b/src/lib/netlist/macro/nlm_opamp.cpp
index 122b324f777..849f7820046 100644
--- a/src/lib/netlist/macro/nlm_opamp.cpp
+++ b/src/lib/netlist/macro/nlm_opamp.cpp
@@ -1,7 +1,7 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
#include "nlm_opamp.h"
-#include "../devices/net_lib.h"
+#include "netlist/devices/net_lib.h"
/*
* Generic layout with 4 opamps, VCC on pin 4 and GND on pin 11
diff --git a/src/lib/netlist/macro/nlm_opamp.h b/src/lib/netlist/macro/nlm_opamp.h
index 9cffbb29c87..fbd7547c976 100644
--- a/src/lib/netlist/macro/nlm_opamp.h
+++ b/src/lib/netlist/macro/nlm_opamp.h
@@ -3,7 +3,7 @@
#ifndef NLM_OPAMP_H_
#define NLM_OPAMP_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#ifndef __PLIB_PREPROCESSOR__
diff --git a/src/lib/netlist/macro/nlm_other.cpp b/src/lib/netlist/macro/nlm_other.cpp
index 7e31ae27bb4..ea0eb1539a8 100644
--- a/src/lib/netlist/macro/nlm_other.cpp
+++ b/src/lib/netlist/macro/nlm_other.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Couriersud
#include "nlm_other.h"
-#include "../devices/nld_system.h"
+#include "netlist/devices/nld_system.h"
/*
* MC14584B: Hex Schmitt Trigger
diff --git a/src/lib/netlist/macro/nlm_other.h b/src/lib/netlist/macro/nlm_other.h
index 7c38d8ad363..ee231fbd6db 100644
--- a/src/lib/netlist/macro/nlm_other.h
+++ b/src/lib/netlist/macro/nlm_other.h
@@ -3,7 +3,7 @@
#ifndef NLM_OTHER_H_
#define NLM_OTHER_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#ifndef __PLIB_PREPROCESSOR__
diff --git a/src/lib/netlist/macro/nlm_ttl74xx.cpp b/src/lib/netlist/macro/nlm_ttl74xx.cpp
index df1b873a468..58cab049ae7 100644
--- a/src/lib/netlist/macro/nlm_ttl74xx.cpp
+++ b/src/lib/netlist/macro/nlm_ttl74xx.cpp
@@ -2,8 +2,8 @@
// copyright-holders:Couriersud
#include "nlm_ttl74xx.h"
-#include "../devices/nld_schmitt.h"
-#include "../devices/nld_system.h"
+#include "netlist/devices/nld_schmitt.h"
+#include "netlist/devices/nld_system.h"
/*
@@ -825,8 +825,9 @@ NETLIST_END()
NETLIST_START(TTL74XX_lib)
- NET_MODEL("DM7414 SCHMITT_TRIGGER(VTP=1.7 VTM=0.9 VI=4.35 RI=6.15k VOH=3.5 ROH=120 VOL=0.1 ROL=37.5 TPLH=15 TPHL=15)")
- NET_MODEL("DM74LS14 SCHMITT_TRIGGER(VTP=1.6 VTM=0.8 VI=4.4 RI=19.3k VOH=3.45 ROH=130 VOL=0.1 ROL=31.2 TPLH=15 TPHL=15)")
+ NET_MODEL("DM7414 SCHMITT_TRIGGER(VTP=1.7 VTM=0.9 VI=4.35 RI=6.15k VOH=3.5 ROH=120 VOL=0.1 ROL=37.5 TPLH=15 TPHL=15)")
+ NET_MODEL("TTL_7414_GATE SCHMITT_TRIGGER(VTP=1.7 VTM=0.9 VI=4.35 RI=6.15k VOH=3.5 ROH=120 VOL=0.1 ROL=37.5 TPLH=15 TPHL=15)")
+ NET_MODEL("DM74LS14 SCHMITT_TRIGGER(VTP=1.6 VTM=0.8 VI=4.4 RI=19.3k VOH=3.45 ROH=130 VOL=0.1 ROL=31.2 TPLH=15 TPHL=15)")
//NET_MODEL("DM7414 FAMILY(FV=5 IVL=0.16 IVH=0.4 OVL=0.1 OVH=0.05 ORL=10.0 ORH=1.0e8)")
diff --git a/src/lib/netlist/macro/nlm_ttl74xx.h b/src/lib/netlist/macro/nlm_ttl74xx.h
index c8868e45f7f..21ff99f2efe 100644
--- a/src/lib/netlist/macro/nlm_ttl74xx.h
+++ b/src/lib/netlist/macro/nlm_ttl74xx.h
@@ -3,7 +3,7 @@
#ifndef NLD_TTL74XX_H_
#define NLD_TTL74XX_H_
-#include "../nl_setup.h"
+#include "netlist/nl_setup.h"
#ifndef __PLIB_PREPROCESSOR__
diff --git a/src/lib/netlist/netlist_types.h b/src/lib/netlist/netlist_types.h
deleted file mode 100644
index 0bd32be21be..00000000000
--- a/src/lib/netlist/netlist_types.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Couriersud
-/*!
- *
- * \file netlist_types.h
- *
- */
-
-#ifndef NETLIST_TYPES_H_
-#define NETLIST_TYPES_H_
-
-#include "nl_config.h"
-#include "plib/pchrono.h"
-#include "plib/pstring.h"
-
-#include <cstdint>
-#include <unordered_map>
-
-namespace netlist
-{
- //============================================================
- // Performance tracking
- //============================================================
-
-#if NL_KEEP_STATISTICS
- using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, true>;
- using nperfcount_t = plib::chrono::counter<true>;
-#else
- using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, false>;
- using nperfcount_t = plib::chrono::counter<false>;
-#endif
-
- //============================================================
- // Types needed by various includes
- //============================================================
-
- namespace detail {
-
- /*! Enum specifying the type of object */
- enum terminal_type {
- TERMINAL = 0, /*!< object is an analog terminal */
- INPUT = 1, /*!< object is an input */
- OUTPUT = 2, /*!< object is an output */
- };
-
- /*! Type of the model map used.
- * This is used to hold all #Models in an unordered map
- */
- using model_map_t = std::unordered_map<pstring, pstring>;
-
- }
-}
-
-#endif /* NETLIST_TYPES_H_ */
diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp
index 9a513c00804..ad048e899bf 100644
--- a/src/lib/netlist/nl_base.cpp
+++ b/src/lib/netlist/nl_base.cpp
@@ -8,18 +8,19 @@
#include "solver/nld_matrix_solver.h"
#include "solver/nld_solver.h"
-#include "plib/putil.h"
#include "plib/palloc.h"
+#include "plib/pmempool.h"
+#include "plib/putil.h"
-#include "nl_base.h"
-#include "devices/nlid_system.h"
#include "devices/nlid_proxy.h"
+#include "devices/nlid_system.h"
#include "macro/nlm_base.h"
+#include "nl_base.h"
#include "nl_errstr.h"
-#include <cstring>
#include <cmath>
+#include <cstring>
#include <limits>
namespace netlist
@@ -27,14 +28,13 @@ namespace netlist
namespace detail
{
- static plib::mempool *pool()
- {
- static plib::mempool *s_pool = nullptr;
- if (s_pool == nullptr)
- s_pool = new plib::mempool(65536, 16);
- return s_pool;
- }
+ //static plib::mempool *pool()
+ //{
+ // static plib::mempool s_pool(655360, 32);
+ // return &s_pool;
+ //}
+#if 0
void * object_t::operator new (size_t size)
{
void *ret = nullptr;
@@ -44,38 +44,30 @@ namespace detail
ret = ::operator new(size);
return ret;
}
-
void object_t::operator delete (void * mem)
{
if (mem)
{
- if ((USE_MEMPOOL))
- pool()->free(mem);
- else
+ //if ((USE_MEMPOOL))
+ // pool()->free(mem);
+ //else
::operator delete(mem);
}
}
+#endif
-}
-
-nl_exception::~nl_exception()
-{
-}
+} // namespace detail
// ----------------------------------------------------------------------------------------
// logic_family_ttl_t
// ----------------------------------------------------------------------------------------
+// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, modernize-use-equals-default)
logic_family_desc_t::logic_family_desc_t()
{
}
-logic_family_desc_t::~logic_family_desc_t()
-{
-}
-
-
class logic_family_ttl_t : public logic_family_desc_t
{
public:
@@ -90,17 +82,17 @@ public:
m_R_low = 1.0;
m_R_high = 130.0;
}
- virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
- virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
+ pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
+ pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
};
-plib::owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_ttl_t::create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const
+pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_ttl_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const
{
- return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
}
-plib::owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_ttl_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const
+pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_ttl_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
{
- return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
+ return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
}
class logic_family_cd4xxx_t : public logic_family_desc_t
@@ -117,17 +109,18 @@ public:
m_R_low = 10.0;
m_R_high = 10.0;
}
- virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
- virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
+ pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
+ pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
};
-plib::owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_cd4xxx_t::create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const
+pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_cd4xxx_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const
{
- return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
}
-plib::owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_cd4xxx_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const
+
+pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_cd4xxx_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
{
- return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
+ return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
}
const logic_family_desc_t *family_TTL()
@@ -146,10 +139,10 @@ const logic_family_desc_t *family_CD4XXX()
// queue_t
// ----------------------------------------------------------------------------------------
-detail::queue_t::queue_t(netlist_t &nl)
- : timed_queue<pqentry_t<net_t *, netlist_time>, false>(512)
+detail::queue_t::queue_t(netlist_state_t &nl)
+ : timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>(512)
, netlist_ref(nl)
- , plib::state_manager_t::callback_t()
+// , plib::state_manager_t::callback_t()
, m_qsize(0)
, m_times(512)
, m_net_ids(512)
@@ -158,52 +151,56 @@ detail::queue_t::queue_t(netlist_t &nl)
void detail::queue_t::register_state(plib::state_manager_t &manager, const pstring &module)
{
- netlist().log().debug("register_state\n");
+ //state().log().debug("register_state\n");
manager.save_item(this, m_qsize, module + "." + "qsize");
manager.save_item(this, &m_times[0], module + "." + "times", m_times.size());
manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size());
}
-void detail::queue_t::on_pre_save()
+void detail::queue_t::on_pre_save(plib::state_manager_t &manager)
{
- netlist().log().debug("on_pre_save\n");
+ plib::unused_var(manager);
m_qsize = this->size();
- netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize);
for (std::size_t i = 0; i < m_qsize; i++ )
{
m_times[i] = this->listptr()[i].m_exec_time.as_raw();
- m_net_ids[i] = netlist().find_net_id(this->listptr()[i].m_object);
+ m_net_ids[i] = state().find_net_id(this->listptr()[i].m_object);
}
}
-void detail::queue_t::on_post_load()
+void detail::queue_t::on_post_load(plib::state_manager_t &manager)
{
+ plib::unused_var(manager);
this->clear();
- netlist().log().debug("current time {1} qsize {2}\n", netlist().time().as_double(), m_qsize);
for (std::size_t i = 0; i < m_qsize; i++ )
{
- detail::net_t *n = netlist().m_nets[m_net_ids[i]].get();
+ detail::net_t *n = state().nets()[m_net_ids[i]].get();
this->push(queue_t::entry_t(netlist_time::from_raw(m_times[i]),n));
}
}
// ----------------------------------------------------------------------------------------
+// netlist_ref_t
+// ----------------------------------------------------------------------------------------
+
+detail::netlist_ref::netlist_ref(netlist_state_t &nl)
+: m_netlist(nl.exec()) { }
+
+// ----------------------------------------------------------------------------------------
// object_t
// ----------------------------------------------------------------------------------------
detail::object_t::object_t(const pstring &aname)
- : m_name(plib::make_unique<pstring>(aname))
+// : m_name(aname)
{
+ name_hash().insert({this, aname});
}
-detail::object_t::~object_t()
+pstring detail::object_t::name() const
{
-}
-
-const pstring &detail::object_t::name() const
-{
- return *m_name;
+ return name_hash().find(this)->second;
+ //return m_name;
}
// ----------------------------------------------------------------------------------------
@@ -230,7 +227,7 @@ detail::terminal_type detail::core_terminal_t::type() const
return terminal_type::OUTPUT;
else
{
- netlist().log().fatal(MF_1_UNKNOWN_TYPE_FOR_OBJECT, name());
+ state().log().fatal(MF_1_UNKNOWN_TYPE_FOR_OBJECT, name());
return terminal_type::TERMINAL; // please compiler
}
}
@@ -239,159 +236,38 @@ detail::terminal_type detail::core_terminal_t::type() const
// netlist_t
// ----------------------------------------------------------------------------------------
-netlist_t::netlist_t(const pstring &aname)
- : m_time(netlist_time::zero())
- , m_queue(*this)
- , m_mainclock(nullptr)
+netlist_t::netlist_t(const pstring &aname, plib::unique_ptr<callbacks_t> callbacks)
+ : m_state(plib::make_unique<netlist_state_t>(aname, *this, std::move(callbacks)))
, m_solver(nullptr)
- , m_params(nullptr)
- , m_name(aname)
- , m_log(*this)
- , m_lib(nullptr)
- , m_state()
-{
- state().save_item(this, static_cast<plib::state_manager_t::callback_t &>(m_queue), "m_queue");
- state().save_item(this, m_time, "m_time");
- m_setup = plib::make_unique<setup_t>(*this);
- /* FIXME: doesn't really belong here */
- NETLIST_NAME(base)(*m_setup);
-}
-
-netlist_t::~netlist_t()
-{
- m_nets.clear();
- m_devices.clear();
-}
-
-nl_double netlist_t::gmin() const NL_NOEXCEPT
-{
- return solver()->gmin();
-}
-
-void netlist_t::register_dev(plib::owned_ptr<core_device_t> dev)
-{
- for (auto & d : m_devices)
- if (d->name() == dev->name())
- log().fatal(MF_1_DUPLICATE_NAME_DEVICE_LIST, d->name());
- m_devices.push_back(std::move(dev));
-}
-
-void netlist_t::remove_dev(core_device_t *dev)
+ , m_time(netlist_time::zero())
+ , m_mainclock(nullptr)
+ , m_queue(*m_state)
{
- m_devices.erase(
- std::remove_if(
- m_devices.begin(),
- m_devices.end(),
- [&] (plib::owned_ptr<core_device_t> const& p)
- {
- return p.get() == dev;
- }),
- m_devices.end()
- );
+ devices::initialize_factory(nlstate().setup().factory());
+ NETLIST_NAME(base)(nlstate().setup());
+ run_state_manager().save_item(this, static_cast<plib::state_manager_t::callback_t &>(m_queue), "m_queue");
+ run_state_manager().save_item(this, m_time, "m_time");
}
+// ----------------------------------------------------------------------------------------
+// netlist_t
+// ----------------------------------------------------------------------------------------
-
-void netlist_t::start()
+netlist_state_t::netlist_state_t(const pstring &aname,
+ netlist_t & anetlist,
+ plib::unique_ptr<callbacks_t> &&callbacks)
+: m_name(aname)
+, m_netlist(anetlist)
+, m_state()
+, m_callbacks(std::move(callbacks)) // Order is important here
+, m_log(*m_callbacks)
+, m_setup(plib::make_unique<setup_t>(*this))
{
- setup().start_devices();
-
- /* load the library ... */
-
- /* make sure the solver and parameters are started first! */
-
- for (auto & e : setup().m_device_factory)
- {
- if ( setup().factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
- || setup().factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
- {
- auto dev = plib::owned_ptr<device_t>(e.second->Create(*this, e.first));
- register_dev(std::move(dev));
- }
- }
-
- log().debug("Searching for mainclock and solver ...\n");
-
- m_solver = get_single_device<devices::NETLIB_NAME(solver)>("solver");
- m_params = get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
-
- /* create devices */
-
- log().debug("Creating devices ...\n");
- for (auto & e : setup().m_device_factory)
- {
- if ( !setup().factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
- && !setup().factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
- {
- auto dev = plib::owned_ptr<device_t>(e.second->Create(*this, e.first));
- register_dev(std::move(dev));
- }
- }
-
- log().debug("Searching for mainclock\n");
- m_mainclock = get_single_device<devices::NETLIB_NAME(mainclock)>("mainclock");
-
- bool use_deactivate = (m_params->m_use_deactivate() ? true : false);
-
- for (auto &d : m_devices)
- {
- if (use_deactivate)
- {
- auto p = setup().m_param_values.find(d->name() + ".HINT_NO_DEACTIVATE");
- if (p != setup().m_param_values.end())
- {
- //FIXME: turn this into a proper function
- bool error;
- auto v = p->second.as_double(&error);
- if (error || std::abs(v - std::floor(v)) > 1e-6 )
- log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second);
- d->set_hint_deactivate(v == 0.0);
- }
- }
- else
- d->set_hint_deactivate(false);
- }
-
pstring libpath = plib::util::environment("NL_BOOSTLIB", plib::util::buildpath({".", "nlboost.so"}));
m_lib = plib::make_unique<plib::dynlib>(libpath);
-
- /* resolve inputs */
- setup().resolve_inputs();
-
- log().verbose("looking for two terms connected to rail nets ...");
- for (auto & t : get_device_list<analog::NETLIB_NAME(twoterm)>())
- {
- if (t->m_N.net().isRailNet() && t->m_P.net().isRailNet())
- {
- log().warning(MW_3_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3,
- t->name(), t->m_N.net().name(), t->m_P.net().name());
- t->m_N.net().remove_terminal(t->m_N);
- t->m_P.net().remove_terminal(t->m_P);
- remove_dev(t);
- }
- }
-
- log().verbose("initialize solver ...\n");
-
- if (m_solver == nullptr)
- {
- for (auto &p : m_nets)
- if (p->is_analog())
- log().fatal(MF_0_NO_SOLVER);
- }
- else
- m_solver->post_start();
-
- for (auto &n : m_nets)
- for (auto & term : n->m_core_terms)
- {
- //core_device_t *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object());
- core_device_t *dev = &term->device();
- dev->set_default_delegate(*term);
- }
-
}
+
void netlist_t::stop()
{
log().debug("Printing statistics ...\n");
@@ -401,7 +277,7 @@ void netlist_t::stop()
m_solver->stop();
}
-detail::net_t *netlist_t::find_net(const pstring &name) const
+detail::net_t *netlist_state_t::find_net(const pstring &name) const
{
for (auto & net : m_nets)
if (net->name() == name)
@@ -410,7 +286,7 @@ detail::net_t *netlist_t::find_net(const pstring &name) const
return nullptr;
}
-std::size_t netlist_t::find_net_id(const detail::net_t *net) const
+std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const
{
for (std::size_t i = 0; i < m_nets.size(); i++)
if (m_nets[i].get() == net)
@@ -420,7 +296,7 @@ std::size_t netlist_t::find_net_id(const detail::net_t *net) const
-void netlist_t::rebuild_lists()
+void netlist_state_t::rebuild_lists()
{
for (auto & net : m_nets)
net->rebuild_list();
@@ -429,32 +305,44 @@ void netlist_t::rebuild_lists()
void netlist_t::reset()
{
+ log().debug("Searching for mainclock\n");
+ m_mainclock = m_state->get_single_device<devices::NETLIB_NAME(mainclock)>("mainclock");
+
+ log().debug("Searching for solver\n");
+ m_solver = m_state->get_single_device<devices::NETLIB_NAME(solver)>("solver");
+
m_time = netlist_time::zero();
m_queue.clear();
if (m_mainclock != nullptr)
- m_mainclock->m_Q.net().set_time(netlist_time::zero());
+ m_mainclock->m_Q.net().set_next_scheduled_time(netlist_time::zero());
//if (m_solver != nullptr)
- // m_solver->do_reset();
-
- std::unordered_map<core_device_t *, bool> m;
+ // m_solver->reset();
- for (auto &d : m_devices)
- {
- m[d.get()] = d->get_hint_deactivate();
- }
+ m_state->reset();
+}
+void netlist_state_t::reset()
+{
+ //FIXME: never used ???
+ std::unordered_map<core_device_t *, bool> m;
// Reset all nets once !
- for (auto & n : m_nets)
+ log().verbose("Call reset on all nets:");
+ for (auto & n : nets())
n->reset();
// Reset all devices once !
+ log().verbose("Call reset on all devices:");
for (auto & dev : m_devices)
- dev->do_reset();
+ dev.second->reset();
// Make sure everything depending on parameters is set
+ // Currently analog input and logic input also
+ // push their outputs to queue.
+
+ log().verbose("Call update_param on all devices:");
for (auto & dev : m_devices)
- dev->update_param();
+ dev.second->update_param();
// Step all devices once !
/*
@@ -462,9 +350,9 @@ void netlist_t::reset()
* variations are explicitly stated in the breakout manual.
*/
- const unsigned startup_strategy = 1; //! \note make this a parameter
+ auto *netlist_params = get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
- switch (startup_strategy)
+ switch (netlist_params->m_startup_strategy())
{
case 0:
{
@@ -472,7 +360,7 @@ void netlist_t::reset()
std::vector<nldelegate *> t;
log().verbose("Using default startup strategy");
for (auto &n : m_nets)
- for (auto & term : n->m_core_terms)
+ for (auto & term : n->core_terms())
if (term->m_delegate.has_object())
{
if (!plib::container::contains(t, &term->m_delegate))
@@ -480,70 +368,68 @@ void netlist_t::reset()
t.push_back(&term->m_delegate);
term->m_delegate();
}
- core_device_t *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object());
+ auto *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object());
if (!plib::container::contains(d, dev))
d.push_back(dev);
}
- log().verbose("Call update on devices which need parameter update:");
- for (auto & dev : m_devices)
- if (dev->needs_update_after_param_change())
- {
- if (!plib::container::contains(d, dev.get()))
- {
- d.push_back(dev.get());
- log().verbose("\t ...{1}", dev->name());
- dev->update_dev();
- }
- }
log().verbose("Devices not yet updated:");
for (auto &dev : m_devices)
- if (!plib::container::contains(d, dev.get()))
- log().verbose("\t ...{1}", dev->name());
- //x->update_dev();
+ if (!plib::container::contains(d, dev.second.get()))
+ {
+ log().verbose("\t ...{1}", dev.second->name());
+ dev.second->update();
+ }
}
break;
case 1: // brute force backward
{
+ log().verbose("Using brute force backward startup strategy");
+
+ for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
+ n->update_inputs();
+
std::size_t i = m_devices.size();
while (i>0)
- m_devices[--i]->update_dev();
+ m_devices[--i].second->update();
+
+ for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
+ n->update_inputs();
+
}
break;
case 2: // brute force forward
{
+ log().verbose("Using brute force forward startup strategy");
for (auto &d : m_devices)
- d->update_dev();
+ d.second->update();
}
break;
}
#if 1
/* the above may screw up m_active and the list */
- for (auto &n : m_nets)
- n->rebuild_list();
+ rebuild_lists();
#endif
}
-void netlist_t::process_queue(const netlist_time &delta) NL_NOEXCEPT
+void netlist_t::process_queue(const netlist_time delta) NL_NOEXCEPT
{
+ auto sm_guard(m_stat_mainloop.guard());
netlist_time stop(m_time + delta);
m_queue.push(detail::queue_t::entry_t(stop, nullptr));
- m_stat_mainloop.start();
if (m_mainclock == nullptr)
{
- detail::queue_t::entry_t e(m_queue.top());
- m_queue.pop();
+ detail::queue_t::entry_t e(m_queue.pop());
m_time = e.m_exec_time;
while (e.m_object != nullptr)
{
e.m_object->update_devs();
m_perf_out_processed.inc();
- e = m_queue.top();
- m_queue.pop();
+ e = m_queue.pop();
m_time = e.m_exec_time;
}
}
@@ -551,9 +437,7 @@ void netlist_t::process_queue(const netlist_time &delta) NL_NOEXCEPT
{
logic_net_t &mc_net(m_mainclock->m_Q.net());
const netlist_time inc(m_mainclock->m_inc);
- netlist_time mc_time(mc_net.time());
-
- detail::queue_t::entry_t e;
+ netlist_time mc_time(mc_net.next_scheduled_time());
do
{
@@ -565,37 +449,37 @@ void netlist_t::process_queue(const netlist_time &delta) NL_NOEXCEPT
mc_time += inc;
}
- e = m_queue.top();
- m_queue.pop();
+ detail::queue_t::entry_t e(m_queue.pop());
m_time = e.m_exec_time;
if (e.m_object != nullptr)
{
e.m_object->update_devs();
m_perf_out_processed.inc();
}
- } while (e.m_object != nullptr);
- mc_net.set_time(mc_time);
+ else
+ break;
+ } while (true); //while (e.m_object != nullptr);
+ mc_net.set_next_scheduled_time(mc_time);
}
- m_stat_mainloop.stop();
}
void netlist_t::print_stats() const
{
- if (nperftime_t::enabled)
+ if (nperftime_t<NL_KEEP_STATISTICS>::enabled)
{
std::vector<size_t> index;
- for (size_t i=0; i<m_devices.size(); i++)
+ for (size_t i=0; i < m_state->m_devices.size(); i++)
index.push_back(i);
std::sort(index.begin(), index.end(),
- [&](size_t i1, size_t i2) { return m_devices[i1]->m_stat_total_time.total() < m_devices[i2]->m_stat_total_time.total(); });
+ [&](size_t i1, size_t i2) { return m_state->m_devices[i1].second->m_stat_total_time.total() < m_state->m_devices[i2].second->m_stat_total_time.total(); });
- nperftime_t::type total_time(0);
- uint_least64_t total_count(0);
+ nperftime_t<NL_KEEP_STATISTICS>::type total_time(0);
+ nperftime_t<NL_KEEP_STATISTICS>::ctype total_count(0);
for (auto & j : index)
{
- auto entry = m_devices[j].get();
+ auto entry = m_state->m_devices[j].second.get();
log().verbose("Device {1:20} : {2:12} {3:12} {4:15} {5:12}", entry->name(),
entry->m_stat_call_count(), entry->m_stat_total_time.count(),
entry->m_stat_total_time.total(), entry->m_stat_inc_active());
@@ -603,22 +487,27 @@ void netlist_t::print_stats() const
total_count += entry->m_stat_total_time.count();
}
- nperftime_t overhead;
- nperftime_t test;
- overhead.start();
- for (int j=0; j<100000;j++)
+ log().verbose("Total calls : {1:12} {2:12} {3:12}", total_count,
+ total_time, total_time / static_cast<decltype(total_time)>(total_count));
+
+ nperftime_t<NL_KEEP_STATISTICS> overhead;
+ nperftime_t<NL_KEEP_STATISTICS> test;
{
- test.start();
- test.stop();
+ auto overhead_guard(overhead.guard());
+ for (int j=0; j<100000;j++)
+ {
+ auto test_guard(test.guard());
+ }
}
- overhead.stop();
- nperftime_t::type total_overhead = overhead()
- * static_cast<nperftime_t::type>(total_count)
- / static_cast<nperftime_t::type>(200000);
+ nperftime_t<NL_KEEP_STATISTICS>::type total_overhead = overhead()
+ * static_cast<nperftime_t<NL_KEEP_STATISTICS>::type>(total_count)
+ / static_cast<nperftime_t<NL_KEEP_STATISTICS>::type>(200000);
- log().verbose("Queue Pushes {1:15}", queue().m_prof_call());
- log().verbose("Queue Moves {1:15}", queue().m_prof_sortmove());
+ log().verbose("Queue Pushes {1:15}", m_queue.m_prof_call());
+ log().verbose("Queue Moves {1:15}", m_queue.m_prof_sortmove());
+ log().verbose("Queue Removes {1:15}", m_queue.m_prof_remove());
+ log().verbose("Queue Retimes {1:15}", m_queue.m_prof_retime());
log().verbose("Total loop {1:15}", m_stat_mainloop());
/* Only one serialization should be counted in total time */
@@ -627,29 +516,36 @@ void netlist_t::print_stats() const
log().verbose("");
log().verbose("Take the next lines with a grain of salt. They depend on the measurement implementation.");
log().verbose("Total overhead {1:15}", total_overhead);
- nperftime_t::type overhead_per_pop = (m_stat_mainloop()-2*total_overhead - (total_time - total_overhead))
- / static_cast<nperftime_t::type>(queue().m_prof_call());
+ nperftime_t<NL_KEEP_STATISTICS>::type overhead_per_pop = (m_stat_mainloop()-2*total_overhead - (total_time - total_overhead))
+ / static_cast<nperftime_t<NL_KEEP_STATISTICS>::type>(m_queue.m_prof_call());
log().verbose("Overhead per pop {1:11}", overhead_per_pop );
log().verbose("");
- for (auto &entry : m_devices)
+
+ auto trigger = total_count * 200 / 1000000; // 200 ppm
+ for (auto &entry : m_state->m_devices)
{
- if (entry->m_stat_inc_active() > 3 * entry->m_stat_total_time.count())
- log().verbose("HINT({}, NO_DEACTIVATE)", entry->name());
+ auto ep = entry.second.get();
+ // Factor of 3 offers best performace increase
+ if (ep->m_stat_inc_active() > 3 * ep->m_stat_total_time.count()
+ && ep->m_stat_inc_active() > trigger)
+ log().verbose("HINT({}, NO_DEACTIVATE) // {} {} {}", ep->name(),
+ static_cast<double>(ep->m_stat_inc_active()) / static_cast<double>(ep->m_stat_total_time.count()),
+ ep->m_stat_inc_active(), ep->m_stat_total_time.count());
}
}
}
-core_device_t *netlist_t::get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const
+core_device_t *netlist_state_t::get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const
{
core_device_t *ret = nullptr;
for (auto &d : m_devices)
{
- if (cc(d.get()))
+ if (cc(d.second.get()))
{
if (ret != nullptr)
- this->log().fatal(MF_1_MORE_THAN_ONE_1_DEVICE_FOUND, classname);
+ m_log.fatal(MF_1_MORE_THAN_ONE_1_DEVICE_FOUND, classname);
else
- ret = d.get();
+ ret = d.second.get();
}
}
return ret;
@@ -660,11 +556,12 @@ core_device_t *netlist_t::get_single_device(const pstring &classname, bool (*cc)
// core_device_t
// ----------------------------------------------------------------------------------------
-core_device_t::core_device_t(netlist_t &owner, const pstring &name)
+core_device_t::core_device_t(netlist_state_t &owner, const pstring &name)
: object_t(name)
, logic_family_t()
, netlist_ref(owner)
, m_hint_deactivate(false)
+ , m_active_outputs(*this, "m_active_outputs", 1)
{
if (logic_family() == nullptr)
set_logic_family(family_TTL());
@@ -673,17 +570,14 @@ core_device_t::core_device_t(netlist_t &owner, const pstring &name)
core_device_t::core_device_t(core_device_t &owner, const pstring &name)
: object_t(owner.name() + "." + name)
, logic_family_t()
- , netlist_ref(owner.netlist())
+ , netlist_ref(owner.state())
, m_hint_deactivate(false)
+ , m_active_outputs(*this, "m_active_outputs", 1)
{
set_logic_family(owner.logic_family());
if (logic_family() == nullptr)
set_logic_family(family_TTL());
- owner.netlist().register_dev(plib::owned_ptr<core_device_t>(this, false));
-}
-
-core_device_t::~core_device_t()
-{
+ state().add_dev(this->name(), pool_owned_ptr<core_device_t>(this, false));
}
void core_device_t::set_default_delegate(detail::core_terminal_t &term)
@@ -692,16 +586,16 @@ void core_device_t::set_default_delegate(detail::core_terminal_t &term)
term.m_delegate.set(&core_device_t::update, this);
}
-plib::plog_base<netlist_t, NL_DEBUG> &core_device_t::log()
+log_type & core_device_t::log()
{
- return netlist().log();
+ return state().log();
}
// ----------------------------------------------------------------------------------------
// device_t
// ----------------------------------------------------------------------------------------
-device_t::device_t(netlist_t &owner, const pstring &name)
+device_t::device_t(netlist_state_t &owner, const pstring &name)
: core_device_t(owner, name)
{
}
@@ -711,14 +605,14 @@ device_t::device_t(core_device_t &owner, const pstring &name)
{
}
-device_t::~device_t()
+setup_t &device_t::setup()
{
- //log().debug("~net_device_t\n");
+ return state().setup();
}
-setup_t &device_t::setup()
+const setup_t &device_t::setup() const
{
- return netlist().setup();
+ return state().setup();
}
void device_t::register_subalias(const pstring &name, detail::core_terminal_t &term)
@@ -762,9 +656,14 @@ void device_t::connect_post_start(detail::core_terminal_t &t1, detail::core_term
// family_setter_t
// -----------------------------------------------------------------------------
+// NOLINTNEXTLINE(modernize-use-equals-default)
+detail::family_setter_t::family_setter_t()
+{
+}
+
detail::family_setter_t::family_setter_t(core_device_t &dev, const pstring &desc)
{
- dev.set_logic_family(dev.netlist().setup().family_from_model(desc));
+ dev.set_logic_family(dev.setup().family_from_model(desc));
}
detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_desc_t *desc)
@@ -776,81 +675,45 @@ detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_
// net_t
// ----------------------------------------------------------------------------------------
-detail::net_t::net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr)
+detail::net_t::net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *mr)
: object_t(aname)
, netlist_ref(nl)
, m_new_Q(*this, "m_new_Q", 0)
, m_cur_Q (*this, "m_cur_Q", 0)
- , m_in_queue(*this, "m_in_queue", QS_DELIVERED)
- , m_active(*this, "m_active", 0)
- , m_time(*this, "m_time", netlist_time::zero())
+ , m_in_queue(*this, "m_in_queue", queue_status::DELIVERED)
+ , m_next_scheduled_time(*this, "m_time", netlist_time::zero())
, m_railterminal(mr)
{
}
-detail::net_t::~net_t()
-{
- netlist().state().remove_save_items(this);
-}
-
-void detail::net_t::inc_active(core_terminal_t &term) NL_NOEXCEPT
-{
- m_list_active.push_front(&term);
- ++m_active;
- nl_assert(m_active <= static_cast<int>(num_cons()));
- if (m_active == 1)
- {
- railterminal().device().do_inc_active();
- if (m_in_queue == QS_DELAYED_DUE_TO_INACTIVE)
- {
- if (m_time > netlist().time())
- {
- m_in_queue = QS_QUEUED; /* pending */
- netlist().queue().push({m_time, this});
- }
- else
- {
- m_in_queue = QS_DELIVERED;
- m_cur_Q = m_new_Q;
- }
- }
- }
-}
-
-void detail::net_t::dec_active(core_terminal_t &term) NL_NOEXCEPT
-{
- --m_active;
- nl_assert(m_active >= 0);
- m_list_active.remove(&term);
- if (m_active == 0)
- railterminal().device().do_dec_active();
-}
-
void detail::net_t::rebuild_list()
{
/* rebuild m_list */
- int cnt = 0;
m_list_active.clear();
for (auto & term : m_core_terms)
- if (term->state() != logic_t::STATE_INP_PASSIVE)
+ if (term->terminal_state() != logic_t::STATE_INP_PASSIVE)
{
m_list_active.push_back(term);
- cnt++;
+ term->set_copied_input(m_cur_Q);
}
- m_active = cnt;
}
-
-void detail::net_t::process(unsigned Mask)
+template <typename T>
+void detail::net_t::process(const T mask, netlist_sig_t sig)
{
+ m_cur_Q = sig;
+
for (auto & p : m_list_active)
{
+ p.set_copied_input(sig);
+
p.device().m_stat_call_count.inc();
- if ((p.state() & Mask) != 0)
+ if ((p.terminal_state() & mask))
{
- p.device().m_stat_total_time.start();
+ auto g(p.device().m_stat_total_time.guard());
+ //p.device().m_stat_total_time.start();
p.m_delegate();
- p.device().m_stat_total_time.stop();
+ //p.device().m_stat_total_time.stop();
}
}
}
@@ -859,67 +722,59 @@ void detail::net_t::update_devs() NL_NOEXCEPT
{
nl_assert(this->isRailNet());
- const unsigned mask((m_new_Q << core_terminal_t::INP_LH_SHIFT)
- | (m_cur_Q<<core_terminal_t::INP_HL_SHIFT));
+ const auto new_Q(m_new_Q);
- m_in_queue = QS_DELIVERED; /* mark as taken ... */
+ const auto mask((new_Q << core_terminal_t::INP_LH_SHIFT)
+ | (m_cur_Q << core_terminal_t::INP_HL_SHIFT));
+ m_in_queue = queue_status::DELIVERED; /* mark as taken ... */
switch (mask)
{
case core_terminal_t::STATE_INP_HL:
- m_cur_Q = m_new_Q;
- process(core_terminal_t::STATE_INP_HL | core_terminal_t::STATE_INP_ACTIVE);
- break;
case core_terminal_t::STATE_INP_LH:
- m_cur_Q = m_new_Q;
- process(core_terminal_t::STATE_INP_LH | core_terminal_t::STATE_INP_ACTIVE);
+ process(mask | core_terminal_t::STATE_INP_ACTIVE, new_Q);
break;
default:
+ /* do nothing */
break;
}
}
void detail::net_t::reset()
{
- m_time = netlist_time::zero();
- m_active = 0;
- m_in_queue = QS_DELIVERED;
+ m_next_scheduled_time = netlist_time::zero();
+ m_in_queue = queue_status::DELIVERED;
m_new_Q = 0;
m_cur_Q = 0;
- analog_net_t *p = dynamic_cast<analog_net_t *>(this);
+ auto *p = dynamic_cast<analog_net_t *>(this);
if (p != nullptr)
p->m_cur_Analog = 0.0;
- /* rebuild m_list */
+ /* rebuild m_list and reset terminals to active or analog out state */
m_list_active.clear();
for (core_terminal_t *ct : m_core_terms)
- m_list_active.push_back(ct);
-
- for (core_terminal_t *ct : m_core_terms)
+ {
ct->reset();
-
- for (core_terminal_t *ct : m_core_terms)
- if (ct->state() != logic_t::STATE_INP_PASSIVE)
- m_active++;
+ if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE)
+ m_list_active.push_back(ct);
+ ct->set_copied_input(m_cur_Q);
+ }
}
void detail::net_t::add_terminal(detail::core_terminal_t &terminal)
{
for (auto &t : m_core_terms)
if (t == &terminal)
- netlist().log().fatal(MF_2_NET_1_DUPLICATE_TERMINAL_2, name(),
+ state().log().fatal(MF_2_NET_1_DUPLICATE_TERMINAL_2, name(),
t->name());
terminal.set_net(this);
m_core_terms.push_back(&terminal);
-
- if (terminal.state() != logic_t::STATE_INP_PASSIVE)
- m_active++;
}
void detail::net_t::remove_terminal(detail::core_terminal_t &terminal)
@@ -930,10 +785,8 @@ void detail::net_t::remove_terminal(detail::core_terminal_t &terminal)
plib::container::remove(m_core_terms, &terminal);
}
else
- netlist().log().fatal(MF_2_REMOVE_TERMINAL_1_FROM_NET_2, terminal.name(),
+ state().log().fatal(MF_2_REMOVE_TERMINAL_1_FROM_NET_2, terminal.name(),
this->name());
- if (terminal.state() != logic_t::STATE_INP_PASSIVE)
- m_active--;
}
void detail::net_t::move_connections(detail::net_t &dest_net)
@@ -941,37 +794,28 @@ void detail::net_t::move_connections(detail::net_t &dest_net)
for (auto &ct : m_core_terms)
dest_net.add_terminal(*ct);
m_core_terms.clear();
- m_active = 0;
}
// ----------------------------------------------------------------------------------------
// logic_net_t
// ----------------------------------------------------------------------------------------
-logic_net_t::logic_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr)
+logic_net_t::logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr)
: net_t(nl, aname, mr)
{
}
-logic_net_t::~logic_net_t()
-{
-}
-
// ----------------------------------------------------------------------------------------
// analog_net_t
// ----------------------------------------------------------------------------------------
-analog_net_t::analog_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr)
+analog_net_t::analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr)
: net_t(nl, aname, mr)
, m_cur_Analog(*this, "m_cur_Analog", 0.0)
, m_solver(nullptr)
{
}
-analog_net_t::~analog_net_t()
-{
-}
-
// ----------------------------------------------------------------------------------------
// core_terminal_t
// ----------------------------------------------------------------------------------------
@@ -981,42 +825,19 @@ detail::core_terminal_t::core_terminal_t(core_device_t &dev, const pstring &anam
: device_object_t(dev, dev.name() + "." + aname)
, plib::linkedlist_t<core_terminal_t>::element_t()
, m_delegate(delegate)
+#if USE_COPY_INSTEAD_OF_REFERENCE
+, m_Q(*this, "m_Q", 0)
+#endif
, m_net(nullptr)
, m_state(*this, "m_state", state)
{
}
-detail::core_terminal_t::~core_terminal_t()
-{
-}
-
-void detail::core_terminal_t::reset()
-{
- if (is_type(OUTPUT))
- set_state(STATE_OUT);
- else
- set_state(STATE_INP_ACTIVE);
-}
-
-void detail::core_terminal_t::set_net(net_t *anet)
-{
- m_net = anet;
-}
-
-void detail::core_terminal_t::clear_net()
-{
- m_net = nullptr;
-}
-
analog_t::analog_t(core_device_t &dev, const pstring &aname, const state_e state)
: core_terminal_t(dev, aname, state)
{
}
-analog_t::~analog_t()
-{
-}
-
logic_t::logic_t(core_device_t &dev, const pstring &aname, const state_e state,
nldelegate delegate)
: core_terminal_t(dev, aname, state, delegate)
@@ -1025,26 +846,18 @@ logic_t::logic_t(core_device_t &dev, const pstring &aname, const state_e state,
{
}
-logic_t::~logic_t()
-{
-}
-
// ----------------------------------------------------------------------------------------
// terminal_t
// ----------------------------------------------------------------------------------------
-terminal_t::terminal_t(core_device_t &dev, const pstring &aname)
+terminal_t::terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm)
: analog_t(dev, aname, STATE_BIDIR)
-, m_otherterm(nullptr)
, m_Idr1(nullptr)
, m_go1(nullptr)
, m_gt1(nullptr)
+, m_connected_terminal(otherterm)
{
- netlist().setup().register_term(*this);
-}
-
-terminal_t::~terminal_t()
-{
+ state().setup().register_term(*this);
}
void terminal_t::solve_now()
@@ -1055,7 +868,7 @@ void terminal_t::solve_now()
net().solver()->update_forced();
}
-void terminal_t::schedule_solve_after(const netlist_time &after)
+void terminal_t::schedule_solve_after(const netlist_time after)
{
// Nets may belong to railnets which do not have a solver attached
if (this->has_net())
@@ -1077,16 +890,12 @@ void terminal_t::schedule_solve_after(const netlist_time &after)
logic_output_t::logic_output_t(core_device_t &dev, const pstring &aname)
: logic_t(dev, aname, STATE_OUT)
- , m_my_net(dev.netlist(), name() + ".net", this)
+ , m_my_net(dev.state(), name() + ".net", this)
{
this->set_net(&m_my_net);
- netlist().m_nets.push_back(plib::owned_ptr<logic_net_t>(&m_my_net, false));
+ state().register_net(pool_owned_ptr<logic_net_t>(&m_my_net, false));
set_logic_family(dev.logic_family());
- netlist().setup().register_term(*this);
-}
-
-logic_output_t::~logic_output_t()
-{
+ state().setup().register_term(*this);
}
void logic_output_t::initial(const netlist_sig_t val)
@@ -1102,11 +911,7 @@ void logic_output_t::initial(const netlist_sig_t val)
analog_input_t::analog_input_t(core_device_t &dev, const pstring &aname)
: analog_t(dev, aname, STATE_INP_ACTIVE)
{
- netlist().setup().register_term(*this);
-}
-
-analog_input_t::~analog_input_t()
-{
+ state().setup().register_term(*this);
}
// ----------------------------------------------------------------------------------------
@@ -1115,17 +920,13 @@ analog_input_t::~analog_input_t()
analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname)
: analog_t(dev, aname, STATE_OUT)
- , m_my_net(dev.netlist(), name() + ".net", this)
+ , m_my_net(dev.state(), name() + ".net", this)
{
- netlist().m_nets.push_back(plib::owned_ptr<analog_net_t>(&m_my_net, false));
+ state().register_net(pool_owned_ptr<analog_net_t>(&m_my_net, false));
this->set_net(&m_my_net);
//net().m_cur_Analog = NL_FCONST(0.0);
- netlist().setup().register_term(*this);
-}
-
-analog_output_t::~analog_output_t()
-{
+ state().setup().register_term(*this);
}
void analog_output_t::initial(const nl_double val)
@@ -1142,11 +943,7 @@ logic_input_t::logic_input_t(core_device_t &dev, const pstring &aname,
: logic_t(dev, aname, STATE_INP_ACTIVE, delegate)
{
set_logic_family(dev.logic_family());
- netlist().setup().register_term(*this);
-}
-
-logic_input_t::~logic_input_t()
-{
+ state().setup().register_term(*this);
}
// ----------------------------------------------------------------------------------------
@@ -1156,11 +953,7 @@ logic_input_t::~logic_input_t()
param_t::param_t(device_t &device, const pstring &name)
: device_object_t(device, device.name() + "." + name)
{
- device.setup().register_param(this->name(), *this);
-}
-
-param_t::~param_t()
-{
+ device.setup().register_param_t(this->name(), *this);
}
param_t::param_type_t param_t::param_type() const
@@ -1177,7 +970,7 @@ param_t::param_type_t param_t::param_type() const
return POINTER;
else
{
- netlist().log().fatal(MF_1_UNKNOWN_PARAM_TYPE, name());
+ state().log().fatal(MF_1_UNKNOWN_PARAM_TYPE, name());
return POINTER; /* Please compiler */
}
}
@@ -1186,50 +979,28 @@ param_t::param_type_t param_t::param_type() const
void param_t::update_param()
{
device().update_param();
- if (device().needs_update_after_param_change())
- device().update_dev();
}
-const pstring param_model_t::model_type()
+pstring param_t::get_initial(const device_t &dev, bool *found)
{
- if (m_map.size() == 0)
- netlist().setup().model_parse(this->Value(), m_map);
- return m_map["COREMODEL"];
+ pstring res = dev.setup().get_initial_param_val(this->name(), "");
+ *found = (res != "");
+ return res;
}
-param_str_t::param_str_t(device_t &device, const pstring &name, const pstring &val)
-: param_t(device, name)
-{
- m_param = device.setup().get_initial_param_val(this->name(),val);
-}
-
-param_str_t::~param_str_t()
-{
-}
-
-void param_str_t::changed()
-{
-}
-
-param_double_t::param_double_t(device_t &device, const pstring &name, const double val)
-: param_t(device, name)
+const pstring param_model_t::model_type()
{
- m_param = device.setup().get_initial_param_val(this->name(),val);
- netlist().save(*this, m_param, "m_param");
+ return state().setup().models().model_type(value());
}
-param_int_t::param_int_t(device_t &device, const pstring &name, const int val)
+param_str_t::param_str_t(device_t &device, const pstring &name, const pstring &val)
: param_t(device, name)
{
m_param = device.setup().get_initial_param_val(this->name(),val);
- netlist().save(*this, m_param, "m_param");
}
-param_logic_t::param_logic_t(device_t &device, const pstring &name, const bool val)
-: param_t(device, name)
+void param_str_t::changed()
{
- m_param = device.setup().get_initial_param_val(this->name(),val);
- netlist().save(*this, m_param, "m_param");
}
param_ptr_t::param_ptr_t(device_t &device, const pstring &name, uint8_t * val)
@@ -1241,53 +1012,25 @@ param_ptr_t::param_ptr_t(device_t &device, const pstring &name, uint8_t * val)
void param_model_t::changed()
{
- netlist().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name());
- m_map.clear();
+ state().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name());
}
const pstring param_model_t::model_value_str(const pstring &entity)
{
- if (m_map.size() == 0)
- netlist().setup().model_parse(this->Value(), m_map);
- return netlist().setup().model_value_str(m_map, entity);
+ return state().setup().models().model_value_str(value(), entity);
}
nl_double param_model_t::model_value(const pstring &entity)
{
- if (m_map.size() == 0)
- netlist().setup().model_parse(this->Value(), m_map);
- return netlist().setup().model_value(m_map, entity);
+ return state().setup().models().model_value(value(), entity);
}
-param_data_t::param_data_t(device_t &device, const pstring &name)
-: param_str_t(device, name, "")
-{
-}
-
-void param_data_t::changed()
-{
-}
-std::unique_ptr<plib::pistream> param_data_t::stream()
+plib::unique_ptr<plib::pistream> param_data_t::stream()
{
- return device().netlist().setup().get_data_stream(Value());
+ return device().setup().get_data_stream(value());
}
- namespace devices
- {
- // ----------------------------------------------------------------------------------------
- // mainclock
- // ----------------------------------------------------------------------------------------
-
- void NETLIB_NAME(mainclock)::mc_update(logic_net_t &net)
- {
- net.toggle_new_Q();
- net.update_devs();
- }
-
-
- } //namespace devices
-
bool detail::core_terminal_t::is_logic() const NL_NOEXCEPT
{
return dynamic_cast<const logic_t *>(this) != nullptr;
diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h
index e56fde89f88..9d0eed869e0 100644
--- a/src/lib/netlist/nl_base.h
+++ b/src/lib/netlist/nl_base.h
@@ -9,27 +9,25 @@
#ifndef NLBASE_H_
#define NLBASE_H_
-#include "nl_lists.h"
-#include "nl_time.h"
+#ifdef NL_PROHIBIT_BASEH_INCLUDE
+#error "nl_base.h included. Please correct."
+#endif
+
#include "plib/palloc.h" // owned_ptr
#include "plib/pdynlib.h"
-#include "plib/pstate.h"
#include "plib/pfmtlog.h"
-#include "plib/pstream.h"
+#include "plib/pmempool.h"
#include "plib/ppmf.h"
+#include "plib/pstate.h"
+#include "plib/pstream.h"
-#include <unordered_map>
-
-#ifdef NL_PROHIBIT_BASEH_INCLUDE
-#error "nl_base.h included. Please correct."
-#endif
-
-// ----------------------------------------------------------------------------------------
-// Type definitions
-// ----------------------------------------------------------------------------------------
+#include "nl_errstr.h"
+#include "nl_lists.h"
+#include "nltypes.h"
+#include "plib/ptime.h"
-/*! netlist_sig_t is the type used for logic signals. */
-using netlist_sig_t = std::uint32_t;
+#include <unordered_map>
+#include <vector>
//============================================================
// MACROS / New Syntax
@@ -73,7 +71,7 @@ class NETLIB_NAME(name) : public device_t
/*! Used to define the destructor of a netlist device.
* The use of a destructor for netlist device should normally not be necessary.
*/
-#define NETLIB_DESTRUCTOR(name) public: virtual ~NETLIB_NAME(name)()
+#define NETLIB_DESTRUCTOR(name) public: virtual ~NETLIB_NAME(name)() noexcept
/*! Define an extended constructor and add further parameters to it.
* The macro allows to add further parameters to a device constructor. This is
@@ -85,14 +83,15 @@ class NETLIB_NAME(name) : public device_t
: device_t(owner, name)
/*! Add this to a device definition to mark the device as dynamic.
- * If NETLIB_IS_DYNAMIC(true) is added to the device definition the device
- * is treated as an analog dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI
- * is called on a each step of the Newton-Raphson step
- * of solving the linear equations.
- *
- * You may also use e.g. NETLIB_IS_DYNAMIC(m_func() != "") to only make the
- * device a dynamic device if parameter m_func is set.
- */
+ *
+ * If NETLIB_IS_DYNAMIC(true) is added to the device definition the device
+ * is treated as an analog dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI
+ * is called on a each step of the Newton-Raphson step
+ * of solving the linear equations.
+ *
+ * You may also use e.g. NETLIB_IS_DYNAMIC(m_func() != "") to only make the
+ * device a dynamic device if parameter m_func is set.
+ */
#define NETLIB_IS_DYNAMIC(expr) \
public: virtual bool is_dynamic() const override { return expr; }
@@ -127,36 +126,30 @@ class NETLIB_NAME(name) : public device_t
#define NETLIB_TIMESTEPI() \
public: virtual void timestep(const nl_double step) override
-#define NETLIB_UPDATE_AFTER_PARAM_CHANGE() \
- public: virtual bool needs_update_after_param_change() const override { return true; }
-
#define NETLIB_FAMILY(family) , m_famsetter(*this, family)
#define NETLIB_DELEGATE(chip, name) nldelegate(&NETLIB_NAME(chip) :: name, this)
-#define NETLIB_UPDATE_TERMINALSI() public: virtual void update_terminals() override
-#define NETLIB_HANDLERI(name) private: virtual void name() NL_NOEXCEPT
-#define NETLIB_UPDATEI() protected: virtual void update() NL_NOEXCEPT override
-#define NETLIB_UPDATE_PARAMI() public: virtual void update_param() override
-#define NETLIB_RESETI() protected: virtual void reset() override
+#define NETLIB_UPDATE_TERMINALSI() virtual void update_terminals() override
+#define NETLIB_HANDLERI(name) virtual void name() NL_NOEXCEPT
+#define NETLIB_UPDATEI() virtual void update() NL_NOEXCEPT override
+#define NETLIB_UPDATE_PARAMI() virtual void update_param() override
+#define NETLIB_RESETI() virtual void reset() override
#define NETLIB_TIMESTEP(chip) void NETLIB_NAME(chip) :: timestep(const nl_double step)
#define NETLIB_SUB(chip) nld_ ## chip
-#define NETLIB_SUBXX(ns, chip) std::unique_ptr< ns :: nld_ ## chip >
+#define NETLIB_SUBXX(ns, chip) pool_owned_ptr< ns :: nld_ ## chip >
-#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name(void) NL_NOEXCEPT
+#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name() NL_NOEXCEPT
#define NETLIB_UPDATE(chip) NETLIB_HANDLER(chip, update)
-// FIXME: NETLIB_PARENT_UPDATE should disappear
-#define NETLIB_PARENT_UPDATE(chip) NETLIB_NAME(chip) :: update();
-
#define NETLIB_RESET(chip) void NETLIB_NAME(chip) :: reset(void)
-#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param(void)
+#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param()
#define NETLIB_FUNC_VOID(chip, name, params) void NETLIB_NAME(chip) :: name params
-#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals(void)
+#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals()
//============================================================
// Asserts
@@ -169,7 +162,7 @@ class NETLIB_NAME(name) : public device_t
#define nl_assert(x) do { if (0) if (!(x)) { /*throw nl_exception(plib::pfmt("assert: {1}:{2}: {3}")(__FILE__)(__LINE__)(#x) ); */} } while (0)
#define NL_NOEXCEPT noexcept
#endif
-#define nl_assert_always(x, msg) do { if (!(x)) throw nl_exception(plib::pfmt("Fatal error: {1}\nCaused by assert: {2}:{3}: {4}")(msg)(__FILE__)(__LINE__)(#x)); } while (0)
+#define nl_assert_always(x, msg) do { if (!(x)) throw nl_exception("Fatal error: {1}\nCaused by assert: {2}:{3}: {4}", msg, __FILE__, __LINE__, #x); } while (0)
//============================================================
// Namespace starts
@@ -177,6 +170,11 @@ class NETLIB_NAME(name) : public device_t
namespace netlist
{
+ /*! Delegate type for device notification.
+ *
+ */
+ using nldelegate = plib::pmfp<void>;
+
// -----------------------------------------------------------------------------
// forward definitions
// -----------------------------------------------------------------------------
@@ -191,27 +189,23 @@ namespace netlist
class NETLIB_NAME(base_proxy);
class NETLIB_NAME(base_d_to_a_proxy);
class NETLIB_NAME(base_a_to_d_proxy);
- }
+ } // namespace devices
namespace detail {
- class object_t;
- class device_object_t;
- struct netlist_ref;
- class core_terminal_t;
struct family_setter_t;
class queue_t;
- class net_t;
- }
+ } // namespace detail
class logic_output_t;
class logic_input_t;
class analog_net_t;
class logic_net_t;
- class net_t;
class setup_t;
class netlist_t;
+ class netlist_state_t;
class core_device_t;
class device_t;
+ class callbacks_t;
//============================================================
// Exceptions
@@ -229,9 +223,12 @@ namespace netlist
explicit nl_exception(const pstring &text //!< text to be passed
)
: plib::pexception(text) { }
- /*! Copy constructor. */
- nl_exception(const nl_exception &e) : plib::pexception(e) { }
- virtual ~nl_exception();
+
+ template<typename... Args>
+ explicit nl_exception(const pstring &fmt //!< format to be used
+ , Args&&... args //!< arguments to be passed
+ )
+ : plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...)) { }
};
/*! Logic families descriptors are used to create proxy devices.
@@ -242,18 +239,21 @@ namespace netlist
{
public:
logic_family_desc_t();
- virtual ~logic_family_desc_t();
- virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, const pstring &name,
+ COPYASSIGNMOVE(logic_family_desc_t, delete)
+
+ virtual ~logic_family_desc_t() noexcept = default;
+
+ virtual pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name,
logic_output_t *proxied) const = 0;
- virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name,
+ virtual pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name,
logic_input_t *proxied) const = 0;
double fixed_V() const { return m_fixed_V; }
double low_thresh_V(const double VN, const double VP) const { return VN + (VP - VN) * m_low_thresh_PCNT; }
double high_thresh_V(const double VN, const double VP) const { return VN + (VP - VN) * m_high_thresh_PCNT; }
- double low_V(const double VN, const double VP) const { return VN + m_low_VO; }
- double high_V(const double VN, const double VP) const { return VP - m_high_VO; }
+ double low_V(const double VN, const double VP) const { plib::unused_var(VP); return VN + m_low_VO; }
+ double high_V(const double VN, const double VP) const { plib::unused_var(VN); return VP - m_high_VO; }
double R_low() const { return m_R_low; }
double R_high() const { return m_R_high; }
@@ -282,12 +282,14 @@ namespace netlist
public:
logic_family_t() : m_logic_family(nullptr) {}
+ COPYASSIGNMOVE(logic_family_t, delete)
+
const logic_family_desc_t *logic_family() const { return m_logic_family; }
void set_logic_family(const logic_family_desc_t *fam) { m_logic_family = fam; }
protected:
- ~logic_family_t() { } // prohibit polymorphic destruction
+ ~logic_family_t() noexcept = default; // prohibit polymorphic destruction
const logic_family_desc_t *m_logic_family;
};
@@ -317,12 +319,15 @@ namespace netlist
const pstring &name, //!< identifier/name for this state variable
const T &value //!< Initial value after construction
);
+
+ //! Destructor.
+ ~state_var() noexcept = default;
//! Copy Constructor.
- constexpr state_var(const state_var &rhs) noexcept = default;
+ constexpr state_var(const state_var &rhs) = default;
//! Move Constructor.
constexpr state_var(state_var &&rhs) noexcept = default;
//! Assignment operator to assign value of a state var.
- C14CONSTEXPR state_var &operator=(const state_var &rhs) noexcept = default;
+ C14CONSTEXPR state_var &operator=(const state_var &rhs) = default;
//! Assignment move operator to assign value of a state var.
C14CONSTEXPR state_var &operator=(state_var &&rhs) noexcept = default;
//! Assignment operator to assign value of type T.
@@ -345,25 +350,29 @@ namespace netlist
* Please refer to \ref state_var.
*/
template <typename T, std::size_t N>
- struct state_var<T[N]>
+ struct state_array
{
public:
//! Constructor.
template <typename O>
- state_var(O &owner, //!< owner must have a netlist() method.
+ state_array(O &owner, //!< owner must have a netlist() method.
const pstring &name, //!< identifier/name for this state variable
const T &value //!< Initial value after construction
);
//! Copy Constructor.
- state_var(const state_var &rhs) NL_NOEXCEPT = default;
+ state_array(const state_array &rhs) noexcept = default;
+ //! Destructor.
+ ~state_array() noexcept = default;
//! Move Constructor.
- state_var(state_var &&rhs) NL_NOEXCEPT = default;
- state_var &operator=(const state_var &rhs) NL_NOEXCEPT = default;
- state_var &operator=(const T &rhs) NL_NOEXCEPT { m_value = rhs; return *this; }
- T & operator[](const std::size_t i) NL_NOEXCEPT { return m_value[i]; }
- constexpr T & operator[](const std::size_t i) const NL_NOEXCEPT { return m_value[i]; }
+ state_array(state_array &&rhs) noexcept = default;
+ state_array &operator=(const state_array &rhs) noexcept = default;
+ state_array &operator=(state_array &&rhs) noexcept = default;
+
+ state_array &operator=(const T &rhs) noexcept { m_value = rhs; return *this; }
+ T & operator[](const std::size_t i) noexcept { return m_value[i]; }
+ constexpr const T & operator[](const std::size_t i) const noexcept { return m_value[i]; }
private:
- T m_value[N];
+ std::array<T, N> m_value;
};
// -----------------------------------------------------------------------------
@@ -382,164 +391,324 @@ namespace netlist
/*! predefined state variable type for sig_t */
using state_var_sig = state_var<netlist_sig_t>;
- // -----------------------------------------------------------------------------
- // object_t
- // -----------------------------------------------------------------------------
+ namespace detail {
- /*! The base class for netlist devices, terminals and parameters.
- *
- * This class serves as the base class for all device, terminal and
- * objects. It provides new and delete operators to support e.g. pooled
- * memory allocation to enhance locality. Please refer to \ref USE_MEMPOOL as
- * well.
- */
- class detail::object_t
- {
- public:
+ // -----------------------------------------------------------------------------
+ // object_t
+ // -----------------------------------------------------------------------------
- /*! Constructor.
+ /*! The base class for netlist devices, terminals and parameters.
*
- * Every class derived from the object_t class must have a name.
+ * This class serves as the base class for all device, terminal and
+ * objects. It provides new and delete operators to support e.g. pooled
+ * memory allocation to enhance locality. Please refer to \ref USE_MEMPOOL as
+ * well.
*/
- explicit object_t(const pstring &aname /*!< string containing name of the object */);
+ class object_t
+ {
+ public:
- /*! return name of the object
- *
- * \returns name of the object.
- */
- const pstring &name() const;
+ /*! Constructor.
+ *
+ * Every class derived from the object_t class must have a name.
+ */
+ explicit object_t(const pstring &aname /*!< string containing name of the object */);
+
+ COPYASSIGNMOVE(object_t, delete)
+ /*! return name of the object
+ *
+ * \returns name of the object.
+ */
+ pstring name() const;
+
+ #if 0
+ void * operator new (size_t size, void *ptr) { plib::unused_var(size); return ptr; }
+ void operator delete (void *ptr, void *) { plib::unused_var(ptr); }
+ void * operator new (size_t size) = delete;
+ void operator delete (void * mem) = delete;
+ #endif
+ protected:
+ ~object_t() noexcept = default; // only childs should be destructible
- void * operator new (size_t size, void *ptr) { return ptr; }
- void operator delete (void *ptr, void *) { }
- void * operator new (size_t size);
- void operator delete (void * mem);
- protected:
- ~object_t(); // only childs should be destructible
+ private:
+ //pstring m_name;
+ static std::unordered_map<const object_t *, pstring> &name_hash()
+ {
+ static std::unordered_map<const object_t *, pstring> lhash;
+ return lhash;
+ }
+ };
- private:
- std::unique_ptr<pstring> m_name;
- };
+ struct netlist_ref
+ {
+ explicit netlist_ref(netlist_state_t &nl);
- struct detail::netlist_ref
- {
- explicit constexpr netlist_ref(netlist_t &nl) : m_netlist(nl) { }
+ COPYASSIGNMOVE(netlist_ref, delete)
- C14CONSTEXPR netlist_t & netlist() NL_NOEXCEPT { return m_netlist; }
- constexpr const netlist_t & netlist() const NL_NOEXCEPT { return m_netlist; }
+ netlist_state_t & state() noexcept;
+ const netlist_state_t & state() const noexcept;
- protected:
- ~netlist_ref() = default; // prohibit polymorphic destruction
+ setup_t & setup() noexcept;
+ const setup_t & setup() const noexcept;
- private:
- netlist_t & m_netlist;
+ netlist_t & exec() noexcept { return m_netlist; }
+ const netlist_t & exec() const noexcept { return m_netlist; }
- };
+ protected:
+ ~netlist_ref() noexcept = default; // prohibit polymorphic destruction
- // -----------------------------------------------------------------------------
- // device_object_t
- // -----------------------------------------------------------------------------
+ private:
+ netlist_t & m_netlist;
- /*! Base class for all objects being owned by a device.
- *
- * Serves as the base class of all objects being owned by a device.
- *
- */
- class detail::device_object_t : public detail::object_t
- {
- public:
- /*! Constructor.
+ };
+
+ // -----------------------------------------------------------------------------
+ // device_object_t
+ // -----------------------------------------------------------------------------
+
+ /*! Base class for all objects being owned by a device.
+ *
+ * Serves as the base class of all objects being owned by a device.
*
- * \param dev device owning the object.
- * \param name string holding the name of the device
*/
- device_object_t(core_device_t &dev, const pstring &name);
+ class device_object_t : public object_t
+ {
+ public:
+ /*! Constructor.
+ *
+ * \param dev device owning the object.
+ * \param name string holding the name of the device
+ */
+ device_object_t(core_device_t &dev, const pstring &name);
+
+ /*! returns reference to owning device.
+ * \returns reference to owning device.
+ */
+ core_device_t &device() noexcept { return m_device; }
+ const core_device_t &device() const noexcept { return m_device; }
+
+ /*! The netlist owning the owner of this object.
+ * \returns reference to netlist object.
+ */
+ netlist_state_t &state() NL_NOEXCEPT;
+ const netlist_state_t &state() const NL_NOEXCEPT;
+
+ netlist_t &exec() NL_NOEXCEPT;
+ const netlist_t &exec() const NL_NOEXCEPT;
- /*! returns reference to owning device.
- * \returns reference to owning device.
- */
- core_device_t &device() NL_NOEXCEPT { return m_device; }
- const core_device_t &device() const NL_NOEXCEPT { return m_device; }
+ private:
+ core_device_t & m_device;
+ };
- /*! The netlist owning the owner of this object.
- * \returns reference to netlist object.
+ // -----------------------------------------------------------------------------
+ // core_terminal_t
+ // -----------------------------------------------------------------------------
+
+ /*! Base class for all terminals.
+ *
+ * All terminals are derived from this class.
+ *
*/
- netlist_t &netlist() NL_NOEXCEPT;
- const netlist_t &netlist() const NL_NOEXCEPT;
- private:
- core_device_t & m_device;
-};
+ class net_t;
- /*! Delegate type for device notification.
- *
- */
- typedef plib::pmfp<void> nldelegate;
+ class core_terminal_t : public device_object_t,
+ public plib::linkedlist_t<core_terminal_t>::element_t
+ {
+ public:
- // -----------------------------------------------------------------------------
- // core_terminal_t
- // -----------------------------------------------------------------------------
+ using list_t = std::vector<core_terminal_t *>;
- /*! Base class for all terminals.
- *
- * All terminals are derived from this class.
- *
- */
- class detail::core_terminal_t : public device_object_t,
- public plib::linkedlist_t<core_terminal_t>::element_t
- {
- public:
+ static constexpr const auto INP_HL_SHIFT = 0;
+ static constexpr const auto INP_LH_SHIFT = 1;
+ static constexpr const auto INP_ACTIVE_SHIFT = 2;
+
+ enum state_e {
+ STATE_INP_PASSIVE = 0,
+ STATE_INP_HL = (1 << INP_HL_SHIFT),
+ STATE_INP_LH = (1 << INP_LH_SHIFT),
+ STATE_INP_ACTIVE = (1 << INP_ACTIVE_SHIFT),
+ STATE_OUT = 128,
+ STATE_BIDIR = 256
+ };
+
+ core_terminal_t(core_device_t &dev, const pstring &aname,
+ const state_e state, nldelegate delegate = nldelegate());
+ virtual ~core_terminal_t() noexcept = default;
+
+ COPYASSIGNMOVE(core_terminal_t, delete)
+
+ /*! The object type.
+ * \returns type of the object
+ */
+ terminal_type type() const;
+ /*! Checks if object is of specified type.
+ * \param atype type to check object against.
+ * \returns true if object is of specified type else false.
+ */
+ bool is_type(const terminal_type atype) const noexcept { return (type() == atype); }
+
+ void set_net(net_t *anet) noexcept { m_net = anet; }
+ void clear_net() noexcept { m_net = nullptr; }
+ bool has_net() const noexcept { return (m_net != nullptr); }
+
+ const net_t & net() const noexcept { return *m_net;}
+ net_t & net() noexcept { return *m_net;}
- using list_t = std::vector<core_terminal_t *>;
+ bool is_logic() const NL_NOEXCEPT;
+ bool is_analog() const NL_NOEXCEPT;
- static constexpr const unsigned INP_HL_SHIFT = 0;
- static constexpr const unsigned INP_LH_SHIFT = 1;
- static constexpr const unsigned INP_ACTIVE_SHIFT = 2;
+ bool is_state(state_e astate) const noexcept { return (m_state == astate); }
+ state_e terminal_state() const noexcept { return m_state; }
+ void set_state(state_e astate) noexcept { m_state = astate; }
- enum state_e {
- STATE_INP_PASSIVE = 0,
- STATE_INP_HL = (1 << INP_HL_SHIFT),
- STATE_INP_LH = (1 << INP_LH_SHIFT),
- STATE_INP_ACTIVE = (1 << INP_ACTIVE_SHIFT),
- STATE_OUT = 128,
- STATE_BIDIR = 256
+ void reset() noexcept { set_state(is_type(OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); }
+
+ nldelegate m_delegate;
+ #if USE_COPY_INSTEAD_OF_REFERENCE
+ void set_copied_input(netlist_sig_t val)
+ {
+ m_Q = val;
+ }
+
+ state_var_sig m_Q;
+ #else
+ void set_copied_input(netlist_sig_t val) const { plib::unused_var(val); }
+ #endif
+
+ private:
+ net_t * m_net;
+ state_var<state_e> m_state;
};
- core_terminal_t(core_device_t &dev, const pstring &aname,
- const state_e state, nldelegate delegate = nldelegate());
- virtual ~core_terminal_t();
+ // -----------------------------------------------------------------------------
+ // net_t
+ // -----------------------------------------------------------------------------
- /*! The object type.
- * \returns type of the object
- */
- terminal_type type() const;
- /*! Checks if object is of specified type.
- * \param atype type to check object against.
- * \returns true if object is of specified type else false.
- */
- bool is_type(const terminal_type atype) const { return (type() == atype); }
+ class net_t :
+ public object_t,
+ public netlist_ref
+ {
+ public:
- void set_net(net_t *anet);
- void clear_net();
- bool has_net() const NL_NOEXCEPT { return (m_net != nullptr); }
+ enum class queue_status
+ {
+ DELAYED_DUE_TO_INACTIVE = 0,
+ QUEUED,
+ DELIVERED
+ };
- const net_t & net() const NL_NOEXCEPT { return *m_net;}
- net_t & net() NL_NOEXCEPT { return *m_net;}
+ net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *mr = nullptr);
- bool is_logic() const NL_NOEXCEPT;
- bool is_analog() const NL_NOEXCEPT;
+ COPYASSIGNMOVE(net_t, delete)
- bool is_state(const state_e &astate) const NL_NOEXCEPT { return (m_state == astate); }
- const state_e &state() const NL_NOEXCEPT { return m_state; }
- void set_state(const state_e &astate) NL_NOEXCEPT { m_state = astate; }
+ virtual ~net_t() noexcept = default;
- void reset();
+ void reset();
- nldelegate m_delegate;
+ void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); }
- private:
- net_t * m_net;
- state_var<state_e> m_state;
- };
+ void toggle_and_push_to_queue(netlist_time delay) NL_NOEXCEPT
+ {
+ toggle_new_Q();
+ push_to_queue(delay);
+ }
+
+ void push_to_queue(netlist_time delay) NL_NOEXCEPT;
+ bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; }
+
+ void update_devs() NL_NOEXCEPT;
+
+ netlist_time next_scheduled_time() const noexcept { return m_next_scheduled_time; }
+ void set_next_scheduled_time(netlist_time ntime) noexcept { m_next_scheduled_time = ntime; }
+
+ bool isRailNet() const noexcept { return !(m_railterminal == nullptr); }
+ core_terminal_t & railterminal() const noexcept { return *m_railterminal; }
+
+ std::size_t num_cons() const noexcept { return m_core_terms.size(); }
+
+ void add_to_active_list(core_terminal_t &term) NL_NOEXCEPT;
+ void remove_from_active_list(core_terminal_t &term) NL_NOEXCEPT;
+
+ /* setup stuff */
+
+ void add_terminal(core_terminal_t &terminal);
+ void remove_terminal(core_terminal_t &terminal);
+
+ bool is_logic() const NL_NOEXCEPT;
+ bool is_analog() const NL_NOEXCEPT;
+
+ void rebuild_list(); /* rebuild m_list after a load */
+ void move_connections(net_t &dest_net);
+
+ std::vector<core_terminal_t *> &core_terms() { return m_core_terms; }
+ #if USE_COPY_INSTEAD_OF_REFERENCE
+ void update_inputs()
+ {
+ for (auto & term : m_core_terms)
+ term->m_Q = m_cur_Q;
+ }
+ #else
+ void update_inputs() const
+ {
+ /* nothing needs to be done */
+ }
+ #endif
+
+ protected:
+
+ /* only used for logic nets */
+ netlist_sig_t Q() const noexcept { return m_cur_Q; }
+
+ /* only used for logic nets */
+ void initial(const netlist_sig_t val) noexcept
+ {
+ m_cur_Q = m_new_Q = val;
+ update_inputs();
+ }
+
+ /* only used for logic nets */
+ void set_Q_and_push(const netlist_sig_t newQ, const netlist_time delay) NL_NOEXCEPT
+ {
+ if (newQ != m_new_Q)
+ {
+ m_new_Q = newQ;
+ push_to_queue(delay);
+ }
+ }
+
+ /* only used for logic nets */
+ void set_Q_time(const netlist_sig_t newQ, const netlist_time at) NL_NOEXCEPT
+ {
+ if (newQ != m_new_Q)
+ {
+ m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
+ m_next_scheduled_time = at;
+ }
+ m_cur_Q = m_new_Q = newQ;
+ update_inputs();
+ }
+
+ /* internal state support
+ * FIXME: get rid of this and implement export/import in MAME
+ */
+ /* only used for logic nets */
+ netlist_sig_t *Q_state_ptr() { return m_cur_Q.ptr(); }
+
+ private:
+ state_var<netlist_sig_t> m_new_Q;
+ state_var<netlist_sig_t> m_cur_Q;
+ state_var<queue_status> m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */
+ state_var<netlist_time> m_next_scheduled_time;
+
+ core_terminal_t * m_railterminal;
+ plib::linkedlist_t<core_terminal_t> m_list_active;
+ std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
+
+ template <typename T>
+ void process(const T mask, netlist_sig_t sig);
+ };
+ } // namespace detail
// -----------------------------------------------------------------------------
// analog_t
@@ -550,7 +719,6 @@ namespace netlist
public:
analog_t(core_device_t &dev, const pstring &aname, const state_e state);
- virtual ~analog_t();
const analog_net_t & net() const NL_NOEXCEPT;
analog_net_t & net() NL_NOEXCEPT;
@@ -564,53 +732,44 @@ namespace netlist
{
public:
- terminal_t(core_device_t &dev, const pstring &aname);
- virtual ~terminal_t();
+ terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm);
nl_double operator ()() const NL_NOEXCEPT;
- void set(const nl_double &G) NL_NOEXCEPT
+ void set_conductivity(const nl_double G) noexcept
{
- set(G,G, 0.0);
+ set_go_gt_I(-G, G, 0.0);
}
- void set(const nl_double &GO, const nl_double &GT) NL_NOEXCEPT
+ void set_go_gt(const nl_double GO, const nl_double GT) noexcept
{
- set(GO, GT, 0.0);
+ set_go_gt_I(GO, GT, 0.0);
}
- void set(const nl_double &GO, const nl_double &GT, const nl_double &I) NL_NOEXCEPT
+ void set_go_gt_I(const nl_double GO, const nl_double GT, const nl_double I) noexcept
{
- set_ptr(m_Idr1, I);
- set_ptr(m_go1, GO);
- set_ptr(m_gt1, GT);
+ if (m_go1 != nullptr)
+ {
+ if (*m_Idr1 != I) *m_Idr1 = I;
+ if (*m_go1 != GO) *m_go1 = GO;
+ if (*m_gt1 != GT) *m_gt1 = GT;
+ }
}
void solve_now();
- void schedule_solve_after(const netlist_time &after);
+ void schedule_solve_after(const netlist_time after);
- void set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) NL_NOEXCEPT
- {
- m_gt1 = gt;
- m_go1 = go;
- m_Idr1 = Idr;
- }
-
- terminal_t *m_otherterm;
+ void set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) noexcept;
+ terminal_t *connected_terminal() const noexcept { return m_connected_terminal; }
private:
- void set_ptr(nl_double *ptr, const nl_double &val) NL_NOEXCEPT
- {
- if (ptr != nullptr && *ptr != val)
- {
- *ptr = val;
- }
- }
nl_double *m_Idr1; // drive current
nl_double *m_go1; // conductance for Voltage from other term
nl_double *m_gt1; // conductance for total conductance
+ terminal_t *m_connected_terminal;
+
};
@@ -623,7 +782,6 @@ namespace netlist
public:
logic_t(core_device_t &dev, const pstring &aname,
const state_e state, nldelegate delegate = nldelegate());
- virtual ~logic_t();
bool has_proxy() const { return (m_proxy != nullptr); }
devices::nld_base_proxy *get_proxy() const { return m_proxy; }
@@ -647,7 +805,6 @@ namespace netlist
public:
logic_input_t(core_device_t &dev, const pstring &aname,
nldelegate delegate = nldelegate());
- virtual ~logic_input_t();
netlist_sig_t operator()() const NL_NOEXCEPT
{
@@ -679,9 +836,6 @@ namespace netlist
const pstring &aname /*!< name of terminal */
);
- /*! Destructor */
- virtual ~analog_input_t();
-
/*! returns voltage at terminal.
* \returns voltage at terminal.
*/
@@ -694,124 +848,18 @@ namespace netlist
};
- // -----------------------------------------------------------------------------
- // net_t
- // -----------------------------------------------------------------------------
-
- class detail::net_t :
- public detail::object_t,
- public detail::netlist_ref
- {
- public:
-
- enum queue_status
- {
- QS_DELAYED_DUE_TO_INACTIVE = 0,
- QS_QUEUED,
- QS_DELIVERED
- };
-
- net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr = nullptr);
- virtual ~net_t();
-
- void reset();
-
- void toggle_new_Q() NL_NOEXCEPT { m_new_Q = (m_cur_Q ^ 1); }
-
- void toggle_and_push_to_queue(const netlist_time &delay) NL_NOEXCEPT
- {
- toggle_new_Q();
- push_to_queue(delay);
- }
-
- void push_to_queue(const netlist_time &delay) NL_NOEXCEPT;
- bool is_queued() const NL_NOEXCEPT { return m_in_queue == QS_QUEUED; }
-
- void update_devs() NL_NOEXCEPT;
-
- const netlist_time &time() const NL_NOEXCEPT { return m_time; }
- void set_time(const netlist_time &ntime) NL_NOEXCEPT { m_time = ntime; }
-
- bool isRailNet() const NL_NOEXCEPT { return !(m_railterminal == nullptr); }
- core_terminal_t & railterminal() const NL_NOEXCEPT { return *m_railterminal; }
-
- std::size_t num_cons() const NL_NOEXCEPT { return m_core_terms.size(); }
-
- void inc_active(core_terminal_t &term) NL_NOEXCEPT;
- void dec_active(core_terminal_t &term) NL_NOEXCEPT;
-
- /* setup stuff */
-
- void add_terminal(core_terminal_t &terminal);
- void remove_terminal(core_terminal_t &terminal);
-
- bool is_logic() const NL_NOEXCEPT;
- bool is_analog() const NL_NOEXCEPT;
-
- void rebuild_list(); /* rebuild m_list after a load */
- void move_connections(net_t &dest_net);
-
- std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
-
- protected:
- state_var<netlist_sig_t> m_new_Q;
- state_var<netlist_sig_t> m_cur_Q;
- state_var<queue_status> m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */
- state_var_s32 m_active;
-
- state_var<netlist_time> m_time;
-
- private:
- plib::linkedlist_t<core_terminal_t> m_list_active;
- core_terminal_t * m_railterminal;
-
- void process(unsigned Mask);
- };
class logic_net_t : public detail::net_t
{
public:
- logic_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
- virtual ~logic_net_t();
-
- netlist_sig_t Q() const NL_NOEXCEPT { return m_cur_Q; }
- void initial(const netlist_sig_t val) NL_NOEXCEPT { m_cur_Q = m_new_Q = val; }
-
- void set_Q_and_push(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
- {
- if (newQ != m_new_Q )
- {
- m_new_Q = newQ;
- push_to_queue(delay);
- }
- }
- void set_Q_and_push_force(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
- {
- if (newQ != m_new_Q || is_queued())
- {
- m_new_Q = newQ;
- push_to_queue(delay);
- }
- }
-
- void set_Q_time(const netlist_sig_t newQ, const netlist_time &at) NL_NOEXCEPT
- {
- if (newQ != m_new_Q)
- {
- m_in_queue = QS_DELAYED_DUE_TO_INACTIVE;
- m_time = at;
- }
- m_cur_Q = m_new_Q = newQ;
- }
-
- /* internal state support
- * FIXME: get rid of this and implement export/import in MAME
- */
- netlist_sig_t *Q_state_ptr() { return m_cur_Q.ptr(); }
+ logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
- protected:
- private:
+ using detail::net_t::Q;
+ using detail::net_t::initial;
+ using detail::net_t::set_Q_and_push;
+ using detail::net_t::set_Q_time;
+ using detail::net_t::Q_state_ptr;
};
@@ -823,9 +871,7 @@ namespace netlist
friend class detail::net_t;
- analog_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
-
- virtual ~analog_net_t();
+ analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
nl_double Q_Analog() const NL_NOEXCEPT { return m_cur_Analog; }
void set_Q_Analog(const nl_double v) NL_NOEXCEPT { m_cur_Analog = v; }
@@ -849,21 +895,15 @@ namespace netlist
public:
logic_output_t(core_device_t &dev, const pstring &aname);
- virtual ~logic_output_t();
void initial(const netlist_sig_t val);
- void push(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
+ void push(const netlist_sig_t newQ, const netlist_time delay) NL_NOEXCEPT
{
m_my_net.set_Q_and_push(newQ, delay); // take the shortcut
}
- void push_force(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
- {
- m_my_net.set_Q_and_push_force(newQ, delay); // take the shortcut
- }
-
- void set_Q_time(const netlist_sig_t newQ, const netlist_time &at) NL_NOEXCEPT
+ void set_Q_time(const netlist_sig_t newQ, const netlist_time at) NL_NOEXCEPT
{
m_my_net.set_Q_time(newQ, at); // take the shortcut
}
@@ -876,7 +916,6 @@ namespace netlist
{
public:
analog_output_t(core_device_t &dev, const pstring &aname);
- virtual ~analog_output_t();
void push(const nl_double val) NL_NOEXCEPT { set_Q(val); }
void initial(const nl_double val);
@@ -904,13 +943,17 @@ namespace netlist
param_t(device_t &device, const pstring &name);
+ COPYASSIGNMOVE(param_t, delete)
+
param_type_t param_type() const;
protected:
- virtual ~param_t(); /* not intended to be destroyed */
+ virtual ~param_t() noexcept = default; /* not intended to be destroyed */
void update_param();
+ pstring get_initial(const device_t &dev, bool *found);
+
template<typename C>
void set(C &p, const C v)
{
@@ -923,53 +966,51 @@ namespace netlist
};
- class param_ptr_t final: public param_t
- {
- public:
- param_ptr_t(device_t &device, const pstring &name, std::uint8_t* val);
- std::uint8_t * operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(std::uint8_t *param) { set(m_param, param); }
- private:
- std::uint8_t* m_param;
- };
+ // -----------------------------------------------------------------------------
+ // numeric parameter template
+ // -----------------------------------------------------------------------------
- class param_logic_t final: public param_t
+ template <typename T>
+ class param_num_t final: public param_t
{
public:
- param_logic_t(device_t &device, const pstring &name, const bool val);
- const bool &operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(const bool &param) { set(m_param, param); }
- private:
- bool m_param;
- };
+ param_num_t(device_t &device, const pstring &name, const T val);
- class param_int_t final: public param_t
- {
- public:
- param_int_t(device_t &device, const pstring &name, const int val);
- const int &operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(const int &param) { set(m_param, param); }
+ const T operator()() const NL_NOEXCEPT { return m_param; }
+ void setTo(const T &param) { set(m_param, param); }
private:
- int m_param;
+ T m_param;
};
- class param_double_t final: public param_t
+ /* FIXME: these should go as well */
+ using param_logic_t = param_num_t<bool>;
+ using param_int_t = param_num_t<int>;
+ using param_double_t = param_num_t<double>;
+
+ // -----------------------------------------------------------------------------
+ // pointer parameter
+ // -----------------------------------------------------------------------------
+
+ class param_ptr_t final: public param_t
{
public:
- param_double_t(device_t &device, const pstring &name, const double val);
- const double &operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(const double &param) { set(m_param, param); }
+ param_ptr_t(device_t &device, const pstring &name, std::uint8_t* val);
+ std::uint8_t * operator()() const NL_NOEXCEPT { return m_param; }
+ void setTo(std::uint8_t *param) { set(m_param, param); }
private:
- double m_param;
+ std::uint8_t* m_param;
};
+ // -----------------------------------------------------------------------------
+ // string parameter
+ // -----------------------------------------------------------------------------
+
class param_str_t : public param_t
{
public:
param_str_t(device_t &device, const pstring &name, const pstring &val);
- virtual ~param_str_t();
- const pstring &operator()() const NL_NOEXCEPT { return Value(); }
+ const pstring &operator()() const NL_NOEXCEPT { return value(); }
void setTo(const pstring &param) NL_NOEXCEPT
{
if (m_param != param)
@@ -981,11 +1022,16 @@ namespace netlist
}
protected:
virtual void changed();
- const pstring &Value() const NL_NOEXCEPT { return m_param; }
+ const pstring &value() const NL_NOEXCEPT { return m_param; }
private:
+ PALIGNAS_CACHELINE()
pstring m_param;
};
+ // -----------------------------------------------------------------------------
+ // model parameter
+ // -----------------------------------------------------------------------------
+
class param_model_t : public param_str_t
{
public:
@@ -997,8 +1043,8 @@ namespace netlist
: m_value(param.model_value(name))
{
}
- const double &operator()() const NL_NOEXCEPT { return m_value; }
- operator const double&() const NL_NOEXCEPT { return m_value; }
+ double operator()() const noexcept { return m_value; }
+ operator double() const noexcept { return m_value; }
private:
const double m_value;
};
@@ -1010,24 +1056,29 @@ namespace netlist
const pstring model_value_str(const pstring &entity) /*const*/;
const pstring model_type() /*const*/;
+ /* hide this */
+ void setTo(const pstring &param) = delete;
protected:
- virtual void changed() override;
+ void changed() override;
nl_double model_value(const pstring &entity) /*const*/;
private:
- /* hide this */
- void setTo(const pstring &param) = delete;
- detail::model_map_t m_map;
};
+ // -----------------------------------------------------------------------------
+ // data parameter
+ // -----------------------------------------------------------------------------
class param_data_t : public param_str_t
{
public:
- param_data_t(device_t &device, const pstring &name);
+ param_data_t(device_t &device, const pstring &name)
+ : param_str_t(device, name, "")
+ {
+ }
- std::unique_ptr<plib::pistream> stream();
+ plib::unique_ptr<plib::pistream> stream();
protected:
- virtual void changed() override;
+ void changed() override { }
};
// -----------------------------------------------------------------------------
@@ -1041,15 +1092,15 @@ namespace netlist
param_rom_t(device_t &device, const pstring &name);
- const ST & operator[] (std::size_t n) NL_NOEXCEPT { return m_data[n]; }
+ ST operator[] (std::size_t n) const NL_NOEXCEPT { return m_data[n]; }
protected:
- virtual void changed() override
+ void changed() override
{
- stream()->read(&m_data[0],1<<AW);
+ stream()->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
}
private:
- ST m_data[1 << AW];
+ std::array<ST, 1 << AW> m_data;
};
// -----------------------------------------------------------------------------
@@ -1062,68 +1113,67 @@ namespace netlist
public detail::netlist_ref
{
public:
- core_device_t(netlist_t &owner, const pstring &name);
+ core_device_t(netlist_state_t &owner, const pstring &name);
core_device_t(core_device_t &owner, const pstring &name);
- virtual ~core_device_t();
+ COPYASSIGNMOVE(core_device_t, delete)
- void update_dev() NL_NOEXCEPT
- {
- do_update();
- }
+ virtual ~core_device_t() noexcept = default;
void do_inc_active() NL_NOEXCEPT
{
if (m_hint_deactivate)
{
- m_stat_inc_active.inc();
- inc_active();
+ if (++m_active_outputs == 1)
+ {
+ m_stat_inc_active.inc();
+ inc_active();
+ }
}
}
void do_dec_active() NL_NOEXCEPT
{
if (m_hint_deactivate)
- dec_active();
+ if (--m_active_outputs == 0)
+ {
+ dec_active();
+ }
}
- void do_reset() { reset(); }
void set_hint_deactivate(bool v) { m_hint_deactivate = v; }
bool get_hint_deactivate() { return m_hint_deactivate; }
+ /* Has to be set in device reset */
+ void set_active_outputs(int n) { m_active_outputs = n; }
void set_default_delegate(detail::core_terminal_t &term);
/* stats */
- nperftime_t m_stat_total_time;
- nperfcount_t m_stat_call_count;
- nperfcount_t m_stat_inc_active;
+ nperftime_t<NL_KEEP_STATISTICS> m_stat_total_time;
+ nperfcount_t<NL_KEEP_STATISTICS> m_stat_call_count;
+ nperfcount_t<NL_KEEP_STATISTICS> m_stat_inc_active;
+ virtual void update() NL_NOEXCEPT { }
+ virtual void reset() { }
protected:
- virtual void update() NL_NOEXCEPT { }
virtual void inc_active() NL_NOEXCEPT { }
virtual void dec_active() NL_NOEXCEPT { }
- virtual void reset() { }
- void do_update() NL_NOEXCEPT
- {
- update();
- }
-
- plib::plog_base<netlist_t, NL_DEBUG> &log();
+ log_type & log();
public:
- virtual void timestep(ATTR_UNUSED const nl_double st) { }
+ virtual void timestep(const nl_double st) { plib::unused_var(st); }
virtual void update_terminals() { }
virtual void update_param() {}
virtual bool is_dynamic() const { return false; }
virtual bool is_timestep() const { return false; }
- virtual bool needs_update_after_param_change() const { return false; }
private:
- bool m_hint_deactivate;
+ bool m_hint_deactivate;
+ state_var_s32 m_active_outputs;
};
// -----------------------------------------------------------------------------
@@ -1134,17 +1184,20 @@ namespace netlist
{
public:
- device_t(netlist_t &owner, const pstring &name);
+ device_t(netlist_state_t &owner, const pstring &name);
device_t(core_device_t &owner, const pstring &name);
- virtual ~device_t() override;
+ COPYASSIGNMOVE(device_t, delete)
+
+ ~device_t() noexcept override = default;
setup_t &setup();
+ const setup_t &setup() const;
template<class C, typename... Args>
- void register_sub(const pstring &name, std::unique_ptr<C> &dev, const Args&... args)
+ void create_and_register_subdevice(const pstring &name, pool_owned_ptr<C> &dev, Args&&... args)
{
- dev.reset(plib::palloc<C>(*this, name, args...));
+ dev = pool().make_poolptr<C>(*this, name, std::forward<Args>(args)...);
}
void register_subalias(const pstring &name, detail::core_terminal_t &term);
@@ -1167,13 +1220,18 @@ namespace netlist
struct detail::family_setter_t
{
- family_setter_t() { }
+ /* clang will complain about an unused private field if
+ * a defaulted constructor is used
+ */
+ // NOLINTNEXTLINE(modernize-use-equals-default)
+ family_setter_t();
family_setter_t(core_device_t &dev, const pstring &desc);
family_setter_t(core_device_t &dev, const logic_family_desc_t *desc);
};
// -----------------------------------------------------------------------------
// nld_base_dummy : basis for dummy devices
+ // FIXME: this is not the right place to define this
// -----------------------------------------------------------------------------
NETLIB_OBJECT(base_dummy)
@@ -1190,19 +1248,25 @@ namespace netlist
* solvers will update inputs after parallel processing.
*/
class detail::queue_t :
- public timed_queue<pqentry_t<net_t *, netlist_time>, false>,
+ public timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>,
public detail::netlist_ref,
public plib::state_manager_t::callback_t
{
public:
- typedef pqentry_t<net_t *, netlist_time> entry_t;
- explicit queue_t(netlist_t &nl);
+ using entry_t = pqentry_t<net_t *, netlist_time>;
+ explicit queue_t(netlist_state_t &nl);
+ virtual ~queue_t() noexcept = default;
+
+ queue_t(const queue_t &) = delete;
+ queue_t(queue_t &&) = delete;
+ queue_t &operator=(const queue_t &) = delete;
+ queue_t &operator=(queue_t &&) = delete;
protected:
void register_state(plib::state_manager_t &manager, const pstring &module) override;
- void on_pre_save() override;
- void on_post_load() override;
+ void on_pre_save(plib::state_manager_t &manager) override;
+ void on_post_load(plib::state_manager_t &manager) override;
private:
std::size_t m_qsize;
@@ -1211,139 +1275,214 @@ namespace netlist
};
// -----------------------------------------------------------------------------
- // netlist_t
+ // netlist_state__t
// -----------------------------------------------------------------------------
-
- class netlist_t : private plib::nocopyassignmove
+ class netlist_state_t
{
public:
- explicit netlist_t(const pstring &aname);
- virtual ~netlist_t();
+ using nets_collection_type = std::vector<pool_owned_ptr<detail::net_t>>;
- /* run functions */
+ /* need to preserve order of device creation ... */
+ using devices_collection_type = std::vector<std::pair<pstring, pool_owned_ptr<core_device_t>>>;
+ netlist_state_t(const pstring &aname,
+ netlist_t & anetlist,
+ plib::unique_ptr<callbacks_t> &&callbacks);
- const netlist_time &time() const NL_NOEXCEPT { return m_time; }
- devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; }
+ COPYASSIGNMOVE(netlist_state_t, delete)
- /* never use this in constructors! */
- nl_double gmin() const NL_NOEXCEPT;
+ ~netlist_state_t() noexcept = default;
- void process_queue(const netlist_time &delta) NL_NOEXCEPT;
- void abort_current_queue_slice() NL_NOEXCEPT { m_queue.retime(detail::queue_t::entry_t(m_time, nullptr)); }
+ friend class netlist_t; // allow access to private members
- /* Control functions */
+ template<class C>
+ static bool check_class(core_device_t *p)
+ {
+ return dynamic_cast<C *>(p) != nullptr;
+ }
- void start();
- void stop();
- void reset();
+ template<class C>
+ C *get_single_device(const pstring &classname) const
+ {
+ return dynamic_cast<C *>(get_single_device(classname, check_class<C>));
+ }
- const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; }
- detail::queue_t &queue() NL_NOEXCEPT { return m_queue; }
+ /* logging and name */
- /* netlist build functions */
+ pstring name() const { return m_name; }
- setup_t &setup() NL_NOEXCEPT { return *m_setup; }
+ log_type & log() { return m_log; }
+ const log_type &log() const { return m_log; }
+
+ plib::dynlib &lib() { return *m_lib; }
+
+ netlist_t &exec() { return m_netlist; }
+ const netlist_t &exec() const { return m_netlist; }
- void register_dev(plib::owned_ptr<core_device_t> dev);
- void remove_dev(core_device_t *dev);
+ /* state handling */
+ plib::state_manager_t &run_state_manager() { return m_state; }
+
+ template<typename O, typename C>
+ void save(O &owner, C &state, const pstring &module, const pstring &stname)
+ {
+ this->run_state_manager().save_item(static_cast<void *>(&owner), state, module + pstring(".") + stname);
+ }
+ template<typename O, typename C>
+ void save(O &owner, C *state, const pstring &module, const pstring &stname, const std::size_t count)
+ {
+ this->run_state_manager().save_state_ptr(static_cast<void *>(&owner), module + pstring(".") + stname, plib::state_manager_t::dtype<C>(), count, state);
+ }
+
+ core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const;
detail::net_t *find_net(const pstring &name) const;
std::size_t find_net_id(const detail::net_t *net) const;
+ template <typename T>
+ void register_net(pool_owned_ptr<T> &&net) { m_nets.push_back(std::move(net)); }
+
template<class device_class>
- std::vector<device_class *> get_device_list() const
+ inline std::vector<device_class *> get_device_list()
{
std::vector<device_class *> tmp;
for (auto &d : m_devices)
{
- device_class *dev = dynamic_cast<device_class *>(d.get());
+ auto dev = dynamic_cast<device_class *>(d.second.get());
if (dev != nullptr)
tmp.push_back(dev);
}
return tmp;
}
- template<class C>
- static bool check_class(core_device_t *p)
+ template <typename T>
+ void add_dev(const pstring &name, pool_owned_ptr<T> &&dev)
{
- return dynamic_cast<C *>(p) != nullptr;
+ for (auto & d : m_devices)
+ if (d.first == name)
+ log().fatal(MF_1_DUPLICATE_NAME_DEVICE_LIST, d.first);
+ //m_devices.push_back(std::move(dev));
+ m_devices.insert(m_devices.end(), { name, std::move(dev) });
}
- template<class C>
- C *get_single_device(const pstring &classname) const
+ /**
+ * @brief Remove device
+ *
+ * Care needs to be applied if this is called to remove devices with
+ * sub-devices which may have registered state.
+ *
+ * @param dev Device to be removed
+ */
+ void remove_dev(core_device_t *dev)
{
- return dynamic_cast<C *>(get_single_device(classname, check_class<C>));
+ for (auto it = m_devices.begin(); it != m_devices.end(); it++)
+ if (it->second.get() == dev)
+ {
+ m_state.remove_save_items(dev);
+ m_devices.erase(it);
+ return;
+ }
}
- /* logging and name */
+ /* sole use is to manage lifetime of family objects */
+ std::vector<std::pair<pstring, plib::unique_ptr<logic_family_desc_t>>> m_family_cache;
- pstring name() const { return m_name; }
- plib::plog_base<netlist_t, NL_DEBUG> &log() { return m_log; }
- const plib::plog_base<netlist_t, NL_DEBUG> &log() const { return m_log; }
+ setup_t &setup() NL_NOEXCEPT { return *m_setup; }
+ const setup_t &setup() const NL_NOEXCEPT { return *m_setup; }
- /* state related */
+ nets_collection_type & nets() { return m_nets; }
+ devices_collection_type & devices() { return m_devices; }
- plib::state_manager_t &state() { return m_state; }
+ // FIXME: make a postload member and include code there
+ void rebuild_lists(); /* must be called after post_load ! */
- template<typename O, typename C> void save(O &owner, C &state, const pstring &stname)
- {
- this->state().save_item(static_cast<void *>(&owner), state, from_utf8(owner.name()) + pstring(".") + stname);
- }
- template<typename O, typename C> void save(O &owner, C *state, const pstring &stname, const std::size_t count)
- {
- this->state().save_state_ptr(static_cast<void *>(&owner), from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f<C>::f(), count, state);
- }
+ private:
- plib::dynlib &lib() { return *m_lib; }
+ void reset();
- // FIXME: find something better
+ pstring m_name;
+ netlist_t &m_netlist;
+ plib::unique_ptr<plib::dynlib> m_lib; // external lib needs to be loaded as long as netlist exists
+ plib::state_manager_t m_state;
+ plib::unique_ptr<callbacks_t> m_callbacks;
+ log_type m_log;
+ plib::unique_ptr<setup_t> m_setup;
+
+ nets_collection_type m_nets;
/* sole use is to manage lifetime of net objects */
- std::vector<plib::owned_ptr<detail::net_t>> m_nets;
- /* sole use is to manage lifetime of family objects */
- std::vector<std::pair<pstring, std::unique_ptr<logic_family_desc_t>>> m_family_cache;
+ devices_collection_type m_devices;
- // FIXME: sort rebuild_lists out
- void rebuild_lists(); /* must be called after post_load ! */
- /* logging callback */
- virtual void vlog(const plib::plog_level &l, const pstring &ls) const = 0;
- protected:
+ };
- void print_stats() const;
+ // -----------------------------------------------------------------------------
+ // netlist_t
+ // -----------------------------------------------------------------------------
- private:
+ class netlist_t
+ {
+ public:
- /* helper for save above */
- static pstring from_utf8(const char *c) { return pstring(c, pstring::UTF8); }
- static pstring from_utf8(const pstring &c) { return c; }
+ explicit netlist_t(const pstring &aname, plib::unique_ptr<callbacks_t> callbacks);
- core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const;
+ COPYASSIGNMOVE(netlist_t, delete)
- /* mostly rw */
- netlist_time m_time;
- detail::queue_t m_queue;
+ ~netlist_t() noexcept = default;
- /* mostly ro */
+ /* run functions */
- devices::NETLIB_NAME(mainclock) * m_mainclock;
- devices::NETLIB_NAME(solver) * m_solver;
- devices::NETLIB_NAME(netlistparams) *m_params;
+ netlist_time time() const NL_NOEXCEPT { return m_time; }
- pstring m_name;
- std::unique_ptr<setup_t> m_setup;
- plib::plog_base<netlist_t, NL_DEBUG> m_log;
- std::unique_ptr<plib::dynlib> m_lib; // external lib needs to be loaded as long as netlist exists
+ void process_queue(const netlist_time delta) NL_NOEXCEPT;
+ void abort_current_queue_slice() NL_NOEXCEPT { m_queue.retime(detail::queue_t::entry_t(m_time, nullptr)); }
- plib::state_manager_t m_state;
+ const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; }
+ detail::queue_t &queue() NL_NOEXCEPT { return m_queue; }
- // performance
- nperftime_t m_stat_mainloop;
- nperfcount_t m_perf_out_processed;
+ /* Control functions */
+
+ void stop();
+ void reset();
+
+ /* state handling */
+
+ plib::state_manager_t &run_state_manager() { return m_state->run_state_manager(); }
+
+ /* only used by nltool to create static c-code */
+ devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; }
+
+ /* force late type resolution */
+ template <typename X = devices::NETLIB_NAME(solver)>
+ nl_double gmin(X *solv = nullptr) const NL_NOEXCEPT
+ {
+ plib::unused_var(solv);
+ return static_cast<X *>(m_solver)->gmin();
+ }
+
+ netlist_state_t &nlstate() NL_NOEXCEPT { return *m_state; }
+ const netlist_state_t &nlstate() const { return *m_state; }
+
+ log_type & log() { return m_state->log(); }
+ const log_type &log() const { return m_state->log(); }
+
+ void print_stats() const;
+
+ private:
+ plib::unique_ptr<netlist_state_t> m_state;
+ devices::NETLIB_NAME(solver) * m_solver;
+
+ /* mostly rw */
+ PALIGNAS_CACHELINE()
+ netlist_time m_time;
+ devices::NETLIB_NAME(mainclock) * m_mainclock;
- std::vector<plib::owned_ptr<core_device_t>> m_devices;
+ PALIGNAS_CACHELINE()
+ detail::queue_t m_queue;
+
+ // performance
+ nperftime_t<NL_KEEP_STATISTICS> m_stat_mainloop;
+ nperfcount_t<NL_KEEP_STATISTICS> m_perf_out_processed;
};
// -----------------------------------------------------------------------------
@@ -1356,12 +1495,13 @@ namespace netlist
public:
struct init
{
- const char *p[N];
+ std::array<const char *, N> p;
};
- object_array_t(core_device_t &dev, init names)
+ template<typename... Args>
+ object_array_t(core_device_t &dev, init names, Args&&... args)
{
for (std::size_t i = 0; i<N; i++)
- this->emplace(i, dev, pstring(names.p[i], pstring::UTF8));
+ this->emplace(i, dev, pstring(names.p[i]), std::forward<Args>(args)...);
}
};
@@ -1369,15 +1509,56 @@ namespace netlist
// inline implementations
// -----------------------------------------------------------------------------
+ inline netlist_state_t & detail::netlist_ref::state() noexcept
+ {
+ return m_netlist.nlstate();
+ }
+
+ inline const netlist_state_t & detail::netlist_ref::state() const noexcept
+ {
+ return m_netlist.nlstate();
+ }
+
+ inline setup_t & detail::netlist_ref::setup() noexcept
+ {
+ return m_netlist.nlstate().setup();
+ }
+
+ inline const setup_t & detail::netlist_ref::setup() const noexcept
+ {
+ return m_netlist.nlstate().setup();
+ }
+
+ template <typename T>
+ param_num_t<T>::param_num_t(device_t &device, const pstring &name, const T val)
+ : param_t(device, name)
+ {
+ //m_param = device.setup().get_initial_param_val(this->name(),val);
+ bool found = false;
+ pstring p = this->get_initial(device, &found);
+ if (found)
+ {
+ bool err = false;
+ auto vald = plib::pstonum_ne<T>(p, err);
+ if (err)
+ device.state().log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, p);
+ m_param = vald;
+ }
+ else
+ m_param = val;
+
+ device.state().save(*this, m_param, this->name(), "m_param");
+ }
+
template <typename ST, std::size_t AW, std::size_t DW>
- inline param_rom_t<ST, AW, DW>::param_rom_t(device_t &device, const pstring &name)
+ param_rom_t<ST, AW, DW>::param_rom_t(device_t &device, const pstring &name)
: param_data_t(device, name)
{
auto f = stream();
if (f != nullptr)
- f->read(&m_data[0],1<<AW);
+ f->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
else
- device.netlist().log().warning("Rom {1} not found", Value());
+ device.state().log().warning("Rom {1} not found", value());
}
inline void logic_input_t::inactivate() NL_NOEXCEPT
@@ -1385,7 +1566,7 @@ namespace netlist
if (!is_state(STATE_INP_PASSIVE))
{
set_state(STATE_INP_PASSIVE);
- net().dec_active(*this);
+ net().remove_from_active_list(*this);
}
}
@@ -1393,7 +1574,7 @@ namespace netlist
{
if (is_state(STATE_INP_PASSIVE))
{
- net().inc_active(*this);
+ net().add_to_active_list(*this);
set_state(STATE_INP_ACTIVE);
}
}
@@ -1402,7 +1583,7 @@ namespace netlist
{
if (is_state(STATE_INP_PASSIVE))
{
- net().inc_active(*this);
+ net().add_to_active_list(*this);
set_state(STATE_INP_HL);
}
}
@@ -1411,24 +1592,68 @@ namespace netlist
{
if (is_state(STATE_INP_PASSIVE))
{
- net().inc_active(*this);
+ net().add_to_active_list(*this);
set_state(STATE_INP_LH);
}
}
- inline void detail::net_t::push_to_queue(const netlist_time &delay) NL_NOEXCEPT
+ inline void detail::net_t::push_to_queue(const netlist_time delay) NL_NOEXCEPT
{
if ((num_cons() != 0))
{
+ auto &lexec(exec());
+ auto &q(lexec.queue());
+ auto nst(lexec.time() + delay);
+
if (is_queued())
- netlist().queue().remove(this);
- m_time = netlist().time() + delay;
- m_in_queue = (m_active > 0) ? QS_QUEUED : QS_DELAYED_DUE_TO_INACTIVE; /* queued ? */
- if (m_in_queue == QS_QUEUED)
- netlist().queue().push(queue_t::entry_t(m_time, this));
+ q.remove(this);
+ m_in_queue = (!m_list_active.empty()) ?
+ queue_status::QUEUED : queue_status::DELAYED_DUE_TO_INACTIVE; /* queued ? */
+ if (m_in_queue == queue_status::QUEUED)
+ q.push(queue_t::entry_t(nst, this));
+ else
+ update_inputs();
+ m_next_scheduled_time = nst;
+ }
+ }
+
+ inline void detail::net_t::add_to_active_list(core_terminal_t &term) NL_NOEXCEPT
+ {
+ if (m_list_active.empty())
+ {
+ m_list_active.push_front(&term);
+ railterminal().device().do_inc_active();
+ if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
+ {
+ if (m_next_scheduled_time > exec().time())
+ {
+ m_in_queue = queue_status::QUEUED; /* pending */
+ exec().queue().push({m_next_scheduled_time, this});
+ }
+ else
+ {
+ m_in_queue = queue_status::DELIVERED;
+ m_cur_Q = m_new_Q;
+ }
+ update_inputs();
+ }
+ else
+ term.set_copied_input(m_cur_Q);
+ }
+ else
+ {
+ term.set_copied_input(m_cur_Q);
+ m_list_active.push_front(&term);
}
}
+ inline void detail::net_t::remove_from_active_list(core_terminal_t &term) NL_NOEXCEPT
+ {
+ m_list_active.remove(&term);
+ if (m_list_active.empty())
+ railterminal().device().do_dec_active();
+ }
+
inline const analog_net_t & analog_t::net() const NL_NOEXCEPT
{
return static_cast<const analog_net_t &>(core_terminal_t::net());
@@ -1441,6 +1666,18 @@ namespace netlist
inline nl_double terminal_t::operator ()() const NL_NOEXCEPT { return net().Q_Analog(); }
+ inline void terminal_t::set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) noexcept
+ {
+ if (!(gt && go && Idr) && (gt || go || Idr))
+ state().log().fatal("Inconsistent nullptrs for terminal {}", name());
+ else
+ {
+ m_gt1 = gt;
+ m_go1 = go;
+ m_Idr1 = Idr;
+ }
+ }
+
inline logic_net_t & logic_t::net() NL_NOEXCEPT
{
return static_cast<logic_net_t &>(core_terminal_t::net());
@@ -1453,8 +1690,14 @@ namespace netlist
inline netlist_sig_t logic_input_t::Q() const NL_NOEXCEPT
{
- nl_assert(state() != STATE_INP_PASSIVE);
+ nl_assert(terminal_state() != STATE_INP_PASSIVE);
+ //if (net().Q() != m_Q)
+ // printf("term: %s, %d %d TS %d\n", this->name().c_str(), net().Q(), m_Q, terminal_state());
+#if USE_COPY_INSTEAD_OF_REFERENCE
+ return m_Q;
+#else
return net().Q();
+#endif
}
inline nl_double analog_input_t::Q_Analog() const NL_NOEXCEPT
@@ -1471,14 +1714,24 @@ namespace netlist
}
}
- inline netlist_t &detail::device_object_t::netlist() NL_NOEXCEPT
+ inline netlist_state_t &detail::device_object_t::state() NL_NOEXCEPT
+ {
+ return m_device.state();
+ }
+
+ inline const netlist_state_t &detail::device_object_t::state() const NL_NOEXCEPT
+ {
+ return m_device.state();
+ }
+
+ inline netlist_t &detail::device_object_t::exec() NL_NOEXCEPT
{
- return m_device.netlist();
+ return m_device.exec();
}
- inline const netlist_t &detail::device_object_t::netlist() const NL_NOEXCEPT
+ inline const netlist_t &detail::device_object_t::exec() const NL_NOEXCEPT
{
- return m_device.netlist();
+ return m_device.exec();
}
template <typename T>
@@ -1486,18 +1739,18 @@ namespace netlist
state_var<T>::state_var(O &owner, const pstring &name, const T &value)
: m_value(value)
{
- owner.netlist().save(owner, m_value, name);
+ owner.state().save(owner, m_value, owner.name(), name);
}
template <typename T, std::size_t N>
template <typename O>
- state_var<T[N]>::state_var(O &owner, const pstring &name, const T & value)
+ state_array<T,N>::state_array(O &owner, const pstring &name, const T & value)
{
- owner.netlist().save(owner, m_value, name);
+ owner.state().save(owner, m_value, owner.name(), name);
for (std::size_t i=0; i<N; i++)
m_value[i] = value;
}
-}
+} // namespace netlist
namespace plib
{
@@ -1505,7 +1758,7 @@ namespace plib
struct ptype_traits<netlist::state_var<X>> : ptype_traits<X>
{
};
-}
+} // namespace plib
diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h
index 6a65abac40a..faa5008ff56 100644
--- a/src/lib/netlist/nl_config.h
+++ b/src/lib/netlist/nl_config.h
@@ -26,10 +26,21 @@
* linear memory pool. This is based of the assumption that
* due to enhanced locality there will be less cache misses.
* Your mileage may vary.
- * This will cause crashes on OSX and thus is ignored on OSX.
*
*/
-#define USE_MEMPOOL (0)
+#define USE_MEMPOOL (1)
+
+/*! Store input values in logic_terminal_t.
+ *
+ * Set to 1 to store values in logic_terminal_t instead of
+ * accessing them indirectly by pointer from logic_net_t.
+ * This approach is stricter and should identify bugs in
+ * the netlist core faster.
+ * By default it is disabled since it is not as fast as
+ * the default approach. It is up to 5% slower.
+ *
+ */
+#define USE_COPY_INSTEAD_OF_REFERENCE (0)
/*
* FIXME: Using truthtable is a lot slower than the explicit device
@@ -43,23 +54,13 @@
#define NL_MAX_LINK_RESOLVE_LOOPS (100)
//============================================================
-// Solver defines
-//============================================================
-
-#define USE_GABS (1)
-// savings are eaten up by effort
-// FIXME: Convert into solver parameter
-#define USE_LINEAR_PREDICTION (0)
-#define NETLIST_GMIN_DEFAULT (1e-9)
-
-
-
-//============================================================
// DEBUGGING
//============================================================
#define NL_DEBUG (false)
#define NL_KEEP_STATISTICS (0)
+//#define NL_DEBUG (true)
+//#define NL_KEEP_STATISTICS (1)
//============================================================
// General Macros
@@ -86,24 +87,19 @@
#endif // !defined(USE_OPENMP)
// Use nano-second resolution - Sufficient for now
-#define NETLIST_INTERNAL_RES (UINT64_C(1000000000))
-#define NETLIST_CLOCK (NETLIST_INTERNAL_RES)
+
+static constexpr const auto NETLIST_INTERNAL_RES = 1000000000;
+static constexpr const auto NETLIST_CLOCK = NETLIST_INTERNAL_RES;
+
+//#define NETLIST_INTERNAL_RES (UINT64_C(1000000000))
+//#define NETLIST_CLOCK (NETLIST_INTERNAL_RES)
//#define NETLIST_INTERNAL_RES (UINT64_C(1000000000000))
//#define NETLIST_CLOCK (UINT64_C(1000000000))
//#define nl_double float
-//#define NL_FCONST(x) (x ## f)
-
-//#define nl_double double
-#define NL_FCONST(x) x
using nl_double = double;
-/* The following option determines how object::update is called.
- * If set to 1, a virtual call is used. If it is left undefined, the best
- * approach will be automatically selected.
- */
-
//============================================================
// WARNINGS
//============================================================
diff --git a/src/lib/netlist/nl_dice_compat.h b/src/lib/netlist/nl_dice_compat.h
index b0ebdb2e371..48695e393ec 100644
--- a/src/lib/netlist/nl_dice_compat.h
+++ b/src/lib/netlist/nl_dice_compat.h
@@ -29,6 +29,7 @@ sed -e 's/#define \(.*\)"\(.*\)"[ \t]*,[ \t]*\(.*\)/NET_ALIAS(\1,\2.\3)/' src/ma
#include "analog/nld_twoterm.h"
#include <cmath>
+
#endif
@@ -111,8 +112,8 @@ public:
#define CHIP(n, t) TTL_ ## t ## _DIP(n)
#define OHM(x) x
-#define K_OHM(x) RES_K(X)
-#define M_OHM(x) RES_M(X)
+#define K_OHM(x) RES_K(x)
+#define M_OHM(x) RES_M(x)
#define U_FARAD(x) CAP_U(x)
#define N_FARAD(x) CAP_N(x)
#define P_FARAD(x) CAP_P(x)
@@ -131,9 +132,9 @@ public:
NET_C(name.6, name ## _R.1) \
NET_C(name.6, name ## _C.1) \
NET_C(name ## _R.2, V5) \
- NET_CSTR(# name "_C.2", "GND") \
+ NET_C(name ## _C.2, GND) \
NET_C(name.8, V5) \
- NET_CSTR(# name ".1", "GND")
+ NET_C(name.1, GND)
#define CHIP_555_Astable(name, pdesc) \
NE555_DIP(name) \
@@ -146,9 +147,9 @@ public:
NET_C(name.6, name ## _C.1) \
NET_C(name.2, name ## _C.1) \
NET_C(name ## _R1.2, V5) \
- NET_CSTR(# name "_C.2", "GND") \
+ NET_C(name ## _C.2, GND) \
NET_C(name.8, V5) \
- NET_CSTR(# name ".1", "GND")
+ NET_C(name.1, GND)
#define CHIP_9602_Mono(name, pdesc) \
CHIP(# name, 9602) \
@@ -178,13 +179,13 @@ public:
#define CHIP_INPUT_ACTIVE_LOW(name) \
SWITCH2(name ## _SW) \
NET_C(name ## _SW.1, V5) \
- NET_CSTR(# name "_SW.2", "GND") \
+ NET_C(name ## _SW.2, GND) \
ALIAS(name.1, name ## _SW.Q)
#define CHIP_INPUT_ACTIVE_HIGH(name) \
SWITCH2(name ## _SW) \
NET_C(name ## _SW.2, V5) \
- NET_CSTR(# name "_SW.1", "GND") \
+ NET_C(name ## _SW.1, GND) \
ALIAS(name.1, name ## _SW.Q)
#define CHIP_LATCH(name) \
diff --git a/src/lib/netlist/nl_errstr.h b/src/lib/netlist/nl_errstr.h
index 35b1e4f6c60..ee3c47f3339 100644
--- a/src/lib/netlist/nl_errstr.h
+++ b/src/lib/netlist/nl_errstr.h
@@ -58,7 +58,8 @@
//#define MF_1_CLASS_1_NOT_FOUND "Class {1} not found!"
#define MF_1_UNABLE_TO_PARSE_MODEL_1 "Unable to parse model: {1}"
#define MF_1_MODEL_ALREADY_EXISTS_1 "Model already exists: {1}"
-#define MF_1_ADDING_ALI1_TO_ALIAS_LIST "Error adding alias {1} to alias list"
+#define MF_1_DEVICE_ALREADY_EXISTS_1 "Device already exists: {1}"
+#define MF_1_ADDING_ALI1_TO_ALIAS_LIST "Error adding alias {1} to alias list"
#define MF_1_DIP_PINS_MUST_BE_AN_EQUAL_NUMBER_OF_PINS_1 "You must pass an equal number of pins to DIPPINS {1}"
#define MF_1_UNKNOWN_OBJECT_TYPE_1 "Unknown object type {1}"
#define MF_2_INVALID_NUMBER_CONVERSION_1_2 "Invalid number conversion {1} : {2}"
diff --git a/src/lib/netlist/nl_factory.cpp b/src/lib/netlist/nl_factory.cpp
index 2bb49590c4b..1f0ac35c6c4 100644
--- a/src/lib/netlist/nl_factory.cpp
+++ b/src/lib/netlist/nl_factory.cpp
@@ -10,102 +10,84 @@
#include "nl_factory.h"
#include "nl_base.h"
+#include "nl_errstr.h"
#include "nl_setup.h"
#include "plib/putil.h"
-#include "nl_errstr.h"
namespace netlist { namespace factory
{
-class NETLIB_NAME(wrapper) : public device_t
-{
-public:
- NETLIB_NAME(wrapper)(netlist_t &anetlist, const pstring &name)
- : device_t(anetlist, name)
+ class NETLIB_NAME(wrapper) : public device_t
+ {
+ public:
+ NETLIB_NAME(wrapper)(netlist_state_t &anetlist, const pstring &name)
+ : device_t(anetlist, name)
+ {
+ }
+ protected:
+ NETLIB_RESETI() { }
+ NETLIB_UPDATEI() { }
+ };
+
+ element_t::element_t(const pstring &name, const pstring &classname,
+ const pstring &def_param, const pstring &sourcefile)
+ : m_name(name), m_classname(classname), m_def_param(def_param),
+ m_sourcefile(sourcefile)
{
}
-protected:
- NETLIB_RESETI();
- NETLIB_UPDATEI();
-};
-
+ element_t::element_t(const pstring &name, const pstring &classname,
+ const pstring &def_param)
+ : m_name(name), m_classname(classname), m_def_param(def_param),
+ m_sourcefile("<unknown>")
+ {
+ }
-element_t::element_t(const pstring &name, const pstring &classname,
- const pstring &def_param, const pstring &sourcefile)
- : m_name(name), m_classname(classname), m_def_param(def_param),
- m_sourcefile(sourcefile)
-{
-}
-
-element_t::element_t(const pstring &name, const pstring &classname,
- const pstring &def_param)
- : m_name(name), m_classname(classname), m_def_param(def_param),
- m_sourcefile("<unknown>")
-{
-}
-
-element_t::~element_t()
-{
-}
-
-// ----------------------------------------------------------------------------------------
-// net_device_t_base_factory
-// ----------------------------------------------------------------------------------------
-
-list_t::list_t( setup_t &setup)
-: m_setup(setup)
-{
-}
-
-list_t::~list_t()
-{
- clear();
-}
-
-void list_t::register_device(std::unique_ptr<element_t> &&factory)
-{
- for (auto & e : *this)
- if (e->name() == factory->name())
- m_setup.log().fatal(MF_1_FACTORY_ALREADY_CONTAINS_1, factory->name());
- push_back(std::move(factory));
-}
+ // ----------------------------------------------------------------------------------------
+ // net_device_t_base_factory
+ // ----------------------------------------------------------------------------------------
-factory::element_t * list_t::factory_by_name(const pstring &devname)
-{
- for (auto & e : *this)
+ list_t::list_t(log_type &alog)
+ : m_log(alog)
{
- if (e->name() == devname)
- return e.get();
}
- m_setup.log().fatal(MF_1_CLASS_1_NOT_FOUND, devname);
- return nullptr; // appease code analysis
-}
-
-// -----------------------------------------------------------------------------
-// factory_lib_entry_t: factory class to wrap macro based chips/elements
-// -----------------------------------------------------------------------------
+ void list_t::register_device(plib::unique_ptr<element_t> &&factory)
+ {
+ for (auto & e : *this)
+ if (e->name() == factory->name())
+ m_log.fatal(MF_1_FACTORY_ALREADY_CONTAINS_1, factory->name());
+ push_back(std::move(factory));
+ }
-plib::owned_ptr<device_t> library_element_t::Create(netlist_t &anetlist, const pstring &name)
-{
- return plib::owned_ptr<device_t>::Create<NETLIB_NAME(wrapper)>(anetlist, name);
-}
+ factory::element_t * list_t::factory_by_name(const pstring &devname)
+ {
+ for (auto & e : *this)
+ {
+ if (e->name() == devname)
+ return e.get();
+ }
+
+ m_log.fatal(MF_1_CLASS_1_NOT_FOUND, devname);
+ return nullptr; // appease code analysis
+ }
-void library_element_t::macro_actions(netlist_t &anetlist, const pstring &name)
-{
- anetlist.setup().namespace_push(name);
- anetlist.setup().include(this->name());
- anetlist.setup().namespace_pop();
-}
+ // -----------------------------------------------------------------------------
+ // factory_lib_entry_t: factory class to wrap macro based chips/elements
+ // -----------------------------------------------------------------------------
-NETLIB_RESET(wrapper)
-{
-}
+ pool_owned_ptr<device_t> library_element_t::Create(netlist_state_t &anetlist, const pstring &name)
+ {
+ return pool().make_poolptr<NETLIB_NAME(wrapper)>(anetlist, name);
+ }
-NETLIB_UPDATE(wrapper)
-{
-}
+ void library_element_t::macro_actions(nlparse_t &nparser, const pstring &name)
+ {
+ nparser.namespace_push(name);
+ nparser.include(this->name());
+ nparser.namespace_pop();
+ }
-} }
+} // namespace factory
+ } // namespace netlist
diff --git a/src/lib/netlist/nl_factory.h b/src/lib/netlist/nl_factory.h
index 6dad6c5e171..271bf72bf90 100644
--- a/src/lib/netlist/nl_factory.h
+++ b/src/lib/netlist/nl_factory.h
@@ -9,46 +9,58 @@
#ifndef NLFACTORY_H_
#define NLFACTORY_H_
+#include "nltypes.h"
#include "plib/palloc.h"
#include "plib/ptypes.h"
-#define NETLIB_DEVICE_IMPL(chip) \
- static std::unique_ptr<factory::element_t> NETLIB_NAME(chip ## _c)( \
- const pstring &name, const pstring &classname, const pstring &def_param) \
- { \
- return std::unique_ptr<factory::element_t>(plib::palloc<factory::device_element_t<NETLIB_NAME(chip)>>(name, classname, def_param, pstring(__FILE__))); \
- } \
- factory::constructor_ptr_t decl_ ## chip = NETLIB_NAME(chip ## _c);
+#include <vector>
+
+#define NETLIB_DEVICE_IMPL_ALIAS(p_alias, chip, p_name, p_def_param) \
+ NETLIB_DEVICE_IMPL_BASE(devices, p_alias, chip, p_name, p_def_param) \
+
+#define NETLIB_DEVICE_IMPL(chip, p_name, p_def_param) \
+ NETLIB_DEVICE_IMPL_NS(devices, chip, p_name, p_def_param)
-#define NETLIB_DEVICE_IMPL_NS(ns, chip) \
- static std::unique_ptr<factory::element_t> NETLIB_NAME(chip ## _c)( \
- const pstring &name, const pstring &classname, const pstring &def_param) \
+#define NETLIB_DEVICE_IMPL_NS(ns, chip, p_name, p_def_param) \
+ NETLIB_DEVICE_IMPL_BASE(ns, chip, chip, p_name, p_def_param) \
+
+#define NETLIB_DEVICE_IMPL_BASE(ns, p_alias, chip, p_name, p_def_param) \
+ static plib::unique_ptr<factory::element_t> NETLIB_NAME(p_alias ## _c) \
+ (const pstring &classname) \
{ \
- return std::unique_ptr<factory::element_t>(plib::palloc<factory::device_element_t<ns :: NETLIB_NAME(chip)>>(name, classname, def_param, pstring(__FILE__))); \
+ return plib::make_unique<factory::device_element_t<ns :: NETLIB_NAME(chip)>>(p_name, classname, p_def_param, pstring(__FILE__)); \
} \
- factory::constructor_ptr_t decl_ ## chip = NETLIB_NAME(chip ## _c);
+ \
+ factory::constructor_ptr_t decl_ ## p_alias = NETLIB_NAME(p_alias ## _c);
namespace netlist {
- class netlist_t;
class device_t;
+ class nlparse_t;
class setup_t;
+ class netlist_state_t;
namespace factory {
// -----------------------------------------------------------------------------
// net_dev class factory
// -----------------------------------------------------------------------------
- class element_t : plib::nocopyassignmove
+ class element_t
{
public:
element_t(const pstring &name, const pstring &classname,
const pstring &def_param);
element_t(const pstring &name, const pstring &classname,
const pstring &def_param, const pstring &sourcefile);
- virtual ~element_t();
+ virtual ~element_t() = default;
- virtual plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) = 0;
- virtual void macro_actions(netlist_t &anetlist, const pstring &name) {}
+ COPYASSIGNMOVE(element_t, default)
+
+ virtual pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) = 0;
+ virtual void macro_actions(nlparse_t &nparser, const pstring &name)
+ {
+ plib::unused_var(nparser);
+ plib::unused_var(name);
+ }
const pstring &name() const { return m_name; }
const pstring &classname() const { return m_classname; }
@@ -73,26 +85,28 @@ namespace factory {
const pstring &def_param, const pstring &sourcefile)
: element_t(name, classname, def_param, sourcefile) { }
- plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override
+ pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) override
{
- return plib::owned_ptr<device_t>::Create<C>(anetlist, name);
+ return pool().make_poolptr<C>(anetlist, name);
}
};
- class list_t : public std::vector<std::unique_ptr<element_t>>
+ class list_t : public std::vector<plib::unique_ptr<element_t>>
{
public:
- explicit list_t(setup_t &m_setup);
- ~list_t();
+ explicit list_t(log_type &alog);
+ ~list_t() = default;
+
+ COPYASSIGNMOVE(list_t, delete)
template<class device_class>
void register_device(const pstring &name, const pstring &classname,
const pstring &def_param)
{
- register_device(std::unique_ptr<element_t>(plib::palloc<device_element_t<device_class>>(name, classname, def_param)));
+ register_device(plib::make_unique<device_element_t<device_class>>(name, classname, def_param));
}
- void register_device(std::unique_ptr<element_t> &&factory);
+ void register_device(plib::unique_ptr<element_t> &&factory);
element_t * factory_by_name(const pstring &devname);
@@ -103,21 +117,20 @@ namespace factory {
}
private:
- setup_t &m_setup;
+ log_type &m_log;
};
// -----------------------------------------------------------------------------
// factory_creator_ptr_t
// -----------------------------------------------------------------------------
- using constructor_ptr_t = std::unique_ptr<element_t> (*)(const pstring &name, const pstring &classname,
- const pstring &def_param);
+ using constructor_ptr_t = plib::unique_ptr<element_t> (*)(const pstring &classname);
template <typename T>
- std::unique_ptr<element_t> constructor_t(const pstring &name, const pstring &classname,
+ plib::unique_ptr<element_t> constructor_t(const pstring &name, const pstring &classname,
const pstring &def_param)
{
- return std::unique_ptr<element_t>(plib::palloc<device_element_t<T>>(name, classname, def_param));
+ return plib::make_unique<device_element_t<T>>(name, classname, def_param);
}
// -----------------------------------------------------------------------------
@@ -128,22 +141,24 @@ namespace factory {
{
public:
- library_element_t(setup_t &setup, const pstring &name, const pstring &classname,
+ library_element_t(const pstring &name, const pstring &classname,
const pstring &def_param, const pstring &source)
- : element_t(name, classname, def_param, source) { }
+ : element_t(name, classname, def_param, source)
+ {
+ }
- plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override;
+ pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) override;
- void macro_actions(netlist_t &anetlist, const pstring &name) override;
+ void macro_actions(nlparse_t &nparser, const pstring &name) override;
private:
};
- }
+ } // namespace factory
namespace devices {
void initialize_factory(factory::list_t &factory);
- }
-}
+ } // namespace devices
+} // namespace netlist
#endif /* NLFACTORY_H_ */
diff --git a/src/lib/netlist/nl_lists.h b/src/lib/netlist/nl_lists.h
index 1eae38b25fb..325f8a67c72 100644
--- a/src/lib/netlist/nl_lists.h
+++ b/src/lib/netlist/nl_lists.h
@@ -10,32 +10,24 @@
#ifndef NLLISTS_H_
#define NLLISTS_H_
-#include "nl_config.h"
-#include "netlist_types.h"
-#include "plib/plists.h"
#include "plib/pchrono.h"
+#include "plib/plists.h"
#include "plib/ptypes.h"
+#include "nl_config.h"
+#include "nltypes.h"
+
+#include <algorithm>
#include <atomic>
-#include <thread>
#include <mutex>
-#include <algorithm>
+#include <thread>
#include <utility>
+
// ----------------------------------------------------------------------------------------
// timed queue
// ----------------------------------------------------------------------------------------
-/*
- * Use -DUSE_HEAP=1 to use stdc++ heap functions instead of linear processing.
- *
- * This slows down processing by about 25% on a Kaby Lake.
- */
-
-#ifndef USE_HEAP
-#define USE_HEAP (0)
-#endif
-
namespace netlist
{
//FIXME: move to an appropriate place
@@ -43,10 +35,11 @@ namespace netlist
class pspin_mutex
{
public:
- pspin_mutex() noexcept { }
+ pspin_mutex() noexcept = default;
void lock() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } }
void unlock() noexcept { m_lock.clear(std::memory_order_release); }
private:
+ PALIGNAS_CACHELINE()
std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
};
@@ -62,10 +55,11 @@ namespace netlist
struct pqentry_t final
{
constexpr pqentry_t() noexcept : m_exec_time(), m_object(nullptr) { }
- constexpr pqentry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { }
+ constexpr pqentry_t(const Time t, const Element o) noexcept : m_exec_time(t), m_object(o) { }
+#if 0
~pqentry_t() = default;
constexpr pqentry_t(const pqentry_t &e) noexcept = default;
- constexpr pqentry_t(pqentry_t &&e) = default;
+ constexpr pqentry_t(pqentry_t &&e) noexcept = default;
pqentry_t& operator=(pqentry_t && other) noexcept = default;
pqentry_t& operator=(const pqentry_t &other) noexcept = default;
@@ -74,91 +68,97 @@ namespace netlist
std::swap(m_exec_time, other.m_exec_time);
std::swap(m_object, other.m_object);
}
-
+#endif
struct QueueOp
{
- static constexpr bool less(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
+ inline static constexpr bool less(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
{
return (lhs.m_exec_time < rhs.m_exec_time);
}
- static constexpr bool equal(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
+ inline static constexpr bool lessequal(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
+ {
+ return (lhs.m_exec_time <= rhs.m_exec_time);
+ }
+
+ inline static constexpr bool equal(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
{
return lhs.m_object == rhs.m_object;
}
- static constexpr bool equal(const pqentry_t &lhs, const Element &rhs) noexcept
+ inline static constexpr bool equal(const pqentry_t &lhs, const Element &rhs) noexcept
{
return lhs.m_object == rhs;
}
- static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); }
+ inline static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); }
};
Time m_exec_time;
Element m_object;
};
-#if !USE_HEAP
/* Use TS = true for a threadsafe queue */
- template <class T, bool TS, class QueueOp = typename T::QueueOp>
- class timed_queue : plib::nocopyassignmove
+ template <class T, bool TS, bool KEEPSTAT, class QueueOp = typename T::QueueOp>
+ class timed_queue_linear : plib::nocopyassignmove
{
public:
- explicit timed_queue(const std::size_t list_size)
+ explicit timed_queue_linear(const std::size_t list_size)
: m_list(list_size)
{
clear();
}
- constexpr std::size_t capacity() const noexcept { return m_list.capacity() - 1; }
- constexpr bool empty() const noexcept { return (m_end == &m_list[1]); }
+ std::size_t capacity() const noexcept { return m_list.capacity() - 1; }
+ bool empty() const noexcept { return (m_end == &m_list[1]); }
- void push(T &&e) noexcept
+ void push(T && e) noexcept
{
/* Lock */
- tqlock lck(m_lock);
- T * i(m_end);
- for (; QueueOp::less(*(i - 1), e); --i)
+ lock_guard_type lck(m_lock);
+ T * i(m_end-1);
+ for (; QueueOp::less(*(i), e); --i)
{
- *(i) = std::move(*(i-1));
+ *(i+1) = *(i);
m_prof_sortmove.inc();
}
- *i = std::move(e);
+ *(i+1) = std::move(e);
++m_end;
m_prof_call.inc();
}
- void pop() noexcept { --m_end; }
+ T pop() noexcept { return *(--m_end); }
const T &top() const noexcept { return *(m_end-1); }
template <class R>
void remove(const R &elem) noexcept
{
/* Lock */
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
+ m_prof_remove.inc();
+
for (T * i = m_end - 1; i > &m_list[0]; --i)
{
if (QueueOp::equal(*i, elem))
{
- --m_end;
- for (;i < m_end; ++i)
- *i = std::move(*(i+1));
+ std::copy(i+1, m_end--, i);
return;
}
}
}
- void retime(const T &elem) noexcept
+ void retime(T && elem) noexcept
{
/* Lock */
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
+ m_prof_retime.inc();
+
for (T * i = m_end - 1; i > &m_list[0]; --i)
{
if (QueueOp::equal(*i, elem)) // partial equal!
{
- *i = elem;
+ *i = std::move(elem);
while (QueueOp::less(*(i-1), *i))
{
std::swap(*(i-1), *i);
@@ -174,9 +174,9 @@ namespace netlist
}
}
- void clear()
+ void clear() noexcept
{
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
m_end = &m_list[0];
/* put an empty element with maximum time into the queue.
* the insert algo above will run into this element and doesn't
@@ -188,55 +188,61 @@ namespace netlist
// save state support & mame disasm
- constexpr const T *listptr() const noexcept { return &m_list[1]; }
- constexpr std::size_t size() const noexcept { return static_cast<std::size_t>(m_end - &m_list[1]); }
- constexpr const T & operator[](const std::size_t index) const noexcept { return m_list[ 1 + index]; }
+ const T *listptr() const noexcept { return &m_list[1]; }
+ std::size_t size() const noexcept { return static_cast<std::size_t>(m_end - &m_list[1]); }
+ const T & operator[](const std::size_t index) const noexcept { return m_list[ 1 + index]; }
private:
- using tqmutex = pspin_mutex<TS>;
- using tqlock = std::lock_guard<tqmutex>;
+ using mutex_type = pspin_mutex<TS>;
+ using lock_guard_type = std::lock_guard<mutex_type>;
- tqmutex m_lock;
- T * m_end;
- std::vector<T> m_list;
+ mutex_type m_lock;
+ PALIGNAS_CACHELINE()
+ T * m_end;
+ //std::vector<T> m_list;
+ plib::aligned_vector<T> m_list;
public:
// profiling
- nperfcount_t m_prof_sortmove;
- nperfcount_t m_prof_call;
+ nperfcount_t<KEEPSTAT> m_prof_sortmove;
+ nperfcount_t<KEEPSTAT> m_prof_call;
+ nperfcount_t<KEEPSTAT> m_prof_remove;
+ nperfcount_t<KEEPSTAT> m_prof_retime;
};
-#else
- template <class T, bool TS, class QueueOp = typename T::QueueOp>
- class timed_queue : plib::nocopyassignmove
+
+ template <class T, bool TS, bool KEEPSTAT, class QueueOp = typename T::QueueOp>
+ class timed_queue_heap : plib::nocopyassignmove
{
public:
struct compare
{
- constexpr bool operator()(const T &a, const T &b) const { return QueueOp::less(b,a); }
+ constexpr bool operator()(const T &a, const T &b) const { return QueueOp::lessequal(b,a); }
};
- explicit timed_queue(const std::size_t list_size)
+ explicit timed_queue_heap(const std::size_t list_size)
: m_list(list_size)
{
clear();
}
- constexpr std::size_t capacity() const noexcept { return m_list.capacity(); }
- constexpr bool empty() const noexcept { return &m_list[0] == m_end; }
+ std::size_t capacity() const noexcept { return m_list.capacity(); }
+ bool empty() const noexcept { return &m_list[0] == m_end; }
void push(T &&e) noexcept
{
/* Lock */
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
*m_end++ = e;
std::push_heap(&m_list[0], m_end, compare());
m_prof_call.inc();
}
- void pop() noexcept
+ T pop() noexcept
{
+ T ret(m_list[0]);
std::pop_heap(&m_list[0], m_end, compare());
m_end--;
+ return ret;
}
const T &top() const noexcept { return m_list[0]; }
@@ -245,7 +251,7 @@ namespace netlist
void remove(const R &elem) noexcept
{
/* Lock */
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
for (T * i = m_end - 1; i >= &m_list[0]; i--)
{
if (QueueOp::equal(*i, elem))
@@ -262,7 +268,7 @@ namespace netlist
void retime(const T &elem) noexcept
{
/* Lock */
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
for (T * i = m_end - 1; i >= &m_list[0]; i--)
{
if (QueueOp::equal(*i, elem)) // partial equal!
@@ -276,7 +282,7 @@ namespace netlist
void clear()
{
- tqlock lck(m_lock);
+ lock_guard_type lck(m_lock);
m_list.clear();
m_end = &m_list[0];
}
@@ -287,19 +293,28 @@ namespace netlist
constexpr std::size_t size() const noexcept { return m_list.size(); }
constexpr const T & operator[](const std::size_t index) const { return m_list[ 0 + index]; }
private:
- using tqmutex = pspin_mutex<TS>;
- using tqlock = std::lock_guard<tqmutex>;
+ using mutex_type = pspin_mutex<TS>;
+ using lock_guard_type = std::lock_guard<mutex_type>;
- tqmutex m_lock;
+ mutex_type m_lock;
std::vector<T> m_list;
T *m_end;
public:
// profiling
- nperfcount_t m_prof_sortmove;
- nperfcount_t m_prof_call;
+ nperfcount_t<KEEPSTAT> m_prof_sortmove;
+ nperfcount_t<KEEPSTAT> m_prof_call;
};
-#endif
-}
+
+ /*
+ * Use timed_queue_heap to use stdc++ heap functions instead of linear processing.
+ *
+ * This slows down processing by about 25% on a Kaby Lake.
+ */
+
+ template <class T, bool TS, bool KEEPSTAT, class QueueOp = typename T::QueueOp>
+ using timed_queue = timed_queue_linear<T, TS, KEEPSTAT, QueueOp>;
+
+} // namespace netlist
#endif /* NLLISTS_H_ */
diff --git a/src/lib/netlist/nl_parser.cpp b/src/lib/netlist/nl_parser.cpp
index 4685a13c354..cecfbe862bf 100644
--- a/src/lib/netlist/nl_parser.cpp
+++ b/src/lib/netlist/nl_parser.cpp
@@ -6,9 +6,9 @@
*/
#include "nl_parser.h"
-#include "nl_factory.h"
-#include "nl_errstr.h"
#include "nl_base.h"
+#include "nl_errstr.h"
+#include "nl_factory.h"
namespace netlist
{
@@ -24,13 +24,13 @@ void parser_t::verror(const pstring &msg, int line_num, const pstring &line)
//throw error;
}
-
bool parser_t::parse(const pstring &nlname)
{
- set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-");
- set_number_chars(".0123456789", "0123456789eE-."); //FIXME: processing of numbers
- set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13));
- set_comment("/*", "*/", "//");
+ this->identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-")
+ .number_chars(".0123456789", "0123456789eE-.") //FIXME: processing of numbers
+ //set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13));
+ .whitespace(pstring("") + ' ' + static_cast<char>(9) + static_cast<char>(10) + static_cast<char>(13))
+ .comment("/*", "*/", "//");
m_tok_param_left = register_token("(");
m_tok_param_right = register_token(")");
m_tok_comma = register_token(",");
@@ -357,10 +357,10 @@ void parser_t::device(const pstring &dev_type)
m_setup.register_dev(dev_type, devname);
m_setup.log().debug("Parser: IC: {1}\n", devname);
- for (pstring tp : paramlist)
+ for (const pstring &tp : paramlist)
{
require_token(m_tok_comma);
- if (tp.startsWith("+"))
+ if (plib::startsWith(tp, "+"))
{
pstring output_name = get_identifier();
m_setup.log().debug("Link: {1} {2}\n", tp, output_name);
@@ -395,18 +395,15 @@ void parser_t::device(const pstring &dev_type)
// ----------------------------------------------------------------------------------------
-nl_double parser_t::eval_param(const token_t tok)
+nl_double parser_t::eval_param(const token_t &tok)
{
- static pstring macs[6] = {"", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"};
- static nl_double facs[6] = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12};
- int i;
- int f=0;
- bool e;
+ static std::array<pstring, 6> macs = {"", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"};
+ static std::array<nl_double, 6> facs = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12};
+ std::size_t f=0;
nl_double ret;
- pstring val;
- for (i=1; i<6;i++)
- if (tok.str().equals(macs[i]))
+ for (std::size_t i=1; i<macs.size();i++)
+ if (tok.str() == macs[i])
f = i;
if (f>0)
{
@@ -416,13 +413,13 @@ nl_double parser_t::eval_param(const token_t tok)
}
else
{
- val = tok.str();
- ret = val.as_double(&e);
- if (e)
- error(plib::pfmt("Parameter value <{1}> not double \n")(val));
+ bool err;
+ ret = plib::pstonum_ne<nl_double>(tok.str(), err);
+ if (err)
+ error(plib::pfmt("Parameter value <{1}> not double \n")(tok.str()));
}
return ret * facs[f];
}
-}
+} // namespace netlist
diff --git a/src/lib/netlist/nl_parser.h b/src/lib/netlist/nl_parser.h
index a813629faa0..92459c4b87b 100644
--- a/src/lib/netlist/nl_parser.h
+++ b/src/lib/netlist/nl_parser.h
@@ -16,8 +16,12 @@ namespace netlist
class parser_t : public plib::ptokenizer
{
public:
- parser_t(plib::putf8_reader &strm, setup_t &setup)
- : plib::ptokenizer(strm), m_setup(setup) {}
+ template <typename T>
+ parser_t(T &&strm, nlparse_t &setup)
+ : plib::ptokenizer(std::forward<T>(strm))
+ , m_setup(setup)
+ {
+ }
bool parse(const pstring &nlname = "");
@@ -39,12 +43,12 @@ namespace netlist
void net_truthtable_start(const pstring &nlname);
/* for debugging messages */
- netlist_t &netlist() { return m_setup.netlist(); }
+ //netlist_state_t &netlist() { return m_setup.netlist(); }
- virtual void verror(const pstring &msg, int line_num, const pstring &line) override;
+ void verror(const pstring &msg, int line_num, const pstring &line) override;
private:
- nl_double eval_param(const token_t tok);
+ nl_double eval_param(const token_t &tok);
token_id_t m_tok_param_left;
token_id_t m_tok_param_right;
@@ -68,9 +72,9 @@ namespace netlist
token_id_t m_tok_TT_LINE;
token_id_t m_tok_TT_FAMILY;
- setup_t &m_setup;
+ nlparse_t &m_setup;
};
-}
+} // namespace netlist
#endif /* NL_PARSER_H_ */
diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp
index df761bc3f88..b9300f5ad9c 100644
--- a/src/lib/netlist/nl_setup.cpp
+++ b/src/lib/netlist/nl_setup.cpp
@@ -6,128 +6,243 @@
*/
#include "plib/palloc.h"
-#include "plib/putil.h"
+#include "analog/nld_twoterm.h"
+#include "devices/nlid_proxy.h"
+#include "devices/nlid_system.h"
+#include "devices/nlid_truthtable.h"
#include "nl_base.h"
-#include "nl_setup.h"
-#include "nl_parser.h"
#include "nl_factory.h"
-#include "devices/nlid_system.h"
-#include "devices/nlid_proxy.h"
-#include "analog/nld_twoterm.h"
+#include "nl_parser.h"
+#include "nl_setup.h"
+#include "plib/putil.h"
#include "solver/nld_solver.h"
-#include "devices/nlid_truthtable.h"
-// ----------------------------------------------------------------------------------------
-// setup_t
-// ----------------------------------------------------------------------------------------
+#include <cmath>
namespace netlist
{
-setup_t::setup_t(netlist_t &netlist)
- : m_netlist(netlist)
- , m_factory(*this)
- , m_proxy_cnt(0)
+ // ----------------------------------------------------------------------------------------
+ // nl_parse_t
+ // ----------------------------------------------------------------------------------------
+
+ nlparse_t::nlparse_t(setup_t &setup, log_type &log)
+ : m_factory(log)
+ , m_setup(setup)
+ , m_log(log)
, m_frontier_cnt(0)
-{
- devices::initialize_factory(m_factory);
-}
+ { }
-setup_t::~setup_t()
-{
- m_links.clear();
- m_alias.clear();
- m_params.clear();
- m_terminals.clear();
- m_param_values.clear();
+ void nlparse_t::register_alias(const pstring &alias, const pstring &out)
+ {
+ pstring alias_fqn = build_fqn(alias);
+ pstring out_fqn = build_fqn(out);
+ register_alias_nofqn(alias_fqn, out_fqn);
+ }
- m_sources.clear();
-}
+ void nlparse_t::register_dippins_arr(const pstring &terms)
+ {
+ std::vector<pstring> list(plib::psplit(terms,", "));
+ if (list.size() == 0 || (list.size() % 2) == 1)
+ log().fatal(MF_1_DIP_PINS_MUST_BE_AN_EQUAL_NUMBER_OF_PINS_1,
+ build_fqn(""));
+ std::size_t n = list.size();
+ for (std::size_t i = 0; i < n / 2; i++)
+ {
+ register_alias(plib::pfmt("{1}")(i+1), list[i * 2]);
+ register_alias(plib::pfmt("{1}")(n-i), list[i * 2 + 1]);
+ }
+ }
-pstring setup_t::build_fqn(const pstring &obj_name) const
-{
- if (m_namespace_stack.empty())
- //return netlist().name() + "." + obj_name;
- return obj_name;
- else
- return m_namespace_stack.top() + "." + obj_name;
-}
+ void nlparse_t::register_dev(const pstring &classname, const pstring &name)
+ {
+ auto f = m_factory.factory_by_name(classname);
+ if (f == nullptr)
+ log().fatal(MF_1_CLASS_1_NOT_FOUND, classname);
+ else
+ {
+ /* make sure we parse macro library entries */
+ f->macro_actions(*this, name);
+ pstring key = build_fqn(name);
+ if (device_exists(key))
+ log().fatal(MF_1_DEVICE_ALREADY_EXISTS_1, name);
+ else
+ m_device_factory.insert(m_device_factory.end(), {key, f});
+ }
+ }
-void setup_t::namespace_push(const pstring &aname)
-{
- if (m_namespace_stack.empty())
- //m_namespace_stack.push(netlist().name() + "." + aname);
- m_namespace_stack.push(aname);
- else
- m_namespace_stack.push(m_namespace_stack.top() + "." + aname);
-}
+ void nlparse_t::register_link(const pstring &sin, const pstring &sout)
+ {
+ register_link_fqn(build_fqn(sin), build_fqn(sout));
+ }
-void setup_t::namespace_pop()
-{
- m_namespace_stack.pop();
-}
+ void nlparse_t::register_link_arr(const pstring &terms)
+ {
+ std::vector<pstring> list(plib::psplit(terms,", "));
+ if (list.size() < 2)
+ log().fatal(MF_2_NET_C_NEEDS_AT_LEAST_2_TERMINAL);
+ for (std::size_t i = 1; i < list.size(); i++)
+ {
+ register_link(list[0], list[i]);
+ }
+ }
-void setup_t::register_lib_entry(const pstring &name, const pstring &sourcefile)
-{
- factory().register_device(plib::make_unique_base<factory::element_t, factory::library_element_t>(*this, name, name, "", sourcefile));
-}
+ void nlparse_t::include(const pstring &netlist_name)
+ {
+ for (auto &source : m_sources)
+ {
+ if (source->parse(*this, netlist_name))
+ return;
+ }
+ log().fatal(MF_1_NOT_FOUND_IN_SOURCE_COLLECTION, netlist_name);
+ }
-void setup_t::register_dev(const pstring &classname, const pstring &name)
-{
- auto f = factory().factory_by_name(classname);
- if (f == nullptr)
- log().fatal(MF_1_CLASS_1_NOT_FOUND, classname);
- /* make sure we parse macro library entries */
- f->macro_actions(netlist(), name);
- m_device_factory.push_back(std::pair<pstring, factory::element_t *>(build_fqn(name), f));
-}
-bool setup_t::device_exists(const pstring &name) const
-{
- for (auto e : m_device_factory)
+ void nlparse_t::namespace_push(const pstring &aname)
{
- if (e.first == name)
- return true;
+ if (m_namespace_stack.empty())
+ //m_namespace_stack.push(netlist().name() + "." + aname);
+ m_namespace_stack.push(aname);
+ else
+ m_namespace_stack.push(m_namespace_stack.top() + "." + aname);
}
- return false;
-}
+ void nlparse_t::namespace_pop()
+ {
+ m_namespace_stack.pop();
+ }
-void setup_t::register_model(const pstring &model_in)
-{
- auto pos = model_in.find(" ");
- if (pos == pstring::npos)
- log().fatal(MF_1_UNABLE_TO_PARSE_MODEL_1, model_in);
- pstring model = model_in.left(pos).trim().ucase();
- pstring def = model_in.substr(pos + 1).trim();
- if (!m_models.insert({model, def}).second)
- log().fatal(MF_1_MODEL_ALREADY_EXISTS_1, model_in);
-}
+ void nlparse_t::register_param(const pstring &param, const double value)
+ {
+ if (std::abs(value - std::floor(value)) > 1e-30 || std::abs(value) > 1e9)
+ register_param(param, plib::pfmt("{1:.9}").e(value));
+ else
+ register_param(param, plib::pfmt("{1}")(static_cast<long>(value)));
+ }
-void setup_t::register_alias_nofqn(const pstring &alias, const pstring &out)
-{
- if (!m_alias.insert({alias, out}).second)
- log().fatal(MF_1_ADDING_ALI1_TO_ALIAS_LIST, alias);
-}
+ void nlparse_t::register_param(const pstring &param, const pstring &value)
+ {
+ pstring fqn = build_fqn(param);
+
+ auto idx = m_param_values.find(fqn);
+ if (idx == m_param_values.end())
+ {
+ if (!m_param_values.insert({fqn, value}).second)
+ log().fatal(MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST,
+ param);
+ }
+ else
+ {
+ log().warning(MW_3_OVERWRITING_PARAM_1_OLD_2_NEW_3, fqn, idx->second,
+ value);
+ m_param_values[fqn] = value;
+ }
+ }
+
+ void nlparse_t::register_lib_entry(const pstring &name, const pstring &sourcefile)
+ {
+ m_factory.register_device(plib::make_unique<factory::library_element_t>(name, name, "", sourcefile));
+ }
+
+ void nlparse_t::register_frontier(const pstring &attach, const double r_IN, const double r_OUT)
+ {
+ pstring frontier_name = plib::pfmt("frontier_{1}")(m_frontier_cnt);
+ m_frontier_cnt++;
+ register_dev("FRONTIER_DEV", frontier_name);
+ register_param(frontier_name + ".RIN", r_IN);
+ register_param(frontier_name + ".ROUT", r_OUT);
+ register_link(frontier_name + ".G", "GND");
+ pstring attfn = build_fqn(attach);
+ pstring front_fqn = build_fqn(frontier_name);
+ bool found = false;
+ for (auto & link : m_links)
+ {
+ if (link.first == attfn)
+ {
+ link.first = front_fqn + ".I";
+ found = true;
+ }
+ else if (link.second == attfn)
+ {
+ link.second = front_fqn + ".I";
+ found = true;
+ }
+ }
+ if (!found)
+ log().fatal(MF_1_FOUND_NO_OCCURRENCE_OF_1, attach);
+ register_link(attach, frontier_name + ".Q");
+ }
+
+ void nlparse_t::tt_factory_create(tt_desc &desc, const pstring &sourcefile)
+ {
+ auto fac = devices::tt_factory_create(desc, sourcefile);
+ m_factory.register_device(std::move(fac));
+ }
+
+ pstring nlparse_t::build_fqn(const pstring &obj_name) const
+ {
+ if (m_namespace_stack.empty())
+ //return netlist().name() + "." + obj_name;
+ return obj_name;
+ else
+ return m_namespace_stack.top() + "." + obj_name;
+ }
+
+ void nlparse_t::register_alias_nofqn(const pstring &alias, const pstring &out)
+ {
+ if (!m_alias.insert({alias, out}).second)
+ log().fatal(MF_1_ADDING_ALI1_TO_ALIAS_LIST, alias);
+ }
+
+ void nlparse_t::register_link_fqn(const pstring &sin, const pstring &sout)
+ {
+ link_t temp = link_t(sin, sout);
+ log().debug("link {1} <== {2}\n", sin, sout);
+ m_links.push_back(temp);
+ }
-void setup_t::register_alias(const pstring &alias, const pstring &out)
+ bool nlparse_t::device_exists(const pstring &name) const
+ {
+ for (auto &d : m_device_factory)
+ if (d.first == name)
+ return true;
+ return false;
+ }
+
+ bool nlparse_t::parse_stream(plib::unique_ptr<plib::pistream> &&istrm, const pstring &name)
+ {
+ return parser_t(std::move(plib::ppreprocessor(&m_defines).process(std::move(istrm))), *this).parse(name);
+ }
+
+ void nlparse_t::add_define(const pstring &defstr)
+ {
+ auto p = defstr.find("=");
+ if (p != pstring::npos)
+ add_define(plib::left(defstr, p), defstr.substr(p+1));
+ else
+ add_define(defstr, "1");
+ }
+
+ // ----------------------------------------------------------------------------------------
+ // setup_t
+ // ----------------------------------------------------------------------------------------
+
+
+setup_t::setup_t(netlist_state_t &nlstate)
+ : nlparse_t(*this, nlstate.log())
+ , m_nlstate(nlstate)
+ , m_netlist_params(nullptr)
+ , m_proxy_cnt(0)
{
- pstring alias_fqn = build_fqn(alias);
- pstring out_fqn = build_fqn(out);
- register_alias_nofqn(alias_fqn, out_fqn);
}
-void setup_t::register_dippins_arr(const pstring &terms)
+setup_t::~setup_t() noexcept
{
- std::vector<pstring> list(plib::psplit(terms,", "));
- if (list.size() == 0 || (list.size() % 2) == 1)
- log().fatal(MF_1_DIP_PINS_MUST_BE_AN_EQUAL_NUMBER_OF_PINS_1,
- build_fqn(""));
- std::size_t n = list.size();
- for (std::size_t i = 0; i < n / 2; i++)
- {
- register_alias(plib::pfmt("{1}")(i+1), list[i * 2]);
- register_alias(plib::pfmt("{1}")(n-i), list[i * 2 + 1]);
- }
+ // FIXME: can't see a need any longer
+ m_links.clear();
+ m_params.clear();
+ m_terminals.clear();
+ m_param_values.clear();
+ m_sources.clear();
}
pstring setup_t::termtype_as_str(detail::core_terminal_t &in) const
@@ -145,7 +260,7 @@ pstring setup_t::termtype_as_str(detail::core_terminal_t &in) const
return pstring("Error");
}
-pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def)
+pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def) const
{
auto i = m_param_values.find(name);
if (i != m_param_values.end())
@@ -154,40 +269,6 @@ pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def)
return def;
}
-double setup_t::get_initial_param_val(const pstring &name, const double def)
-{
- auto i = m_param_values.find(name);
- if (i != m_param_values.end())
- {
- double vald = 0;
- if (sscanf(i->second.c_str(), "%lf", &vald) != 1)
- log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second);
- return vald;
- }
- else
- return def;
-}
-
-int setup_t::get_initial_param_val(const pstring &name, const int def)
-{
- auto i = m_param_values.find(name);
- if (i != m_param_values.end())
- {
- double vald = 0;
- if (sscanf(i->second.c_str(), "%lf", &vald) != 1)
- log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, i->second);
- return static_cast<int>(vald);
- }
- else
- return def;
-}
-
-void setup_t::register_param(const pstring &name, param_t &param)
-{
- if (!m_params.insert({param.name(), param_ref_t(param.name(), param.device(), param)}).second)
- log().fatal(MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST, name);
-}
-
void setup_t::register_term(detail::core_terminal_t &term)
{
if (!m_terminals.insert({term.name(), &term}).second)
@@ -196,30 +277,6 @@ void setup_t::register_term(detail::core_terminal_t &term)
log().debug("{1} {2}\n", termtype_as_str(term), term.name());
}
-void setup_t::register_link_arr(const pstring &terms)
-{
- std::vector<pstring> list(plib::psplit(terms,", "));
- if (list.size() < 2)
- log().fatal(MF_2_NET_C_NEEDS_AT_LEAST_2_TERMINAL);
- for (std::size_t i = 1; i < list.size(); i++)
- {
- register_link(list[0], list[i]);
- }
-}
-
-
-void setup_t::register_link_fqn(const pstring &sin, const pstring &sout)
-{
- link_t temp = link_t(sin, sout);
- log().debug("link {1} <== {2}\n", sin, sout);
- m_links.push_back(temp);
-}
-
-void setup_t::register_link(const pstring &sin, const pstring &sout)
-{
- register_link_fqn(build_fqn(sin), build_fqn(sout));
-}
-
void setup_t::remove_connections(const pstring &pin)
{
pstring pinfn = build_fqn(pin);
@@ -241,59 +298,14 @@ void setup_t::remove_connections(const pstring &pin)
}
-void setup_t::register_frontier(const pstring &attach, const double r_IN, const double r_OUT)
-{
- pstring frontier_name = plib::pfmt("frontier_{1}")(m_frontier_cnt);
- m_frontier_cnt++;
- register_dev("FRONTIER_DEV", frontier_name);
- register_param(frontier_name + ".RIN", r_IN);
- register_param(frontier_name + ".ROUT", r_OUT);
- register_link(frontier_name + ".G", "GND");
- pstring attfn = build_fqn(attach);
- pstring front_fqn = build_fqn(frontier_name);
- bool found = false;
- for (auto & link : m_links)
- {
- if (link.first == attfn)
- {
- link.first = front_fqn + ".I";
- found = true;
- }
- else if (link.second == attfn)
- {
- link.second = front_fqn + ".I";
- found = true;
- }
- }
- if (!found)
- log().fatal(MF_1_FOUND_NO_OCCURRENCE_OF_1, attach);
- register_link(attach, frontier_name + ".Q");
-}
-
-void setup_t::register_param(const pstring &param, const double value)
+void setup_t::register_param_t(const pstring &name, param_t &param)
{
- register_param(param, plib::pfmt("{1:.9}").e(value));
+ if (!m_params.insert({param.name(), param_ref_t(param.name(), param.device(), param)}).second)
+ log().fatal(MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST, name);
}
-void setup_t::register_param(const pstring &param, const pstring &value)
-{
- pstring fqn = build_fqn(param);
- auto idx = m_param_values.find(fqn);
- if (idx == m_param_values.end())
- {
- if (!m_param_values.insert({fqn, value}).second)
- log().fatal(MF_1_ADDING_PARAMETER_1_TO_PARAMETER_LIST,
- param);
- }
- else
- {
- log().warning(MW_3_OVERWRITING_PARAM_1_OLD_2_NEW_3, fqn, idx->second,
- value);
- m_param_values[fqn] = value;
- }
-}
const pstring setup_t::resolve_alias(const pstring &name) const
{
@@ -311,6 +323,42 @@ const pstring setup_t::resolve_alias(const pstring &name) const
return ret;
}
+std::vector<pstring> setup_t::get_terminals_for_device_name(const pstring &devname)
+{
+ std::vector<pstring> terms;
+ for (auto & t : m_terminals)
+ {
+ if (plib::startsWith(t.second->name(), devname))
+ {
+ pstring tn(t.second->name().substr(devname.length()+1));
+ if (tn.find(".") == pstring::npos)
+ terms.push_back(tn);
+ }
+ }
+
+ for (auto & t : m_alias)
+ {
+ if (plib::startsWith(t.first, devname))
+ {
+ pstring tn(t.first.substr(devname.length()+1));
+ //printf("\t%s %s %s\n", t.first.c_str(), t.second.c_str(), tn.c_str());
+ if (tn.find(".") == pstring::npos)
+ {
+ terms.push_back(tn);
+ pstring resolved = resolve_alias(t.first);
+ //printf("\t%s %s %s\n", t.first.c_str(), t.second.c_str(), resolved.c_str());
+ if (resolved != t.first)
+ {
+ auto found = std::find(terms.begin(), terms.end(), resolved.substr(devname.length()+1));
+ if (found!=terms.end())
+ terms.erase(found);
+ }
+ }
+ }
+ }
+ return terms;
+}
+
detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, bool required)
{
const pstring &tname = resolve_alias(terminal_in);
@@ -377,7 +425,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(detail::core_terminal_t &out)
{
nl_assert(out.is_logic());
- logic_output_t &out_cast = static_cast<logic_output_t &>(out);
+ auto &out_cast = static_cast<logic_output_t &>(out);
devices::nld_base_proxy *proxy = out_cast.get_proxy();
if (proxy == nullptr)
@@ -385,28 +433,25 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(detail::core_terminal_t &out)
// create a new one ...
pstring x = plib::pfmt("proxy_da_{1}_{2}")(out.name())(m_proxy_cnt);
auto new_proxy =
- out_cast.logic_family()->create_d_a_proxy(netlist(), x, &out_cast);
+ out_cast.logic_family()->create_d_a_proxy(m_nlstate, x, &out_cast);
m_proxy_cnt++;
-
- //new_proxy->start_dev();
-
/* connect all existing terminals to new net */
- for (auto & p : out.net().m_core_terms)
+ for (auto & p : out.net().core_terms())
{
p->clear_net(); // de-link from all nets ...
if (!connect(new_proxy->proxy_term(), *p))
log().fatal(MF_2_CONNECTING_1_TO_2,
new_proxy->proxy_term().name(), (*p).name());
}
- out.net().m_core_terms.clear(); // clear the list
+ out.net().core_terms().clear(); // clear the list
out.net().add_terminal(new_proxy->in());
out_cast.set_proxy(proxy);
proxy = new_proxy.get();
- netlist().register_dev(std::move(new_proxy));
+ m_nlstate.add_dev(new_proxy->name(), std::move(new_proxy));
}
return proxy;
}
@@ -415,7 +460,7 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
{
nl_assert(inp.is_logic());
- logic_input_t &incast = dynamic_cast<logic_input_t &>(inp);
+ auto &incast = dynamic_cast<logic_input_t &>(inp);
devices::nld_base_proxy *proxy = incast.get_proxy();
if (proxy != nullptr)
@@ -424,7 +469,7 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
{
log().debug("connect_terminal_input: connecting proxy\n");
pstring x = plib::pfmt("proxy_ad_{1}_{2}")(inp.name())(m_proxy_cnt);
- auto new_proxy = incast.logic_family()->create_a_d_proxy(netlist(), x, &incast);
+ auto new_proxy = incast.logic_family()->create_a_d_proxy(m_nlstate, x, &incast);
//auto new_proxy = plib::owned_ptr<devices::nld_a_to_d_proxy>::Create(netlist(), x, &incast);
incast.set_proxy(new_proxy.get());
m_proxy_cnt++;
@@ -435,17 +480,17 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
if (inp.has_net())
{
- for (auto & p : inp.net().m_core_terms)
+ for (auto & p : inp.net().core_terms())
{
p->clear_net(); // de-link from all nets ...
if (!connect(ret->proxy_term(), *p))
log().fatal(MF_2_CONNECTING_1_TO_2,
ret->proxy_term().name(), (*p).name());
}
- inp.net().m_core_terms.clear(); // clear the list
+ inp.net().core_terms().clear(); // clear the list
}
ret->out().net().add_terminal(inp);
- netlist().register_dev(std::move(new_proxy));
+ m_nlstate.add_dev(new_proxy->name(), std::move(new_proxy));
return ret;
}
}
@@ -568,11 +613,12 @@ void setup_t::connect_terminals(detail::core_terminal_t &t1, detail::core_termin
{
log().debug("adding analog net ...\n");
// FIXME: Nets should have a unique name
- auto anet = plib::palloc<analog_net_t>(netlist(),"net." + t1.name());
- netlist().m_nets.push_back(plib::owned_ptr<analog_net_t>(anet, true));
- t1.set_net(anet);
- anet->add_terminal(t2);
- anet->add_terminal(t1);
+ auto anet = pool().make_poolptr<analog_net_t>(m_nlstate,"net." + t1.name());
+ auto anetp = anet.get();
+ m_nlstate.register_net(std::move(anet));
+ t1.set_net(anetp);
+ anetp->add_terminal(t2);
+ anetp->add_terminal(t1);
}
}
@@ -580,7 +626,7 @@ static detail::core_terminal_t &resolve_proxy(detail::core_terminal_t &term)
{
if (term.is_logic())
{
- logic_t &out = dynamic_cast<logic_t &>(term);
+ auto &out = dynamic_cast<logic_t &>(term);
if (out.has_proxy())
return out.get_proxy()->proxy_term();
}
@@ -596,7 +642,7 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term
ret = connect(t2, t1.net().railterminal());
if (!ret)
{
- for (auto & t : t1.net().m_core_terms)
+ for (auto & t : t1.net().core_terms())
{
if (t->is_type(detail::terminal_type::TERMINAL))
ret = connect(t2, *t);
@@ -611,7 +657,7 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term
ret = connect(t1, t2.net().railterminal());
if (!ret)
{
- for (auto & t : t2.net().m_core_terms)
+ for (auto & t : t2.net().core_terms())
{
if (t->is_type(detail::terminal_type::TERMINAL))
ret = connect(t1, *t);
@@ -623,8 +669,6 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term
return ret;
}
-
-
bool setup_t::connect(detail::core_terminal_t &t1_in, detail::core_terminal_t &t2_in)
{
log().debug("Connecting {1} to {2}\n", t1_in.name(), t2_in.name());
@@ -712,18 +756,7 @@ void setup_t::resolve_inputs()
// delete empty nets
- netlist().m_nets.erase(
- std::remove_if(netlist().m_nets.begin(), netlist().m_nets.end(),
- [](plib::owned_ptr<detail::net_t> &x)
- {
- if (x->num_cons() == 0)
- {
- x->netlist().log().verbose("Deleting net {1} ...", x->name());
- return true;
- }
- else
- return false;
- }), netlist().m_nets.end());
+ delete_empty_nets();
pstring errstr("");
@@ -744,7 +777,7 @@ void setup_t::resolve_inputs()
}
-void setup_t::start_devices()
+void setup_t::register_dynamic_log_devices()
{
pstring env = plib::util::environment("NL_LOGS", "");
@@ -752,41 +785,43 @@ void setup_t::start_devices()
{
log().debug("Creating dynamic logs ...");
std::vector<pstring> loglist(plib::psplit(env, ":"));
- for (pstring ll : loglist)
+ for (const pstring &ll : loglist)
{
pstring name = "log_" + ll;
- auto nc = factory().factory_by_name("LOG")->Create(netlist(), name);
+ auto nc = factory().factory_by_name("LOG")->Create(m_nlstate, name);
register_link(name + ".I", ll);
log().debug(" dynamic link {1}: <{2}>\n",ll, name);
- netlist().register_dev(std::move(nc));
+ m_nlstate.add_dev(nc->name(), std::move(nc));
}
}
}
-plib::plog_base<netlist_t, NL_DEBUG> &setup_t::log()
+log_type &setup_t::log()
{
- return netlist().log();
+ return m_nlstate.log();
}
-const plib::plog_base<netlist_t, NL_DEBUG> &setup_t::log() const
+const log_type &setup_t::log() const
{
- return netlist().log();
+ return m_nlstate.log();
}
// ----------------------------------------------------------------------------------------
-// Model
+// Models
// ----------------------------------------------------------------------------------------
-static pstring model_string(detail::model_map_t &map)
+void models_t::register_model(pstring model_in)
{
- pstring ret = map["COREMODEL"] + "(";
- for (auto & i : map)
- ret = ret + i.first + "=" + i.second + " ";
-
- return ret + ")";
+ auto pos = model_in.find(" ");
+ if (pos == pstring::npos)
+ throw nl_exception(MF_1_UNABLE_TO_PARSE_MODEL_1, model_in);
+ pstring model = plib::ucase(plib::trim(plib::left(model_in, pos)));
+ pstring def = plib::trim(model_in.substr(pos + 1));
+ if (!m_models.insert({model, def}).second)
+ throw nl_exception(MF_1_MODEL_ALREADY_EXISTS_1, model_in);
}
-void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map)
+void models_t::model_parse(const pstring &model_in, model_map_t &map)
{
pstring model = model_in;
std::size_t pos = 0;
@@ -797,15 +832,15 @@ void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map)
pos = model.find("(");
if (pos != pstring::npos) break;
- key = model.ucase();
+ key = plib::ucase(model);
auto i = m_models.find(key);
if (i == m_models.end())
- log().fatal(MF_1_MODEL_NOT_FOUND, model);
+ throw nl_exception(MF_1_MODEL_NOT_FOUND, model);
model = i->second;
}
- pstring xmodel = model.left(pos);
+ pstring xmodel = plib::left(model, pos);
- if (xmodel.equals("_"))
+ if (xmodel == "_")
map["COREMODEL"] = key;
else
{
@@ -813,46 +848,65 @@ void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map)
if (i != m_models.end())
model_parse(xmodel, map);
else
- log().fatal(MF_1_MODEL_NOT_FOUND, model_in);
+ throw nl_exception(MF_1_MODEL_NOT_FOUND, model_in);
}
- pstring remainder = model.substr(pos + 1).trim();
- if (!remainder.endsWith(")"))
- log().fatal(MF_1_MODEL_ERROR_1, model);
+ pstring remainder = plib::trim(model.substr(pos + 1));
+ if (!plib::endsWith(remainder, ")"))
+ throw nl_exception(MF_1_MODEL_ERROR_1, model);
// FIMXE: Not optimal
- remainder = remainder.left(remainder.length() - 1);
+ remainder = plib::left(remainder, remainder.size() - 1);
std::vector<pstring> pairs(plib::psplit(remainder," ", true));
for (pstring &pe : pairs)
{
auto pose = pe.find("=");
if (pose == pstring::npos)
- log().fatal(MF_1_MODEL_ERROR_ON_PAIR_1, model);
- map[pe.left(pose).ucase()] = pe.substr(pose + 1);
+ throw nl_exception(MF_1_MODEL_ERROR_ON_PAIR_1, model);
+ map[plib::ucase(plib::left(pe, pose))] = pe.substr(pose + 1);
}
}
-const pstring setup_t::model_value_str(detail::model_map_t &map, const pstring &entity)
+pstring models_t::model_string(model_map_t &map)
+{
+ pstring ret = map["COREMODEL"] + "(";
+ for (auto & i : map)
+ ret = ret + i.first + "=" + i.second + " ";
+
+ return ret + ")";
+}
+
+pstring models_t::model_value_str(pstring model, pstring entity)
{
+ model_map_t &map = m_cache[model];
+
+ if (map.size() == 0)
+ model_parse(model , map);
+
pstring ret;
- if (entity != entity.ucase())
- log().fatal(MF_2_MODEL_PARAMETERS_NOT_UPPERCASE_1_2, entity,
+ if (entity != plib::ucase(entity))
+ throw nl_exception(MF_2_MODEL_PARAMETERS_NOT_UPPERCASE_1_2, entity,
model_string(map));
if (map.find(entity) == map.end())
- log().fatal(MF_2_ENTITY_1_NOT_FOUND_IN_MODEL_2, entity, model_string(map));
+ throw nl_exception(MF_2_ENTITY_1_NOT_FOUND_IN_MODEL_2, entity, model_string(map));
else
ret = map[entity];
return ret;
}
-nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity)
+nl_double models_t::model_value(pstring model, pstring entity)
{
- pstring tmp = model_value_str(map, entity);
+ model_map_t &map = m_cache[model];
+
+ if (map.size() == 0)
+ model_parse(model , map);
- nl_double factor = NL_FCONST(1.0);
- auto p = std::next(tmp.begin(), static_cast<pstring::difference_type>(tmp.length() - 1));
+ pstring tmp = model_value_str(model, entity);
+
+ nl_double factor = plib::constants<nl_double>::one();
+ auto p = std::next(tmp.begin(), static_cast<pstring::difference_type>(tmp.size() - 1));
switch (*p)
{
case 'M': factor = 1e6; break;
@@ -865,85 +919,69 @@ nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity)
case 'a': factor = 1e-18; break;
default:
if (*p < '0' || *p > '9')
- log().fatal(MF_1_UNKNOWN_NUMBER_FACTOR_IN_1, entity);
+ throw nl_exception(MF_1_UNKNOWN_NUMBER_FACTOR_IN_1, entity);
}
- if (factor != NL_FCONST(1.0))
- tmp = tmp.left(tmp.length() - 1);
- return tmp.as_double() * factor;
+ if (factor != plib::constants<nl_double>::one())
+ tmp = plib::left(tmp, tmp.size() - 1);
+ // FIXME: check for errors
+ //printf("%s %s %e %e\n", entity.c_str(), tmp.c_str(), plib::pstonum<nl_double>(tmp), factor);
+ return plib::pstonum<nl_double>(tmp) * factor;
}
class logic_family_std_proxy_t : public logic_family_desc_t
{
public:
- logic_family_std_proxy_t() { }
- virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist,
+ logic_family_std_proxy_t() = default;
+ pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist,
const pstring &name, logic_output_t *proxied) const override;
- virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
+ pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
};
-plib::owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_std_proxy_t::create_d_a_proxy(netlist_t &anetlist,
+pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_std_proxy_t::create_d_a_proxy(netlist_state_t &anetlist,
const pstring &name, logic_output_t *proxied) const
{
- return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
}
-plib::owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_std_proxy_t::create_a_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *proxied) const
+pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_std_proxy_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
{
- return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
+ return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
}
const logic_family_desc_t *setup_t::family_from_model(const pstring &model)
{
- detail::model_map_t map;
- model_parse(model, map);
- if (model_value_str(map, "TYPE") == "TTL")
+ if (m_models.model_value_str(model, "TYPE") == "TTL")
return family_TTL();
- if (model_value_str(map, "TYPE") == "CD4XXX")
+ if (m_models.model_value_str(model, "TYPE") == "CD4XXX")
return family_CD4XXX();
- for (auto & e : netlist().m_family_cache)
+ for (auto & e : m_nlstate.m_family_cache)
if (e.first == model)
return e.second.get();
- auto ret = plib::make_unique_base<logic_family_desc_t, logic_family_std_proxy_t>();
+ auto ret = plib::make_unique<logic_family_std_proxy_t>();
- ret->m_fixed_V = model_value(map, "FV");
- ret->m_low_thresh_PCNT = model_value(map, "IVL");
- ret->m_high_thresh_PCNT = model_value(map, "IVH");
- ret->m_low_VO = model_value(map, "OVL");
- ret->m_high_VO = model_value(map, "OVH");
- ret->m_R_low = model_value(map, "ORL");
- ret->m_R_high = model_value(map, "ORH");
+ ret->m_fixed_V = m_models.model_value(model, "FV");
+ ret->m_low_thresh_PCNT = m_models.model_value(model, "IVL");
+ ret->m_high_thresh_PCNT = m_models.model_value(model, "IVH");
+ ret->m_low_VO = m_models.model_value(model, "OVL");
+ ret->m_high_VO = m_models. model_value(model, "OVH");
+ ret->m_R_low = m_models.model_value(model, "ORL");
+ ret->m_R_high = m_models.model_value(model, "ORH");
auto retp = ret.get();
- netlist().m_family_cache.emplace_back(model, std::move(ret));
+ m_nlstate.m_family_cache.emplace_back(model, std::move(ret));
return retp;
}
-void setup_t::tt_factory_create(tt_desc &desc, const pstring &sourcefile)
-{
- devices::tt_factory_create(*this, desc, sourcefile);
-}
-
-
// ----------------------------------------------------------------------------------------
// Sources
// ----------------------------------------------------------------------------------------
-void setup_t::include(const pstring &netlist_name)
-{
- for (auto &source : m_sources)
- {
- if (source->parse(netlist_name))
- return;
- }
- log().fatal(MF_1_NOT_FOUND_IN_SOURCE_COLLECTION, netlist_name);
-}
-
-std::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring &name)
+plib::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring &name)
{
for (auto &source : m_sources)
{
@@ -955,77 +993,189 @@ std::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring &name)
}
}
log().warning(MW_1_DATA_1_NOT_FOUND, name);
- return std::unique_ptr<plib::pistream>(nullptr);
+ return plib::unique_ptr<plib::pistream>(nullptr);
}
-bool setup_t::parse_stream(plib::putf8_reader &istrm, const pstring &name)
-{
- plib::pomemstream ostrm;
- plib::putf8_writer owrt(ostrm);
+// ----------------------------------------------------------------------------------------
+// Device handling
+// ----------------------------------------------------------------------------------------
- plib::ppreprocessor(&m_defines).process(istrm, owrt);
- plib::pimemstream istrm2(ostrm);
- plib::putf8_reader reader2(istrm2);
- return parser_t(reader2, *this).parse(name);
+void setup_t::delete_empty_nets()
+{
+ m_nlstate.nets().erase(
+ std::remove_if(m_nlstate.nets().begin(), m_nlstate.nets().end(),
+ [](pool_owned_ptr<detail::net_t> &x)
+ {
+ if (x->num_cons() == 0)
+ {
+ x->state().log().verbose("Deleting net {1} ...", x->name());
+ x->state().run_state_manager().remove_save_items(x.get());
+ return true;
+ }
+ else
+ return false;
+ }), m_nlstate.nets().end());
}
-void setup_t::register_define(pstring defstr)
+// ----------------------------------------------------------------------------------------
+// Run preparation
+// ----------------------------------------------------------------------------------------
+
+void setup_t::prepare_to_run()
{
- auto p = defstr.find("=");
- if (p != pstring::npos)
- register_define(defstr.left(p), defstr.substr(p+1));
+ register_dynamic_log_devices();
+
+ /* make sure the solver and parameters are started first! */
+
+ for (auto & e : m_device_factory)
+ {
+ if ( factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
+ || factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
+ {
+ m_nlstate.add_dev(e.first, pool_owned_ptr<device_t>(e.second->Create(m_nlstate, e.first)));
+ }
+ }
+
+ log().debug("Searching for solver and parameters ...\n");
+
+ auto solver = m_nlstate.get_single_device<devices::NETLIB_NAME(solver)>("solver");
+ m_netlist_params = m_nlstate.get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
+
+ /* create devices */
+
+ log().debug("Creating devices ...\n");
+ for (auto & e : m_device_factory)
+ {
+ if ( !factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
+ && !factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
+ {
+ auto dev = pool_owned_ptr<device_t>(e.second->Create(m_nlstate, e.first));
+ m_nlstate.add_dev(dev->name(), std::move(dev));
+ }
+ }
+
+ log().debug("Looking for unknown parameters ...\n");
+ for (auto &p : m_param_values)
+ {
+ auto f = m_params.find(p.first);
+ if (f == m_params.end())
+ {
+ if (plib::endsWith(p.first, pstring(".HINT_NO_DEACTIVATE")))
+ {
+ // FIXME: get device name, check for device
+ }
+ else
+ log().info("Unknown parameter: {}", p.first);
+ }
+ }
+
+ bool use_deactivate = m_netlist_params->m_use_deactivate() ? true : false;
+
+ for (auto &d : m_nlstate.devices())
+ {
+ if (use_deactivate)
+ {
+ auto p = m_param_values.find(d.second->name() + ".HINT_NO_DEACTIVATE");
+ if (p != m_param_values.end())
+ {
+ //FIXME: check for errors ...
+ auto v = plib::pstonum<double>(p->second);
+ if (std::abs(v - std::floor(v)) > 1e-6 )
+ log().fatal(MF_1_HND_VAL_NOT_SUPPORTED, p->second);
+ d.second->set_hint_deactivate(v == 0.0);
+ }
+ }
+ else
+ d.second->set_hint_deactivate(false);
+ }
+
+ /* resolve inputs */
+ resolve_inputs();
+
+ log().verbose("looking for two terms connected to rail nets ...");
+ for (auto & t : m_nlstate.get_device_list<analog::NETLIB_NAME(twoterm)>())
+ {
+ if (t->m_N.net().isRailNet() && t->m_P.net().isRailNet())
+ {
+ log().warning(MW_3_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3,
+ t->name(), t->m_N.net().name(), t->m_P.net().name());
+ t->m_N.net().remove_terminal(t->m_N);
+ t->m_P.net().remove_terminal(t->m_P);
+ m_nlstate.remove_dev(t);
+ }
+ }
+
+ log().verbose("initialize solver ...\n");
+
+ if (solver == nullptr)
+ {
+ for (auto &p : m_nlstate.nets())
+ if (p->is_analog())
+ log().fatal(MF_0_NO_SOLVER);
+ }
else
- register_define(defstr, "1");
+ solver->post_start();
+
+ for (auto &n : m_nlstate.nets())
+ for (auto & term : n->core_terms())
+ {
+ //core_device_t *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object());
+ core_device_t *dev = &term->device();
+ dev->set_default_delegate(*term);
+ }
+
}
// ----------------------------------------------------------------------------------------
// base sources
// ----------------------------------------------------------------------------------------
-bool source_t::parse(const pstring &name)
+bool source_t::parse(nlparse_t &setup, const pstring &name)
{
if (m_type != SOURCE)
return false;
else
{
- auto rstream = stream(name);
- plib::putf8_reader reader(*rstream);
- return m_setup.parse_stream(reader, name);
+ return setup.parse_stream(stream(name), name);
}
}
-std::unique_ptr<plib::pistream> source_string_t::stream(const pstring &name)
+plib::unique_ptr<plib::pistream> source_string_t::stream(const pstring &name)
{
- return plib::make_unique_base<plib::pistream, plib::pimemstream>(m_str.c_str(), m_str.mem_t_size());
+ plib::unused_var(name);
+ return plib::make_unique<plib::pimemstream>(m_str.c_str(), std::strlen(m_str.c_str()));
}
-std::unique_ptr<plib::pistream> source_mem_t::stream(const pstring &name)
+plib::unique_ptr<plib::pistream> source_mem_t::stream(const pstring &name)
{
- return plib::make_unique_base<plib::pistream, plib::pimemstream>(m_str.c_str(), m_str.mem_t_size());
+ plib::unused_var(name);
+ return plib::make_unique<plib::pimemstream>(m_str.c_str(), std::strlen(m_str.c_str()));
}
-std::unique_ptr<plib::pistream> source_file_t::stream(const pstring &name)
+plib::unique_ptr<plib::pistream> source_file_t::stream(const pstring &name)
{
- return plib::make_unique_base<plib::pistream, plib::pifilestream>(m_filename);
+ plib::unused_var(name);
+ return plib::make_unique<plib::pifilestream>(m_filename);
}
-bool source_proc_t::parse(const pstring &name)
+bool source_proc_t::parse(nlparse_t &setup, const pstring &name)
{
if (name == m_setup_func_name)
{
- m_setup_func(setup());
+ m_setup_func(setup);
return true;
}
else
return false;
}
-std::unique_ptr<plib::pistream> source_proc_t::stream(const pstring &name)
+plib::unique_ptr<plib::pistream> source_proc_t::stream(const pstring &name)
{
- std::unique_ptr<plib::pistream> p(nullptr);
+ plib::unused_var(name);
+ plib::unique_ptr<plib::pistream> p(nullptr);
return p;
}
-}
+} // namespace netlist
diff --git a/src/lib/netlist/nl_setup.h b/src/lib/netlist/nl_setup.h
index d0359928711..ed0248a48e6 100644
--- a/src/lib/netlist/nl_setup.h
+++ b/src/lib/netlist/nl_setup.h
@@ -8,18 +8,20 @@
#ifndef NLSETUP_H_
#define NLSETUP_H_
+#include "plib/pparser.h"
+#include "plib/pstream.h"
#include "plib/pstring.h"
#include "plib/putil.h"
-#include "plib/pstream.h"
-#include "plib/pparser.h"
-#include "nl_factory.h"
#include "nl_config.h"
-#include "netlist_types.h"
+#include "nl_factory.h"
+#include "nltypes.h"
+#include <memory>
#include <stack>
+#include <unordered_map>
#include <vector>
-#include <memory>
+
//============================================================
// MACROS / inline netlist definitions
@@ -27,46 +29,46 @@
#define NET_STR(x) # x
-#define NET_MODEL(model) \
+#define NET_MODEL(model) \
setup.register_model(model);
-#define ALIAS(alias, name) \
+#define ALIAS(alias, name) \
setup.register_alias(# alias, # name);
-#define DIPPINS(pin1, ...) \
+#define DIPPINS(pin1, ...) \
setup.register_dippins_arr( # pin1 ", " # __VA_ARGS__);
/* to be used to reference new library truthtable devices */
-#define NET_REGISTER_DEV(type, name) \
+#define NET_REGISTER_DEV(type, name) \
setup.register_dev(# type, # name);
-#define NET_CONNECT(name, input, output) \
+#define NET_CONNECT(name, input, output) \
setup.register_link(# name "." # input, # output);
-#define NET_C(term1, ...) \
+#define NET_C(term1, ...) \
setup.register_link_arr( # term1 ", " # __VA_ARGS__);
-#define PARAM(name, val) \
+#define PARAM(name, val) \
setup.register_param(# name, val);
#define HINT(name, val) \
setup.register_param(# name ".HINT_" # val, 1);
-#define NETDEV_PARAMI(name, param, val) \
+#define NETDEV_PARAMI(name, param, val) \
setup.register_param(# name "." # param, val);
#define NETLIST_NAME(name) netlist ## _ ## name
#define NETLIST_EXTERNAL(name) \
- void NETLIST_NAME(name)(netlist::setup_t &setup);
+ void NETLIST_NAME(name)(netlist::nlparse_t &setup);
#define NETLIST_START(name) \
-void NETLIST_NAME(name)(netlist::setup_t &setup) \
+void NETLIST_NAME(name)(netlist::nlparse_t &setup) \
{
#define NETLIST_END() }
#define LOCAL_SOURCE(name) \
- setup.register_source(plib::make_unique_base<netlist::source_t, netlist::source_proc_t>(setup, # name, &NETLIST_NAME(name)));
+ setup.register_source(plib::make_unique<netlist::source_proc_t>(# name, &NETLIST_NAME(name)));
#define LOCAL_LIB_ENTRY(name) \
LOCAL_SOURCE(name) \
@@ -80,7 +82,7 @@ void NETLIST_NAME(name)(netlist::setup_t &setup) \
NETLIST_NAME(model)(setup); \
setup.namespace_pop();
-#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \
+#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \
setup.register_frontier(# attach, r_in, r_out);
// -----------------------------------------------------------------------------
@@ -98,10 +100,10 @@ void NETLIST_NAME(name)(netlist::setup_t &setup) \
desc.family = "";
#define TT_HEAD(x) \
- desc.desc.push_back(x);
+ desc.desc.emplace_back(x);
#define TT_LINE(x) \
- desc.desc.push_back(x);
+ desc.desc.emplace_back(x);
#define TT_FAMILY(x) \
desc.family = x;
@@ -110,22 +112,23 @@ void NETLIST_NAME(name)(netlist::setup_t &setup) \
setup.tt_factory_create(desc, __FILE__); \
}
-
namespace netlist
{
namespace detail {
class core_terminal_t;
class net_t;
- }
+ } // namespace detail
namespace devices {
class nld_base_proxy;
- }
+ class nld_netlistparams;
+ } // namespace devices
class core_device_t;
class param_t;
class setup_t;
+ class netlist_state_t;
class netlist_t;
class logic_family_desc_t;
class terminal_t;
@@ -136,6 +139,7 @@ namespace netlist
struct tt_desc
{
+ tt_desc() : ni(0), no(0) { }
pstring name;
pstring classname;
unsigned long ni;
@@ -168,138 +172,222 @@ namespace netlist
class source_t
{
public:
+
+ friend class setup_t;
+
enum type_t
{
SOURCE,
DATA
};
- using list_t = std::vector<std::unique_ptr<source_t>>;
+ using list_t = std::vector<plib::unique_ptr<source_t>>;
- source_t(setup_t &setup, const type_t type = SOURCE)
- : m_setup(setup), m_type(type)
+ source_t(const type_t type = SOURCE)
+ : m_type(type)
{}
- virtual ~source_t() { }
+ COPYASSIGNMOVE(source_t, delete)
- virtual bool parse(const pstring &name);
- virtual std::unique_ptr<plib::pistream> stream(const pstring &name) = 0;
+ virtual ~source_t() noexcept = default;
+
+ virtual bool parse(nlparse_t &setup, const pstring &name);
- setup_t &setup() { return m_setup; }
type_t type() const { return m_type; }
+
+ protected:
+ virtual plib::unique_ptr<plib::pistream> stream(const pstring &name) = 0;
+
private:
- setup_t &m_setup;
const type_t m_type;
};
+
// ----------------------------------------------------------------------------------------
- // setup_t
+ // Collection of models
// ----------------------------------------------------------------------------------------
-
- class setup_t : plib::nocopyassignmove
+ class models_t
{
public:
+ void register_model(pstring model_in);
+ /* model / family related */
- using link_t = std::pair<pstring, pstring>;
+ pstring model_value_str(pstring model, pstring entity);
- explicit setup_t(netlist_t &netlist);
- ~setup_t();
+ double model_value(pstring model, pstring entity);
- netlist_t &netlist() { return m_netlist; }
- const netlist_t &netlist() const { return m_netlist; }
+ pstring model_type(pstring model) { return model_value_str(model, "COREMODEL"); }
- pstring build_fqn(const pstring &obj_name) const;
+ private:
+ using model_map_t = std::unordered_map<pstring, pstring>;
- void register_param(const pstring &name, param_t &param);
- pstring get_initial_param_val(const pstring &name, const pstring &def);
- double get_initial_param_val(const pstring &name, const double def);
- int get_initial_param_val(const pstring &name, const int def);
+ void model_parse(const pstring &model, model_map_t &map);
+ pstring model_string(model_map_t &map);
- void register_term(detail::core_terminal_t &obj);
+ std::unordered_map<pstring, pstring> m_models;
+ std::unordered_map<pstring, model_map_t> m_cache;
+ };
- void register_dev(const pstring &classname, const pstring &name);
+ // ----------------------------------------------------------------------------------------
+ // nlparse_t
+ // ----------------------------------------------------------------------------------------
- void register_lib_entry(const pstring &name, const pstring &sourcefile);
+ class nlparse_t
+ {
+ public:
+ using link_t = std::pair<pstring, pstring>;
+
+ nlparse_t(setup_t &netlist, log_type &log);
- void register_model(const pstring &model_in);
+ void register_model(const pstring &model_in) { m_models.register_model(model_in); }
void register_alias(const pstring &alias, const pstring &out);
void register_dippins_arr(const pstring &terms);
-
- void register_alias_nofqn(const pstring &alias, const pstring &out);
-
- void register_link_arr(const pstring &terms);
- void register_link_fqn(const pstring &sin, const pstring &sout);
+ void register_dev(const pstring &classname, const pstring &name);
void register_link(const pstring &sin, const pstring &sout);
-
+ void register_link_arr(const pstring &terms);
void register_param(const pstring &param, const pstring &value);
void register_param(const pstring &param, const double value);
-
+ void register_lib_entry(const pstring &name, const pstring &sourcefile);
void register_frontier(const pstring &attach, const double r_IN, const double r_OUT);
- void remove_connections(const pstring &attach);
-
- bool connect(detail::core_terminal_t &t1, detail::core_terminal_t &t2);
-
- bool device_exists(const pstring &name) const;
-
- param_t *find_param(const pstring &param_in, bool required = true) const;
+ /* register a source */
+ void register_source(plib::unique_ptr<source_t> &&src)
+ {
+ m_sources.push_back(std::move(src));
+ }
- void start_devices();
- void resolve_inputs();
+ void tt_factory_create(tt_desc &desc, const pstring &sourcefile);
/* handle namespace */
void namespace_push(const pstring &aname);
void namespace_pop();
- /* parse a source */
+ /* include other files */
void include(const pstring &netlist_name);
- std::unique_ptr<plib::pistream> get_data_stream(const pstring &name);
+ pstring build_fqn(const pstring &obj_name) const;
+ void register_alias_nofqn(const pstring &alias, const pstring &out);
+
+ /* also called from devices for latebinding connected terminals */
+ void register_link_fqn(const pstring &sin, const pstring &sout);
- bool parse_stream(plib::putf8_reader &istrm, const pstring &name);
+ /* used from netlist.cpp (mame) */
+ bool device_exists(const pstring &name) const;
- /* register a source */
+ /* FIXME: used by source_t - need a different approach at some time */
+ bool parse_stream(plib::unique_ptr<plib::pistream> &&istrm, const pstring &name);
- void register_source(std::unique_ptr<source_t> &&src)
+ void add_define(const pstring &def, const pstring &val)
{
- m_sources.push_back(std::move(src));
+ m_defines.insert({ def, plib::ppreprocessor::define_t(def, val)});
}
- void register_define(pstring def, pstring val) { m_defines.push_back(plib::ppreprocessor::define_t(def, val)); }
- void register_define(pstring defstr);
+ void add_define(const pstring &defstr);
factory::list_t &factory() { return m_factory; }
const factory::list_t &factory() const { return m_factory; }
- /* model / family related */
+ log_type &log() { return m_log; }
+ const log_type &log() const { return m_log; }
+
+ /* FIXME: sources may need access to the netlist parent type
+ * since they may be created in a context in which they don't
+ * have access to their environment.
+ * Example is the MAME memregion source.
+ * We thus need a better approach to creating netlists in a context
+ * other than static procedures.
+ */
+ setup_t &setup() { return m_setup; }
+ const setup_t &setup() const { return m_setup; }
+
+ models_t &models() { return m_models; }
+ const models_t &models() const { return m_models; }
+
+ protected:
+ models_t m_models;
+ std::stack<pstring> m_namespace_stack;
+ std::unordered_map<pstring, pstring> m_alias;
+ std::vector<link_t> m_links;
+ std::unordered_map<pstring, pstring> m_param_values;
+
+ source_t::list_t m_sources;
+
+ factory::list_t m_factory;
+
+ /* need to preserve order of device creation ... */
+ std::vector<std::pair<pstring, factory::element_t *>> m_device_factory;
+
+
+ private:
+ plib::ppreprocessor::defines_map_type m_defines;
+
+ setup_t &m_setup;
+ log_type &m_log;
+ unsigned m_frontier_cnt;
+ };
+
+ // ----------------------------------------------------------------------------------------
+ // setup_t
+ // ----------------------------------------------------------------------------------------
+
+ class setup_t : public nlparse_t
+ {
+ public:
+
+ explicit setup_t(netlist_state_t &nlstate);
+ ~setup_t() noexcept;
+
+ COPYASSIGNMOVE(setup_t, delete)
+
+ netlist_state_t &nlstate() { return m_nlstate; }
+ const netlist_state_t &nlstate() const { return m_nlstate; }
+
+ void register_param_t(const pstring &name, param_t &param);
+
+ pstring get_initial_param_val(const pstring &name, const pstring &def) const;
+
+ void register_term(detail::core_terminal_t &obj);
+
+ void remove_connections(const pstring &attach);
- const pstring model_value_str(detail::model_map_t &map, const pstring &entity);
- double model_value(detail::model_map_t &map, const pstring &entity);
+ bool connect(detail::core_terminal_t &t1, detail::core_terminal_t &t2);
- void model_parse(const pstring &model, detail::model_map_t &map);
+ param_t *find_param(const pstring &param_in, bool required = true) const;
+ /* get family */
const logic_family_desc_t *family_from_model(const pstring &model);
- void tt_factory_create(tt_desc &desc, const pstring &sourcefile);
+ void register_dynamic_log_devices();
+ void resolve_inputs();
+
+ plib::unique_ptr<plib::pistream> get_data_stream(const pstring &name);
+
+ factory::list_t &factory() { return m_factory; }
+ const factory::list_t &factory() const { return m_factory; }
/* helper - also used by nltool */
const pstring resolve_alias(const pstring &name) const;
- plib::plog_base<netlist_t, NL_DEBUG> &log();
- const plib::plog_base<netlist_t, NL_DEBUG> &log() const;
-
- std::vector<std::pair<pstring, factory::element_t *>> m_device_factory;
+ /* needed by nltool */
+ std::vector<pstring> get_terminals_for_device_name(const pstring &devname);
- std::unordered_map<pstring, pstring> m_alias;
- std::unordered_map<pstring, pstring> m_param_values;
- std::unordered_map<pstring, detail::core_terminal_t *> m_terminals;
+ log_type &log();
+ const log_type &log() const;
/* needed by proxy */
detail::core_terminal_t *find_terminal(const pstring &outname_in, const detail::terminal_type atype, bool required = true);
+ /* core net handling */
+
+ void delete_empty_nets();
+
+ /* run preparation */
+
+ void prepare_to_run();
+
private:
detail::core_terminal_t *find_terminal(const pstring &outname_in, bool required = true);
@@ -318,35 +406,30 @@ namespace netlist
devices::nld_base_proxy *get_d_a_proxy(detail::core_terminal_t &out);
devices::nld_base_proxy *get_a_d_proxy(detail::core_terminal_t &inp);
- netlist_t &m_netlist;
- std::unordered_map<pstring, param_ref_t> m_params;
- std::vector<link_t> m_links;
- factory::list_t m_factory;
- std::unordered_map<pstring, pstring> m_models;
+ std::unordered_map<pstring, detail::core_terminal_t *> m_terminals;
- std::stack<pstring> m_namespace_stack;
- source_t::list_t m_sources;
- std::vector<plib::ppreprocessor::define_t> m_defines;
+ netlist_state_t &m_nlstate;
+ devices::nld_netlistparams *m_netlist_params;
+ std::unordered_map<pstring, param_ref_t> m_params;
unsigned m_proxy_cnt;
- unsigned m_frontier_cnt;
-};
+ };
// ----------------------------------------------------------------------------------------
// base sources
// ----------------------------------------------------------------------------------------
-
class source_string_t : public source_t
{
public:
- source_string_t(setup_t &setup, const pstring &source)
- : source_t(setup), m_str(source)
+ source_string_t(const pstring &source)
+ : source_t(), m_str(source)
{
}
- virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override;
+ protected:
+ plib::unique_ptr<plib::pistream> stream(const pstring &name) override;
private:
pstring m_str;
@@ -356,12 +439,13 @@ namespace netlist
{
public:
- source_file_t(setup_t &setup, const pstring &filename)
- : source_t(setup), m_filename(filename)
+ source_file_t(const pstring &filename)
+ : source_t(), m_filename(filename)
{
}
- virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override;
+ protected:
+ plib::unique_ptr<plib::pistream> stream(const pstring &name) override;
private:
pstring m_filename;
@@ -370,12 +454,13 @@ namespace netlist
class source_mem_t : public source_t
{
public:
- source_mem_t(setup_t &setup, const char *mem)
- : source_t(setup), m_str(mem, pstring::UTF8)
+ source_mem_t(const char *mem)
+ : source_t(), m_str(mem)
{
}
- virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override;
+ protected:
+ plib::unique_ptr<plib::pistream> stream(const pstring &name) override;
private:
pstring m_str;
@@ -384,22 +469,28 @@ namespace netlist
class source_proc_t : public source_t
{
public:
- source_proc_t(setup_t &setup, pstring name, void (*setup_func)(setup_t &))
- : source_t(setup),
+ source_proc_t(const pstring &name, void (*setup_func)(nlparse_t &))
+ : source_t(),
m_setup_func(setup_func),
m_setup_func_name(name)
{
}
- virtual bool parse(const pstring &name) override;
- virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override;
+ bool parse(nlparse_t &setup, const pstring &name) override;
+
+ protected:
+ plib::unique_ptr<plib::pistream> stream(const pstring &name) override;
private:
- void (*m_setup_func)(setup_t &);
+ void (*m_setup_func)(nlparse_t &);
pstring m_setup_func_name;
};
-}
+ // -----------------------------------------------------------------------------
+ // inline implementations
+ // -----------------------------------------------------------------------------
+
+} // namespace netlist
#endif /* NLSETUP_H_ */
diff --git a/src/lib/netlist/nl_time.h b/src/lib/netlist/nl_time.h
deleted file mode 100644
index 7c81f890e07..00000000000
--- a/src/lib/netlist/nl_time.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Couriersud
-/*
- * nltime.h
- */
-
-#ifndef NLTIME_H_
-#define NLTIME_H_
-
-#include "nl_config.h"
-#include "plib/ptypes.h"
-#include "plib/pstate.h"
-
-#include <cstdint>
-
-//============================================================
-// MACROS
-//============================================================
-
-#define NLTIME_FROM_NS(t) netlist_time::from_nsec(t)
-#define NLTIME_FROM_US(t) netlist_time::from_usec(t)
-#define NLTIME_FROM_MS(t) netlist_time::from_msec(t)
-#define NLTIME_IMMEDIATE netlist_time::from_nsec(1)
-
-// ----------------------------------------------------------------------------------------
-// netlist_time
-// ----------------------------------------------------------------------------------------
-
-namespace netlist
-{
- template <typename TYPE, TYPE RES>
- struct ptime final
- {
- public:
-
- using internal_type = TYPE;
- using mult_type = std::uint64_t;
-
- constexpr ptime() noexcept : m_time(0) {}
-
- constexpr ptime(const ptime &rhs) noexcept = default;
- constexpr ptime(ptime &&rhs) noexcept = default;
- C14CONSTEXPR ptime &operator=(const ptime &rhs) noexcept = default;
- C14CONSTEXPR ptime &operator=(ptime &&rhs) noexcept = default;
-
- constexpr explicit ptime(const double t) = delete;
- //: m_time((internal_type) ( t * (double) resolution)) { }
- constexpr explicit ptime(const internal_type &nom, const internal_type &den) noexcept
- : m_time(nom * (RES / den)) { }
-
- C14CONSTEXPR ptime &operator+=(const ptime &rhs) noexcept { m_time += rhs.m_time; return *this; }
- C14CONSTEXPR ptime &operator-=(const ptime &rhs) noexcept { m_time -= rhs.m_time; return *this; }
- C14CONSTEXPR ptime &operator*=(const mult_type &factor) noexcept { m_time *= static_cast<internal_type>(factor); return *this; }
-
- friend C14CONSTEXPR ptime operator-(ptime lhs, const ptime &rhs) noexcept
- {
- return lhs -= rhs;
- }
-
- friend C14CONSTEXPR ptime operator+(ptime lhs, const ptime &rhs) noexcept
- {
- return lhs += rhs;
- }
-
- friend C14CONSTEXPR ptime operator*(ptime lhs, const mult_type &factor) noexcept
- {
- return lhs *= factor;
- }
-
- friend constexpr mult_type operator/(const ptime &lhs, const ptime &rhs) noexcept
- {
- return static_cast<mult_type>(lhs.m_time / rhs.m_time);
- }
-
- friend constexpr bool operator<(const ptime &lhs, const ptime &rhs) noexcept
- {
- return (lhs.m_time < rhs.m_time);
- }
-
- friend constexpr bool operator>(const ptime &lhs, const ptime &rhs) noexcept
- {
- return (rhs < lhs);
- }
-
- friend constexpr bool operator<=(const ptime &lhs, const ptime &rhs) noexcept
- {
- return !(lhs > rhs);
- }
-
- friend constexpr bool operator>=(const ptime &lhs, const ptime &rhs) noexcept
- {
- return !(lhs < rhs);
- }
-
- friend constexpr bool operator==(const ptime &lhs, const ptime &rhs) noexcept
- {
- return lhs.m_time == rhs.m_time;
- }
-
- friend constexpr bool operator!=(const ptime &lhs, const ptime &rhs) noexcept
- {
- return !(lhs == rhs);
- }
-
- constexpr internal_type as_raw() const noexcept { return m_time; }
- constexpr double as_double() const noexcept
- {
- return static_cast<double>(m_time) / static_cast<double>(RES);
- }
-
- // for save states ....
- C14CONSTEXPR internal_type *get_internaltype_ptr() noexcept { return &m_time; }
-
- static constexpr ptime from_nsec(const internal_type &ns) noexcept { return ptime(ns, UINT64_C(1000000000)); }
- static constexpr ptime from_usec(const internal_type &us) noexcept { return ptime(us, UINT64_C(1000000)); }
- static constexpr ptime from_msec(const internal_type &ms) noexcept { return ptime(ms, UINT64_C(1000)); }
- static constexpr ptime from_hz(const internal_type &hz) noexcept { return ptime(1 , hz); }
- static constexpr ptime from_raw(const internal_type &raw) noexcept { return ptime(raw); }
- static constexpr ptime from_double(const double t) noexcept { return ptime(static_cast<internal_type>( t * static_cast<double>(RES)), RES); }
-
- static constexpr ptime zero() noexcept { return ptime(0, RES); }
- static constexpr ptime quantum() noexcept { return ptime(1, RES); }
- static constexpr ptime never() noexcept { return ptime(plib::numeric_limits<internal_type>::max(), RES); }
- static constexpr internal_type resolution() noexcept { return RES; }
- private:
- constexpr explicit ptime(const internal_type &time) : m_time(time) {}
- constexpr explicit ptime(internal_type &&time) : m_time(time) {}
- internal_type m_time;
- };
-
-#if (PHAS_INT128)
- using netlist_time = ptime<UINT128, NETLIST_INTERNAL_RES>;
-#else
- using netlist_time = ptime<std::uint64_t, NETLIST_INTERNAL_RES>;
-#endif
-}
-
-namespace plib {
-template<> inline void state_manager_t::save_item(const void *owner, netlist::netlist_time &nlt, const pstring &stname)
-{
- save_state_ptr(owner, stname, datatype_t(sizeof(netlist::netlist_time::internal_type), true, false), 1, nlt.get_internaltype_ptr());
-}
-}
-
-#endif /* NLTIME_H_ */
diff --git a/src/lib/netlist/nltypes.h b/src/lib/netlist/nltypes.h
new file mode 100644
index 00000000000..7d7582774b1
--- /dev/null
+++ b/src/lib/netlist/nltypes.h
@@ -0,0 +1,147 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*!
+ *
+ * \file nltypes.h
+ *
+ */
+
+/* \note never change the name to nl_types.h. This creates a conflict
+ * with nl_types.h file provided by libc++ (clang, macosx)
+ */
+
+#ifndef NLTYPES_H_
+#define NLTYPES_H_
+
+#include "nl_config.h"
+#include "plib/pchrono.h"
+#include "plib/pfmtlog.h"
+#include "plib/pmempool.h"
+#include "plib/pstate.h"
+#include "plib/pstring.h"
+#include "plib/ptime.h"
+#include "plib/putil.h"
+
+#include <cstdint>
+#include <unordered_map>
+
+namespace netlist
+{
+ /*! @brief plib::constants struct specialized for nl_double
+ *
+ * This may be any of bool, uint8_t, uint16_t, uin32_t and uint64_t.
+ * The choice has little to no impact on performance.
+ */
+ using constants = plib::constants<nl_double>;
+
+ /*! @brief netlist_sig_t is the type used for logic signals.
+ *
+ * This may be any of bool, uint8_t, uint16_t, uin32_t and uint64_t.
+ * The choice has little to no impact on performance.
+ */
+ using netlist_sig_t = std::uint32_t;
+
+ /* FIXME: belongs into nl_base.h to nlstate */
+ /**
+ * @brief Interface definition for netlist callbacks into calling code
+ *
+ * A class inheriting from netlist_callbacks_t has to be passed to the netlist_t
+ * constructor. Netlist does processing during construction and thus needs
+ * the object passed completely constructed.
+ *
+ */
+ class callbacks_t
+ {
+ public:
+
+ callbacks_t() = default;
+ /* what is done before this is passed as a unique_ptr to netlist
+ * we should not limit.
+ */
+ virtual ~callbacks_t() = default;
+ COPYASSIGNMOVE(callbacks_t, default)
+
+ /* logging callback */
+ virtual void vlog(const plib::plog_level &l, const pstring &ls) const = 0;
+
+ };
+
+ using log_type = plib::plog_base<callbacks_t, NL_DEBUG>;
+
+
+ //============================================================
+ // Performance tracking
+ //============================================================
+
+ template<bool enabled_>
+ using nperftime_t = plib::chrono::timer<plib::chrono::exact_ticks, enabled_>;
+
+ template<bool enabled_>
+ using nperfcount_t = plib::chrono::counter<enabled_>;
+
+ //============================================================
+ // Types needed by various includes
+ //============================================================
+
+ /*! The memory pool for netlist objects
+ *
+ * \note This is not the right location yet.
+ *
+ */
+
+#if (USE_MEMPOOL)
+ using nlmempool = plib::mempool;
+#else
+ using nlmempool = plib::aligned_arena;
+#endif
+
+ /*! Owned pointer type for pooled allocations.
+ *
+ */
+ template <typename T>
+ using pool_owned_ptr = nlmempool::owned_pool_ptr<T>;
+
+ inline nlmempool &pool()
+ {
+ static nlmempool static_pool;
+ return static_pool;
+ }
+
+ namespace detail {
+
+ /*! Enum specifying the type of object */
+ enum terminal_type {
+ TERMINAL = 0, /*!< object is an analog terminal */
+ INPUT = 1, /*!< object is an input */
+ OUTPUT = 2, /*!< object is an output */
+ };
+
+ } // namespace detail
+
+#if (PHAS_INT128)
+ using netlist_time = ptime<INT128, NETLIST_INTERNAL_RES>;
+#else
+ using netlist_time = plib::ptime<std::int64_t, NETLIST_INTERNAL_RES>;
+ static_assert(noexcept(netlist_time::from_nsec(1)) == true, "Not evaluated as constexpr");
+#endif
+
+ //============================================================
+ // MACROS
+ //============================================================
+
+ template <typename T> inline constexpr const netlist_time NLTIME_FROM_NS(T &&t) noexcept { return netlist_time::from_nsec(t); }
+ template <typename T> inline constexpr const netlist_time NLTIME_FROM_US(T &&t) noexcept { return netlist_time::from_usec(t); }
+ template <typename T> inline constexpr const netlist_time NLTIME_FROM_MS(T &&t) noexcept { return netlist_time::from_msec(t); }
+
+} // namespace netlist
+
+namespace plib {
+
+ template<>
+ inline void state_manager_t::save_item(const void *owner, netlist::netlist_time &nlt, const pstring &stname)
+ {
+ save_state_ptr(owner, stname, datatype_t(sizeof(netlist::netlist_time::internal_type), true, false), 1, nlt.get_internaltype_ptr());
+ }
+} // namespace plib
+
+#endif /* NLTYPES_H_ */
diff --git a/src/lib/netlist/plib/gmres.h b/src/lib/netlist/plib/gmres.h
new file mode 100644
index 00000000000..2c357e97624
--- /dev/null
+++ b/src/lib/netlist/plib/gmres.h
@@ -0,0 +1,450 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * gmres.h
+ *
+ */
+
+#ifndef PLIB_GMRES_H_
+#define PLIB_GMRES_H_
+
+#include "mat_cr.h"
+#include "parray.h"
+#include "pconfig.h"
+#include "vector_ops.h"
+
+#include <algorithm>
+#include <cmath>
+
+
+namespace plib
+{
+
+ template <typename FT, int SIZE>
+ struct mat_precondition_ILU
+ {
+ using mat_type = plib::matrix_compressed_rows_t<FT, SIZE>;
+
+ mat_precondition_ILU(std::size_t size, int ilu_scale = 4
+ , std::size_t bw = plib::matrix_compressed_rows_t<FT, SIZE>::FILL_INFINITY)
+ : m_mat(static_cast<typename mat_type::index_type>(size))
+ , m_LU(static_cast<typename mat_type::index_type>(size))
+ , m_use_iLU_preconditioning(ilu_scale >= 0)
+ , m_ILU_scale(static_cast<std::size_t>(ilu_scale))
+ , m_band_width(bw)
+ {
+ }
+
+ template <typename M>
+ void build(M &fill)
+ {
+ m_mat.build_from_fill_mat(fill, 0);
+ if (m_use_iLU_preconditioning)
+ {
+ m_LU.gaussian_extend_fill_mat(fill);
+ m_LU.build_from_fill_mat(fill, m_ILU_scale, m_band_width); // ILU(2)
+ //m_LU.build_from_fill_mat(fill, 9999, 20); // Band matrix width 20
+ }
+ }
+
+
+ template<typename R, typename V>
+ void calc_rhs(R &rhs, const V &v)
+ {
+ m_mat.mult_vec(rhs, v);
+ }
+
+ void precondition()
+ {
+ if (m_use_iLU_preconditioning)
+ {
+ if (m_ILU_scale < 1)
+ m_LU.raw_copy_from(m_mat);
+ else
+ m_LU.reduction_copy_from(m_mat);
+ m_LU.incomplete_LU_factorization();
+ }
+ }
+
+ template<typename V>
+ void solve_LU_inplace(V &v)
+ {
+ if (m_use_iLU_preconditioning)
+ {
+ m_LU.solveLUx(v);
+ }
+ }
+
+ PALIGNAS_VECTOROPT()
+ mat_type m_mat;
+ PALIGNAS_VECTOROPT()
+ mat_type m_LU;
+ bool m_use_iLU_preconditioning;
+ std::size_t m_ILU_scale;
+ std::size_t m_band_width;
+ };
+
+ template <typename FT, int SIZE>
+ struct mat_precondition_diag
+ {
+ mat_precondition_diag(std::size_t size)
+ : m_mat(size)
+ , m_diag(size)
+ , m_use_iLU_preconditioning(true)
+ {
+ }
+
+ template <typename M>
+ void build(M &fill)
+ {
+ m_mat.build_from_fill_mat(fill, 0);
+ }
+
+ template<typename R, typename V>
+ void calc_rhs(R &rhs, const V &v)
+ {
+ m_mat.mult_vec(rhs, v);
+ }
+
+ void precondition()
+ {
+ if (m_use_iLU_preconditioning)
+ {
+ for (std::size_t i = 0; i< m_diag.size(); i++)
+ {
+ m_diag[i] = 1.0 / m_mat.A[m_mat.diag[i]];
+ }
+ }
+ }
+
+ template<typename V>
+ void solve_LU_inplace(V &v)
+ {
+ if (m_use_iLU_preconditioning)
+ {
+ for (std::size_t i = 0; i< m_diag.size(); i++)
+ v[i] = v[i] * m_diag[i];
+ }
+ }
+
+ plib::matrix_compressed_rows_t<FT, SIZE> m_mat;
+ plib::parray<FT, SIZE> m_diag;
+ bool m_use_iLU_preconditioning;
+ };
+
+ /* FIXME: hardcoding RESTART to 20 becomes an issue on very large
+ * systems.
+ */
+ template <typename FT, int SIZE, int RESTART = 20>
+ struct gmres_t
+ {
+ public:
+
+ using float_type = FT;
+ // FIXME: dirty hack to make this compile
+ static constexpr const std::size_t storage_N = plib::sizeabs<FT, SIZE>::ABS();
+
+ gmres_t(std::size_t size)
+ : residual(size)
+ , Ax(size)
+ , m_size(size)
+ , m_use_more_precise_stop_condition(false)
+ {
+ }
+
+ void givens_mult( const FT c, const FT s, FT & g0, FT & g1 )
+ {
+ const FT g0_last(g0);
+
+ g0 = c * g0 - s * g1;
+ g1 = s * g0_last + c * g1;
+ }
+
+ std::size_t size() const { return (SIZE<=0) ? m_size : static_cast<std::size_t>(SIZE); }
+
+ template <typename OPS, typename VT, typename VRHS>
+ std::size_t solve(OPS &ops, VT &x, const VRHS & rhs, const std::size_t itr_max, float_type accuracy)
+ {
+ /*-------------------------------------------------------------------------
+ * The code below was inspired by code published by John Burkardt under
+ * the LPGL here:
+ *
+ * http://people.sc.fsu.edu/~jburkardt/cpp_src/mgmres/mgmres.html
+ *
+ * The code below was completely written from scratch based on the pseudo code
+ * found here:
+ *
+ * http://de.wikipedia.org/wiki/GMRES-Verfahren
+ *
+ * The Algorithm itself is described in
+ *
+ * Yousef Saad,
+ * Iterative Methods for Sparse Linear Systems,
+ * Second Edition,
+ * SIAM, 20003,
+ * ISBN: 0898715342,
+ * LC: QA188.S17.
+ *
+ *------------------------------------------------------------------------*/
+
+ std::size_t itr_used = 0;
+ double rho_delta = 0.0;
+
+ const std::size_t n = size();
+
+ ops.precondition();
+
+ if (m_use_more_precise_stop_condition)
+ {
+ /* derive residual for a given delta x
+ *
+ * LU y = A dx
+ *
+ * ==> rho / accuracy = sqrt(y * y)
+ *
+ * This approach will approximate the iterative stop condition
+ * based |xnew - xold| pretty precisely. But it is slow, or expressed
+ * differently: The invest doesn't pay off.
+ */
+
+ vec_set_scalar(n, residual, accuracy);
+ ops.calc_rhs(Ax, residual);
+
+ ops.solve_LU_inplace(Ax);
+
+ const float_type rho_to_accuracy = std::sqrt(vec_mult2<FT>(n, Ax)) / accuracy;
+
+ rho_delta = accuracy * rho_to_accuracy;
+ }
+ else
+ rho_delta = accuracy * std::sqrt(static_cast<FT>(n));
+
+ /*
+ * Using
+ *
+ * vec_set(n, x, rhs);
+ * ops.solve_LU_inplace(x);
+ *
+ * to get a starting point for x degrades convergence speed compared
+ * to using the last solution for x.
+ *
+ * LU x = b; solve for x;
+ *
+ */
+
+ while (itr_used < itr_max)
+ {
+ std::size_t last_k = RESTART;
+ float_type rho;
+
+ ops.calc_rhs(Ax, x);
+
+ vec_sub(n, residual, rhs, Ax);
+
+ ops.solve_LU_inplace(residual);
+
+ rho = std::sqrt(vec_mult2<FT>(n, residual));
+
+ if (rho < rho_delta)
+ return itr_used + 1;
+
+ /* FIXME: The "+" is necessary to avoid link issues
+ * on some systems / compiler versions. Issue reported by
+ * AJR, no details known yet.
+ */
+ vec_set_scalar(RESTART+1, m_g, +constants<FT>::zero());
+ m_g[0] = rho;
+
+ //for (std::size_t i = 0; i < mr + 1; i++)
+ // vec_set_scalar(mr, m_ht[i], NL_FCONST(0.0));
+
+ vec_mult_scalar(n, m_v[0], residual, constants<FT>::one() / rho);
+
+ for (std::size_t k = 0; k < RESTART; k++)
+ {
+ const std::size_t kp1 = k + 1;
+
+ ops.calc_rhs(m_v[kp1], m_v[k]);
+ ops.solve_LU_inplace(m_v[kp1]);
+
+ for (std::size_t j = 0; j <= k; j++)
+ {
+ m_ht[j][k] = vec_mult<FT>(n, m_v[kp1], m_v[j]);
+ vec_add_mult_scalar(n, m_v[kp1], m_v[j], -m_ht[j][k]);
+ }
+ m_ht[kp1][k] = std::sqrt(vec_mult2<FT>(n, m_v[kp1]));
+
+ if (m_ht[kp1][k] != 0.0)
+ vec_scale(n, m_v[kp1], constants<FT>::one() / m_ht[kp1][k]);
+
+ for (std::size_t j = 0; j < k; j++)
+ givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]);
+
+ const float_type mu = 1.0 / std::hypot(m_ht[k][k], m_ht[kp1][k]);
+
+ m_c[k] = m_ht[k][k] * mu;
+ m_s[k] = -m_ht[kp1][k] * mu;
+ m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[kp1][k];
+ m_ht[kp1][k] = 0.0;
+
+ givens_mult(m_c[k], m_s[k], m_g[k], m_g[kp1]);
+
+ rho = std::abs(m_g[kp1]);
+
+ itr_used = itr_used + 1;
+
+ if (rho <= rho_delta)
+ {
+ last_k = k;
+ break;
+ }
+ }
+
+ if (last_k >= RESTART)
+ /* didn't converge within accuracy */
+ last_k = RESTART - 1;
+
+ /* Solve the system H * y = g */
+ /* x += m_v[j] * m_y[j] */
+ for (std::size_t i = last_k + 1; i-- > 0;)
+ {
+ double tmp = m_g[i];
+ for (std::size_t j = i + 1; j <= last_k; j++)
+ tmp -= m_ht[i][j] * m_y[j];
+ m_y[i] = tmp / m_ht[i][i];
+ }
+
+ for (std::size_t i = 0; i <= last_k; i++)
+ vec_add_mult_scalar(n, x, m_v[i], m_y[i]);
+
+ if (rho <= rho_delta)
+ break;
+
+ }
+ return itr_used;
+ }
+
+ private:
+
+ //typedef typename plib::mat_cr_t<FT, SIZE>::index_type mattype;
+
+ plib::parray<float_type, SIZE> residual;
+ plib::parray<float_type, SIZE> Ax;
+
+ plib::parray<float_type, RESTART + 1> m_c; /* mr + 1 */
+ plib::parray<float_type, RESTART + 1> m_g; /* mr + 1 */
+ plib::parray<plib::parray<float_type, RESTART>, RESTART + 1> m_ht; /* (mr + 1), mr */
+ plib::parray<float_type, RESTART + 1> m_s; /* mr + 1 */
+ plib::parray<float_type, RESTART + 1> m_y; /* mr + 1 */
+
+ //plib::parray<float_type, SIZE> m_v[RESTART + 1]; /* mr + 1, n */
+ plib::parray<plib::parray<float_type, storage_N>, RESTART + 1> m_v; /* mr + 1, n */
+
+ std::size_t m_size;
+
+ bool m_use_more_precise_stop_condition;
+
+
+ };
+
+
+#if 0
+ /* Example of a Chebyshev iteration solver. This one doesn't work yet,
+ * it needs to be extended for non-symmetric matrix operation and
+ * depends on spectral radius estimates - which we don't have.
+ *
+ * Left here as another example.
+ */
+
+ template <typename FT, int SIZE>
+ struct ch_t
+ {
+ public:
+
+ typedef FT float_type;
+ // FIXME: dirty hack to make this compile
+ static constexpr const std::size_t storage_N = plib::sizeabs<FT, SIZE>::ABS();
+
+ // Maximum iterations before a restart ...
+ static constexpr const std::size_t restart_N = (storage_N > 0 ? 20 : 0);
+
+ ch_t(std::size_t size)
+ : residual(size)
+ , Ax(size)
+ , m_size(size)
+ {
+ }
+
+ std::size_t size() const { return (SIZE<=0) ? m_size : static_cast<std::size_t>(SIZE); }
+
+ template <typename OPS, typename VT, typename VRHS>
+ std::size_t solve(OPS &ops, VT &x0, const VRHS & rhs, const std::size_t iter_max, float_type accuracy)
+ {
+ /*-------------------------------------------------------------------------
+ *
+ *
+ *------------------------------------------------------------------------*/
+
+ ops.precondition();
+
+ const FT lmax = 20.0;
+ const FT lmin = 0.0001;
+
+ const FT d = (lmax+lmin)/2.0;
+ const FT c = (lmax-lmin)/2.0;
+ FT alpha = 0;
+ FT beta = 0;
+ std::size_t itr_used = 0;
+
+ plib::parray<FT, SIZE> x(size());
+ plib::parray<FT, SIZE> p(size());
+
+ plib::vec_set(size(), x, x0);
+
+ ops.calc_rhs(Ax, x);
+ vec_sub(size(), rhs, Ax, residual);
+
+ FT rho_delta = accuracy * std::sqrt(static_cast<FT>(size()));
+
+ rho_delta = 1e-9;
+
+ for (int i = 0; i < iter_max; i++)
+ {
+ ops.solve_LU_inplace(residual);
+ if (i==0)
+ {
+ vec_set(size(), p, residual);
+ alpha = 2.0 / d;
+ }
+ else
+ {
+ beta = alpha * ( c / 2.0)*( c / 2.0);
+ alpha = 1.0 / (d - beta);
+ for (std::size_t k = 0; k < size(); k++)
+ p[k] = residual[k] + beta * p[k];
+ }
+ plib::vec_add_mult_scalar(size(), p, alpha, x);
+ ops.calc_rhs(Ax, x);
+ plib::vec_sub(size(), rhs, Ax, residual);
+ FT rho = std::sqrt(plib::vec_mult2<FT>(size(), residual));
+ if (rho < rho_delta)
+ break;
+ itr_used++;
+ }
+ return itr_used;
+ }
+ private:
+
+ //typedef typename plib::mat_cr_t<FT, SIZE>::index_type mattype;
+
+ plib::parray<float_type, SIZE> residual;
+ plib::parray<float_type, SIZE> Ax;
+
+ std::size_t m_size;
+
+ };
+#endif
+
+} // namespace plib
+
+#endif /* PLIB_GMRES_H_ */
diff --git a/src/lib/netlist/plib/mat_cr.h b/src/lib/netlist/plib/mat_cr.h
new file mode 100644
index 00000000000..4cc027f0d8f
--- /dev/null
+++ b/src/lib/netlist/plib/mat_cr.h
@@ -0,0 +1,530 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * mat_cr.h
+ *
+ * Compressed row format matrices
+ *
+ */
+
+#ifndef MAT_CR_H_
+#define MAT_CR_H_
+
+#include "palloc.h"
+#include "parray.h"
+#include "pconfig.h"
+#include "pomp.h"
+#include "pstate.h"
+#include "ptypes.h"
+#include "putil.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <cstdlib>
+#include <type_traits>
+#include <vector>
+
+namespace plib
+{
+
+ // FIXME: causes a crash with GMRES handler
+ // template<typename T, int N, typename C = std::size_t>
+
+ template<typename T, int N, typename C = uint16_t>
+ struct matrix_compressed_rows_t
+ {
+ using index_type = C;
+ using value_type = T;
+
+ COPYASSIGNMOVE(matrix_compressed_rows_t, default)
+
+ enum constants_e
+ {
+ FILL_INFINITY = 9999999
+ };
+
+ parray<index_type, N> diag; // diagonal index pointer n
+ parray<index_type, (N == 0) ? 0 : (N < 0 ? N - 1 : N + 1)> row_idx; // row index pointer n + 1
+ parray<index_type, N < 0 ? -N * N : N *N> col_idx; // column index array nz_num, initially (n * n)
+ parray<value_type, N < 0 ? -N * N : N *N> A; // Matrix elements nz_num, initially (n * n)
+ //parray<C, N < 0 ? -N * (N-1) / 2 : N * (N+1) / 2 > nzbd; // Support for gaussian elimination
+ parray<std::vector<index_type>, N > nzbd; // Support for gaussian elimination
+ // contains elimination rows below the diagonal
+ // FIXME: convert to pvector
+ std::vector<std::vector<index_type>> m_ge_par;
+
+ index_type nz_num;
+
+ explicit matrix_compressed_rows_t(const index_type n)
+ : diag(n)
+ , row_idx(n+1)
+ , col_idx(n*n)
+ , A(n*n)
+ //, nzbd(n * (n+1) / 2)
+ , nzbd(n)
+ , nz_num(0)
+ , m_size(n)
+ {
+ for (index_type i=0; i<n+1; i++)
+ row_idx[i] = 0;
+ }
+
+ ~matrix_compressed_rows_t() = default;
+
+ constexpr index_type size() const { return static_cast<index_type>((N>0) ? N : m_size); }
+
+ void clear()
+ {
+ nz_num = 0;
+ for (index_type i=0; i < size() + 1; i++)
+ row_idx[i] = 0;
+ }
+
+ void set_scalar(const T scalar)
+ {
+ for (index_type i=0, e=nz_num; i<e; i++)
+ A[i] = scalar;
+ }
+
+ void set(C r, C c, T val)
+ {
+ C ri = row_idx[r];
+ while (ri < row_idx[r+1] && col_idx[ri] < c)
+ ri++;
+ // we have the position now;
+ if (ri < row_idx[r+1] && col_idx[ri] == c)
+ A[ri] = val;
+ else
+ {
+ for (C i = nz_num; i>ri; i--)
+ {
+ A[i] = A[i-1];
+ col_idx[i] = col_idx[i-1];
+ }
+ A[ri] = val;
+ col_idx[ri] = c;
+ for (C i = r + 1; i < size() + 1; i++)
+ row_idx[i]++;
+ nz_num++;
+ if (c==r)
+ diag[r] = ri;
+ }
+ }
+
+ template <typename M>
+ std::pair<std::size_t, std::size_t> gaussian_extend_fill_mat(M &fill)
+ {
+ std::size_t ops = 0;
+ std::size_t fill_max = 0;
+
+ for (std::size_t k = 0; k < fill.size(); k++)
+ {
+ ops++; // 1/A(k,k)
+ for (std::size_t row = k + 1; row < fill.size(); row++)
+ {
+ if (fill[row][k] < FILL_INFINITY)
+ {
+ ops++;
+ for (std::size_t col = k + 1; col < fill[row].size(); col++)
+ //if (fill[k][col] < FILL_INFINITY)
+ {
+ auto f = std::min(fill[row][col], 1 + fill[row][k] + fill[k][col]);
+ if (f < FILL_INFINITY)
+ {
+ if (f > fill_max)
+ fill_max = f;
+ ops += 2;
+ }
+ fill[row][col] = f;
+ }
+ }
+ }
+ }
+ build_parallel_gaussian_execution_scheme(fill);
+ return { fill_max, ops };
+ }
+
+ template <typename M>
+ void build_from_fill_mat(const M &f, std::size_t max_fill = FILL_INFINITY - 1,
+ std::size_t band_width = FILL_INFINITY)
+ {
+ C nz = 0;
+ if (nz_num != 0)
+ throw pexception("build_from_mat only allowed on empty CR matrix");
+ for (std::size_t k=0; k < size(); k++)
+ {
+ row_idx[k] = nz;
+
+ for (std::size_t j=0; j < size(); j++)
+ if (f[k][j] <= max_fill && std::abs(static_cast<int>(k)-static_cast<int>(j)) <= static_cast<int>(band_width))
+ {
+ col_idx[nz] = static_cast<C>(j);
+ if (j == k)
+ diag[k] = nz;
+ nz++;
+ }
+ }
+
+ row_idx[size()] = nz;
+ nz_num = nz;
+ /* build nzbd */
+
+ for (std::size_t k=0; k < size(); k++)
+ {
+ for (std::size_t j=k + 1; j < size(); j++)
+ if (f[j][k] < FILL_INFINITY)
+ nzbd[k].push_back(static_cast<C>(j));
+ nzbd[k].push_back(0); // end of sequence
+ }
+ }
+
+ template <typename V>
+ void gaussian_elimination(V & RHS)
+ {
+ const std::size_t iN = size();
+
+ for (std::size_t i = 0; i < iN - 1; i++)
+ {
+ std::size_t nzbdp = 0;
+ std::size_t pi = diag[i];
+ const value_type f = 1.0 / A[pi++];
+ const std::size_t piie = row_idx[i+1];
+ const auto &nz = nzbd[i];
+
+ while (auto j = nz[nzbdp++])
+ {
+ // proceed to column i
+
+ std::size_t pj = row_idx[j];
+
+ while (col_idx[pj] < i)
+ pj++;
+
+ const value_type f1 = - A[pj++] * f;
+
+ // subtract row i from j
+ // fill-in available assumed, i.e. matrix was prepared
+
+ for (std::size_t pii = pi; pii<piie; pii++)
+ {
+ while (col_idx[pj] < col_idx[pii])
+ pj++;
+ if (col_idx[pj] == col_idx[pii])
+ A[pj++] += A[pii] * f1;
+ }
+
+ RHS[j] += f1 * RHS[i];
+ }
+ }
+ }
+
+ template <typename V>
+ void gaussian_elimination_parallel(V & RHS)
+ {
+ // FIXME: move into solver creation ...
+ plib::omp::set_num_threads(4);
+ for (auto l = 0ul; l < m_ge_par.size(); l++)
+ plib::omp::for_static(0ul, m_ge_par[l].size(), [this, &RHS, &l] (unsigned ll)
+ {
+ auto &i = m_ge_par[l][ll];
+ {
+ std::size_t nzbdp = 0;
+ std::size_t pi = diag[i];
+ const value_type f = 1.0 / A[pi++];
+ const std::size_t piie = row_idx[i+1];
+
+ while (auto j = nzbd[i][nzbdp++])
+ {
+ // proceed to column i
+
+ std::size_t pj = row_idx[j];
+
+ while (col_idx[pj] < i)
+ pj++;
+
+ const value_type f1 = - A[pj++] * f;
+
+ // subtract row i from j
+ // fill-in available assumed, i.e. matrix was prepared
+ for (std::size_t pii = pi; pii<piie; pii++)
+ {
+ while (col_idx[pj] < col_idx[pii])
+ pj++;
+ if (col_idx[pj] == col_idx[pii])
+ A[pj++] += A[pii] * f1;
+ }
+ RHS[j] += f1 * RHS[i];
+ }
+ }
+ });
+ }
+
+ template <typename V1, typename V2>
+ void gaussian_back_substitution(V1 &V, const V2 &RHS)
+ {
+ const std::size_t iN = size();
+ /* row n-1 */
+ V[iN - 1] = RHS[iN - 1] / A[diag[iN - 1]];
+
+ for (std::size_t j = iN - 1; j-- > 0;)
+ {
+ value_type tmp = 0;
+ const auto jdiag = diag[j];
+ const std::size_t e = row_idx[j+1];
+ for (std::size_t pk = jdiag + 1; pk < e; pk++)
+ tmp += A[pk] * V[col_idx[pk]];
+ V[j] = (RHS[j] - tmp) / A[jdiag];
+ }
+ }
+
+ template <typename V1>
+ void gaussian_back_substitution(V1 &V)
+ {
+ const std::size_t iN = size();
+ /* row n-1 */
+ V[iN - 1] = V[iN - 1] / A[diag[iN - 1]];
+
+ for (std::size_t j = iN - 1; j-- > 0;)
+ {
+ value_type tmp = 0;
+ const auto jdiag = diag[j];
+ const std::size_t e = row_idx[j+1];
+ for (std::size_t pk = jdiag + 1; pk < e; pk++)
+ tmp += A[pk] * V[col_idx[pk]];
+ V[j] = (V[j] - tmp) / A[jdiag];
+ }
+ }
+
+
+ template <typename VTV, typename VTR>
+ void mult_vec(VTR & res, const VTV & x)
+ {
+ /*
+ * res = A * x
+ */
+
+ std::size_t row = 0;
+ std::size_t k = 0;
+ const std::size_t oe = nz_num;
+
+ while (k < oe)
+ {
+ T tmp = 0.0;
+ const std::size_t e = row_idx[row+1];
+ for (; k < e; k++)
+ tmp += A[k] * x[col_idx[k]];
+ res[row++] = tmp;
+ }
+ }
+
+ /* throws error if P(source)>P(destination) */
+ template <typename LUMAT>
+ void slim_copy_from(LUMAT & src)
+ {
+ for (std::size_t r=0; r<src.size(); r++)
+ {
+ C dp = row_idx[r];
+ for (C sp = src.row_idx[r]; sp < src.row_idx[r+1]; sp++)
+ {
+ /* advance dp to source column and fill 0s if necessary */
+ while (col_idx[dp] < src.col_idx[sp])
+ A[dp++] = 0;
+ if (row_idx[r+1] <= dp || col_idx[dp] != src.col_idx[sp])
+ throw plib::pexception("slim_copy_from error");
+ A[dp++] = src.A[sp];
+ }
+ /* fill remaining elements in row */
+ while (dp < row_idx[r+1])
+ A[dp++] = 0;
+ }
+ }
+
+ /* only copies common elements */
+ template <typename LUMAT>
+ void reduction_copy_from(LUMAT & src)
+ {
+ C sp = 0;
+ for (std::size_t r=0; r<src.size(); r++)
+ {
+ C dp = row_idx[r];
+ while(sp < src.row_idx[r+1])
+ {
+ /* advance dp to source column and fill 0s if necessary */
+ if (col_idx[dp] < src.col_idx[sp])
+ A[dp++] = 0;
+ else if (col_idx[dp] == src.col_idx[sp])
+ A[dp++] = src.A[sp++];
+ else
+ sp++;
+ }
+ /* fill remaining elements in row */
+ while (dp < row_idx[r+1])
+ A[dp++] = 0;
+ }
+ }
+
+ /* checks at all - may crash */
+ template <typename LUMAT>
+ void raw_copy_from(LUMAT & src)
+ {
+ for (std::size_t k = 0; k < nz_num; k++)
+ A[k] = src.A[k];
+ }
+
+ void incomplete_LU_factorization()
+ {
+ /*
+ * incomplete LU Factorization according to http://de.wikipedia.org/wiki/ILU-Zerlegung
+ *
+ * Result is stored in matrix LU
+ *
+ * For i = 1,...,N-1
+ * For k = 0, ... , i - 1
+ * If a[i,k] != 0
+ * a[i,k] = a[i,k] / a[k,k]
+ * For j = k + 1, ... , N - 1
+ * If a[i,j] != 0
+ * a[i,j] = a[i,j] - a[i,k] * a[k,j]
+ * j=j+1
+ * k=k+1
+ * i=i+1
+ *
+ */
+
+ for (std::size_t i = 1; i < size(); i++) // row i
+ {
+ const std::size_t p_i_end = row_idx[i + 1];
+ // loop over all columns k left of diag in row i
+ for (std::size_t i_k = row_idx[i]; i_k < diag[i]; i_k++)
+ {
+ const std::size_t k = col_idx[i_k];
+ const std::size_t p_k_end = row_idx[k + 1];
+ const T LUp_i_k = A[i_k] = A[i_k] / A[diag[k]];
+
+ std::size_t k_j = diag[k] + 1;
+ std::size_t i_j = i_k + 1;
+
+ while (i_j < p_i_end && k_j < p_k_end ) // pj = (i, j)
+ {
+ // we can assume that within a row ja increases continuously */
+ const std::size_t c_i_j = col_idx[i_j]; // row i, column j
+ const std::size_t c_k_j = col_idx[k_j]; // row i, column j
+ if (c_k_j < c_i_j)
+ k_j++;
+ else if (c_k_j == c_i_j)
+ A[i_j++] -= LUp_i_k * A[k_j++];
+ else
+ i_j++;
+ }
+ }
+ }
+ }
+
+ template <typename R>
+ void solveLUx (R &r)
+ {
+ /*
+ * Solve a linear equation Ax = r
+ * where
+ * A = L*U
+ *
+ * L unit lower triangular
+ * U upper triangular
+ *
+ * ==> LUx = r
+ *
+ * ==> Ux = L⁻¹ r = w
+ *
+ * ==> r = Lw
+ *
+ * This can be solved for w using backwards elimination in L.
+ *
+ * Now Ux = w
+ *
+ * This can be solved for x using backwards elimination in U.
+ *
+ */
+ for (std::size_t i = 1; i < size(); ++i )
+ {
+ T tmp = 0.0;
+ const std::size_t j1 = row_idx[i];
+ const std::size_t j2 = diag[i];
+
+ for (std::size_t j = j1; j < j2; ++j )
+ tmp += A[j] * r[col_idx[j]];
+ r[i] -= tmp;
+ }
+ // i now is equal to n;
+ for (std::size_t i = size(); i-- > 0; )
+ {
+ T tmp = 0.0;
+ const std::size_t di = diag[i];
+ const std::size_t j2 = row_idx[i+1];
+ for (std::size_t j = di + 1; j < j2; j++ )
+ tmp += A[j] * r[col_idx[j]];
+ r[i] = (r[i] - tmp) / A[di];
+ }
+ }
+ private:
+ template <typename M>
+ void build_parallel_gaussian_execution_scheme(const M &fill)
+ {
+ // calculate parallel scheme for gaussian elimination
+ std::vector<std::vector<index_type>> rt(size());
+ for (index_type k = 0; k < size(); k++)
+ {
+ for (index_type j = k+1; j < size(); j++)
+ {
+ if (fill[j][k] < FILL_INFINITY)
+ {
+ rt[k].push_back(j);
+ }
+ }
+ }
+
+ std::vector<index_type> levGE(size(), 0);
+ index_type cl = 0;
+
+ for (index_type k = 0; k < size(); k++ )
+ {
+ if (levGE[k] >= cl)
+ {
+ std::vector<index_type> t = rt[k];
+ for (index_type j = k+1; j < size(); j++ )
+ {
+ bool overlap = false;
+ // is there overlap
+ if (plib::container::contains(t, j))
+ overlap = true;
+ for (auto &x : rt[j])
+ if (plib::container::contains(t, x))
+ {
+ overlap = true;
+ break;
+ }
+ if (overlap)
+ levGE[j] = cl + 1;
+ else
+ {
+ t.push_back(j);
+ for (auto &x : rt[j])
+ t.push_back(x);
+ }
+ }
+ cl++;
+ }
+ }
+
+ m_ge_par.clear();
+ m_ge_par.resize(cl+1);
+ for (index_type k = 0; k < size(); k++)
+ m_ge_par[levGE[k]].push_back(k);
+ }
+
+ index_type m_size;
+ };
+
+} // namespace plib
+
+#endif /* MAT_CR_H_ */
diff --git a/src/lib/netlist/plib/palloc.cpp b/src/lib/netlist/plib/palloc.cpp
deleted file mode 100644
index e4d31985b23..00000000000
--- a/src/lib/netlist/plib/palloc.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Couriersud
-/*
- * palloc.c
- *
- */
-
-#include "pconfig.h"
-#include "palloc.h"
-#include "pfmtlog.h"
-
-#include <algorithm>
-
-namespace plib {
-
-//============================================================
-// Memory pool
-//============================================================
-
-mempool::mempool(size_t min_alloc, size_t min_align)
-: m_min_alloc(min_alloc), m_min_align(min_align)
-{
-}
-mempool::~mempool()
-{
- for (auto & b : m_blocks)
- {
- if (b.m_num_alloc != 0)
- {
- fprintf(stderr, "Found block with %d dangling allocations\n", static_cast<int>(b.m_num_alloc));
- }
- ::operator delete(b.data);
- }
- m_blocks.clear();
-}
-
-size_t mempool::new_block()
-{
- block b;
- b.data = static_cast<char *>(::operator new(m_min_alloc));
- b.cur_ptr = b.data;
- b.m_free = m_min_alloc;
- b.m_num_alloc = 0;
- m_blocks.push_back(b);
- return m_blocks.size() - 1;
-}
-
-size_t mempool::mininfosize()
-{
- size_t sinfo = sizeof(mempool::info);
-#ifdef __APPLE__
- size_t ma = 16;
-#else
- size_t ma = 8;
-#endif
- return ((std::max(m_min_align, sinfo) + ma - 1) / ma) * ma;
-}
-
-void *mempool::alloc(size_t size)
-{
- size_t rs = (size + mininfosize() + m_min_align - 1) & ~(m_min_align - 1);
- for (size_t bn=0; bn < m_blocks.size(); bn++)
- {
- auto &b = m_blocks[bn];
- if (b.m_free > rs)
- {
- b.m_free -= rs;
- b.m_num_alloc++;
- auto i = reinterpret_cast<info *>(b.cur_ptr);
- i->m_block = bn;
- auto ret = reinterpret_cast<void *>(b.cur_ptr + mininfosize());
- b.cur_ptr += rs;
- return ret;
- }
- }
- {
- size_t bn = new_block();
- auto &b = m_blocks[bn];
- b.m_num_alloc = 1;
- b.m_free = m_min_alloc - rs;
- auto i = reinterpret_cast<info *>(b.cur_ptr);
- i->m_block = bn;
- auto ret = reinterpret_cast<void *>(b.cur_ptr + mininfosize());
- b.cur_ptr += rs;
- return ret;
- }
-}
-
-void mempool::free(void *ptr)
-{
- auto p = reinterpret_cast<char *>(ptr);
-
- auto i = reinterpret_cast<info *>(p - mininfosize());
- block *b = &m_blocks[i->m_block];
- if (b->m_num_alloc == 0)
- fprintf(stderr, "Argh .. double free\n");
- else
- {
- //b->m_free = m_min_alloc;
- //b->cur_ptr = b->data;
- }
- b->m_num_alloc--;
-}
-
-}
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h
index a35bc50ff17..15fede3a99b 100644
--- a/src/lib/netlist/plib/palloc.h
+++ b/src/lib/netlist/plib/palloc.h
@@ -8,172 +8,427 @@
#ifndef PALLOC_H_
#define PALLOC_H_
+#include "pconfig.h"
#include "pstring.h"
+#include "ptypes.h"
-#include <vector>
+#include <cstddef>
+#include <cstdlib>
#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
+#include <malloc.h>
+#endif
namespace plib {
-//============================================================
-// Memory allocation
-//============================================================
-
-template<typename T, typename... Args>
-T *palloc(Args&&... args)
-{
- return new T(std::forward<Args>(args)...);
-}
-
-template<typename T>
-void pfree(T *ptr)
-{
- delete ptr;
-}
-
-template<typename T>
-T* palloc_array(const std::size_t num)
-{
- return new T[num]();
-}
-
-template<typename T>
-void pfree_array(T *ptr)
-{
- delete [] ptr;
-}
-
-template<typename T, typename... Args>
-std::unique_ptr<T> make_unique(Args&&... args)
-{
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
-}
-
-template<typename BC, typename DC, typename... Args>
-static std::unique_ptr<BC> make_unique_base(Args&&... args)
-{
- std::unique_ptr<BC> ret(new DC(std::forward<Args>(args)...));
- return ret;
-}
-
-template <typename SC>
-class owned_ptr
-{
-private:
- owned_ptr()
- : m_ptr(nullptr), m_is_owned(true) { }
-public:
- owned_ptr(SC *p, bool owned) noexcept
- : m_ptr(p), m_is_owned(owned)
- { }
-
- owned_ptr(const owned_ptr &r) = delete;
- owned_ptr & operator =(owned_ptr &r) = delete;
-
- template<typename DC>
- owned_ptr & operator =(owned_ptr<DC> &&r)
+ //============================================================
+ // Standard arena_deleter
+ //============================================================
+
+ template <typename P, typename T>
+ struct arena_deleter
+ {
+ //using arena_storage_type = P *;
+ using arena_storage_type = typename std::conditional<P::is_stateless, P, P *>::type;
+ template <typename X, typename Y = void>
+ typename std::enable_if<!X::is_stateless, X&>::type getref(X *x) { return *x;}
+ template <typename X, typename Y = void *>
+ typename std::enable_if<std::remove_pointer<X>::type::is_stateless, X&>::type
+ getref(X &x, Y y = nullptr)
+ {
+ unused_var(y);
+ return x;
+ }
+
+ constexpr arena_deleter(arena_storage_type a = arena_storage_type()) noexcept
+ : m_a(a) { }
+
+ template<typename PU, typename U, typename = typename
+ std::enable_if<std::is_convertible< U*, T*>::value>::type>
+ arena_deleter(const arena_deleter<PU, U> &rhs) noexcept : m_a(rhs.m_a) { }
+
+ void operator()(T *p) //const
+ {
+ /* call destructor */
+ p->~T();
+ getref(m_a).deallocate(p);
+ }
+ //private:
+ arena_storage_type m_a;
+ };
+
+ //============================================================
+ // owned_ptr: smart pointer with ownership information
+ //============================================================
+
+ template <typename SC, typename D>
+ class owned_ptr
+ {
+ public:
+
+ using pointer = SC *;
+ using element_type = SC;
+ using deleter_type = D;
+
+ owned_ptr()
+ : m_ptr(nullptr), m_deleter(), m_is_owned(true) { }
+
+ template <typename, typename>
+ friend class owned_ptr;
+
+ owned_ptr(pointer p, bool owned) noexcept
+ : m_ptr(p), m_deleter(), m_is_owned(owned)
+ { }
+
+ owned_ptr(pointer p, bool owned, D deleter) noexcept
+ : m_ptr(p), m_deleter(deleter), m_is_owned(owned)
+ { }
+
+
+ owned_ptr(const owned_ptr &r) = delete;
+ owned_ptr & operator =(owned_ptr &r) = delete;
+
+ template<typename DC, typename DC_D>
+ owned_ptr & operator =(owned_ptr<DC, DC_D> &&r)
+ {
+ if (m_is_owned && (m_ptr != nullptr))
+ //delete m_ptr;
+ m_deleter(m_ptr);
+ m_is_owned = r.m_is_owned;
+ m_ptr = r.m_ptr;
+ m_deleter = r.m_deleter;
+ r.m_is_owned = false;
+ r.m_ptr = nullptr;
+ return *this;
+ }
+
+ owned_ptr(owned_ptr &&r) noexcept
+ : m_ptr(r.m_ptr)
+ , m_deleter(r.m_deleter)
+ , m_is_owned(r.m_is_owned)
+ {
+ r.m_is_owned = false;
+ r.m_ptr = nullptr;
+ }
+
+ owned_ptr &operator=(owned_ptr &&r) noexcept
+ {
+ if (m_is_owned && (m_ptr != nullptr))
+ //delete m_ptr;
+ m_deleter(m_ptr);
+ m_is_owned = r.m_is_owned;
+ m_ptr = r.m_ptr;
+ m_deleter = std::move(r.m_deleter);
+ r.m_is_owned = false;
+ r.m_ptr = nullptr;
+ return *this;
+ }
+
+ template<typename DC, typename DC_D>
+ owned_ptr(owned_ptr<DC, DC_D> &&r) noexcept
+ : m_ptr(static_cast<pointer >(r.get()))
+ , m_deleter(r.m_deleter)
+ , m_is_owned(r.is_owned())
+ {
+ r.release();
+ }
+
+ ~owned_ptr() noexcept
+ {
+ if (m_is_owned && (m_ptr != nullptr))
+ {
+ //delete m_ptr;
+ m_deleter(m_ptr);
+ }
+ m_is_owned = false;
+ m_ptr = nullptr;
+ }
+
+ /**
+ * \brief Return @c true if the stored pointer is not null.
+ */
+ explicit operator bool() const noexcept { return m_ptr != nullptr; }
+
+ pointer release()
+ {
+ pointer tmp = m_ptr;
+ m_is_owned = false;
+ m_ptr = nullptr;
+ return tmp;
+ }
+
+ bool is_owned() const { return m_is_owned; }
+
+ pointer operator ->() const noexcept { return m_ptr; }
+ typename std::add_lvalue_reference<element_type>::type operator *() const noexcept { return *m_ptr; }
+ pointer get() const noexcept { return m_ptr; }
+
+ deleter_type& get_deleter() noexcept { return m_deleter; }
+ const deleter_type& get_deleter() const noexcept { return m_deleter; }
+
+ private:
+ pointer m_ptr;
+ D m_deleter;
+ bool m_is_owned;
+ };
+
+ //============================================================
+ // Arena allocator for use with containers
+ //============================================================
+
+ template <class ARENA, class T, std::size_t ALIGN = alignof(T)>
+ class arena_allocator
{
- if (m_is_owned && (m_ptr != nullptr))
- delete m_ptr;
- m_is_owned = r.m_is_owned;
- m_ptr = r.m_ptr;
- r.m_is_owned = false;
- r.m_ptr = nullptr;
- return *this;
+ public:
+ using value_type = T;
+ static constexpr const std::size_t align_size = ALIGN;
+ using arena_type = ARENA;
+
+ static_assert(align_size >= alignof(T) && (align_size % alignof(T)) == 0,
+ "ALIGN must be greater than alignof(T) and a multiple");
+
+ arena_allocator() noexcept
+ : m_a(arena_type::instance())
+ { }
+
+ ~arena_allocator() noexcept = default;
+
+ arena_allocator(const arena_allocator &rhs) noexcept = default;
+ arena_allocator& operator=(const arena_allocator&) noexcept = delete;
+
+ arena_allocator(arena_allocator&&) noexcept = default;
+ arena_allocator& operator=(arena_allocator&&) = delete;
+
+ arena_allocator(arena_type & a) noexcept : m_a(a)
+ {
+ }
+
+ template <class U>
+ arena_allocator(const arena_allocator<ARENA, U, ALIGN>& rhs) noexcept
+ : m_a(rhs.m_a)
+ {
+ }
+
+ template <class U> struct rebind
+ {
+ using other = arena_allocator<ARENA, U, ALIGN>;
+ };
+
+ T* allocate(std::size_t n)
+ {
+ return reinterpret_cast<T *>(m_a.allocate(ALIGN, sizeof(T) * n));
+ }
+
+ void deallocate(T* p, std::size_t n) noexcept
+ {
+ unused_var(n);
+ m_a.deallocate(p);
+ }
+
+ template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
+ friend bool operator==(const arena_allocator<AR1, T1, A1>& lhs,
+ const arena_allocator<AR2, T2, A2>& rhs) noexcept;
+
+ template <class AU, class U, std::size_t A> friend class arena_allocator;
+ private:
+ arena_type &m_a;
+ };
+
+ template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
+ inline bool operator==(const arena_allocator<AR1, T1, A1>& lhs,
+ const arena_allocator<AR2, T2, A2>& rhs) noexcept
+ {
+ return A1 == A2 && rhs.m_a == lhs.m_a;
+ }
+ template <class AR1, class T1, std::size_t A1, class AR2, class T2, std::size_t A2>
+ inline bool operator!=(const arena_allocator<AR1, T1, A1>& lhs,
+ const arena_allocator<AR2, T2, A2>& rhs) noexcept
+ {
+ return !(lhs == rhs);
}
- owned_ptr(owned_ptr &&r) noexcept
+ //============================================================
+ // Memory allocation
+ //============================================================
+
+ struct aligned_arena
{
- m_is_owned = r.m_is_owned;
- m_ptr = r.m_ptr;
- r.m_is_owned = false;
- r.m_ptr = nullptr;
+ static constexpr const bool is_stateless = true;
+ template <class T, std::size_t ALIGN = alignof(T)>
+ using allocator_type = arena_allocator<aligned_arena, T, ALIGN>;
+
+ template <typename T>
+ using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<aligned_arena, T>>;
+
+ static inline aligned_arena &instance()
+ {
+ static aligned_arena s_arena;
+ return s_arena;
+ }
+
+ static inline void *allocate( size_t alignment, size_t size )
+ {
+ #if (USE_ALIGNED_ALLOCATION)
+ #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
+ return _aligned_malloc(size, alignment);
+ #elif defined(__APPLE__)
+ void* p;
+ if (::posix_memalign(&p, alignment, size) != 0) {
+ p = nullptr;
+ }
+ return p;
+ #else
+ return aligned_alloc(alignment, size);
+ #endif
+ #else
+ unused_var(alignment);
+ return ::operator new(size);
+ #endif
+ }
+
+ static inline void deallocate( void *ptr )
+ {
+ #if (USE_ALIGNED_ALLOCATION)
+ // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
+ free(ptr);
+ #else
+ ::operator delete(ptr);
+ #endif
+ }
+
+ template<typename T, typename... Args>
+ owned_pool_ptr<T> make_poolptr(Args&&... args)
+ {
+ auto *mem = allocate(alignof(T), sizeof(T));
+ return owned_pool_ptr<T>(new (mem) T(std::forward<Args>(args)...), true, arena_deleter<aligned_arena, T>(*this));
+ }
+
+ };
+
+ template <typename T, std::size_t ALIGN>
+ /*inline */ C14CONSTEXPR T *assume_aligned_ptr(T *p) noexcept
+ {
+ static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
+ static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
+ //auto t = reinterpret_cast<std::uintptr_t>(p);
+ //if (t & (ALIGN-1))
+ // printf("alignment error!");
+#if (USE_ALIGNED_HINTS)
+ return reinterpret_cast<T *>(__builtin_assume_aligned(p, ALIGN));
+#else
+ return p;
+#endif
}
- template<typename DC>
- owned_ptr(owned_ptr<DC> &&r) noexcept
+ template <typename T, std::size_t ALIGN>
+ constexpr const T *assume_aligned_ptr(const T *p) noexcept
{
- m_ptr = static_cast<SC *>(r.get());
- m_is_owned = r.is_owned();
- r.release();
+ static_assert(ALIGN >= alignof(T), "Alignment must be greater or equal to alignof(T)");
+ static_assert(is_pow2(ALIGN), "Alignment must be a power of 2");
+#if (USE_ALIGNED_HINTS)
+ return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN));
+#else
+ return p;
+#endif
}
- ~owned_ptr()
+ // FIXME: remove
+ template<typename T, typename... Args>
+ inline T *pnew(Args&&... args)
{
- if (m_is_owned && (m_ptr != nullptr))
- delete m_ptr;
- m_is_owned = false;
- m_ptr = nullptr;
+ auto *p = aligned_arena::allocate(alignof(T), sizeof(T));
+ return new(p) T(std::forward<Args>(args)...);
}
- template<typename DC, typename... Args>
- static owned_ptr Create(Args&&... args)
+
+ template<typename T>
+ inline void pdelete(T *ptr)
{
- owned_ptr a;
- DC *x = new DC(std::forward<Args>(args)...);
- a.m_ptr = static_cast<SC *>(x);
- return std::move(a);
+ ptr->~T();
+ aligned_arena::deallocate(ptr);
}
- template<typename... Args>
- static owned_ptr Create(Args&&... args)
+
+ template <typename T>
+ using unique_ptr = std::unique_ptr<T, arena_deleter<aligned_arena, T>>;
+
+ template<typename T, typename... Args>
+ plib::unique_ptr<T> make_unique(Args&&... args)
{
- owned_ptr a;
- a.m_ptr = new SC(std::forward<Args>(args)...);
- return std::move(a);
+ return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...));
}
- SC * release()
+
+#if 0
+ template<typename T, typename... Args>
+ static owned_ptr<T> make_owned(Args&&... args)
{
- SC *tmp = m_ptr;
- m_is_owned = false;
- m_ptr = nullptr;
- return tmp;
+ return owned_ptr<T>(pnew<T>(std::forward<Args>(args)...), true);
}
+#endif
+
- bool is_owned() const { return m_is_owned; }
+ template <class T, std::size_t ALIGN = alignof(T)>
+ using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>;
- SC * operator ->() const { return m_ptr; }
- SC & operator *() const { return *m_ptr; }
- SC * get() const { return m_ptr; }
-private:
- SC *m_ptr;
- bool m_is_owned;
-};
+ //============================================================
+ // traits to determine alignment size and stride size
+ // from types supporting alignment
+ //============================================================
-class mempool
-{
-private:
- struct block
+ PDEFINE_HAS_MEMBER(has_align, align_size);
+
+ template <typename T, typename X = void>
+ struct align_traits
{
- block() : m_num_alloc(0), m_free(0), cur_ptr(nullptr), data(nullptr) { }
- std::size_t m_num_alloc;
- std::size_t m_free;
- char *cur_ptr;
- char *data;
+ static constexpr const std::size_t align_size = alignof(std::max_align_t);
+ static constexpr const std::size_t value_size = sizeof(typename T::value_type);
+ static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
};
- size_t new_block();
- size_t mininfosize();
-
- struct info
+ template <typename T>
+ struct align_traits<T, typename std::enable_if<has_align<T>::value, void>::type>
{
- info() : m_block(0) { }
- size_t m_block;
+ static constexpr const std::size_t align_size = T::align_size;
+ static constexpr const std::size_t value_size = sizeof(typename T::value_type);
+ static constexpr const std::size_t stride_size = lcm(align_size, value_size) / value_size;
};
- size_t m_min_alloc;
- size_t m_min_align;
+ //============================================================
+ // Aligned vector
+ //============================================================
- std::vector<block> m_blocks;
+ // FIXME: needs a separate file
+ template <class T, std::size_t ALIGN = alignof(T)>
+ class aligned_vector : public std::vector<T, aligned_allocator<T, ALIGN>>
+ {
+ public:
+ using base = std::vector<T, aligned_allocator<T, ALIGN>>;
+
+ using reference = typename base::reference;
+ using const_reference = typename base::const_reference;
+ using pointer = typename base::pointer;
+ using const_pointer = typename base::const_pointer;
+ using size_type = typename base::size_type;
-public:
- mempool(size_t min_alloc, size_t min_align);
- ~mempool();
+ using base::base;
- void *alloc(size_t size);
- void free(void *ptr);
+ C14CONSTEXPR reference operator[](size_type i) noexcept
+ {
+ return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
+ }
+ constexpr const_reference operator[](size_type i) const noexcept
+ {
+ return assume_aligned_ptr<T, ALIGN>(&(base::operator[](0)))[i];
+ }
-};
+ pointer data() noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
+ const_pointer data() const noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); }
+
+ };
-}
+} // namespace plib
#endif /* PALLOC_H_ */
diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h
new file mode 100644
index 00000000000..1be37b908cd
--- /dev/null
+++ b/src/lib/netlist/plib/parray.h
@@ -0,0 +1,126 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * parray.h
+ *
+ */
+
+#ifndef PARRAY_H_
+#define PARRAY_H_
+
+#include "palloc.h"
+#include "pconfig.h"
+#include "pexception.h"
+
+#include <array>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace plib {
+
+ template <typename FT, int SIZE>
+ struct sizeabs
+ {
+ static constexpr std::size_t ABS() { return (SIZE < 0) ? static_cast<std::size_t>(0 - SIZE) : static_cast<std::size_t>(SIZE); }
+ using container = typename std::array<FT, ABS()> ;
+ };
+
+ template <typename FT>
+ struct sizeabs<FT, 0>
+ {
+ static constexpr const std::size_t ABS = 0;
+ using container = typename std::vector<FT, aligned_allocator<FT, PALIGN_VECTOROPT>>;
+ };
+
+ /**
+ * \brief Array with preallocated or dynamic allocation
+ *
+ * Passing SIZE > 0 has the same functionality as a std::array.
+ * SIZE = 0 is pure dynamic allocation, the actual array size is passed to the
+ * constructor.
+ * SIZE < 0 reserves std::abs(SIZE) elements statically in place allocated. The
+ * actual size is passed in by the constructor.
+ * This array is purely intended for HPC application where depending on the
+ * architecture a preference dynamic/static has to be made.
+ *
+ * This struct is not intended to be a full replacement to std::array.
+ * It is a subset to enable switching between dynamic and static allocation.
+ * I consider > 10% performance difference to be a use case.
+ */
+
+ template <typename FT, int SIZE>
+ struct parray
+ {
+ public:
+ static constexpr std::size_t SIZEABS() { return sizeabs<FT, SIZE>::ABS(); }
+
+ using base_type = typename sizeabs<FT, SIZE>::container;
+ using size_type = typename base_type::size_type;
+ using reference = typename base_type::reference;
+ using const_reference = typename base_type::const_reference;
+ using value_type = typename base_type::value_type;
+
+ template <int X = SIZE >
+ parray(size_type size, typename std::enable_if<X==0, int>::type = 0)
+ : m_a(size), m_size(size)
+ {
+ }
+
+#if 1
+ /* allow construction in fixed size arrays */
+ template <int X = SIZE >
+ parray(typename std::enable_if<(X > 0), int>::type = 0)
+ : m_size(X)
+ {
+ }
+#endif
+ template <int X = SIZE >
+ parray(size_type size, typename std::enable_if<X!=0, int>::type = 0)
+ : m_size(size)
+ {
+ if (SIZE < 0 && size > SIZEABS())
+ throw plib::pexception("parray: size error " + plib::to_string(size) + ">" + plib::to_string(SIZEABS()));
+ else if (SIZE > 0 && size != SIZEABS())
+ throw plib::pexception("parray: size error");
+ }
+
+ inline size_type size() const noexcept { return SIZE <= 0 ? m_size : SIZEABS(); }
+
+ constexpr size_type max_size() const noexcept { return base_type::max_size(); }
+
+ bool empty() const noexcept { return size() == 0; }
+
+#if 0
+ reference operator[](size_type i) /*noexcept*/
+ {
+ if (i >= m_size) throw plib::pexception("limits error " + to_string(i) + ">=" + to_string(m_size));
+ return m_a[i];
+ }
+ const_reference operator[](size_type i) const /*noexcept*/
+ {
+ if (i >= m_size) throw plib::pexception("limits error " + to_string(i) + ">=" + to_string(m_size));
+ return m_a[i];
+ }
+#else
+ C14CONSTEXPR reference operator[](size_type i) noexcept
+ {
+ return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(&m_a[0])[i];
+ }
+ constexpr const_reference operator[](size_type i) const noexcept
+ {
+ return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(&m_a[0])[i];
+ }
+#endif
+ FT * data() noexcept { return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(m_a.data()); }
+ const FT * data() const noexcept { return assume_aligned_ptr<FT, PALIGN_VECTOROPT>(m_a.data()); }
+
+ private:
+ PALIGNAS_VECTOROPT()
+ base_type m_a;
+ size_type m_size;
+ };
+} // namespace plib
+
+#endif /* PARRAY_H_ */
diff --git a/src/lib/netlist/plib/pchrono.cpp b/src/lib/netlist/plib/pchrono.cpp
index 971d19b3645..953d948e062 100644
--- a/src/lib/netlist/plib/pchrono.cpp
+++ b/src/lib/netlist/plib/pchrono.cpp
@@ -49,5 +49,5 @@ exact_ticks::type exact_ticks::per_second()
#endif
-}
-}
+} // namespace chrono
+} // namespace plib
diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h
index a229128e7b8..8ce0eca23b3 100644
--- a/src/lib/netlist/plib/pchrono.h
+++ b/src/lib/netlist/plib/pchrono.h
@@ -9,16 +9,17 @@
#define PCHRONO_H_
#include "pconfig.h"
+#include "ptypes.h"
-#include <cstdint>
#include <chrono>
+#include <cstdint>
namespace plib {
namespace chrono {
template <typename T>
struct sys_ticks
{
- typedef typename T::rep type;
+ using type = typename T::rep;
static inline type start() { return T::now().time_since_epoch().count(); }
static inline type stop() { return T::now().time_since_epoch().count(); }
static inline constexpr type per_second() { return T::period::den / T::period::num; }
@@ -145,7 +146,7 @@ namespace chrono {
struct counter
{
counter() : m_count(0) { }
- typedef uint_least64_t type;
+ using type = uint_least64_t;
type operator()() const { return m_count; }
void inc() { ++m_count; }
void reset() { m_count = 0; }
@@ -157,7 +158,7 @@ namespace chrono {
template<>
struct counter<false>
{
- typedef uint_least64_t type;
+ using type = uint_least64_t;
constexpr type operator()() const { return 0; }
void inc() const { }
void reset() const { }
@@ -168,15 +169,28 @@ namespace chrono {
template< typename T, bool enabled_ = true>
struct timer
{
- typedef typename T::type type;
- typedef uint_least64_t ctype;
+ using type = typename T::type;
+ using ctype = uint_least64_t;
+ constexpr static bool enabled = enabled_;
+
+ struct guard_t
+ {
+ guard_t() = delete;
+ guard_t(timer &m) noexcept : m_m(m) { m_m.m_time -= T::start(); }
+ ~guard_t() { m_m.m_time += T::stop(); ++m_m.m_count; }
+
+ COPYASSIGNMOVE(guard_t, default)
+
+ private:
+ timer &m_m;
+ };
+
+ friend struct guard_t;
timer() : m_time(0), m_count(0) { }
type operator()() const { return m_time; }
- void start() { m_time -= T::start(); }
- void stop() { m_time += T::stop(); ++m_count; }
void reset() { m_time = 0; m_count = 0; }
type average() const { return (m_count == 0) ? 0 : m_time / m_count; }
type total() const { return m_time; }
@@ -185,7 +199,7 @@ namespace chrono {
double as_seconds() const { return static_cast<double>(total())
/ static_cast<double>(T::per_second()); }
- constexpr static bool enabled = enabled_;
+ guard_t guard() { return guard_t(*this); }
private:
type m_time;
ctype m_count;
@@ -194,19 +208,31 @@ namespace chrono {
template<typename T>
struct timer<T, false>
{
- typedef typename T::type type;
- typedef uint_least64_t ctype;
+ using type = typename T::type;
+ using ctype = uint_least64_t;
+
+ struct guard_t
+ {
+ guard_t() = default;
+ COPYASSIGNMOVE(guard_t, default)
+ /* using default constructor will trigger warning on
+ * unused local variable.
+ */
+ // NOLINTNEXTLINE(modernize-use-equals-default)
+ ~guard_t() { }
+ };
+
constexpr type operator()() const { return 0; }
- void start() const { }
- void stop() const { }
void reset() const { }
constexpr type average() const { return 0; }
constexpr type total() const { return 0; }
constexpr ctype count() const { return 0; }
constexpr double as_seconds() const { return 0.0; }
constexpr static bool enabled = false;
+ guard_t guard() { return guard_t(); }
};
+
} // namespace chrono
} // namespace plib
diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h
index 0200c305ecd..d66b342f815 100644
--- a/src/lib/netlist/plib/pconfig.h
+++ b/src/lib/netlist/plib/pconfig.h
@@ -21,18 +21,46 @@
* if PHAS_RDTSCP == 1
*/
#ifndef PUSE_ACCURATE_STATS
-#define PUSE_ACCURATE_STATS (1)
+#define PUSE_ACCURATE_STATS (0)
#endif
/*
* Set this to one if you want to use 128 bit int for ptime.
- * This is for tests only.
+ * This is about 5% slower on a kaby lake processor.
*/
#ifndef PHAS_INT128
#define PHAS_INT128 (0)
#endif
+/*
+ * Set this to one if you want to use aligned storage optimizations.
+ */
+
+#ifndef USE_ALIGNED_OPTIMIZATIONS
+#define USE_ALIGNED_OPTIMIZATIONS (0)
+#endif
+
+#define USE_ALIGNED_ALLOCATION (USE_ALIGNED_OPTIMIZATIONS)
+#define USE_ALIGNED_HINTS (USE_ALIGNED_OPTIMIZATIONS)
+/*
+ * Standard alignment macros
+ */
+
+#define PALIGN_CACHELINE (64)
+#define PALIGN_VECTOROPT (64)
+
+#define PALIGNAS_CACHELINE() PALIGNAS(PALIGN_CACHELINE)
+#define PALIGNAS_VECTOROPT() PALIGNAS(PALIGN_VECTOROPT)
+
+/* Breaks mame build on windows due to -Wattribute
+ * FIXME: no error on cross-compile - need further checks */
+#if defined(_WIN32) && defined(__GNUC__)
+#define PALIGNAS(x)
+#else
+#define PALIGNAS(x) alignas(x)
+#endif
+
/*============================================================
* Check for CPP Version
*
@@ -47,6 +75,13 @@
*
*============================================================*/
+#ifndef NVCCBUILD
+#define NVCCBUILD (0)
+#endif
+
+#if NVCCBUILD
+#define C14CONSTEXPR
+#else
#if __cplusplus == 201103L
#define C14CONSTEXPR
#elif __cplusplus == 201402L
@@ -58,6 +93,7 @@
#else
#error "C++ version not supported"
#endif
+#endif
#ifndef PHAS_INT128
#define PHAS_INT128 (0)
@@ -68,17 +104,6 @@ typedef __uint128_t UINT128;
typedef __int128_t INT128;
#endif
-#if defined(__GNUC__)
-#ifdef RESTRICT
-#undef RESTRICT
-#endif
-#define RESTRICT __restrict__
-#define ATTR_UNUSED __attribute__((__unused__))
-#else
-#define RESTRICT
-#define ATTR_UNUSED
-#endif
-
//============================================================
// Standard defines
//============================================================
diff --git a/src/lib/netlist/plib/pdynlib.cpp b/src/lib/netlist/plib/pdynlib.cpp
index 13827eaf24c..0d32bead51d 100644
--- a/src/lib/netlist/plib/pdynlib.cpp
+++ b/src/lib/netlist/plib/pdynlib.cpp
@@ -25,7 +25,7 @@ CHAR *astring_from_utf8(const char *utf8string)
// convert UTF-16 to "ANSI code page" string
char_count = WideCharToMultiByte(CP_ACP, 0, wstring, -1, nullptr, 0, nullptr, nullptr);
- result = palloc_array<CHAR>(char_count);
+ result = new CHAR[char_count];
if (result != nullptr)
WideCharToMultiByte(CP_ACP, 0, wstring, -1, result, char_count, nullptr, nullptr);
@@ -39,7 +39,7 @@ WCHAR *wstring_from_utf8(const char *utf8string)
// convert MAME string (UTF-8) to UTF-16
char_count = MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, nullptr, 0);
- result = palloc_array<WCHAR>(char_count);
+ result = new WCHAR[char_count];
if (result != nullptr)
MultiByteToWideChar(CP_UTF8, 0, utf8string, -1, result, char_count);
@@ -58,7 +58,7 @@ WCHAR *wstring_from_utf8(const char *utf8string)
#endif
namespace plib {
-dynlib::dynlib(const pstring libname)
+dynlib::dynlib(const pstring &libname)
: m_isLoaded(false), m_lib(nullptr)
{
#ifdef _WIN32
@@ -72,7 +72,7 @@ dynlib::dynlib(const pstring libname)
m_isLoaded = true;
//else
// fprintf(stderr, "win: library <%s> not found!\n", libname.c_str());
- pfree_array(buffer);
+ delete [] buffer;
#elif defined(EMSCRIPTEN)
//no-op
#else
@@ -88,9 +88,11 @@ dynlib::dynlib(const pstring libname)
#endif
}
-dynlib::dynlib(const pstring path, const pstring libname)
+dynlib::dynlib(const pstring &path, const pstring &libname)
: m_isLoaded(false), m_lib(nullptr)
{
+ // FIXME: implement path search
+ plib::unused_var(path);
// printf("win: loading <%s>\n", libname.c_str());
#ifdef _WIN32
TCHAR *buffer = tstring_from_utf8(libname.c_str());
@@ -104,7 +106,7 @@ dynlib::dynlib(const pstring path, const pstring libname)
{
//printf("win: library <%s> not found!\n", libname.c_str());
}
- pfree_array(buffer);
+ delete [] buffer;
#elif defined(EMSCRIPTEN)
//no-op
#else
@@ -139,7 +141,7 @@ bool dynlib::isLoaded() const
return m_isLoaded;
}
-void *dynlib::getsym_p(const pstring name)
+void *dynlib::getsym_p(const pstring &name)
{
#ifdef _WIN32
return (void *) GetProcAddress((HMODULE) m_lib, name.c_str());
@@ -148,4 +150,4 @@ void *dynlib::getsym_p(const pstring name)
#endif
}
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pdynlib.h b/src/lib/netlist/plib/pdynlib.h
index 7c9412593c9..1454c053298 100644
--- a/src/lib/netlist/plib/pdynlib.h
+++ b/src/lib/netlist/plib/pdynlib.h
@@ -8,28 +8,31 @@
#define PDYNLIB_H_
#include "pstring.h"
+#include "ptypes.h"
namespace plib {
// ----------------------------------------------------------------------------------------
// pdynlib: dynamic loading of libraries ...
// ----------------------------------------------------------------------------------------
-class dynlib
+class dynlib : public nocopyassignmove
{
public:
- explicit dynlib(const pstring libname);
- dynlib(const pstring path, const pstring libname);
+ explicit dynlib(const pstring &libname);
+ dynlib(const pstring &path, const pstring &libname);
+
~dynlib();
+ COPYASSIGNMOVE(dynlib, delete)
bool isLoaded() const;
template <typename T>
- T getsym(const pstring name)
+ T getsym(const pstring &name)
{
return reinterpret_cast<T>(getsym_p(name));
}
private:
- void *getsym_p(const pstring name);
+ void *getsym_p(const pstring &name);
bool m_isLoaded;
void *m_lib;
@@ -64,6 +67,6 @@ private:
calltype m_sym;
};
-}
+} // namespace plib
#endif /* PSTRING_H_ */
diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp
index a4ed8f367e0..8d6907d66f2 100644
--- a/src/lib/netlist/plib/pexception.cpp
+++ b/src/lib/netlist/plib/pexception.cpp
@@ -9,6 +9,7 @@
#include "pfmtlog.h"
#include <cfenv>
+#include <iostream>
#if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__)
#define HAS_FEENABLE_EXCEPT (1)
@@ -17,127 +18,113 @@
#endif
namespace plib {
-//============================================================
-// Exceptions
-//============================================================
-
-pexception::pexception(const pstring &text)
-: m_text(text)
-{
-}
-
-pexception::~pexception() noexcept
-{
-}
-
-file_e::file_e(const pstring &fmt, const pstring &filename)
- : pexception(pfmt(fmt)(filename))
-{
-}
-
-file_e::~file_e() noexcept
-{
-}
-
-file_open_e::file_open_e(const pstring &filename)
- : file_e("File open failed: {}", filename)
-{
-}
-
-file_open_e::~file_open_e() noexcept
-{
-
-}
-
-file_read_e::file_read_e(const pstring &filename)
- : file_e("File read failed: {}", filename)
-{
-}
-
-file_read_e::~file_read_e() noexcept
-{
-
-}
-
-file_write_e::file_write_e(const pstring &filename)
- : file_e("File write failed: {}", filename)
-{
-}
-
-file_write_e::~file_write_e() noexcept
-{
-}
-
-null_argument_e::null_argument_e(const pstring &argument)
- : pexception(pfmt("Null argument passed: {}")(argument))
-{
-}
-
-null_argument_e::~null_argument_e() noexcept
-{
-}
-
-out_of_mem_e::out_of_mem_e(const pstring &location)
- : pexception(pfmt("Out of memory: {}")(location))
-{
-}
-
-out_of_mem_e::~out_of_mem_e() noexcept
-{
-}
-
-fpexception_e::fpexception_e(const pstring &text)
- : pexception(pfmt("Out of memory: {}")(text))
-{
-}
-
-fpexception_e::~fpexception_e() noexcept
-{
-}
-
-bool fpsignalenabler::m_enable = false;
-
-fpsignalenabler::fpsignalenabler(unsigned fpexceptions)
-{
-#if HAS_FEENABLE_EXCEPT
- if (m_enable)
+
+ //============================================================
+ // terminate
+ //============================================================
+
+ void terminate(const pstring &msg) noexcept
{
- int b = 0;
- if (fpexceptions & plib::FP_INEXACT) b = b | FE_INEXACT;
- if (fpexceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO;
- if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW;
- if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW;
- if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID;
- m_last_enabled = feenableexcept(b);
+ std::cerr << msg.c_str() << "\n";
+ std::terminate();
}
-#else
- m_last_enabled = 0;
-#endif
-}
-fpsignalenabler::~fpsignalenabler()
-{
-#if HAS_FEENABLE_EXCEPT
- if (m_enable)
+ //============================================================
+ // Exceptions
+ //============================================================
+
+ pexception::pexception(const pstring &text)
+ : m_text(text)
+ {
+ }
+
+
+ file_e::file_e(const pstring &fmt, const pstring &filename)
+ : pexception(pfmt(fmt)(filename))
+ {
+ }
+
+
+ file_open_e::file_open_e(const pstring &filename)
+ : file_e("File open failed: {}", filename)
+ {
+ }
+
+
+ file_read_e::file_read_e(const pstring &filename)
+ : file_e("File read failed: {}", filename)
{
- fedisableexcept(FE_ALL_EXCEPT); // Enable all floating point exceptions but FE_INEXACT
- feenableexcept(m_last_enabled); // Enable all floating point exceptions but FE_INEXACT
}
-#endif
-}
-bool fpsignalenabler::supported()
-{
- return true;
-}
-bool fpsignalenabler::global_enable(bool enable)
-{
- bool old = m_enable;
- m_enable = enable;
- return old;
-}
+ file_write_e::file_write_e(const pstring &filename)
+ : file_e("File write failed: {}", filename)
+ {
+ }
+
+
+ null_argument_e::null_argument_e(const pstring &argument)
+ : pexception(pfmt("Null argument passed: {}")(argument))
+ {
+ }
+
+
+ out_of_mem_e::out_of_mem_e(const pstring &location)
+ : pexception(pfmt("Out of memory: {}")(location))
+ {
+ }
+
+
+ fpexception_e::fpexception_e(const pstring &text)
+ : pexception(pfmt("Out of memory: {}")(text))
+ {
+ }
+
+
+ bool fpsignalenabler::m_enable = false;
+
+ fpsignalenabler::fpsignalenabler(unsigned fpexceptions)
+ {
+ #if HAS_FEENABLE_EXCEPT
+ if (m_enable)
+ {
+ int b = 0;
+ if (fpexceptions & plib::FP_INEXACT) b = b | FE_INEXACT;
+ if (fpexceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO;
+ if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW;
+ if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW;
+ if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID;
+ m_last_enabled = feenableexcept(b);
+ }
+ #else
+ m_last_enabled = 0;
+ #endif
+ }
+
+
+ fpsignalenabler::~fpsignalenabler()
+ {
+ #if HAS_FEENABLE_EXCEPT
+ if (m_enable)
+ {
+ fedisableexcept(FE_ALL_EXCEPT); // Enable all floating point exceptions but FE_INEXACT
+ feenableexcept(m_last_enabled); // Enable all floating point exceptions but FE_INEXACT
+ }
+ #endif
+ }
+
+ bool fpsignalenabler::supported()
+ {
+ return true;
+ }
+
+ bool fpsignalenabler::global_enable(bool enable)
+ {
+ bool old = m_enable;
+ m_enable = enable;
+ return old;
+ }
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pexception.h b/src/lib/netlist/plib/pexception.h
index 4827081b754..28a3ac1adf1 100644
--- a/src/lib/netlist/plib/pexception.h
+++ b/src/lib/netlist/plib/pexception.h
@@ -9,118 +9,116 @@
#define PEXCEPTION_H_
#include "pstring.h"
+#include "ptypes.h"
#include <exception>
namespace plib {
-//============================================================
-// exception base
-//============================================================
-
-class pexception : public std::exception
-{
-public:
- explicit pexception(const pstring &text);
- pexception(const pexception &e) : std::exception(e), m_text(e.m_text) { }
-
- virtual ~pexception() noexcept;
-
- const pstring &text() { return m_text; }
- const char* what() const noexcept override { return m_text.c_str(); }
-
-private:
- pstring m_text;
-};
-
-class file_e : public plib::pexception
-{
-public:
- file_e(const pstring &fmt, const pstring &filename);
- file_e(const file_e &e) : pexception(e) { }
- virtual ~file_e() noexcept;
-};
-
-class file_open_e : public file_e
-{
-public:
- explicit file_open_e(const pstring &filename);
- file_open_e(const file_open_e &e) : file_e(e) { }
- virtual ~file_open_e() noexcept;
-};
-
-class file_read_e : public file_e
-{
-public:
- explicit file_read_e(const pstring &filename);
- file_read_e(const file_read_e &e) : file_e(e) { }
- virtual ~file_read_e() noexcept;
-};
-
-class file_write_e : public file_e
-{
-public:
- explicit file_write_e(const pstring &filename);
- file_write_e(const file_write_e &e) : file_e(e) { }
- virtual ~file_write_e() noexcept;
-};
-
-class null_argument_e : public plib::pexception
-{
-public:
- explicit null_argument_e(const pstring &argument);
- null_argument_e(const null_argument_e &e) : pexception(e) { }
- virtual ~null_argument_e() noexcept;
-};
-
-class out_of_mem_e : public plib::pexception
-{
-public:
- explicit out_of_mem_e(const pstring &location);
- out_of_mem_e(const out_of_mem_e &e) : pexception(e) { }
- virtual ~out_of_mem_e() noexcept;
-};
-
-/* FIXME: currently only a stub for later use. More use could be added by
- * using “-fnon-call-exceptions" and sigaction to enable c++ exception supported.
- */
-
-class fpexception_e : public pexception
-{
-public:
- explicit fpexception_e(const pstring &text);
- fpexception_e(const fpexception_e &e) : pexception(e) { }
- virtual ~fpexception_e() noexcept;
-};
-
-static constexpr unsigned FP_INEXACT = 0x0001;
-static constexpr unsigned FP_DIVBYZERO = 0x0002;
-static constexpr unsigned FP_UNDERFLOW = 0x0004;
-static constexpr unsigned FP_OVERFLOW = 0x0008;
-static constexpr unsigned FP_INVALID = 0x00010;
-static constexpr unsigned FP_ALL = 0x0001f;
-
-/*
- * Catch SIGFPE on linux for debugging purposes.
- */
-
-class fpsignalenabler
-{
-public:
- explicit fpsignalenabler(unsigned fpexceptions);
- ~fpsignalenabler();
-
- /* is the functionality supported ? */
- static bool supported();
- /* returns last global enable state */
- static bool global_enable(bool enable);
-
-private:
- int m_last_enabled;
-
- static bool m_enable;
-};
-
-}
+ //============================================================
+ // terminate
+ //============================================================
+
+ /*! Terminate the program
+ *
+ * \note could be enhanced by setting a termination handler
+ */
+ [[noreturn]] void terminate(const pstring &msg) noexcept;
+
+ //============================================================
+ // exception base
+ //============================================================
+
+ class pexception : public std::exception
+ {
+ public:
+ explicit pexception(const pstring &text);
+
+ const pstring &text() { return m_text; }
+ const char* what() const noexcept override { return m_text.c_str(); }
+
+ private:
+ pstring m_text;
+ };
+
+ class file_e : public plib::pexception
+ {
+ public:
+ file_e(const pstring &fmt, const pstring &filename);
+ };
+
+ class file_open_e : public file_e
+ {
+ public:
+ explicit file_open_e(const pstring &filename);
+ };
+
+ class file_read_e : public file_e
+ {
+ public:
+ explicit file_read_e(const pstring &filename);
+ };
+
+ class file_write_e : public file_e
+ {
+ public:
+ explicit file_write_e(const pstring &filename);
+ };
+
+ class null_argument_e : public plib::pexception
+ {
+ public:
+ explicit null_argument_e(const pstring &argument);
+ };
+
+ class out_of_mem_e : public plib::pexception
+ {
+ public:
+ explicit out_of_mem_e(const pstring &location);
+ };
+
+ /* FIXME: currently only a stub for later use. More use could be added by
+ * using “-fnon-call-exceptions" and sigaction to enable c++ exception supported.
+ */
+
+ class fpexception_e : public pexception
+ {
+ public:
+ explicit fpexception_e(const pstring &text);
+ };
+
+ static constexpr unsigned FP_INEXACT = 0x0001;
+ static constexpr unsigned FP_DIVBYZERO = 0x0002;
+ static constexpr unsigned FP_UNDERFLOW = 0x0004;
+ static constexpr unsigned FP_OVERFLOW = 0x0008;
+ static constexpr unsigned FP_INVALID = 0x00010;
+ static constexpr unsigned FP_ALL = 0x0001f;
+
+ /*
+ * Catch SIGFPE on linux for debugging purposes.
+ */
+
+ class fpsignalenabler
+ {
+ public:
+ explicit fpsignalenabler(unsigned fpexceptions);
+
+ COPYASSIGNMOVE(fpsignalenabler, delete)
+
+ ~fpsignalenabler();
+
+ /* is the functionality supported ? */
+ static bool supported();
+ /* returns last global enable state */
+ static bool global_enable(bool enable);
+
+ private:
+ int m_last_enabled;
+
+ static bool m_enable;
+ };
+
+
+} // namespace plib
#endif /* PEXCEPTION_H_ */
diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp
index b8b5fcb3b91..af87251fbdf 100644
--- a/src/lib/netlist/plib/pfmtlog.cpp
+++ b/src/lib/netlist/plib/pfmtlog.cpp
@@ -8,83 +8,96 @@
#include "pfmtlog.h"
#include "palloc.h"
-#include <cstring>
-#include <cstdlib>
-#include <cstdarg>
#include <algorithm>
-#include <locale>
+#include <array>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include <iostream>
+#include <locale>
namespace plib {
pfmt &pfmt::format_element(const char *l, const unsigned cfmt_spec, ...)
{
va_list ap;
- va_start(ap, cfmt_spec);
- pstring fmt("%");
- char buf[2048]; // FIXME
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
+ std::array<char, 2048> buf;
std::size_t sl;
+ bool found_abs = false;
m_arg++;
- pstring search("{");
- search += plib::to_string(m_arg);
- sl = search.length();
+ do {
+ pstring fmt("%");
+ va_start(ap, cfmt_spec);
+ found_abs = false;
+ buf[0] = 0;
+ pstring search("{");
+ search += plib::to_string(m_arg);
+ sl = search.size();
- auto p = m_str.find(search + ":");
- sl++; // ":"
- if (p == pstring::npos) // no further specifiers
- {
- p = m_str.find(search + "}");
- if (p == pstring::npos) // not found try default
- {
- sl = 2;
- p = m_str.find("{}");
- }
- if (p == pstring::npos)
+ auto p = m_str.find(search + ":");
+ sl++; // ":"
+ if (p == pstring::npos) // no further specifiers
{
- sl=1;
- p = m_str.find("{");
- if (p != pstring:: npos)
+ p = m_str.find(search + "}");
+ if (p == pstring::npos) // not found try default
{
- auto p1 = m_str.find("}", p);
- if (p1 != pstring::npos)
+ sl = 2;
+ p = m_str.find("{}");
+ }
+ else
+ // found absolute positional place holder
+ found_abs = true;
+ if (p == pstring::npos)
+ {
+ sl=2;
+ p = m_str.find("{:");
+ if (p != pstring:: npos)
{
- sl = p1 - p + 1;
- fmt += m_str.substr(p+1, p1 - p - 1);
+ auto p1 = m_str.find("}", p);
+ if (p1 != pstring::npos)
+ {
+ sl = p1 - p + 1;
+ fmt += m_str.substr(p+1, p1 - p - 1);
+ }
}
}
}
- }
- else
- {
- auto p1 = m_str.find("}", p);
- if (p1 != pstring::npos)
+ else
+ {
+ // found absolute positional place holder
+ auto p1 = m_str.find("}", p);
+ if (p1 != pstring::npos)
+ {
+ sl = p1 - p + 1;
+ fmt += ((m_arg>=10) ? m_str.substr(p+4, p1 - p - 4) : m_str.substr(p+3, p1 - p - 3));
+ found_abs = true;
+ }
+ }
+ pstring::value_type pend = fmt.at(fmt.size() - 1);
+ if (pstring("duxo").find(cfmt_spec) != pstring::npos)
{
- sl = p1 - p + 1;
- fmt += ((m_arg>=10) ? m_str.substr(p+4, p1 - p - 4) : m_str.substr(p+3, p1 - p - 3));
+ if (pstring("duxo").find(pend) == pstring::npos)
+ fmt += (pstring(l) + static_cast<pstring::value_type>(cfmt_spec));
+ else
+ fmt = plib::left(fmt, fmt.size() - 1) + pstring(l) + plib::right(fmt, 1);
+ }
+ else if (pstring("fge").find(cfmt_spec) != pstring::npos)
+ {
+ if (pstring("fge").find(pend) == pstring::npos)
+ fmt += cfmt_spec;
}
- }
- pstring::code_t pend = fmt.at(fmt.length() - 1);
- if (pstring("duxo").find(cfmt_spec) != pstring::npos)
- {
- if (pstring("duxo").find(pend) == pstring::npos)
- fmt += (pstring(l, pstring::UTF8) + cfmt_spec);
else
- fmt = fmt.left(fmt.length() - 1) + pstring(l, pstring::UTF8) + fmt.right(1);
- }
- else if (pstring("fge").find(cfmt_spec) != pstring::npos)
- {
- if (pstring("fge").find(pend) == pstring::npos)
fmt += cfmt_spec;
- }
- else
- fmt += cfmt_spec;
- vsprintf(buf, fmt.c_str(), ap);
- if (p != pstring::npos)
- m_str = m_str.substr(0, p) + pstring(buf, pstring::UTF8) + m_str.substr(p + sl);
- va_end(ap);
+ std::vsnprintf(buf.data(), buf.size(), fmt.c_str(), ap);
+ if (p != pstring::npos)
+ m_str = m_str.substr(0, p) + pstring(buf.data()) + m_str.substr(p + sl);
+ va_end(ap);
+ } while (found_abs);
return *this;
}
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h
index 9b7a85d8d8d..cb9b59c01ce 100644
--- a/src/lib/netlist/plib/pfmtlog.h
+++ b/src/lib/netlist/plib/pfmtlog.h
@@ -9,6 +9,7 @@
#include "pstring.h"
#include "ptypes.h"
+#include "putil.h"
#include <limits>
@@ -34,7 +35,6 @@ struct ptype_traits_base
template <>
struct ptype_traits_base<bool>
{
- static unsigned int cast(bool &x) { return static_cast<unsigned int>(x); }
static unsigned int cast(const bool &x) { return static_cast<unsigned int>(x); }
static const bool is_signed = std::numeric_limits<bool>::is_signed;
static const char *size_spec() { return ""; }
@@ -136,7 +136,6 @@ struct ptype_traits<double> : ptype_traits_base<double>
static char32_t fmt_spec() { return 'f'; }
};
-
template<>
struct ptype_traits<char *> : ptype_traits_base<char *>
{
@@ -144,6 +143,13 @@ struct ptype_traits<char *> : ptype_traits_base<char *>
static char32_t fmt_spec() { return 's'; }
};
+template<>
+struct ptype_traits<std::string> : ptype_traits_base<char *>
+{
+ static const char *cast(const std::string &x) { return x.c_str(); }
+ static char32_t fmt_spec() { return 's'; }
+};
+
class pfmt
{
public:
@@ -151,44 +157,57 @@ public:
: m_str(fmt), m_arg(0)
{
}
+ COPYASSIGNMOVE(pfmt, default)
- pfmt(const pfmt &rhs) : m_str(rhs.m_str), m_arg(rhs.m_arg) { }
-
- ~pfmt()
- {
- }
+ ~pfmt() noexcept = default;
operator pstring() const { return m_str; }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
pfmt & e(const double &x) {return format_element("", 'e', x); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
pfmt & g(const double &x) {return format_element("", 'g', x); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
pfmt & e(const float &x) {return format_element("", 'e', static_cast<double>(x)); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
pfmt & g(const float &x) {return format_element("", 'g', static_cast<double>(x)); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
pfmt &operator ()(const void *x) {return format_element("", 'p', x); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
pfmt &operator ()(const pstring &x) {return format_element("", 's', x.c_str() ); }
template<typename T>
pfmt &operator ()(const T &x)
{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
return format_element(ptype_traits<T>::size_spec(), ptype_traits<T>::fmt_spec(), ptype_traits<T>::cast(x));
}
template<typename T>
pfmt &operator ()(const T *x)
{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
return format_element(ptype_traits<T *>::size_spec(), ptype_traits<T *>::fmt_spec(), ptype_traits<T *>::cast(x));
}
+ template<typename X, typename Y, typename... Args>
+ pfmt &operator()(X&& x, Y && y, Args&&... args)
+ {
+ return ((*this)(std::forward<X>(x)))(std::forward<Y>(y), std::forward<Args>(args)...);
+ }
+
template<typename T>
pfmt &x(const T &x)
{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
return format_element(ptype_traits<T>::size_spec(), 'x', x);
}
template<typename T>
pfmt &o(const T &x)
{
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
return format_element(ptype_traits<T>::size_spec(), 'o', x);
}
@@ -203,11 +222,13 @@ private:
};
template <class T, bool build_enabled = true>
-class pfmt_writer_t : plib::nocopyassignmove
+class pfmt_writer_t
{
public:
explicit pfmt_writer_t() : m_enabled(true) { }
+ COPYASSIGNMOVE(pfmt_writer_t, delete)
+
/* runtime enable */
template<bool enabled, typename... Args>
void log(const pstring & fmt, Args&&... args) const
@@ -237,7 +258,7 @@ public:
bool is_enabled() const { return m_enabled; }
protected:
- ~pfmt_writer_t() { }
+ ~pfmt_writer_t() noexcept = default;
private:
pfmt &xlog(pfmt &fmt) const { return fmt; }
@@ -258,7 +279,10 @@ class plog_channel : public pfmt_writer_t<plog_channel<T, L, build_enabled>, bui
friend class pfmt_writer_t<plog_channel<T, L, build_enabled>, build_enabled>;
public:
explicit plog_channel(T &b) : pfmt_writer_t<plog_channel, build_enabled>(), m_base(b) { }
- ~plog_channel() { }
+
+ COPYASSIGNMOVE(plog_channel, delete)
+
+ ~plog_channel() noexcept = default;
protected:
void vdowrite(const pstring &ls) const
@@ -283,7 +307,9 @@ public:
error(proxy),
fatal(proxy)
{}
- virtual ~plog_base() {}
+
+ COPYASSIGNMOVE(plog_base, default)
+ virtual ~plog_base() noexcept = default;
plog_channel<T, plog_level::DEBUG, debug_enabled> debug;
plog_channel<T, plog_level::INFO> info;
@@ -293,7 +319,7 @@ public:
plog_channel<T, plog_level::FATAL> fatal;
};
-}
+} // namespace plib
template<typename T>
plib::pfmt& operator<<(plib::pfmt &p, T&& val) { return p(std::forward<T>(val)); }
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp
index 79f09cb4a46..6a2179e0e6f 100644
--- a/src/lib/netlist/plib/pfunction.cpp
+++ b/src/lib/netlist/plib/pfunction.cpp
@@ -6,9 +6,9 @@
*/
#include "pfunction.h"
+#include "pexception.h"
#include "pfmtlog.h"
#include "putil.h"
-#include "pexception.h"
#include <cmath>
#include <stack>
@@ -17,7 +17,7 @@ namespace plib {
void pfunction::compile(const std::vector<pstring> &inputs, const pstring &expr)
{
- if (expr.startsWith("rpn:"))
+ if (plib::startsWith(expr, "rpn:"))
compile_postfix(inputs, expr.substr(4));
else
compile_infix(inputs, expr);
@@ -56,7 +56,7 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
{ rc.m_cmd = RAND; stk += 1; }
else
{
- for (unsigned i = 0; i < inputs.size(); i++)
+ for (std::size_t i = 0; i < inputs.size(); i++)
{
if (inputs[i] == cmd)
{
@@ -68,9 +68,9 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
}
if (rc.m_cmd != PUSH_INPUT)
{
- bool err = false;
rc.m_cmd = PUSH_CONST;
- rc.m_param = cmd.as_double(&err);
+ bool err;
+ rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err);
if (err)
throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
stk += 1;
@@ -84,11 +84,11 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
throw plib::pexception(plib::pfmt("nld_function: stack count different to one on <{2}>")(expr));
}
-static int get_prio(pstring v)
+static int get_prio(const pstring &v)
{
if (v == "(" || v == ")")
return 1;
- else if (v.left(1) >= "a" && v.left(1) <= "z")
+ else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z")
return 0;
else if (v == "*" || v == "/")
return 20;
@@ -113,12 +113,11 @@ void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring
{
// Shunting-yard infix parsing
std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"};
- std::vector<pstring> sexpr(plib::psplit(expr.replace_all(" ",""), sep));
+ std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, pstring(" "), pstring("")), sep));
std::stack<pstring> opstk;
std::vector<pstring> postfix;
- //printf("dbg: %s\n", expr.c_str());
- for (unsigned i = 0; i < sexpr.size(); i++)
+ for (std::size_t i = 0; i < sexpr.size(); i++)
{
pstring &s = sexpr[i];
if (s=="(")
@@ -182,14 +181,15 @@ void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring
#define OP(OP, ADJ, EXPR) \
case OP: \
- ptr-=ADJ; \
- stack[ptr-1] = EXPR; \
+ ptr-= (ADJ); \
+ stack[ptr-1] = (EXPR); \
break;
double pfunction::evaluate(const std::vector<double> &values)
{
- double stack[20];
+ std::array<double, 20> stack = { 0 };
unsigned ptr = 0;
+ stack[0] = 0.0;
for (auto &rc : m_precompiled)
{
switch (rc.m_cmd)
@@ -199,8 +199,8 @@ double pfunction::evaluate(const std::vector<double> &values)
OP(SUB, 1, ST2 - ST1)
OP(DIV, 1, ST2 / ST1)
OP(POW, 1, std::pow(ST2, ST1))
- OP(SIN, 0, std::sin(ST2));
- OP(COS, 0, std::cos(ST2));
+ OP(SIN, 0, std::sin(ST2))
+ OP(COS, 0, std::cos(ST2))
case RAND:
stack[ptr++] = lfsr_random();
break;
@@ -215,4 +215,4 @@ double pfunction::evaluate(const std::vector<double> &values)
return stack[ptr-1];
}
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h
index 7d5984f9d15..fbb6c508333 100644
--- a/src/lib/netlist/plib/pfunction.h
+++ b/src/lib/netlist/plib/pfunction.h
@@ -8,8 +8,8 @@
#ifndef PFUNCTION_H_
#define PFUNCTION_H_
-#include "pstring.h"
#include "pstate.h"
+#include "pstring.h"
#include <vector>
@@ -112,6 +112,6 @@ namespace plib {
};
-}
+} // namespace plib
#endif /* PEXCEPTION_H_ */
diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h
index 5fefa658b83..c2fee9c2f8e 100644
--- a/src/lib/netlist/plib/plists.h
+++ b/src/lib/netlist/plib/plists.h
@@ -12,6 +12,8 @@
#include "pstring.h"
+#include <array>
+#include <type_traits>
#include <vector>
namespace plib {
@@ -29,14 +31,13 @@ class uninitialised_array_t
{
public:
- typedef C* iterator;
- typedef const C* const_iterator;
+ using iterator = C *;
+ using const_iterator = const C *;
- uninitialised_array_t()
- {
- }
+ uninitialised_array_t() noexcept = default;
- ~uninitialised_array_t()
+ COPYASSIGNMOVE(uninitialised_array_t, delete)
+ ~uninitialised_array_t() noexcept
{
for (std::size_t i=0; i<N; i++)
(*this)[i].~C();
@@ -51,7 +52,7 @@ public:
const C& operator[](const std::size_t &index) const noexcept
{
- return *reinterpret_cast<C *>(&m_buf[index]);
+ return *reinterpret_cast<const C *>(&m_buf[index]);
}
template<typename... Args>
@@ -75,7 +76,8 @@ protected:
private:
/* ensure proper alignment */
- typename std::aligned_storage<sizeof(C), alignof(C)>::type m_buf[N];
+ PALIGNAS_VECTOROPT()
+ std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf;
};
// ----------------------------------------------------------------------------------------
@@ -83,6 +85,7 @@ private:
// the list allows insertions / deletions if used properly
// ----------------------------------------------------------------------------------------
+#if 0
template <class LC>
class linkedlist_t
{
@@ -152,9 +155,10 @@ public:
void remove(const LC *elem) noexcept
{
auto p = &m_head;
- for ( ; *p != elem; p = &((*p)->m_next))
+ while(*p != elem)
{
//nl_assert(*p != nullptr);
+ p = &((*p)->m_next);
}
(*p) = elem->m_next;
}
@@ -166,7 +170,105 @@ public:
private:
LC *m_head;
};
+#else
+template <class LC>
+class linkedlist_t
+{
+public:
+
+ struct element_t
+ {
+ public:
+
+ friend class linkedlist_t<LC>;
+
+ constexpr element_t() : m_next(nullptr), m_prev(nullptr) {}
+ ~element_t() noexcept = default;
+
+ COPYASSIGNMOVE(element_t, delete)
+
+ constexpr LC *next() const noexcept { return m_next; }
+ constexpr LC *prev() const noexcept { return m_prev; }
+ private:
+ LC * m_next;
+ LC * m_prev;
+ };
+
+ struct iter_t final : public std::iterator<std::forward_iterator_tag, LC>
+ {
+ private:
+ LC* p;
+ public:
+ explicit constexpr iter_t(LC* x) noexcept : p(x) { }
+ constexpr iter_t(iter_t &rhs) noexcept : p(rhs.p) { }
+ iter_t(iter_t &&rhs) noexcept { std::swap(*this, rhs); }
+ iter_t& operator=(const iter_t &rhs) noexcept { iter_t t(rhs); std::swap(*this, t); return *this; }
+ iter_t& operator=(iter_t &&rhs) noexcept { std::swap(*this, rhs); return *this; }
+ iter_t& operator++() noexcept {p = p->next();return *this;}
+ // NOLINTNEXTLINE(cert-dcl21-cpp)
+ iter_t operator++(int) & noexcept {const iter_t tmp(*this); operator++(); return tmp;}
+
+ ~iter_t() = default;
+
+ constexpr bool operator==(const iter_t& rhs) const noexcept {return p == rhs.p;}
+ constexpr bool operator!=(const iter_t& rhs) const noexcept {return p != rhs.p;}
+ /* constexpr */ LC& operator*() noexcept {return *p;}
+ /* constexpr */ LC* operator->() noexcept {return p;}
+
+ constexpr LC& operator*() const noexcept {return *p;}
+ constexpr LC* operator->() const noexcept {return p;}
+ };
+
+ constexpr linkedlist_t() : m_head(nullptr) {}
-}
+ constexpr iter_t begin() const noexcept { return iter_t(m_head); }
+ constexpr iter_t end() const noexcept { return iter_t(nullptr); }
+
+ void push_front(LC *elem) noexcept
+ {
+ if (m_head)
+ m_head->m_prev = elem;
+ elem->m_next = m_head;
+ elem->m_prev = nullptr;
+ m_head = elem;
+ }
+
+ void push_back(LC *elem) noexcept
+ {
+ LC ** p(&m_head);
+ LC * prev(nullptr);
+ while (*p != nullptr)
+ {
+ prev = *p;
+ p = &((*p)->m_next);
+ }
+ *p = elem;
+ elem->m_prev = prev;
+ elem->m_next = nullptr;
+ }
+
+ void remove(const LC *elem) noexcept
+ {
+ if (elem->m_prev)
+ elem->m_prev->m_next = elem->m_next;
+ else
+ m_head = elem->m_next;
+ if (elem->m_next)
+ elem->m_next->m_prev = elem->m_prev;
+ else
+ {
+ /* update tail */
+ }
+ }
+
+ LC *front() const noexcept { return m_head; }
+ void clear() noexcept { m_head = nullptr; }
+ constexpr bool empty() const noexcept { return (m_head == nullptr); }
+
+private:
+ LC *m_head;
+};
+#endif
+} // namespace plib
#endif /* PLISTS_H_ */
diff --git a/src/lib/netlist/plib/pmain.cpp b/src/lib/netlist/plib/pmain.cpp
index 93c4076bac2..b381d96dca7 100644
--- a/src/lib/netlist/plib/pmain.cpp
+++ b/src/lib/netlist/plib/pmain.cpp
@@ -23,7 +23,7 @@ namespace plib {
char *buf = new char[dst_char_count + 1];
WideCharToMultiByte(CP_UTF8, 0, w, wlen, buf, dst_char_count, nullptr, nullptr);
buf[dst_char_count] = 0;
- auto ret = pstring(buf, pstring::UTF8);
+ auto ret = pstring(buf);
delete [] buf;
return ret;
}
@@ -37,18 +37,13 @@ namespace plib {
: options()
, pout_strm()
, perr_strm()
- , pout(pout_strm)
- , perr(perr_strm)
+ , pout(&pout_strm)
+ , perr(&perr_strm)
{
}
- app::~app()
- {
-
- }
-
- int app::main_utfX(int argc, char *argv[])
+ int app::main_utfX(int argc, char **argv)
{
auto r = this->parse(argc, argv);
int ret = 0;
diff --git a/src/lib/netlist/plib/pmain.h b/src/lib/netlist/plib/pmain.h
index e2f84b90de6..4f4be779251 100644
--- a/src/lib/netlist/plib/pmain.h
+++ b/src/lib/netlist/plib/pmain.h
@@ -10,20 +10,21 @@
#ifndef PMAIN_H_
#define PMAIN_H_
+#include "palloc.h"
#include "poptions.h"
+#include "pstream.h"
#include "pstring.h"
#include "putil.h"
-#include "pstream.h"
-#include <memory>
#include <cwchar>
+#include <memory>
#ifdef _WIN32
#define PMAIN(appclass) \
extern "C" int wmain(int argc, wchar_t *argv[]) { return plib::app::mainrun<appclass, wchar_t>(argc, argv); }
#else
#define PMAIN(appclass) \
-int main(int argc, char *argv[]) { return plib::app::mainrun<appclass, char>(argc, argv); }
+int main(int argc, char **argv) { return plib::app::mainrun<appclass, char>(argc, argv); }
#endif
@@ -36,7 +37,10 @@ namespace plib {
{
public:
app();
- virtual ~app();
+
+ COPYASSIGNMOVE(app, delete)
+
+ virtual ~app() = default;
virtual pstring usage() = 0;
virtual int execute() = 0;
@@ -48,21 +52,21 @@ namespace plib {
plib::putf8_fmt_writer perr;
template <class C, typename T>
- static int mainrun(int argc, T *argv[])
+ static int mainrun(int argc, T **argv)
{
- auto a = std::unique_ptr<C>(new C);
+ auto a = plib::make_unique<C>();
return a->main_utfX(argc, argv);
}
private:
- int main_utfX(int argc, char *argv[]);
+ int main_utfX(int argc, char **argv);
#ifdef _WIN32
int main_utfX(int argc, wchar_t *argv[]);
#endif
};
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pmatrix2d.h b/src/lib/netlist/plib/pmatrix2d.h
new file mode 100644
index 00000000000..eab533688d7
--- /dev/null
+++ b/src/lib/netlist/plib/pmatrix2d.h
@@ -0,0 +1,85 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * pmatrix2d.h
+ *
+ * NxM regular matrix
+ *
+ */
+
+#ifndef PMATRIX2D_H_
+#define PMATRIX2D_H_
+
+#include "palloc.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+#include <type_traits>
+#include <vector>
+
+namespace plib
+{
+
+
+ template<typename T, typename A = aligned_allocator<T>>
+ class pmatrix2d
+ {
+ public:
+ using value_type = T;
+ using allocator_type = A;
+
+ static constexpr const std::size_t align_size = align_traits<A>::align_size;
+ static constexpr const std::size_t stride_size = align_traits<A>::stride_size;
+ pmatrix2d()
+ : m_N(0), m_M(0), m_stride(8), m_v()
+ {
+ }
+
+ pmatrix2d(std::size_t N, std::size_t M)
+ : m_N(N), m_M(M), m_v()
+ {
+ m_stride = ((M + stride_size-1) / stride_size) * stride_size;
+ m_v.resize(N * m_stride);
+ }
+
+ void resize(std::size_t N, std::size_t M)
+ {
+ m_N = N;
+ m_M = M;
+ m_stride = ((M + stride_size-1) / stride_size) * stride_size;
+ m_v.resize(N * m_stride);
+ }
+
+ C14CONSTEXPR T * operator[] (std::size_t row) noexcept
+ {
+ return assume_aligned_ptr<T, align_size>(&m_v[m_stride * row]);
+ }
+
+ constexpr const T * operator[] (std::size_t row) const noexcept
+ {
+ return assume_aligned_ptr<T, align_size>(&m_v[m_stride * row]);
+ }
+
+ T & operator()(std::size_t r, std::size_t c) noexcept
+ {
+ return (*this)[r][c];
+ }
+
+ const T & operator()(std::size_t r, std::size_t c) const noexcept
+ {
+ return (*this)[r][c];
+ }
+
+ private:
+
+ std::size_t m_N;
+ std::size_t m_M;
+ std::size_t m_stride;
+
+ std::vector<T, A> m_v;
+ };
+
+} // namespace plib
+
+#endif /* MAT_CR_H_ */
diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h
new file mode 100644
index 00000000000..f55807c86dc
--- /dev/null
+++ b/src/lib/netlist/plib/pmempool.h
@@ -0,0 +1,187 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * pmempool.h
+ *
+ */
+
+#ifndef PMEMPOOL_H_
+#define PMEMPOOL_H_
+
+#include "palloc.h"
+#include "pstream.h"
+#include "pstring.h"
+#include "ptypes.h"
+#include "putil.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace plib {
+
+ //============================================================
+ // Memory pool
+ //============================================================
+
+ class mempool
+ {
+ private:
+ struct block
+ {
+ block(mempool *mp, std::size_t min_bytes)
+ : m_num_alloc(0)
+ , m_cur(0)
+ , m_data(nullptr)
+ , m_mempool(mp)
+ {
+ min_bytes = std::max(mp->m_min_alloc, min_bytes);
+ m_free = min_bytes;
+ std::size_t alloc_bytes = (min_bytes + mp->m_min_align - 1) & ~(mp->m_min_align - 1);
+ m_data_allocated = static_cast<char *>(::operator new(alloc_bytes));
+ void *r = m_data_allocated;
+ std::align(mp->m_min_align, min_bytes, r, alloc_bytes);
+ m_data = reinterpret_cast<char *>(r);
+ }
+ std::size_t m_num_alloc;
+ std::size_t m_free;
+ std::size_t m_cur;
+ char *m_data;
+ char *m_data_allocated;
+ mempool *m_mempool;
+ };
+
+ struct info
+ {
+ info(block *b, std::size_t p) : m_block(b), m_pos(p) { }
+ ~info() = default;
+ COPYASSIGNMOVE(info, default)
+
+ block * m_block;
+ std::size_t m_pos;
+ };
+
+
+ block * new_block(std::size_t min_bytes)
+ {
+ auto *b = plib::pnew<block>(this, min_bytes);
+ m_blocks.push_back(b);
+ return b;
+ }
+
+
+ static std::unordered_map<void *, info> &sinfo()
+ {
+ static std::unordered_map<void *, info> spinfo;
+ return spinfo;
+ }
+
+ size_t m_min_alloc;
+ size_t m_min_align;
+
+ std::vector<block *> m_blocks;
+
+ public:
+ static constexpr const bool is_stateless = false;
+ template <class T, std::size_t ALIGN = alignof(T)>
+ using allocator_type = arena_allocator<mempool, T, ALIGN>;
+
+ mempool(size_t min_alloc = (1<<21), size_t min_align = 16)
+ : m_min_alloc(min_alloc), m_min_align(min_align)
+ {
+ }
+
+ COPYASSIGNMOVE(mempool, delete)
+
+ ~mempool()
+ {
+
+ for (auto & b : m_blocks)
+ {
+ if (b->m_num_alloc != 0)
+ {
+ plib::perrlogger("Found {} info blocks\n", sinfo().size());
+ plib::perrlogger("Found block with {} dangling allocations\n", b->m_num_alloc);
+ }
+ ::operator delete(b->m_data);
+ }
+ }
+
+ void *allocate(size_t align, size_t size)
+ {
+ if (align < m_min_align)
+ align = m_min_align;
+
+ size_t rs = size + align;
+ for (auto &b : m_blocks)
+ {
+ if (b->m_free > rs)
+ {
+ b->m_free -= rs;
+ b->m_num_alloc++;
+ auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur);
+ auto capacity(rs);
+ ret = std::align(align, size, ret, capacity);
+ // FIXME: if (ret == nullptr)
+ // printf("Oh no\n");
+ sinfo().insert({ ret, info(b, b->m_cur)});
+ rs -= (capacity - size);
+ b->m_cur += rs;
+
+ return ret;
+ }
+ }
+ {
+ block *b = new_block(rs);
+ b->m_num_alloc = 1;
+ b->m_free = m_min_alloc - rs;
+ auto *ret = reinterpret_cast<void *>(b->m_data + b->m_cur);
+ auto capacity(rs);
+ ret = std::align(align, size, ret, capacity);
+ // FIXME: if (ret == nullptr)
+ // printf("Oh no\n");
+ sinfo().insert({ ret, info(b, b->m_cur)});
+ rs -= (capacity - size);
+ b->m_cur += rs;
+ return ret;
+ }
+ }
+
+ static void deallocate(void *ptr)
+ {
+
+ auto it = sinfo().find(ptr);
+ if (it == sinfo().end())
+ plib::terminate("mempool::free - pointer not found\n");
+ info i = it->second;
+ block *b = i.m_block;
+ if (b->m_num_alloc == 0)
+ plib::terminate("mempool::free - double free was called\n");
+ else
+ {
+ //b->m_free = m_min_alloc;
+ //b->cur_ptr = b->data;
+ }
+ b->m_num_alloc--;
+ //printf("Freeing in block %p %lu\n", b, b->m_num_alloc);
+ sinfo().erase(it);
+ }
+
+ template <typename T>
+ using owned_pool_ptr = plib::owned_ptr<T, arena_deleter<mempool, T>>;
+
+ template<typename T, typename... Args>
+ owned_pool_ptr<T> make_poolptr(Args&&... args)
+ {
+ auto *mem = this->allocate(alignof(T), sizeof(T));
+ return owned_pool_ptr<T>(new (mem) T(std::forward<Args>(args)...), true, arena_deleter<mempool, T>(this));
+ }
+
+ };
+
+} // namespace plib
+
+#endif /* PMEMPOOL_H_ */
diff --git a/src/lib/netlist/plib/pomp.h b/src/lib/netlist/plib/pomp.h
index 6559207f09d..f8a516df485 100644
--- a/src/lib/netlist/plib/pomp.h
+++ b/src/lib/netlist/plib/pomp.h
@@ -11,6 +11,8 @@
#include "pconfig.h"
+#include <cstddef>
+
#if HAS_OPENMP
#include "omp.h"
#endif
@@ -18,29 +20,39 @@
namespace plib {
namespace omp {
-template <class T>
-void for_static(const int start, const int end, const T &what)
+template <typename I, class T>
+void for_static(const I start, const I end, const T &what)
{
#if HAS_OPENMP && USE_OPENMP
#pragma omp parallel
#endif
{
#if HAS_OPENMP && USE_OPENMP
- #pragma omp for schedule(static)
+ #pragma omp for //schedule(static)
#endif
- for (int i = start; i < end; i++)
+ for (I i = start; i < end; i++)
what(i);
}
}
-inline void set_num_threads(const int threads)
+template <typename I, class T>
+void for_static_np(const I start, const I end, const T &what)
+{
+ for (I i = start; i < end; i++)
+ what(i);
+}
+
+
+inline void set_num_threads(const std::size_t threads)
{
#if HAS_OPENMP && USE_OPENMP
omp_set_num_threads(threads);
+#else
+ plib::unused_var(threads);
#endif
}
-inline int get_max_threads()
+inline std::size_t get_max_threads()
{
#if HAS_OPENMP && USE_OPENMP
return omp_get_max_threads();
@@ -54,7 +66,7 @@ inline int get_max_threads()
// pdynlib: dynamic loading of libraries ...
// ----------------------------------------------------------------------------------------
-}
-}
+} // namespace omp
+} // namespace plib
#endif /* PSTRING_H_ */
diff --git a/src/lib/netlist/plib/poptions.cpp b/src/lib/netlist/plib/poptions.cpp
index 910660acb3d..4a3d32c4723 100644
--- a/src/lib/netlist/plib/poptions.cpp
+++ b/src/lib/netlist/plib/poptions.cpp
@@ -6,77 +6,39 @@
*/
#include "poptions.h"
+#include "pexception.h"
+#include "ptypes.h"
namespace plib {
/***************************************************************************
Options
***************************************************************************/
- option_base::option_base(options &parent, pstring help)
+ option_base::option_base(options &parent, const pstring &help)
: m_help(help)
{
parent.register_option(this);
}
- option_base::~option_base()
- {
- }
-
- option_group::~option_group()
- {
- }
-
- option_example::~option_example()
- {
- }
-
- option::option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument)
+ option::option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument)
: option_base(parent, help), m_short(ashort), m_long(along),
m_has_argument(has_argument), m_specified(false)
{
}
- option::~option()
- {
- }
-
int option_str::parse(const pstring &argument)
{
m_val = argument;
return 0;
}
- int option_str_limit::parse(const pstring &argument)
- {
- if (plib::container::contains(m_limit, argument))
- {
- m_val = argument;
- return 0;
- }
- else
- return 1;
- }
-
int option_bool::parse(const pstring &argument)
{
+ unused_var(argument);
m_val = true;
return 0;
}
- int option_double::parse(const pstring &argument)
- {
- bool err = false;
- m_val = argument.as_double(&err);
- return (err ? 1 : 0);
- }
-
- int option_long::parse(const pstring &argument)
- {
- bool err = false;
- m_val = argument.as_long(&err);
- return (err ? 1 : 0);
- }
-
int option_vec::parse(const pstring &argument)
{
bool err = false;
@@ -85,53 +47,88 @@ namespace plib {
}
options::options()
+ : m_other_args(nullptr)
{
}
- options::options(option *o[])
+ options::options(option **o)
+ : m_other_args(nullptr)
{
int i=0;
while (o[i] != nullptr)
{
- m_opts.push_back(o[i]);
+ register_option(o[i]);
i++;
}
}
- options::~options()
+ void options::register_option(option_base *opt)
{
- m_opts.clear();
+ m_opts.push_back(opt);
}
- void options::register_option(option_base *opt)
+ void options::check_consistency()
{
- m_opts.push_back(opt);
+ for (auto &opt : m_opts)
+ {
+ auto *o = dynamic_cast<option *>(opt);
+ if (o != nullptr)
+ {
+ if (o->short_opt() == "" && o->long_opt() == "")
+ {
+ auto *ov = dynamic_cast<option_args *>(o);
+ if (ov != nullptr)
+ {
+ if (m_other_args != nullptr)
+ {
+ throw pexception("other args can only be specified once!");
+ }
+ else
+ {
+ m_other_args = ov;
+ }
+ }
+ else
+ throw pexception("found option with neither short or long tag!" );
+ }
+ }
+ }
}
- int options::parse(int argc, char *argv[])
+ int options::parse(int argc, char **argv)
{
- m_app = pstring(argv[0], pstring::UTF8);
+ check_consistency();
+ m_app = pstring(argv[0]);
+ bool seen_other_args = false;
for (int i=1; i<argc; )
{
- pstring arg(argv[i], pstring::UTF8);
+ pstring arg(argv[i]);
option *opt = nullptr;
pstring opt_arg;
bool has_equal_arg = false;
- if (arg.startsWith("--"))
+ if (!seen_other_args && plib::startsWith(arg, "--"))
{
auto v = psplit(arg.substr(2),"=");
- opt = getopt_long(v[0]);
- has_equal_arg = (v.size() > 1);
- if (has_equal_arg)
+ if (v.size() && v[0] != pstring(""))
{
- for (unsigned j = 1; j < v.size() - 1; j++)
- opt_arg = opt_arg + v[j] + "=";
- opt_arg += v[v.size()-1];
+ opt = getopt_long(v[0]);
+ has_equal_arg = (v.size() > 1);
+ if (has_equal_arg)
+ {
+ for (std::size_t j = 1; j < v.size() - 1; j++)
+ opt_arg = opt_arg + v[j] + "=";
+ opt_arg += v[v.size()-1];
+ }
+ }
+ else
+ {
+ opt = m_other_args;
+ seen_other_args = true;
}
}
- else if (arg.startsWith("-"))
+ else if (!seen_other_args && plib::startsWith(arg, "-"))
{
std::size_t p = 1;
opt = getopt_short(arg.substr(p, 1));
@@ -144,7 +141,11 @@ namespace plib {
}
else
{
- return i;
+ seen_other_args = true;
+ if (m_other_args == nullptr)
+ return i;
+ opt = m_other_args;
+ i--; // we haven't had an option specifier;
}
if (opt == nullptr)
return i;
@@ -158,7 +159,7 @@ namespace plib {
else
{
i++; // FIXME: are there more arguments?
- if (opt->do_parse(pstring(argv[i], pstring::UTF8)) != 0)
+ if (opt->do_parse(pstring(argv[i])) != 0)
return i - 1;
}
}
@@ -173,7 +174,7 @@ namespace plib {
return argc;
}
- pstring options::split_paragraphs(pstring text, unsigned width, unsigned indent,
+ pstring options::split_paragraphs(const pstring &text, unsigned width, unsigned indent,
unsigned firstline_indent)
{
auto paragraphs = psplit(text,"\n");
@@ -181,13 +182,13 @@ namespace plib {
for (auto &p : paragraphs)
{
- pstring line = pstring("").rpad(" ", firstline_indent);
+ pstring line = plib::rpad(pstring(""), pstring(" "), firstline_indent);
for (auto &s : psplit(p, " "))
{
if (line.length() + s.length() > width)
{
ret += line + "\n";
- line = pstring("").rpad(" ", indent);
+ line = plib::rpad(pstring(""), pstring(" "), indent);
}
line += s + " ";
}
@@ -196,8 +197,8 @@ namespace plib {
return ret;
}
- pstring options::help(pstring description, pstring usage,
- unsigned width, unsigned indent)
+ pstring options::help(const pstring &description, const pstring &usage,
+ unsigned width, unsigned indent) const
{
pstring ret;
@@ -206,6 +207,10 @@ namespace plib {
for (auto & optbase : m_opts )
{
+ // Skip anonymous inputs which are collected in option_args
+ if (dynamic_cast<option_args *>(optbase) != nullptr)
+ continue;
+
if (auto opt = dynamic_cast<option *>(optbase))
{
pstring line = "";
@@ -221,20 +226,20 @@ namespace plib {
if (opt->has_argument())
{
line += "=";
- option_str_limit *ol = dynamic_cast<option_str_limit *>(opt);
+ auto *ol = dynamic_cast<option_str_limit_base *>(opt);
if (ol)
{
for (auto &v : ol->limit())
{
line += v + "|";
}
- line = line.left(line.length() - 1);
+ line = plib::left(line, line.length() - 1);
}
else
line += "Value";
}
}
- line = line.rpad(" ", indent - 2) + " ";
+ line = plib::rpad(line, pstring(" "), indent - 2) + " ";
if (line.length() > indent)
{
//ret += "TestGroup abc\n def gef\nxyz\n\n" ;
@@ -250,6 +255,7 @@ namespace plib {
if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n";
}
}
+ // FIXME: other help ...
pstring ex("");
for (auto & optbase : m_opts )
{
@@ -266,22 +272,22 @@ namespace plib {
return ret;
}
- option *options::getopt_short(pstring arg)
+ option *options::getopt_short(const pstring &arg) const
{
for (auto & optbase : m_opts)
{
auto opt = dynamic_cast<option *>(optbase);
- if (opt && opt->short_opt() == arg)
+ if (opt && arg != "" && opt->short_opt() == arg)
return opt;
}
return nullptr;
}
- option *options::getopt_long(pstring arg)
+ option *options::getopt_long(const pstring &arg) const
{
for (auto & optbase : m_opts)
{
auto opt = dynamic_cast<option *>(optbase);
- if (opt && opt->long_opt() == arg)
+ if (opt && arg !="" && opt->long_opt() == arg)
return opt;
}
return nullptr;
diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h
index 491ac0b4d91..086fe32fc8a 100644
--- a/src/lib/netlist/plib/poptions.h
+++ b/src/lib/netlist/plib/poptions.h
@@ -10,8 +10,8 @@
#ifndef POPTIONS_H_
#define POPTIONS_H_
-#include "pstring.h"
#include "plists.h"
+#include "pstring.h"
#include "putil.h"
namespace plib {
@@ -24,10 +24,12 @@ class options;
class option_base
{
public:
- option_base(options &parent, pstring help);
- virtual ~option_base();
+ option_base(options &parent, const pstring &help);
+ virtual ~option_base() = default;
+
+ COPYASSIGNMOVE(option_base, delete)
- pstring help() { return m_help; }
+ pstring help() const { return m_help; }
private:
pstring m_help;
};
@@ -35,11 +37,10 @@ private:
class option_group : public option_base
{
public:
- option_group(options &parent, pstring group, pstring help)
+ option_group(options &parent, const pstring &group, const pstring &help)
: option_base(parent, help), m_group(group) { }
- ~option_group();
- pstring group() { return m_group; }
+ pstring group() const { return m_group; }
private:
pstring m_group;
};
@@ -47,11 +48,10 @@ private:
class option_example : public option_base
{
public:
- option_example(options &parent, pstring group, pstring help)
+ option_example(options &parent, const pstring &group, const pstring &help)
: option_base(parent, help), m_example(group) { }
- ~option_example();
- pstring example() { return m_example; }
+ pstring example() const { return m_example; }
private:
pstring m_example;
};
@@ -60,8 +60,7 @@ private:
class option : public option_base
{
public:
- option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument);
- ~option();
+ option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument);
/* no_argument options will be called with "" argument */
@@ -89,131 +88,177 @@ private:
class option_str : public option
{
public:
- option_str(options &parent, pstring ashort, pstring along, pstring defval, pstring help)
+ option_str(options &parent, const pstring &ashort, const pstring &along, const pstring &defval, const pstring &help)
: option(parent, ashort, along, help, true), m_val(defval)
{}
- pstring operator ()() { return m_val; }
+ pstring operator ()() const { return m_val; }
protected:
- virtual int parse(const pstring &argument) override;
+ int parse(const pstring &argument) override;
private:
pstring m_val;
};
-class option_str_limit : public option
+class option_str_limit_base : public option
{
public:
- option_str_limit(options &parent, pstring ashort, pstring along, pstring defval, pstring limit, pstring help)
- : option(parent, ashort, along, help, true), m_val(defval)
- , m_limit(plib::psplit(limit, ":"))
+ option_str_limit_base(options &parent, const pstring &ashort, const pstring &along, std::vector<pstring> &&limit, const pstring &help)
+ : option(parent, ashort, along, help, true)
+ , m_limit(limit)
{
}
-
- pstring operator ()() { return m_val; }
- const std::vector<pstring> &limit() { return m_limit; }
+ const std::vector<pstring> &limit() const { return m_limit; }
protected:
- virtual int parse(const pstring &argument) override;
private:
- pstring m_val;
std::vector<pstring> m_limit;
};
-class option_bool : public option
+
+template <typename T>
+class option_str_limit : public option_str_limit_base
{
public:
- option_bool(options &parent, pstring ashort, pstring along, pstring help)
- : option(parent, ashort, along, help, false), m_val(false)
- {}
+ option_str_limit(options &parent, const pstring &ashort, const pstring &along, const T &defval, std::vector<pstring> &&limit, const pstring &help)
+ : option_str_limit_base(parent, ashort, along, std::move(limit), help), m_val(defval)
+ {
+ }
+
+ T operator ()() const { return m_val; }
- bool operator ()() { return m_val; }
+ pstring as_string() const { return limit()[m_val]; }
protected:
- virtual int parse(const pstring &argument) override;
+ int parse(const pstring &argument) override
+ {
+ auto raw = plib::container::indexof(limit(), argument);
+
+ if (raw != plib::container::npos)
+ {
+ m_val = static_cast<T>(raw);
+ return 0;
+ }
+ else
+ return 1;
+ }
private:
- bool m_val;
+ T m_val;
};
-class option_double : public option
+class option_bool : public option
{
public:
- option_double(options &parent, pstring ashort, pstring along, double defval, pstring help)
- : option(parent, ashort, along, help, true), m_val(defval)
+ option_bool(options &parent, const pstring &ashort, const pstring &along, const pstring &help)
+ : option(parent, ashort, along, help, false), m_val(false)
{}
- double operator ()() { return m_val; }
+ bool operator ()() const { return m_val; }
protected:
- virtual int parse(const pstring &argument) override;
+ int parse(const pstring &argument) override;
private:
- double m_val;
+ bool m_val;
};
-class option_long : public option
+template <typename T>
+class option_num : public option
{
public:
- option_long(options &parent, pstring ashort, pstring along, long defval, pstring help)
- : option(parent, ashort, along, help, true), m_val(defval)
+ option_num(options &parent, const pstring &ashort, const pstring &along, T defval,
+ const pstring &help,
+ T minval = std::numeric_limits<T>::min(),
+ T maxval = std::numeric_limits<T>::max() )
+ : option(parent, ashort, along, help, true)
+ , m_val(defval)
+ , m_min(minval)
+ , m_max(maxval)
{}
- long operator ()() { return m_val; }
+ T operator ()() const { return m_val; }
protected:
- virtual int parse(const pstring &argument) override;
+ int parse(const pstring &argument) override
+ {
+ bool err;
+ m_val = pstonum_ne<T>(argument, err);
+ return (err ? 1 : (m_val < m_min || m_val > m_max));
+ }
private:
- long m_val;
+ T m_val;
+ T m_min;
+ T m_max;
};
class option_vec : public option
{
public:
- option_vec(options &parent, pstring ashort, pstring along, pstring help)
+ option_vec(options &parent, const pstring &ashort, const pstring &along, const pstring &help)
: option(parent, ashort, along, help, true)
{}
- std::vector<pstring> operator ()() { return m_val; }
+ const std::vector<pstring> &operator ()() const { return m_val; }
protected:
- virtual int parse(const pstring &argument) override;
+ int parse(const pstring &argument) override;
private:
std::vector<pstring> m_val;
};
-class options
+class option_args : public option_vec
{
public:
+ option_args(options &parent, const pstring &help)
+ : option_vec(parent, "", "", help)
+ {}
+};
- options();
- explicit options(option *o[]);
+class options : public nocopyassignmove
+{
+public:
- ~options();
+ options();
+ explicit options(option **o);
void register_option(option_base *opt);
- int parse(int argc, char *argv[]);
+ int parse(int argc, char **argv);
- pstring help(pstring description, pstring usage,
- unsigned width = 72, unsigned indent = 20);
+ pstring help(const pstring &description, const pstring &usage,
+ unsigned width = 72, unsigned indent = 20) const;
- pstring app() { return m_app; }
+ pstring app() const { return m_app; }
private:
- static pstring split_paragraphs(pstring text, unsigned width, unsigned indent,
+ static pstring split_paragraphs(const pstring &text, unsigned width, unsigned indent,
unsigned firstline_indent);
- option *getopt_short(pstring arg);
- option *getopt_long(pstring arg);
+ void check_consistency();
+
+ template <typename T>
+ T *getopt_type() const
+ {
+ for (auto & optbase : m_opts )
+ {
+ if (auto opt = dynamic_cast<T *>(optbase))
+ return opt;
+ }
+ return nullptr;
+ }
+
+ option *getopt_short(const pstring &arg) const;
+ option *getopt_long(const pstring &arg) const;
std::vector<option_base *> m_opts;
pstring m_app;
+ option_args * m_other_args;
};
-}
+} // namespace plib
#endif /* POPTIONS_H_ */
diff --git a/src/lib/netlist/plib/pparser.cpp b/src/lib/netlist/plib/pparser.cpp
index 7547572192d..5e1a231da81 100644
--- a/src/lib/netlist/plib/pparser.cpp
+++ b/src/lib/netlist/plib/pparser.cpp
@@ -16,16 +16,6 @@ namespace plib {
// A simple tokenizer
// ----------------------------------------------------------------------------------------
-ptokenizer::ptokenizer(plib::putf8_reader &strm)
-: m_strm(strm), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"')
-{
-}
-
-ptokenizer::~ptokenizer()
-{
-}
-
-
pstring ptokenizer::currentline_str()
{
return m_cur_line;
@@ -34,7 +24,7 @@ pstring ptokenizer::currentline_str()
void ptokenizer::skipeol()
{
- pstring::code_t c = getc();
+ pstring::value_type c = getc();
while (c)
{
if (c == 10)
@@ -49,11 +39,11 @@ void ptokenizer::skipeol()
}
-pstring::code_t ptokenizer::getc()
+pstring::value_type ptokenizer::getc()
{
if (m_unget != 0)
{
- pstring::code_t c = m_unget;
+ pstring::value_type c = m_unget;
m_unget = 0;
return c;
}
@@ -66,11 +56,11 @@ pstring::code_t ptokenizer::getc()
return 0;
return '\n';
}
- pstring::code_t c = *(m_px++);
+ pstring::value_type c = *(m_px++);
return c;
}
-void ptokenizer::ungetc(pstring::code_t c)
+void ptokenizer::ungetc(pstring::value_type c)
{
m_unget = c;
}
@@ -122,6 +112,7 @@ pstring ptokenizer::get_identifier_or_number()
return tok.str();
}
+// FIXME: combine into template
double ptokenizer::get_number_double()
{
token_t tok = get_token();
@@ -129,8 +120,8 @@ double ptokenizer::get_number_double()
{
error(pfmt("Expected a number, got <{1}>")(tok.str()) );
}
- bool err = false;
- double ret = tok.str().as_double(&err);
+ bool err;
+ auto ret = plib::pstonum_ne<double>(tok.str(), err);
if (err)
error(pfmt("Expected a number, got <{1}>")(tok.str()) );
return ret;
@@ -143,8 +134,8 @@ long ptokenizer::get_number_long()
{
error(pfmt("Expected a long int, got <{1}>")(tok.str()) );
}
- bool err = false;
- long ret = tok.str().as_long(&err);
+ bool err;
+ auto ret = plib::pstonum_ne<long>(tok.str(), err);
if (err)
error(pfmt("Expected a long int, got <{1}>")(tok.str()) );
return ret;
@@ -182,7 +173,7 @@ ptokenizer::token_t ptokenizer::get_token()
ptokenizer::token_t ptokenizer::get_token_internal()
{
/* skip ws */
- pstring::code_t c = getc();
+ pstring::value_type c = getc();
while (m_whitespace.find(c) != pstring::npos)
{
c = getc();
@@ -272,28 +263,31 @@ void ptokenizer::error(const pstring &errs)
// A simple preprocessor
// ----------------------------------------------------------------------------------------
-ppreprocessor::ppreprocessor(std::vector<define_t> *defines)
-: m_ifflag(0), m_level(0), m_lineno(0)
+ppreprocessor::ppreprocessor(defines_map_type *defines)
+: pistream()
+, m_ifflag(0)
+, m_level(0)
+, m_lineno(0)
+, m_pos(0)
+, m_state(PROCESS)
+, m_comment(false)
{
- m_expr_sep.push_back("!");
- m_expr_sep.push_back("(");
- m_expr_sep.push_back(")");
- m_expr_sep.push_back("+");
- m_expr_sep.push_back("-");
- m_expr_sep.push_back("*");
- m_expr_sep.push_back("/");
- m_expr_sep.push_back("==");
- m_expr_sep.push_back(" ");
- m_expr_sep.push_back("\t");
+ m_expr_sep.emplace_back("!");
+ m_expr_sep.emplace_back("(");
+ m_expr_sep.emplace_back(")");
+ m_expr_sep.emplace_back("+");
+ m_expr_sep.emplace_back("-");
+ m_expr_sep.emplace_back("*");
+ m_expr_sep.emplace_back("/");
+ m_expr_sep.emplace_back("&&");
+ m_expr_sep.emplace_back("||");
+ m_expr_sep.emplace_back("==");
+ m_expr_sep.emplace_back(" ");
+ m_expr_sep.emplace_back("\t");
- m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")});
if (defines != nullptr)
- {
- for (auto & p : *defines)
- {
- m_defines.insert({p.m_name, p});
- }
- }
+ m_defines = *defines;
+ m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")});
}
void ppreprocessor::error(const pstring &err)
@@ -301,35 +295,42 @@ void ppreprocessor::error(const pstring &err)
throw pexception("PREPRO ERROR: " + err);
}
+pstream::size_type ppreprocessor::vread(value_type *buf, const pstream::size_type n)
+{
+ size_type bytes = std::min(m_buf.size() - m_pos, n);
+
+ if (bytes==0)
+ return 0;
+
+ std::memcpy(buf, m_buf.c_str() + m_pos, bytes);
+ m_pos += bytes;
+ return bytes;
+}
+
+#define CHECKTOK2(p_op, p_prio) \
+ else if (tok == # p_op) \
+ { \
+ if (prio < (p_prio)) \
+ return val; \
+ start++; \
+ const auto v2 = expr(sexpr, start, (p_prio)); \
+ val = (val p_op v2); \
+ } \
+// Operator precedence see https://en.cppreference.com/w/cpp/language/operator_precedence
-double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio)
+int ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio)
{
- double val;
+ int val = 0;
pstring tok=sexpr[start];
if (tok == "(")
{
start++;
- val = expr(sexpr, start, /*prio*/ 0);
+ val = expr(sexpr, start, /*prio*/ 255);
if (sexpr[start] != ")")
error("parsing error!");
start++;
}
- else if (tok == "!")
- {
- start++;
- val = expr(sexpr, start, 90);
- if (val != 0)
- val = 0;
- else
- val = 1;
- }
- else
- {
- tok=sexpr[start];
- val = tok.as_double();
- start++;
- }
while (start < sexpr.size())
{
tok=sexpr[start];
@@ -338,36 +339,25 @@ double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start
// FIXME: catch error
return val;
}
- else if (tok == "+")
+ else if (tok == "!")
{
- if (prio > 10)
+ if (prio < 3)
return val;
start++;
- val = val + expr(sexpr, start, 10);
+ val = !expr(sexpr, start, 3);
}
- else if (tok == "-")
- {
- if (prio > 10)
- return val;
- start++;
- val = val - expr(sexpr, start, 10);
- }
- else if (tok == "*")
- {
- start++;
- val = val * expr(sexpr, start, 20);
- }
- else if (tok == "/")
- {
- start++;
- val = val / expr(sexpr, start, 20);
- }
- else if (tok == "==")
+ CHECKTOK2(*, 5)
+ CHECKTOK2(/, 5)
+ CHECKTOK2(+, 6)
+ CHECKTOK2(-, 6)
+ CHECKTOK2(==, 10)
+ CHECKTOK2(&&, 14)
+ CHECKTOK2(||, 15)
+ else
{
- if (prio > 5)
- return val;
+ // FIXME: error handling
+ val = plib::pstonum<decltype(val)>(tok);
start++;
- val = (val == expr(sexpr, start, 5)) ? 1.0 : 0.0;
}
}
return val;
@@ -376,10 +366,7 @@ double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start
ppreprocessor::define_t *ppreprocessor::get_define(const pstring &name)
{
auto idx = m_defines.find(name);
- if (idx != m_defines.end())
- return &idx->second;
- else
- return nullptr;
+ return (idx != m_defines.end()) ? &idx->second : nullptr;
}
pstring ppreprocessor::replace_macros(const pstring &line)
@@ -389,78 +376,135 @@ pstring ppreprocessor::replace_macros(const pstring &line)
for (auto & elem : elems)
{
define_t *def = get_define(elem);
- if (def != nullptr)
- ret += def->m_replace;
- else
- ret += elem;
+ ret += (def != nullptr) ? def->m_replace : elem;
}
return ret;
}
-static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, pstring sep)
+static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, const pstring &sep)
{
pstring ret("");
- for (auto & elem : elems)
+ for (std::size_t i = start; i < elems.size(); i++)
{
- ret += elem;
+ ret += elems[i];
ret += sep;
}
return ret;
}
-pstring ppreprocessor::process_line(const pstring &line)
+pstring ppreprocessor::process_comments(pstring line)
+{
+ bool in_string = false;
+
+ std::size_t e = line.size();
+ pstring ret = "";
+ for (std::size_t i=0; i < e; )
+ {
+ pstring c = plib::left(line, 1);
+ line = line.substr(1);
+ if (!m_comment)
+ {
+ if (c=="\"")
+ {
+ in_string = !in_string;
+ ret += c;
+ }
+ else if (in_string && c=="\\")
+ {
+ i++;
+ ret += (c + plib::left(line, 1));
+ line = line.substr(1);
+ }
+ else if (!in_string && c=="/" && plib::left(line,1) == "*")
+ m_comment = true;
+ else if (!in_string && c=="/" && plib::left(line,1) == "/")
+ break;
+ else
+ ret += c;
+ }
+ else
+ if (c=="*" && plib::left(line,1) == "/")
+ {
+ i++;
+ line = line.substr(1);
+ m_comment = false;
+ }
+ i++;
+ }
+ return ret;
+}
+
+pstring ppreprocessor::process_line(pstring line)
{
- pstring lt = line.replace_all("\t"," ").trim();
+ bool line_cont = plib::right(line, 1) == "\\";
+ if (line_cont)
+ line = plib::left(line, line.size() - 1);
+
+ if (m_state == LINE_CONTINUATION)
+ m_line += line;
+ else
+ m_line = line;
+
+ if (line_cont)
+ {
+ m_state = LINE_CONTINUATION;
+ return "";
+ }
+ else
+ m_state = PROCESS;
+
+ line = process_comments(m_line);
+
+ pstring lt = plib::trim(plib::replace_all(line, pstring("\t"), pstring(" ")));
pstring ret;
- m_lineno++;
// FIXME ... revise and extend macro handling
- if (lt.startsWith("#"))
+ if (plib::startsWith(lt, "#"))
{
std::vector<pstring> lti(psplit(lt, " ", true));
- if (lti[0].equals("#if"))
+ if (lti[0] == "#if")
{
m_level++;
std::size_t start = 0;
lt = replace_macros(lt);
- std::vector<pstring> t(psplit(lt.substr(3).replace_all(" ",""), m_expr_sep));
- int val = static_cast<int>(expr(t, start, 0));
+ std::vector<pstring> t(psplit(replace_all(lt.substr(3), pstring(" "), pstring("")), m_expr_sep));
+ auto val = static_cast<int>(expr(t, start, 255));
if (val == 0)
m_ifflag |= (1 << m_level);
}
- else if (lti[0].equals("#ifdef"))
+ else if (lti[0] == "#ifdef")
{
m_level++;
if (get_define(lti[1]) == nullptr)
m_ifflag |= (1 << m_level);
}
- else if (lti[0].equals("#ifndef"))
+ else if (lti[0] == "#ifndef")
{
m_level++;
if (get_define(lti[1]) != nullptr)
m_ifflag |= (1 << m_level);
}
- else if (lti[0].equals("#else"))
+ else if (lti[0] == "#else")
{
m_ifflag ^= (1 << m_level);
}
- else if (lti[0].equals("#endif"))
+ else if (lti[0] == "#endif")
{
m_ifflag &= ~(1 << m_level);
m_level--;
}
- else if (lti[0].equals("#include"))
+ else if (lti[0] == "#include")
{
// ignore
}
- else if (lti[0].equals("#pragma"))
+ else if (lti[0] == "#pragma")
{
- if (m_ifflag == 0 && lti.size() > 3 && lti[1].equals("NETLIST"))
+ if (m_ifflag == 0 && lti.size() > 3 && lti[1] == "NETLIST")
{
- if (lti[2].equals("warning"))
+ if (lti[2] == "warning")
error("NETLIST: " + catremainder(lti, 3, " "));
}
}
- else if (lti[0].equals("#define"))
+ else if (lti[0] == "#define")
{
if (m_ifflag == 0)
{
@@ -470,28 +514,20 @@ pstring ppreprocessor::process_line(const pstring &line)
}
}
else
- error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(line));
+ {
+ if (m_ifflag == 0)
+ error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(replace_macros(line)));
+ }
}
else
{
lt = replace_macros(lt);
if (m_ifflag == 0)
- {
ret += lt;
- }
}
return ret;
}
-void ppreprocessor::process(putf8_reader &istrm, putf8_writer &ostrm)
-{
- pstring line;
- while (istrm.readline(line))
- {
- line = process_line(line);
- ostrm.writeline(line);
- }
-}
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pparser.h b/src/lib/netlist/plib/pparser.h
index 7ec517255c8..1eca20e99ad 100644
--- a/src/lib/netlist/plib/pparser.h
+++ b/src/lib/netlist/plib/pparser.h
@@ -8,20 +8,27 @@
#ifndef PPARSER_H_
#define PPARSER_H_
-#include "pstring.h"
#include "plists.h"
#include "pstream.h"
+#include "pstring.h"
-#include <unordered_map>
#include <cstdint>
+#include <unordered_map>
+
namespace plib {
-class ptokenizer : nocopyassignmove
+class ptokenizer
{
public:
- explicit ptokenizer(plib::putf8_reader &strm);
+ template <typename T>
+ ptokenizer(T &&strm) // NOLINT(misc-forwarding-reference-overload, bugprone-forwarding-reference-overload)
+ : m_strm(std::forward<T>(strm)), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"')
+ {
+ }
+
+ COPYASSIGNMOVE(ptokenizer, delete)
- virtual ~ptokenizer();
+ virtual ~ptokenizer() = default;
enum token_type
{
@@ -91,22 +98,23 @@ public:
void require_token(const token_id_t &token_num);
void require_token(const token_t &tok, const token_id_t &token_num);
- token_id_t register_token(pstring token)
+ token_id_t register_token(const pstring &token)
{
token_id_t ret(m_tokens.size());
m_tokens.emplace(token, ret);
return ret;
}
- void set_identifier_chars(pstring s) { m_identifier_chars = s; }
- void set_number_chars(pstring st, pstring rem) { m_number_chars_start = st; m_number_chars = rem; }
- void set_string_char(pstring::code_t c) { m_string = c; }
- void set_whitespace(pstring s) { m_whitespace = s; }
- void set_comment(pstring start, pstring end, pstring line)
+ ptokenizer & identifier_chars(pstring s) { m_identifier_chars = std::move(s); return *this; }
+ ptokenizer & number_chars(pstring st, pstring rem) { m_number_chars_start = std::move(st); m_number_chars = std::move(rem); return *this; }
+ ptokenizer & string_char(pstring::value_type c) { m_string = c; return *this; }
+ ptokenizer & whitespace(pstring s) { m_whitespace = std::move(s); return *this; }
+ ptokenizer & comment(const pstring &start, const pstring &end, const pstring &line)
{
m_tok_comment_start = register_token(start);
m_tok_comment_end = register_token(end);
m_tok_line_comment = register_token(line);
+ return *this;
}
token_t get_token_internal();
@@ -118,17 +126,17 @@ protected:
private:
void skipeol();
- pstring::code_t getc();
- void ungetc(pstring::code_t c);
+ pstring::value_type getc();
+ void ungetc(pstring::value_type c);
bool eof() { return m_strm.eof(); }
- putf8_reader &m_strm;
+ putf8_reader m_strm;
int m_lineno;
pstring m_cur_line;
pstring::const_iterator m_px;
- pstring::code_t m_unget;
+ pstring::value_type m_unget;
/* tokenizer stuff follows ... */
@@ -137,7 +145,7 @@ private:
pstring m_number_chars_start;
std::unordered_map<pstring, token_id_t> m_tokens;
pstring m_whitespace;
- pstring::code_t m_string;
+ pstring::value_type m_string;
token_id_t m_tok_comment_start;
token_id_t m_tok_comment_end;
@@ -145,7 +153,7 @@ private:
};
-class ppreprocessor : plib::nocopyassignmove
+class ppreprocessor : public pistream
{
public:
@@ -158,29 +166,80 @@ public:
pstring m_replace;
};
- explicit ppreprocessor(std::vector<define_t> *defines = nullptr);
- virtual ~ppreprocessor() {}
+ using defines_map_type = std::unordered_map<pstring, define_t>;
+
+ explicit ppreprocessor(defines_map_type *defines = nullptr);
+ ~ppreprocessor() override = default;
+
+ template <typename T>
+ ppreprocessor & process(T &&istrm)
+ {
+ putf8_reader reader(std::forward<T>(istrm));
+ pstring line;
+ while (reader.readline(line))
+ {
+ m_lineno++;
+ line = process_line(line);
+ m_buf += decltype(m_buf)(line.c_str()) + static_cast<char>(10);
+ }
+ return *this;
+ }
+
+ COPYASSIGN(ppreprocessor, delete)
+ ppreprocessor &operator=(ppreprocessor &&src) = delete;
- void process(putf8_reader &istrm, putf8_writer &ostrm);
+
+ ppreprocessor(ppreprocessor &&s) noexcept
+ : m_defines(std::move(s.m_defines))
+ , m_expr_sep(std::move(s.m_expr_sep))
+ , m_ifflag(s.m_ifflag)
+ , m_level(s.m_level)
+ , m_lineno(s.m_lineno)
+ , m_buf(std::move(s.m_buf))
+ , m_pos(s.m_pos)
+ , m_state(s.m_state)
+ , m_comment(s.m_comment)
+ {
+ }
protected:
- double expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio);
+
+ size_type vread(value_type *buf, const size_type n) override;
+ void vseek(const pos_type n) override
+ {
+ plib::unused_var(n);
+ /* FIXME throw exception - should be done in base unless implemented */
+ }
+ pos_type vtell() const override { return m_pos; }
+
+ int expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio);
define_t *get_define(const pstring &name);
pstring replace_macros(const pstring &line);
virtual void error(const pstring &err);
private:
- pstring process_line(const pstring &line);
+ enum state_e
+ {
+ PROCESS,
+ LINE_CONTINUATION
+ };
+ pstring process_line(pstring line);
+ pstring process_comments(pstring line);
- std::unordered_map<pstring, define_t> m_defines;
+ defines_map_type m_defines;
std::vector<pstring> m_expr_sep;
std::uint_least64_t m_ifflag; // 31 if levels
int m_level;
int m_lineno;
+ pstring_t<pu8_traits> m_buf;
+ pos_type m_pos;
+ state_e m_state;
+ pstring m_line;
+ bool m_comment;
};
-}
+} // namespace plib
#endif /* PPARSER_H_ */
diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h
index dc151d5d6a6..9c5329cccde 100644
--- a/src/lib/netlist/plib/ppmf.h
+++ b/src/lib/netlist/plib/ppmf.h
@@ -10,9 +10,8 @@
#include "pconfig.h"
-#include <utility>
#include <cstdint>
-
+#include <utility>
/*
*
@@ -70,7 +69,8 @@ namespace plib {
using generic_function = void (*)();
template<typename MemberFunctionType>
- mfp(MemberFunctionType mftp)
+ mfp(MemberFunctionType mftp) // NOLINT(cppcoreguidelines-pro-type-member-init)
+
: m_function(0), m_this_delta(0), m_size(sizeof(mfp))
{
*reinterpret_cast<MemberFunctionType *>(this) = mftp;
@@ -82,7 +82,7 @@ namespace plib {
mfp mfpo(mftp);
//return mfpo.update_after_bind<FunctionType>(object);
generic_function rfunc(nullptr);
- generic_class *robject = reinterpret_cast<generic_class *>(object);
+ auto robject = reinterpret_cast<generic_class *>(object);
mfpo.convert_to_generic(rfunc, robject);
func = reinterpret_cast<FunctionType>(rfunc);
object = reinterpret_cast<ObjectType *>(robject);
@@ -95,7 +95,8 @@ namespace plib {
if (PHAS_PMF_INTERNAL == 1)
{
// apply the "this" delta to the object first
- generic_class * o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
+ // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
+ auto o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta);
// if the low bit of the vtable index is clear, then it is just a raw function pointer
if (!(m_function & 1))
@@ -241,23 +242,28 @@ namespace plib {
{
public:
class generic_class;
+
+ template <class C>
+ using MemberFunctionType = R (C::*)(Targs...);
+
pmfp() : pmfp_base<R, Targs...>(), m_obj(nullptr) {}
- template<typename MemberFunctionType, typename O>
- pmfp(MemberFunctionType mftp, O *object)
+ template<typename O>
+ pmfp(MemberFunctionType<O> mftp, O *object)
: pmfp_base<R, Targs...>()
{
this->set(mftp, object);
}
- template<typename MemberFunctionType, typename O>
- void set(MemberFunctionType mftp, O *object)
+
+ template<typename O>
+ void set(MemberFunctionType<O> mftp, O *object)
{
this->set_base(mftp, object);
m_obj = reinterpret_cast<generic_class *>(object);
}
- inline R operator()(Targs... args)
+ inline R operator()(Targs ... args)
{
return this->call(m_obj, std::forward<Targs>(args)...);
}
@@ -269,6 +275,6 @@ namespace plib {
};
-}
+} // namespace plib
#endif /* PPMF_H_ */
diff --git a/src/lib/netlist/plib/pstate.cpp b/src/lib/netlist/plib/pstate.cpp
index 043033ed1ea..3bd93ed4f8e 100644
--- a/src/lib/netlist/plib/pstate.cpp
+++ b/src/lib/netlist/plib/pstate.cpp
@@ -9,17 +9,6 @@
#include "palloc.h"
namespace plib {
-state_manager_t::state_manager_t()
-{
-}
-
-state_manager_t::~state_manager_t()
-{
- m_save.clear();
- m_custom.clear();
-}
-
-
void state_manager_t::save_state_ptr(const void *owner, const pstring &stname, const datatype_t &dt, const std::size_t count, void *ptr)
{
@@ -29,46 +18,40 @@ void state_manager_t::save_state_ptr(const void *owner, const pstring &stname, c
void state_manager_t::remove_save_items(const void *owner)
{
- for (auto i = m_save.begin(); i != m_save.end(); )
+ auto i = m_save.end();
+ while (i != m_save.begin())
{
+ i--;
if (i->get()->m_owner == owner)
i = m_save.erase(i);
- else
- i++;
}
- for (auto i = m_custom.begin(); i != m_custom.end(); )
+ i = m_custom.end();
+ while (i > m_custom.begin())
{
+ i--;
if (i->get()->m_owner == owner)
i = m_custom.erase(i);
- else
- i++;
}
}
void state_manager_t::pre_save()
{
for (auto & s : m_custom)
- s->m_callback->on_pre_save();
+ s->m_callback->on_pre_save(*this);
}
void state_manager_t::post_load()
{
for (auto & s : m_custom)
- s->m_callback->on_post_load();
+ s->m_callback->on_post_load(*this);
}
template<> void state_manager_t::save_item(const void *owner, callback_t &state, const pstring &stname)
{
- //save_state_ptr(stname, DT_CUSTOM, 0, 1, &state);
callback_t *state_p = &state;
auto p = plib::make_unique<entry_t>(stname, owner, state_p);
m_custom.push_back(std::move(p));
state.register_state(*this, stname);
}
-state_manager_t::callback_t::~callback_t()
-{
-}
-
-
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pstate.h b/src/lib/netlist/plib/pstate.h
index 9757d6408b7..ac75ca6b69e 100644
--- a/src/lib/netlist/plib/pstate.h
+++ b/src/lib/netlist/plib/pstate.h
@@ -8,11 +8,13 @@
#ifndef PSTATE_H_
#define PSTATE_H_
+#include "palloc.h"
#include "pstring.h"
#include "ptypes.h"
-#include <vector>
+#include <array>
#include <memory>
+#include <vector>
// ----------------------------------------------------------------------------------------
// state saving ...
@@ -38,32 +40,31 @@ public:
const bool is_custom;
};
- template<typename T> struct datatype_f
+ template<typename T>
+ static datatype_t dtype()
{
- static inline const datatype_t f()
- {
- return datatype_t(sizeof(T),
- plib::is_integral<T>::value || std::is_enum<T>::value,
- std::is_floating_point<T>::value);
- }
- };
+ return datatype_t(sizeof(T),
+ plib::is_integral<T>::value || std::is_enum<T>::value,
+ std::is_floating_point<T>::value);
+ }
class callback_t
{
public:
using list_t = std::vector<callback_t *>;
- virtual ~callback_t();
-
virtual void register_state(state_manager_t &manager, const pstring &module) = 0;
- virtual void on_pre_save() = 0;
- virtual void on_post_load() = 0;
+ virtual void on_pre_save(state_manager_t &manager) = 0;
+ virtual void on_post_load(state_manager_t &manager) = 0;
protected:
+ callback_t() = default;
+ ~callback_t() = default;
+ COPYASSIGNMOVE(callback_t, default)
};
struct entry_t
{
- using list_t = std::vector<std::unique_ptr<entry_t>>;
+ using list_t = std::vector<plib::unique_ptr<entry_t>>;
entry_t(const pstring &stname, const datatype_t &dt, const void *owner,
const std::size_t count, void *ptr)
@@ -72,8 +73,6 @@ public:
entry_t(const pstring &stname, const void *owner, callback_t *callback)
: m_name(stname), m_dt(datatype_t(true)), m_owner(owner), m_callback(callback), m_count(0), m_ptr(nullptr) { }
- ~entry_t() { }
-
pstring m_name;
const datatype_t m_dt;
const void * m_owner;
@@ -82,35 +81,49 @@ public:
void * m_ptr;
};
- state_manager_t();
- ~state_manager_t();
+ state_manager_t() = default;
- template<typename C> void save_item(const void *owner, C &state, const pstring &stname)
+ template<typename C>
+ void save_item(const void *owner, C &state, const pstring &stname)
{
- save_state_ptr( owner, stname, datatype_f<C>::f(), 1, &state);
+ save_state_ptr( owner, stname, dtype<C>(), 1, &state);
}
- template<typename C, std::size_t N> void save_item(const void *owner, C (&state)[N], const pstring &stname)
+ template<typename C, std::size_t N>
+ void save_item(const void *owner, C (&state)[N], const pstring &stname) // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
{
- save_state_ptr(owner, stname, datatype_f<C>::f(), N, &(state[0]));
+ save_state_ptr(owner, stname, dtype<C>(), N, &(state[0]));
}
- template<typename C> void save_item(const void *owner, C *state, const pstring &stname, const std::size_t count)
+ template<typename C>
+ void save_item(const void *owner, C *state, const pstring &stname, const std::size_t count)
{
- save_state_ptr(owner, stname, datatype_f<C>::f(), count, state);
+ save_state_ptr(owner, stname, dtype<C>(), count, state);
}
template<typename C>
void save_item(const void *owner, std::vector<C> &v, const pstring &stname)
{
- save_state(v.data(), owner, stname, v.size());
+ save_state_ptr(owner, stname, dtype<C>(), v.size(), v.data());
+ }
+
+ template<typename C, std::size_t N>
+ void save_item(const void *owner, std::array<C, N> &a, const pstring &stname)
+ {
+ save_state_ptr(owner, stname, dtype<C>(), N, a.data());
}
void pre_save();
void post_load();
void remove_save_items(const void *owner);
- const entry_t::list_t &save_list() const { return m_save; }
+ const std::vector<const entry_t *> save_list() const
+ {
+ std::vector<const entry_t *> ret;
+ for (auto &i : m_save)
+ ret.push_back(i.get());
+ return ret;
+ }
void save_state_ptr(const void *owner, const pstring &stname, const datatype_t &dt, const std::size_t count, void *ptr);
@@ -124,6 +137,6 @@ private:
template<> void state_manager_t::save_item(const void *owner, callback_t &state, const pstring &stname);
-}
+} // namespace plib
#endif /* PSTATE_H_ */
diff --git a/src/lib/netlist/plib/pstream.cpp b/src/lib/netlist/plib/pstream.cpp
index 420f63c9e5e..a7acdaafb52 100644
--- a/src/lib/netlist/plib/pstream.cpp
+++ b/src/lib/netlist/plib/pstream.cpp
@@ -8,9 +8,9 @@
#include "pstream.h"
#include "palloc.h"
+#include <algorithm>
#include <cstdio>
#include <cstdlib>
-#include <algorithm>
// VS2015 prefers _dup
#ifdef _WIN32
@@ -21,34 +21,14 @@
namespace plib {
-pstream::~pstream()
-{
-}
-
// -----------------------------------------------------------------------------
// pistream: input stream
// -----------------------------------------------------------------------------
-pistream::~pistream()
-{
-}
-
// -----------------------------------------------------------------------------
// postream: output stream
// -----------------------------------------------------------------------------
-postream::~postream()
-{
-}
-
-void postream::write(pistream &strm)
-{
- char buf[1024];
- pos_type r;
- while ((r=strm.read(buf, 1024)) > 0)
- write(buf, r);
-}
-
// -----------------------------------------------------------------------------
// Input file stream
// -----------------------------------------------------------------------------
@@ -91,7 +71,7 @@ pifilestream::~pifilestream()
}
}
-pifilestream::pos_type pifilestream::vread(void *buf, const pos_type n)
+pifilestream::pos_type pifilestream::vread(value_type *buf, const pos_type n)
{
pos_type r = fread(buf, 1, n, static_cast<FILE *>(m_file));
if (r < n)
@@ -119,7 +99,7 @@ void pifilestream::vseek(const pos_type n)
throw file_e("Generic file operation failed: {}", m_filename);
}
-pifilestream::pos_type pifilestream::vtell()
+pifilestream::pos_type pifilestream::vtell() const
{
long ret = ftell(static_cast<FILE *>(m_file));
if (ret < 0)
@@ -140,10 +120,6 @@ pstdin::pstdin()
/* nothing to do */
}
-pstdin::~pstdin()
-{
-}
-
// -----------------------------------------------------------------------------
// Output file stream
// -----------------------------------------------------------------------------
@@ -180,12 +156,11 @@ pofilestream::~pofilestream()
}
}
-void pofilestream::vwrite(const void *buf, const pos_type n)
+void pofilestream::vwrite(const value_type *buf, const pos_type n)
{
std::size_t r = fwrite(buf, 1, n, static_cast<FILE *>(m_file));
if (r < n)
{
- //printf("%ld %ld %s\n", r, n, strerror(errno));
if (ferror(static_cast<FILE *>(m_file)))
throw file_write_e(m_filename);
}
@@ -204,7 +179,7 @@ void pofilestream::vseek(const pos_type n)
}
}
-pstream::pos_type pofilestream::vtell()
+pstream::pos_type pofilestream::vtell() const
{
std::ptrdiff_t ret = ftell(static_cast<FILE *>(m_file));
if (ret < 0)
@@ -215,11 +190,6 @@ pstream::pos_type pofilestream::vtell()
return static_cast<pos_type>(ret);
}
-postringstream::~postringstream()
-{
-}
-
-
// -----------------------------------------------------------------------------
// pstderr: write to stderr
// -----------------------------------------------------------------------------
@@ -233,10 +203,6 @@ pstderr::pstderr()
{
}
-pstderr::~pstderr()
-{
-}
-
// -----------------------------------------------------------------------------
// pstdout: write to stdout
// -----------------------------------------------------------------------------
@@ -250,35 +216,32 @@ pstdout::pstdout()
{
}
-pstdout::~pstdout()
-{
-}
-
// -----------------------------------------------------------------------------
// Memory stream
// -----------------------------------------------------------------------------
pimemstream::pimemstream(const void *mem, const pos_type len)
- : pistream(FLAG_SEEKABLE), m_pos(0), m_len(len), m_mem(static_cast<const pstring::mem_t *>(mem))
+ : pistream(FLAG_SEEKABLE), m_pos(0), m_len(len), m_mem(static_cast<const char *>(mem))
{
}
-pimemstream::pimemstream(const pomemstream &ostrm)
-: pistream(FLAG_SEEKABLE), m_pos(0), m_len(ostrm.size()), m_mem(reinterpret_cast<pstring::mem_t *>(ostrm.memory()))
+pimemstream::pimemstream()
+ : pistream(FLAG_SEEKABLE), m_pos(0), m_len(0), m_mem(static_cast<const char *>(nullptr))
{
}
-pimemstream::~pimemstream()
+pimemstream::pimemstream(const pomemstream &ostrm)
+: pistream(FLAG_SEEKABLE), m_pos(0), m_len(ostrm.size()), m_mem(reinterpret_cast<const char *>(ostrm.memory()))
{
}
-pimemstream::pos_type pimemstream::vread(void *buf, const pos_type n)
+pimemstream::pos_type pimemstream::vread(value_type *buf, const pos_type n)
{
pos_type ret = (m_pos + n <= m_len) ? n : m_len - m_pos;
if (ret > 0)
{
- std::copy(m_mem + m_pos, m_mem + m_pos + ret, static_cast<char *>(buf));
+ std::copy(m_mem + m_pos, m_mem + m_pos + ret, reinterpret_cast<char *>(buf));
m_pos += ret;
}
@@ -295,78 +258,45 @@ void pimemstream::vseek(const pos_type n)
}
-pimemstream::pos_type pimemstream::vtell()
+pimemstream::pos_type pimemstream::vtell() const
{
return m_pos;
}
-pistringstream::~pistringstream()
-{
-}
-
// -----------------------------------------------------------------------------
// Output memory stream
// -----------------------------------------------------------------------------
pomemstream::pomemstream()
-: postream(FLAG_SEEKABLE), m_pos(0), m_capacity(1024), m_size(0)
-{
- m_mem = palloc_array<char>(m_capacity);
-}
-
-pomemstream::~pomemstream()
+: postream(FLAG_SEEKABLE), m_pos(0), m_mem(1024)
{
- pfree_array(m_mem);
+ m_mem.clear();
}
-void pomemstream::vwrite(const void *buf, const pos_type n)
+void pomemstream::vwrite(const value_type *buf, const pos_type n)
{
- if (m_pos + n >= m_capacity)
- {
- while (m_pos + n >= m_capacity)
- m_capacity *= 2;
- char *o = m_mem;
- m_mem = palloc_array<char>(m_capacity);
- if (m_mem == nullptr)
- {
- throw out_of_mem_e("pomemstream::vwrite");
- }
- std::copy(o, o + m_pos, m_mem);
- pfree_array(o);
- }
+ if (m_pos + n >= m_mem.size())
+ m_mem.resize(m_pos + n);
- std::copy(static_cast<const char *>(buf), static_cast<const char *>(buf) + n, m_mem + m_pos);
+ std::copy(buf, buf + n, &m_mem[0] + m_pos);
m_pos += n;
- m_size = std::max(m_pos, m_size);
}
void pomemstream::vseek(const pos_type n)
{
m_pos = n;
- m_size = std::max(m_pos, m_size);
- if (m_size >= m_capacity)
- {
- while (m_size >= m_capacity)
- m_capacity *= 2;
- char *o = m_mem;
- m_mem = palloc_array<char>(m_capacity);
- if (m_mem == nullptr)
- {
- throw out_of_mem_e("pomemstream::vseek");
- }
- std::copy(o, o + m_pos, m_mem);
- pfree_array(o);
- }
+ if (m_pos>=m_mem.size())
+ m_mem.resize(m_pos);
}
-pstream::pos_type pomemstream::vtell()
+pstream::pos_type pomemstream::vtell() const
{
return m_pos;
}
bool putf8_reader::readline(pstring &line)
{
- pstring::code_t c = 0;
+ putf8string::code_t c = 0;
m_linebuf = "";
if (!this->readcode(c))
{
@@ -378,23 +308,14 @@ bool putf8_reader::readline(pstring &line)
if (c == 10)
break;
else if (c != 13) /* ignore CR */
- m_linebuf += pstring(c);
+ m_linebuf += putf8string(c);
if (!this->readcode(c))
break;
}
- line = m_linebuf;
+ line = m_linebuf.c_str();
return true;
}
-putf8_fmt_writer::putf8_fmt_writer(postream &strm)
-: pfmt_writer_t()
-, putf8_writer(strm)
-{
-}
-
-putf8_fmt_writer::~putf8_fmt_writer()
-{
-}
void putf8_fmt_writer::vdowrite(const pstring &ls) const
{
@@ -403,4 +324,4 @@ void putf8_fmt_writer::vdowrite(const pstring &ls) const
-}
+} // namespace plib
diff --git a/src/lib/netlist/plib/pstream.h b/src/lib/netlist/plib/pstream.h
index 3e9ee99cba0..93497eb1423 100644
--- a/src/lib/netlist/plib/pstream.h
+++ b/src/lib/netlist/plib/pstream.h
@@ -7,46 +7,76 @@
#ifndef PSTREAM_H_
#define PSTREAM_H_
+
+#include "palloc.h"
#include "pconfig.h"
-#include "pstring.h"
-#include "pfmtlog.h"
#include "pexception.h"
+#include "pfmtlog.h"
+#include "pstring.h"
+
+#define USE_CSTREAM (0)
+#include <array>
+#include <type_traits>
#include <vector>
+#if USE_CSTREAM
+#include <fstream>
+//#include <strstream>
+#include <sstream>
+#endif
+
namespace plib {
+
+#if USE_CSTREAM
+typedef std::ostream postream;
+typedef std::ofstream pofilestream;
+typedef std::ostringstream postringstream;
+typedef std::ostringstream pomemstream;
+
+#endif
+
// -----------------------------------------------------------------------------
// pstream: things common to all streams
// -----------------------------------------------------------------------------
-class pstream : nocopyassignmove
+class pstream
{
public:
using pos_type = std::size_t;
+ using size_type = std::size_t;
static constexpr pos_type SEEK_EOF = static_cast<pos_type>(-1);
+ COPYASSIGN(pstream, delete)
+ pstream &operator=(pstream &&) noexcept = delete;
+
bool seekable() const { return ((m_flags & FLAG_SEEKABLE) != 0); }
- void seek(const pos_type n)
+ void seekp(const pos_type n)
{
- return vseek(n);
+ vseek(n);
}
- pos_type tell()
+ pos_type tellp() const
{
return vtell();
}
protected:
+ pstream() : m_flags(0)
+ {
+ }
explicit pstream(const unsigned flags) : m_flags(flags)
{
}
- ~pstream();
+ pstream(pstream &&src) noexcept = default;
+
+ virtual ~pstream() = default;
virtual void vseek(const pos_type n) = 0;
- virtual pos_type vtell() = 0;
+ virtual pos_type vtell() const = 0;
static constexpr unsigned FLAG_EOF = 0x01;
static constexpr unsigned FLAG_SEEKABLE = 0x04;
@@ -69,51 +99,71 @@ private:
// pistream: input stream
// -----------------------------------------------------------------------------
-class pistream : public pstream
+template <typename T>
+class pistream_base : public pstream
{
public:
- virtual ~pistream();
+ using value_type = T;
+
+ ~pistream_base() noexcept override = default;
+
+ COPYASSIGN(pistream_base, delete)
+ pistream_base &operator=(pistream_base &&src) noexcept = delete;
bool eof() const { return ((flags() & FLAG_EOF) != 0); }
- pos_type read(void *buf, const pos_type n)
+ pos_type read(T *buf, const pos_type n)
{
return vread(buf, n);
}
protected:
- explicit pistream(const unsigned flags) : pstream(flags) {}
- /* read up to n bytes from stream */
- virtual pos_type vread(void *buf, const pos_type n) = 0;
+ pistream_base() : pstream(0) {}
+ explicit pistream_base(const unsigned flags) : pstream(flags) {}
+ pistream_base(pistream_base &&src) noexcept : pstream(std::move(src)) {}
+ /* read up to n bytes from stream */
+ virtual size_type vread(T *buf, const size_type n) = 0;
};
+using pistream = pistream_base<char>;
+
// -----------------------------------------------------------------------------
// postream: output stream
// -----------------------------------------------------------------------------
-class postream : public pstream
+#if !USE_CSTREAM
+template <typename T>
+class postream_base : public pstream
{
public:
- virtual ~postream();
+ using value_type = T;
+
+ postream_base() = default;
+ ~postream_base() noexcept override = default;
+
+ COPYASSIGN(postream_base, delete)
+ postream_base &operator=(postream_base &&src) noexcept = delete;
- void write(const void *buf, const pos_type n)
+ void write(const T *buf, const size_type n)
{
vwrite(buf, n);
}
- void write(pistream &strm);
-
protected:
- explicit postream(unsigned flags) : pstream(flags) {}
+ explicit postream_base(unsigned flags) : pstream(flags) {}
+ postream_base(postream_base &&src) noexcept : pstream(std::move(src)) {}
+
/* write n bytes to stream */
- virtual void vwrite(const void *buf, const pos_type n) = 0;
+ virtual void vwrite(const T *buf, const size_type n) = 0;
private:
};
+using postream = postream_base<char>;
+
// -----------------------------------------------------------------------------
// pomemstream: output string stream
// -----------------------------------------------------------------------------
@@ -123,22 +173,31 @@ class pomemstream : public postream
public:
pomemstream();
- virtual ~pomemstream() override;
- char *memory() const { return m_mem; }
- pos_type size() const { return m_size; }
+ COPYASSIGN(pomemstream, delete)
+
+ pomemstream(pomemstream &&src) noexcept
+ : postream(std::move(src))
+ , m_pos(src.m_pos)
+ , m_mem(std::move(src.m_mem))
+ {
+ }
+ pomemstream &operator=(pomemstream &&src) = delete;
+
+ ~pomemstream() override = default;
+
+ const char *memory() const { return m_mem.data(); }
+ pos_type size() const { return m_mem.size(); }
protected:
/* write n bytes to stream */
- virtual void vwrite(const void *buf, const pos_type) override;
- virtual void vseek(const pos_type n) override;
- virtual pos_type vtell() override;
+ void vwrite(const value_type *buf, const pos_type) override;
+ void vseek(const pos_type n) override;
+ pos_type vtell() const override;
private:
pos_type m_pos;
- pos_type m_capacity;
- pos_type m_size;
- char *m_mem;
+ std::vector<char> m_mem;
};
class postringstream : public postream
@@ -146,18 +205,26 @@ class postringstream : public postream
public:
postringstream() : postream(0) { }
- virtual ~postringstream() override;
+ postringstream(postringstream &&src) noexcept
+ : postream(std::move(src))
+ , m_buf(std::move(src.m_buf))
+ { src.m_buf = ""; }
+
+ COPYASSIGN(postringstream, delete)
+ postringstream &operator=(postringstream &&src) = delete;
+
+ ~postringstream() override = default;
const pstring &str() { return m_buf; }
protected:
/* write n bytes to stream */
- virtual void vwrite(const void *buf, const pos_type n) override
+ void vwrite(const value_type *buf, const pos_type n) override
{
- m_buf += pstring(static_cast<const pstring::mem_t *>(buf), n, pstring::UTF8);
+ m_buf += pstring(reinterpret_cast<const pstring::mem_t *>(buf), n);
}
- virtual void vseek(const pos_type n) override { }
- virtual pos_type vtell() override { return m_buf.mem_t_size(); }
+ void vseek(const pos_type n) override { unused_var(n); }
+ pos_type vtell() const override { return m_buf.size(); }
private:
pstring m_buf;
@@ -171,15 +238,28 @@ class pofilestream : public postream
{
public:
- explicit pofilestream(const pstring &fname);
- virtual ~pofilestream() override;
+ pofilestream(const pstring &fname);
+ pofilestream(pofilestream &&src) noexcept
+ : postream(std::move(src))
+ , m_file(src.m_file)
+ , m_pos(src.m_pos)
+ , m_actually_close(src.m_actually_close)
+ , m_filename(std::move(src.m_filename))
+ {
+ src.m_file = nullptr;
+ src.m_actually_close = false;
+ }
+ COPYASSIGN(pofilestream, delete)
+ pofilestream &operator=(pofilestream &&src) = delete;
+
+ ~pofilestream() override;
protected:
pofilestream(void *file, const pstring &name, const bool do_close);
/* write n bytes to stream */
- virtual void vwrite(const void *buf, const pos_type n) override;
- virtual void vseek(const pos_type n) override;
- virtual pos_type vtell() override;
+ void vwrite(const value_type *buf, const pos_type n) override;
+ void vseek(const pos_type n) override;
+ pos_type vtell() const override;
private:
void *m_file;
@@ -193,12 +273,17 @@ private:
// -----------------------------------------------------------------------------
// pstderr: write to stderr
// -----------------------------------------------------------------------------
+#endif
class pstderr : public pofilestream
{
public:
pstderr();
- virtual ~pstderr();
+ pstderr(pstderr &&src) noexcept = default;
+ pstderr &operator=(pstderr &&src) = delete;
+ COPYASSIGN(pstderr, delete)
+
+ ~pstderr() noexcept override= default;
};
// -----------------------------------------------------------------------------
@@ -209,7 +294,11 @@ class pstdout : public pofilestream
{
public:
pstdout();
- virtual ~pstdout();
+ pstdout(pstdout &&src) noexcept = default;
+ pstdout &operator=(pstdout &&src) = delete;
+ COPYASSIGN(pstdout, delete)
+
+ ~pstdout() noexcept override = default;
};
// -----------------------------------------------------------------------------
@@ -220,16 +309,29 @@ class pifilestream : public pistream
{
public:
- explicit pifilestream(const pstring &fname);
- virtual ~pifilestream() override;
+ pifilestream(const pstring &fname);
+ ~pifilestream() override;
+
+ pifilestream(pifilestream &&src) noexcept
+ : pistream(std::move(src))
+ , m_file(src.m_file)
+ , m_pos(src.m_pos)
+ , m_actually_close(src.m_actually_close)
+ , m_filename(std::move(src.m_filename))
+ {
+ src.m_actually_close = false;
+ src.m_file = nullptr;
+ }
+ COPYASSIGN(pifilestream, delete)
+ pifilestream &operator=(pifilestream &&src) = delete;
protected:
pifilestream(void *file, const pstring &name, const bool do_close);
/* read up to n bytes from stream */
- virtual pos_type vread(void *buf, const pos_type n) override;
- virtual void vseek(const pos_type n) override;
- virtual pos_type vtell() override;
+ pos_type vread(value_type *buf, const pos_type n) override;
+ void vseek(const pos_type n) override;
+ pos_type vtell() const override;
private:
void *m_file;
@@ -249,7 +351,10 @@ class pstdin : public pifilestream
public:
pstdin();
- virtual ~pstdin() override;
+ pstdin(pstdin &&src) noexcept = default;
+ pstdin &operator=(pstdin &&src) = delete;
+ COPYASSIGN(pstdin, delete)
+ ~pstdin() override = default;
};
// -----------------------------------------------------------------------------
@@ -261,15 +366,36 @@ class pimemstream : public pistream
public:
pimemstream(const void *mem, const pos_type len);
+ pimemstream();
+
+ pimemstream(pimemstream &&src) noexcept
+ : pistream(std::move(src))
+ , m_pos(src.m_pos)
+ , m_len(src.m_len)
+ , m_mem(src.m_mem)
+ {
+ src.m_mem = nullptr;
+ }
+ COPYASSIGN(pimemstream, delete)
+ pimemstream &operator=(pimemstream &&src) = delete;
+
explicit pimemstream(const pomemstream &ostrm);
- virtual ~pimemstream() override;
+
+ ~pimemstream() override = default;
pos_type size() const { return m_len; }
protected:
+
+ void set_mem(const void *mem, const pos_type len)
+ {
+ m_mem = static_cast<const char *>(mem);
+ m_len = len;
+ }
+
/* read up to n bytes from stream */
- virtual pos_type vread(void *buf, const pos_type n) override;
- virtual void vseek(const pos_type n) override;
- virtual pos_type vtell() override;
+ pos_type vread(value_type *buf, const pos_type n) override;
+ void vseek(const pos_type n) override;
+ pos_type vtell() const override;
private:
pos_type m_pos;
@@ -284,12 +410,25 @@ private:
class pistringstream : public pimemstream
{
public:
- explicit pistringstream(const pstring &str) : pimemstream(str.c_str(), str.mem_t_size()), m_str(str) { }
- virtual ~pistringstream() override;
+ pistringstream(const pstring &str)
+ : pimemstream()
+ , m_str(str)
+ {
+ set_mem(m_str.c_str(), std::strlen(m_str.c_str()));
+ }
+ pistringstream(pistringstream &&src) noexcept
+ : pimemstream(std::move(src)), m_str(src.m_str)
+ {
+ set_mem(m_str.c_str(), std::strlen(m_str.c_str()));
+ }
+ COPYASSIGN(pistringstream, delete)
+ pistringstream &operator=(pistringstream &&src) = delete;
+
+ ~pistringstream() override = default;
private:
/* only needed for a reference till destruction */
- pstring m_str;
+ const pstring m_str;
};
// -----------------------------------------------------------------------------
@@ -298,47 +437,84 @@ private:
/* this digests linux & dos/windows text files */
-class putf8_reader : plib::nocopyassignmove
+
+template <typename T>
+struct constructor_helper
+{
+ plib::unique_ptr<pistream> operator()(T &&s) { return std::move(plib::make_unique<T>(std::move(s))); }
+};
+
+// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
+class putf8_reader
{
public:
- explicit putf8_reader(pistream &strm) : m_strm(strm) {}
- virtual ~putf8_reader() {}
- bool eof() const { return m_strm.eof(); }
+ COPYASSIGN(putf8_reader, delete)
+ putf8_reader &operator=(putf8_reader &&src) = delete;
+ virtual ~putf8_reader() = default;
+
+ template <typename T>
+ friend struct constructor_helper;
+
+ template <typename T>
+ putf8_reader(T &&strm) // NOLINT(cppcoreguidelines-special-member-functions, misc-forwarding-reference-overload, bugprone-forwarding-reference-overload)
+ : m_strm(std::move(constructor_helper<T>()(std::move(strm)))) // NOLINT(bugprone-move-forwarding-reference)
+ {}
+
+ bool eof() const { return m_strm->eof(); }
bool readline(pstring &line);
- bool readbyte1(char &b)
+ bool readbyte1(pistream::value_type &b)
{
- return (m_strm.read(&b, 1) == 1);
+ return (m_strm->read(&b, 1) == 1);
}
- bool readcode(pstring::code_t &c)
+ bool readcode(putf8string::traits_type::code_t &c)
{
- char b[4];
- if (m_strm.read(&b[0], 1) != 1)
+ std::array<pistream::value_type, 4> b{0};
+ if (m_strm->read(&b[0], 1) != 1)
return false;
- const std::size_t l = pstring::traits_type::codelen(b);
+ const std::size_t l = putf8string::traits_type::codelen(reinterpret_cast<putf8string::traits_type::mem_t *>(&b));
for (std::size_t i = 1; i < l; i++)
- if (m_strm.read(&b[i], 1) != 1)
+ if (m_strm->read(&b[i], 1) != 1)
return false;
- c = pstring::traits_type::code(b);
+ c = putf8string::traits_type::code(reinterpret_cast<putf8string::traits_type::mem_t *>(&b));
return true;
}
private:
- pistream &m_strm;
- pstring m_linebuf;
+ plib::unique_ptr<pistream> m_strm;
+ putf8string m_linebuf;
};
+template <>
+struct constructor_helper<putf8_reader>
+{
+ plib::unique_ptr<pistream> operator()(putf8_reader &&s) { return std::move(s.m_strm); }
+};
+
+template <>
+struct constructor_helper<plib::unique_ptr<pistream>>
+{
+ plib::unique_ptr<pistream> operator()(plib::unique_ptr<pistream> &&s) { return std::move(s); }
+};
+
+
// -----------------------------------------------------------------------------
// putf8writer_t: writer on top of ostream
// -----------------------------------------------------------------------------
-class putf8_writer : plib::nocopyassignmove
+class putf8_writer
{
public:
- explicit putf8_writer(postream &strm) : m_strm(strm) {}
- virtual ~putf8_writer() {}
+ explicit putf8_writer(postream *strm) : m_strm(strm) {}
+
+ putf8_writer(putf8_writer &&src) noexcept : m_strm(src.m_strm) {}
+
+ COPYASSIGN(putf8_writer, delete)
+ putf8_writer &operator=(putf8_writer &&src) = delete;
+
+ virtual ~putf8_writer() = default;
void writeline(const pstring &line) const
{
@@ -348,24 +524,34 @@ public:
void write(const pstring &text) const
{
- m_strm.write(text.c_str(), text.mem_t_size());
+ // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
+ const putf8string conv_utf8(text);
+ m_strm->write(reinterpret_cast<const pistream::value_type *>(conv_utf8.c_str()), conv_utf8.mem_t_size());
}
- void write(const pstring::code_t c) const
+ void write(const pstring::value_type c) const
{
- write(pstring(c));
+ pstring t = pstring("") + c;
+ write(t);
}
private:
- postream &m_strm;
+ postream *m_strm;
};
class putf8_fmt_writer : public pfmt_writer_t<putf8_fmt_writer>, public putf8_writer
{
public:
- explicit putf8_fmt_writer(postream &strm);
- virtual ~putf8_fmt_writer() override;
+ explicit putf8_fmt_writer(postream *strm)
+ : pfmt_writer_t()
+ , putf8_writer(strm)
+ {
+ }
+
+ COPYASSIGNMOVE(putf8_fmt_writer, delete)
+
+ ~putf8_fmt_writer() override = default;
//protected:
void vdowrite(const pstring &ls) const;
@@ -377,22 +563,29 @@ private:
// pbinary_writer_t: writer on top of ostream
// -----------------------------------------------------------------------------
-class pbinary_writer : plib::nocopyassignmove
+class pbinary_writer
{
public:
explicit pbinary_writer(postream &strm) : m_strm(strm) {}
- virtual ~pbinary_writer() {}
+ pbinary_writer(pbinary_writer &&src) noexcept : m_strm(src.m_strm) {}
+
+ COPYASSIGN(pbinary_writer, delete)
+ postringstream &operator=(pbinary_writer &&src) = delete;
+
+ virtual ~pbinary_writer() = default;
template <typename T>
- void write(const T val)
+ void write(const T &val)
{
- m_strm.write(&val, sizeof(T));
+ m_strm.write(reinterpret_cast<const postream::value_type *>(&val), sizeof(T));
}
void write(const pstring &s)
{
- write(s.mem_t_size());
- m_strm.write(s.c_str(), s.mem_t_size());
+ const auto sm = reinterpret_cast<const postream::value_type *>(s.c_str());
+ const std::size_t sl = std::strlen(s.c_str());
+ write(sl);
+ m_strm.write(sm, sl);
}
template <typename T>
@@ -400,34 +593,38 @@ public:
{
std::size_t sz = val.size();
write(sz);
- m_strm.write(val.data(), sizeof(T) * sz);
+ m_strm.write(reinterpret_cast<const postream::value_type *>(val.data()), sizeof(T) * sz);
}
private:
postream &m_strm;
};
-class pbinary_reader : plib::nocopyassignmove
+class pbinary_reader
{
public:
explicit pbinary_reader(pistream &strm) : m_strm(strm) {}
- virtual ~pbinary_reader() {}
+ pbinary_reader(pbinary_reader &&src) noexcept : m_strm(src.m_strm) { }
+
+ COPYASSIGN(pbinary_reader, delete)
+ pbinary_reader &operator=(pbinary_reader &&src) = delete;
+
+ virtual ~pbinary_reader() = default;
template <typename T>
void read(T &val)
{
- m_strm.read(&val, sizeof(T));
+ m_strm.read(reinterpret_cast<pistream::value_type *>(&val), sizeof(T));
}
void read( pstring &s)
{
std::size_t sz = 0;
read(sz);
- pstring::mem_t *buf = new pstring::mem_t[sz+1];
- m_strm.read(buf, sz);
+ std::vector<plib::string_info<pstring>::mem_t> buf(sz+1);
+ m_strm.read(buf.data(), sz);
buf[sz] = 0;
- s = pstring(buf, pstring::UTF8);
- delete [] buf;
+ s = pstring(buf.data());
}
template <typename T>
@@ -436,13 +633,38 @@ public:
std::size_t sz = 0;
read(sz);
val.resize(sz);
- m_strm.read(val.data(), sizeof(T) * sz);
+ m_strm.read(reinterpret_cast<pistream::value_type *>(val.data()), sizeof(T) * sz);
}
private:
pistream &m_strm;
};
+inline void copystream(postream &dest, pistream &src)
+{
+ std::array<postream::value_type, 1024> buf; // NOLINT(cppcoreguidelines-pro-type-member-init)
+ pstream::pos_type r;
+ while ((r=src.read(buf.data(), 1024)) > 0)
+ dest.write(buf.data(), r);
}
+struct perrlogger
+{
+ template <typename ... Args>
+ explicit perrlogger(Args&& ... args)
+ {
+ h()(std::forward<Args>(args)...);
+ }
+private:
+ static putf8_fmt_writer &h()
+ {
+ static plib::pstderr perr_strm;
+ static plib::putf8_fmt_writer perr(&perr_strm);
+ return perr;
+ }
+};
+
+
+} // namespace plib
+
#endif /* PSTREAM_H_ */
diff --git a/src/lib/netlist/plib/pstring.cpp b/src/lib/netlist/plib/pstring.cpp
index 47d35d7c82f..c304f11d1fd 100644
--- a/src/lib/netlist/plib/pstring.cpp
+++ b/src/lib/netlist/plib/pstring.cpp
@@ -10,17 +10,8 @@
#include "plists.h"
#include <algorithm>
-#include <stack>
#include <atomic>
-
-template <typename T>
-std::size_t strlen_mem(const T *s)
-{
- std::size_t len(0);
- while (*s++)
- ++len;
- return len;
-}
+#include <stack>
template<typename F>
int pstring_t<F>::compare(const pstring_t &right) const
@@ -67,18 +58,6 @@ pstring_t<F> pstring_t<F>::substr(size_type start, size_type nlen) const
}
template<typename F>
-pstring_t<F> pstring_t<F>::ucase() const
-{
- pstring_t ret;
- for (const auto &c : *this)
- if (c >= 'a' && c <= 'z')
- ret += (c - 'a' + 'A');
- else
- ret += c;
- return ret;
-}
-
-template<typename F>
typename pstring_t<F>::size_type pstring_t<F>::find_first_not_of(const pstring_t &no) const
{
size_type pos = 0;
@@ -150,114 +129,6 @@ typename pstring_t<F>::size_type pstring_t<F>::find(code_t search, size_type sta
return find(ss, start);
}
-
-template<typename F>
-pstring_t<F> pstring_t<F>::replace_all(const pstring_t &search, const pstring_t &replace) const
-{
- pstring_t ret;
- const size_type slen = search.length();
-
- size_type last_s = 0;
- size_type s = find(search, last_s);
- while (s != npos)
- {
- ret += substr(last_s, s - last_s);
- ret += replace;
- last_s = s + slen;
- s = find(search, last_s);
- }
- ret += substr(last_s);
- return ret;
-}
-
-template<typename F>
-pstring_t<F> pstring_t<F>::rpad(const pstring_t &ws, const size_type cnt) const
-{
- // FIXME: pstringbuffer ret(*this);
-
- pstring_t ret(*this);
- size_type wsl = ws.length();
- for (auto i = ret.length(); i < cnt; i+=wsl)
- ret += ws;
- return ret;
-}
-
-static double pstod(const pstring_t<pu8_traits> &str, std::size_t *e)
-{
- return std::stod(str.cpp_string(), e);
-}
-
-static double pstod(const pstring &str, std::size_t *e)
-{
- return std::stod(str.cpp_string(), e);
-}
-
-static double pstod(const pwstring &str, std::size_t *e)
-{
- return std::stod(str.cpp_string(), e);
-}
-
-static double pstod(const pu16string &str, std::size_t *e)
-{
- pstring c;
- c = str;
- return std::stod(c.cpp_string(), e);
-}
-
-static long pstol(const pstring_t<pu8_traits> &str, std::size_t *e, int base = 10)
-{
- return std::stol(str.cpp_string(), e, base);
-}
-
-static long pstol(const pstring &str, std::size_t *e, int base = 10)
-{
- return std::stol(str.cpp_string(), e, base);
-}
-
-static long pstol(const pwstring &str, std::size_t *e, int base = 10)
-{
- return std::stol(str.cpp_string(), e, base);
-}
-
-static long pstol(const pu16string &str, std::size_t *e, int base = 10)
-{
- pstring c;
- c = str;
- return std::stol(c.cpp_string(), e, base);
-}
-
-template<typename F>
-double pstring_t<F>::as_double(bool *error) const
-{
- std::size_t e = 0;
- if (error != nullptr)
- *error = false;
- double ret = pstod(*this, &e);
- if (e != mem_t_size())
- if (error != nullptr)
- *error = true;
- return ret;
-}
-
-template<typename F>
-long pstring_t<F>::as_long(bool *error) const
-{
- static pstring_t prefix(pstring("0x"));
- long ret;
- std::size_t e = 0;
-
- if (error != nullptr)
- *error = false;
- if (startsWith(prefix))
- ret = pstol(substr(2), &e, 16);
- else
- ret = pstol(*this, &e, 10);
- if (e != mem_t_size())
- if (error != nullptr)
- *error = true;
- return ret;
-}
-
// ----------------------------------------------------------------------------------------
// template stuff ...
// ----------------------------------------------------------------------------------------
diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h
index cabce0e7b93..c4caeab8e8f 100644
--- a/src/lib/netlist/plib/pstring.h
+++ b/src/lib/netlist/plib/pstring.h
@@ -7,45 +7,50 @@
#ifndef PSTRING_H_
#define PSTRING_H_
-#include <iterator>
+#include "ptypes.h"
+
+#include <cstring>
#include <exception>
+#include <iterator>
+#include <limits>
+#include <stdexcept>
#include <string>
+#include <type_traits>
// ----------------------------------------------------------------------------------------
// pstring: semi-immutable strings ...
//
// The only reason this class exists is the absence of support for multi-byte
-// strings in std:: which I would consider usuable for the use-cases I encounter.
+// strings in std:: which I would consider sub-optimal for the use-cases I encounter.
// ----------------------------------------------------------------------------------------
+// enable this to use std::string instead of pstring globally.
+
+#define PSTRING_USE_STD_STRING (0)
+
template <typename T>
class pstring_const_iterator final
{
public:
- typedef typename T::ref_value_type value_type;
+ using value_type = typename T::ref_value_type;
- typedef value_type const *pointer;
- typedef value_type const &reference;
- typedef std::ptrdiff_t difference_type;
- typedef std::forward_iterator_tag iterator_category;
- typedef typename T::string_type string_type;
- typedef typename T::traits_type traits_type;
+ using pointer = value_type const *;
+ using reference = value_type const &;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::forward_iterator_tag;
+ using string_type = typename T::string_type;
+ using traits_type = typename T::traits_type;
- pstring_const_iterator() noexcept : p() { }
+ constexpr pstring_const_iterator() noexcept : p() { }
explicit constexpr pstring_const_iterator(const typename string_type::const_iterator &x) noexcept : p(x) { }
-#if !defined(_MSC_VER) || !defined(_ITERATOR_DEBUG_LEVEL) || (0 == _ITERATOR_DEBUG_LEVEL) // debug iterators are broken
- pstring_const_iterator(const pstring_const_iterator &rhs) noexcept = default;
- pstring_const_iterator(pstring_const_iterator &&rhs) noexcept = default;
- pstring_const_iterator &operator=(const pstring_const_iterator &rhs) noexcept = default;
- pstring_const_iterator &operator=(pstring_const_iterator &&rhs) noexcept = default;
-#endif
pstring_const_iterator& operator++() noexcept { p += static_cast<difference_type>(traits_type::codelen(&(*p))); return *this; }
- pstring_const_iterator operator++(int) noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; }
+ // NOLINTNEXTLINE(cert-dcl21-cpp)
+ pstring_const_iterator operator++(int) & noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; }
- bool operator==(const pstring_const_iterator& rhs) const noexcept { return p == rhs.p; }
- bool operator!=(const pstring_const_iterator& rhs) const noexcept { return p != rhs.p; }
+ constexpr bool operator==(const pstring_const_iterator& rhs) const noexcept { return p == rhs.p; }
+ constexpr bool operator!=(const pstring_const_iterator& rhs) const noexcept { return p != rhs.p; }
reference operator*() const noexcept { return *reinterpret_cast<pointer>(&(*p)); }
pointer operator->() const noexcept { return reinterpret_cast<pointer>(&(*p)); }
@@ -60,18 +65,21 @@ template <typename F>
struct pstring_t
{
public:
- typedef F traits_type;
+ using traits_type = F;
- typedef typename traits_type::mem_t mem_t;
- typedef typename traits_type::code_t code_t;
- typedef std::size_t size_type;
- typedef std::ptrdiff_t difference_type;
- typedef typename traits_type::string_type string_type;
+ using mem_t = typename traits_type::mem_t;
+ using code_t = typename traits_type::code_t;
+ using value_type = typename traits_type::code_t;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using string_type = typename traits_type::string_type;
- class ref_value_type final
+ // FIXME: this is ugly
+ struct ref_value_type final
{
public:
ref_value_type() = delete;
+ ~ref_value_type() = delete;
ref_value_type(const ref_value_type &) = delete;
ref_value_type(ref_value_type &&) = delete;
ref_value_type &operator=(const ref_value_type &) = delete;
@@ -80,37 +88,27 @@ public:
private:
const mem_t m;
};
- typedef const ref_value_type& const_reference;
- typedef const_reference reference;
-
- enum enc_t
- {
- UTF8,
- UTF16
- };
+ using const_reference = const ref_value_type &;
+ using reference = const_reference;
// simple construction/destruction
- pstring_t()
- {
- }
- ~pstring_t()
- {
- }
+ pstring_t() = default;
+ ~pstring_t() noexcept = default;
// FIXME: Do something with encoding
- pstring_t(const mem_t *string, const enc_t enc)
+ pstring_t(const mem_t *string)
: m_str(string)
{
}
- pstring_t(const mem_t *string, const size_type len, const enc_t enc)
+ pstring_t(const mem_t *string, const size_type len)
: m_str(string, len)
{
}
template<typename C, std::size_t N,
class = typename std::enable_if<std::is_same<C, const mem_t>::value>::type>
- pstring_t(C (&string)[N])
+ pstring_t(C (&string)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
{
static_assert(N > 0,"pstring from array of length 0");
if (string[N-1] != 0)
@@ -118,17 +116,15 @@ public:
m_str.assign(string, N - 1);
}
- pstring_t(const pstring_t &string)
- : m_str(string.m_str)
- { }
- explicit pstring_t(const string_type &string, const enc_t enc)
+ explicit pstring_t(const string_type &string)
: m_str(string)
{ }
- pstring_t(pstring_t &&string)
- : m_str(string.m_str)
- { }
+ pstring_t(const pstring_t &string) = default;
+ pstring_t(pstring_t &&string) noexcept = default;
+ pstring_t &operator=(const pstring_t &string) = default;
+ pstring_t &operator=(pstring_t &&string) noexcept = default;
explicit pstring_t(code_t code)
{
@@ -144,7 +140,8 @@ public:
*this += static_cast<code_t>(c); // FIXME: codepage conversion for u8
}
- pstring_t &operator=(const pstring_t &string) { m_str = string.m_str; return *this; }
+ operator string_type () const { return m_str; }
+
template <typename T,
class = typename std::enable_if<!std::is_same<T, pstring_t::traits_type>::value>::type>
@@ -157,8 +154,8 @@ public:
}
// no non-const const_iterator for now
- typedef pstring_const_iterator<pstring_t> iterator;
- typedef pstring_const_iterator<pstring_t> const_iterator;
+ using iterator = pstring_const_iterator<pstring_t<F> >;
+ using const_iterator = pstring_const_iterator<pstring_t<F> >;
iterator begin() { return iterator(m_str.begin()); }
iterator end() { return iterator(m_str.end()); }
@@ -201,67 +198,26 @@ public:
const_reference at(const size_type pos) const { return *reinterpret_cast<const ref_value_type *>(F::nthcode(m_str.c_str(),pos)); }
- /* The following is not compatible to std::string */
-
- bool equals(const pstring_t &string) const { return (compare(string) == 0); }
-
- bool startsWith(const pstring_t &arg) const { return arg.mem_t_size() > mem_t_size() ? false : m_str.compare(0, arg.mem_t_size(), arg.m_str) == 0; }
- bool endsWith(const pstring_t &arg) const { return arg.mem_t_size() > mem_t_size() ? false : m_str.compare(mem_t_size()-arg.mem_t_size(), arg.mem_t_size(), arg.m_str) == 0; }
-
- pstring_t replace_all(const pstring_t &search, const pstring_t &replace) const;
- pstring_t cat(const pstring_t &s) const { return *this + s; }
- pstring_t cat(code_t c) const { return *this + c; }
-
- // conversions
-
- double as_double(bool *error = nullptr) const;
- long as_long(bool *error = nullptr) const;
-
/* the following are extensions to <string> */
size_type mem_t_size() const { return m_str.size(); }
- pstring_t left(size_type len) const { return substr(0, len); }
- pstring_t right(size_type nlen) const
- {
- return nlen >= length() ? *this : substr(length() - nlen, nlen);
- }
-
- pstring_t ltrim(const pstring_t &ws = pstring_t(" \t\n\r")) const
- {
- return substr(find_first_not_of(ws));
- }
-
- pstring_t rtrim(const pstring_t &ws = pstring_t(" \t\n\r")) const
- {
- auto f = find_last_not_of(ws);
- return f == npos ? pstring_t() : substr(0, f + 1);
- }
-
- pstring_t trim(const pstring_t &ws = pstring_t(" \t\n\r")) const { return this->ltrim(ws).rtrim(ws); }
-
- pstring_t rpad(const pstring_t &ws, const size_type cnt) const;
-
- pstring_t ucase() const;
-
const string_type &cpp_string() const { return m_str; }
- static const size_type npos = static_cast<size_type>(-1);
-
-protected:
- string_type m_str;
+ static constexpr const size_type npos = static_cast<size_type>(-1);
private:
+ string_type m_str;
};
struct pu8_traits
{
- typedef char mem_t;
- typedef char code_t;
- typedef std::string string_type;
+ using mem_t = char;
+ using code_t = char;
+ using string_type = std::string;
static std::size_t len(const string_type &p) { return p.size(); }
- static std::size_t codelen(const mem_t *p) { return 1; }
- static std::size_t codelen(const code_t c) { return 1; }
+ static std::size_t codelen(const mem_t *p) { plib::unused_var(p); return 1; }
+ static std::size_t codelen(const code_t c) { plib::unused_var(c); return 1; }
static code_t code(const mem_t *p) { return *p; }
static void encode(const code_t c, string_type &s) { s += static_cast<mem_t>(c); }
static const mem_t *nthcode(const mem_t *p, const std::size_t n) { return &(p[n]); }
@@ -270,9 +226,9 @@ struct pu8_traits
/* No checking, this may deliver invalid codes */
struct putf8_traits
{
- typedef char mem_t;
- typedef char32_t code_t;
- typedef std::string string_type;
+ using mem_t = char;
+ using code_t = char32_t;
+ using string_type = std::string;
static std::size_t len(const string_type &p)
{
std::size_t ret = 0;
@@ -285,7 +241,7 @@ struct putf8_traits
}
static std::size_t codelen(const mem_t *p)
{
- const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p);
+ const auto p1 = reinterpret_cast<const unsigned char *>(p);
if ((*p1 & 0x80) == 0x00)
return 1;
else if ((*p1 & 0xE0) == 0xC0)
@@ -312,7 +268,7 @@ struct putf8_traits
}
static code_t code(const mem_t *p)
{
- const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p);
+ const auto p1 = reinterpret_cast<const unsigned char *>(p);
if ((*p1 & 0x80) == 0x00)
return *p1;
else if ((*p1 & 0xE0) == 0xC0)
@@ -361,9 +317,9 @@ struct putf8_traits
struct putf16_traits
{
- typedef char16_t mem_t;
- typedef char32_t code_t;
- typedef std::u16string string_type;
+ using mem_t = char16_t;
+ using code_t = char32_t;
+ using string_type = std::u16string;
static std::size_t len(const string_type &p)
{
std::size_t ret = 0;
@@ -371,7 +327,7 @@ struct putf16_traits
while (i != p.end())
{
// FIXME: check that size is equal
- uint16_t c = static_cast<uint16_t>(*i++);
+ auto c = static_cast<uint16_t>(*i++);
if (!((c & 0xd800) == 0xd800))
ret++;
}
@@ -379,7 +335,7 @@ struct putf16_traits
}
static std::size_t codelen(const mem_t *p)
{
- uint16_t c = static_cast<uint16_t>(*p);
+ auto c = static_cast<uint16_t>(*p);
return ((c & 0xd800) == 0xd800) ? 2 : 1;
}
static std::size_t codelen(const code_t c)
@@ -391,7 +347,7 @@ struct putf16_traits
}
static code_t code(const mem_t *p)
{
- uint32_t c = static_cast<uint32_t>(*p++);
+ auto c = static_cast<uint32_t>(*p++);
if ((c & 0xd800) == 0xd800)
{
c = (c - 0xd800) << 10;
@@ -401,7 +357,7 @@ struct putf16_traits
}
static void encode(code_t c, string_type &s)
{
- uint32_t cu = static_cast<uint32_t>(c);
+ auto cu = static_cast<uint32_t>(c);
if (c > 0xffff)
{ //make a surrogate pair
uint32_t t = ((cu - 0x10000) >> 10) + 0xd800;
@@ -425,9 +381,9 @@ struct putf16_traits
struct pwchar_traits
{
- typedef wchar_t mem_t;
- typedef char32_t code_t;
- typedef std::wstring string_type;
+ using mem_t = wchar_t;
+ using code_t = char32_t;
+ using string_type = std::wstring;
static std::size_t len(const string_type &p)
{
if (sizeof(wchar_t) == 2)
@@ -437,7 +393,7 @@ struct pwchar_traits
while (i != p.end())
{
// FIXME: check that size is equal
- uint32_t c = static_cast<uint32_t>(*i++);
+ auto c = static_cast<uint32_t>(*i++);
if (!((c & 0xd800) == 0xd800))
ret++;
}
@@ -451,7 +407,7 @@ struct pwchar_traits
{
if (sizeof(wchar_t) == 2)
{
- uint16_t c = static_cast<uint16_t>(*p);
+ auto c = static_cast<uint16_t>(*p);
return ((c & 0xd800) == 0xd800) ? 2 : 1;
}
else
@@ -470,7 +426,7 @@ struct pwchar_traits
{
if (sizeof(wchar_t) == 2)
{
- uint32_t c = static_cast<uint32_t>(*p++);
+ auto c = static_cast<uint32_t>(*p++);
if ((c & 0xd800) == 0xd800)
{
c = (c - 0xd800) << 10;
@@ -486,7 +442,7 @@ struct pwchar_traits
{
if (sizeof(wchar_t) == 2)
{
- uint32_t cu = static_cast<uint32_t>(c);
+ auto cu = static_cast<uint32_t>(c);
if (c > 0xffff)
{ //make a surrogate pair
uint32_t t = ((cu - 0x10000) >> 10) + 0xd800;
@@ -519,41 +475,280 @@ extern template struct pstring_t<putf8_traits>;
extern template struct pstring_t<putf16_traits>;
extern template struct pstring_t<pwchar_traits>;
-typedef pstring_t<putf8_traits> pstring;
-typedef pstring_t<putf16_traits> pu16string;
-typedef pstring_t<pwchar_traits> pwstring;
+#if (PSTRING_USE_STD_STRING)
+typedef std::string pstring;
+#else
+using pstring = pstring_t<putf8_traits>;
+#endif
+using putf8string = pstring_t<putf8_traits>;
+using pu16string = pstring_t<putf16_traits>;
+using pwstring = pstring_t<pwchar_traits>;
namespace plib
{
+ template<class T>
+ struct string_info
+ {
+ using mem_t = typename T::mem_t;
+ };
+
+ template<>
+ struct string_info<std::string>
+ {
+ using mem_t = char;
+ };
+
template<typename T>
pstring to_string(const T &v)
{
- return pstring(std::to_string(v), pstring::UTF8);
+ return pstring(std::to_string(v));
}
template<typename T>
pwstring to_wstring(const T &v)
{
- return pwstring(std::to_wstring(v), pwstring::UTF16);
+ return pwstring(std::to_wstring(v));
+ }
+
+ template <typename T, typename E = void>
+ struct pstonum_helper;
+
+ template<typename T>
+ struct pstonum_helper<T, typename std::enable_if<std::is_integral<T>::value
+ && std::is_signed<T>::value>::type>
+ {
+ template <typename S>
+ long long operator()(const S &arg, std::size_t *idx)
+ {
+ return std::stoll(arg, idx);
+ }
+ };
+
+ template<typename T>
+ struct pstonum_helper<T, typename std::enable_if<std::is_integral<T>::value
+ && !std::is_signed<T>::value>::type>
+ {
+ template <typename S>
+ unsigned long long operator()(const S &arg, std::size_t *idx)
+ {
+ return std::stoull(arg, idx);
+ }
+ };
+
+ template<typename T>
+ struct pstonum_helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
+ {
+ template <typename S>
+ long double operator()(const S &arg, std::size_t *idx)
+ {
+ return std::stold(arg, idx);
+ }
+ };
+
+ template<typename T, typename S>
+ T pstonum(const S &arg)
+ {
+ decltype(arg.c_str()) cstr = arg.c_str();
+ std::size_t idx(0);
+ auto ret = pstonum_helper<T>()(cstr, &idx);
+ using ret_type = decltype(ret);
+ if (ret >= static_cast<ret_type>(std::numeric_limits<T>::lowest())
+ && ret <= static_cast<ret_type>(std::numeric_limits<T>::max()))
+ //&& (ret == T(0) || std::abs(ret) >= std::numeric_limits<T>::min() ))
+ {
+ if (cstr[idx] != 0)
+ throw std::invalid_argument(std::string("Continuation after numeric value ends: ") + cstr);
+ }
+ else
+ {
+ throw std::out_of_range(std::string("Out of range: ") + cstr);
+ }
+ return static_cast<T>(ret);
+ }
+
+ template<typename R, typename T>
+ R pstonum_ne(const T &str, bool &err) noexcept
+ {
+ try
+ {
+ err = false;
+ return pstonum<R>(str);
+ }
+ catch (...)
+ {
+ err = true;
+ return R(0);
+ }
+ }
+
+ template<typename T>
+ typename T::size_type find_first_not_of(const T &str, const T &no)
+ {
+ typename T::size_type pos = 0;
+ for (auto it = str.begin(); it != str.end(); ++it, ++pos)
+ {
+ bool f = true;
+ for (typename T::value_type const jt : no)
+ {
+ if (*it == jt)
+ {
+ f = false;
+ break;
+ }
+ }
+ if (f)
+ return pos;
+ }
+ return T::npos;
+ }
+
+ template<typename T>
+ typename T::size_type find_last_not_of(const T &str, const T &no)
+ {
+ /* FIXME: reverse iterator */
+ typename T::size_type last_found = T::npos;
+ typename T::size_type pos = 0;
+ for (auto it = str.begin(); it != str.end(); ++it, ++pos)
+ {
+ bool f = true;
+ for (typename T::value_type const jt : no)
+ {
+ if (*it == jt)
+ {
+ f = false;
+ break;
+ }
+ }
+ if (f)
+ last_found = pos;
+ }
+ return last_found;
+ }
+
+ template<typename T>
+ T ltrim(const T &str, const T &ws = T(" \t\n\r"))
+ {
+ auto f = find_first_not_of(str, ws);
+ return (f == T::npos) ? T() : str.substr(f);
}
-}
+
+ template<typename T>
+ T rtrim(const T &str, const T &ws = T(" \t\n\r"))
+ {
+ auto f = find_last_not_of(str, ws);
+ return (f == T::npos) ? T() : str.substr(0, f + 1);
+ }
+
+ template<typename T>
+ T trim(const T &str, const T &ws = T(" \t\n\r"))
+ {
+ return rtrim(ltrim(str, ws), ws);
+ }
+
+ template<typename T>
+ T left(const T &str, typename T::size_type len)
+ {
+ return str.substr(0, len);
+ }
+
+ template<typename T>
+ T right(const T &str, typename T::size_type nlen)
+ {
+ return nlen >= str.length() ? str : str.substr(str.length() - nlen, nlen);
+ }
+
+ template<typename T>
+ bool startsWith(const T &str, const T &arg)
+ {
+ return (arg == left(str, arg.length()));
+ }
+
+ template<typename T>
+ bool endsWith(const T &str, const T &arg)
+ {
+ return (right(str, arg.length()) == arg);
+ }
+
+ template<typename T>
+ bool startsWith(const T &str, const char *arg)
+ {
+ return (left(str, std::strlen(arg)) == arg);
+ }
+
+ template<typename T>
+ bool endsWith(const T &str, const char *arg)
+ {
+ return (right(str, std::strlen(arg)) == arg);
+ }
+
+ template<typename T>
+ T ucase(const T &str)
+ {
+ T ret;
+ for (const auto &c : str)
+ if (c >= 'a' && c <= 'z')
+ ret += (c - 'a' + 'A');
+ else
+ ret += c;
+ return ret;
+ }
+
+ template<typename T>
+ T rpad(const T &str, const T &ws, const typename T::size_type cnt)
+ {
+ // FIXME: pstringbuffer ret(*this);
+
+ T ret(str);
+ typename T::size_type wsl = ws.length();
+ for (auto i = ret.length(); i < cnt; i+=wsl)
+ ret += ws;
+ return ret;
+ }
+
+ template<typename T>
+ T replace_all(const T &str, const T &search, const T &replace)
+ {
+ T ret;
+ const typename T::size_type slen = search.length();
+
+ typename T::size_type last_s = 0;
+ typename T::size_type s = str.find(search, last_s);
+ while (s != T::npos)
+ {
+ ret += str.substr(last_s, s - last_s);
+ ret += replace;
+ last_s = s + slen;
+ s = str.find(search, last_s);
+ }
+ ret += str.substr(last_s);
+ return ret;
+ }
+
+ template<typename T, typename T1, typename T2>
+ T replace_all(const T &str, const T1 &search, const T2 &replace)
+ {
+ return replace_all(str, static_cast<T>(search), static_cast<T>(replace));
+ }
+
+} // namespace plib
// custom specialization of std::hash can be injected in namespace std
namespace std
{
+
template<typename T> struct hash<pstring_t<T>>
{
- typedef pstring_t<T> argument_type;
- typedef std::size_t result_type;
+ using argument_type = pstring_t<T>;
+ using result_type = std::size_t;
result_type operator()(argument_type const& s) const
{
- const pstring::mem_t *string = s.c_str();
+ const typename argument_type::mem_t *string = s.c_str();
result_type result = 5381;
- for (pstring::mem_t c = *string; c != 0; c = *string++)
+ for (typename argument_type::mem_t c = *string; c != 0; c = *string++)
result = ((result << 5) + result ) ^ (result >> (32 - 5)) ^ static_cast<result_type>(c);
return result;
}
};
-}
+} // namespace std
#endif /* PSTRING_H_ */
diff --git a/src/lib/netlist/plib/ptime.h b/src/lib/netlist/plib/ptime.h
new file mode 100644
index 00000000000..32ccc4f7b0d
--- /dev/null
+++ b/src/lib/netlist/plib/ptime.h
@@ -0,0 +1,136 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * ptime.h
+ */
+
+#ifndef PTIME_H_
+#define PTIME_H_
+
+#include "pconfig.h"
+#include "ptypes.h"
+
+#include <cstdint>
+
+// ----------------------------------------------------------------------------------------
+// netlist_time
+// ----------------------------------------------------------------------------------------
+
+namespace plib
+{
+
+ template <typename TYPE, TYPE RES>
+ struct ptime final
+ {
+ public:
+
+ using internal_type = TYPE;
+ using mult_type = TYPE;
+
+ constexpr ptime() noexcept : m_time(0) {}
+
+ ~ptime() noexcept = default;
+
+ constexpr ptime(const ptime &rhs) noexcept = default;
+ constexpr ptime(ptime &&rhs) noexcept = default;
+ constexpr explicit ptime(const internal_type &time) noexcept : m_time(time) {}
+ constexpr explicit ptime(internal_type &&time) noexcept : m_time(time) {}
+ C14CONSTEXPR ptime &operator=(const ptime &rhs) noexcept = default;
+ C14CONSTEXPR ptime &operator=(ptime &&rhs) noexcept = default;
+
+ constexpr explicit ptime(const double t) = delete;
+ //: m_time((internal_type) ( t * (double) resolution)) { }
+ constexpr explicit ptime(const internal_type nom, const internal_type den) noexcept
+ : m_time(nom * (RES / den)) { }
+
+ C14CONSTEXPR ptime &operator+=(const ptime rhs) noexcept { m_time += rhs.m_time; return *this; }
+ C14CONSTEXPR ptime &operator-=(const ptime rhs) noexcept { m_time -= rhs.m_time; return *this; }
+ C14CONSTEXPR ptime &operator*=(const mult_type factor) noexcept { m_time *= static_cast<internal_type>(factor); return *this; }
+
+ friend constexpr const ptime operator-(ptime lhs, const ptime rhs) noexcept
+ {
+ return ptime(lhs.m_time - rhs.m_time);
+ }
+
+ friend constexpr const ptime operator+(ptime lhs, const ptime rhs) noexcept
+ {
+ return ptime(lhs.m_time + rhs.m_time);
+ }
+
+ friend constexpr const ptime operator*(ptime lhs, const mult_type &factor) noexcept
+ {
+ return ptime(lhs.m_time * factor);
+ }
+
+ friend constexpr mult_type operator/(const ptime lhs, const ptime rhs) noexcept
+ {
+ return static_cast<mult_type>(lhs.m_time / rhs.m_time);
+ }
+
+ friend constexpr bool operator<(const ptime lhs, const ptime rhs) noexcept
+ {
+ return (lhs.m_time < rhs.m_time);
+ }
+
+ friend constexpr bool operator>(const ptime lhs, const ptime rhs) noexcept
+ {
+ return (rhs < lhs);
+ }
+
+ friend constexpr bool operator<=(const ptime lhs, const ptime rhs) noexcept
+ {
+ return !(lhs > rhs);
+ }
+
+ friend constexpr bool operator>=(const ptime lhs, const ptime rhs) noexcept
+ {
+ return !(lhs < rhs);
+ }
+
+ friend constexpr bool operator==(const ptime lhs, const ptime rhs) noexcept
+ {
+ return lhs.m_time == rhs.m_time;
+ }
+
+ friend constexpr bool operator!=(const ptime lhs, const ptime rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ constexpr internal_type as_raw() const noexcept { return m_time; }
+ constexpr double as_double() const noexcept
+ {
+ return static_cast<double>(m_time) * inv_res;
+ }
+
+ // for save states ....
+ C14CONSTEXPR internal_type *get_internaltype_ptr() noexcept { return &m_time; }
+
+ static constexpr ptime from_nsec(const internal_type ns) noexcept { return ptime(ns, UINT64_C(1000000000)); }
+ static constexpr ptime from_usec(const internal_type us) noexcept { return ptime(us, UINT64_C( 1000000)); }
+ static constexpr ptime from_msec(const internal_type ms) noexcept { return ptime(ms, UINT64_C( 1000)); }
+ static constexpr ptime from_sec(const internal_type s) noexcept { return ptime(s, UINT64_C( 1)); }
+ static constexpr ptime from_hz(const internal_type hz) noexcept { return ptime(1 , hz); }
+ static constexpr ptime from_raw(const internal_type raw) noexcept { return ptime(raw); }
+ static constexpr ptime from_double(const double t) noexcept { return ptime(static_cast<internal_type>( t * static_cast<double>(RES)), RES); }
+
+ static constexpr ptime zero() noexcept { return ptime(0, RES); }
+ static constexpr ptime quantum() noexcept { return ptime(1, RES); }
+ static constexpr ptime never() noexcept { return ptime(plib::numeric_limits<internal_type>::max(), RES); }
+ static constexpr internal_type resolution() noexcept { return RES; }
+
+ constexpr internal_type in_nsec() const noexcept { return m_time / (RES / UINT64_C(1000000000)); }
+ constexpr internal_type in_usec() const noexcept { return m_time / (RES / UINT64_C( 1000000)); }
+ constexpr internal_type in_msec() const noexcept { return m_time / (RES / UINT64_C( 1000)); }
+ constexpr internal_type in_sec() const noexcept { return m_time / (RES / UINT64_C( 1)); }
+
+ private:
+ static constexpr const double inv_res = 1.0 / static_cast<double>(RES);
+ internal_type m_time;
+ };
+
+
+} // namespace plib
+
+
+#endif /* PTIME_H_ */
diff --git a/src/lib/netlist/plib/ptypes.h b/src/lib/netlist/plib/ptypes.h
index 0934a86fdf2..bda62099150 100644
--- a/src/lib/netlist/plib/ptypes.h
+++ b/src/lib/netlist/plib/ptypes.h
@@ -9,10 +9,20 @@
#define PTYPES_H_
#include "pconfig.h"
-#include "pstring.h"
-#include <type_traits>
#include <limits>
+#include <string>
+#include <type_traits>
+
+#define COPYASSIGNMOVE(name, def) \
+ name(const name &) = def; \
+ name(name &&) noexcept = def; \
+ name &operator=(const name &) = def; \
+ name &operator=(name &&) noexcept = def;
+
+#define COPYASSIGN(name, def) \
+ name(const name &) = def; \
+ name &operator=(const name &) = def; \
namespace plib
{
@@ -25,14 +35,14 @@ namespace plib
template<> struct is_integral<INT128> { static constexpr bool value = true; };
template<> struct numeric_limits<UINT128>
{
- static inline constexpr UINT128 max()
+ static constexpr UINT128 max()
{
return ~((UINT128)0);
}
};
template<> struct numeric_limits<INT128>
{
- static inline constexpr INT128 max()
+ static constexpr INT128 max()
{
return (~((UINT128)0)) >> 1;
}
@@ -45,56 +55,98 @@ namespace plib
struct nocopyassignmove
{
- protected:
- nocopyassignmove() = default;
- ~nocopyassignmove() = default;
- private:
nocopyassignmove(const nocopyassignmove &) = delete;
nocopyassignmove(nocopyassignmove &&) = delete;
nocopyassignmove &operator=(const nocopyassignmove &) = delete;
nocopyassignmove &operator=(nocopyassignmove &&) = delete;
+ protected:
+ nocopyassignmove() = default;
+ ~nocopyassignmove() = default;
};
struct nocopyassign
{
+ nocopyassign(const nocopyassign &) = delete;
+ nocopyassign &operator=(const nocopyassign &) = delete;
protected:
nocopyassign() = default;
~nocopyassign() = default;
- private:
- nocopyassign(const nocopyassign &) = delete;
- nocopyassign &operator=(const nocopyassign &) = delete;
+ nocopyassign(nocopyassign &&) = default;
+ nocopyassign &operator=(nocopyassign &&) = default;
};
//============================================================
- // penum - strongly typed enumeration
+ // Avoid unused variable warnings
//============================================================
+ template<typename... Ts>
+ inline void unused_var(Ts&&...) {}
- struct penum_base
+ //============================================================
+ // is_pow2
+ //============================================================
+ template <typename T>
+ constexpr bool is_pow2(T v) noexcept
{
- protected:
- static int from_string_int(const char *str, const char *x);
- static pstring nthstr(int n, const char *str);
- };
+ static_assert(is_integral<T>::value, "is_pow2 needs integer arguments");
+ return !(v & (v-1));
+ }
+
+
+ //============================================================
+ // abs, lcd, gcm
+ //============================================================
+
+ template<typename T>
+ constexpr
+ typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type
+ abs(T v)
+ {
+ return v < 0 ? -v : v;
+ }
+
+ template<typename T>
+ constexpr
+ typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type
+ abs(T v)
+ {
+ return v;
+ }
+
+ template<typename M, typename N>
+ constexpr typename std::common_type<M, N>::type
+ gcd(M m, N n)
+ {
+ static_assert(std::is_integral<M>::value, "gcd: M must be an integer");
+ static_assert(std::is_integral<N>::value, "gcd: N must be an integer");
+
+ return m == 0 ? plib::abs(n)
+ : n == 0 ? plib::abs(m)
+ : gcd(n, m % n);
+ }
+
+ template<typename M, typename N>
+ constexpr typename std::common_type<M, N>::type
+ lcm(M m, N n)
+ {
+ static_assert(std::is_integral<M>::value, "lcm: M must be an integer");
+ static_assert(std::is_integral<N>::value, "lcm: N must be an integer");
+
+ return (m != 0 && n != 0) ? (plib::abs(m) / gcd(m, n)) * plib::abs(n) : 0;
+ }
+
+} // namespace plib
-}
-
-#define P_ENUM(ename, ...) \
- struct ename : public plib::penum_base { \
- enum E { __VA_ARGS__ }; \
- ename (E v) : m_v(v) { } \
- bool set_from_string (const pstring &s) { \
- static char const *const strings = # __VA_ARGS__; \
- int f = from_string_int(strings, s.c_str()); \
- if (f>=0) { m_v = static_cast<E>(f); return true; } else { return false; } \
- } \
- operator E() const {return m_v;} \
- bool operator==(const ename &rhs) const {return m_v == rhs.m_v;} \
- bool operator==(const E &rhs) const {return m_v == rhs;} \
- const pstring name() const { \
- static char const *const strings = # __VA_ARGS__; \
- return nthstr(static_cast<int>(m_v), strings); \
- } \
- private: E m_v; };
+//============================================================
+// Define a "has member" trait.
+//============================================================
+#define PDEFINE_HAS_MEMBER(name, member) \
+ template <typename T> class name \
+ { \
+ template <typename U> static long test(decltype(&U:: member)); \
+ template <typename U> static char test(...); \
+ public: \
+ static constexpr const bool value = sizeof(test<T>(nullptr)) == sizeof(long); \
+ }
#endif /* PTYPES_H_ */
diff --git a/src/lib/netlist/plib/putil.cpp b/src/lib/netlist/plib/putil.cpp
index c34102417ec..b62cbf60865 100644
--- a/src/lib/netlist/plib/putil.cpp
+++ b/src/lib/netlist/plib/putil.cpp
@@ -2,13 +2,13 @@
// copyright-holders:Couriersud
#include "putil.h"
-#include "ptypes.h"
#include "plists.h"
+#include "ptypes.h"
-#include <cstdlib>
#include <algorithm>
-#include <initializer_list>
+#include <cstdlib>
#include <cstring>
+#include <initializer_list>
namespace plib
{
@@ -17,7 +17,7 @@ namespace plib
const pstring buildpath(std::initializer_list<pstring> list )
{
pstring ret = "";
- for( auto elem : list )
+ for( const auto &elem : list )
{
if (ret == "")
ret = elem;
@@ -33,12 +33,12 @@ namespace plib
const pstring environment(const pstring &var, const pstring &default_val)
{
- if (getenv(var.c_str()) == nullptr)
+ if (std::getenv(var.c_str()) == nullptr)
return default_val;
else
- return pstring(getenv(var.c_str()), pstring::UTF8);
+ return pstring(std::getenv(var.c_str()));
}
- }
+ } // namespace util
std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty)
{
@@ -64,6 +64,36 @@ namespace plib
return ret;
}
+ std::vector<std::string> psplit_r(const std::string &stri,
+ const std::string &token,
+ const std::size_t maxsplit)
+ {
+ std::string str(stri);
+ std::vector<std::string> result;
+ std::size_t splits = 0;
+
+ while(str.size())
+ {
+ std::size_t index = str.rfind(token);
+ bool found = index!=std::string::npos;
+ if (found)
+ splits++;
+ if ((splits <= maxsplit || maxsplit == 0) && found)
+ {
+ result.push_back(str.substr(index+token.size()));
+ str = str.substr(0, index);
+ if (str.size()==0)
+ result.push_back(str);
+ }
+ else
+ {
+ result.push_back(str);
+ str = "";
+ }
+ }
+ return result;
+ }
+
std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl)
{
pstring col = "";
@@ -72,7 +102,7 @@ namespace plib
auto i = str.begin();
while (i != str.end())
{
- std::size_t p = static_cast<std::size_t>(-1);
+ auto p = static_cast<std::size_t>(-1);
for (std::size_t j=0; j < onstrl.size(); j++)
{
if (std::equal(onstrl[j].begin(), onstrl[j].end(), i))
@@ -92,7 +122,7 @@ namespace plib
}
else
{
- pstring::code_t c = *i;
+ pstring::value_type c = *i;
col += c;
i++;
}
@@ -131,31 +161,8 @@ namespace plib
return cnt;
return -1;
}
- pstring penum_base::nthstr(int n, const char *str)
+ std::string penum_base::nthstr(int n, const char *str)
{
- char buf[64];
- char *bufp = buf;
- int cur = 0;
- while (*str)
- {
- if (cur == n)
- {
- if (*str == ',')
- {
- *bufp = 0;
- return pstring(buf, pstring::UTF8);
- }
- else if (*str != ' ')
- *bufp++ = *str;
- }
- else
- {
- if (*str == ',')
- cur++;
- }
- str++;
- }
- *bufp = 0;
- return pstring(buf, pstring::UTF8);
+ return psplit(str, ",", false)[static_cast<std::size_t>(n)];
}
} // namespace plib
diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h
index 8d59c0357e2..e8145361d9d 100644
--- a/src/lib/netlist/plib/putil.h
+++ b/src/lib/netlist/plib/putil.h
@@ -5,27 +5,32 @@
*
*/
-#ifndef P_UTIL_H_
-#define P_UTIL_H_
+#ifndef PUTIL_H_
+#define PUTIL_H_
#include "pstring.h"
-#include <initializer_list>
#include <algorithm>
-#include <vector> // <<= needed by windows build
+#include <initializer_list>
+#include <vector>
+
+#define PSTRINGIFY_HELP(y) # y
+#define PSTRINGIFY(x) PSTRINGIFY_HELP(x)
+
namespace plib
{
+
namespace util
{
const pstring buildpath(std::initializer_list<pstring> list );
const pstring environment(const pstring &var, const pstring &default_val);
- }
+ } // namespace util
namespace container
{
- template <class C>
- bool contains(C &con, const typename C::value_type &elem)
+ template <class C, class T>
+ bool contains(C &con, const T &elem)
{
return std::find(con.begin(), con.end(), elem) != con.end();
}
@@ -51,7 +56,51 @@ namespace plib
{
con.erase(std::remove(con.begin(), con.end(), elem), con.end());
}
- }
+ } // namespace container
+
+ /* May be further specialized .... This is the generic version */
+ template <typename T>
+ struct constants
+ {
+ static constexpr T zero() noexcept { return static_cast<T>(0); }
+ static constexpr T one() noexcept { return static_cast<T>(1); }
+ static constexpr T two() noexcept { return static_cast<T>(2); }
+
+ /*!
+ * \brief Electric constant of vacuum
+ */
+ static constexpr T eps_0() noexcept { return static_cast<T>(8.854187817e-12); }
+ /*!
+ * \brief Relative permittivity of Silicon dioxide
+ */
+ static constexpr T eps_SiO2() noexcept { return static_cast<T>(3.9); }
+ /*!
+ * \brief Relative permittivity of Silicon
+ */
+ static constexpr T eps_Si() noexcept { return static_cast<T>(11.7); }
+ /*!
+ * \brief Boltzmann constant
+ */
+ static constexpr T k_b() noexcept { return static_cast<T>(1.38064852e-23); }
+ /*!
+ * \brief room temperature (gives VT = 0.02585 at T=300)
+ */
+ static constexpr T T0() noexcept { return static_cast<T>(300); }
+ /*!
+ * \brief Elementary charge
+ */
+ static constexpr T Q_e() noexcept { return static_cast<T>(1.6021765314e-19); }
+ /*!
+ * \brief Intrinsic carrier concentration in 1/m^3 of Silicon
+ */
+ static constexpr T NiSi() noexcept { return static_cast<T>(1.45e16); }
+
+ template <typename V>
+ static constexpr const T cast(V &&v) noexcept { return static_cast<T>(v); }
+ };
+
+ static_assert(noexcept(constants<double>::one()) == true, "Not evaluated as constexpr");
+
template <class C>
struct indexed_compare
@@ -69,7 +118,41 @@ namespace plib
std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty = false);
std::vector<pstring> psplit(const pstring &str, const std::vector<pstring> &onstrl);
+ std::vector<std::string> psplit_r(const std::string &stri,
+ const std::string &token,
+ const std::size_t maxsplit);
+
+
+ //============================================================
+ // penum - strongly typed enumeration
+ //============================================================
+
+ struct penum_base
+ {
+ protected:
+ static int from_string_int(const char *str, const char *x);
+ static std::string nthstr(int n, const char *str);
+ };
+
+} // namespace plib
+
+#define P_ENUM(ename, ...) \
+ struct ename : public plib::penum_base { \
+ enum E { __VA_ARGS__ }; \
+ ename (E v) : m_v(v) { } \
+ bool set_from_string (const std::string &s) { \
+ static char const *const strings = # __VA_ARGS__; \
+ int f = from_string_int(strings, s.c_str()); \
+ if (f>=0) { m_v = static_cast<E>(f); return true; } else { return false; } \
+ } \
+ operator E() const {return m_v;} \
+ bool operator==(const ename &rhs) const {return m_v == rhs.m_v;} \
+ bool operator==(const E &rhs) const {return m_v == rhs;} \
+ std::string name() const { \
+ static char const *const strings = # __VA_ARGS__; \
+ return nthstr(static_cast<int>(m_v), strings); \
+ } \
+ private: E m_v; };
-}
-#endif /* P_UTIL_H_ */
+#endif /* PUTIL_H_ */
diff --git a/src/lib/netlist/plib/vector_ops.h b/src/lib/netlist/plib/vector_ops.h
new file mode 100644
index 00000000000..8043c48f61c
--- /dev/null
+++ b/src/lib/netlist/plib/vector_ops.h
@@ -0,0 +1,151 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud
+/*
+ * vector_ops.h
+ *
+ * Base vector operations
+ *
+ */
+
+#ifndef PLIB_VECTOR_OPS_H_
+#define PLIB_VECTOR_OPS_H_
+
+#include "pconfig.h"
+
+#include <algorithm>
+#include <cmath>
+#include <type_traits>
+
+#if !defined(__clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
+#if !(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 3))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+#endif
+
+namespace plib
+{
+ template<typename VT, typename T>
+ void vec_set_scalar(const std::size_t n, VT &v, T && scalar)
+ {
+ const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
+ for ( std::size_t i = 0; i < n; i++ )
+ v[i] = s;
+ }
+
+ template<typename VT, typename VS>
+ void vec_set(const std::size_t n, VT &v, const VS & source)
+ {
+ for ( std::size_t i = 0; i < n; i++ )
+ v[i] = source[i];
+ }
+
+ template<typename T, typename V1, typename V2>
+ T vec_mult(const std::size_t n, const V1 & v1, const V2 & v2 )
+ {
+ using b8 = T[8];
+ PALIGNAS_VECTOROPT() b8 value = {0};
+ for (std::size_t i = 0; i < n ; i++ )
+ {
+ value[i & 7] += v1[i] * v2[i];
+ }
+ return value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7];
+ }
+
+ template<typename T, typename VT>
+ T vec_mult2(const std::size_t n, const VT &v)
+ {
+ using b8 = T[8];
+ PALIGNAS_VECTOROPT() b8 value = {0};
+ for (std::size_t i = 0; i < n ; i++ )
+ {
+ value[i & 7] += v[i] * v[i];
+ }
+ return value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7];
+ }
+
+ template<typename T, typename VT>
+ T vec_sum(const std::size_t n, const VT &v)
+ {
+ if (n<8)
+ {
+ T value(0);
+ for (std::size_t i = 0; i < n ; i++ )
+ value += v[i];
+
+ return value;
+ }
+ else
+ {
+ using b8 = T[8];
+ PALIGNAS_VECTOROPT() b8 value = {0};
+ for (std::size_t i = 0; i < n ; i++ )
+ value[i & 7] += v[i];
+
+ return ((value[0] + value[1]) + (value[2] + value[3])) + ((value[4] + value[5]) + (value[6] + value[7]));
+ }
+ }
+
+ template<typename VV, typename T, typename VR>
+ void vec_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar)
+ {
+ const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
+ for ( std::size_t i = 0; i < n; i++ )
+ result[i] = s * v[i];
+ }
+
+ template<typename VR, typename VV, typename T>
+ void vec_add_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar)
+ {
+ const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
+ for ( std::size_t i = 0; i < n; i++ )
+ result[i] += s * v[i];
+ }
+
+ template<typename T>
+ void vec_add_mult_scalar_p(const std::size_t n, T * result, const T * v, T scalar)
+ {
+ for ( std::size_t i = 0; i < n; i++ )
+ result[i] += scalar * v[i];
+ }
+
+ template<typename R, typename V>
+ void vec_add_ip(const std::size_t n, R & result, const V & v)
+ {
+ for ( std::size_t i = 0; i < n; i++ )
+ result[i] += v[i];
+ }
+
+ template<typename VR, typename V1, typename V2>
+ void vec_sub(const std::size_t n, VR & result, const V1 &v1, const V2 & v2)
+ {
+ for ( std::size_t i = 0; i < n; i++ )
+ result[i] = v1[i] - v2[i];
+ }
+
+ template<typename V, typename T>
+ void vec_scale(const std::size_t n, V & v, T &&scalar)
+ {
+ const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
+ for ( std::size_t i = 0; i < n; i++ )
+ v[i] *= s;
+ }
+
+ template<typename T, typename V>
+ T vec_maxabs(const std::size_t n, const V & v)
+ {
+ T ret = 0.0;
+ for ( std::size_t i = 0; i < n; i++ )
+ ret = std::max(ret, std::abs(v[i]));
+
+ return ret;
+ }
+} // namespace plib
+
+#if !defined(__clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
+#if !(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 3))
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+#endif /* PLIB_VECTOR_OPS_H_ */
diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp
index a1d53d6792d..4a1c8ac0315 100644
--- a/src/lib/netlist/prg/nltool.cpp
+++ b/src/lib/netlist/prg/nltool.cpp
@@ -9,21 +9,23 @@
****************************************************************************/
#include "netlist/plib/pmain.h"
-#include "netlist/nl_setup.h"
-#include "netlist/nl_parser.h"
#include "netlist/devices/net_lib.h"
-#include "netlist/tools/nl_convert.h"
+#include "netlist/nl_parser.h"
+#include "netlist/nl_setup.h"
#include "netlist/solver/nld_solver.h"
+#include "netlist/tools/nl_convert.h"
#include <cstring>
+#define NLTOOL_VERSION 20190202
+
class tool_app_t : public plib::app
{
public:
tool_app_t() :
plib::app(),
opt_grp1(*this, "General options", "The following options apply to all commands."),
- opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"),
+ opt_cmd (*this, "c", "cmd", 0, std::vector<pstring>({"run","convert","listdevices","static","header","docheader"}), "run|convert|listdevices|static|header|docheader"),
opt_file(*this, "f", "file", "-", "file to process (default is stdin)"),
opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."),
opt_rfolders(*this, "r", "rom", "where to look for data files"),
@@ -31,25 +33,34 @@ public:
opt_quiet(*this, "q", "quiet", "be quiet - no warnings"),
opt_version(*this, "", "version", "display version and exit"),
opt_help(*this, "h", "help", "display help and exit"),
+
opt_grp2(*this, "Options for run and static commands", "These options apply to run and static commands."),
opt_name(*this, "n", "name", "", "the netlist in file specified by ""-f"" option to run; default is first one"),
+
opt_grp3(*this, "Options for run command", "These options are only used by the run command."),
- opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)"),
+ opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)\n\n abc def\n\n xyz"),
opt_logs(*this, "l", "log" , "define terminal to log. This option may be specified repeatedly."),
opt_inp(*this, "i", "input", "", "input file to process (default is none)"),
opt_loadstate(*this,"", "loadstate", "", "load state from file and continue from there"),
opt_savestate(*this,"", "savestate", "", "save state to file at end of run"),
+
opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."),
- opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"),
+ opt_type(*this, "y", "type", 0, std::vector<pstring>({"spice","eagle","rinf"}), "type of file to be converted: spice,eagle,rinf"),
+
+ opt_grp5(*this, "Options for header command", "These options are only used by the header command."),
+ opt_tabwidth(*this, "", "tab-width", 4, "Tab width for output."),
+ opt_linewidth(*this,"", "line-width", 72, "Line width for output."),
opt_ex1(*this, "nltool -c run -t 3.5 -f nl_examples/cdelay.c -n cap_delay",
"Run netlist \"cap_delay\" from file nl_examples/cdelay.c for 3.5 seconds"),
opt_ex2(*this, "nltool --cmd=listdevices",
- "List all known devices.")
+ "List all known devices."),
+ opt_ex3(*this, "nltool --cmd=header --tab-width=8 --line-width=80",
+ "Create the header file needed for including netlists as code.")
{}
plib::option_group opt_grp1;
- plib::option_str_limit opt_cmd;
+ plib::option_str_limit<unsigned> opt_cmd;
plib::option_str opt_file;
plib::option_vec opt_defines;
plib::option_vec opt_rfolders;
@@ -60,18 +71,22 @@ public:
plib::option_group opt_grp2;
plib::option_str opt_name;
plib::option_group opt_grp3;
- plib::option_double opt_ttr;
+ plib::option_num<double> opt_ttr;
plib::option_vec opt_logs;
plib::option_str opt_inp;
plib::option_str opt_loadstate;
plib::option_str opt_savestate;
plib::option_group opt_grp4;
- plib::option_str_limit opt_type;
+ plib::option_str_limit<unsigned> opt_type;
+ plib::option_group opt_grp5;
+ plib::option_num<unsigned> opt_tabwidth;
+ plib::option_num<unsigned> opt_linewidth;
plib::option_example opt_ex1;
plib::option_example opt_ex2;
+ plib::option_example opt_ex3;
- int execute();
- pstring usage();
+ int execute() override;
+ pstring usage() override;
private:
void run();
@@ -86,6 +101,8 @@ private:
void listdevices();
+ std::vector<pstring> m_options;
+
};
static NETLIST_START(dummy)
@@ -103,45 +120,54 @@ NETLIST_END()
class netlist_data_folder_t : public netlist::source_t
{
public:
- netlist_data_folder_t(netlist::setup_t &setup,
- pstring folder)
- : netlist::source_t(setup, netlist::source_t::DATA)
+ netlist_data_folder_t(const pstring &folder)
+ : netlist::source_t(netlist::source_t::DATA)
, m_folder(folder)
{
}
- virtual std::unique_ptr<plib::pistream> stream(const pstring &file) override;
+ plib::unique_ptr<plib::pistream> stream(const pstring &file) override;
private:
pstring m_folder;
};
-std::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file)
+plib::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file)
{
pstring name = m_folder + "/" + file;
try
{
- auto strm = plib::make_unique_base<plib::pistream, plib::pifilestream>(name);
- return strm;
+ auto strm = plib::make_unique<plib::pifilestream>(name);
+ return std::move(strm);
}
catch (const plib::pexception &e)
{
if (dynamic_cast<const plib::file_open_e *>(&e) == nullptr )
throw;
}
- return std::unique_ptr<plib::pistream>(nullptr);
+ return plib::unique_ptr<plib::pistream>(nullptr);
}
+class netlist_tool_callbacks_t : public netlist::callbacks_t
+{
+public:
+ netlist_tool_callbacks_t(tool_app_t &app)
+ : netlist::callbacks_t()
+ , m_app(app)
+ { }
+
+ void vlog(const plib::plog_level &l, const pstring &ls) const override;
+
+private:
+ tool_app_t &m_app;
+};
+
class netlist_tool_t : public netlist::netlist_t
{
public:
netlist_tool_t(tool_app_t &app, const pstring &aname)
- : netlist::netlist_t(aname), m_app(app)
- {
- }
-
- virtual ~netlist_tool_t() override
+ : netlist::netlist_t(aname, plib::make_unique<netlist_tool_callbacks_t>(app))
{
}
@@ -149,6 +175,8 @@ public:
{
}
+ netlist::setup_t &setup() { return nlstate().setup(); }
+
void read_netlist(const pstring &filename, const pstring &name,
const std::vector<pstring> &logs,
const std::vector<pstring> &defines,
@@ -157,23 +185,22 @@ public:
// read the netlist ...
for (auto & d : defines)
- setup().register_define(d);
+ setup().add_define(d);
for (auto & r : roms)
- setup().register_source(plib::make_unique_base<netlist::source_t, netlist_data_folder_t>(setup(), r));
+ setup().register_source(plib::make_unique<netlist_data_folder_t>(r));
- setup().register_source(plib::make_unique_base<netlist::source_t,
- netlist::source_file_t>(setup(), filename));
+ setup().register_source(plib::make_unique<netlist::source_file_t>(filename));
setup().include(name);
- log_setup(logs);
+ create_dynamic_logs(logs);
// start devices
- this->start();
+ setup().prepare_to_run();
// reset
this->reset();
}
- void log_setup(const std::vector<pstring> &logs)
+ void create_dynamic_logs(const std::vector<pstring> &logs)
{
log().debug("Creating dynamic logs ...\n");
for (auto & log : logs)
@@ -186,15 +213,15 @@ public:
std::vector<char> save_state()
{
- state().pre_save();
+ run_state_manager().pre_save();
std::size_t size = 0;
- for (auto const & s : state().save_list())
+ for (auto const & s : run_state_manager().save_list())
size += s->m_dt.size * s->m_count;
std::vector<char> buf(size);
char *p = buf.data();
- for (auto const & s : state().save_list())
+ for (auto const & s : run_state_manager().save_list())
{
std::size_t sz = s->m_dt.size * s->m_count;
if (s->m_dt.is_float || s->m_dt.is_integral)
@@ -210,7 +237,7 @@ public:
void load_state(std::vector<char> &buf)
{
std::size_t size = 0;
- for (auto const & s : state().save_list())
+ for (auto const & s : run_state_manager().save_list())
size += s->m_dt.size * s->m_count;
if (buf.size() != size)
@@ -218,7 +245,7 @@ public:
char *p = buf.data();
- for (auto const & s : state().save_list())
+ for (auto const & s : run_state_manager().save_list())
{
std::size_t sz = s->m_dt.size * s->m_count;
if (s->m_dt.is_float || s->m_dt.is_integral)
@@ -227,19 +254,16 @@ public:
log().fatal("found unsupported save element {1}\n", s->m_name);
p += sz;
}
- state().post_load();
- rebuild_lists();
+ run_state_manager().post_load();
+ nlstate().rebuild_lists();
}
protected:
- void vlog(const plib::plog_level &l, const pstring &ls) const override;
-
private:
- tool_app_t &m_app;
};
-void netlist_tool_t::vlog(const plib::plog_level &l, const pstring &ls) const
+void netlist_tool_callbacks_t::vlog(const plib::plog_level &l, const pstring &ls) const
{
pstring err = plib::pfmt("{}: {}\n")(l.name())(ls.c_str());
// FIXME: ...
@@ -248,18 +272,19 @@ void netlist_tool_t::vlog(const plib::plog_level &l, const pstring &ls) const
throw netlist::nl_exception(err);
}
-
struct input_t
{
input_t(const netlist::setup_t &setup, const pstring &line)
+ : m_value(0.0)
{
- char buf[400];
+ std::array<char, 400> buf; // NOLINT(cppcoreguidelines-pro-type-member-init)
double t;
- int e = sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf, &m_value);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
+ int e = sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf.data(), &m_value);
if (e != 3)
throw netlist::nl_exception(plib::pfmt("error {1} scanning line {2}\n")(e)(line));
m_time = netlist::netlist_time::from_double(t);
- m_param = setup.find_param(pstring(buf, pstring::UTF8), true);
+ m_param = setup.find_param(pstring(buf.data()), true);
}
void setparam()
@@ -286,13 +311,12 @@ struct input_t
double m_value;
};
-static std::vector<input_t> read_input(const netlist::setup_t &setup, pstring fname)
+static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstring &fname)
{
std::vector<input_t> ret;
if (fname != "")
{
- plib::pifilestream f(fname);
- plib::putf8_reader r(f);
+ plib::putf8_reader r = plib::putf8_reader(plib::pifilestream(fname));
pstring l;
while (r.readline(l))
{
@@ -309,78 +333,82 @@ static std::vector<input_t> read_input(const netlist::setup_t &setup, pstring fn
void tool_app_t::run()
{
plib::chrono::timer<plib::chrono::system_ticks> t;
- t.start();
-
+ std::vector<input_t> inps;
+ netlist::netlist_time ttr;
netlist_tool_t nt(*this, "netlist");
- //plib::perftime_t<plib::exact_ticks> t;
- nt.init();
+ {
+ auto t_guard(t.guard());
+ //plib::perftime_t<plib::exact_ticks> t;
- if (!opt_verb())
- nt.log().verbose.set_enabled(false);
- if (opt_quiet())
- nt.log().warning.set_enabled(false);
+ nt.init();
- nt.read_netlist(opt_file(), opt_name(),
- opt_logs(),
- opt_defines(), opt_rfolders());
+ if (!opt_verb())
+ nt.log().verbose.set_enabled(false);
+ if (opt_quiet())
+ nt.log().warning.set_enabled(false);
- std::vector<input_t> inps = read_input(nt.setup(), opt_inp());
+ nt.read_netlist(opt_file(), opt_name(),
+ opt_logs(),
+ m_options, opt_rfolders());
+
+ inps = read_input(nt.setup(), opt_inp());
+ ttr = netlist::netlist_time::from_double(opt_ttr());
+ }
- netlist::netlist_time ttr = netlist::netlist_time::from_double(opt_ttr());
- t.stop();
pout("startup time ==> {1:5.3f}\n", t.as_seconds() );
t.reset();
- t.start();
- // FIXME: error handling
- if (opt_loadstate.was_specified())
+ netlist::netlist_time nlt = nt.time();
{
- plib::pifilestream strm(opt_loadstate());
- plib::pbinary_reader reader(strm);
- std::vector<char> loadstate;
- reader.read(loadstate);
- nt.load_state(loadstate);
- pout("Loaded state, run will continue at {1:.6f}\n", nt.time().as_double());
- }
+ auto t_guard(t.guard());
- unsigned pos = 0;
- netlist::netlist_time nlt = nt.time();
+ // FIXME: error handling
+ if (opt_loadstate.was_specified())
+ {
+ plib::pifilestream strm(opt_loadstate());
+ plib::pbinary_reader reader(strm);
+ std::vector<char> loadstate;
+ reader.read(loadstate);
+ nt.load_state(loadstate);
+ pout("Loaded state, run will continue at {1:.6f}\n", nt.time().as_double());
+ }
+ unsigned pos = 0;
- while (pos < inps.size()
- && inps[pos].m_time < ttr
- && inps[pos].m_time >= nlt)
- {
- nt.process_queue(inps[pos].m_time - nlt);
- inps[pos].setparam();
- nlt = inps[pos].m_time;
- pos++;
- }
- pout("runnning ...\n");
+ while (pos < inps.size()
+ && inps[pos].m_time < ttr
+ && inps[pos].m_time >= nlt)
+ {
+ nt.process_queue(inps[pos].m_time - nlt);
+ inps[pos].setparam();
+ nlt = inps[pos].m_time;
+ pos++;
+ }
- if (ttr > nlt)
- nt.process_queue(ttr - nlt);
- else
- {
- pout("end time {1:.6f} less than saved time {2:.6f}\n",
- ttr.as_double(), nlt.as_double());
- ttr = nlt;
- }
+ pout("runnning ...\n");
- if (opt_savestate.was_specified())
- {
- auto savestate = nt.save_state();
- plib::pofilestream strm(opt_savestate());
- plib::pbinary_writer writer(strm);
- writer.write(savestate);
- }
- nt.stop();
+ if (ttr > nlt)
+ nt.process_queue(ttr - nlt);
+ else
+ {
+ pout("end time {1:.6f} less than saved time {2:.6f}\n",
+ ttr.as_double(), nlt.as_double());
+ ttr = nlt;
+ }
- t.stop();
+ if (opt_savestate.was_specified())
+ {
+ auto savestate = nt.save_state();
+ plib::pofilestream strm(opt_savestate());
+ plib::pbinary_writer writer(strm);
+ writer.write(savestate);
+ }
+ nt.stop();
+ }
double emutime = t.as_seconds();
pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n",
@@ -399,9 +427,9 @@ void tool_app_t::static_compile()
nt.read_netlist(opt_file(), opt_name(),
opt_logs(),
- opt_defines(), opt_rfolders());
+ m_options, opt_rfolders());
- plib::putf8_writer w(pout_strm);
+ plib::putf8_writer w(&pout_strm);
std::map<pstring, pstring> mp;
nt.solver()->create_solver_code(mp);
@@ -417,13 +445,26 @@ void tool_app_t::static_compile()
void tool_app_t::mac_out(const pstring &s, const bool cont)
{
- static constexpr unsigned RIGHT = 72;
if (cont)
{
- unsigned adj = 0;
+ unsigned pos = 0;
+ pstring r;
for (const auto &x : s)
- adj += (x == '\t' ? 3 : 0);
- pout("{1}\\\n", s.rpad(" ", RIGHT-1-adj));
+ {
+ if (x == '\t')
+ {
+ auto pos_mod_4 = pos % opt_tabwidth();
+ auto tab_adj = opt_tabwidth() - pos_mod_4;
+ r += plib::rpad(pstring(""), pstring(" "), tab_adj);
+ pos += tab_adj;
+ }
+ else
+ {
+ r += x;
+ pos++;
+ }
+ }
+ pout("{1}\\\n", plib::rpad(r, pstring(" "), opt_linewidth()-1));
}
else
pout("{1}\n", s);
@@ -433,15 +474,15 @@ void tool_app_t::cmac(const netlist::factory::element_t *e)
{
auto v = plib::psplit(e->param_desc(), ",");
pstring vs;
- for (auto s : v)
- vs += ", p" + s.replace_all("+", "").replace_all(".", "_");
+ for (const auto &s : v)
+ vs += ", p" + plib::replace_all(plib::replace_all(s, "+", ""), ".", "_");
mac_out("#define " + e->name() + "(name" + vs + ")");
mac_out("\tNET_REGISTER_DEV(" + e->name() +", name)");
- for (auto s : v)
+ for (const auto &s : v)
{
- pstring r(s.replace_all("+", "").replace_all(".", "_"));
- if (s.startsWith("+"))
+ pstring r(plib::replace_all(plib::replace_all(s, "+", ""), ".", "_"));
+ if (plib::startsWith(s, "+"))
mac_out("\tNET_CONNECT(name, " + r + ", p" + r + ")");
else
mac_out("\tNETDEV_PARAMI(name, " + r + ", p" + r + ")");
@@ -453,18 +494,18 @@ void tool_app_t::mac(const netlist::factory::element_t *e)
{
auto v = plib::psplit(e->param_desc(), ",");
pstring vs;
- for (auto s : v)
+ for (const auto &s : v)
{
- vs += ", " + s.replace_all("+", "").replace_all(".", "_");
+ vs += ", " + plib::replace_all(plib::replace_all(s, "+", ""), ".", "_");
}
pout("{1}(name{2})\n", e->name(), vs);
if (v.size() > 0)
{
pout("/*\n");
- for (auto s : v)
+ for (const auto &s : v)
{
- pstring r(s.replace_all("+", "").replace_all(".", "_"));
- if (s.startsWith("+"))
+ pstring r(plib::replace_all(plib::replace_all(s, "+", ""), ".", "_"));
+ if (plib::startsWith(s, "+"))
pout("{1:10}: Terminal\n",r);
else
pout("{1:10}: Parameter\n", r);
@@ -482,8 +523,7 @@ void tool_app_t::create_header()
nt.log().verbose.set_enabled(false);
nt.log().warning.set_enabled(false);
- nt.setup().register_source(plib::make_unique_base<netlist::source_t,
- netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy));
+ nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy));
nt.setup().include("dummy");
pout("// license:GPL-2.0+\n");
@@ -506,9 +546,9 @@ void tool_app_t::create_header()
if (last_source != e->sourcefile())
{
last_source = e->sourcefile();
- pout("{1}\n", pstring("// ").rpad("-", 72));
- pout("{1}{2}\n", pstring("// Source: "), e->sourcefile().replace_all("../", ""));
- pout("{1}\n", pstring("// ").rpad("-", 72));
+ pout("{1}\n", plib::rpad(pstring("// "), pstring("-"), opt_linewidth()));
+ pout("{1}{2}\n", pstring("// Source: "), plib::replace_all(e->sourcefile(), "../", ""));
+ pout("{1}\n", plib::rpad(pstring("// "), pstring("-"), opt_linewidth()));
}
cmac(e.get());
}
@@ -527,8 +567,7 @@ void tool_app_t::create_docheader()
nt.log().verbose.set_enabled(false);
nt.log().warning.set_enabled(false);
- nt.setup().register_source(plib::make_unique_base<netlist::source_t,
- netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy));
+ nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy));
nt.setup().include("dummy");
std::vector<pstring> devs;
@@ -580,73 +619,42 @@ void tool_app_t::listdevices()
netlist::factory::list_t &list = nt.setup().factory();
- nt.setup().register_source(plib::make_unique_base<netlist::source_t,
- netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy));
+ nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy));
nt.setup().include("dummy");
- nt.start();
+ nt.setup().prepare_to_run();
- std::vector<plib::owned_ptr<netlist::core_device_t>> devs;
+ std::vector<netlist::pool_owned_ptr<netlist::core_device_t>> devs;
for (auto & f : list)
{
pstring out = plib::pfmt("{1:-20} {2}(<id>")(f->classname())(f->name());
- std::vector<pstring> terms;
- f->macro_actions(nt.setup().netlist(), f->name() + "_lc");
- auto d = f->Create(nt.setup().netlist(), f->name() + "_lc");
+ f->macro_actions(nt.setup(), f->name() + "_lc");
+ auto d = f->Create(nt.nlstate(), f->name() + "_lc");
// get the list of terminals ...
- for (auto & t : nt.setup().m_terminals)
- {
- if (t.second->name().startsWith(d->name()))
- {
- pstring tn(t.second->name().substr(d->name().length()+1));
- if (tn.find(".") == pstring::npos)
- terms.push_back(tn);
- }
- }
-
- for (auto & t : nt.setup().m_alias)
- {
- if (t.first.startsWith(d->name()))
- {
- pstring tn(t.first.substr(d->name().length()+1));
- //printf("\t%s %s %s\n", t.first.c_str(), t.second.c_str(), tn.c_str());
- if (tn.find(".") == pstring::npos)
- {
- terms.push_back(tn);
- pstring resolved = nt.setup().resolve_alias(t.first);
- //printf("\t%s %s %s\n", t.first.c_str(), t.second.c_str(), resolved.c_str());
- if (resolved != t.first)
- {
- auto found = std::find(terms.begin(), terms.end(), resolved.substr(d->name().length()+1));
- if (found!=terms.end())
- terms.erase(found);
- }
- }
- }
- }
+ std::vector<pstring> terms(nt.setup().get_terminals_for_device_name(d->name()));
out += "," + f->param_desc();
- for (auto p : plib::psplit(f->param_desc(),",") )
+ for (const auto &p : plib::psplit(f->param_desc(),",") )
{
- if (p.startsWith("+"))
+ if (plib::startsWith(p, "+"))
{
plib::container::remove(terms, p.substr(1));
}
}
out += ")";
- printf("%s\n", out.c_str());
+ pout("{}\n", out);
if (terms.size() > 0)
{
pstring t = "";
for (auto & j : terms)
t += "," + j;
- printf("\tTerminals: %s\n", t.substr(1).c_str());
+ pout("\tTerminals: {}\n", t.substr(1));
}
- devs.push_back(std::move(d));
+ devs.emplace_back(std::move(d));
}
}
@@ -681,10 +689,6 @@ int tool_app_t::execute()
plib::fpsignalenabler::global_enable(true);
plib::fpsignalenabler sigen(plib::FP_ALL & ~plib::FP_INEXACT & ~plib::FP_UNDERFLOW);
- //perr("{}", "WARNING: This is Work In Progress! - It may fail anytime\n");
- //perr("Update dispatching using method {}\n", pmf_verbose[NL_PMF_TYPE]);
- //printf("test2 %f\n", std::exp(-14362.38064713));
-
if (opt_help())
{
pout(usage());
@@ -694,8 +698,8 @@ int tool_app_t::execute()
if (opt_version())
{
pout(
- "nltool (netlist) 0.1\n"
- "Copyright (C) 2018 Couriersud\n"
+ "nltool (netlist) " PSTRINGIFY(NLTOOL_VERSION) "\n"
+ "Copyright (C) 2019 Couriersud\n"
"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n\n"
@@ -703,9 +707,12 @@ int tool_app_t::execute()
return 0;
}
+ m_options = opt_defines();
+ m_options.emplace_back("NLTOOL_VERSION=" PSTRINGIFY(NLTOOL_VERSION));
+
try
{
- pstring cmd = opt_cmd();
+ pstring cmd = opt_cmd.as_string();
if (cmd == "listdevices")
listdevices();
else if (cmd == "run")
@@ -723,29 +730,29 @@ int tool_app_t::execute()
if (opt_file() == "-")
{
plib::pstdin f;
- ostrm.write(f);
+ plib::copystream(ostrm, f);
}
else
{
plib::pifilestream f(opt_file());
- ostrm.write(f);
+ plib::copystream(ostrm, f);
}
contents = ostrm.str();
pstring result;
- if (opt_type().equals("spice"))
+ if (opt_type.as_string() == "spice")
{
nl_convert_spice_t c;
c.convert(contents);
result = c.result();
}
- else if (opt_type().equals("eagle"))
+ else if (opt_type.as_string() == "eagle")
{
nl_convert_eagle_t c;
c.convert(contents);
result = c.result();
}
- else if (opt_type().equals("rinf"))
+ else if (opt_type.as_string() == "rinf")
{
nl_convert_rinf_t c;
c.convert(contents);
@@ -771,13 +778,6 @@ int tool_app_t::execute()
perr("plib exception caught: {}\n", e.text());
}
-#if 0
-#define str(x) # x
-#define strx(x) str(x)
-#define ttt strx(__cplusplus)
- printf("%s\n", ttt);
-#endif
-
return 0;
}
diff --git a/src/lib/netlist/prg/nlwav.cpp b/src/lib/netlist/prg/nlwav.cpp
index 23491e88349..683bb8a1c55 100644
--- a/src/lib/netlist/prg/nlwav.cpp
+++ b/src/lib/netlist/prg/nlwav.cpp
@@ -1,45 +1,13 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
-#include <cstring>
-#include "../plib/pstring.h"
-#include "../plib/plists.h"
-#include "../plib/pstream.h"
-#include "../plib/pmain.h"
-#include "../plib/ppmf.h"
-#include "../nl_setup.h"
-
-class nlwav_app : public plib::app
-{
-public:
- nlwav_app() :
- plib::app(),
- opt_inp(*this, "i", "input", "-", "input file"),
- opt_out(*this, "o", "output", "-", "output file"),
- opt_amp(*this, "a", "amp", 10000.0, "amplification after mean correction"),
- opt_rate(*this, "r", "rate", 48000, "sample rate of output file"),
- opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
- opt_quiet(*this,"q", "quiet", "be quiet - no warnings"),
- opt_version(*this, "", "version", "display version and exit"),
- opt_help(*this, "h", "help", "display help and exit")
- {}
- plib::option_str opt_inp;
- plib::option_str opt_out;
- plib::option_double opt_amp;
- plib::option_long opt_rate;
- plib::option_bool opt_verb;
- plib::option_bool opt_quiet;
- plib::option_bool opt_version;
- plib::option_bool opt_help;
-
- int execute();
- pstring usage();
-
- plib::pstdin pin_strm;
-private:
- void convert1(long sample_rate);
- void convert(long sample_rate);
-};
+#include "plib/pstring.h"
+#include "netlist/nl_setup.h"
+#include "plib/plists.h"
+#include "plib/pmain.h"
+#include "plib/ppmf.h"
+#include "plib/pstream.h"
+#include <cstring>
/* From: https://ffmpeg.org/pipermail/ffmpeg-devel/2007-October/038122.html
* The most compatible way to make a wav header for unknown length is to put
@@ -51,324 +19,470 @@ private:
* and data chunk length to the file.
*/
/* http://de.wikipedia.org/wiki/RIFF_WAVE */
+
class wav_t
{
public:
- wav_t(plib::postream &strm, unsigned sr) : m_f(strm)
+ // XXNOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
+ wav_t(plib::postream &strm, std::size_t sr, std::size_t channels)
+ : m_f(strm)
+ /* force "play" to play and warn about eof instead of being silent */
+ , m_fmt(static_cast<std::uint16_t>(channels), static_cast<std::uint32_t>(sr))
+ , m_data(m_f.seekable() ? 0 : 0xffffffff)
{
- initialize(sr);
- m_f.write(&m_fh, sizeof(m_fh));
- m_f.write(&m_fmt, sizeof(m_fmt));
- m_f.write(&m_data, sizeof(m_data));
+
+ write(m_fh);
+ write(m_fmt);
+ write(m_data);
}
+
+ COPYASSIGNMOVE(wav_t, delete)
+
~wav_t()
{
if (m_f.seekable())
{
m_fh.filelen = m_data.len + sizeof(m_data) + sizeof(m_fh) + sizeof(m_fmt) - 8;
- m_f.seek(0);
- m_f.write(&m_fh, sizeof(m_fh));
- m_f.write(&m_fmt, sizeof(m_fmt));
+ m_f.seekp(0);
+ write(m_fh);
+ write(m_fmt);
//data.len = fmt.block_align * n;
- m_f.write(&m_data, sizeof(m_data));
+ write(m_data);
}
}
- unsigned channels() { return m_fmt.channels; }
- unsigned sample_rate() { return m_fmt.sample_rate; }
+ std::size_t channels() { return m_fmt.channels; }
+ std::size_t sample_rate() { return m_fmt.sample_rate; }
+
+ template <typename T>
+ void write(const T &val)
+ {
+ m_f.write(reinterpret_cast<const plib::postream::value_type *>(&val), sizeof(T));
+ }
- void write_sample(int sample)
+ void write_sample(int *sample)
{
m_data.len += m_fmt.block_align;
- int16_t ps = static_cast<int16_t>(sample); /* 16 bit sample, FIXME: Endianess? */
- m_f.write(&ps, sizeof(ps));
+ for (std::size_t i = 0; i < channels(); i++)
+ {
+ auto ps = static_cast<int16_t>(sample[i]); /* 16 bit sample, FIXME: Endianess? */
+ write(ps);
+ }
}
private:
struct riff_chunk_t
{
- uint8_t group_id[4];
- uint32_t filelen;
- uint8_t rifftype[4];
+ uint8_t group_id[4] = {'R','I','F','F'};
+ uint32_t filelen = 0;
+ uint8_t rifftype[4] = {'W','A','V','E'};
};
struct riff_format_t
{
- uint8_t signature[4];
- uint32_t fmt_length;
- uint16_t format_tag;
+ riff_format_t(uint16_t achannels, uint32_t asample_rate)
+ {
+ channels = achannels;
+ sample_rate = asample_rate;
+ block_align = channels * ((bits_sample + 7) / 8);
+ bytes_per_second = sample_rate * block_align;
+ }
+ uint8_t signature[4] = {'f','m','t',' '};
+ uint32_t fmt_length = 16;
+ uint16_t format_tag = 0x0001; // PCM
uint16_t channels;
uint32_t sample_rate;
uint32_t bytes_per_second;
uint16_t block_align;
- uint16_t bits_sample;
+ uint16_t bits_sample = 16;
};
struct riff_data_t
{
- uint8_t signature[4];
+ riff_data_t(uint32_t alen) : len(alen) {}
+ uint8_t signature[4] = {'d','a','t','a'};
uint32_t len;
// data follows
};
- void initialize(unsigned sr)
- {
- std::memcpy(m_fh.group_id, "RIFF", 4);
- m_fh.filelen = 0x0; // Fixme
- std::memcpy(m_fh.rifftype, "WAVE", 4);
-
- std::memcpy(m_fmt.signature, "fmt ", 4);
- m_fmt.fmt_length = 16;
- m_fmt.format_tag = 0x0001; //PCM
- m_fmt.channels = 1;
- m_fmt.sample_rate = sr;
- m_fmt.bits_sample = 16;
- m_fmt.block_align = m_fmt.channels * ((m_fmt.bits_sample + 7) / 8);
- m_fmt.bytes_per_second = m_fmt.sample_rate * m_fmt.block_align;
-
- std::memcpy(m_data.signature, "data", 4);
- //m_data.len = m_fmt.bytes_per_second * 2 * 0;
- /* force "play" to play and warn about eof instead of being silent */
- m_data.len = (m_f.seekable() ? 0 : 0xffffffff);
-
- }
+ plib::postream &m_f;
riff_chunk_t m_fh;
riff_format_t m_fmt;
riff_data_t m_data;
- plib::postream &m_f;
-
};
class log_processor
{
public:
- typedef plib::pmfp<void, double, double> callback_type;
- log_processor(plib::pistream &is, callback_type cb) : m_is(is), m_cb(cb) { }
+ using callback_type = plib::pmfp<void, std::size_t, double, double>;
+
+ struct elem
+ {
+ elem() : t(0), v(0), eof(false), need_more(true) { }
+ double t;
+ double v;
+ bool eof;
+ bool need_more;
+ };
+
+ log_processor(std::size_t channels, callback_type &cb)
+ : m_cb(cb)
+ , m_e(channels)
+ { }
+
+ bool readmore(std::vector<plib::putf8_reader> &r)
+ {
+ bool success = false;
+ for (std::size_t i = 0; i< r.size(); i++)
+ {
+ if (m_e[i].need_more)
+ {
+ pstring line;
+ m_e[i].eof = !r[i].readline(line);
+ if (!m_e[i].eof)
+ {
+ // sscanf is very fast ...
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
+ sscanf(line.c_str(), "%lf %lf", &m_e[i].t, &m_e[i].v);
+ m_e[i].need_more = false;
+ }
+ }
+ success |= !m_e[i].eof;
+ }
+ return success;
+ }
- void process()
+ void process(std::vector<plib::unique_ptr<plib::pistream>> &is)
{
- plib::putf8_reader reader(m_is);
+ std::vector<plib::putf8_reader> readers;
+ for (auto &i : is)
+ {
+ plib::putf8_reader r(std::move(i));
+ readers.push_back(std::move(r));
+ }
+
pstring line;
+ bool more = readmore(readers);
- while(reader.readline(line))
+ while (more)
{
- double t = 0.0; double v = 0.0;
- sscanf(line.c_str(), "%lf %lf", &t, &v);
- m_cb(t, v);
+ double mint = 1e200;
+ std::size_t mini = 0;
+ for (std::size_t i = 0; i<readers.size(); i++)
+ if (!m_e[i].need_more)
+ {
+ if (m_e[i].t < mint)
+ {
+ mint = m_e[i].t;
+ mini = i;
+ }
+ }
+
+ m_e[mini].need_more = true;
+ m_cb(mini, mint, m_e[mini].v);
+ more = readmore(readers);
}
}
private:
- plib::pistream &m_is;
callback_type m_cb;
+ std::vector<elem> m_e;
};
struct aggregator
{
- typedef plib::pmfp<void, double, double> callback_type;
+ using callback_type = plib::pmfp<void, std::size_t, double, double>;
- aggregator(double quantum, callback_type cb)
- : m_quantum(quantum)
+ aggregator(std::size_t channels, double quantum, callback_type cb)
+ : m_channels(channels)
+ , m_quantum(quantum)
, m_cb(cb)
, ct(0.0)
, lt(0.0)
- , outsam(0.0)
- , cursam(0.0)
+ , outsam(channels, 0.0)
+ , cursam(channels, 0.0)
{ }
- void process(double time, double val)
+ void process(std::size_t chan, double time, double val)
{
- while (time >= ct)
+ while (time >= ct + m_quantum)
{
- outsam += (ct - lt) * cursam;
- outsam = outsam / m_quantum;
- m_cb(ct, outsam);
- outsam = 0.0;
+ for (std::size_t i=0; i< m_channels; i++)
+ {
+ outsam[i] += (ct - lt) * cursam[i];
+ outsam[i] = outsam[i] / m_quantum;
+ m_cb(i, ct, outsam[i]);
+ outsam[i] = 0.0;
+ }
lt = ct;
ct += m_quantum;
}
- outsam += (time-lt)*cursam;
+ for (std::size_t i=0; i< m_channels; i++)
+ outsam[i] += (time-lt)*cursam[i];
lt = time;
- cursam = val;
+ cursam[chan] = val;
}
private:
+ std::size_t m_channels;
double m_quantum;
callback_type m_cb;
double ct;
double lt;
- double outsam;
- double cursam;
+ std::vector<double> outsam;
+ std::vector<double> cursam;
};
class wavwriter
{
public:
- wavwriter(plib::postream &fo, unsigned sample_rate, double ampa)
- : mean(0.0)
- , means(0.0)
- , maxsam(-1e9)
- , minsam(1e9)
- , n(0)
+ wavwriter(plib::postream &fo, std::size_t channels, std::size_t sample_rate, double ampa)
+ : mean(channels, 0.0)
+ , means(channels, 0.0)
+ , maxsam(channels, -1e9)
+ , minsam(channels, 1e9)
+ , m_n(channels, 0)
+ , m_samples(channels, 0)
+ , m_last_time(0)
, m_fo(fo)
- , amp(ampa)
- , m_wo(m_fo, sample_rate)
+ , m_amp(ampa)
+ , m_wo(m_fo, sample_rate, channels)
{ }
- void process(double time, double outsam)
+ void process(std::size_t chan, double time, double outsam)
{
- means += outsam;
- maxsam = std::max(maxsam, outsam);
- minsam = std::min(minsam, outsam);
- n++;
- //mean = means / (double) n;
- mean += 5.0 / static_cast<double>(m_wo.sample_rate()) * (outsam - mean);
-
- outsam = (outsam - mean) * amp;
+ if (time > m_last_time)
+ m_wo.write_sample(m_samples.data());
+ m_last_time = time;
+ means[chan] += outsam;
+ maxsam[chan] = std::max(maxsam[chan], outsam);
+ minsam[chan] = std::min(minsam[chan], outsam);
+ m_n[chan]++;
+ //mean = means / (double) m_n;
+ mean[chan] += 5.0 / static_cast<double>(m_wo.sample_rate()) * (outsam - mean[chan]);
+
+ outsam = (outsam - mean[chan]) * m_amp;
outsam = std::max(-32000.0, outsam);
outsam = std::min(32000.0, outsam);
- m_wo.write_sample(static_cast<int>(outsam));
+ m_samples[chan] = static_cast<int>(outsam);
}
- double mean;
- double means;
- double maxsam;
- double minsam;
- std::size_t n;
+ std::vector<double> mean;
+ std::vector<double> means;
+ std::vector<double> maxsam;
+ std::vector<double> minsam;
+ std::vector<std::size_t> m_n;
+ std::vector<int> m_samples;
+ double m_last_time;
private:
+
plib::postream &m_fo;
- double amp;
+ double m_amp;
wav_t m_wo;
};
-void nlwav_app::convert(long sample_rate)
+class vcdwriter
{
- plib::postream *fo = (opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opt_out()));
- plib::pistream *fin = (opt_inp() == "-" ? &pin_strm : plib::palloc<plib::pifilestream>(opt_inp()));
- plib::putf8_reader reader(*fin);
- wav_t *wo = plib::palloc<wav_t>(*fo, static_cast<unsigned>(sample_rate));
-
- double dt = 1.0 / static_cast<double>(wo->sample_rate());
- double ct = dt;
- //double mean = 2.4;
- double amp = opt_amp();
- double mean = 0.0;
- double means = 0.0;
- double cursam = 0.0;
- double outsam = 0.0;
- double lt = 0.0;
- double maxsam = -1e9;
- double minsam = 1e9;
- int n = 0;
- //short sample = 0;
- pstring line;
-
- while(reader.readline(line))
+public:
+
+ enum format_e
+ {
+ DIGITAL,
+ ANALOG
+ };
+
+ vcdwriter(plib::postream &fo, const std::vector<pstring> &channels,
+ format_e format, double high_level = 2.0, double low_level = 1.0)
+ : m_channels(channels.size())
+ , m_last_time(0)
+ , m_fo(fo)
+ , m_high_level(high_level)
+ , m_low_level(low_level)
+ , m_format(format)
{
-#if 1
- double t = 0.0; double v = 0.0;
- sscanf(line.c_str(), "%lf %lf", &t, &v);
- while (t >= ct)
+ for (pstring::value_type c = 64; c < 64+26; c++)
+ m_ids.emplace_back(pstring(c));
+ write("$date Sat Jan 19 14:14:17 2019\n");
+ write("$end\n");
+ write("$version Netlist nlwav 0.1\n");
+ write("$end\n");
+ write("$timescale 1 ns\n");
+ write("$end\n");
+ std::size_t i = 0;
+ for (const auto &ch : channels)
{
- outsam += (ct - lt) * cursam;
- outsam = outsam / dt;
- if (t>0.0)
- {
- means += outsam;
- maxsam = std::max(maxsam, outsam);
- minsam = std::min(minsam, outsam);
- n++;
- //mean = means / (double) n;
- mean += 5.0 / static_cast<double>(wo->sample_rate()) * (outsam - mean);
- }
- outsam = (outsam - mean) * amp;
- outsam = std::max(-32000.0, outsam);
- outsam = std::min(32000.0, outsam);
- wo->write_sample(static_cast<int>(outsam));
- outsam = 0.0;
- lt = ct;
- ct += dt;
+ // $var real 64 N1X1 N1X1 $end
+ if (format == ANALOG)
+ write(pstring("$var real 64 ") + m_ids[i++] + " " + ch + " $end\n");
+ else if (format == DIGITAL)
+ write(pstring("$var wire 1 ") + m_ids[i++] + " " + ch + " $end\n");
}
- outsam += (t-lt)*cursam;
- lt = t;
- cursam = v;
-#else
- float t = 0.0; float v = 0.0;
- fscanf(FIN, "%f %f", &t, &v);
- while (ct <= t)
+ write("$enddefinitions $end\n");
+ if (format == ANALOG)
{
- wo.write_sample(sample);
- n++;
- ct += dt;
+ write("$dumpvars\n");
+ //r0.0 N1X1
+ for (i = 0; i < channels.size(); i++)
+ write(pstring("r0.0 ") + m_ids[i] + "\n");
+ write("$end\n");
}
- means += v;
- mean = means / (double) n;
- v = v - mean;
- v = v * amp;
- if (v>32000.0)
- v = 32000.0;
- else if (v<-32000.0)
- v = -32000.0;
- sample = v;
- //printf("%f %f\n", t, v);
-#endif
+
}
- plib::pfree(wo);
- if (opt_inp() != "-")
- plib::pfree(fin);
- if (opt_out() != "-")
- plib::pfree(fo);
- if (!opt_quiet())
+ void process(std::size_t chan, double time, double outsam)
{
- perr("Mean (low freq filter): {}\n", mean);
- perr("Mean (static): {}\n", means / static_cast<double>(n));
- perr("Amp + {}\n", 32000.0 / (maxsam- mean));
- perr("Amp - {}\n", -32000.0 / (minsam- mean));
+ if (time > m_last_time)
+ {
+ write(pstring("#") + plib::to_string(static_cast<std::int64_t>(m_last_time * 1e9)) + " ");
+ write(m_buf + "\n");
+ m_buf = "";
+ m_last_time = time;
+ }
+ if (m_format == ANALOG)
+ m_buf += "r" + plib::to_string(outsam)+ " " + m_ids[chan] + " ";
+ else
+ {
+ if (outsam >= m_high_level)
+ m_buf += pstring("1") + m_ids[chan] + " ";
+ else if (outsam <= m_low_level)
+ m_buf += pstring("0") + m_ids[chan] + " ";
+ }
+ }
+
+private:
+ void write(const pstring &line)
+ {
+ auto p = static_cast<const char *>(line.c_str());
+ std::size_t len = std::strlen(p);
+ m_fo.write(p, len);
}
-}
-void nlwav_app::convert1(long sample_rate)
+ std::size_t m_channels;
+ double m_last_time;
+
+ plib::postream &m_fo;
+ std::vector<pstring> m_ids;
+ pstring m_buf;
+ double m_high_level;
+ double m_low_level;
+ format_e m_format;
+};
+
+class nlwav_app : public plib::app
{
- plib::postream *fo = (opt_out() == "-" ? &pout_strm : plib::palloc<plib::pofilestream>(opt_out()));
- plib::pistream *fin = (opt_inp() == "-" ? &pin_strm : plib::palloc<plib::pifilestream>(opt_inp()));
+public:
+ nlwav_app() :
+ plib::app(),
+ opt_fmt(*this, "f", "format", 0, std::vector<pstring>({"wav","vcda","vcdd"}),
+ "output format. Available options are wav|vcda|vcdd."
+ " wav : multichannel wav output"
+ " vcda : analog VCD output"
+ " vcdd : digital VCD output"
+ " Digital signals are created using the --high and --low options"
+ ),
+ opt_out(*this, "o", "output", "-", "output file"),
+ opt_rate(*this, "r", "rate", 48000, "sample rate of output file"),
+ opt_amp(*this, "a", "amp", 10000.0, "amplification after mean correction (wav only)"),
+ opt_high(*this, "u", "high", 2.0, "minimum input for high level (vcdd only)"),
+ opt_low(*this, "l", "low", 1.0, "maximum input for low level (vcdd only)"),
+ opt_verb(*this, "v", "verbose", "be verbose - this produces lots of output"),
+ opt_quiet(*this,"q", "quiet", "be quiet - no warnings"),
+ opt_args(*this, "input file(s)"),
+ opt_version(*this, "", "version", "display version and exit"),
+ opt_help(*this, "h", "help", "display help and exit"),
+ opt_ex1(*this, "./nlwav -f vcdd -o x.vcd log_V*",
+ "convert all files starting with \"log_V\" into a digital vcd file"),
+ opt_ex2(*this, "./nlwav -f wav -o x.wav log_V*",
+ "convert all files starting with \"log_V\" into a multichannel wav file"),
+ m_outstrm(nullptr)
+ {}
- double dt = 1.0 / static_cast<double>(sample_rate);
+ int execute() override;
+ pstring usage() override;
- wavwriter *wo = plib::palloc<wavwriter>(*fo, static_cast<unsigned>(sample_rate), opt_amp());
- aggregator ag(dt, aggregator::callback_type(&wavwriter::process, wo));
- log_processor lp(*fin, log_processor::callback_type(&aggregator::process, &ag));
+private:
+ void convert_wav();
+ void convert_vcd(vcdwriter::format_e format);
- lp.process();
+ plib::option_str_limit<unsigned> opt_fmt;
+ plib::option_str opt_out;
+ plib::option_num<std::size_t> opt_rate;
+ plib::option_num<double> opt_amp;
+ plib::option_num<double> opt_high;
+ plib::option_num<double> opt_low;
+ plib::option_bool opt_verb;
+ plib::option_bool opt_quiet;
+ plib::option_args opt_args;
+ plib::option_bool opt_version;
+ plib::option_bool opt_help;
+ plib::option_example opt_ex1;
+ plib::option_example opt_ex2;
+ plib::pstdin pin_strm;
+
+ std::vector<plib::unique_ptr<plib::pistream>> m_instrms;
+ plib::postream *m_outstrm;
+};
+
+void nlwav_app::convert_wav()
+{
+
+ double dt = 1.0 / static_cast<double>(opt_rate());
+
+ plib::unique_ptr<wavwriter> wo = plib::make_unique<wavwriter>(*m_outstrm, m_instrms.size(), opt_rate(), opt_amp());
+ plib::unique_ptr<aggregator> ago = plib::make_unique<aggregator>(m_instrms.size(), dt, aggregator::callback_type(&wavwriter::process, wo.get()));
+ aggregator::callback_type agcb = log_processor::callback_type(&aggregator::process, ago.get());
+
+ log_processor lp(m_instrms.size(), agcb);
+
+ lp.process(m_instrms);
if (!opt_quiet())
{
+#if 0
perr("Mean (low freq filter): {}\n", wo->mean);
- perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->n));
+ perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->m_n));
perr("Amp + {}\n", 32000.0 / (wo->maxsam - wo->mean));
perr("Amp - {}\n", -32000.0 / (wo->minsam - wo->mean));
+#endif
}
+}
- plib::pfree(wo);
- if (opt_inp() != "-")
- plib::pfree(fin);
- if (opt_out() != "-")
- plib::pfree(fo);
+void nlwav_app::convert_vcd(vcdwriter::format_e format)
+{
+
+ plib::unique_ptr<vcdwriter> wo = plib::make_unique<vcdwriter>(*m_outstrm, opt_args(),
+ format, opt_high(), opt_low());
+ log_processor::callback_type agcb = log_processor::callback_type(&vcdwriter::process, wo.get());
+
+ log_processor lp(m_instrms.size(), agcb);
+ lp.process(m_instrms);
+
+ if (!opt_quiet())
+ {
+#if 0
+ perr("Mean (low freq filter): {}\n", wo->mean);
+ perr("Mean (static): {}\n", wo->means / static_cast<double>(wo->m_n));
+ perr("Amp + {}\n", 32000.0 / (wo->maxsam - wo->mean));
+ perr("Amp - {}\n", -32000.0 / (wo->minsam - wo->mean));
+#endif
+ }
}
pstring nlwav_app::usage()
{
return help("Convert netlist log files into wav files.\n",
- "nltool [options]");
+ "nlwav [OPTION] ... [FILE] ...");
}
int nlwav_app::execute()
{
+ for (auto &i : opt_args())
+ pout(pstring("Hello : ") + i + "\n");
if (opt_help())
{
pout(usage());
@@ -379,7 +493,7 @@ int nlwav_app::execute()
{
pout(
"nlwav (netlist) 0.1\n"
- "Copyright (C) 2018 Couriersud\n"
+ "Copyright (C) 2019 Couriersud\n"
"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n\n"
@@ -387,10 +501,31 @@ int nlwav_app::execute()
return 0;
}
- if ((1))
- convert1(opt_rate());
- else
- convert(opt_rate());
+ m_outstrm = (opt_out() == "-" ? &pout_strm : plib::pnew<plib::pofilestream>(opt_out()));
+
+ for (auto &oi: opt_args())
+ {
+ plib::unique_ptr<plib::pistream> fin = (oi == "-" ?
+ plib::make_unique<plib::pstdin>()
+ : plib::make_unique<plib::pifilestream>(oi));
+ m_instrms.push_back(std::move(fin));
+ }
+
+ switch (opt_fmt())
+ {
+ case 0:
+ convert_wav(); break;
+ case 1:
+ convert_vcd(vcdwriter::ANALOG); break;
+ case 2:
+ convert_vcd(vcdwriter::DIGITAL); break;
+ default:
+ // tease compiler - can't happen
+ break;
+ }
+
+ if (opt_out() != "-")
+ plib::pdelete(m_outstrm);
return 0;
}
diff --git a/src/lib/netlist/solver/mat_cr.h b/src/lib/netlist/solver/mat_cr.h
deleted file mode 100644
index 8693c49c3e1..00000000000
--- a/src/lib/netlist/solver/mat_cr.h
+++ /dev/null
@@ -1,175 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Couriersud
-/*
- * mat_cr.h
- *
- * Compressed row format matrices
- *
- */
-
-#ifndef MAT_CR_H_
-#define MAT_CR_H_
-
-#include <algorithm>
-#include "../plib/pconfig.h"
-#include "../plib/palloc.h"
-
-template<std::size_t N, typename C = uint16_t, typename T = double>
-struct mat_cr_t
-{
- typedef C index_type;
- typedef T value_type;
-
- C diag[N]; // diagonal index pointer n
- C ia[N+1]; // row index pointer n + 1
- C ja[N*N]; // column index array nz_num, initially (n * n)
- T A[N*N]; // Matrix elements nz_num, initially (n * n)
-
- std::size_t size;
- std::size_t nz_num;
-
- explicit mat_cr_t(const std::size_t n)
- : size(n)
- , nz_num(0)
- {
-#if 0
-#if 0
- ia = plib::palloc_array<C>(n + 1);
- ja = plib::palloc_array<C>(n * n);
- diag = plib::palloc_array<C>(n);
-#else
- diag = plib::palloc_array<C>(n + (n + 1) + n * n);
- ia = diag + n;
- ja = ia + (n+1);
- A = plib::palloc_array<T>(n * n);
-#endif
-#endif
- }
-
- ~mat_cr_t()
- {
-#if 0
- plib::pfree_array(diag);
-#if 0
- plib::pfree_array(ia);
- plib::pfree_array(ja);
-#endif
- plib::pfree_array(A);
-#endif
- }
-
- void set_scalar(const T scalar)
- {
- for (std::size_t i=0, e=nz_num; i<e; i++)
- A[i] = scalar;
- }
-
- void mult_vec(const T * RESTRICT x, T * RESTRICT res)
- {
- /*
- * res = A * x
- */
-
- std::size_t i = 0;
- std::size_t k = 0;
- const std::size_t oe = nz_num;
-
- while (k < oe)
- {
- T tmp = 0.0;
- const std::size_t e = ia[i+1];
- for (; k < e; k++)
- tmp += A[k] * x[ja[k]];
- res[i++] = tmp;
- }
- }
-
- void incomplete_LU_factorization(T * RESTRICT LU)
- {
- /*
- * incomplete LU Factorization according to http://de.wikipedia.org/wiki/ILU-Zerlegung
- *
- * Result is stored in matrix LU
- *
- */
-
- const std::size_t lnz = nz_num;
-
- for (std::size_t k = 0; k < lnz; k++)
- LU[k] = A[k];
-
- for (std::size_t i = 1; ia[i] < lnz; i++) // row i
- {
- const std::size_t iai1 = ia[i + 1];
- const std::size_t pke = diag[i];
- for (std::size_t pk = ia[i]; pk < pke; pk++) // all columns left of diag in row i
- {
- // pk == (i, k)
- const std::size_t k = ja[pk];
- const std::size_t iak1 = ia[k + 1];
- const T LUpk = LU[pk] = LU[pk] / LU[diag[k]];
-
- std::size_t pt = ia[k];
-
- for (std::size_t pj = pk + 1; pj < iai1; pj++) // pj = (i, j)
- {
- // we can assume that within a row ja increases continuously */
- const std::size_t ej = ja[pj];
- while (ja[pt] < ej && pt < iak1)
- pt++;
- if (pt < iak1 && ja[pt] == ej)
- LU[pj] = LU[pj] - LUpk * LU[pt];
- }
- }
- }
- }
-
- void solveLUx (const T * RESTRICT LU, T * RESTRICT r)
- {
- /*
- * Solve a linear equation Ax = r
- * where
- * A = L*U
- *
- * L unit lower triangular
- * U upper triangular
- *
- * ==> LUx = r
- *
- * ==> Ux = L⁻¹ r = w
- *
- * ==> r = Lw
- *
- * This can be solved for w using backwards elimination in L.
- *
- * Now Ux = w
- *
- * This can be solved for x using backwards elimination in U.
- *
- */
-
- for (std::size_t i = 1; ia[i] < nz_num; ++i )
- {
- T tmp = 0.0;
- const std::size_t j1 = ia[i];
- const std::size_t j2 = diag[i];
-
- for (std::size_t j = j1; j < j2; ++j )
- tmp += LU[j] * r[ja[j]];
-
- r[i] -= tmp;
- }
- // i now is equal to n;
- for (std::size_t i = size; i-- > 0; )
- {
- T tmp = 0.0;
- const std::size_t di = diag[i];
- const std::size_t j2 = ia[i+1];
- for (std::size_t j = di + 1; j < j2; j++ )
- tmp += LU[j] * r[ja[j]];
- r[i] = (r[i] - tmp) / LU[di];
- }
- }
-};
-
-#endif /* MAT_CR_H_ */
diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp
index 87c9b46ba21..1fe14b0f5e1 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.cpp
+++ b/src/lib/netlist/solver/nld_matrix_solver.cpp
@@ -6,552 +6,623 @@
*/
#include "nld_matrix_solver.h"
-#include "../plib/putil.h"
+#include "plib/putil.h"
#include <cmath> // <<= needed by windows build
namespace netlist
{
- namespace devices
- {
-
-proxied_analog_output_t::~proxied_analog_output_t()
+namespace devices
{
-}
-terms_for_net_t::terms_for_net_t()
- : m_railstart(0)
- , m_last_V(0.0)
- , m_DD_n_m_1(0.0)
- , m_h_n_m_1(1e-9)
-{
-}
+ terms_for_net_t::terms_for_net_t()
+ : m_railstart(0)
+ , m_last_V(0.0)
+ , m_DD_n_m_1(0.0)
+ , m_h_n_m_1(1e-9)
+ {
+ }
-void terms_for_net_t::clear()
-{
- m_terms.clear();
- m_connected_net_idx.clear();
- m_gt.clear();
- m_go.clear();
- m_Idr.clear();
- m_connected_net_V.clear();
-}
-
-void terms_for_net_t::add(terminal_t *term, int net_other, bool sorted)
-{
- if (sorted)
- for (unsigned i=0; i < m_connected_net_idx.size(); i++)
- {
- if (m_connected_net_idx[i] > net_other)
+ void terms_for_net_t::add(terminal_t *term, int net_other, bool sorted)
+ {
+ if (sorted)
+ for (std::size_t i=0; i < m_connected_net_idx.size(); i++)
{
- plib::container::insert_at(m_terms, i, term);
- plib::container::insert_at(m_connected_net_idx, i, net_other);
- plib::container::insert_at(m_gt, i, 0.0);
- plib::container::insert_at(m_go, i, 0.0);
- plib::container::insert_at(m_Idr, i, 0.0);
- plib::container::insert_at(m_connected_net_V, i, nullptr);
- return;
+ if (m_connected_net_idx[i] > net_other)
+ {
+ plib::container::insert_at(m_terms, i, term);
+ plib::container::insert_at(m_connected_net_idx, i, net_other);
+ return;
+ }
}
- }
- m_terms.push_back(term);
- m_connected_net_idx.push_back(net_other);
- m_gt.push_back(0.0);
- m_go.push_back(0.0);
- m_Idr.push_back(0.0);
- m_connected_net_V.push_back(nullptr);
-}
-
-void terms_for_net_t::set_pointers()
-{
- for (unsigned i = 0; i < count(); i++)
+ m_terms.push_back(term);
+ m_connected_net_idx.push_back(net_other);
+ }
+
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver
+ // ----------------------------------------------------------------------------------------
+
+ matrix_solver_t::matrix_solver_t(netlist_state_t &anetlist, const pstring &name,
+ const eSortType sort, const solver_parameters_t *params)
+ : device_t(anetlist, name)
+ , m_params(*params)
+ , m_stat_calculations(*this, "m_stat_calculations", 0)
+ , m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
+ , m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
+ , m_iterative_fail(*this, "m_iterative_fail", 0)
+ , m_iterative_total(*this, "m_iterative_total", 0)
+ , m_last_step(*this, "m_last_step", netlist_time::zero())
+ , m_fb_sync(*this, "FB_sync")
+ , m_Q_sync(*this, "Q_sync")
+ , m_ops(0)
+ , m_sort(sort)
{
- m_terms[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]);
- m_connected_net_V[i] = m_terms[i]->m_otherterm->net().Q_Analog_state_ptr();
+ connect_post_start(m_fb_sync, m_Q_sync);
}
-}
-
-// ----------------------------------------------------------------------------------------
-// matrix_solver
-// ----------------------------------------------------------------------------------------
-
-matrix_solver_t::matrix_solver_t(netlist_t &anetlist, const pstring &name,
- const eSortType sort, const solver_parameters_t *params)
- : device_t(anetlist, name)
- , m_params(*params)
- , m_stat_calculations(*this, "m_stat_calculations", 0)
- , m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
- , m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
- , m_iterative_fail(*this, "m_iterative_fail", 0)
- , m_iterative_total(*this, "m_iterative_total", 0)
- , m_last_step(*this, "m_last_step", netlist_time::zero())
- , m_fb_sync(*this, "FB_sync")
- , m_Q_sync(*this, "Q_sync")
- , m_ops(0)
- , m_sort(sort)
-{
- connect_post_start(m_fb_sync, m_Q_sync);
-}
-matrix_solver_t::~matrix_solver_t()
-{
-}
+ void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
+ {
-void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
-{
+ log().debug("New solver setup\n");
- log().debug("New solver setup\n");
+ m_nets.clear();
+ m_terms.clear();
- m_nets.clear();
- m_terms.clear();
+ for (auto & net : nets)
+ {
+ m_nets.push_back(net);
+ m_terms.push_back(plib::make_unique<terms_for_net_t>());
+ m_rails_temp.push_back(plib::make_unique<terms_for_net_t>());
+ }
- for (auto & net : nets)
- {
- m_nets.push_back(net);
- m_terms.push_back(plib::make_unique<terms_for_net_t>());
- m_rails_temp.push_back(plib::palloc<terms_for_net_t>());
- }
+ for (std::size_t k = 0; k < nets.size(); k++)
+ {
+ analog_net_t *net = nets[k];
- for (std::size_t k = 0; k < nets.size(); k++)
- {
- analog_net_t *net = nets[k];
+ log().debug("setting up net\n");
- log().debug("setting up net\n");
+ net->set_solver(this);
- net->set_solver(this);
+ for (auto &p : net->core_terms())
+ {
+ log().debug("{1} {2} {3}\n", p->name(), net->name(), net->isRailNet());
+ switch (p->type())
+ {
+ case detail::terminal_type::TERMINAL:
+ if (p->device().is_timestep())
+ if (!plib::container::contains(m_step_devices, &p->device()))
+ m_step_devices.push_back(&p->device());
+ if (p->device().is_dynamic())
+ if (!plib::container::contains(m_dynamic_devices, &p->device()))
+ m_dynamic_devices.push_back(&p->device());
+ {
+ auto *pterm = dynamic_cast<terminal_t *>(p);
+ add_term(k, pterm);
+ }
+ log().debug("Added terminal {1}\n", p->name());
+ break;
+ case detail::terminal_type::INPUT:
+ {
+ proxied_analog_output_t *net_proxy_output = nullptr;
+ for (auto & input : m_inps)
+ if (input->proxied_net() == &p->net())
+ {
+ net_proxy_output = input.get();
+ break;
+ }
+
+ if (net_proxy_output == nullptr)
+ {
+ pstring nname = this->name() + "." + pstring(plib::pfmt("m{1}")(m_inps.size()));
+ nl_assert(p->net().is_analog());
+ auto net_proxy_output_u = pool().make_poolptr<proxied_analog_output_t>(*this, nname, static_cast<analog_net_t *>(&p->net()));
+ net_proxy_output = net_proxy_output_u.get();
+ m_inps.push_back(std::move(net_proxy_output_u));
+ }
+ net_proxy_output->net().add_terminal(*p);
+ // FIXME: repeated calling - kind of brute force
+ net_proxy_output->net().rebuild_list();
+ log().debug("Added input\n");
+ }
+ break;
+ case detail::terminal_type::OUTPUT:
+ log().fatal(MF_1_UNHANDLED_ELEMENT_1_FOUND,
+ p->name());
+ break;
+ }
+ }
+ log().debug("added net with {1} populated connections\n", net->core_terms().size());
+ }
- for (auto &p : net->m_core_terms)
+ /* now setup the matrix */
+ setup_matrix();
+ }
+
+ void matrix_solver_t::sort_terms(eSortType sort)
+ {
+ /* Sort in descending order by number of connected matrix voltages.
+ * The idea is, that for Gauss-Seidel algo the first voltage computed
+ * depends on the greatest number of previous voltages thus taking into
+ * account the maximum amout of information.
+ *
+ * This actually improves performance on popeye slightly. Average
+ * GS computations reduce from 2.509 to 2.370
+ *
+ * Smallest to largest : 2.613
+ * Unsorted : 2.509
+ * Largest to smallest : 2.370
+ *
+ * Sorting as a general matrix pre-conditioning is mentioned in
+ * literature but I have found no articles about Gauss Seidel.
+ *
+ * For Gaussian Elimination however increasing order is better suited.
+ * NOTE: Even better would be to sort on elements right of the matrix diagonal.
+ *
+ */
+
+ const std::size_t iN = m_nets.size();
+
+ switch (sort)
{
- log().debug("{1} {2} {3}\n", p->name(), net->name(), net->isRailNet());
- switch (p->type())
- {
- case detail::terminal_type::TERMINAL:
- if (p->device().is_timestep())
- if (!plib::container::contains(m_step_devices, &p->device()))
- m_step_devices.push_back(&p->device());
- if (p->device().is_dynamic())
- if (!plib::container::contains(m_dynamic_devices, &p->device()))
- m_dynamic_devices.push_back(&p->device());
+ case PREFER_BAND_MATRIX:
+ {
+ for (std::size_t k = 0; k < iN - 1; k++)
{
- terminal_t *pterm = dynamic_cast<terminal_t *>(p);
- add_term(k, pterm);
+ auto pk = get_weight_around_diag(k,k);
+ for (std::size_t i = k+1; i < iN; i++)
+ {
+ auto pi = get_weight_around_diag(i,k);
+ if (pi < pk)
+ {
+ std::swap(m_terms[i], m_terms[k]);
+ std::swap(m_nets[i], m_nets[k]);
+ pk = get_weight_around_diag(k,k);
+ }
+ }
}
- log().debug("Added terminal {1}\n", p->name());
- break;
- case detail::terminal_type::INPUT:
+ }
+ break;
+ case PREFER_IDENTITY_TOP_LEFT:
+ {
+ for (std::size_t k = 0; k < iN - 1; k++)
{
- proxied_analog_output_t *net_proxy_output = nullptr;
- for (auto & input : m_inps)
- if (input->m_proxied_net == &p->net())
+ auto pk = get_left_right_of_diag(k,k);
+ for (std::size_t i = k+1; i < iN; i++)
+ {
+ auto pi = get_left_right_of_diag(i,k);
+ if (pi.first <= pk.first && pi.second >= pk.second)
{
- net_proxy_output = input.get();
- break;
+ std::swap(m_terms[i], m_terms[k]);
+ std::swap(m_nets[i], m_nets[k]);
+ pk = get_left_right_of_diag(k,k);
}
+ }
+ }
+ }
+ break;
+ case ASCENDING:
+ case DESCENDING:
+ {
+ int sort_order = (m_sort == DESCENDING ? 1 : -1);
- if (net_proxy_output == nullptr)
+ for (std::size_t k = 0; k < iN - 1; k++)
+ for (std::size_t i = k+1; i < iN; i++)
{
- pstring nname = this->name() + "." + pstring(plib::pfmt("m{1}")(m_inps.size()));
- auto net_proxy_output_u = plib::make_unique<proxied_analog_output_t>(*this, nname);
- net_proxy_output = net_proxy_output_u.get();
- m_inps.push_back(std::move(net_proxy_output_u));
- nl_assert(p->net().is_analog());
- net_proxy_output->m_proxied_net = static_cast<analog_net_t *>(&p->net());
+ if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0)
+ {
+ std::swap(m_terms[i], m_terms[k]);
+ std::swap(m_nets[i], m_nets[k]);
+ }
}
- net_proxy_output->net().add_terminal(*p);
- // FIXME: repeated calling - kind of brute force
- net_proxy_output->net().rebuild_list();
- log().debug("Added input\n");
- }
- break;
- case detail::terminal_type::OUTPUT:
- log().fatal(MF_1_UNHANDLED_ELEMENT_1_FOUND,
- p->name());
- break;
- }
+ }
+ break;
+ case NOSORT:
+ break;
+ }
+ /* rebuild */
+ for (auto &term : m_terms)
+ {
+ int *other = term->m_connected_net_idx.data();
+ for (std::size_t i = 0; i < term->count(); i++)
+ //FIXME: this is weird
+ if (other[i] != -1)
+ other[i] = get_net_idx(&term->terms()[i]->connected_terminal()->net());
}
- log().debug("added net with {1} populated connections\n", net->m_core_terms.size());
}
- /* now setup the matrix */
- setup_matrix();
-}
+ void matrix_solver_t::setup_matrix()
+ {
+ const std::size_t iN = m_nets.size();
-void matrix_solver_t::setup_matrix()
-{
- const std::size_t iN = m_nets.size();
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ m_terms[k]->m_railstart = m_terms[k]->count();
+ for (std::size_t i = 0; i < m_rails_temp[k]->count(); i++)
+ this->m_terms[k]->add(m_rails_temp[k]->terms()[i], m_rails_temp[k]->m_connected_net_idx.data()[i], false);
+ }
- for (std::size_t k = 0; k < iN; k++)
- {
- m_terms[k]->m_railstart = m_terms[k]->count();
- for (std::size_t i = 0; i < m_rails_temp[k]->count(); i++)
- this->m_terms[k]->add(m_rails_temp[k]->terms()[i], m_rails_temp[k]->connected_net_idx()[i], false);
+ // free all - no longer needed
+ m_rails_temp.clear();
- m_terms[k]->set_pointers();
- }
+ sort_terms(m_sort);
- for (terms_for_net_t *rt : m_rails_temp)
- {
- rt->clear(); // no longer needed
- plib::pfree(rt); // no longer needed
- }
+ this->set_pointers();
- m_rails_temp.clear();
+ /* create a list of non zero elements. */
+ for (unsigned k = 0; k < iN; k++)
+ {
+ terms_for_net_t * t = m_terms[k].get();
+ /* pretty brutal */
+ int *other = t->m_connected_net_idx.data();
- /* Sort in descending order by number of connected matrix voltages.
- * The idea is, that for Gauss-Seidel algo the first voltage computed
- * depends on the greatest number of previous voltages thus taking into
- * account the maximum amout of information.
- *
- * This actually improves performance on popeye slightly. Average
- * GS computations reduce from 2.509 to 2.370
- *
- * Smallest to largest : 2.613
- * Unsorted : 2.509
- * Largest to smallest : 2.370
- *
- * Sorting as a general matrix pre-conditioning is mentioned in
- * literature but I have found no articles about Gauss Seidel.
- *
- * For Gaussian Elimination however increasing order is better suited.
- * NOTE: Even better would be to sort on elements right of the matrix diagonal.
- *
- */
+ t->m_nz.clear();
- if (m_sort != NOSORT)
- {
- int sort_order = (m_sort == DESCENDING ? 1 : -1);
+ for (std::size_t i = 0; i < t->m_railstart; i++)
+ if (!plib::container::contains(t->m_nz, static_cast<unsigned>(other[i])))
+ t->m_nz.push_back(static_cast<unsigned>(other[i]));
+
+ t->m_nz.push_back(k); // add diagonal
+
+ /* and sort */
+ std::sort(t->m_nz.begin(), t->m_nz.end());
+ }
+
+ /* create a list of non zero elements right of the diagonal
+ * These list anticipate the population of array elements by
+ * Gaussian elimination.
+ */
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ terms_for_net_t * t = m_terms[k].get();
+ /* pretty brutal */
+ int *other = t->m_connected_net_idx.data();
- for (unsigned k = 0; k < iN - 1; k++)
- for (unsigned i = k+1; i < iN; i++)
+ if (k==0)
+ t->m_nzrd.clear();
+ else
{
- if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0)
+ t->m_nzrd = m_terms[k-1]->m_nzrd;
+ for (auto j = t->m_nzrd.begin(); j != t->m_nzrd.end(); )
{
- std::swap(m_terms[i], m_terms[k]);
- std::swap(m_nets[i], m_nets[k]);
+ if (*j < k + 1)
+ j = t->m_nzrd.erase(j);
+ else
+ ++j;
}
}
- for (auto &term : m_terms)
- {
- int *other = term->connected_net_idx();
- for (unsigned i = 0; i < term->count(); i++)
- if (other[i] != -1)
- other[i] = get_net_idx(&term->terms()[i]->m_otherterm->net());
- }
- }
+ for (std::size_t i = 0; i < t->m_railstart; i++)
+ if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
+ t->m_nzrd.push_back(static_cast<unsigned>(other[i]));
- /* create a list of non zero elements. */
- for (unsigned k = 0; k < iN; k++)
- {
- terms_for_net_t * t = m_terms[k].get();
- /* pretty brutal */
- int *other = t->connected_net_idx();
-
- t->m_nz.clear();
-
- for (unsigned i = 0; i < t->m_railstart; i++)
- if (!plib::container::contains(t->m_nz, static_cast<unsigned>(other[i])))
- t->m_nz.push_back(static_cast<unsigned>(other[i]));
+ /* and sort */
+ std::sort(t->m_nzrd.begin(), t->m_nzrd.end());
+ }
- t->m_nz.push_back(k); // add diagonal
+ /* create a list of non zero elements below diagonal k
+ * This should reduce cache misses ...
+ */
- /* and sort */
- std::sort(t->m_nz.begin(), t->m_nz.end());
- }
+ std::vector<std::vector<bool>> touched(iN, std::vector<bool>(iN));
- /* create a list of non zero elements right of the diagonal
- * These list anticipate the population of array elements by
- * Gaussian elimination.
- */
- for (unsigned k = 0; k < iN; k++)
- {
- terms_for_net_t * t = m_terms[k].get();
- /* pretty brutal */
- int *other = t->connected_net_idx();
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ for (std::size_t j = 0; j < iN; j++)
+ touched[k][j] = false;
+ for (std::size_t j = 0; j < m_terms[k]->m_nz.size(); j++)
+ touched[k][m_terms[k]->m_nz[j]] = true;
+ }
- if (k==0)
- t->m_nzrd.clear();
- else
+ m_ops = 0;
+ for (unsigned k = 0; k < iN; k++)
{
- t->m_nzrd = m_terms[k-1]->m_nzrd;
- for (auto j = t->m_nzrd.begin(); j != t->m_nzrd.end(); )
+ m_ops++; // 1/A(k,k)
+ for (unsigned row = k + 1; row < iN; row++)
{
- if (*j < k + 1)
- j = t->m_nzrd.erase(j);
- else
- ++j;
+ if (touched[row][k])
+ {
+ m_ops++;
+ if (!plib::container::contains(m_terms[k]->m_nzbd, row))
+ m_terms[k]->m_nzbd.push_back(row);
+ for (std::size_t col = k + 1; col < iN; col++)
+ if (touched[k][col])
+ {
+ touched[row][col] = true;
+ m_ops += 2;
+ }
+ }
}
}
+ log().verbose("Number of mults/adds for {1}: {2}", name(), m_ops);
- for (unsigned i = 0; i < t->m_railstart; i++)
- if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
- t->m_nzrd.push_back(static_cast<unsigned>(other[i]));
+ if ((false))
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ pstring line = plib::pfmt("{1:3}")(k);
+ for (const auto & nzrd : m_terms[k]->m_nzrd)
+ line += plib::pfmt(" {1:3}")(nzrd);
+ log().verbose("{1}", line);
+ }
- /* and sort */
- std::sort(t->m_nzrd.begin(), t->m_nzrd.end());
- }
+ /*
+ * save states
+ */
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ pstring num = plib::pfmt("{1}")(k);
- /* create a list of non zero elements below diagonal k
- * This should reduce cache misses ...
- */
+ state().save(*this, m_terms[k]->m_last_V, this->name(), "lastV." + num);
+ state().save(*this, m_terms[k]->m_DD_n_m_1, this->name(), "m_DD_n_m_1." + num);
+ state().save(*this, m_terms[k]->m_h_n_m_1, this->name(), "m_h_n_m_1." + num);
- bool **touched = plib::palloc_array<bool *>(iN);
- for (unsigned k=0; k<iN; k++)
- touched[k] = plib::palloc_array<bool>(iN);
+ // FIXME: This shouldn't be necessary, recalculate on each entry ...
+ state().save(*this, m_gonn[k],"GO" + num, this->name(), m_terms[k]->count());
+ state().save(*this, m_gtn[k],"GT" + num, this->name(), m_terms[k]->count());
+ state().save(*this, m_Idrn[k],"IDR" + num, this->name(), m_terms[k]->count());
+ }
+ }
- for (unsigned k = 0; k < iN; k++)
+ void matrix_solver_t::update_inputs()
{
- for (unsigned j = 0; j < iN; j++)
- touched[k][j] = false;
- for (unsigned j = 0; j < m_terms[k]->m_nz.size(); j++)
- touched[k][m_terms[k]->m_nz[j]] = true;
+ // avoid recursive calls. Inputs are updated outside this call
+ for (auto &inp : m_inps)
+ inp->push(inp->proxied_net()->Q_Analog());
}
- m_ops = 0;
- for (unsigned k = 0; k < iN; k++)
+ void matrix_solver_t::update_dynamic()
{
- m_ops++; // 1/A(k,k)
- for (unsigned row = k + 1; row < iN; row++)
- {
- if (touched[row][k])
- {
- m_ops++;
- if (!plib::container::contains(m_terms[k]->m_nzbd, row))
- m_terms[k]->m_nzbd.push_back(row);
- for (unsigned col = k + 1; col < iN; col++)
- if (touched[k][col])
- {
- touched[row][col] = true;
- m_ops += 2;
- }
- }
- }
+ /* update all non-linear devices */
+ for (auto &dyn : m_dynamic_devices)
+ dyn->update_terminals();
}
- log().verbose("Number of mults/adds for {1}: {2}", name(), m_ops);
- if ((0))
- for (unsigned k = 0; k < iN; k++)
+ void matrix_solver_t::reset()
+ {
+ m_last_step = netlist_time::zero();
+ }
+
+ void matrix_solver_t::update() NL_NOEXCEPT
+ {
+ const netlist_time new_timestep = solve(exec().time());
+ update_inputs();
+
+ if (m_params.m_dynamic_ts && has_timestep_devices() && new_timestep > netlist_time::zero())
{
- pstring line = plib::pfmt("{1:3}")(k);
- for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++)
- line += plib::pfmt(" {1:3}")(m_terms[k]->m_nzrd[j]);
- log().verbose("{1}", line);
+ m_Q_sync.net().toggle_and_push_to_queue(new_timestep);
}
+ }
- /*
- * save states
+ /* update_forced is called from within param_update
+ *
+ * this should only occur outside of execution and thus
+ * using time should be safe.
+ *
*/
- for (unsigned k = 0; k < iN; k++)
+ void matrix_solver_t::update_forced()
{
- pstring num = plib::pfmt("{1}")(k);
+ const netlist_time new_timestep = solve(exec().time());
+ plib::unused_var(new_timestep);
- netlist().save(*this, m_terms[k]->m_last_V, "lastV." + num);
- netlist().save(*this, m_terms[k]->m_DD_n_m_1, "m_DD_n_m_1." + num);
- netlist().save(*this, m_terms[k]->m_h_n_m_1, "m_h_n_m_1." + num);
+ update_inputs();
- netlist().save(*this, m_terms[k]->go(),"GO" + num, m_terms[k]->count());
- netlist().save(*this, m_terms[k]->gt(),"GT" + num, m_terms[k]->count());
- netlist().save(*this, m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count());
+ if (m_params.m_dynamic_ts && has_timestep_devices())
+ {
+ m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_min_timestep));
+ }
}
- for (unsigned k=0; k<iN; k++)
- plib::pfree_array(touched[k]);
- plib::pfree_array(touched);
-}
+ void matrix_solver_t::step(const netlist_time &delta)
+ {
+ const nl_double dd = delta.as_double();
+ for (auto &d : m_step_devices)
+ d->timestep(dd);
+ }
-void matrix_solver_t::update_inputs()
-{
- // avoid recursive calls. Inputs are updated outside this call
- for (auto &inp : m_inps)
- inp->push(inp->m_proxied_net->Q_Analog());
-}
+ void matrix_solver_t::solve_base()
+ {
+ ++m_stat_vsolver_calls;
+ if (has_dynamic_devices())
+ {
+ std::size_t this_resched;
+ std::size_t newton_loops = 0;
+ do
+ {
+ update_dynamic();
+ // Gauss-Seidel will revert to Gaussian elemination if steps exceeded.
+ this_resched = this->vsolve_non_dynamic(true);
+ newton_loops++;
+ } while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
+
+ m_stat_newton_raphson += newton_loops;
+ // reschedule ....
+ if (this_resched > 1 && !m_Q_sync.net().is_queued())
+ {
+ log().warning(MW_1_NEWTON_LOOPS_EXCEEDED_ON_NET_1, this->name());
+ m_Q_sync.net().toggle_and_push_to_queue(m_params.m_nr_recalc_delay);
+ }
+ }
+ else
+ {
+ this->vsolve_non_dynamic(false);
+ }
+ }
-void matrix_solver_t::update_dynamic()
-{
- /* update all non-linear devices */
- for (auto &dyn : m_dynamic_devices)
- dyn->update_terminals();
-}
+ const netlist_time matrix_solver_t::solve(netlist_time now)
+ {
+ const netlist_time delta = now - m_last_step;
-void matrix_solver_t::reset()
-{
- m_last_step = netlist_time::zero();
-}
+ // We are already up to date. Avoid oscillations.
+ // FIXME: Make this a parameter!
+ if (delta < netlist_time::quantum())
+ return netlist_time::zero();
-void matrix_solver_t::update() NL_NOEXCEPT
-{
- const netlist_time new_timestep = solve();
- update_inputs();
+ /* update all terminals for new time step */
+ m_last_step = now;
+ step(delta);
+ solve_base();
+ const netlist_time next_time_step = compute_next_timestep(delta.as_double());
- if (m_params.m_dynamic_ts && has_timestep_devices() && new_timestep > netlist_time::zero())
- {
- m_Q_sync.net().toggle_and_push_to_queue(new_timestep);
+ return next_time_step;
}
-}
-
-void matrix_solver_t::update_forced()
-{
- ATTR_UNUSED const netlist_time new_timestep = solve();
- update_inputs();
- if (m_params.m_dynamic_ts && has_timestep_devices())
+ int matrix_solver_t::get_net_idx(detail::net_t *net)
{
- m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_min_timestep));
+ for (std::size_t k = 0; k < m_nets.size(); k++)
+ if (m_nets[k] == net)
+ return static_cast<int>(k);
+ return -1;
}
-}
-
-void matrix_solver_t::step(const netlist_time &delta)
-{
- const nl_double dd = delta.as_double();
- for (std::size_t k=0; k < m_step_devices.size(); k++)
- m_step_devices[k]->timestep(dd);
-}
-void matrix_solver_t::solve_base()
-{
- ++m_stat_vsolver_calls;
- if (has_dynamic_devices())
+ std::pair<int, int> matrix_solver_t::get_left_right_of_diag(std::size_t irow, std::size_t idiag)
{
- unsigned this_resched;
- unsigned newton_loops = 0;
- do
- {
- update_dynamic();
- // Gauss-Seidel will revert to Gaussian elemination if steps exceeded.
- this_resched = this->vsolve_non_dynamic(true);
- newton_loops++;
- } while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
-
- m_stat_newton_raphson += newton_loops;
- // reschedule ....
- if (this_resched > 1 && !m_Q_sync.net().is_queued())
- {
- log().warning(MW_1_NEWTON_LOOPS_EXCEEDED_ON_NET_1, this->name());
- m_Q_sync.net().toggle_and_push_to_queue(m_params.m_nr_recalc_delay);
- }
- }
- else
- {
- this->vsolve_non_dynamic(false);
- }
-}
+ /*
+ * return the maximum column left of the diagonal (-1 if no cols found)
+ * return the minimum column right of the diagonal (999999 if no cols found)
+ */
-const netlist_time matrix_solver_t::solve()
-{
- const netlist_time now = netlist().time();
- const netlist_time delta = now - m_last_step;
+ const auto row = static_cast<int>(irow);
+ const auto diag = static_cast<int>(idiag);
- // We are already up to date. Avoid oscillations.
- // FIXME: Make this a parameter!
- if (delta < netlist_time::quantum())
- return netlist_time::zero();
+ int colmax = -1;
+ int colmin = 999999;
- /* update all terminals for new time step */
- m_last_step = now;
- step(delta);
- solve_base();
- const netlist_time next_time_step = compute_next_timestep(delta.as_double());
+ auto &term = m_terms[irow];
- return next_time_step;
-}
+ for (std::size_t i = 0; i < term->count(); i++)
+ {
+ auto col = get_net_idx(&term->terms()[i]->connected_terminal()->net());
+ if (col != -1)
+ {
+ if (col==row) col = diag;
+ else if (col==diag) col = row;
-int matrix_solver_t::get_net_idx(detail::net_t *net)
-{
- for (std::size_t k = 0; k < m_nets.size(); k++)
- if (m_nets[k] == net)
- return static_cast<int>(k);
- return -1;
-}
+ if (col > diag && col < colmin)
+ colmin = col;
+ else if (col < diag && col > colmax)
+ colmax = col;
+ }
+ }
+ return {colmax, colmin};
+ }
-void matrix_solver_t::add_term(std::size_t k, terminal_t *term)
-{
- if (term->m_otherterm->net().isRailNet())
+ double matrix_solver_t::get_weight_around_diag(std::size_t row, std::size_t diag)
{
- m_rails_temp[k]->add(term, -1, false);
+ {
+ /*
+ * return average absolute distance
+ */
+
+ std::vector<bool> touched(1024, false); // FIXME!
+
+ double weight = 0.0;
+ auto &term = m_terms[row];
+ for (std::size_t i = 0; i < term->count(); i++)
+ {
+ auto col = get_net_idx(&term->terms()[i]->connected_terminal()->net());
+ if (col >= 0)
+ {
+ auto colu = static_cast<std::size_t>(col);
+ if (!touched[colu])
+ {
+ if (colu==row) colu = static_cast<unsigned>(diag);
+ else if (colu==diag) colu = static_cast<unsigned>(row);
+
+ weight = weight + std::abs(static_cast<double>(colu) - static_cast<double>(diag));
+ touched[colu] = true;
+ }
+ }
+ }
+ return weight; // / static_cast<double>(term->m_railstart);
+ }
}
- else
+
+ void matrix_solver_t::add_term(std::size_t k, terminal_t *term)
{
- int ot = get_net_idx(&term->m_otherterm->net());
- if (ot>=0)
+ if (term->connected_terminal()->net().isRailNet())
{
- m_terms[k]->add(term, ot, true);
+ m_rails_temp[k]->add(term, -1, false);
}
- /* Should this be allowed ? */
- else // if (ot<0)
+ else
{
- m_rails_temp[k]->add(term, ot, true);
- log().fatal(MF_1_FOUND_TERM_WITH_MISSING_OTHERNET, term->name());
+ int ot = get_net_idx(&term->connected_terminal()->net());
+ if (ot>=0)
+ {
+ m_terms[k]->add(term, ot, true);
+ }
+ /* Should this be allowed ? */
+ else // if (ot<0)
+ {
+ m_rails_temp[k]->add(term, ot, true);
+ log().fatal(MF_1_FOUND_TERM_WITH_MISSING_OTHERNET, term->name());
+ }
}
}
-}
-netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts)
-{
- nl_double new_solver_timestep = m_params.m_max_timestep;
-
- if (m_params.m_dynamic_ts)
+ netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts)
{
- for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++)
+ nl_double new_solver_timestep = m_params.m_max_timestep;
+
+ if (m_params.m_dynamic_ts)
{
- analog_net_t *n = m_nets[k];
- terms_for_net_t *t = m_terms[k].get();
+ for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++)
+ {
+ analog_net_t *n = m_nets[k];
+ terms_for_net_t *t = m_terms[k].get();
- const nl_double DD_n = (n->Q_Analog() - t->m_last_V);
- const nl_double hn = cur_ts;
+ const nl_double DD_n = (n->Q_Analog() - t->m_last_V);
+ const nl_double hn = cur_ts;
- //printf("%f %f %f %f\n", DD_n, t->m_DD_n_m_1, hn, t->m_h_n_m_1);
- nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1);
- nl_double new_net_timestep;
+ nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1);
+ nl_double new_net_timestep;
- t->m_h_n_m_1 = hn;
- t->m_DD_n_m_1 = DD_n;
- if (std::fabs(DD2) > NL_FCONST(1e-60)) // avoid div-by-zero
- new_net_timestep = std::sqrt(m_params.m_dynamic_lte / std::fabs(NL_FCONST(0.5)*DD2));
- else
- new_net_timestep = m_params.m_max_timestep;
+ t->m_h_n_m_1 = hn;
+ t->m_DD_n_m_1 = DD_n;
+ if (std::fabs(DD2) > plib::constants<nl_double>::cast(1e-60)) // avoid div-by-zero
+ new_net_timestep = std::sqrt(m_params.m_dynamic_lte / std::fabs(plib::constants<nl_double>::cast(0.5)*DD2));
+ else
+ new_net_timestep = m_params.m_max_timestep;
- if (new_net_timestep < new_solver_timestep)
- new_solver_timestep = new_net_timestep;
+ if (new_net_timestep < new_solver_timestep)
+ new_solver_timestep = new_net_timestep;
- t->m_last_V = n->Q_Analog();
- }
- if (new_solver_timestep < m_params.m_min_timestep)
- {
- //log().warning("Dynamic timestep below min timestep. Consider decreasing MIN_TIMESTEP: {1} us", new_solver_timestep*1.0e6);
- new_solver_timestep = m_params.m_min_timestep;
+ t->m_last_V = n->Q_Analog();
+ }
+ if (new_solver_timestep < m_params.m_min_timestep)
+ {
+ //log().warning("Dynamic timestep below min timestep. Consider decreasing MIN_TIMESTEP: {1} us", new_solver_timestep*1.0e6);
+ new_solver_timestep = m_params.m_min_timestep;
+ }
}
+ //if (new_solver_timestep > 10.0 * hn)
+ // new_solver_timestep = 10.0 * hn;
+ /*
+ * FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
+ */
+ return std::max(netlist_time::from_double(new_solver_timestep), netlist_time::quantum() * 2);
}
- //if (new_solver_timestep > 10.0 * hn)
- // new_solver_timestep = 10.0 * hn;
- /*
- * FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
- */
- return std::max(netlist_time::from_double(new_solver_timestep), netlist_time::quantum() * 2);
-}
-
-
-void matrix_solver_t::log_stats()
-{
- if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats)
+ void matrix_solver_t::log_stats()
{
- log().verbose("==============================================");
- log().verbose("Solver {1}", this->name());
- log().verbose(" ==> {1} nets", this->m_nets.size()); //, (*(*groups[i].first())->m_core_terms.first())->name());
- log().verbose(" has {1} elements", this->has_dynamic_devices() ? "dynamic" : "no dynamic");
- log().verbose(" has {1} elements", this->has_timestep_devices() ? "timestep" : "no timestep");
- log().verbose(" {1:6.3} average newton raphson loops",
- static_cast<double>(this->m_stat_newton_raphson) / static_cast<double>(this->m_stat_vsolver_calls));
- log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
- this->m_stat_calculations,
- static_cast<double>(this->m_stat_calculations) / this->netlist().time().as_double(),
- this->m_iterative_fail,
- 100.0 * static_cast<double>(this->m_iterative_fail)
- / static_cast<double>(this->m_stat_calculations),
- static_cast<double>(this->m_iterative_total) / static_cast<double>(this->m_stat_calculations));
+ if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats)
+ {
+ log().verbose("==============================================");
+ log().verbose("Solver {1}", this->name());
+ log().verbose(" ==> {1} nets", this->m_nets.size()); //, (*(*groups[i].first())->m_core_terms.first())->name());
+ log().verbose(" has {1} elements", this->has_dynamic_devices() ? "dynamic" : "no dynamic");
+ log().verbose(" has {1} elements", this->has_timestep_devices() ? "timestep" : "no timestep");
+ log().verbose(" {1:6.3} average newton raphson loops",
+ static_cast<double>(this->m_stat_newton_raphson) / static_cast<double>(this->m_stat_vsolver_calls));
+ log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
+ this->m_stat_calculations,
+ static_cast<double>(this->m_stat_calculations) / this->exec().time().as_double(),
+ this->m_iterative_fail,
+ 100.0 * static_cast<double>(this->m_iterative_fail)
+ / static_cast<double>(this->m_stat_calculations),
+ static_cast<double>(this->m_iterative_total) / static_cast<double>(this->m_stat_calculations));
+ }
}
-}
-
- } //namespace devices
+} // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h
index da44370d0d9..f76660e1cb9 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.h
+++ b/src/lib/netlist/solver/nld_matrix_solver.h
@@ -10,282 +10,367 @@
#include "netlist/nl_base.h"
#include "netlist/nl_errstr.h"
-#include "netlist/plib/putil.h"
+#include "plib/palloc.h"
+#include "plib/pmatrix2d.h"
+#include "plib/putil.h"
+#include "plib/vector_ops.h"
+
+#include <cmath>
namespace netlist
{
- namespace devices
- {
+namespace devices
+{
/* FIXME: these should become proper devices */
struct solver_parameters_t
{
- int m_pivot;
+ bool m_pivot;
nl_double m_accuracy;
nl_double m_dynamic_lte;
nl_double m_min_timestep;
nl_double m_max_timestep;
nl_double m_gs_sor;
bool m_dynamic_ts;
- unsigned m_gs_loops;
- unsigned m_nr_loops;
+ std::size_t m_gs_loops;
+ std::size_t m_nr_loops;
netlist_time m_nr_recalc_delay;
+ bool m_use_gabs;
+ bool m_use_linear_prediction;
bool m_log_stats;
};
-class terms_for_net_t : plib::nocopyassignmove
-{
-public:
- terms_for_net_t();
+ class terms_for_net_t : plib::nocopyassignmove
+ {
+ public:
+ terms_for_net_t();
- void clear();
+ void clear();
- void add(terminal_t *term, int net_other, bool sorted);
+ void add(terminal_t *term, int net_other, bool sorted);
- inline std::size_t count() const { return m_terms.size(); }
+ std::size_t count() const { return m_terms.size(); }
- inline terminal_t **terms() { return m_terms.data(); }
- inline int *connected_net_idx() { return m_connected_net_idx.data(); }
- inline nl_double *gt() { return m_gt.data(); }
- inline nl_double *go() { return m_go.data(); }
- inline nl_double *Idr() { return m_Idr.data(); }
- inline nl_double * const *connected_net_V() const { return m_connected_net_V.data(); }
+ terminal_t **terms() { return m_terms.data(); }
- void set_pointers();
+ std::size_t m_railstart;
- std::size_t m_railstart;
+ std::vector<unsigned> m_nz; /* all non zero for multiplication */
+ std::vector<unsigned> m_nzrd; /* non zero right of the diagonal for elimination, may include RHS element */
+ std::vector<unsigned> m_nzbd; /* non zero below of the diagonal for elimination */
- std::vector<unsigned> m_nz; /* all non zero for multiplication */
- std::vector<unsigned> m_nzrd; /* non zero right of the diagonal for elimination, may include RHS element */
- std::vector<unsigned> m_nzbd; /* non zero below of the diagonal for elimination */
+ /* state */
+ nl_double m_last_V;
+ nl_double m_DD_n_m_1;
+ nl_double m_h_n_m_1;
- /* state */
- nl_double m_last_V;
- nl_double m_DD_n_m_1;
- nl_double m_h_n_m_1;
+ std::vector<int> m_connected_net_idx;
+ private:
+ std::vector<terminal_t *> m_terms;
-private:
- std::vector<int> m_connected_net_idx;
- std::vector<nl_double> m_go;
- std::vector<nl_double> m_gt;
- std::vector<nl_double> m_Idr;
- std::vector<nl_double *> m_connected_net_V;
- std::vector<terminal_t *> m_terms;
+ };
-};
+ class proxied_analog_output_t : public analog_output_t
+ {
+ public:
-class proxied_analog_output_t : public analog_output_t
-{
-public:
+ proxied_analog_output_t(core_device_t &dev, const pstring &aname, analog_net_t *pnet)
+ : analog_output_t(dev, aname)
+ , m_proxied_net(pnet)
+ { }
- proxied_analog_output_t(core_device_t &dev, const pstring &aname)
- : analog_output_t(dev, aname)
- , m_proxied_net(nullptr)
- { }
- virtual ~proxied_analog_output_t();
+ analog_net_t *proxied_net() const { return m_proxied_net;}
+ private:
+ analog_net_t *m_proxied_net; // only for proxy nets in analog input logic
+ };
- analog_net_t *m_proxied_net; // only for proxy nets in analog input logic
-};
+ class matrix_solver_t : public device_t
+ {
+ public:
+ using list_t = std::vector<matrix_solver_t *>;
+ enum eSortType
+ {
+ NOSORT,
+ ASCENDING,
+ DESCENDING,
+ PREFER_IDENTITY_TOP_LEFT,
+ PREFER_BAND_MATRIX
+ };
+
+ void setup(analog_net_t::list_t &nets)
+ {
+ vsetup(nets);
+ }
-class matrix_solver_t : public device_t
-{
-public:
- using list_t = std::vector<matrix_solver_t *>;
+ void solve_base();
- enum eSortType
- {
- NOSORT,
- ASCENDING,
- DESCENDING
- };
+ /* after every call to solve, update inputs must be called.
+ * this can be done as well as a batch to ease parallel processing.
+ */
+ const netlist_time solve(netlist_time now);
+ void update_inputs();
- virtual ~matrix_solver_t() override;
+ bool has_dynamic_devices() const { return m_dynamic_devices.size() > 0; }
+ bool has_timestep_devices() const { return m_step_devices.size() > 0; }
- void setup(analog_net_t::list_t &nets)
- {
- vsetup(nets);
- }
+ void update_forced();
+ void update_after(const netlist_time after)
+ {
+ m_Q_sync.net().toggle_and_push_to_queue(after);
+ }
- void solve_base();
+ /* netdevice functions */
+ NETLIB_UPDATEI();
+ NETLIB_RESETI();
- /* after every call to solve, update inputs must be called.
- * this can be done as well as a batch to ease parallel processing.
- */
- const netlist_time solve();
- void update_inputs();
+ public:
+ int get_net_idx(detail::net_t *net);
+ std::pair<int, int> get_left_right_of_diag(std::size_t row, std::size_t diag);
+ double get_weight_around_diag(std::size_t row, std::size_t diag);
- inline bool has_dynamic_devices() const { return m_dynamic_devices.size() > 0; }
- inline bool has_timestep_devices() const { return m_step_devices.size() > 0; }
+ virtual void log_stats();
- void update_forced();
- void update_after(const netlist_time &after)
- {
- m_Q_sync.net().toggle_and_push_to_queue(after);
- }
+ virtual std::pair<pstring, pstring> create_solver_code()
+ {
+ return std::pair<pstring, pstring>("", plib::pfmt("/* solver doesn't support static compile */\n\n"));
+ }
- /* netdevice functions */
- NETLIB_UPDATEI();
- NETLIB_RESETI();
+ /* return number of floating point operations for solve */
+ std::size_t ops() { return m_ops; }
-public:
- int get_net_idx(detail::net_t *net);
+ protected:
- virtual void log_stats();
+ matrix_solver_t(netlist_state_t &anetlist, const pstring &name,
+ eSortType sort, const solver_parameters_t *params);
- virtual std::pair<pstring, pstring> create_solver_code()
- {
- return std::pair<pstring, pstring>("", plib::pfmt("/* solver doesn't support static compile */\n\n"));
- }
+ void sort_terms(eSortType sort);
- /* return number of floating point operations for solve */
- std::size_t ops() { return m_ops; }
+ void setup_base(analog_net_t::list_t &nets);
+ void update_dynamic();
-protected:
+ virtual void vsetup(analog_net_t::list_t &nets) = 0;
+ virtual unsigned vsolve_non_dynamic(const bool newton_raphson) = 0;
- matrix_solver_t(netlist_t &anetlist, const pstring &name,
- const eSortType sort, const solver_parameters_t *params);
+ netlist_time compute_next_timestep(const double cur_ts);
+ /* virtual */ void add_term(std::size_t net_idx, terminal_t *term);
- void setup_base(analog_net_t::list_t &nets);
- void update_dynamic();
+ template <typename T>
+ void store(const T & V);
- virtual void vsetup(analog_net_t::list_t &nets) = 0;
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) = 0;
+ template <typename T>
+ auto delta(const T & V) -> typename std::decay<decltype(V[0])>::type;
- netlist_time compute_next_timestep(const double cur_ts);
- /* virtual */ void add_term(std::size_t net_idx, terminal_t *term);
+ template <typename T>
+ void build_LE_A(T &child);
+ template <typename T>
+ void build_LE_RHS(T &child);
- template <typename T>
- void store(const T * RESTRICT V);
- template <typename T>
- T delta(const T * RESTRICT V);
+ void set_pointers()
+ {
+ const std::size_t iN = this->m_nets.size();
+
+ std::size_t max_count = 0;
+ std::size_t max_rail = 0;
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ max_count = std::max(max_count, m_terms[k]->count());
+ max_rail = std::max(max_rail, m_terms[k]->m_railstart);
+ }
+
+ m_mat_ptr.resize(iN, max_rail+1);
+ m_gtn.resize(iN, max_count);
+ m_gonn.resize(iN, max_count);
+ m_Idrn.resize(iN, max_count);
+ m_connected_net_Vn.resize(iN, max_count);
+
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ auto count = m_terms[k]->count();
+
+ for (std::size_t i = 0; i < count; i++)
+ {
+ m_terms[k]->terms()[i]->set_ptrs(&m_gtn[k][i], &m_gonn[k][i], &m_Idrn[k][i]);
+ m_connected_net_Vn[k][i] = m_terms[k]->terms()[i]->connected_terminal()->net().Q_Analog_state_ptr();
+ }
+ }
+ }
- template <typename T>
- void build_LE_A();
- template <typename T>
- void build_LE_RHS();
+ template <typename AP, typename FT>
+ void fill_matrix(std::size_t N, AP &tcr, FT &RHS)
+ {
+ for (std::size_t k = 0; k < N; k++)
+ {
+ auto *net = m_terms[k].get();
+ auto **tcr_r = &(tcr[k][0]);
+
+ const std::size_t term_count = net->count();
+ const std::size_t railstart = net->m_railstart;
+ const auto &go = m_gonn[k];
+ const auto &gt = m_gtn[k];
+ const auto &Idr = m_Idrn[k];
+ const auto &cnV = m_connected_net_Vn[k];
+
+ for (std::size_t i = 0; i < railstart; i++)
+ *tcr_r[i] += go[i];
+
+ typename FT::value_type gtot_t = 0.0;
+ typename FT::value_type RHS_t = 0.0;
+
+ for (std::size_t i = 0; i < term_count; i++)
+ {
+ gtot_t += gt[i];
+ RHS_t += Idr[i];
+ }
+ // FIXME: Code above is faster than vec_sum - Check this
+ #if 0
+ auto gtot_t = plib::vec_sum<FT>(term_count, m_gt);
+ auto RHS_t = plib::vec_sum<FT>(term_count, m_Idr);
+ #endif
+
+ for (std::size_t i = railstart; i < term_count; i++)
+ {
+ RHS_t += (/*m_Idr[i]*/ (- go[i]) * *cnV[i]);
+ }
+
+ RHS[k] = RHS_t;
+ // update diagonal element ...
+ *tcr_r[railstart] += gtot_t; //mat.A[mat.diag[k]] += gtot_t;
+ }
- std::vector<std::unique_ptr<terms_for_net_t>> m_terms;
- std::vector<analog_net_t *> m_nets;
- std::vector<std::unique_ptr<proxied_analog_output_t>> m_inps;
+ }
- std::vector<terms_for_net_t *> m_rails_temp;
+ template <typename T>
+ using aligned_alloc = plib::aligned_allocator<T, PALIGN_VECTOROPT>;
- const solver_parameters_t &m_params;
+ plib::pmatrix2d<nl_double, aligned_alloc<nl_double>> m_gonn;
+ plib::pmatrix2d<nl_double, aligned_alloc<nl_double>> m_gtn;
+ plib::pmatrix2d<nl_double, aligned_alloc<nl_double>> m_Idrn;
+ plib::pmatrix2d<nl_double *, aligned_alloc<nl_double *>> m_mat_ptr;
+ plib::pmatrix2d<nl_double *, aligned_alloc<nl_double *>> m_connected_net_Vn;
- state_var<int> m_stat_calculations;
- state_var<int> m_stat_newton_raphson;
- state_var<int> m_stat_vsolver_calls;
- state_var<int> m_iterative_fail;
- state_var<int> m_iterative_total;
+ plib::pmatrix2d<nl_double> m_test;
-private:
+ std::vector<plib::unique_ptr<terms_for_net_t>> m_terms;
+ std::vector<analog_net_t *> m_nets;
+ std::vector<pool_owned_ptr<proxied_analog_output_t>> m_inps;
- state_var<netlist_time> m_last_step;
- std::vector<core_device_t *> m_step_devices;
- std::vector<core_device_t *> m_dynamic_devices;
+ std::vector<plib::unique_ptr<terms_for_net_t>> m_rails_temp;
- logic_input_t m_fb_sync;
- logic_output_t m_Q_sync;
+ const solver_parameters_t &m_params;
- /* calculate matrix */
- void setup_matrix();
+ state_var<int> m_stat_calculations;
+ state_var<int> m_stat_newton_raphson;
+ state_var<int> m_stat_vsolver_calls;
+ state_var<int> m_iterative_fail;
+ state_var<int> m_iterative_total;
- void step(const netlist_time &delta);
+ private:
- std::size_t m_ops;
- const eSortType m_sort;
-};
+ state_var<netlist_time> m_last_step;
+ std::vector<core_device_t *> m_step_devices;
+ std::vector<core_device_t *> m_dynamic_devices;
-template <typename T>
-T matrix_solver_t::delta(const T * RESTRICT V)
-{
- /* NOTE: Ideally we should also include currents (RHS) here. This would
- * need a reevaluation of the right hand side after voltages have been updated
- * and thus belong into a different calculation. This applies to all solvers.
- */
-
- const std::size_t iN = this->m_terms.size();
- T cerr = 0;
- for (std::size_t i = 0; i < iN; i++)
- cerr = std::max(cerr, std::abs(V[i] - static_cast<T>(this->m_nets[i]->Q_Analog())));
- return cerr;
-}
-
-template <typename T>
-void matrix_solver_t::store(const T * RESTRICT V)
-{
- const std::size_t iN = this->m_terms.size();
- for (std::size_t i = 0; i < iN; i++)
- this->m_nets[i]->set_Q_Analog(V[i]);
-}
+ logic_input_t m_fb_sync;
+ logic_output_t m_Q_sync;
-template <typename T>
-void matrix_solver_t::build_LE_A()
-{
- static_assert(std::is_base_of<matrix_solver_t, T>::value, "T must derive from matrix_solver_t");
+ /* calculate matrix */
+ void setup_matrix();
- T &child = static_cast<T &>(*this);
+ void step(const netlist_time &delta);
- const std::size_t iN = child.N();
- for (std::size_t k = 0; k < iN; k++)
+ std::size_t m_ops;
+ const eSortType m_sort;
+ };
+
+ template <typename T>
+ auto matrix_solver_t::delta(const T & V) -> typename std::decay<decltype(V[0])>::type
{
- terms_for_net_t *terms = m_terms[k].get();
- nl_double * Ak = &child.A(k, 0);
+ /* NOTE: Ideally we should also include currents (RHS) here. This would
+ * need a reevaluation of the right hand side after voltages have been updated
+ * and thus belong into a different calculation. This applies to all solvers.
+ */
+
+ const std::size_t iN = this->m_terms.size();
+ typename std::decay<decltype(V[0])>::type cerr = 0;
+ for (std::size_t i = 0; i < iN; i++)
+ cerr = std::max(cerr, std::abs(V[i] - this->m_nets[i]->Q_Analog()));
+ return cerr;
+ }
- for (std::size_t i=0; i < iN; i++)
- Ak[i] = 0.0;
+ template <typename T>
+ void matrix_solver_t::store(const T & V)
+ {
+ const std::size_t iN = this->m_terms.size();
+ for (std::size_t i = 0; i < iN; i++)
+ this->m_nets[i]->set_Q_Analog(V[i]);
+ }
- const std::size_t terms_count = terms->count();
- const std::size_t railstart = terms->m_railstart;
- const nl_double * const RESTRICT gt = terms->gt();
+ template <typename T>
+ void matrix_solver_t::build_LE_A(T &child)
+ {
+ using float_type = typename T::float_type;
+ static_assert(std::is_base_of<matrix_solver_t, T>::value, "T must derive from matrix_solver_t");
+ const std::size_t iN = child.size();
+ for (std::size_t k = 0; k < iN; k++)
{
- nl_double akk = 0.0;
- for (std::size_t i = 0; i < terms_count; i++)
- akk += gt[i];
+ terms_for_net_t *terms = m_terms[k].get();
+ float_type * Ak = &child.A(k, 0ul);
- Ak[k] = akk;
- }
+ for (std::size_t i=0; i < iN; i++)
+ Ak[i] = 0.0;
- const nl_double * const RESTRICT go = terms->go();
- int * RESTRICT net_other = terms->connected_net_idx();
+ const std::size_t terms_count = terms->count();
+ const std::size_t railstart = terms->m_railstart;
+ const float_type * const gt = m_gtn[k];
- for (std::size_t i = 0; i < railstart; i++)
- Ak[net_other[i]] -= go[i];
- }
-}
+ {
+ float_type akk = 0.0;
+ for (std::size_t i = 0; i < terms_count; i++)
+ akk += gt[i];
-template <typename T>
-void matrix_solver_t::build_LE_RHS()
-{
- static_assert(std::is_base_of<matrix_solver_t, T>::value, "T must derive from matrix_solver_t");
- T &child = static_cast<T &>(*this);
+ Ak[k] = akk;
+ }
+
+ const float_type * const go = m_gonn[k];
+ int * net_other = terms->m_connected_net_idx.data();
+
+ for (std::size_t i = 0; i < railstart; i++)
+ Ak[net_other[i]] += go[i];
+ }
+ }
- const std::size_t iN = child.N();
- for (std::size_t k = 0; k < iN; k++)
+ template <typename T>
+ void matrix_solver_t::build_LE_RHS(T &child)
{
- nl_double rhsk_a = 0.0;
- nl_double rhsk_b = 0.0;
+ static_assert(std::is_base_of<matrix_solver_t, T>::value, "T must derive from matrix_solver_t");
+ using float_type = typename T::float_type;
- const std::size_t terms_count = m_terms[k]->count();
- const nl_double * const RESTRICT go = m_terms[k]->go();
- const nl_double * const RESTRICT Idr = m_terms[k]->Idr();
- const nl_double * const * RESTRICT other_cur_analog = m_terms[k]->connected_net_V();
+ const std::size_t iN = child.size();
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ float_type rhsk_a = 0.0;
+ float_type rhsk_b = 0.0;
- for (std::size_t i = 0; i < terms_count; i++)
- rhsk_a = rhsk_a + Idr[i];
+ const std::size_t terms_count = m_terms[k]->count();
+ const float_type * const go = m_gonn[k];
+ const float_type * const Idr = m_Idrn[k];
+ const float_type * const * other_cur_analog = m_connected_net_Vn[k];
- for (std::size_t i = m_terms[k]->m_railstart; i < terms_count; i++)
- //rhsk = rhsk + go[i] * terms[i]->m_otherterm->net().as_analog().Q_Analog();
- rhsk_b = rhsk_b + go[i] * *other_cur_analog[i];
+ for (std::size_t i = 0; i < terms_count; i++)
+ rhsk_a = rhsk_a + Idr[i];
+
+ for (std::size_t i = m_terms[k]->m_railstart; i < terms_count; i++)
+ //rhsk = rhsk + go[i] * terms[i]->m_otherterm->net().as_analog().Q_Analog();
+ rhsk_b = rhsk_b - go[i] * *other_cur_analog[i];
- child.RHS(k) = rhsk_a + rhsk_b;
+ child.RHS(k) = rhsk_a + rhsk_b;
+ }
}
-}
- } //namespace devices
+} //namespace devices
} // namespace netlist
#endif /* NLD_MS_DIRECT_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_direct.h b/src/lib/netlist/solver/nld_ms_direct.h
index f03cb738028..2501742218d 100644
--- a/src/lib/netlist/solver/nld_ms_direct.h
+++ b/src/lib/netlist/solver/nld_ms_direct.h
@@ -8,286 +8,228 @@
#ifndef NLD_MS_DIRECT_H_
#define NLD_MS_DIRECT_H_
-#include <algorithm>
-
-#include "nld_solver.h"
#include "nld_matrix_solver.h"
-#include "vector_base.h"
+#include "nld_solver.h"
+#include "plib/mat_cr.h"
+#include "plib/vector_ops.h"
-/* Disabling dynamic allocation gives a ~10% boost in performance
- * This flag has been added to support continuous storage for arrays
- * going forward in case we implement cuda solvers in the future.
- */
-#define NL_USE_DYNAMIC_ALLOCATION (1)
+#include <algorithm>
+#include <cmath>
namespace netlist
{
- namespace devices
- {
-//#define nl_ext_double _float128 // slow, very slow
-//#define nl_ext_double long double // slightly slower
-#define nl_ext_double nl_double
-
-
-template <std::size_t m_N, std::size_t storage_N>
-class matrix_solver_direct_t: public matrix_solver_t
+namespace devices
{
- friend class matrix_solver_t;
-public:
- matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size);
- matrix_solver_direct_t(netlist_t &anetlist, const pstring &name, const eSortType sort, const solver_parameters_t *params, const std::size_t size);
+ template <typename FT, int SIZE>
+ class matrix_solver_direct_t: public matrix_solver_t
+ {
+ friend class matrix_solver_t;
+ public:
- virtual ~matrix_solver_direct_t() override;
+ using float_type = FT;
- virtual void vsetup(analog_net_t::list_t &nets) override;
- virtual void reset() override { matrix_solver_t::reset(); }
+ matrix_solver_direct_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size);
+ matrix_solver_direct_t(netlist_state_t &anetlist, const pstring &name, const eSortType sort, const solver_parameters_t *params, const std::size_t size);
-protected:
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
- unsigned solve_non_dynamic(const bool newton_raphson);
+ void vsetup(analog_net_t::list_t &nets) override;
+ void reset() override { matrix_solver_t::reset(); }
- constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; }
+ protected:
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ unsigned solve_non_dynamic(const bool newton_raphson);
- void LE_solve();
+ constexpr std::size_t size() const { return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim; }
- template <typename T>
- void LE_back_subst(T * RESTRICT x);
-
-#if (NL_USE_DYNAMIC_ALLOCATION)
- template <typename T1, typename T2>
- nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r * m_pitch + c]; }
- template <typename T1>
- nl_ext_double &RHS(const T1 &r) { return m_A[r * m_pitch + N()]; }
-#else
- template <typename T1, typename T2>
- nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
- template <typename T1>
- nl_ext_double &RHS(const T1 &r) { return m_A[r][N()]; }
-#endif
- nl_double m_last_RHS[storage_N]; // right hand side - contains currents
-
-private:
- //static const std::size_t m_pitch = (((storage_N + 1) + 0) / 1) * 1;
- static constexpr std::size_t m_pitch = (((storage_N + 1) + 7) / 8) * 8;
- //static const std::size_t m_pitch = (((storage_N + 1) + 15) / 16) * 16;
- //static const std::size_t m_pitch = (((storage_N + 1) + 31) / 32) * 32;
-#if (NL_USE_DYNAMIC_ALLOCATION)
- //nl_ext_double * RESTRICT m_A;
- std::vector<nl_ext_double> m_A;
-#else
- nl_ext_double m_A[storage_N][m_pitch];
-#endif
- //nl_ext_double m_RHSx[storage_N];
-
- const std::size_t m_dim;
-
-};
-
-// ----------------------------------------------------------------------------------------
-// matrix_solver_direct
-// ----------------------------------------------------------------------------------------
-
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_direct_t<m_N, storage_N>::~matrix_solver_direct_t()
-{
-#if (NL_USE_DYNAMIC_ALLOCATION)
- //plib::pfree_array(m_A);
-#endif
-}
+ void LE_solve();
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
-{
- matrix_solver_t::setup_base(nets);
+ template <typename T>
+ void LE_back_subst(T & x);
- /* add RHS element */
- for (std::size_t k = 0; k < N(); k++)
- {
- terms_for_net_t * t = m_terms[k].get();
+ FT &A(std::size_t r, std::size_t c) { return m_A[r * m_pitch + c]; }
+ FT &RHS(std::size_t r) { return m_A[r * m_pitch + size()]; }
+ plib::parray<FT, SIZE> m_new_V;
- if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(N())))
- t->m_nzrd.push_back(static_cast<unsigned>(N()));
- }
+ private:
+ static constexpr const std::size_t SIZEABS = plib::parray<FT, SIZE>::SIZEABS();
+ static constexpr const std::size_t m_pitch_ABS = (((SIZEABS + 1) + 7) / 8) * 8;
- netlist().save(*this, m_last_RHS, "m_last_RHS");
+ const std::size_t m_dim;
+ const std::size_t m_pitch;
+ plib::parray<FT, SIZE * int(m_pitch_ABS)> m_A;
- for (std::size_t k = 0; k < N(); k++)
- netlist().save(*this, RHS(k), plib::pfmt("RHS.{1}")(k));
-}
+ };
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver_direct
+ // ----------------------------------------------------------------------------------------
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_direct_t<m_N, storage_N>::LE_solve()
-{
- const std::size_t kN = N();
- if (!m_params.m_pivot)
+ template <typename FT, int SIZE>
+ void matrix_solver_direct_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
{
- for (std::size_t i = 0; i < kN; i++)
- {
+ matrix_solver_t::setup_base(nets);
- /* FIXME: Singular matrix? */
- nl_double *Ai = &A(i, 0);
- const nl_double f = 1.0 / A(i,i);
- const auto &nzrd = m_terms[i]->m_nzrd;
- const auto &nzbd = m_terms[i]->m_nzbd;
+ /* add RHS element */
+ for (std::size_t k = 0; k < size(); k++)
+ {
+ terms_for_net_t * t = m_terms[k].get();
- for (std::size_t j : nzbd)
- {
- nl_double *Aj = &A(j, 0);
- const nl_double f1 = -f * Aj[i];
- for (std::size_t k : nzrd)
- Aj[k] += Ai[k] * f1;
- //RHS(j) += RHS(i) * f1;
- }
+ if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(size())))
+ t->m_nzrd.push_back(static_cast<unsigned>(size()));
}
+
+ // FIXME: This shouldn't be necessary ...
+ for (std::size_t k = 0; k < size(); k++)
+ state().save(*this, RHS(k), this->name(), plib::pfmt("RHS.{1}")(k));
}
- else
+
+ template <typename FT, int SIZE>
+ void matrix_solver_direct_t<FT, SIZE>::LE_solve()
{
- for (std::size_t i = 0; i < kN; i++)
+ const std::size_t kN = size();
+ if (!m_params.m_pivot)
{
- /* Find the row with the largest first value */
- std::size_t maxrow = i;
- for (std::size_t j = i + 1; j < kN; j++)
+ for (std::size_t i = 0; i < kN; i++)
{
- //if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i]))
- if (A(j,i) * A(j,i) > A(maxrow,i) * A(maxrow,i))
- maxrow = j;
- }
+ /* FIXME: Singular matrix? */
+ const FT f = 1.0 / A(i,i);
+ const auto &nzrd = m_terms[i]->m_nzrd;
+ const auto &nzbd = m_terms[i]->m_nzbd;
- if (maxrow != i)
- {
- /* Swap the maxrow and ith row */
- for (std::size_t k = 0; k < kN + 1; k++) {
- std::swap(A(i,k), A(maxrow,k));
+ for (std::size_t j : nzbd)
+ {
+ const FT f1 = -f * A(j, i);
+ for (std::size_t k : nzrd)
+ A(j, k) += A(i, k) * f1;
+ //RHS(j) += RHS(i) * f1;
}
- //std::swap(RHS(i), RHS(maxrow));
}
- /* FIXME: Singular matrix? */
- const nl_double f = 1.0 / A(i,i);
+ }
+ else
+ {
+ for (std::size_t i = 0; i < kN; i++)
+ {
+ /* Find the row with the largest first value */
+ std::size_t maxrow = i;
+ for (std::size_t j = i + 1; j < kN; j++)
+ {
+ //if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i]))
+ if (A(j,i) * A(j,i) > A(maxrow,i) * A(maxrow,i))
+ maxrow = j;
+ }
- /* Eliminate column i from row j */
+ if (maxrow != i)
+ {
+ /* Swap the maxrow and ith row */
+ for (std::size_t k = 0; k < kN + 1; k++) {
+ std::swap(A(i,k), A(maxrow,k));
+ }
+ //std::swap(RHS(i), RHS(maxrow));
+ }
+ /* FIXME: Singular matrix? */
+ const FT f = 1.0 / A(i,i);
- for (std::size_t j = i + 1; j < kN; j++)
- {
- const nl_double f1 = - A(j,i) * f;
- if (f1 != NL_FCONST(0.0))
+ /* Eliminate column i from row j */
+
+ for (std::size_t j = i + 1; j < kN; j++)
{
- const nl_double * RESTRICT pi = &A(i,i+1);
- nl_double * RESTRICT pj = &A(j,i+1);
-#if 1
- vec_add_mult_scalar_p(kN-i,pi,f1,pj);
-#else
- vec_add_mult_scalar_p(kN-i-1,pj,f1,pi);
- //for (unsigned k = i+1; k < kN; k++)
- // pj[k] = pj[k] + pi[k] * f1;
- //for (unsigned k = i+1; k < kN; k++)
- //A(j,k) += A(i,k) * f1;
- RHS(j) += RHS(i) * f1;
-#endif
+ const FT f1 = - A(j,i) * f;
+ if (f1 != plib::constants<FT>::zero())
+ {
+ const FT * pi = &A(i,i+1);
+ FT * pj = &A(j,i+1);
+ #if 1
+ plib::vec_add_mult_scalar_p(kN-i,pj, pi,f1);
+ #else
+ vec_add_mult_scalar_p1(kN-i-1,pj,pi,f1);
+ //for (unsigned k = i+1; k < kN; k++)
+ // pj[k] = pj[k] + pi[k] * f1;
+ //for (unsigned k = i+1; k < kN; k++)
+ //A(j,k) += A(i,k) * f1;
+ RHS(j) += RHS(i) * f1;
+ #endif
+ }
}
}
}
}
-}
-template <std::size_t m_N, std::size_t storage_N>
-template <typename T>
-void matrix_solver_direct_t<m_N, storage_N>::LE_back_subst(
- T * RESTRICT x)
-{
- const std::size_t kN = N();
-
- /* back substitution */
- if (m_params.m_pivot)
+ template <typename FT, int SIZE>
+ template <typename T>
+ void matrix_solver_direct_t<FT, SIZE>::LE_back_subst(
+ T & x)
{
- for (std::size_t j = kN; j-- > 0; )
+ const std::size_t kN = size();
+
+ /* back substitution */
+ if (m_params.m_pivot)
{
- T tmp = 0;
- for (std::size_t k = j+1; k < kN; k++)
- tmp += A(j,k) * x[k];
- x[j] = (RHS(j) - tmp) / A(j,j);
+ for (std::size_t j = kN; j-- > 0; )
+ {
+ FT tmp = 0;
+ for (std::size_t k = j+1; k < kN; k++)
+ tmp += A(j,k) * x[k];
+ x[j] = (RHS(j) - tmp) / A(j,j);
+ }
}
- }
- else
- {
- for (std::size_t j = kN; j-- > 0; )
+ else
{
- T tmp = 0;
-
- const auto *p = m_terms[j]->m_nzrd.data();
- const auto e = m_terms[j]->m_nzrd.size() - 1; /* exclude RHS element */
- T * Aj = &A(j,0);
- for (std::size_t k = 0; k < e; k++)
+ for (std::size_t j = kN; j-- > 0; )
{
- const auto pk = p[k];
- tmp += Aj[pk] * x[pk];
+ FT tmp = 0;
+ const auto &nzrd = m_terms[j]->m_nzrd;
+ const auto e = nzrd.size() - 1; /* exclude RHS element */
+ for ( std::size_t k = 0; k < e; k++)
+ tmp += A(j, nzrd[k]) * x[nzrd[k]];
+ x[j] = (RHS(j) - tmp) / A(j,j);
}
- x[j] = (RHS(j) - tmp) / A(j,j);
}
}
-}
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_direct_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphson)
+ {
+ this->LE_solve();
+ this->LE_back_subst(m_new_V);
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_direct_t<m_N, storage_N>::solve_non_dynamic(const bool newton_raphson)
-{
- nl_double new_V[storage_N]; // = { 0.0 };
-
- this->LE_solve();
- this->LE_back_subst(new_V);
-
- const nl_double err = (newton_raphson ? delta(new_V) : 0.0);
- store(new_V);
- return (err > this->m_params.m_accuracy) ? 2 : 1;
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-inline unsigned matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
-{
- build_LE_A<matrix_solver_direct_t>();
- build_LE_RHS<matrix_solver_direct_t>();
+ const FT err = (newton_raphson ? delta(m_new_V) : 0.0);
+ store(m_new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
+ }
- for (std::size_t i=0, iN=N(); i < iN; i++)
- m_last_RHS[i] = RHS(i);
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
+ {
+ this->build_LE_A(*this);
+ this->build_LE_RHS(*this);
- this->m_stat_calculations++;
- return this->solve_non_dynamic(newton_raphson);
-}
+ this->m_stat_calculations++;
+ return this->solve_non_dynamic(newton_raphson);
+ }
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(netlist_t &anetlist, const pstring &name,
- const solver_parameters_t *params, const std::size_t size)
-: matrix_solver_t(anetlist, name, ASCENDING, params)
-, m_dim(size)
-{
-#if (NL_USE_DYNAMIC_ALLOCATION)
- m_A.resize(N() * m_pitch);
- //m_A = plib::palloc_array<nl_ext_double>(N() * m_pitch);
-#endif
- for (unsigned k = 0; k < N(); k++)
+ template <typename FT, int SIZE>
+ matrix_solver_direct_t<FT, SIZE>::matrix_solver_direct_t(netlist_state_t &anetlist, const pstring &name,
+ const solver_parameters_t *params, const std::size_t size)
+ : matrix_solver_t(anetlist, name, ASCENDING, params)
+ , m_new_V(size)
+ , m_dim(size)
+ , m_pitch(m_pitch_ABS ? m_pitch_ABS : (((m_dim + 1) + 7) / 8) * 8)
+ , m_A(size * m_pitch)
{
- m_last_RHS[k] = 0.0;
}
-}
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(netlist_t &anetlist, const pstring &name,
- const eSortType sort, const solver_parameters_t *params, const std::size_t size)
-: matrix_solver_t(anetlist, name, sort, params)
-, m_dim(size)
-{
-#if (NL_USE_DYNAMIC_ALLOCATION)
- m_A.resize(N() * m_pitch);
- //m_A = plib::palloc_array<nl_ext_double>(N() * m_pitch);
-#endif
- for (unsigned k = 0; k < N(); k++)
+ template <typename FT, int SIZE>
+ matrix_solver_direct_t<FT, SIZE>::matrix_solver_direct_t(netlist_state_t &anetlist, const pstring &name,
+ const eSortType sort, const solver_parameters_t *params, const std::size_t size)
+ : matrix_solver_t(anetlist, name, sort, params)
+ , m_new_V(size)
+ , m_dim(size)
+ , m_pitch(m_pitch_ABS ? m_pitch_ABS : (((m_dim + 1) + 7) / 8) * 8)
+ , m_A(size * m_pitch)
{
- m_last_RHS[k] = 0.0;
}
-}
- } //namespace devices
+} // namespace devices
} // namespace netlist
#endif /* NLD_MS_DIRECT_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_direct1.h b/src/lib/netlist/solver/nld_ms_direct1.h
index 6e1f99bad7d..fbbb8ecb098 100644
--- a/src/lib/netlist/solver/nld_ms_direct1.h
+++ b/src/lib/netlist/solver/nld_ms_direct1.h
@@ -13,37 +13,41 @@
namespace netlist
{
- namespace devices
- {
-class matrix_solver_direct1_t: public matrix_solver_direct_t<1,1>
+namespace devices
{
-public:
+ template <typename FT>
+ class matrix_solver_direct1_t: public matrix_solver_direct_t<FT, 1>
+ {
+ public:
- matrix_solver_direct1_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params)
- : matrix_solver_direct_t<1, 1>(anetlist, name, params, 1)
- {}
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ using float_type = FT;
+ using base_type = matrix_solver_direct_t<FT, 1>;
-};
+ matrix_solver_direct1_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params)
+ : matrix_solver_direct_t<FT, 1>(anetlist, name, params, 1)
+ {}
-// ----------------------------------------------------------------------------------------
-// matrix_solver - Direct1
-// ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver - Direct1
+ // ----------------------------------------------------------------------------------------
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override
+ {
+ this->build_LE_A(*this);
+ this->build_LE_RHS(*this);
+ //NL_VERBOSE_OUT(("{1} {2}\n", new_val, m_RHS[0] / m_A[0][0]);
-inline unsigned matrix_solver_direct1_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
-{
- build_LE_A<matrix_solver_direct1_t>();
- build_LE_RHS<matrix_solver_direct1_t>();
- //NL_VERBOSE_OUT(("{1} {2}\n", new_val, m_RHS[0] / m_A[0][0]);
+ std::array<FT, 1> new_V = { this->RHS(0) / this->A(0,0) };
+
+ const FT err = (newton_raphson ? this->delta(new_V) : 0.0);
+ this->store(new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
+ }
+
+ };
- nl_double new_V[1] = { RHS(0) / A(0,0) };
- const nl_double err = (newton_raphson ? delta(new_V) : 0.0);
- store(new_V);
- return (err > this->m_params.m_accuracy) ? 2 : 1;
-}
- } //namespace devices
+} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/solver/nld_ms_direct2.h b/src/lib/netlist/solver/nld_ms_direct2.h
index 4004bce9cc4..01f77c3bc3c 100644
--- a/src/lib/netlist/solver/nld_ms_direct2.h
+++ b/src/lib/netlist/solver/nld_ms_direct2.h
@@ -13,43 +13,46 @@
namespace netlist
{
- namespace devices
- {
-class matrix_solver_direct2_t: public matrix_solver_direct_t<2,2>
+namespace devices
{
-public:
- matrix_solver_direct2_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params)
- : matrix_solver_direct_t<2, 2>(anetlist, name, params, 2)
- {}
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver - Direct2
+ // ----------------------------------------------------------------------------------------
+
+ template <typename FT>
+ class matrix_solver_direct2_t: public matrix_solver_direct_t<FT, 2>
+ {
+ public:
-};
+ using float_type = FT;
-// ----------------------------------------------------------------------------------------
-// matrix_solver - Direct2
-// ----------------------------------------------------------------------------------------
+ matrix_solver_direct2_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params)
+ : matrix_solver_direct_t<double, 2>(anetlist, name, params, 2)
+ {}
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override
+ {
+ this->build_LE_A(*this);
+ this->build_LE_RHS(*this);
-inline unsigned matrix_solver_direct2_t::vsolve_non_dynamic(ATTR_UNUSED const bool newton_raphson)
-{
- build_LE_A<matrix_solver_direct2_t>();
- build_LE_RHS<matrix_solver_direct2_t>();
+ const float_type a = this->A(0,0);
+ const float_type b = this->A(0,1);
+ const float_type c = this->A(1,0);
+ const float_type d = this->A(1,1);
- const nl_double a = A(0,0);
- const nl_double b = A(0,1);
- const nl_double c = A(1,0);
- const nl_double d = A(1,1);
+ const float_type v1 = (a * this->RHS(1) - c * this->RHS(0)) / (a * d - b * c);
+ const float_type v0 = (this->RHS(0) - b * v1) / a;
+ std::array<float_type, 2> new_V = {v0, v1};
- nl_double new_V[2];
- new_V[1] = (a * RHS(1) - c * RHS(0)) / (a * d - b * c);
- new_V[0] = (RHS(0) - b * new_V[1]) / a;
+ this->m_stat_calculations++;
+ const float_type err = (newton_raphson ? this->delta(new_V) : 0.0);
+ this->store(new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
+ }
- const nl_double err = (newton_raphson ? delta(new_V) : 0.0);
- store(new_V);
- return (err > this->m_params.m_accuracy) ? 2 : 1;
-}
+ };
- } //namespace devices
+} //namespace devices
} // namespace netlist
#endif /* NLD_MS_DIRECT2_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_direct_lu.h b/src/lib/netlist/solver/nld_ms_direct_lu.h
index c379cf8d055..e7cedc1dd29 100644
--- a/src/lib/netlist/solver/nld_ms_direct_lu.h
+++ b/src/lib/netlist/solver/nld_ms_direct_lu.h
@@ -8,11 +8,11 @@
#ifndef NLD_MS_DIRECT_H_
#define NLD_MS_DIRECT_H_
-#include <algorithm>
-
#include "solver/nld_solver.h"
#include "solver/nld_matrix_solver.h"
+#include <algorithm>
+
//#define A(r, c) m_A[_r][_c]
namespace netlist
@@ -36,9 +36,9 @@ public:
virtual void vsetup(analog_net_t::list_t &nets) override;
virtual void reset() override { matrix_solver_t::reset(); }
- inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
+ unsigned N() const { if (m_N == 0) return m_dim; else return m_N; }
- inline int vsolve_non_dynamic(const bool newton_raphson);
+ int vsolve_non_dynamic(const bool newton_raphson);
protected:
virtual void add_term(int net_idx, terminal_t *term) override;
@@ -139,12 +139,10 @@ protected:
nl_double compute_next_timestep();
template <typename T1, typename T2>
- inline nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; }
+ nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; }
//nl_double m_A[storage_N][((storage_N + 7) / 8) * 8];
nl_double m_RHS[storage_N];
- nl_double m_last_RHS[storage_N]; // right hand side - contains currents
- nl_double m_last_V[storage_N];
terms_for_net_t *m_rails_temp;
@@ -355,7 +353,6 @@ void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
* save states
*/
save(NLNAME(m_RHS));
- save(NLNAME(m_last_RHS));
save(NLNAME(m_last_V));
for (unsigned k = 0; k < N(); k++)
@@ -590,13 +587,10 @@ unsigned matrix_solver_direct_t<m_N, storage_N>::solve_non_dynamic(const bool ne
}
template <unsigned m_N, unsigned storage_N>
-inline int matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+int matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
{
this->build_LE_A();
- this->build_LE_RHS(m_last_RHS);
-
- for (unsigned i=0, iN=N(); i < iN; i++)
- m_RHS[i] = m_last_RHS[i];
+ this->build_LE_RHS(m_RHS);
return this->solve_non_dynamic(newton_raphson);
}
@@ -608,11 +602,6 @@ matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(const solver_para
, m_lp_fact(0)
{
m_rails_temp = palloc_array(terms_for_net_t, N());
-
- for (unsigned k = 0; k < N(); k++)
- {
- m_last_RHS[k] = 0.0;
- }
}
template <unsigned m_N, unsigned storage_N>
@@ -626,7 +615,6 @@ matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(const eSolverType
for (unsigned k = 0; k < N(); k++)
{
m_terms[k] = palloc(terms_for_net_t);
- m_last_RHS[k] = 0.0;
}
}
diff --git a/src/lib/netlist/solver/nld_ms_gcr.h b/src/lib/netlist/solver/nld_ms_gcr.h
index a17ca1ec282..f3e56a342d6 100644
--- a/src/lib/netlist/solver/nld_ms_gcr.h
+++ b/src/lib/netlist/solver/nld_ms_gcr.h
@@ -10,390 +10,201 @@
#ifndef NLD_MS_GCR_H_
#define NLD_MS_GCR_H_
-#include <algorithm>
+#include "plib/mat_cr.h"
-#include "../plib/pdynlib.h"
-#include "mat_cr.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"
-#include "vector_base.h"
-#include "../plib/pstream.h"
+#include "plib/pdynlib.h"
+#include "plib/pstream.h"
+#include "plib/vector_ops.h"
+
+#include <algorithm>
namespace netlist
{
- namespace devices
- {
-template <std::size_t m_N, std::size_t storage_N>
-class matrix_solver_GCR_t: public matrix_solver_t
+namespace devices
{
-public:
-
- matrix_solver_GCR_t(netlist_t &anetlist, const pstring &name,
- const solver_parameters_t *params, const std::size_t size)
- : matrix_solver_t(anetlist, name, matrix_solver_t::ASCENDING, params)
- , m_dim(size)
- , mat(size)
- , m_proc()
- {
- }
- virtual ~matrix_solver_GCR_t() override
+ template <typename FT, int SIZE>
+ class matrix_solver_GCR_t: public matrix_solver_t
{
- }
-
- constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; }
-
- virtual void vsetup(analog_net_t::list_t &nets) override;
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ public:
+
+ using mat_type = plib::matrix_compressed_rows_t<FT, SIZE>;
+ // FIXME: dirty hack to make this compile
+ static constexpr const std::size_t storage_N = 100;
+
+ matrix_solver_GCR_t(netlist_state_t &anetlist, const pstring &name,
+ const solver_parameters_t *params, const std::size_t size)
+ : matrix_solver_t(anetlist, name, matrix_solver_t::PREFER_IDENTITY_TOP_LEFT, params)
+ , m_dim(size)
+ , RHS(size)
+ , new_V(size)
+ , mat(static_cast<typename mat_type::index_type>(size))
+ , m_proc()
+ {
+ }
- virtual std::pair<pstring, pstring> create_solver_code() override;
+ constexpr std::size_t N() const { return m_dim; }
-private:
+ void vsetup(analog_net_t::list_t &nets) override;
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
- //typedef typename mat_cr_t<storage_N>::type mattype;
- typedef typename mat_cr_t<storage_N>::index_type mattype;
+ std::pair<pstring, pstring> create_solver_code() override;
- void csc_private(plib::putf8_fmt_writer &strm);
+ private:
- using extsolver = void (*)(double * RESTRICT m_A, double * RESTRICT RHS, double * RESTRICT V);
+ using mat_index_type = typename plib::matrix_compressed_rows_t<FT, SIZE>::index_type;
- pstring static_compile_name();
+ void csc_private(plib::putf8_fmt_writer &strm);
- const std::size_t m_dim;
- std::vector<unsigned> m_term_cr[storage_N];
- mat_cr_t<storage_N> mat;
+ using extsolver = void (*)(double * m_A, double * RHS, double * V);
- //extsolver m_proc;
- plib::dynproc<void, double * RESTRICT, double * RESTRICT, double * RESTRICT> m_proc;
+ pstring static_compile_name();
-};
+ const std::size_t m_dim;
+ plib::parray<FT, SIZE> RHS;
+ plib::parray<FT, SIZE> new_V;
-// ----------------------------------------------------------------------------------------
-// matrix_solver - GCR
-// ----------------------------------------------------------------------------------------
+ mat_type mat;
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_GCR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
-{
- setup_base(nets);
+ //extsolver m_proc;
+ plib::dynproc<void, double * , double * , double * > m_proc;
- mattype nz = 0;
- const std::size_t iN = this->N();
+ };
- /* build the final matrix */
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver - GCR
+ // ----------------------------------------------------------------------------------------
- bool touched[storage_N][storage_N] = { { false } };
- for (std::size_t k = 0; k < iN; k++)
+ // FIXME: namespace or static class member
+ template <typename V>
+ std::size_t inline get_level(const V &v, std::size_t k)
{
- for (auto &j : this->m_terms[k]->m_nz)
- touched[k][j] = true;
+ for (std::size_t i = 0; i < v.size(); i++)
+ if (plib::container::contains(v[i], k))
+ return i;
+ throw plib::pexception("Error in get_level");
}
- unsigned fc = 0;
+ template <typename FT, int SIZE>
+ void matrix_solver_GCR_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
+ {
+ setup_base(nets);
- unsigned ops = 0;
+ const std::size_t iN = this->N();
- for (std::size_t k = 0; k < iN; k++)
- {
- ops++; // 1/A(k,k)
- for (std::size_t row = k + 1; row < iN; row++)
- {
- if (touched[row][k])
- {
- ops++;
- fc++;
- for (std::size_t col = k + 1; col < iN; col++)
- if (touched[k][col])
- {
- touched[row][col] = true;
- ops += 2;
- }
- }
- }
- }
+ /* build the final matrix */
+ std::vector<std::vector<unsigned>> fill(iN);
- for (mattype k=0; k<iN; k++)
- {
- mat.ia[k] = nz;
+ std::size_t raw_elements = 0;
- for (mattype j=0; j<iN; j++)
+ for (std::size_t k = 0; k < iN; k++)
{
- if (touched[k][j])
+ fill[k].resize(iN, decltype(mat)::FILL_INFINITY);
+ for (auto &j : this->m_terms[k]->m_nz)
{
- mat.ja[nz] = j;
- if (j == k)
- mat.diag[k] = nz;
- nz++;
+ fill[k][j] = 0;
+ raw_elements++;
}
- }
- m_term_cr[k].clear();
- /* build pointers into the compressed row format matrix for each terminal */
- for (std::size_t j=0; j< this->m_terms[k]->m_railstart;j++)
- {
- int other = this->m_terms[k]->connected_net_idx()[j];
- for (auto i = mat.ia[k]; i < nz; i++)
- if (other == static_cast<int>(mat.ja[i]))
- {
- m_term_cr[k].push_back(i);
- break;
- }
}
- nl_assert(m_term_cr[k].size() == this->m_terms[k]->m_railstart);
- }
- mat.ia[iN] = nz;
- mat.nz_num = nz;
+ auto gr = mat.gaussian_extend_fill_mat(fill);
- this->log().verbose("Ops: {1} Occupancy ratio: {2}\n", ops,
- static_cast<double>(nz) / static_cast<double>(iN * iN));
-
- // FIXME: Move me
-
- if (netlist().lib().isLoaded())
- {
- pstring symname = static_compile_name();
-#if 0
- m_proc = this->netlist().lib().template getsym<extsolver>(symname);
- if (m_proc != nullptr)
- this->log().verbose("External static solver {1} found ...", symname);
- else
- this->log().warning("External static solver {1} not found ...", symname);
-#else
- m_proc.load(this->netlist().lib(), symname);
- if (m_proc.resolved())
- this->log().warning("External static solver {1} found ...", symname);
- else
- this->log().warning("External static solver {1} not found ...", symname);
-#endif
- }
+ /* FIXME: move this to the cr matrix class and use computed
+ * parallel ordering once it makes sense.
+ */
-}
-#if 0
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_GCR_t<m_N, storage_N>::csc_private(plib::putf8_fmt_writer &strm)
-{
- const std::size_t iN = N();
- for (std::size_t i = 0; i < iN - 1; i++)
- {
- const auto &nzbd = this->m_terms[i]->m_nzbd;
+ std::vector<unsigned> levL(iN, 0);
+ std::vector<unsigned> levU(iN, 0);
- if (nzbd.size() > 0)
+ // parallel scheme for L x = y
+ for (std::size_t k = 0; k < iN; k++)
{
- std::size_t pi = mat.diag[i];
-
- //const nl_double f = 1.0 / m_A[pi++];
- strm("const double f{1} = 1.0 / m_A[{2}];\n", i, pi);
- pi++;
- const std::size_t piie = mat.ia[i+1];
-
- //for (auto & j : nzbd)
- for (std::size_t j : nzbd)
- {
- // proceed to column i
- std::size_t pj = mat.ia[j];
-
- while (mat.ja[pj] < i)
- pj++;
-
- //const nl_double f1 = - m_A[pj++] * f;
- strm("\tconst double f{1}_{2} = -f{3} * m_A[{4}];\n", i, j, i, pj);
- pj++;
-
- // subtract row i from j */
- for (std::size_t pii = pi; pii<piie; )
- {
- while (mat.ja[pj] < mat.ja[pii])
- pj++;
- //m_A[pj++] += m_A[pii++] * f1;
- strm("\tm_A[{1}] += m_A[{2}] * f{3}_{4};\n", pj, pii, i, j);
- pj++; pii++;
- }
- //RHS[j] += f1 * RHS[i];
- strm("\tRHS[{1}] += f{2}_{3} * RHS[{4}];\n", j, i, j, i);
- }
+ unsigned lm=0;
+ for (std::size_t j = 0; j<k; j++)
+ if (fill[k][j] < decltype(mat)::FILL_INFINITY)
+ lm = std::max(lm, levL[j]);
+ levL[k] = 1+lm;
}
- }
- //new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]];
- strm("\tV[{1}] = RHS[{2}] / m_A[{3}];\n", iN - 1, iN - 1, mat.diag[iN - 1]);
- for (std::size_t j = iN - 1; j-- > 0;)
- {
- strm("\tdouble tmp{1} = 0.0;\n", j);
- const std::size_t e = mat.ia[j+1];
- for (std::size_t pk = mat.diag[j] + 1; pk < e; pk++)
+ // parallel scheme for U x = y
+ for (std::size_t k = iN; k-- > 0; )
{
- strm("\ttmp{1} += m_A[{2}] * V[{3}];\n", j, pk, mat.ja[pk]);
+ unsigned lm=0;
+ for (std::size_t j = iN; --j > k; )
+ if (fill[k][j] < decltype(mat)::FILL_INFINITY)
+ lm = std::max(lm, levU[j]);
+ levU[k] = 1+lm;
}
- strm("\tV[{1}] = (RHS[{1}] - tmp{1}) / m_A[{4}];\n", j, j, j, mat.diag[j]);
- }
-}
-#else
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_GCR_t<m_N, storage_N>::csc_private(plib::putf8_fmt_writer &strm)
-{
- const std::size_t iN = N();
- for (std::size_t i = 0; i < mat.nz_num; i++)
- strm("double m_A{1} = m_A[{2}];\n", i, i);
- for (std::size_t i = 0; i < iN - 1; i++)
- {
- const auto &nzbd = this->m_terms[i]->m_nzbd;
-
- if (nzbd.size() > 0)
+ for (std::size_t k = 0; k < iN; k++)
{
- std::size_t pi = mat.diag[i];
-
- //const nl_double f = 1.0 / m_A[pi++];
- strm("const double f{1} = 1.0 / m_A{2};\n", i, pi);
- pi++;
- const std::size_t piie = mat.ia[i+1];
-
- //for (auto & j : nzbd)
- for (std::size_t j : nzbd)
+ unsigned fm = 0;
+ pstring ml = "";
+ for (std::size_t j = 0; j < iN; j++)
{
- // proceed to column i
- std::size_t pj = mat.ia[j];
-
- while (mat.ja[pj] < i)
- pj++;
-
- //const nl_double f1 = - m_A[pj++] * f;
- strm("\tconst double f{1}_{2} = -f{3} * m_A{4};\n", i, j, i, pj);
- pj++;
-
- // subtract row i from j */
- for (std::size_t pii = pi; pii<piie; )
- {
- while (mat.ja[pj] < mat.ja[pii])
- pj++;
- //m_A[pj++] += m_A[pii++] * f1;
- strm("\tm_A{1} += m_A{2} * f{3}_{4};\n", pj, pii, i, j);
- pj++; pii++;
- }
- //RHS[j] += f1 * RHS[i];
- strm("\tRHS[{1}] += f{2}_{3} * RHS[{4}];\n", j, i, j, i);
+ ml += fill[k][j] == 0 ? "X" : fill[k][j] < decltype(mat)::FILL_INFINITY ? "+" : ".";
+ if (fill[k][j] < decltype(mat)::FILL_INFINITY)
+ if (fill[k][j] > fm)
+ fm = fill[k][j];
}
+ this->log().verbose("{1:4} {2} {3:4} {4:4} {5:4} {6:4}", k, ml, levL[k], levU[k], get_level(mat.m_ge_par, k), fm);
}
- }
-
- //new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]];
- strm("\tV[{1}] = RHS[{2}] / m_A{3};\n", iN - 1, iN - 1, mat.diag[iN - 1]);
- for (std::size_t j = iN - 1; j-- > 0;)
- {
- strm("\tdouble tmp{1} = 0.0;\n", j);
- const std::size_t e = mat.ia[j+1];
- for (std::size_t pk = mat.diag[j] + 1; pk < e; pk++)
- {
- strm("\ttmp{1} += m_A{2} * V[{3}];\n", j, pk, mat.ja[pk]);
- }
- strm("\tV[{1}] = (RHS[{1}] - tmp{1}) / m_A{4};\n", j, j, j, mat.diag[j]);
- }
-}
-#endif
-
-template <std::size_t m_N, std::size_t storage_N>
-pstring matrix_solver_GCR_t<m_N, storage_N>::static_compile_name()
-{
- plib::postringstream t;
- plib::putf8_fmt_writer w(t);
- csc_private(w);
- std::hash<pstring> h;
-
- return plib::pfmt("nl_gcr_{1:x}_{2}")(h( t.str() ))(mat.nz_num);
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-std::pair<pstring, pstring> matrix_solver_GCR_t<m_N, storage_N>::create_solver_code()
-{
- plib::postringstream t;
- plib::putf8_fmt_writer strm(t);
- pstring name = static_compile_name();
-
- strm.writeline(plib::pfmt("extern \"C\" void {1}(double * __restrict m_A, double * __restrict RHS, double * __restrict V)\n")(name));
- strm.writeline("{\n");
- csc_private(strm);
- strm.writeline("}\n");
- return std::pair<pstring, pstring>(name, t.str());
-}
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_GCR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
-{
- const std::size_t iN = this->N();
-
- nl_double RHS[storage_N];
- nl_double new_V[storage_N];
+ mat.build_from_fill_mat(fill);
- mat.set_scalar(0.0);
-
- for (std::size_t k = 0; k < iN; k++)
- {
- terms_for_net_t *t = this->m_terms[k].get();
- nl_double gtot_t = 0.0;
- nl_double RHS_t = 0.0;
-
- const std::size_t term_count = t->count();
- const std::size_t railstart = t->m_railstart;
- const nl_double * const RESTRICT gt = t->gt();
- const nl_double * const RESTRICT go = t->go();
- const nl_double * const RESTRICT Idr = t->Idr();
- const nl_double * const * RESTRICT other_cur_analog = t->connected_net_V();
- const unsigned * const RESTRICT tcr = m_term_cr[k].data();
-
-#if 0
- for (std::size_t i = 0; i < term_count; i++)
+ for (mat_index_type k=0; k<iN; k++)
{
- gtot_t += gt[i];
- RHS_t += Idr[i];
+ std::size_t cnt(0);
+ /* build pointers into the compressed row format matrix for each terminal */
+ for (std::size_t j=0; j< this->m_terms[k]->m_railstart;j++)
+ {
+ int other = this->m_terms[k]->m_connected_net_idx[j];
+ for (auto i = mat.row_idx[k]; i < mat.row_idx[k+1]; i++)
+ if (other == static_cast<int>(mat.col_idx[i]))
+ {
+ m_mat_ptr[k][j] = &mat.A[i];
+ cnt++;
+ break;
+ }
+ }
+ nl_assert(cnt == this->m_terms[k]->m_railstart);
+ m_mat_ptr[k][this->m_terms[k]->m_railstart] = &mat.A[mat.diag[k]];
}
- for (std::size_t i = railstart; i < term_count; i++)
- RHS_t += go[i] * *other_cur_analog[i];
+ this->log().verbose("maximum fill: {1}", gr.first);
+ this->log().verbose("Post elimination occupancy ratio: {2} Ops: {1}", gr.second,
+ static_cast<double>(mat.nz_num) / static_cast<double>(iN * iN));
+ this->log().verbose(" Pre elimination occupancy ratio: {2}",
+ static_cast<double>(raw_elements) / static_cast<double>(iN * iN));
- RHS[k] = RHS_t;
+ // FIXME: Move me
- // add diagonal element
- mat.A[mat.diag[k]] = gtot_t;
-
- for (std::size_t i = 0; i < railstart; i++)
- mat.A[tcr[i]] -= go[i];
- }
-#else
- for (std::size_t i = 0; i < railstart; i++)
- mat.A[tcr[i]] -= go[i];
-
- for (std::size_t i = 0; i < railstart; i++)
+ if (state().lib().isLoaded())
{
- gtot_t += gt[i];
- RHS_t += Idr[i];
+ pstring symname = static_compile_name();
+ m_proc.load(this->state().lib(), symname);
+ if (m_proc.resolved())
+ this->log().warning("External static solver {1} found ...", symname);
+ else
+ this->log().warning("External static solver {1} not found ...", symname);
}
- for (std::size_t i = railstart; i < term_count; i++)
- {
- RHS_t += (Idr[i] + go[i] * *other_cur_analog[i]);
- gtot_t += gt[i];
- }
-
- RHS[k] = RHS_t;
- mat.A[mat.diag[k]] += gtot_t;
}
-#endif
- mat.ia[iN] = static_cast<mattype>(mat.nz_num);
-
- /* now solve it */
- //if (m_proc != nullptr)
- if (m_proc.resolved())
- {
- //static_solver(m_A, RHS);
- m_proc(&mat.A[0], &RHS[0], &new_V[0]);
- }
- else
+ template <typename FT, int SIZE>
+ void matrix_solver_GCR_t<FT, SIZE>::csc_private(plib::putf8_fmt_writer &strm)
{
+ const std::size_t iN = N();
+
+ for (std::size_t i = 0; i < mat.nz_num; i++)
+ strm("double m_A{1} = m_A[{2}];\n", i, i);
+
for (std::size_t i = 0; i < iN - 1; i++)
{
const auto &nzbd = this->m_terms[i]->m_nzbd;
@@ -401,61 +212,114 @@ unsigned matrix_solver_GCR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt
if (nzbd.size() > 0)
{
std::size_t pi = mat.diag[i];
- const nl_double f = 1.0 / mat.A[pi++];
- const std::size_t piie = mat.ia[i+1];
- for (std::size_t j : nzbd) // for (std::size_t j = i + 1; j < iN; j++)
+ //const FT f = 1.0 / m_A[pi++];
+ strm("const double f{1} = 1.0 / m_A{2};\n", i, pi);
+ pi++;
+ const std::size_t piie = mat.row_idx[i+1];
+
+ //for (auto & j : nzbd)
+ for (std::size_t j : nzbd)
{
// proceed to column i
- //__builtin_prefetch(&m_A[mat.diag[j+1]], 1);
- std::size_t pj = mat.ia[j];
+ std::size_t pj = mat.row_idx[j];
- while (mat.ja[pj] < i)
+ while (mat.col_idx[pj] < i)
pj++;
- const nl_double f1 = - mat.A[pj++] * f;
+ //const FT f1 = - m_A[pj++] * f;
+ strm("\tconst double f{1}_{2} = -f{3} * m_A{4};\n", i, j, i, pj);
+ pj++;
// subtract row i from j */
for (std::size_t pii = pi; pii<piie; )
{
- while (mat.ja[pj] < mat.ja[pii])
+ while (mat.col_idx[pj] < mat.col_idx[pii])
pj++;
- mat.A[pj++] += mat.A[pii++] * f1;
+ //m_A[pj++] += m_A[pii++] * f1;
+ strm("\tm_A{1} += m_A{2} * f{3}_{4};\n", pj, pii, i, j);
+ pj++; pii++;
}
- RHS[j] += f1 * RHS[i];
+ //RHS[j] += f1 * RHS[i];
+ strm("\tRHS[{1}] += f{2}_{3} * RHS[{4}];\n", j, i, j, i);
}
}
}
- /* backward substitution
- *
- */
-
- /* row n-1 */
- new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]];
+ //new_V[iN - 1] = RHS[iN - 1] / mat.A[mat.diag[iN - 1]];
+ strm("\tV[{1}] = RHS[{2}] / m_A{3};\n", iN - 1, iN - 1, mat.diag[iN - 1]);
for (std::size_t j = iN - 1; j-- > 0;)
{
- //__builtin_prefetch(&new_V[j-1], 1);
- //if (j>0)__builtin_prefetch(&m_A[mat.diag[j-1]], 0);
- double tmp = 0;
- auto jdiag = mat.diag[j];
- const std::size_t e = mat.ia[j+1];
- for (std::size_t pk = jdiag + 1; pk < e; pk++)
+ strm("\tdouble tmp{1} = 0.0;\n", j);
+ const std::size_t e = mat.row_idx[j+1];
+ for (std::size_t pk = mat.diag[j] + 1; pk < e; pk++)
{
- tmp += mat.A[pk] * new_V[mat.ja[pk]];
+ strm("\ttmp{1} += m_A{2} * V[{3}];\n", j, pk, mat.col_idx[pk]);
}
- new_V[j] = (RHS[j] - tmp) / mat.A[jdiag];
+ strm("\tV[{1}] = (RHS[{1}] - tmp{1}) / m_A{4};\n", j, j, j, mat.diag[j]);
}
}
- this->m_stat_calculations++;
+ template <typename FT, int SIZE>
+ pstring matrix_solver_GCR_t<FT, SIZE>::static_compile_name()
+ {
+ plib::postringstream t;
+ plib::putf8_fmt_writer w(&t);
+ csc_private(w);
+ std::hash<pstring> h;
+
+ return plib::pfmt("nl_gcr_{1:x}_{2}")(h( t.str() ))(mat.nz_num);
+ }
- const nl_double err = (newton_raphson ? delta(new_V) : 0.0);
- store(new_V);
- return (err > this->m_params.m_accuracy) ? 2 : 1;
-}
+ template <typename FT, int SIZE>
+ std::pair<pstring, pstring> matrix_solver_GCR_t<FT, SIZE>::create_solver_code()
+ {
+ plib::postringstream t;
+ plib::putf8_fmt_writer strm(&t);
+ pstring name = static_compile_name();
+
+ strm.writeline(plib::pfmt("extern \"C\" void {1}(double * __restrict m_A, double * __restrict RHS, double * __restrict V)\n")(name));
+ strm.writeline("{\n");
+ csc_private(strm);
+ strm.writeline("}\n");
+ return std::pair<pstring, pstring>(name, t.str());
+ }
+
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_GCR_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
+ {
+ const std::size_t iN = this->N();
+
+ mat.set_scalar(0.0);
+
+ /* populate matrix */
+
+ this->fill_matrix(iN, m_mat_ptr, RHS);
+
+ /* now solve it */
+
+ //if (m_proc != nullptr)
+ if (m_proc.resolved())
+ {
+ //static_solver(m_A, RHS);
+ m_proc(&mat.A[0], &RHS[0], &new_V[0]);
+ }
+ else
+ {
+ // mat.gaussian_elimination_parallel(RHS);
+ mat.gaussian_elimination(RHS);
+ /* backward substitution */
+ mat.gaussian_back_substitution(new_V, RHS);
+ }
+
+ this->m_stat_calculations++;
+
+ const FT err = (newton_raphson ? delta(new_V) : 0.0);
+ store(new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
+ }
- } //namespace devices
+} // namespace devices
} // namespace netlist
#endif /* NLD_MS_GCR_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_gmres.h b/src/lib/netlist/solver/nld_ms_gmres.h
index 2e4e447d14f..2ff515ebda7 100644
--- a/src/lib/netlist/solver/nld_ms_gmres.h
+++ b/src/lib/netlist/solver/nld_ms_gmres.h
@@ -1,387 +1,145 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
- * nld_ms_sor.h
- *
- * Generic successive over relaxation solver.
- *
- * Fow w==1 we will do the classic Gauss-Seidel approach
+ * nld_ms_gmres.h
*
*/
#ifndef NLD_MS_GMRES_H_
#define NLD_MS_GMRES_H_
-#include <algorithm>
-
-#include "mat_cr.h"
#include "nld_ms_direct.h"
#include "nld_solver.h"
-#include "vector_base.h"
+#include "plib/gmres.h"
+#include "plib/mat_cr.h"
+#include "plib/parray.h"
+#include "plib/vector_ops.h"
+
+#include <algorithm>
+#include <cmath>
+
namespace netlist
{
- namespace devices
- {
-template <std::size_t m_N, std::size_t storage_N>
-class matrix_solver_GMRES_t: public matrix_solver_direct_t<m_N, storage_N>
+namespace devices
{
-public:
-
- matrix_solver_GMRES_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size)
- : matrix_solver_direct_t<m_N, storage_N>(anetlist, name, matrix_solver_t::ASCENDING, params, size)
- , m_use_iLU_preconditioning(true)
- , m_use_more_precise_stop_condition(false)
- , m_accuracy_mult(1.0)
- , mat(size)
- {
- }
- virtual ~matrix_solver_GMRES_t() override
+ template <typename FT, int SIZE>
+ class matrix_solver_GMRES_t: public matrix_solver_direct_t<FT, SIZE>
{
- }
-
- virtual void vsetup(analog_net_t::list_t &nets) override;
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ public:
-private:
+ using float_type = FT;
- //typedef typename mat_cr_t<storage_N>::type mattype;
- typedef typename mat_cr_t<storage_N>::index_type mattype;
-
- unsigned solve_ilu_gmres(nl_double (& RESTRICT x)[storage_N], const nl_double (& RESTRICT rhs)[storage_N], const unsigned restart_max, std::size_t mr, nl_double accuracy);
-
- std::vector<unsigned> m_term_cr[storage_N];
-
- bool m_use_iLU_preconditioning;
- bool m_use_more_precise_stop_condition;
- nl_double m_accuracy_mult; // FXIME: Save state
-
- mat_cr_t<storage_N> mat;
-
- nl_double m_LU[storage_N * storage_N];
+ /* Sort rows in ascending order. This should minimize fill-in and thus
+ * maximize the efficiency of the incomplete LUT.
+ * This is already preconditioning.
+ */
+ matrix_solver_GMRES_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size)
+ : matrix_solver_direct_t<FT, SIZE>(anetlist, name, matrix_solver_t::PREFER_BAND_MATRIX, params, size)
+ //, m_ops(size, 2)
+ , m_ops(size, 4)
+ , m_gmres(size)
+ {
+ }
- nl_double m_c[storage_N + 1]; /* mr + 1 */
- nl_double m_g[storage_N + 1]; /* mr + 1 */
- nl_double m_ht[storage_N + 1][storage_N]; /* (mr + 1), mr */
- nl_double m_s[storage_N + 1]; /* mr + 1 */
- nl_double m_v[storage_N + 1][storage_N]; /*(mr + 1), n */
- nl_double m_y[storage_N + 1]; /* mr + 1 */
+ void vsetup(analog_net_t::list_t &nets) override;
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
-};
+ private:
-// ----------------------------------------------------------------------------------------
-// matrix_solver - GMRES
-// ----------------------------------------------------------------------------------------
+ using mattype = typename plib::matrix_compressed_rows_t<FT, SIZE>::index_type;
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_GMRES_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
-{
- matrix_solver_direct_t<m_N, storage_N>::vsetup(nets);
+ plib::mat_precondition_ILU<FT, SIZE> m_ops;
+ plib::gmres_t<FT, SIZE> m_gmres;
+ };
- mattype nz = 0;
- const std::size_t iN = this->N();
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver - GMRES
+ // ----------------------------------------------------------------------------------------
- for (std::size_t k=0; k<iN; k++)
+ template <typename FT, int SIZE>
+ void matrix_solver_GMRES_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
{
- terms_for_net_t * RESTRICT row = this->m_terms[k].get();
- mat.ia[k] = nz;
+ matrix_solver_direct_t<FT, SIZE>::vsetup(nets);
- for (std::size_t j=0; j<row->m_nz.size(); j++)
- {
- mat.ja[nz] = static_cast<mattype>(row->m_nz[j]);
- if (row->m_nz[j] == k)
- mat.diag[k] = nz;
- nz++;
- }
+ const std::size_t iN = this->size();
- /* build pointers into the compressed row format matrix for each terminal */
+ std::vector<std::vector<unsigned>> fill(iN);
- for (unsigned j=0; j< this->m_terms[k]->m_railstart;j++)
+ for (std::size_t k=0; k<iN; k++)
{
- for (unsigned i = mat.ia[k]; i<nz; i++)
- if (this->m_terms[k]->connected_net_idx()[j] == static_cast<int>(mat.ja[i]))
- {
- m_term_cr[k].push_back(i);
- break;
- }
- nl_assert(m_term_cr[k].size() == this->m_terms[k]->m_railstart);
- }
- }
-
- mat.ia[iN] = nz;
- mat.nz_num = nz;
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_GMRES_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
-{
- const std::size_t iN = this->N();
-
- /* ideally, we could get an estimate for the spectral radius of
- * Inv(D - L) * U
- *
- * and estimate using
- *
- * omega = 2.0 / (1.0 + std::sqrt(1-rho))
- */
-
- //nz_num = 0;
- nl_double RHS[storage_N];
- nl_double new_V[storage_N];
-
- mat.set_scalar(0.0);
-
- for (std::size_t k = 0; k < iN; k++)
- {
- nl_double gtot_t = 0.0;
- nl_double RHS_t = 0.0;
-
- const std::size_t term_count = this->m_terms[k]->count();
- const std::size_t railstart = this->m_terms[k]->m_railstart;
- const nl_double * const RESTRICT gt = this->m_terms[k]->gt();
- const nl_double * const RESTRICT go = this->m_terms[k]->go();
- const nl_double * const RESTRICT Idr = this->m_terms[k]->Idr();
- const nl_double * const * RESTRICT other_cur_analog = this->m_terms[k]->connected_net_V();
-
- for (std::size_t i = 0; i < term_count; i++)
- {
- gtot_t = gtot_t + gt[i];
- RHS_t = RHS_t + Idr[i];
+ fill[k].resize(iN, decltype(m_ops.m_mat)::FILL_INFINITY);
+ terms_for_net_t * row = this->m_terms[k].get();
+ for (const auto &nz_j : row->m_nz)
+ {
+ fill[k][static_cast<mattype>(nz_j)] = 0;
+ }
}
- for (std::size_t i = railstart; i < term_count; i++)
- RHS_t = RHS_t + go[i] * *other_cur_analog[i];
+ m_ops.build(fill);
- RHS[k] = RHS_t;
-
- // add diagonal element
- mat.A[mat.diag[k]] = gtot_t;
+ /* build pointers into the compressed row format matrix for each terminal */
- for (std::size_t i = 0; i < railstart; i++)
+ for (std::size_t k=0; k<iN; k++)
{
- const std::size_t pi = m_term_cr[k][i];
- mat.A[pi] -= go[i];
+ std::size_t cnt = 0;
+ for (std::size_t j=0; j< this->m_terms[k]->m_railstart;j++)
+ {
+ for (std::size_t i = m_ops.m_mat.row_idx[k]; i<m_ops.m_mat.row_idx[k+1]; i++)
+ if (this->m_terms[k]->m_connected_net_idx[j] == static_cast<int>(m_ops.m_mat.col_idx[i]))
+ {
+ this->m_mat_ptr[k][j] = &m_ops.m_mat.A[i];
+ cnt++;
+ break;
+ }
+ }
+ nl_assert(cnt == this->m_terms[k]->m_railstart);
+ this->m_mat_ptr[k][this->m_terms[k]->m_railstart] = &m_ops.m_mat.A[m_ops.m_mat.diag[k]];
}
-
- new_V[k] = this->m_nets[k]->Q_Analog();
-
}
- mat.ia[iN] = static_cast<mattype>(mat.nz_num);
-
- const nl_double accuracy = this->m_params.m_accuracy;
-
- unsigned mr = iN;
- if (iN > 3 )
- mr = static_cast<unsigned>(std::sqrt(iN) * 2.0);
- unsigned iter = std::max(1u, this->m_params.m_gs_loops);
- unsigned gsl = solve_ilu_gmres(new_V, RHS, iter, mr, accuracy);
- unsigned failed = mr * iter;
- this->m_iterative_total += gsl;
- this->m_stat_calculations++;
-
- if (gsl>=failed)
- {
- this->m_iterative_fail++;
- return matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(newton_raphson);
- }
-
- const nl_double err = (newton_raphson ? this->delta(new_V) : 0.0);
- this->store(new_V);
- return (err > this->m_params.m_accuracy) ? 2 : 1;
-}
-
-template <typename T>
-inline static void givens_mult( const T c, const T s, T & g0, T & g1 )
-{
- const T tg0 = c * g0 - s * g1;
- const T tg1 = s * g0 + c * g1;
-
- g0 = tg0;
- g1 = tg1;
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_GMRES_t<m_N, storage_N>::solve_ilu_gmres (nl_double (& RESTRICT x)[storage_N], const nl_double (& RESTRICT rhs)[storage_N], const unsigned restart_max, std::size_t mr, nl_double accuracy)
-{
- /*-------------------------------------------------------------------------
- * The code below was inspired by code published by John Burkardt under
- * the LPGL here:
- *
- * http://people.sc.fsu.edu/~jburkardt/cpp_src/mgmres/mgmres.html
- *
- * The code below was completely written from scratch based on the pseudo code
- * found here:
- *
- * http://de.wikipedia.org/wiki/GMRES-Verfahren
- *
- * The Algorithm itself is described in
- *
- * Yousef Saad,
- * Iterative Methods for Sparse Linear Systems,
- * Second Edition,
- * SIAM, 20003,
- * ISBN: 0898715342,
- * LC: QA188.S17.
- *
- *------------------------------------------------------------------------*/
-
- unsigned itr_used = 0;
- double rho_delta = 0.0;
-
- const std::size_t n = this->N();
-
- if (mr > n) mr = n;
-
- if (m_use_iLU_preconditioning)
- mat.incomplete_LU_factorization(m_LU);
-
- if (m_use_more_precise_stop_condition)
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_GMRES_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
{
- /* derive residual for a given delta x
- *
- * LU y = A dx
- *
- * ==> rho / accuracy = sqrt(y * y)
- *
- * This approach will approximate the iterative stop condition
- * based |xnew - xold| pretty precisely. But it is slow, or expressed
- * differently: The invest doesn't pay off.
- * Therefore we use the approach in the else part.
- */
- nl_double t[storage_N];
- nl_double Ax[storage_N];
- vec_set(n, accuracy, t);
- mat.mult_vec(t, Ax);
-
- mat.solveLUx(m_LU, Ax);
-
- const nl_double rho_to_accuracy = std::sqrt(vec_mult2(n, Ax)) / accuracy;
-
- rho_delta = accuracy * rho_to_accuracy;
- }
- else
- rho_delta = accuracy * std::sqrt(n) * m_accuracy_mult;
-
- for (unsigned itr = 0; itr < restart_max; itr++)
- {
- std::size_t last_k = mr;
- nl_double rho;
-
- nl_double Ax[storage_N];
- nl_double residual[storage_N];
-
- mat.mult_vec(x, Ax);
-
- vec_sub(n, rhs, Ax, residual);
-
- if (m_use_iLU_preconditioning)
- {
- mat.solveLUx(m_LU, residual);
- }
-
- rho = std::sqrt(vec_mult2(n, residual));
+ const std::size_t iN = this->size();
- if (rho < rho_delta)
- return itr_used + 1;
+ plib::parray<FT, SIZE> RHS(iN);
+ //float_type new_V[storage_N];
- vec_set(mr+1, NL_FCONST(0.0), m_g);
- m_g[0] = rho;
+ m_ops.m_mat.set_scalar(0.0);
- for (std::size_t i = 0; i < mr; i++)
- vec_set(mr + 1, NL_FCONST(0.0), m_ht[i]);
+ /* populate matrix and V for first estimate */
+ this->fill_matrix(iN, this->m_mat_ptr, RHS);
- vec_mult_scalar(n, residual, NL_FCONST(1.0) / rho, m_v[0]);
-
- for (std::size_t k = 0; k < mr; k++)
+ for (std::size_t k = 0; k < iN; k++)
{
- const std::size_t k1 = k + 1;
-
- mat.mult_vec(m_v[k], m_v[k1]);
-
- if (m_use_iLU_preconditioning)
- mat.solveLUx(m_LU, m_v[k1]);
-
- for (std::size_t j = 0; j <= k; j++)
- {
- m_ht[j][k] = vec_mult(n, m_v[k1], m_v[j]);
- vec_add_mult_scalar(n, m_v[j], -m_ht[j][k], m_v[k1]);
- }
- m_ht[k1][k] = std::sqrt(vec_mult2(n, m_v[k1]));
-
- if (m_ht[k1][k] != 0.0)
- vec_scale(n, m_v[k1], NL_FCONST(1.0) / m_ht[k1][k]);
-
- for (std::size_t j = 0; j < k; j++)
- givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]);
-
- const nl_double mu = 1.0 / std::hypot(m_ht[k][k], m_ht[k1][k]);
-
- m_c[k] = m_ht[k][k] * mu;
- m_s[k] = -m_ht[k1][k] * mu;
- m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[k1][k];
- m_ht[k1][k] = 0.0;
-
- givens_mult(m_c[k], m_s[k], m_g[k], m_g[k1]);
-
- rho = std::abs(m_g[k1]);
-
- itr_used = itr_used + 1;
-
- if (rho <= rho_delta)
- {
- last_k = k;
- break;
- }
+ this->m_new_V[k] = this->m_nets[k]->Q_Analog();
}
- if (last_k >= mr)
- /* didn't converge within accuracy */
- last_k = mr - 1;
+ const float_type accuracy = this->m_params.m_accuracy;
- /* Solve the system H * y = g */
- /* x += m_v[j] * m_y[j] */
- for (std::size_t i = last_k + 1; i-- > 0;)
- {
- double tmp = m_g[i];
- for (std::size_t j = i + 1; j <= last_k; j++)
- {
- tmp -= m_ht[i][j] * m_y[j];
- }
- m_y[i] = tmp / m_ht[i][i];
- }
-
- for (std::size_t i = 0; i <= last_k; i++)
- vec_add_mult_scalar(n, m_v[i], m_y[i], x);
+ auto iter = std::max(plib::constants<std::size_t>::one(), this->m_params.m_gs_loops);
+ auto gsl = m_gmres.solve(m_ops, this->m_new_V, RHS, iter, accuracy);
-#if 1
- if (rho <= rho_delta)
- {
- break;
- }
-#else
- /* we try to approximate the x difference between to steps using m_v[last_k] */
+ this->m_iterative_total += gsl;
+ this->m_stat_calculations++;
- double xdelta = m_y[last_k] * vec_maxabs(n, m_v[last_k]);
- if (xdelta < accuracy)
+ if (gsl > iter)
{
- if (m_accuracy_mult < 16384.0)
- m_accuracy_mult = m_accuracy_mult * 2.0;
- break;
+ this->m_iterative_fail++;
+ return matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(newton_raphson);
}
- else
- m_accuracy_mult = m_accuracy_mult / 2.0;
-#endif
+ const float_type err = (newton_raphson ? this->delta(this->m_new_V) : 0.0);
+ this->store(this->m_new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
}
- return itr_used;
-}
- } //namespace devices
+} // namespace devices
} // namespace netlist
#endif /* NLD_MS_GMRES_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_sm.h b/src/lib/netlist/solver/nld_ms_sm.h
index ed95cd2dc03..d85ab0044f4 100644
--- a/src/lib/netlist/solver/nld_ms_sm.h
+++ b/src/lib/netlist/solver/nld_ms_sm.h
@@ -33,293 +33,275 @@
#ifndef NLD_MS_SM_H_
#define NLD_MS_SM_H_
-#include <algorithm>
-
-#include "nld_solver.h"
#include "nld_matrix_solver.h"
-#include "vector_base.h"
+#include "nld_solver.h"
+#include "plib/vector_ops.h"
+
+#include <algorithm>
namespace netlist
{
- namespace devices
- {
-//#define nl_ext_double _float128 // slow, very slow
-//#define nl_ext_double long double // slightly slower
-#define nl_ext_double nl_double
-
-template <std::size_t m_N, std::size_t storage_N>
-class matrix_solver_sm_t: public matrix_solver_t
+namespace devices
{
- friend class matrix_solver_t;
-
-public:
- matrix_solver_sm_t(netlist_t &anetlist, const pstring &name,
- const solver_parameters_t *params, const std::size_t size);
-
- virtual ~matrix_solver_sm_t() override;
-
- virtual void vsetup(analog_net_t::list_t &nets) override;
- virtual void reset() override { matrix_solver_t::reset(); }
-
-protected:
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
- unsigned solve_non_dynamic(const bool newton_raphson);
-
- constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; }
-
- void LE_invert();
-
- template <typename T>
- void LE_compute_x(T * RESTRICT x);
+ template <typename FT, int SIZE>
+ class matrix_solver_sm_t: public matrix_solver_t
+ {
+ friend class matrix_solver_t;
+ public:
- template <typename T1, typename T2>
- nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
- template <typename T1, typename T2>
- nl_ext_double &W(const T1 &r, const T2 &c) { return m_W[r][c]; }
- template <typename T1, typename T2>
- nl_ext_double &Ainv(const T1 &r, const T2 &c) { return m_Ainv[r][c]; }
- template <typename T1>
- nl_ext_double &RHS(const T1 &r) { return m_RHS[r]; }
+ using float_ext_type = FT;
+ using float_type = FT;
+ // FIXME: dirty hack to make this compile
+ static constexpr const std::size_t storage_N = 100;
+ matrix_solver_sm_t(netlist_state_t &anetlist, const pstring &name,
+ const solver_parameters_t *params, const std::size_t size);
- template <typename T1, typename T2>
- nl_ext_double &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; }
- template <typename T1, typename T2>
- nl_ext_double &lAinv(const T1 &r, const T2 &c) { return m_lAinv[r][c]; }
+ void vsetup(analog_net_t::list_t &nets) override;
+ void reset() override { matrix_solver_t::reset(); }
- nl_double m_last_RHS[storage_N]; // right hand side - contains currents
+ protected:
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ unsigned solve_non_dynamic(const bool newton_raphson);
-private:
- static constexpr std::size_t m_pitch = ((( storage_N) + 7) / 8) * 8;
- nl_ext_double m_A[storage_N][m_pitch];
- nl_ext_double m_Ainv[storage_N][m_pitch];
- nl_ext_double m_W[storage_N][m_pitch];
- nl_ext_double m_RHS[storage_N]; // right hand side - contains currents
+ constexpr std::size_t size() const { return m_dim; }
- nl_ext_double m_lA[storage_N][m_pitch];
- nl_ext_double m_lAinv[storage_N][m_pitch];
+ void LE_invert();
- //nl_ext_double m_RHSx[storage_N];
+ template <typename T>
+ void LE_compute_x(T * x);
- const std::size_t m_dim;
- std::size_t m_cnt;
-};
+ template <typename T1, typename T2>
+ float_ext_type &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
+ template <typename T1, typename T2>
+ float_ext_type &W(const T1 &r, const T2 &c) { return m_W[r][c]; }
+ template <typename T1, typename T2>
+ float_ext_type &Ainv(const T1 &r, const T2 &c) { return m_Ainv[r][c]; }
+ template <typename T1>
+ float_ext_type &RHS(const T1 &r) { return m_RHS[r]; }
-// ----------------------------------------------------------------------------------------
-// matrix_solver_direct
-// ----------------------------------------------------------------------------------------
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_sm_t<m_N, storage_N>::~matrix_solver_sm_t()
-{
-}
+ template <typename T1, typename T2>
+ float_ext_type &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; }
+ template <typename T1, typename T2>
+ float_ext_type &lAinv(const T1 &r, const T2 &c) { return m_lAinv[r][c]; }
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_sm_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
-{
- matrix_solver_t::setup_base(nets);
+ private:
+ static constexpr std::size_t m_pitch = ((( storage_N) + 7) / 8) * 8;
+ float_ext_type m_A[storage_N][m_pitch];
+ float_ext_type m_Ainv[storage_N][m_pitch];
+ float_ext_type m_W[storage_N][m_pitch];
+ float_ext_type m_RHS[storage_N]; // right hand side - contains currents
- netlist().save(*this, m_last_RHS, "m_last_RHS");
+ float_ext_type m_lA[storage_N][m_pitch];
+ float_ext_type m_lAinv[storage_N][m_pitch];
- for (unsigned k = 0; k < N(); k++)
- netlist().save(*this, RHS(k), plib::pfmt("RHS.{1}")(k));
-}
+ //float_ext_type m_RHSx[storage_N];
+ const std::size_t m_dim;
+ std::size_t m_cnt;
+ };
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_sm_t<m_N, storage_N>::LE_invert()
-{
- const std::size_t kN = N();
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver_direct
+ // ----------------------------------------------------------------------------------------
- for (std::size_t i = 0; i < kN; i++)
+ template <typename FT, int SIZE>
+ void matrix_solver_sm_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
{
- for (std::size_t j = 0; j < kN; j++)
- {
- W(i,j) = lA(i,j) = A(i,j);
- Ainv(i,j) = 0.0;
- }
- Ainv(i,i) = 1.0;
+ matrix_solver_t::setup_base(nets);
+
+ /* FIXME: Shouldn't be necessary */
+ for (std::size_t k = 0; k < size(); k++)
+ state().save(*this, RHS(k), this->name(), plib::pfmt("RHS.{1}")(k));
}
- /* down */
- for (std::size_t i = 0; i < kN; i++)
- {
- /* FIXME: Singular matrix? */
- const nl_double f = 1.0 / W(i,i);
- const auto * RESTRICT const p = m_terms[i]->m_nzrd.data();
- const std::size_t e = m_terms[i]->m_nzrd.size();
- /* Eliminate column i from row j */
+ template <typename FT, int SIZE>
+ void matrix_solver_sm_t<FT, SIZE>::LE_invert()
+ {
+ const std::size_t kN = size();
- const auto * RESTRICT const pb = m_terms[i]->m_nzbd.data();
- const std::size_t eb = m_terms[i]->m_nzbd.size();
- for (std::size_t jb = 0; jb < eb; jb++)
+ for (std::size_t i = 0; i < kN; i++)
{
- const unsigned j = pb[jb];
- const nl_double f1 = - W(j,i) * f;
- if (f1 != 0.0)
+ for (std::size_t j = 0; j < kN; j++)
{
- for (std::size_t k = 0; k < e; k++)
- W(j,p[k]) += W(i,p[k]) * f1;
- for (std::size_t k = 0; k <= i; k ++)
- Ainv(j,k) += Ainv(i,k) * f1;
+ W(i,j) = lA(i,j) = A(i,j);
+ Ainv(i,j) = 0.0;
}
+ Ainv(i,i) = 1.0;
}
- }
- /* up */
- for (std::size_t i = kN; i-- > 0; )
- {
- /* FIXME: Singular matrix? */
- const nl_double f = 1.0 / W(i,i);
- for (std::size_t j = i; j-- > 0; )
+ /* down */
+ for (std::size_t i = 0; i < kN; i++)
{
- const nl_double f1 = - W(j,i) * f;
- if (f1 != 0.0)
+ /* FIXME: Singular matrix? */
+ const float_type f = 1.0 / W(i,i);
+ const auto * const p = m_terms[i]->m_nzrd.data();
+ const std::size_t e = m_terms[i]->m_nzrd.size();
+
+ /* Eliminate column i from row j */
+
+ const auto * const pb = m_terms[i]->m_nzbd.data();
+ const std::size_t eb = m_terms[i]->m_nzbd.size();
+ for (std::size_t jb = 0; jb < eb; jb++)
{
- for (std::size_t k = i; k < kN; k++)
- W(j,k) += W(i,k) * f1;
- for (std::size_t k = 0; k < kN; k++)
- Ainv(j,k) += Ainv(i,k) * f1;
+ const unsigned j = pb[jb];
+ const float_type f1 = - W(j,i) * f;
+ if (f1 != 0.0)
+ {
+ for (std::size_t k = 0; k < e; k++)
+ W(j,p[k]) += W(i,p[k]) * f1;
+ for (std::size_t k = 0; k <= i; k ++)
+ Ainv(j,k) += Ainv(i,k) * f1;
+ }
}
}
- for (std::size_t k = 0; k < kN; k++)
+ /* up */
+ for (std::size_t i = kN; i-- > 0; )
{
- Ainv(i,k) *= f;
- lAinv(i,k) = Ainv(i,k);
+ /* FIXME: Singular matrix? */
+ const float_type f = 1.0 / W(i,i);
+ for (std::size_t j = i; j-- > 0; )
+ {
+ const float_type f1 = - W(j,i) * f;
+ if (f1 != 0.0)
+ {
+ for (std::size_t k = i; k < kN; k++)
+ W(j,k) += W(i,k) * f1;
+ for (std::size_t k = 0; k < kN; k++)
+ Ainv(j,k) += Ainv(i,k) * f1;
+ }
+ }
+ for (std::size_t k = 0; k < kN; k++)
+ {
+ Ainv(i,k) *= f;
+ lAinv(i,k) = Ainv(i,k);
+ }
}
}
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-template <typename T>
-void matrix_solver_sm_t<m_N, storage_N>::LE_compute_x(
- T * RESTRICT x)
-{
- const std::size_t kN = N();
- for (std::size_t i=0; i<kN; i++)
- x[i] = 0.0;
-
- for (std::size_t k=0; k<kN; k++)
+ template <typename FT, int SIZE>
+ template <typename T>
+ void matrix_solver_sm_t<FT, SIZE>::LE_compute_x(
+ T * x)
{
- const nl_double f = RHS(k);
+ const std::size_t kN = size();
for (std::size_t i=0; i<kN; i++)
- x[i] += Ainv(i,k) * f;
- }
-}
-
-
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_sm_t<m_N, storage_N>::solve_non_dynamic(const bool newton_raphson)
-{
- static constexpr const bool incremental = true;
- const std::size_t iN = N();
+ x[i] = 0.0;
- nl_double new_V[storage_N]; // = { 0.0 };
+ for (std::size_t k=0; k<kN; k++)
+ {
+ const float_type f = RHS(k);
- if ((m_cnt % 50) == 0)
- {
- /* complete calculation */
- this->LE_invert();
+ for (std::size_t i=0; i<kN; i++)
+ x[i] += Ainv(i,k) * f;
+ }
}
- else
+
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_sm_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphson)
{
- if (!incremental)
+ static constexpr const bool incremental = true;
+ const std::size_t iN = size();
+
+ float_type new_V[storage_N]; // = { 0.0 };
+
+ if ((m_cnt % 50) == 0)
{
- for (std::size_t row = 0; row < iN; row ++)
- for (std::size_t k = 0; k < iN; k++)
- Ainv(row,k) = lAinv(row, k);
+ /* complete calculation */
+ this->LE_invert();
}
- for (std::size_t row = 0; row < iN; row ++)
+ else
{
- nl_double v[m_pitch] = {0};
- std::size_t cols[m_pitch];
- std::size_t colcount = 0;
-
- auto &nz = m_terms[row]->m_nz;
- for (unsigned & col : nz)
+ if (!incremental)
{
- v[col] = A(row,col) - lA(row,col);
- if (incremental)
- lA(row,col) = A(row,col);
- if (v[col] != 0.0)
- cols[colcount++] = col;
+ for (std::size_t row = 0; row < iN; row ++)
+ for (std::size_t k = 0; k < iN; k++)
+ Ainv(row,k) = lAinv(row, k);
}
-
- if (colcount > 0)
+ for (std::size_t row = 0; row < iN; row ++)
{
- nl_double lamba = 0.0;
- nl_double w[m_pitch] = {0};
-
- nl_double z[m_pitch];
- /* compute w and lamba */
- for (std::size_t i = 0; i < iN; i++)
- z[i] = Ainv(i, row); /* u is row'th column */
+ float_type v[m_pitch] = {0};
+ std::size_t cols[m_pitch];
+ std::size_t colcount = 0;
- for (std::size_t j = 0; j < colcount; j++)
- lamba += v[cols[j]] * z[cols[j]];
-
- for (std::size_t j=0; j<colcount; j++)
+ auto &nz = m_terms[row]->m_nz;
+ for (unsigned & col : nz)
{
- std::size_t col = cols[j];
- nl_double f = v[col];
- for (std::size_t k = 0; k < iN; k++)
- w[k] += Ainv(col,k) * f; /* Transpose(Ainv) * v */
+ v[col] = A(row,col) - lA(row,col);
+ if (incremental)
+ lA(row,col) = A(row,col);
+ if (v[col] != 0.0)
+ cols[colcount++] = col;
}
- lamba = -1.0 / (1.0 + lamba);
- for (std::size_t i=0; i<iN; i++)
+ if (colcount > 0)
{
- const nl_double f = lamba * z[i];
- if (f != 0.0)
+ float_type lamba = 0.0;
+ float_type w[m_pitch] = {0};
+
+ float_type z[m_pitch];
+ /* compute w and lamba */
+ for (std::size_t i = 0; i < iN; i++)
+ z[i] = Ainv(i, row); /* u is row'th column */
+
+ for (std::size_t j = 0; j < colcount; j++)
+ lamba += v[cols[j]] * z[cols[j]];
+
+ for (std::size_t j=0; j<colcount; j++)
+ {
+ std::size_t col = cols[j];
+ float_type f = v[col];
for (std::size_t k = 0; k < iN; k++)
- Ainv(i,k) += f * w[k];
+ w[k] += Ainv(col,k) * f; /* Transpose(Ainv) * v */
+ }
+
+ lamba = -1.0 / (1.0 + lamba);
+ for (std::size_t i=0; i<iN; i++)
+ {
+ const float_type f = lamba * z[i];
+ if (f != 0.0)
+ for (std::size_t k = 0; k < iN; k++)
+ Ainv(i,k) += f * w[k];
+ }
}
- }
+ }
}
- }
- m_cnt++;
+ m_cnt++;
- this->LE_compute_x(new_V);
+ this->LE_compute_x(new_V);
- const nl_double err = (newton_raphson ? delta(new_V) : 0.0);
- store(new_V);
- return (err > this->m_params.m_accuracy) ? 2 : 1;
-}
+ const float_type err = (newton_raphson ? delta(new_V) : 0.0);
+ store(new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
+ }
-template <std::size_t m_N, std::size_t storage_N>
-inline unsigned matrix_solver_sm_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
-{
- build_LE_A<matrix_solver_sm_t>();
- build_LE_RHS<matrix_solver_sm_t>();
-
- for (std::size_t i=0, iN=N(); i < iN; i++)
- m_last_RHS[i] = RHS(i);
-
- this->m_stat_calculations++;
- return this->solve_non_dynamic(newton_raphson);
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_sm_t<m_N, storage_N>::matrix_solver_sm_t(netlist_t &anetlist, const pstring &name,
- const solver_parameters_t *params, const std::size_t size)
-: matrix_solver_t(anetlist, name, NOSORT, params)
-, m_dim(size)
-, m_cnt(0)
-{
- for (std::size_t k = 0; k < N(); k++)
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_sm_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
+ {
+ this->build_LE_A(*this);
+ this->build_LE_RHS(*this);
+
+ this->m_stat_calculations++;
+ return this->solve_non_dynamic(newton_raphson);
+ }
+
+ template <typename FT, int SIZE>
+ matrix_solver_sm_t<FT, SIZE>::matrix_solver_sm_t(netlist_state_t &anetlist, const pstring &name,
+ const solver_parameters_t *params, const std::size_t size)
+ : matrix_solver_t(anetlist, name, NOSORT, params)
+ , m_dim(size)
+ , m_cnt(0)
{
- m_last_RHS[k] = 0.0;
}
-}
- } //namespace devices
+} // namespace devices
} // namespace netlist
#endif /* NLD_MS_DIRECT_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_sor.h b/src/lib/netlist/solver/nld_ms_sor.h
index eea692d6c47..c31aaa6d46a 100644
--- a/src/lib/netlist/solver/nld_ms_sor.h
+++ b/src/lib/netlist/solver/nld_ms_sor.h
@@ -12,33 +12,42 @@
#ifndef NLD_MS_SOR_H_
#define NLD_MS_SOR_H_
-#include <algorithm>
-
#include "nld_ms_direct.h"
#include "nld_solver.h"
+#include <algorithm>
+
namespace netlist
{
namespace devices
- {
-template <std::size_t m_N, std::size_t storage_N>
-class matrix_solver_SOR_t: public matrix_solver_direct_t<m_N, storage_N>
+{
+
+template <typename FT, int SIZE>
+class matrix_solver_SOR_t: public matrix_solver_direct_t<FT, SIZE>
{
public:
- matrix_solver_SOR_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size)
- : matrix_solver_direct_t<m_N, storage_N>(anetlist, name, matrix_solver_t::ASCENDING, params, size)
+ using float_type = FT;
+
+ matrix_solver_SOR_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size)
+ : matrix_solver_direct_t<FT, SIZE>(anetlist, name, matrix_solver_t::ASCENDING, params, size)
, m_lp_fact(*this, "m_lp_fact", 0)
+ , w(size, 0.0)
+ , one_m_w(size, 0.0)
+ , RHS(size, 0.0)
+ //, new_V(size, 0.0)
{
}
- virtual ~matrix_solver_SOR_t() override {}
-
- virtual void vsetup(analog_net_t::list_t &nets) override;
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ void vsetup(analog_net_t::list_t &nets) override;
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
private:
- state_var<nl_double> m_lp_fact;
+ state_var<float_type> m_lp_fact;
+ std::vector<float_type> w;
+ std::vector<float_type> one_m_w;
+ std::vector<float_type> RHS;
+ //std::vector<float_type> new_V;
};
// ----------------------------------------------------------------------------------------
@@ -46,16 +55,16 @@ private:
// ----------------------------------------------------------------------------------------
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_SOR_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
+template <typename FT, int SIZE>
+void matrix_solver_SOR_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
{
- matrix_solver_direct_t<m_N, storage_N>::vsetup(nets);
+ matrix_solver_direct_t<FT, SIZE>::vsetup(nets);
}
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+template <typename FT, int SIZE>
+unsigned matrix_solver_SOR_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
{
- const std::size_t iN = this->N();
+ const std::size_t iN = this->size();
bool resched = false;
unsigned resched_cnt = 0;
@@ -67,26 +76,21 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt
* omega = 2.0 / (1.0 + std::sqrt(1-rho))
*/
- const nl_double ws = this->m_params.m_gs_sor;
-
- nl_double w[storage_N];
- nl_double one_m_w[storage_N];
- nl_double RHS[storage_N];
- nl_double new_V[storage_N];
+ const float_type ws = this->m_params.m_gs_sor;
for (std::size_t k = 0; k < iN; k++)
{
- nl_double gtot_t = 0.0;
- nl_double gabs_t = 0.0;
- nl_double RHS_t = 0.0;
+ float_type gtot_t = 0.0;
+ float_type gabs_t = 0.0;
+ float_type RHS_t = 0.0;
const std::size_t term_count = this->m_terms[k]->count();
- const nl_double * const RESTRICT gt = this->m_terms[k]->gt();
- const nl_double * const RESTRICT go = this->m_terms[k]->go();
- const nl_double * const RESTRICT Idr = this->m_terms[k]->Idr();
- const nl_double * const *other_cur_analog = this->m_terms[k]->connected_net_V();
+ const float_type * const gt = this->m_gtn[k];
+ const float_type * const go = this->m_gonn[k];
+ const float_type * const Idr = this->m_Idrn[k];
+ auto other_cur_analog = this->m_connected_net_Vn[k];
- new_V[k] = this->m_nets[k]->Q_Analog();
+ this->m_new_V[k] = this->m_nets[k]->Q_Analog();
for (std::size_t i = 0; i < term_count; i++)
{
@@ -95,61 +99,60 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt
}
for (std::size_t i = this->m_terms[k]->m_railstart; i < term_count; i++)
- RHS_t = RHS_t + go[i] * *other_cur_analog[i];
+ RHS_t = RHS_t - go[i] * *other_cur_analog[i];
RHS[k] = RHS_t;
- if (USE_GABS)
+ if (this->m_params.m_use_gabs)
{
for (std::size_t i = 0; i < term_count; i++)
gabs_t = gabs_t + std::abs(go[i]);
- gabs_t *= NL_FCONST(0.5); // derived by try and error
+ gabs_t *= plib::constants<nl_double>::cast(0.5); // derived by try and error
if (gabs_t <= gtot_t)
{
w[k] = ws / gtot_t;
- one_m_w[k] = NL_FCONST(1.0) - ws;
+ one_m_w[k] = plib::constants<FT>::one() - ws;
}
else
{
- w[k] = NL_FCONST(1.0) / (gtot_t + gabs_t);
- one_m_w[k] = NL_FCONST(1.0) - NL_FCONST(1.0) * gtot_t / (gtot_t + gabs_t);
+ w[k] = plib::constants<FT>::one() / (gtot_t + gabs_t);
+ one_m_w[k] = plib::constants<FT>::one() - plib::constants<FT>::one() * gtot_t / (gtot_t + gabs_t);
}
}
else
{
w[k] = ws / gtot_t;
- one_m_w[k] = NL_FCONST(1.0) - ws;
+ one_m_w[k] = plib::constants<FT>::one() - ws;
}
}
- const nl_double accuracy = this->m_params.m_accuracy;
+ const float_type accuracy = this->m_params.m_accuracy;
do {
resched = false;
- nl_double err = 0;
+ float_type err = 0;
for (std::size_t k = 0; k < iN; k++)
{
- const int * RESTRICT net_other = this->m_terms[k]->connected_net_idx();
+ const int * net_other = this->m_terms[k]->m_connected_net_idx.data();
const std::size_t railstart = this->m_terms[k]->m_railstart;
- const nl_double * RESTRICT go = this->m_terms[k]->go();
+ const float_type * go = this->m_gonn[k];
- nl_double Idrive = 0.0;
+ float_type Idrive = 0.0;
for (std::size_t i = 0; i < railstart; i++)
- Idrive = Idrive + go[i] * new_V[net_other[i]];
+ Idrive = Idrive - go[i] * this->m_new_V[static_cast<std::size_t>(net_other[i])];
- const nl_double new_val = new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k];
+ const float_type new_val = this->m_new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k];
- err = std::max(std::abs(new_val - new_V[k]), err);
- new_V[k] = new_val;
+ err = std::max(std::abs(new_val - this->m_new_V[k]), err);
+ this->m_new_V[k] = new_val;
}
if (err > accuracy)
resched = true;
resched_cnt++;
- //} while (resched && (resched_cnt < this->m_params.m_gs_loops));
- } while (resched && ((resched_cnt < this->m_params.m_gs_loops)));
+ } while (resched && (resched_cnt < this->m_params.m_gs_loops));
this->m_iterative_total += resched_cnt;
this->m_stat_calculations++;
@@ -158,13 +161,12 @@ unsigned matrix_solver_SOR_t<m_N, storage_N>::vsolve_non_dynamic(const bool newt
{
// Fallback to direct solver ...
this->m_iterative_fail++;
- return matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(newton_raphson);
+ return matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(newton_raphson);
}
- for (std::size_t k = 0; k < iN; k++)
- this->m_nets[k]->set_Q_Analog(new_V[k]);
-
- return resched_cnt;
+ const float_type err = (newton_raphson ? this->delta(this->m_new_V) : 0.0);
+ this->store(this->m_new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
}
} //namespace devices
diff --git a/src/lib/netlist/solver/nld_ms_sor_mat.h b/src/lib/netlist/solver/nld_ms_sor_mat.h
index 50bcac1a52d..83e4870cf28 100644
--- a/src/lib/netlist/solver/nld_ms_sor_mat.h
+++ b/src/lib/netlist/solver/nld_ms_sor_mat.h
@@ -12,212 +12,220 @@
#ifndef NLD_MS_SOR_MAT_H_
#define NLD_MS_SOR_MAT_H_
-#include <algorithm>
-
-#include "nld_ms_direct.h"
#include "nld_matrix_solver.h"
+#include "nld_ms_direct.h"
#include "nld_solver.h"
+#include <algorithm>
+
namespace netlist
{
- namespace devices
- {
-template <std::size_t m_N, std::size_t storage_N>
-class matrix_solver_SOR_mat_t: public matrix_solver_direct_t<m_N, storage_N>
+namespace devices
{
- friend class matrix_solver_t;
-public:
+ template <typename FT, int SIZE>
+ class matrix_solver_SOR_mat_t: public matrix_solver_direct_t<FT, SIZE>
+ {
+ friend class matrix_solver_t;
- matrix_solver_SOR_mat_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, std::size_t size)
- : matrix_solver_direct_t<m_N, storage_N>(anetlist, name, matrix_solver_t::DESCENDING, params, size)
- , m_Vdelta(*this, "m_Vdelta", 0.0)
- , m_omega(*this, "m_omega", params->m_gs_sor)
- , m_lp_fact(*this, "m_lp_fact", 0)
- , m_gs_fail(*this, "m_gs_fail", 0)
- , m_gs_total(*this, "m_gs_total", 0)
- {
- }
+ public:
- virtual ~matrix_solver_SOR_mat_t() override {}
+ using float_type = FT;
- virtual void vsetup(analog_net_t::list_t &nets) override;
+ matrix_solver_SOR_mat_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params, std::size_t size)
+ : matrix_solver_direct_t<FT, SIZE>(anetlist, name, matrix_solver_t::ASCENDING, params, size)
+ , m_Vdelta(*this, "m_Vdelta", std::vector<float_type>(size))
+ , m_omega(*this, "m_omega", params->m_gs_sor)
+ , m_lp_fact(*this, "m_lp_fact", 0)
+ {
+ }
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ void vsetup(analog_net_t::list_t &nets) override;
-private:
- state_var<nl_double[storage_N]> m_Vdelta;
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
- state_var<nl_double> m_omega;
- state_var<nl_double> m_lp_fact;
- state_var<int> m_gs_fail;
- state_var<int> m_gs_total;
-};
+ private:
+ //state_var<float_type[storage_N]> m_Vdelta;
+ state_var<std::vector<float_type>> m_Vdelta;
-// ----------------------------------------------------------------------------------------
-// matrix_solver - Gauss - Seidel
-// ----------------------------------------------------------------------------------------
+ state_var<float_type> m_omega;
+ state_var<float_type> m_lp_fact;
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_SOR_mat_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
-{
- matrix_solver_direct_t<m_N, storage_N>::vsetup(nets);
-}
+ };
-#if 0
-//FIXME: move to solve_base
-template <unsigned m_N, unsigned storage_N>
-nl_double matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve()
-{
- /*
- * enable linear prediction on first newton pass
- */
+ // ----------------------------------------------------------------------------------------
+ // matrix_solver - Gauss - Seidel
+ // ----------------------------------------------------------------------------------------
- if (USE_LINEAR_PREDICTION)
- for (unsigned k = 0; k < this->N(); k++)
- {
- this->m_last_V[k] = this->m_nets[k]->m_cur_Analog;
- this->m_nets[k]->m_cur_Analog = this->m_nets[k]->m_cur_Analog + this->m_Vdelta[k] * this->current_timestep() * m_lp_fact;
- }
- else
- for (unsigned k = 0; k < this->N(); k++)
- {
- this->m_last_V[k] = this->m_nets[k]->m_cur_Analog;
- }
-
- this->solve_base(this);
-
- if (USE_LINEAR_PREDICTION)
+ template <typename FT, int SIZE>
+ void matrix_solver_SOR_mat_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
{
- nl_double sq = 0;
- nl_double sqo = 0;
- const nl_double rez_cts = 1.0 / this->current_timestep();
- for (unsigned k = 0; k < this->N(); k++)
- {
- const analog_net_t *n = this->m_nets[k];
- const nl_double nv = (n->Q_Analog() - this->m_last_V[k]) * rez_cts ;
- sq += nv * nv;
- sqo += this->m_Vdelta[k] * this->m_Vdelta[k];
- this->m_Vdelta[k] = nv;
- }
-
- // FIXME: used to be 1e90, but this would not be compatible with float
- if (sqo > NL_FCONST(1e-20))
- m_lp_fact = std::min(std::sqrt(sq/sqo), (nl_double) 2.0);
- else
- m_lp_fact = NL_FCONST(0.0);
+ matrix_solver_direct_t<FT, SIZE>::vsetup(nets);
}
+ #if 0
+ //FIXME: move to solve_base
+ template <unsigned m_N, unsigned storage_N>
+ float_type matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve()
+ {
+ /*
+ * enable linear prediction on first newton pass
+ */
+
+ if (this->m_params->use_linear_prediction)
+ for (unsigned k = 0; k < this->size(); k++)
+ {
+ this->m_last_V[k] = this->m_nets[k]->m_cur_Analog;
+ this->m_nets[k]->m_cur_Analog = this->m_nets[k]->m_cur_Analog + this->m_Vdelta[k] * this->current_timestep() * m_lp_fact;
+ }
+ else
+ for (unsigned k = 0; k < this->size(); k++)
+ {
+ this->m_last_V[k] = this->m_nets[k]->m_cur_Analog;
+ }
- return this->compute_next_timestep();
-}
-#endif
-
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_SOR_mat_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
-{
- /* The matrix based code looks a lot nicer but actually is 30% slower than
- * the optimized code which works directly on the data structures.
- * Need something like that for gaussian elimination as well.
- */
-
-
- nl_double new_v[storage_N] = { 0.0 };
- const std::size_t iN = this->N();
-
- matrix_solver_t::build_LE_A<matrix_solver_SOR_mat_t>();
- matrix_solver_t::build_LE_RHS<matrix_solver_SOR_mat_t>();
+ this->solve_base(this);
- bool resched = false;
+ if (this->m_params->use_linear_prediction)
+ {
+ float_type sq = 0;
+ float_type sqo = 0;
+ const float_type rez_cts = 1.0 / this->current_timestep();
+ for (unsigned k = 0; k < this->size(); k++)
+ {
+ const analog_net_t *n = this->m_nets[k];
+ const float_type nv = (n->Q_Analog() - this->m_last_V[k]) * rez_cts ;
+ sq += nv * nv;
+ sqo += this->m_Vdelta[k] * this->m_Vdelta[k];
+ this->m_Vdelta[k] = nv;
+ }
+
+ // FIXME: used to be 1e90, but this would not be compatible with float
+ if (sqo > NL_FCONST(1e-20))
+ m_lp_fact = std::min(std::sqrt(sq/sqo), (float_type) 2.0);
+ else
+ m_lp_fact = NL_FCONST(0.0);
+ }
- unsigned resched_cnt = 0;
+ return this->compute_next_timestep();
+ }
+ #endif
-#if 0
- static int ws_cnt = 0;
- ws_cnt++;
- if (1 && ws_cnt % 200 == 0)
+ template <typename FT, int SIZE>
+ unsigned matrix_solver_SOR_mat_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
{
- // update omega
- nl_double lambdaN = 0;
- nl_double lambda1 = 1e9;
- for (int k = 0; k < iN; k++)
- {
- #if 0
- nl_double akk = std::abs(this->m_A[k][k]);
- if ( akk > lambdaN)
- lambdaN = akk;
- if (akk < lambda1)
- lambda1 = akk;
- #else
- nl_double akk = std::abs(this->m_A[k][k]);
- nl_double s = 0.0;
- for (int i=0; i<iN; i++)
- s = s + std::abs(this->m_A[k][i]);
- akk = s / akk - 1.0;
- if ( akk > lambdaN)
- lambdaN = akk;
- if (akk < lambda1)
- lambda1 = akk;
- #endif
- }
- //printf("lambda: %f %f\n", lambda, 2.0 / (1.0 + 2 * sqrt(lambda)) );
+ /* The matrix based code looks a lot nicer but actually is 30% slower than
+ * the optimized code which works directly on the data structures.
+ * Need something like that for gaussian elimination as well.
+ */
- //ws = 2.0 / (2.0 - lambdaN - lambda1);
- m_omega = 2.0 / (2.0 - lambda1);
- //printf("%f %f %f\n", m_omega, lambda1, lambdaN);
- }
-#endif
- for (std::size_t k = 0; k < iN; k++)
- new_v[k] = this->m_nets[k]->Q_Analog();
+ const std::size_t iN = this->size();
- do {
- resched = false;
- nl_double cerr = 0.0;
+ this->build_LE_A(*this);
+ this->build_LE_RHS(*this);
- for (std::size_t k = 0; k < iN; k++)
- {
- nl_double Idrive = 0;
+ bool resched = false;
- const auto *p = this->m_terms[k]->m_nz.data();
- const std::size_t e = this->m_terms[k]->m_nz.size();
+ unsigned resched_cnt = 0;
- for (std::size_t i = 0; i < e; i++)
- Idrive = Idrive + this->A(k,p[i]) * new_v[p[i]];
- const nl_double delta = m_omega * (this->RHS(k) - Idrive) / this->A(k,k);
- cerr = std::max(cerr, std::abs(delta));
- new_v[k] += delta;
+ #if 0
+ static int ws_cnt = 0;
+ ws_cnt++;
+ if (1 && ws_cnt % 200 == 0)
+ {
+ // update omega
+ float_type lambdaN = 0;
+ float_type lambda1 = 1e9;
+ for (int k = 0; k < iN; k++)
+ {
+ #if 0
+ float_type akk = std::abs(this->m_A[k][k]);
+ if ( akk > lambdaN)
+ lambdaN = akk;
+ if (akk < lambda1)
+ lambda1 = akk;
+ #else
+ float_type akk = std::abs(this->m_A[k][k]);
+ float_type s = 0.0;
+ for (int i=0; i<iN; i++)
+ s = s + std::abs(this->m_A[k][i]);
+ akk = s / akk - 1.0;
+ if ( akk > lambdaN)
+ lambdaN = akk;
+ if (akk < lambda1)
+ lambda1 = akk;
+ #endif
+ }
+
+ //ws = 2.0 / (2.0 - lambdaN - lambda1);
+ m_omega = 2.0 / (2.0 - lambda1);
}
+ #endif
- if (cerr > this->m_params.m_accuracy)
+ for (std::size_t k = 0; k < iN; k++)
+ this->m_new_V[k] = this->m_nets[k]->Q_Analog();
+
+ do {
+ resched = false;
+ float_type cerr = 0.0;
+
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ float_type Idrive = 0;
+
+ const auto *p = this->m_terms[k]->m_nz.data();
+ const std::size_t e = this->m_terms[k]->m_nz.size();
+
+ for (std::size_t i = 0; i < e; i++)
+ Idrive = Idrive + this->A(k,p[i]) * this->m_new_V[p[i]];
+
+ FT w = m_omega / this->A(k,k);
+ if (this->m_params.m_use_gabs)
+ {
+ FT gabs_t = 0.0;
+ for (std::size_t i = 0; i < e; i++)
+ if (p[i] != k)
+ gabs_t = gabs_t + std::abs(this->A(k,p[i]));
+
+ gabs_t *= plib::constants<FT>::one(); // derived by try and error
+ if (gabs_t > this->A(k,k))
+ {
+ w = plib::constants<FT>::one() / (this->A(k,k) + gabs_t);
+ }
+ }
+
+ const float_type delta = w * (this->RHS(k) - Idrive) ;
+ cerr = std::max(cerr, std::abs(delta));
+ this->m_new_V[k] += delta;
+ }
+
+ if (cerr > this->m_params.m_accuracy)
+ {
+ resched = true;
+ }
+ resched_cnt++;
+ } while (resched && (resched_cnt < this->m_params.m_gs_loops));
+
+ this->m_stat_calculations++;
+ this->m_iterative_total += resched_cnt;
+
+ if (resched)
{
- resched = true;
+ this->m_iterative_fail++;
+ //this->netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS");
+ return matrix_solver_direct_t<FT, SIZE>::solve_non_dynamic(newton_raphson);
}
- resched_cnt++;
- } while (resched && (resched_cnt < this->m_params.m_gs_loops));
-
- this->m_stat_calculations++;
- this->m_iterative_total += resched_cnt;
- this->m_gs_total += resched_cnt;
- if (resched)
- {
- this->m_iterative_fail++;
- //this->netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS");
- this->m_gs_fail++;
+ const float_type err = (newton_raphson ? this->delta(this->m_new_V) : 0.0);
+ this->store(this->m_new_V);
+ return (err > this->m_params.m_accuracy) ? 2 : 1;
- return matrix_solver_direct_t<m_N, storage_N>::solve_non_dynamic(newton_raphson);
- }
- else {
- this->store(new_v);
- return resched_cnt;
}
-}
-
- } //namespace devices
+} // namespace devices
} // namespace netlist
#endif /* NLD_MS_GAUSS_SEIDEL_H_ */
diff --git a/src/lib/netlist/solver/nld_ms_w.h b/src/lib/netlist/solver/nld_ms_w.h
index 0d4e7781eed..3372b50c7c5 100644
--- a/src/lib/netlist/solver/nld_ms_w.h
+++ b/src/lib/netlist/solver/nld_ms_w.h
@@ -40,80 +40,80 @@
#ifndef NLD_MS_W_H_
#define NLD_MS_W_H_
-#include <algorithm>
-
-#include "nld_solver.h"
#include "nld_matrix_solver.h"
-#include "vector_base.h"
+#include "nld_solver.h"
+#include "plib/vector_ops.h"
+
+#include <algorithm>
namespace netlist
{
namespace devices
{
-//#define nl_ext_double _float128 // slow, very slow
-//#define nl_ext_double long double // slightly slower
-#define nl_ext_double nl_double
-template <std::size_t m_N, std::size_t storage_N>
+template <typename FT, int SIZE>
class matrix_solver_w_t: public matrix_solver_t
{
friend class matrix_solver_t;
+
public:
+ using float_ext_type = FT;
+ using float_type = FT;
- matrix_solver_w_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size);
+ // FIXME: dirty hack to make this compile
+ static constexpr const std::size_t storage_N = 100;
- virtual ~matrix_solver_w_t() override;
+ matrix_solver_w_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size);
- virtual void vsetup(analog_net_t::list_t &nets) override;
- virtual void reset() override { matrix_solver_t::reset(); }
+ void vsetup(analog_net_t::list_t &nets) override;
+ void reset() override { matrix_solver_t::reset(); }
protected:
- virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override;
+ unsigned vsolve_non_dynamic(const bool newton_raphson) override;
unsigned solve_non_dynamic(const bool newton_raphson);
- constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; }
+ constexpr std::size_t size() const { return m_dim; }
void LE_invert();
template <typename T>
- void LE_compute_x(T * RESTRICT x);
+ void LE_compute_x(T * x);
template <typename T1, typename T2>
- inline nl_ext_double &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
+ float_ext_type &A(const T1 &r, const T2 &c) { return m_A[r][c]; }
template <typename T1, typename T2>
- inline nl_ext_double &W(const T1 &r, const T2 &c) { return m_W[r][c]; }
+ float_ext_type &W(const T1 &r, const T2 &c) { return m_W[r][c]; }
/* access to Ainv for fixed columns over row, there store transposed */
template <typename T1, typename T2>
- inline nl_ext_double &Ainv(const T1 &r, const T2 &c) { return m_Ainv[c][r]; }
+ float_ext_type &Ainv(const T1 &r, const T2 &c) { return m_Ainv[c][r]; }
template <typename T1>
- inline nl_ext_double &RHS(const T1 &r) { return m_RHS[r]; }
+ float_ext_type &RHS(const T1 &r) { return m_RHS[r]; }
template <typename T1, typename T2>
- inline nl_ext_double &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; }
+ float_ext_type &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; }
- nl_double m_last_RHS[storage_N]; // right hand side - contains currents
private:
static constexpr std::size_t m_pitch = ((( storage_N) + 7) / 8) * 8;
- nl_ext_double m_A[storage_N][m_pitch];
- nl_ext_double m_Ainv[storage_N][m_pitch];
- nl_ext_double m_W[storage_N][m_pitch];
- nl_ext_double m_RHS[storage_N]; // right hand side - contains currents
+ float_ext_type m_A[storage_N][m_pitch];
+ float_ext_type m_Ainv[storage_N][m_pitch];
+ float_ext_type m_W[storage_N][m_pitch];
+ float_ext_type m_RHS[storage_N]; // right hand side - contains currents
- nl_ext_double m_lA[storage_N][m_pitch];
+ float_ext_type m_lA[storage_N][m_pitch];
/* temporary */
- nl_double H[storage_N][m_pitch] ;
+ float_type H[storage_N][m_pitch] ;
unsigned rows[storage_N];
unsigned cols[storage_N][m_pitch];
unsigned colcount[storage_N];
unsigned m_cnt;
- //nl_ext_double m_RHSx[storage_N];
+ //float_ext_type m_RHSx[storage_N];
const std::size_t m_dim;
@@ -123,28 +123,22 @@ private:
// matrix_solver_direct
// ----------------------------------------------------------------------------------------
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_w_t<m_N, storage_N>::~matrix_solver_w_t()
-{
-}
-
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_w_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets)
+template <typename FT, int SIZE>
+void matrix_solver_w_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets)
{
matrix_solver_t::setup_base(nets);
- netlist().save(*this, m_last_RHS, "m_last_RHS");
-
- for (unsigned k = 0; k < N(); k++)
- netlist().save(*this, RHS(k), plib::pfmt("RHS.{1}")(k));
+ // FIXME: This shouldn't be necessary, recalculate on each entry ...
+ for (std::size_t k = 0; k < size(); k++)
+ state().save(*this, RHS(k), this->name(), plib::pfmt("RHS.{1}")(k));
}
-template <std::size_t m_N, std::size_t storage_N>
-void matrix_solver_w_t<m_N, storage_N>::LE_invert()
+template <typename FT, int SIZE>
+void matrix_solver_w_t<FT, SIZE>::LE_invert()
{
- const std::size_t kN = N();
+ const std::size_t kN = size();
for (std::size_t i = 0; i < kN; i++)
{
@@ -159,18 +153,18 @@ void matrix_solver_w_t<m_N, storage_N>::LE_invert()
for (std::size_t i = 0; i < kN; i++)
{
/* FIXME: Singular matrix? */
- const nl_double f = 1.0 / W(i,i);
- const auto * RESTRICT const p = m_terms[i]->m_nzrd.data();
+ const float_type f = 1.0 / W(i,i);
+ const auto * const p = m_terms[i]->m_nzrd.data();
const size_t e = m_terms[i]->m_nzrd.size();
/* Eliminate column i from row j */
- const auto * RESTRICT const pb = m_terms[i]->m_nzbd.data();
+ const auto * const pb = m_terms[i]->m_nzbd.data();
const size_t eb = m_terms[i]->m_nzbd.size();
for (std::size_t jb = 0; jb < eb; jb++)
{
const auto j = pb[jb];
- const nl_double f1 = - W(j,i) * f;
+ const float_type f1 = - W(j,i) * f;
if (f1 != 0.0)
{
for (std::size_t k = 0; k < e; k++)
@@ -184,10 +178,10 @@ void matrix_solver_w_t<m_N, storage_N>::LE_invert()
for (std::size_t i = kN; i-- > 0; )
{
/* FIXME: Singular matrix? */
- const nl_double f = 1.0 / W(i,i);
+ const float_type f = 1.0 / W(i,i);
for (std::size_t j = i; j-- > 0; )
{
- const nl_double f1 = - W(j,i) * f;
+ const float_type f1 = - W(j,i) * f;
if (f1 != 0.0)
{
for (std::size_t k = i; k < kN; k++)
@@ -203,19 +197,19 @@ void matrix_solver_w_t<m_N, storage_N>::LE_invert()
}
}
-template <std::size_t m_N, std::size_t storage_N>
+template <typename FT, int SIZE>
template <typename T>
-void matrix_solver_w_t<m_N, storage_N>::LE_compute_x(
- T * RESTRICT x)
+void matrix_solver_w_t<FT, SIZE>::LE_compute_x(
+ T * x)
{
- const std::size_t kN = N();
+ const std::size_t kN = size();
for (std::size_t i=0; i<kN; i++)
x[i] = 0.0;
for (std::size_t k=0; k<kN; k++)
{
- const nl_double f = RHS(k);
+ const float_type f = RHS(k);
for (std::size_t i=0; i<kN; i++)
x[i] += Ainv(i,k) * f;
@@ -223,14 +217,14 @@ void matrix_solver_w_t<m_N, storage_N>::LE_compute_x(
}
-template <std::size_t m_N, std::size_t storage_N>
-unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_raphson)
+template <typename FT, int SIZE>
+unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphson)
{
- const auto iN = N();
+ const auto iN = size();
- nl_double new_V[storage_N]; // = { 0.0 };
+ float_type new_V[storage_N]; // = { 0.0 };
- if ((m_cnt % 100) == 0)
+ if ((m_cnt % 50) == 0)
{
/* complete calculation */
this->LE_invert();
@@ -266,7 +260,7 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_
/* construct w = transform(V) * y
* dim: rowcount x iN
* */
- nl_double w[storage_N];
+ float_type w[storage_N];
for (unsigned i = 0; i < rowcount; i++)
{
const unsigned r = rows[i];
@@ -287,7 +281,7 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_
for (unsigned k=0; k< colcount[i]; k++)
{
const unsigned col = cols[i][k];
- nl_double f = VT(rows[i],col);
+ float_type f = VT(rows[i],col);
if (f!=0.0)
for (unsigned j= 0; j < rowcount; j++)
H[i][j] += f * Ainv(col,rows[j]);
@@ -297,16 +291,16 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_
for (unsigned i = 0; i < rowcount; i++)
{
if (H[i][i] == 0.0)
- printf("%s H singular\n", this->name().c_str());
- const nl_double f = 1.0 / H[i][i];
+ plib::perrlogger("{} H singular\n", this->name());
+ const float_type f = 1.0 / H[i][i];
for (unsigned j = i+1; j < rowcount; j++)
{
- const nl_double f1 = - f * H[j][i];
+ const float_type f1 = - f * H[j][i];
if (f1!=0.0)
{
- nl_double *pj = &H[j][i+1];
- const nl_double *pi = &H[i][i+1];
+ float_type *pj = &H[j][i+1];
+ const float_type *pi = &H[i][i+1];
for (unsigned k = 0; k < rowcount-i-1; k++)
pj[k] += f1 * pi[k];
//H[j][k] += f1 * H[i][k];
@@ -316,12 +310,12 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_
}
/* Back substitution */
//inv(H) w = t w = H t
- nl_double t[storage_N]; // FIXME: convert to member
+ float_type t[storage_N]; // FIXME: convert to member
for (unsigned j = rowcount; j-- > 0; )
{
- nl_double tmp = 0;
- const nl_double *pj = &H[j][j+1];
- const nl_double *tj = &t[j+1];
+ float_type tmp = 0;
+ const float_type *pj = &H[j][j+1];
+ const float_type *tj = &t[j+1];
for (unsigned k = 0; k < rowcount-j-1; k++)
tmp += pj[k] * tj[k];
//tmp += H[j][k] * t[k];
@@ -331,7 +325,7 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_
/* x = y - Zt */
for (unsigned i=0; i<iN; i++)
{
- nl_double tmp = 0.0;
+ float_type tmp = 0.0;
for (unsigned j=0; j<rowcount;j++)
{
const unsigned row = rows[j];
@@ -343,47 +337,40 @@ unsigned matrix_solver_w_t<m_N, storage_N>::solve_non_dynamic(const bool newton_
}
m_cnt++;
- if (0)
+ if (false)
for (unsigned i=0; i<iN; i++)
{
- nl_double tmp = 0.0;
+ float_type tmp = 0.0;
for (unsigned j=0; j<iN; j++)
{
tmp += A(i,j) * new_V[j];
}
if (std::abs(tmp-RHS(i)) > 1e-6)
- printf("%s failed on row %d: %f RHS: %f\n", this->name().c_str(), i, std::abs(tmp-RHS(i)), RHS(i));
+ plib::perrlogger("{} failed on row {}: {} RHS: {}\n", this->name(), i, std::abs(tmp-RHS(i)), RHS(i));
}
- const nl_double err = (newton_raphson ? delta(new_V) : 0.0);
+ const float_type err = (newton_raphson ? delta(new_V) : 0.0);
store(new_V);
return (err > this->m_params.m_accuracy) ? 2 : 1;
}
-template <std::size_t m_N, std::size_t storage_N>
-inline unsigned matrix_solver_w_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson)
+template <typename FT, int SIZE>
+unsigned matrix_solver_w_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
{
- build_LE_A<matrix_solver_w_t>();
- build_LE_RHS<matrix_solver_w_t>();
-
- for (std::size_t i=0, iN=N(); i < iN; i++)
- m_last_RHS[i] = RHS(i);
+ this->build_LE_A(*this);
+ this->build_LE_RHS(*this);
this->m_stat_calculations++;
return this->solve_non_dynamic(newton_raphson);
}
-template <std::size_t m_N, std::size_t storage_N>
-matrix_solver_w_t<m_N, storage_N>::matrix_solver_w_t(netlist_t &anetlist, const pstring &name,
+template <typename FT, int SIZE>
+matrix_solver_w_t<FT, SIZE>::matrix_solver_w_t(netlist_state_t &anetlist, const pstring &name,
const solver_parameters_t *params, const std::size_t size)
-: matrix_solver_t(anetlist, name, NOSORT, params)
- ,m_cnt(0)
+ : matrix_solver_t(anetlist, name, NOSORT, params)
+ , m_cnt(0)
, m_dim(size)
{
- for (std::size_t k = 0; k < N(); k++)
- {
- m_last_RHS[k] = 0.0;
- }
}
} //namespace devices
diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp
index cae76caab1a..4734cc3624d 100644
--- a/src/lib/netlist/solver/nld_solver.cpp
+++ b/src/lib/netlist/solver/nld_solver.cpp
@@ -31,393 +31,398 @@
#pragma GCC optimize "ivopts"
#endif
-#include <algorithm>
-#include <cmath> // <<= needed by windows build
-
-#include "../nl_lists.h"
-
-#include "../plib/pomp.h"
-
-#include "../nl_factory.h"
-
-#include "nld_solver.h"
+#include "netlist/nl_lists.h"
+#include "netlist/nl_factory.h"
#include "nld_matrix_solver.h"
-
-#if 1
#include "nld_ms_direct.h"
-#include "nld_ms_gcr.h"
-#else
-#include "nld_ms_direct_lu.h"
-#endif
-#include "nld_ms_w.h"
-#include "nld_ms_sm.h"
#include "nld_ms_direct1.h"
#include "nld_ms_direct2.h"
+#include "nld_ms_gcr.h"
+#include "nld_ms_gmres.h"
+#include "nld_ms_sm.h"
#include "nld_ms_sor.h"
#include "nld_ms_sor_mat.h"
-#include "nld_ms_gmres.h"
+#include "nld_ms_w.h"
+#include "nld_solver.h"
+#include "plib/pomp.h"
+
+#include <algorithm>
+#include <cmath>
namespace netlist
{
- namespace devices
- {
-
-
+namespace devices
+{
-// ----------------------------------------------------------------------------------------
-// solver
-// ----------------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------------------
+ // solver
+ // ----------------------------------------------------------------------------------------
-NETLIB_RESET(solver)
-{
- for (std::size_t i = 0; i < m_mat_solvers.size(); i++)
- m_mat_solvers[i]->do_reset();
-}
+ NETLIB_RESET(solver)
+ {
+ for (auto &s : m_mat_solvers)
+ s->reset();
+ }
-void NETLIB_NAME(solver)::stop()
-{
- for (std::size_t i = 0; i < m_mat_solvers.size(); i++)
- m_mat_solvers[i]->log_stats();
-}
+ void NETLIB_NAME(solver)::stop()
+ {
+ for (auto &s : m_mat_solvers)
+ s->log_stats();
+ }
-NETLIB_NAME(solver)::~NETLIB_NAME(solver)()
-{
-}
+ NETLIB_UPDATE(solver)
+ {
+ if (m_params.m_dynamic_ts)
+ return;
-NETLIB_UPDATE(solver)
-{
- if (m_params.m_dynamic_ts)
- return;
+ netlist_time now(exec().time());
+ /* force solving during start up if there are no time-step devices */
+ /* FIXME: Needs a more elegant solution */
+ bool force_solve = (now < netlist_time::from_double(2 * m_params.m_max_timestep));
- /* force solving during start up if there are no time-step devices */
- /* FIXME: Needs a more elegant solution */
- bool force_solve = (netlist().time() < netlist_time::from_double(2 * m_params.m_max_timestep));
+ std::size_t nthreads = std::min(static_cast<std::size_t>(m_parallel()), plib::omp::get_max_threads());
- std::size_t nthreads = std::min(m_parallel(), plib::omp::get_max_threads());
- std::size_t t_cnt = 0;
- int solv[128];
- for (int i = 0; i < m_mat_solvers.size(); i++)
- if (m_mat_solvers[i]->has_timestep_devices() || force_solve)
- solv[t_cnt++] = i;
+ std::vector<matrix_solver_t *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_timestepping);
- if (nthreads > 1 && t_cnt > 1)
- {
- plib::omp::set_num_threads(nthreads);
- plib::omp::for_static(0, t_cnt, [this, &solv](int i) { ATTR_UNUSED const netlist_time ts = this->m_mat_solvers[solv[i]]->solve(); });
- }
- else
- for (auto & solver : m_mat_solvers)
- if (solver->has_timestep_devices() || force_solve)
- ATTR_UNUSED const netlist_time ts = solver->solve();
+ if (nthreads > 1 && solvers.size() > 1)
+ {
+ plib::omp::set_num_threads(nthreads);
+ plib::omp::for_static(static_cast<std::size_t>(0), solvers.size(), [&solvers, now](std::size_t i)
+ {
+ const netlist_time ts = solvers[i]->solve(now);
+ plib::unused_var(ts);
+ });
+ }
+ else
+ for (auto & solver : solvers)
+ {
+ const netlist_time ts = solver->solve(now);
+ plib::unused_var(ts);
+ }
- for (auto & solver : m_mat_solvers)
- if (solver->has_timestep_devices() || force_solve)
+ for (auto & solver : solvers)
solver->update_inputs();
- /* step circuit */
- if (!m_Q_step.net().is_queued())
- {
- m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_max_timestep));
+ /* step circuit */
+ if (!m_Q_step.net().is_queued())
+ {
+ m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_max_timestep));
+ }
}
-}
-
-template <class C>
-std::unique_ptr<matrix_solver_t> create_it(netlist_t &nl, pstring name, solver_parameters_t &params, std::size_t size)
-{
- typedef C solver;
- return plib::make_unique<solver>(nl, name, &params, size);
-}
-template <std::size_t m_N, std::size_t storage_N>
-std::unique_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername)
-{
- if (pstring("SOR_MAT").equals(m_method()))
+ template <class C>
+ pool_owned_ptr<matrix_solver_t> create_it(netlist_state_t &nl, pstring name, solver_parameters_t &params, std::size_t size)
{
- return create_it<matrix_solver_SOR_mat_t<m_N, storage_N>>(netlist(), solvername, m_params, size);
- //typedef matrix_solver_SOR_mat_t<m_N,storage_N> solver_sor_mat;
- //return plib::make_unique<solver_sor_mat>(netlist(), solvername, &m_params, size);
+ return pool().make_poolptr<C>(nl, name, &params, size);
}
- else if (pstring("MAT_CR").equals(m_method()))
+
+ template <typename FT, int SIZE>
+ pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername)
{
- if (size > 0) // GCR always outperforms MAT solver
+ if (m_method() == "SOR_MAT")
+ {
+ return create_it<matrix_solver_SOR_mat_t<FT, SIZE>>(state(), solvername, m_params, size);
+ //typedef matrix_solver_SOR_mat_t<m_N,storage_N> solver_sor_mat;
+ //return plib::make_unique<solver_sor_mat>(state(), solvername, &m_params, size);
+ }
+ else if (m_method() == "MAT_CR")
+ {
+ if (size > 0) // GCR always outperforms MAT solver
+ {
+ return create_it<matrix_solver_GCR_t<FT, SIZE>>(state(), solvername, m_params, size);
+ }
+ else
+ {
+ return create_it<matrix_solver_direct_t<FT, SIZE>>(state(), solvername, m_params, size);
+ }
+ }
+ else if (m_method() == "MAT")
+ {
+ return create_it<matrix_solver_direct_t<FT, SIZE>>(state(), solvername, m_params, size);
+ }
+ else if (m_method() == "SM")
+ {
+ /* Sherman-Morrison Formula */
+ return create_it<matrix_solver_sm_t<FT, SIZE>>(state(), solvername, m_params, size);
+ }
+ else if (m_method() == "W")
{
- typedef matrix_solver_GCR_t<m_N,storage_N> solver_mat;
- return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
+ /* Woodbury Formula */
+ return create_it<matrix_solver_w_t<FT, SIZE>>(state(), solvername, m_params, size);
+ }
+ else if (m_method() == "SOR")
+ {
+ return create_it<matrix_solver_SOR_t<FT, SIZE>>(state(), solvername, m_params, size);
+ }
+ else if (m_method() == "GMRES")
+ {
+ return create_it<matrix_solver_GMRES_t<FT, SIZE>>(state(), solvername, m_params, size);
}
else
{
- typedef matrix_solver_direct_t<m_N,storage_N> solver_mat;
- return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
+ log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method());
+ return pool_owned_ptr<matrix_solver_t>();
}
}
- else if (pstring("MAT").equals(m_method()))
- {
- typedef matrix_solver_direct_t<m_N,storage_N> solver_mat;
- return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
- }
- else if (pstring("SM").equals(m_method()))
- {
- /* Sherman-Morrison Formula */
- typedef matrix_solver_sm_t<m_N,storage_N> solver_mat;
- return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
- }
- else if (pstring("W").equals(m_method()))
- {
- /* Woodbury Formula */
- typedef matrix_solver_w_t<m_N,storage_N> solver_mat;
- return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size);
- }
- else if (pstring("SOR").equals(m_method()))
- {
- typedef matrix_solver_SOR_t<m_N,storage_N> solver_GS;
- return plib::make_unique<solver_GS>(netlist(), solvername, &m_params, size);
- }
- else if (pstring("GMRES").equals(m_method()))
- {
- typedef matrix_solver_GMRES_t<m_N,storage_N> solver_GMRES;
- return plib::make_unique<solver_GMRES>(netlist(), solvername, &m_params, size);
- }
- else
+
+ template <typename FT, int SIZE>
+ pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver_x(std::size_t size, const pstring &solvername)
{
- log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method());
- return nullptr;
+ if (SIZE > 0)
+ {
+ if (size == SIZE)
+ return create_solver<FT, SIZE>(size, solvername);
+ else
+ return this->create_solver_x<FT, SIZE-1>(size, solvername);
+ }
+ else
+ {
+ if (size * 2 > -SIZE )
+ return create_solver<FT, SIZE>(size, solvername);
+ else
+ return this->create_solver_x<FT, SIZE / 2>(size, solvername);
+ }
}
-}
-
-struct net_splitter
-{
- bool already_processed(analog_net_t *n)
+ struct net_splitter
{
- if (n->isRailNet())
- return true;
- for (auto & grp : groups)
- if (plib::container::contains(grp, n))
+
+ bool already_processed(const analog_net_t &n) const
+ {
+ /* no need to process rail nets - these are known variables */
+ if (n.isRailNet())
return true;
- return false;
- }
+ /* if it's already processed - no need to continue */
+ for (auto & grp : groups)
+ if (plib::container::contains(grp, &n))
+ return true;
+ return false;
+ }
- void process_net(analog_net_t *n)
- {
- if (n->num_cons() == 0)
- return;
- /* add the net */
- groups.back().push_back(n);
- for (auto &p : n->m_core_terms)
+ void process_net(analog_net_t &n)
{
- if (p->is_type(detail::terminal_type::TERMINAL))
+ /* ignore empty nets. FIXME: print a warning message */
+ if (n.num_cons() == 0)
+ return;
+ /* add the net */
+ groups.back().push_back(&n);
+ /* process all terminals connected to this net */
+ for (auto &term : n.core_terms())
{
- terminal_t *pt = static_cast<terminal_t *>(p);
- analog_net_t *other_net = &pt->m_otherterm->net();
- if (!already_processed(other_net))
- process_net(other_net);
+ /* only process analog terminals */
+ if (term->is_type(detail::terminal_type::TERMINAL))
+ {
+ auto *pt = static_cast<terminal_t *>(term);
+ /* check the connected terminal */
+ analog_net_t &connected_net = pt->connected_terminal()->net();
+ if (!already_processed(connected_net))
+ process_net(connected_net);
+ }
}
}
- }
- void run(netlist_t &netlist)
- {
- for (auto & net : netlist.m_nets)
+ void run(netlist_state_t &netlist)
{
- netlist.log().debug("processing {1}\n", net->name());
- if (!net->isRailNet() && net->num_cons() > 0)
+ for (auto & net : netlist.nets())
{
- netlist.log().debug(" ==> not a rail net\n");
- /* Must be an analog net */
- analog_net_t *n = static_cast<analog_net_t *>(net.get());
- if (!already_processed(n))
+ netlist.log().debug("processing {1}\n", net->name());
+ if (!net->isRailNet() && net->num_cons() > 0)
{
- groups.push_back(analog_net_t::list_t());
- process_net(n);
+ netlist.log().debug(" ==> not a rail net\n");
+ /* Must be an analog net */
+ auto &n = *static_cast<analog_net_t *>(net.get());
+ if (!already_processed(n))
+ {
+ groups.emplace_back(analog_net_t::list_t());
+ process_net(n);
+ }
}
}
}
- }
- std::vector<analog_net_t::list_t> groups;
-};
+ std::vector<analog_net_t::list_t> groups;
+ };
-void NETLIB_NAME(solver)::post_start()
-{
- const bool use_specific = true;
-
- m_params.m_pivot = m_pivot();
- m_params.m_accuracy = m_accuracy();
- /* FIXME: Throw when negative */
- m_params.m_gs_loops = static_cast<unsigned>(m_gs_loops());
- m_params.m_nr_loops = static_cast<unsigned>(m_nr_loops());
- m_params.m_nr_recalc_delay = netlist_time::from_double(m_nr_recalc_delay());
- m_params.m_dynamic_lte = m_dynamic_lte();
- m_params.m_gs_sor = m_gs_sor();
-
- m_params.m_min_timestep = m_dynamic_min_ts();
- m_params.m_dynamic_ts = (m_dynamic_ts() == 1 ? true : false);
- m_params.m_max_timestep = netlist_time::from_double(1.0 / m_freq()).as_double();
-
- if (m_params.m_dynamic_ts)
+ void NETLIB_NAME(solver)::post_start()
{
- m_params.m_max_timestep *= 1;//NL_FCONST(1000.0);
- }
- else
- {
- m_params.m_min_timestep = m_params.m_max_timestep;
- }
+ m_params.m_pivot = m_pivot();
+ m_params.m_accuracy = m_accuracy();
+ /* FIXME: Throw when negative */
+ m_params.m_gs_loops = static_cast<unsigned>(m_gs_loops());
+ m_params.m_nr_loops = static_cast<unsigned>(m_nr_loops());
+ m_params.m_nr_recalc_delay = netlist_time::from_double(m_nr_recalc_delay());
+ m_params.m_dynamic_lte = m_dynamic_lte();
+ m_params.m_gs_sor = m_gs_sor();
+
+ m_params.m_min_timestep = m_dynamic_min_ts();
+ m_params.m_dynamic_ts = (m_dynamic_ts() == 1 ? true : false);
+ m_params.m_max_timestep = netlist_time::from_double(1.0 / m_freq()).as_double();
- //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::)
+ m_params.m_use_gabs = m_use_gabs();
+ m_params.m_use_linear_prediction = m_use_linear_prediction();
+
+
+ if (m_params.m_dynamic_ts)
+ {
+ m_params.m_max_timestep *= 1;//NL_FCONST(1000.0);
+ }
+ else
+ {
+ m_params.m_min_timestep = m_params.m_max_timestep;
+ }
- // Override log statistics
- pstring p = plib::util::environment("NL_STATS", "");
- if (p != "")
- m_params.m_log_stats = p.as_long();
- else
- m_params.m_log_stats = m_log_stats();
+ //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::)
- log().verbose("Scanning net groups ...");
- // determine net groups
+ // Override log statistics
+ pstring p = plib::util::environment("NL_STATS", "");
+ if (p != "")
+ m_params.m_log_stats = plib::pstonum<decltype(m_params.m_log_stats)>(p);
+ else
+ m_params.m_log_stats = m_log_stats();
- net_splitter splitter;
+ log().verbose("Scanning net groups ...");
+ // determine net groups
- splitter.run(netlist());
+ net_splitter splitter;
- // setup the solvers
- log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), netlist().m_nets.size());
- for (auto & grp : splitter.groups)
- {
- std::unique_ptr<matrix_solver_t> ms;
- std::size_t net_count = grp.size();
- pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size());
+ splitter.run(state());
- switch (net_count)
+ // setup the solvers
+ log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size());
+ for (auto & grp : splitter.groups)
{
-#if 1
- case 1:
- if (use_specific)
- ms = plib::make_unique<matrix_solver_direct1_t>(netlist(), sname, &m_params);
- else
- ms = create_solver<1,1>(1, sname);
- break;
- case 2:
- if (use_specific)
- ms = plib::make_unique<matrix_solver_direct2_t>(netlist(), sname, &m_params);
- else
- ms = create_solver<2,2>(2, sname);
- break;
-#if 0
- case 3:
- ms = create_solver<3,3>(3, sname);
- break;
- case 4:
- ms = create_solver<4,4>(4, sname);
- break;
- case 5:
- ms = create_solver<5,5>(5, sname);
- break;
- case 6:
- ms = create_solver<6,6>(6, sname);
- break;
- case 7:
- ms = create_solver<7,7>(7, sname);
- break;
- case 8:
- ms = create_solver<8,8>(8, sname);
- break;
- case 9:
- ms = create_solver<9,9>(9, sname);
- break;
- case 10:
- ms = create_solver<10,10>(10, sname);
- break;
- case 11:
- ms = create_solver<11,11>(11, sname);
- break;
- case 12:
- ms = create_solver<12,12>(12, sname);
- break;
- case 15:
- ms = create_solver<15,15>(15, sname);
- break;
- case 31:
- ms = create_solver<31,31>(31, sname);
- break;
- case 35:
- ms = create_solver<35,35>(35, sname);
- break;
- case 43:
- ms = create_solver<43,43>(43, sname);
- break;
- case 49:
- ms = create_solver<49,49>(49, sname);
- break;
-#endif
-#if 0
- case 87:
- ms = create_solver<87,87>(87, sname);
- break;
-#endif
-#endif
- default:
- log().warning(MW_1_NO_SPECIFIC_SOLVER, net_count);
- if (net_count <= 8)
- {
- ms = create_solver<0, 8>(net_count, sname);
- }
- else if (net_count <= 16)
- {
- ms = create_solver<0,16>(net_count, sname);
- }
- else if (net_count <= 32)
- {
- ms = create_solver<0,32>(net_count, sname);
- }
- else
- if (net_count <= 64)
- {
- ms = create_solver<0,64>(net_count, sname);
- }
- else
- if (net_count <= 128)
- {
- ms = create_solver<0,128>(net_count, sname);
- }
- else
- {
- log().fatal(MF_1_NETGROUP_SIZE_EXCEEDED_1, 128);
- ms = nullptr; /* tease compilers */
- }
+ pool_owned_ptr<matrix_solver_t> ms;
+ std::size_t net_count = grp.size();
+ pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size());
- break;
- }
+ switch (net_count)
+ {
+ #if 1
+ case 1:
+ ms = pool().make_poolptr<matrix_solver_direct1_t<double>>(state(), sname, &m_params);
+ break;
+ case 2:
+ ms = pool().make_poolptr<matrix_solver_direct2_t<double>>(state(), sname, &m_params);
+ break;
+ case 3:
+ ms = create_solver<double, 3>(3, sname);
+ break;
+ case 4:
+ ms = create_solver<double, 4>(4, sname);
+ break;
+ case 5:
+ ms = create_solver<double, 5>(5, sname);
+ break;
+ case 6:
+ ms = create_solver<double, 6>(6, sname);
+ break;
+ case 7:
+ ms = create_solver<double, 7>(7, sname);
+ break;
+ case 8:
+ ms = create_solver<double, 8>(8, sname);
+ break;
+ case 9:
+ ms = create_solver<double, 9>(9, sname);
+ break;
+ case 10:
+ ms = create_solver<double, 10>(10, sname);
+ break;
+ #if 0
+ case 11:
+ ms = create_solver<double, 11>(11, sname);
+ break;
+ case 12:
+ ms = create_solver<double, 12>(12, sname);
+ break;
+ case 15:
+ ms = create_solver<double, 15>(15, sname);
+ break;
+ case 31:
+ ms = create_solver<double, 31>(31, sname);
+ break;
+ case 35:
+ ms = create_solver<double, 35>(35, sname);
+ break;
+ case 43:
+ ms = create_solver<double, 43>(43, sname);
+ break;
+ case 49:
+ ms = create_solver<double, 49>(49, sname);
+ break;
+ #endif
+ #if 1
+ case 86:
+ ms = create_solver<double,86>(86, sname);
+ break;
+ #endif
+ #endif
+ default:
+ log().warning(MW_1_NO_SPECIFIC_SOLVER, net_count);
+ if (net_count <= 8)
+ {
+ ms = create_solver<double, -8>(net_count, sname);
+ }
+ else if (net_count <= 16)
+ {
+ ms = create_solver<double, -16>(net_count, sname);
+ }
+ else if (net_count <= 32)
+ {
+ ms = create_solver<double, -32>(net_count, sname);
+ }
+ else
+ if (net_count <= 64)
+ {
+ ms = create_solver<double, -64>(net_count, sname);
+ }
+ else
+ if (net_count <= 128)
+ {
+ ms = create_solver<double, -128>(net_count, sname);
+ }
+ else
+ {
+ log().fatal(MF_1_NETGROUP_SIZE_EXCEEDED_1, 128);
+ return; /* tease compilers */
+ }
+ break;
+ }
- // FIXME ...
- ms->setup(grp);
+ // FIXME ...
+ ms->setup(grp);
- log().verbose("Solver {1}", ms->name());
- log().verbose(" ==> {2} nets", grp.size());
- log().verbose(" has {1} elements", ms->has_dynamic_devices() ? "dynamic" : "no dynamic");
- log().verbose(" has {1} elements", ms->has_timestep_devices() ? "timestep" : "no timestep");
- for (auto &n : grp)
- {
- log().verbose("Net {1}", n->name());
- for (const auto &pcore : n->m_core_terms)
+ log().verbose("Solver {1}", ms->name());
+ log().verbose(" ==> {2} nets", grp.size());
+ log().verbose(" has {1} elements", ms->has_dynamic_devices() ? "dynamic" : "no dynamic");
+ log().verbose(" has {1} elements", ms->has_timestep_devices() ? "timestep" : "no timestep");
+ for (auto &n : grp)
{
- log().verbose(" {1}", pcore->name());
+ log().verbose("Net {1}", n->name());
+ for (const auto &pcore : n->core_terms())
+ {
+ log().verbose(" {1}", pcore->name());
+ }
}
- }
- m_mat_solvers.push_back(std::move(ms));
+ m_mat_solvers_all.push_back(ms.get());
+ if (ms->has_timestep_devices())
+ m_mat_solvers_timestepping.push_back(ms.get());
+
+ m_mat_solvers.emplace_back(std::move(ms));
+ }
}
-}
-void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp)
-{
- for (auto & s : m_mat_solvers)
+ void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp)
{
- auto r = s->create_solver_code();
- mp[r.first] = r.second; // automatically overwrites identical names
+ for (auto & s : m_mat_solvers)
+ {
+ auto r = s->create_solver_code();
+ mp[r.first] = r.second; // automatically overwrites identical names
+ }
}
-}
- NETLIB_DEVICE_IMPL(solver)
+ NETLIB_DEVICE_IMPL(solver, "SOLVER", "FREQ")
- } //namespace devices
+} // namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h
index 986d14f401a..c9ec967a72a 100644
--- a/src/lib/netlist/solver/nld_solver.h
+++ b/src/lib/netlist/solver/nld_solver.h
@@ -8,11 +8,13 @@
#ifndef NLD_SOLVER_H_
#define NLD_SOLVER_H_
-#include <map>
-
-#include "../nl_base.h"
-#include "../plib/pstream.h"
+#include "netlist/nl_base.h"
#include "nld_matrix_solver.h"
+#include "plib/pstream.h"
+
+#include <map>
+#include <memory>
+#include <vector>
//#define ATTR_ALIGNED(N) __attribute__((aligned(N)))
#define ATTR_ALIGNED(N) ATTR_ALIGN
@@ -23,89 +25,97 @@
namespace netlist
{
- namespace devices
- {
-class NETLIB_NAME(solver);
-
-
-class matrix_solver_t;
-
-NETLIB_OBJECT(solver)
+namespace devices
{
- NETLIB_CONSTRUCTOR(solver)
- , m_fb_step(*this, "FB_step")
- , m_Q_step(*this, "Q_step")
- , m_freq(*this, "FREQ", 48000.0)
-
- /* iteration parameters */
- , m_gs_sor(*this, "SOR_FACTOR", 1.059)
- , m_method(*this, "METHOD", "MAT_CR")
- , m_accuracy(*this, "ACCURACY", 1e-7)
- , m_gs_loops(*this, "GS_LOOPS",9) // Gauss-Seidel loops
-
- /* general parameters */
- , m_gmin(*this, "GMIN", NETLIST_GMIN_DEFAULT)
- , m_pivot(*this, "PIVOT", 0) // 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_parallel(*this, "PARALLEL", 0)
-
- /* automatic time step */
- , m_dynamic_ts(*this, "DYNAMIC_TS", 0)
- , m_dynamic_lte(*this, "DYNAMIC_LTE", 1e-5) // diff/timestep
- , m_dynamic_min_ts(*this, "DYNAMIC_MIN_TIMESTEP", 1e-6) // nl_double timestep resolution
-
- , m_log_stats(*this, "LOG_STATS", 0) // log statistics on shutdown
- , m_params()
- {
- // internal staff
-
- connect(m_fb_step, m_Q_step);
- }
-
- virtual ~NETLIB_NAME(solver)() override;
+ class NETLIB_NAME(solver);
- void post_start();
- void stop();
+ class matrix_solver_t;
- inline nl_double gmin() { return m_gmin(); }
-
- void create_solver_code(std::map<pstring, pstring> &mp);
-
- NETLIB_UPDATEI();
- NETLIB_RESETI();
- // NETLIB_UPDATE_PARAMI();
-
-protected:
- logic_input_t m_fb_step;
- logic_output_t m_Q_step;
-
- param_double_t m_freq;
- param_double_t m_gs_sor;
- param_str_t m_method;
- param_double_t m_accuracy;
- param_int_t m_gs_loops;
- param_double_t m_gmin;
- param_logic_t m_pivot;
- param_int_t m_nr_loops;
- param_double_t m_nr_recalc_delay;
- param_int_t m_parallel;
- param_logic_t m_dynamic_ts;
- param_double_t m_dynamic_lte;
- param_double_t m_dynamic_min_ts;
-
- param_logic_t m_log_stats;
-
- std::vector<std::unique_ptr<matrix_solver_t>> m_mat_solvers;
-private:
-
- solver_parameters_t m_params;
-
- template <std::size_t m_N, std::size_t storage_N>
- std::unique_ptr<matrix_solver_t> create_solver(std::size_t size, const pstring &solvername);
-};
-
- } //namespace devices
+ NETLIB_OBJECT(solver)
+ {
+ NETLIB_CONSTRUCTOR(solver)
+ , m_fb_step(*this, "FB_step")
+ , m_Q_step(*this, "Q_step")
+ , m_freq(*this, "FREQ", 48000.0)
+
+ /* iteration parameters */
+ , m_gs_sor(*this, "SOR_FACTOR", 1.059)
+ , m_method(*this, "METHOD", "MAT_CR")
+ , m_accuracy(*this, "ACCURACY", 1e-7)
+ , m_gs_loops(*this, "GS_LOOPS", 9) // Gauss-Seidel loops
+
+ /* general parameters */
+ , 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_parallel(*this, "PARALLEL", 0)
+
+ /* automatic time step */
+ , m_dynamic_ts(*this, "DYNAMIC_TS", false)
+ , m_dynamic_lte(*this, "DYNAMIC_LTE", 1e-5) // diff/timestep
+ , m_dynamic_min_ts(*this, "DYNAMIC_MIN_TIMESTEP", 1e-6) // nl_double timestep resolution
+
+ /* special */
+ , m_use_gabs(*this, "USE_GABS", true)
+ , m_use_linear_prediction(*this, "USE_LINEAR_PREDICTION", false) // // savings are eaten up by effort
+
+ , m_log_stats(*this, "LOG_STATS", true) // log statistics on shutdown
+ , m_params()
+ {
+ // internal staff
+
+ connect(m_fb_step, m_Q_step);
+ }
+
+ void post_start();
+ void stop();
+
+ nl_double gmin() const { return m_gmin(); }
+
+ void create_solver_code(std::map<pstring, pstring> &mp);
+
+ NETLIB_UPDATEI();
+ NETLIB_RESETI();
+ // NETLIB_UPDATE_PARAMI();
+
+ private:
+ logic_input_t m_fb_step;
+ logic_output_t m_Q_step;
+
+ param_double_t m_freq;
+ param_double_t m_gs_sor;
+ param_str_t m_method;
+ param_double_t m_accuracy;
+ param_int_t m_gs_loops;
+ param_double_t m_gmin;
+ param_logic_t m_pivot;
+ param_int_t m_nr_loops;
+ param_double_t m_nr_recalc_delay;
+ param_int_t m_parallel;
+ param_logic_t m_dynamic_ts;
+ param_double_t m_dynamic_lte;
+ param_double_t m_dynamic_min_ts;
+
+ param_logic_t m_use_gabs;
+ param_logic_t m_use_linear_prediction;
+
+ param_logic_t m_log_stats;
+
+ std::vector<pool_owned_ptr<matrix_solver_t>> m_mat_solvers;
+ std::vector<matrix_solver_t *> m_mat_solvers_all;
+ std::vector<matrix_solver_t *> m_mat_solvers_timestepping;
+
+ solver_parameters_t m_params;
+
+ template <typename FT, int SIZE>
+ pool_owned_ptr<matrix_solver_t> create_solver(std::size_t size, const pstring &solvername);
+
+ template <typename FT, int SIZE>
+ pool_owned_ptr<matrix_solver_t> create_solver_x(std::size_t size, const pstring &solvername);
+ };
+
+} //namespace devices
} // namespace netlist
#endif /* NLD_SOLVER_H_ */
diff --git a/src/lib/netlist/solver/vector_base.h b/src/lib/netlist/solver/vector_base.h
deleted file mode 100644
index 28f5fa0dd44..00000000000
--- a/src/lib/netlist/solver/vector_base.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Couriersud
-/*
- * vector_base.h
- *
- * Base vector operations
- *
- */
-
-#ifndef VECTOR_BASE_H_
-#define VECTOR_BASE_H_
-
-#include <algorithm>
-#include "../plib/pconfig.h"
-
-#if 0
-template <unsigned storage_N>
-struct pvector
-{
- pvector(unsigned size)
- : m_N(size) { }
-
- unsigned size() {
- if (storage_N)
- }
-
- double m_V[storage_N];
-private:
- unsigned m_N;
-};
-#endif
-
-#if !defined(__clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif
-
-template<typename T, std::size_t N>
-inline static void vec_set (const std::size_t n, const T scalar, T (& RESTRICT v)[N])
-{
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- v[i] = scalar;
- else
- for ( std::size_t i = 0; i < N; i++ )
- v[i] = scalar;
-}
-
-template<typename T, std::size_t N>
-inline static T vec_mult (const std::size_t n, const T (& RESTRICT v1)[N], const T (& RESTRICT v2)[N] )
-{
- T value = 0.0;
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- value += v1[i] * v2[i];
- else
- for ( std::size_t i = 0; i < N; i++ )
- value += v1[i] * v2[i];
- return value;
-}
-
-template<typename T, std::size_t N>
-inline static T vec_mult2 (const std::size_t n, const T (& RESTRICT v)[N])
-{
- T value = 0.0;
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- value += v[i] * v[i];
- else
- for ( std::size_t i = 0; i < N; i++ )
- value += v[i] * v[i];
- return value;
-}
-
-template<typename T, std::size_t N>
-inline static void vec_mult_scalar (const std::size_t n, const T (& RESTRICT v)[N], const T & scalar, T (& RESTRICT result)[N])
-{
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- result[i] = scalar * v[i];
- else
- for ( std::size_t i = 0; i < N; i++ )
- result[i] = scalar * v[i];
-}
-
-template<typename T, std::size_t N>
-inline static void vec_add_mult_scalar (const std::size_t n, const T (& RESTRICT v)[N], const T scalar, T (& RESTRICT result)[N])
-{
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- result[i] = result[i] + scalar * v[i];
- else
- for ( std::size_t i = 0; i < N; i++ )
- result[i] = result[i] + scalar * v[i];
-}
-
-template<typename T>
-inline static void vec_add_mult_scalar_p(const std::size_t & n, const T * RESTRICT v, const T scalar, T * RESTRICT result)
-{
- for ( std::size_t i = 0; i < n; i++ )
- result[i] += scalar * v[i];
-}
-
-inline static void vec_add_ip(const std::size_t n, const double * RESTRICT v, double * RESTRICT result)
-{
- for ( std::size_t i = 0; i < n; i++ )
- result[i] += v[i];
-}
-
-template<typename T, std::size_t N>
-inline void vec_sub(const std::size_t n, const T (& RESTRICT v1)[N], const T (& RESTRICT v2)[N], T (& RESTRICT result)[N])
-{
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- result[i] = v1[i] - v2[i];
- else
- for ( std::size_t i = 0; i < N; i++ )
- result[i] = v1[i] - v2[i];
-}
-
-template<typename T, std::size_t N>
-inline void vec_scale(const std::size_t n, T (& RESTRICT v)[N], const T scalar)
-{
- if (n != N)
- for ( std::size_t i = 0; i < n; i++ )
- v[i] = scalar * v[i];
- else
- for ( std::size_t i = 0; i < N; i++ )
- v[i] = scalar * v[i];
-}
-
-inline double vec_maxabs(const std::size_t n, const double * RESTRICT v)
-{
- double ret = 0.0;
- for ( std::size_t i = 0; i < n; i++ )
- ret = std::max(ret, std::abs(v[i]));
-
- return ret;
-}
-#if !defined(__clang__) && !defined(_MSC_VER) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
-#pragma GCC diagnostic pop
-#endif
-
-#endif /* MAT_CR_H_ */
diff --git a/src/lib/netlist/tools/nl_convert.cpp b/src/lib/netlist/tools/nl_convert.cpp
index bedddba3cda..0acf5041c91 100644
--- a/src/lib/netlist/tools/nl_convert.cpp
+++ b/src/lib/netlist/tools/nl_convert.cpp
@@ -5,19 +5,20 @@
*
*/
+#include "plib/palloc.h"
+#include "nl_convert.h"
+#include "plib/putil.h"
+
#include <algorithm>
#include <cmath>
#include <unordered_map>
-#include "nl_convert.h"
-#include "../plib/palloc.h"
-#include "../plib/putil.h"
/* FIXME: temporarily defined here - should be in a file */
/* FIXME: family logic in netlist is convoluted, create
* define a model param on core device
*/
/* Format: external name,netlist device,model */
-static const pstring s_lib_map =
+static const char * s_lib_map =
"SN74LS00D, TTL_7400_DIP, 74LSXX\n"
"SN74LS04D, TTL_7404_DIP, 74LSXX\n"
"SN74ALS08D, TTL_7408_DIP, 74ALSXX\n"
@@ -42,14 +43,13 @@ using lib_map_t = std::unordered_map<pstring, lib_map_entry>;
static lib_map_t read_lib_map(const pstring &lm)
{
- plib::pistringstream istrm(lm);
- plib::putf8_reader reader(istrm);
+ auto reader = plib::putf8_reader(plib::pistringstream(lm));
lib_map_t m;
pstring line;
while (reader.readline(line))
{
std::vector<pstring> split(plib::psplit(line, ","));
- m[split[0].trim()] = { split[1].trim(), split[2].trim() };
+ m[plib::trim(split[0])] = { plib::trim(split[1]), plib::trim(split[2]) };
}
return m;
}
@@ -59,7 +59,7 @@ static lib_map_t read_lib_map(const pstring &lm)
-------------------------------------------------*/
nl_convert_base_t::nl_convert_base_t()
- : out(m_buf)
+ : out(&m_buf)
, m_numberchars("0123456789-+e.")
{
}
@@ -82,7 +82,7 @@ void nl_convert_base_t::add_ext_alias(const pstring &alias)
m_ext_alias.push_back(alias);
}
-void nl_convert_base_t::add_device(std::unique_ptr<dev_t> dev)
+void nl_convert_base_t::add_device(plib::unique_ptr<dev_t> dev)
{
for (auto & d : m_devs)
if (d->name() == dev->name())
@@ -106,7 +106,7 @@ void nl_convert_base_t::add_device(const pstring &atype, const pstring &aname)
add_device(plib::make_unique<dev_t>(atype, aname));
}
-void nl_convert_base_t::add_term(pstring netname, pstring termname)
+void nl_convert_base_t::add_term(const pstring &netname, const pstring &termname)
{
net_t * net = nullptr;
auto idx = m_nets.find(netname);
@@ -130,11 +130,11 @@ void nl_convert_base_t::add_term(pstring netname, pstring termname)
void nl_convert_base_t::dump_nl()
{
- for (std::size_t i=0; i<m_ext_alias.size(); i++)
+ for (auto & alias : m_ext_alias)
{
- net_t *net = m_nets[m_ext_alias[i]].get();
+ net_t *net = m_nets[alias].get();
// use the first terminal ...
- out("ALIAS({}, {})\n", m_ext_alias[i].c_str(), net->terminals()[0].c_str());
+ out("ALIAS({}, {})\n", alias.c_str(), net->terminals()[0].c_str());
// if the aliased net only has this one terminal connected ==> don't dump
if (net->terminals().size() == 1)
net->set_no_export();
@@ -166,7 +166,6 @@ void nl_convert_base_t::dump_nl()
net_t * net = i.second.get();
if (!net->is_no_export())
{
- //printf("Net {}\n", net->name().c_str());
out("NET_C({}", net->terminals()[0].c_str() );
for (std::size_t j=1; j<net->terminals().size(); j++)
{
@@ -185,25 +184,25 @@ const pstring nl_convert_base_t::get_nl_val(const double val)
{
{
int i = 0;
- while (pstring(m_units[i].m_unit, pstring::UTF8) != "-" )
+ while (pstring(m_units[i].m_unit) != "-" )
{
if (m_units[i].m_mult <= std::abs(val))
break;
i++;
}
- return plib::pfmt(pstring(m_units[i].m_func, pstring::UTF8))(val / m_units[i].m_mult);
+ return plib::pfmt(pstring(m_units[i].m_func))(val / m_units[i].m_mult);
}
}
double nl_convert_base_t::get_sp_unit(const pstring &unit)
{
int i = 0;
- while (pstring(m_units[i].m_unit, pstring::UTF8) != "-")
+ while (pstring(m_units[i].m_unit) != "-")
{
- if (pstring(m_units[i].m_unit, pstring::UTF8) == unit)
+ if (pstring(m_units[i].m_unit) == unit)
return m_units[i].m_mult;
i++;
}
- fprintf(stderr, "Unit %s unknown\n", unit.c_str());
+ plib::perrlogger("Unit {} unknown\n", unit);
return 0.0;
}
@@ -212,9 +211,9 @@ double nl_convert_base_t::get_sp_val(const pstring &sin)
std::size_t p = 0;
while (p < sin.length() && (m_numberchars.find(sin.substr(p, 1)) != pstring::npos))
++p;
- pstring val = sin.left(p);
+ pstring val = plib::left(sin, p);
pstring unit = sin.substr(p);
- double ret = get_sp_unit(unit) * val.as_double();
+ double ret = get_sp_unit(unit) * plib::pstonum<double>(val);
return ret;
}
@@ -252,11 +251,11 @@ void nl_convert_spice_t::convert(const pstring &contents)
pstring line = "";
- for (std::size_t i=0; i < spnl.size(); i++)
+ for (const auto &i : spnl)
{
// Basic preprocessing
- pstring inl = spnl[i].trim().ucase();
- if (inl.startsWith("+"))
+ pstring inl = plib::ucase(plib::trim(i));
+ if (plib::startsWith(inl, "+"))
line = line + inl.substr(1);
else
{
@@ -285,13 +284,13 @@ void nl_convert_spice_t::process_line(const pstring &line)
out("// {}\n", line.substr(1).c_str());
break;
case '.':
- if (tt[0].equals(".SUBCKT"))
+ if (tt[0] == ".SUBCKT")
{
out("NETLIST_START({})\n", tt[1].c_str());
for (std::size_t i=2; i<tt.size(); i++)
add_ext_alias(tt[i]);
}
- else if (tt[0].equals(".ENDS"))
+ else if (tt[0] == ".ENDS")
{
dump_nl();
out("NETLIST_END()\n");
@@ -301,15 +300,16 @@ void nl_convert_spice_t::process_line(const pstring &line)
break;
case 'Q':
{
- bool cerr = false;
/* check for fourth terminal ... should be numeric net
* including "0" or start with "N" (ltspice)
*/
- ATTR_UNUSED long nval(tt[4].as_long(&cerr));
pstring model;
pstring pins ="CBE";
+ bool err;
+ auto nval = plib::pstonum_ne<long>(tt[4], err);
+ plib::unused_var(nval);
- if ((!cerr || tt[4].startsWith("N")) && tt.size() > 5)
+ if ((err || plib::startsWith(tt[4], "N")) && tt.size() > 5)
model = tt[5];
else
model = tt[4];
@@ -317,8 +317,8 @@ void nl_convert_spice_t::process_line(const pstring &line)
if (m.size() == 2)
{
if (m[1].length() != 4)
- fprintf(stderr, "error with model desc %s\n", model.c_str());
- pins = m[1].left(3);
+ plib::perrlogger("error with model desc {}\n", model);
+ pins = plib::left(m[1], 3);
}
add_device("QBJT_EB", tt[0], m[0]);
add_term(tt[1], tt[0] + "." + pins.at(0));
@@ -327,7 +327,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
}
break;
case 'R':
- if (tt[0].startsWith("RV"))
+ if (plib::startsWith(tt[0], "RV"))
{
val = get_sp_val(tt[4]);
add_device("POT", tt[0], val);
@@ -351,7 +351,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
break;
case 'V':
// just simple Voltage sources ....
- if (tt[2].equals("0"))
+ if (tt[2] == "0")
{
val = get_sp_val(tt[3]);
add_device("ANALOG_INPUT", tt[0], val);
@@ -359,7 +359,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
//add_term(tt[2], tt[0] + ".2");
}
else
- fprintf(stderr, "Voltage Source %s not connected to GND\n", tt[0].c_str());
+ plib::perrlogger("Voltage Source {} not connected to GND\n", tt[0]);
break;
case 'I': // Input pin special notation
{
@@ -381,7 +381,7 @@ void nl_convert_spice_t::process_line(const pstring &line)
// last element is component type
// FIXME: Parameter
- pstring xname = tt[0].replace_all(".", "_");
+ pstring xname = plib::replace_all(tt[0], pstring("."), pstring("_"));
pstring tname = "TTL_" + tt[tt.size()-1] + "_DIP";
add_device(tname, xname);
for (std::size_t i=1; i < tt.size() - 1; i++)
@@ -401,16 +401,16 @@ void nl_convert_spice_t::process_line(const pstring &line)
Eagle converter
-------------------------------------------------*/
-nl_convert_eagle_t::tokenizer::tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &strm)
- : plib::ptokenizer(strm)
+nl_convert_eagle_t::tokenizer::tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &&strm)
+ : plib::ptokenizer(std::move(strm))
, m_convert(convert)
{
- set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-");
- set_number_chars(".0123456789", "0123456789eE-."); //FIXME: processing of numbers
- set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13));
- /* FIXME: gnetlist doesn't print comments */
- set_comment("/*", "*/", "//");
- set_string_char('\'');
+ this->identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-")
+ .number_chars(".0123456789", "0123456789eE-.") //FIXME: processing of numbers
+ .whitespace(pstring("") + ' ' + static_cast<char>(9) + static_cast<char>(10) + static_cast<char>(13))
+ /* FIXME: gnetlist doesn't print comments */
+ .comment("/*", "*/", "//")
+ .string_char('\'');
m_tok_ADD = register_token("ADD");
m_tok_VALUE = register_token("VALUE");
m_tok_SIGNAL = register_token("SIGNAL");
@@ -428,9 +428,8 @@ void nl_convert_eagle_t::tokenizer::verror(const pstring &msg, int line_num, con
//FIXME: should accept a stream as well
void nl_convert_eagle_t::convert(const pstring &contents)
{
- plib::pistringstream istrm(contents);
- plib::putf8_reader reader(istrm);
- tokenizer tok(*this, reader);
+
+ tokenizer tok(*this, plib::putf8_reader(plib::pistringstream(contents)));
out("NETLIST_START(dummy)\n");
add_term("GND", "GND");
@@ -487,12 +486,12 @@ void nl_convert_eagle_t::convert(const pstring &contents)
}
break;
case 'P':
- if (sval.ucase() == "HIGH")
+ if (plib::ucase(sval) == "HIGH")
add_device("TTL_INPUT", name, 1);
- else if (sval.ucase() == "LOW")
+ else if (plib::ucase(sval) == "LOW")
add_device("TTL_INPUT", name, 0);
else
- add_device("ANALOG_INPUT", name, sval.as_double());
+ add_device("ANALOG_INPUT", name, plib::pstonum<double>(sval));
add_pin_alias(name, "1", "Q");
break;
case 'D':
@@ -538,16 +537,16 @@ void nl_convert_eagle_t::convert(const pstring &contents)
RINF converter
-------------------------------------------------*/
-nl_convert_rinf_t::tokenizer::tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &strm)
- : plib::ptokenizer(strm)
+nl_convert_rinf_t::tokenizer::tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &&strm)
+ : plib::ptokenizer(std::move(strm))
, m_convert(convert)
{
- set_identifier_chars(".abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-");
- set_number_chars("0123456789", "0123456789eE-."); //FIXME: processing of numbers
- set_whitespace(pstring("").cat(' ').cat(9).cat(10).cat(13));
- /* FIXME: gnetlist doesn't print comments */
- set_comment("","","//"); // FIXME:needs to be confirmed
- set_string_char('"');
+ this->identifier_chars(".abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-")
+ .number_chars("0123456789", "0123456789eE-.") //FIXME: processing of numbers
+ .whitespace(pstring("") + ' ' + static_cast<char>(9) + static_cast<char>(10) + static_cast<char>(13))
+ /* FIXME: gnetlist doesn't print comments */
+ .comment("","","//") // FIXME:needs to be confirmed
+ .string_char('"');
m_tok_HEA = register_token(".HEA");
m_tok_APP = register_token(".APP");
m_tok_TIM = register_token(".TIM");
@@ -577,9 +576,7 @@ void nl_convert_rinf_t::tokenizer::verror(const pstring &msg, int line_num, cons
void nl_convert_rinf_t::convert(const pstring &contents)
{
- plib::pistringstream istrm(contents);
- plib::putf8_reader reader(istrm);
- tokenizer tok(*this, reader);
+ tokenizer tok(*this, plib::putf8_reader(plib::pistringstream(contents)));
auto lm = read_lib_map(s_lib_map);
out("NETLIST_START(dummy)\n");
diff --git a/src/lib/netlist/tools/nl_convert.h b/src/lib/netlist/tools/nl_convert.h
index d3881320678..5cdae8e372d 100644
--- a/src/lib/netlist/tools/nl_convert.h
+++ b/src/lib/netlist/tools/nl_convert.h
@@ -10,10 +10,12 @@
#ifndef NL_CONVERT_H_
#define NL_CONVERT_H_
+#include "plib/plists.h"
+#include "plib/pparser.h"
+#include "plib/pstring.h"
+#include "plib/ptypes.h"
+
#include <memory>
-#include "../plib/pstring.h"
-#include "../plib/plists.h"
-#include "../plib/pparser.h"
/*-------------------------------------------------
convert - convert a spice netlist
@@ -23,6 +25,8 @@ class nl_convert_base_t
{
public:
+ COPYASSIGNMOVE(nl_convert_base_t, delete)
+
virtual ~nl_convert_base_t();
const pstring &result() { return m_buf.str(); }
@@ -40,7 +44,7 @@ protected:
void add_device(const pstring &atype, const pstring &aname, double aval);
void add_device(const pstring &atype, const pstring &aname);
- void add_term(pstring netname, pstring termname);
+ void add_term(const pstring &netname, const pstring &termname);
void dump_nl();
@@ -55,8 +59,8 @@ private:
struct net_t
{
public:
- explicit net_t(const pstring &aname)
- : m_name(aname), m_no_export(false) {}
+ explicit net_t(pstring aname)
+ : m_name(std::move(aname)), m_no_export(false) {}
const pstring &name() { return m_name;}
std::vector<pstring> &terminals() { return m_terminals; }
@@ -72,16 +76,28 @@ private:
struct dev_t
{
public:
- dev_t(const pstring &atype, const pstring &aname, const pstring &amodel)
- : m_type(atype), m_name(aname), m_model(amodel), m_val(0), m_has_val(false)
+ dev_t(pstring atype, pstring aname, pstring amodel)
+ : m_type(std::move(atype))
+ , m_name(std::move(aname))
+ , m_model(std::move(amodel))
+ , m_val(0)
+ , m_has_val(false)
{}
- dev_t(const pstring &atype, const pstring &aname, double aval)
- : m_type(atype), m_name(aname), m_model(""), m_val(aval), m_has_val(true)
+ dev_t(pstring atype, pstring aname, double aval)
+ : m_type(std::move(atype))
+ , m_name(std::move(aname))
+ , m_model("")
+ , m_val(aval)
+ , m_has_val(true)
{}
- dev_t(const pstring &atype, const pstring &aname)
- : m_type(atype), m_name(aname), m_model(""), m_val(0.0), m_has_val(false)
+ dev_t(pstring atype, pstring aname)
+ : m_type(std::move(atype))
+ , m_name(std::move(aname))
+ , m_model("")
+ , m_val(0.0)
+ , m_has_val(false)
{}
const pstring &name() { return m_name;}
@@ -109,8 +125,8 @@ private:
struct pin_alias_t
{
public:
- pin_alias_t(const pstring &name, const pstring &alias)
- : m_name(name), m_alias(alias)
+ pin_alias_t(pstring name, pstring alias)
+ : m_name(std::move(name)), m_alias(std::move(alias))
{}
const pstring &name() { return m_name; }
const pstring &alias() { return m_alias; }
@@ -121,14 +137,14 @@ private:
private:
- void add_device(std::unique_ptr<dev_t> dev);
+ void add_device(plib::unique_ptr<dev_t> dev);
plib::postringstream m_buf;
- std::vector<std::unique_ptr<dev_t>> m_devs;
- std::unordered_map<pstring, std::unique_ptr<net_t> > m_nets;
+ std::vector<plib::unique_ptr<dev_t>> m_devs;
+ std::unordered_map<pstring, plib::unique_ptr<net_t> > m_nets;
std::vector<pstring> m_ext_alias;
- std::unordered_map<pstring, std::unique_ptr<pin_alias_t>> m_pins;
+ std::unordered_map<pstring, plib::unique_ptr<pin_alias_t>> m_pins;
static unit_t m_units[];
pstring m_numberchars;
@@ -140,9 +156,6 @@ class nl_convert_spice_t : public nl_convert_base_t
public:
nl_convert_spice_t() : nl_convert_base_t() {}
- virtual ~nl_convert_spice_t() override
- {
- }
void convert(const pstring &contents) override;
@@ -159,14 +172,11 @@ class nl_convert_eagle_t : public nl_convert_base_t
public:
nl_convert_eagle_t() : nl_convert_base_t() {}
- virtual ~nl_convert_eagle_t() override
- {
- }
class tokenizer : public plib::ptokenizer
{
public:
- tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &strm);
+ tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &&strm);
token_id_t m_tok_ADD;
token_id_t m_tok_VALUE;
@@ -175,7 +185,7 @@ public:
protected:
- virtual void verror(const pstring &msg, int line_num, const pstring &line) override;
+ void verror(const pstring &msg, int line_num, const pstring &line) override;
private:
nl_convert_eagle_t &m_convert;
@@ -195,14 +205,11 @@ class nl_convert_rinf_t : public nl_convert_base_t
public:
nl_convert_rinf_t() : nl_convert_base_t() {}
- virtual ~nl_convert_rinf_t() override
- {
- }
class tokenizer : public plib::ptokenizer
{
public:
- tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &strm);
+ tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &&strm);
token_id_t m_tok_HEA;
token_id_t m_tok_APP;
@@ -216,7 +223,7 @@ public:
protected:
- virtual void verror(const pstring &msg, int line_num, const pstring &line) override;
+ void verror(const pstring &msg, int line_num, const pstring &line) override;
private:
nl_convert_rinf_t &m_convert;