diff options
Diffstat (limited to 'src/lib/netlist')
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 >) 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 >, 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 ¶m) { 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 ¶m) { set(m_param, param); } + const T operator()() const NL_NOEXCEPT { return m_param; } + void setTo(const T ¶m) { 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 ¶m) { 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 ¶m) 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 ¶m) = delete; protected: - virtual void changed() override; + void changed() override; nl_double model_value(const pstring &entity) /*const*/; private: - /* hide this */ - void setTo(const pstring ¶m) = 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 ¶m, 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 ¶m, 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 ¶m) -{ - 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 ¶m, const double value) +void setup_t::register_param_t(const pstring &name, param_t ¶m) { - 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 ¶m, 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 ¶m); - 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 ¶m, const pstring &value); void register_param(const pstring ¶m, 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 ¶m_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 ¶m); + + 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 ¶m_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 > = 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 ¶ms, std::size_t size) -{ - typedef C solver; - return plib::make_unique<solver>(nl, name, ¶ms, 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 ¶ms, 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, ¶ms, 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; |