diff options
Diffstat (limited to 'src/lib/netlist')
202 files changed, 8552 insertions, 11668 deletions
diff --git a/src/lib/netlist/analog/nld_bjt.cpp b/src/lib/netlist/analog/nld_bjt.cpp index aef920635fe..6f4a2db86bf 100644 --- a/src/lib/netlist/analog/nld_bjt.cpp +++ b/src/lib/netlist/analog/nld_bjt.cpp @@ -5,49 +5,47 @@ * */ -#include "netlist/solver/nld_solver.h" -#include "netlist/nl_setup.h" +#include "../solver/nld_solver.h" #include "nlid_twoterm.h" - +#include "../nl_setup.h" #include <cmath> namespace netlist { -namespace analog -{ - using constants = plib::constants<nl_double>; + namespace analog + { - class diode +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) { - 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; - }; + 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); } - // ----------------------------------------------------------------------------- - // nld_Q - Base classes - // ----------------------------------------------------------------------------- +private: + nl_double m_Is; + nl_double m_VT; + nl_double m_VT_inv; +}; + +// ----------------------------------------------------------------------------- +// nld_Q - Base classes +// ----------------------------------------------------------------------------- /*! Class representing the bjt model paramers. * @@ -75,7 +73,7 @@ namespace analog * | | RBM | minimum base resistance at high currents | | RB | 10 | * | * | | RE | emitter resistance | | 0 | 1 | * | * | | RC | collector resistance | | 0 | 10 | * | - * | Y | CJE | B-E zero-bias depletion capacitance | F | 0 | 2pF | * | + * | | 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 | | @@ -83,7 +81,7 @@ namespace analog * | | 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 | | | - * | Y | CJC | B-C zero-bias depletion capacitance | F | 0 | 2pF | * | + * | | 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 | | | @@ -97,369 +95,343 @@ namespace analog * | | 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_CJE(*this, "CJE") - , m_CJC(*this, "CJC") + , m_IS(*this, "IS") + , m_BF(*this, "BF") + , m_NF(*this, "NF") + , m_BR(*this, "BR") + , m_NR(*this, "NR") {} - 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 - + 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 }; // Have a common start for transistors - 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_OBJECT(Q) +{ +public: + enum q_type { + BJT_NPN, + BJT_PNP }; - NETLIB_OBJECT_DERIVED(QBJT, Q) + NETLIB_CONSTRUCTOR(Q) + , m_model(*this, "MODEL", "NPN") + , m_qtype(BJT_NPN) { - public: - NETLIB_CONSTRUCTOR_DERIVED(QBJT, Q) - { } + } - protected: + NETLIB_IS_DYNAMIC(true) - private: - }; + //NETLIB_RESETI(); + NETLIB_UPDATEI(); + + 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: + bjt_model_t m_model; +private: + q_type m_qtype; +}; +NETLIB_OBJECT_DERIVED(QBJT, Q) +{ +public: + NETLIB_CONSTRUCTOR_DERIVED(QBJT, Q) + { } +protected: - // ----------------------------------------------------------------------------- - // nld_QBJT_switch - // ----------------------------------------------------------------------------- +private: +}; - /* - * + - 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(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 - // ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- +// nld_QBJT_switch +// ----------------------------------------------------------------------------- - NETLIB_OBJECT_DERIVED(QBJT_EB, QBJT) +/* + * + - 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) { - 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_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); - // ---------------------------------------------------------------------------------------- - // nld_Q - // ---------------------------------------------------------------------------------------- + connect(m_RB.m_N, m_RC.m_N); - NETLIB_UPDATE(Q) - { - // netlist().solver()->schedule1(); + connect(m_RB.m_P, m_BC_dummy.m_P); + connect(m_RC.m_P, m_BC_dummy.m_N); } - // ---------------------------------------------------------------------------------------- - // nld_QBJT_switch - // ---------------------------------------------------------------------------------------- + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + NETLIB_UPDATE_TERMINALSI(); + nld_twoterm m_RB; + nld_twoterm m_RC; - NETLIB_RESET(QBJT_switch) - { - NETLIB_NAME(Q)::reset(); + // FIXME: this is needed so we have all terminals belong to one net list - m_state_on = 0; + nld_twoterm m_BC_dummy; - m_RB.set_G_V_I(exec().gmin(), 0.0, 0.0); - m_RC.set_G_V_I(exec().gmin(), 0.0, 0.0); +protected: - m_BC_dummy.set_G_V_I(exec().gmin() / 10.0, 0.0, 0.0); - } + 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 +// ----------------------------------------------------------------------------- - NETLIB_UPDATE(QBJT_switch) + +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) { - 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 + 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); } +protected: - 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_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); + NETLIB_UPDATE_TERMINALSI(); - set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP); + generic_diode m_gD_BC; + generic_diode m_gD_BE; - nl_double alpha = BF / (1.0 + BF); +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 - diode d(IS, NF); + nl_double m_alpha_f; + nl_double m_alpha_r; - // Assume 5mA Collector current for switch operation +}; - m_V = d.V(0.005 / alpha); - /* Base current is 0.005 / beta - * as a rough estimate, we just scale the conductance down */ +// ---------------------------------------------------------------------------------------- +// nld_Q +// ---------------------------------------------------------------------------------------- - m_gB = 1.0 / (m_V/(0.005 / BF)); +NETLIB_UPDATE(Q) +{ +// netlist().solver()->schedule1(); +} - //m_gB = d.gI(0.005 / alpha); +// ---------------------------------------------------------------------------------------- +// nld_QBJT_switch +// ---------------------------------------------------------------------------------------- - if (m_gB < exec().gmin()) - m_gB = exec().gmin(); - m_gC = d.gI(0.005); // very rough estimate - } - 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; - } - } +NETLIB_RESET(QBJT_switch) +{ + NETLIB_NAME(Q)::reset(); + m_state_on = 0; - // ---------------------------------------------------------------------------------------- - // nld_Q - Ebers Moll - // ---------------------------------------------------------------------------------------- + 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(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(); - 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); - } +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 +} - } - NETLIB_UPDATE_TERMINALS(QBJT_EB) +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); + + set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP); + + nl_double alpha = BF / (1.0 + BF); + + diode d(IS, NF); + + // Assume 5mA Collector current for switch operation + + m_V = d.V(0.005 / alpha); + + /* Base current is 0.005 / beta + * as a rough estimate, we just scale the conductance down */ + + m_gB = 1.0 / (m_V/(0.005 / BF)); + + //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 +} + +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 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); + 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; } +} - 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); +// ---------------------------------------------------------------------------------------- +// nld_Q - Ebers Moll +// ---------------------------------------------------------------------------------------- - 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); +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(); +} - 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()); - } +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); -} // namespace analog + set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP); -namespace devices { - NETLIB_DEVICE_IMPL_NS(analog, QBJT_EB, "QBJT_EB", "MODEL") - NETLIB_DEVICE_IMPL_NS(analog, QBJT_switch, "QBJT_SW", "MODEL") -} // namespace devices + 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()); +} + + } //namespace analog + + namespace devices { + NETLIB_DEVICE_IMPL_NS(analog, QBJT_EB) + NETLIB_DEVICE_IMPL_NS(analog, QBJT_switch) + } } // namespace netlist diff --git a/src/lib/netlist/analog/nld_bjt.h b/src/lib/netlist/analog/nld_bjt.h index 3a8478f19f7..9e1f82afbaa 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ----------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/analog/nld_fourterm.h b/src/lib/netlist/analog/nld_fourterm.h index 66c47c0be29..b4bb5db1059 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp deleted file mode 100644 index ea717fdefee..00000000000 --- a/src/lib/netlist/analog/nld_mosfet.cpp +++ /dev/null @@ -1,488 +0,0 @@ -// 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 deleted file mode 100644 index 32011d709d8..00000000000 --- a/src/lib/netlist/analog/nld_mosfet.h +++ /dev/null @@ -1,21 +0,0 @@ -// 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 8c3c655bfa9..5f55a26f5d0 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 "netlist/nl_base.h" -#include "netlist/nl_errstr.h" -#include "nlid_fourterm.h" +#include "../nl_base.h" +#include "../nl_errstr.h" #include "nlid_twoterm.h" +#include "nlid_fourterm.h" #include <cmath> @@ -129,10 +129,10 @@ namespace netlist } else if (m_type == 3) { - 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)"); + 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)"); //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.reset(); + m_G1.do_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->reset(); - m_DP->reset(); - m_DN->reset(); - m_CP->reset(); - m_RP.reset(); + m_EBUF->do_reset(); + m_DP->do_reset(); + m_DN->do_reset(); + m_CP->do_reset(); + m_RP.do_reset(); m_EBUF->m_G.setTo(1.0); m_EBUF->m_RO.setTo(m_model.m_RO); @@ -239,6 +239,6 @@ namespace netlist } //namespace analog namespace devices { - NETLIB_DEVICE_IMPL_NS(analog, opamp, "OPAMP", "MODEL") - } // namespace devices + NETLIB_DEVICE_IMPL_NS(analog, opamp) + } } // namespace netlist diff --git a/src/lib/netlist/analog/nld_opamps.h b/src/lib/netlist/analog/nld_opamps.h index 4a07f646587..d05a19aa3dc 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/analog/nld_switches.cpp b/src/lib/netlist/analog/nld_switches.cpp index 0e62fe13952..1575551f260 100644 --- a/src/lib/netlist/analog/nld_switches.cpp +++ b/src/lib/netlist/analog/nld_switches.cpp @@ -6,13 +6,10 @@ */ #include "nlid_twoterm.h" -#include "netlist/nl_base.h" -#include "netlist/nl_factory.h" -#include "netlist/solver/nld_solver.h" +#include "../nl_base.h" +#include "../nl_factory.h" -/* FIXME : convert to parameters */ - -#define R_OFF (1.0 / exec().gmin()) +#define R_OFF (1.0 / netlist().gmin()) #define R_ON 0.01 namespace netlist @@ -27,7 +24,7 @@ namespace netlist { NETLIB_CONSTRUCTOR(switch1) , m_R(*this, "R") - , m_POS(*this, "POS", false) + , m_POS(*this, "POS", 0) { register_subalias("1", m_R.m_P); register_subalias("2", m_R.m_N); @@ -49,11 +46,6 @@ namespace netlist NETLIB_UPDATE(switch1) { - } - - NETLIB_UPDATE_PARAM(switch1) - { - m_R.solve_now(); if (!m_POS()) { m_R.set_R(R_OFF); @@ -62,8 +54,13 @@ namespace netlist { m_R.set_R(R_ON); } - m_R.solve_later(); + m_R.update_dev(); + } + + NETLIB_UPDATE_PARAM(switch1) + { + update(); } // ---------------------------------------------------------------------------------------- @@ -75,7 +72,7 @@ namespace netlist NETLIB_CONSTRUCTOR(switch2) , m_R1(*this, "R1") , m_R2(*this, "R2") - , m_POS(*this, "POS", false) + , m_POS(*this, "POS", 0) { connect(m_R1.m_N, m_R2.m_N); @@ -113,31 +110,19 @@ namespace netlist m_R2.set_R(R_ON); } - //m_R1.update_dev(time); - //m_R2.update_dev(time); + m_R1.update_dev(); + m_R2.update_dev(); } NETLIB_UPDATE_PARAM(switch2) { - 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(); + update(); } } //namespace analog namespace devices { - NETLIB_DEVICE_IMPL_NS(analog, switch1, "SWITCH", "") - NETLIB_DEVICE_IMPL_NS(analog, switch2, "SWITCH2", "") - } // namespace devices + NETLIB_DEVICE_IMPL_NS(analog, switch1) + NETLIB_DEVICE_IMPL_NS(analog, switch2) + } } // namespace netlist diff --git a/src/lib/netlist/analog/nld_switches.h b/src/lib/netlist/analog/nld_switches.h index 7aa31c925ae..3cd561f84b1 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/analog/nld_twoterm.h b/src/lib/netlist/analog/nld_twoterm.h index b175f40af97..d5cf6f6d228 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ----------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/analog/nlid_fourterm.cpp b/src/lib/netlist/analog/nlid_fourterm.cpp index 7fa6a2f3809..aa2723fe8e1 100644 --- a/src/lib/netlist/analog/nlid_fourterm.cpp +++ b/src/lib/netlist/analog/nlid_fourterm.cpp @@ -5,8 +5,8 @@ * */ -#include "netlist/solver/nld_solver.h" -#include "netlist/nl_factory.h" +#include "../solver/nld_solver.h" +#include "../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 = plib::constants<nl_double>::one() / m_RI(); + const nl_double GI = NL_FCONST(1.0) / m_RI(); - m_IP.set_conductivity(GI); - m_IN.set_conductivity(GI); + m_IP.set(GI); + m_IN.set(GI); - 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_OP.set(m_mult, NL_FCONST(0.0)); + m_OP1.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()); + m_ON.set(-m_mult, NL_FCONST(0.0)); + m_ON1.set(m_mult, NL_FCONST(0.0)); } NETLIB_UPDATE(VCCS) @@ -63,6 +63,11 @@ 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 @@ -79,11 +84,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_go_gt_I(-beta, plib::constants<nl_double>::zero(), I); - m_OP1.set_go_gt(beta, plib::constants<nl_double>::zero()); + m_OP.set(beta, NL_FCONST(0.0), I); + m_OP1.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()); + m_ON.set(-beta, NL_FCONST(0.0), -I); + m_ON1.set(beta, NL_FCONST(0.0)); } // ---------------------------------------------------------------------------------------- @@ -100,25 +105,30 @@ NETLIB_UPDATE_PARAM(CCCS) NETLIB_NAME(VCCS)::update_param(); } +NETLIB_UPDATE(CCCS) +{ + NETLIB_NAME(VCCS)::update(); +} + // ---------------------------------------------------------------------------------------- // nld_VCVS // ---------------------------------------------------------------------------------------- NETLIB_RESET(VCVS) { - m_gfac = plib::constants<nl_double>::one() / m_RO(); + m_gfac = NL_FCONST(1.0) / m_RO(); NETLIB_NAME(VCCS)::reset(); - m_OP2.set_conductivity(plib::constants<nl_double>::one() / m_RO()); - m_ON2.set_conductivity(plib::constants<nl_double>::one() / m_RO()); + m_OP2.set(NL_FCONST(1.0) / m_RO()); + m_ON2.set(NL_FCONST(1.0) / m_RO()); } } //namespace analog namespace devices { - 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 + NETLIB_DEVICE_IMPL_NS(analog, VCVS) + NETLIB_DEVICE_IMPL_NS(analog, VCCS) + NETLIB_DEVICE_IMPL_NS(analog, CCCS) + NETLIB_DEVICE_IMPL_NS(analog, LVCCS) + } } // namespace netlist diff --git a/src/lib/netlist/analog/nlid_fourterm.h b/src/lib/netlist/analog/nlid_fourterm.h index 5ca6a747116..641fc72427b 100644 --- a/src/lib/netlist/analog/nlid_fourterm.h +++ b/src/lib/netlist/analog/nlid_fourterm.h @@ -8,8 +8,7 @@ #ifndef NLID_FOURTERM_H_ #define NLID_FOURTERM_H_ -#include "netlist/nl_base.h" -#include "plib/putil.h" +#include "../nl_base.h" namespace netlist { namespace analog { @@ -41,32 +40,39 @@ namespace netlist { NETLIB_CONSTRUCTOR(VCCS) , m_G(*this, "G", 1.0) , m_RI(*this, "RI", 1e9) - , 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_OP(*this, "OP") + , m_ON(*this, "ON") + , m_IP(*this, "IP") + , m_IN(*this, "IN") + , m_OP1(*this, "_OP1") + , m_ON1(*this, "_ON1") , 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 = plib::constants<nl_double>::one(); + m_gfac = NL_FCONST(1.0); } - 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; @@ -92,14 +98,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; }; @@ -131,13 +137,12 @@ namespace netlist { public: NETLIB_CONSTRUCTOR_DERIVED(CCCS, VCCS) { - m_gfac = plib::constants<nl_double>::one() / m_RI(); + m_gfac = NL_FCONST(1.0) / m_RI(); } - NETLIB_RESETI(); - protected: - //NETLIB_UPDATEI(); + NETLIB_UPDATEI(); + NETLIB_RESETI(); NETLIB_UPDATE_PARAMI(); }; @@ -175,28 +180,29 @@ namespace netlist { public: NETLIB_CONSTRUCTOR_DERIVED(VCVS, VCCS) , m_RO(*this, "RO", 1.0) - , m_OP2(*this, "_OP2", &m_ON2) - , m_ON2(*this, "_ON2", &m_OP2) + , m_OP2(*this, "_OP2") + , m_ON2(*this, "_ON2") { + 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; - private: + protected: //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 5019c98c0e4..f54c2b3e68f 100644 --- a/src/lib/netlist/analog/nlid_twoterm.cpp +++ b/src/lib/netlist/analog/nlid_twoterm.cpp @@ -5,10 +5,10 @@ * */ -#include "netlist/solver/nld_solver.h" +#include "../solver/nld_solver.h" -#include "netlist/nl_factory.h" #include "nlid_twoterm.h" +#include "../nl_factory.h" #include <cmath> @@ -16,34 +16,81 @@ namespace netlist { namespace analog { - // ---------------------------------------------------------------------------------------- -// nld_twoterm +// generic_diode // ---------------------------------------------------------------------------------------- -void NETLIB_NAME(twoterm)::solve_now() +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) { - /* 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(); + set_param(1e-15, 1, 1e-15); } -void NETLIB_NAME(twoterm)::solve_later(netlist_time delay) +void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double 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); + 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; +} + +void generic_diode::update_diode(const nl_double nVd) +{ + 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; + } } +// ---------------------------------------------------------------------------------------- +// nld_twoterm +// ---------------------------------------------------------------------------------------- NETLIB_UPDATE(twoterm) { /* only called if connected to a rail net ==> notify the solver to recalculate */ - solve_now(); + /* 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(); } // ---------------------------------------------------------------------------------------- @@ -53,7 +100,12 @@ NETLIB_UPDATE(twoterm) NETLIB_RESET(R_base) { NETLIB_NAME(twoterm)::reset(); - set_R(1.0 / exec().gmin()); + set_R(1.0 / netlist().gmin()); +} + +NETLIB_UPDATE(R_base) +{ + NETLIB_NAME(twoterm)::update(); } // ---------------------------------------------------------------------------------------- @@ -62,14 +114,14 @@ NETLIB_RESET(R_base) NETLIB_UPDATE_PARAM(R) { - solve_now(); - set_R(std::max(m_R(), exec().gmin())); + update_dev(); + set_R(std::max(m_R(), netlist().gmin())); } NETLIB_RESET(R) { NETLIB_NAME(twoterm)::reset(); - set_R(std::max(m_R(), exec().gmin())); + set_R(std::max(m_R(), netlist().gmin())); } // ---------------------------------------------------------------------------------------- @@ -82,22 +134,21 @@ 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, exec().gmin())); - m_R2.set_R(std::max(m_R() * (plib::constants<nl_double>::one() - v), exec().gmin())); + 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())); } NETLIB_UPDATE_PARAM(POT) { - m_R1.solve_now(); - m_R2.solve_now(); + m_R1.update_dev(); + m_R2.update_dev(); nl_double v = m_Dial(); if (m_DialIsLog()) 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, exec().gmin())); - m_R2.set_R(std::max(m_R() * (plib::constants<nl_double>::one() - v), exec().gmin())); + + 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())); } @@ -113,13 +164,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, exec().gmin())); + m_R1.set_R(std::max(m_R() * v, netlist().gmin())); } NETLIB_UPDATE_PARAM(POT2) { - m_R1.solve_now(); + m_R1.update_dev(); nl_double v = m_Dial(); @@ -127,7 +178,38 @@ 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, exec().gmin())); + 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); } // ---------------------------------------------------------------------------------------- @@ -136,9 +218,9 @@ NETLIB_UPDATE_PARAM(POT2) NETLIB_RESET(L) { - m_gmin = exec().gmin(); + m_GParallel = netlist().gmin(); m_I = 0.0; - m_G = m_gmin; + m_G = m_GParallel; 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); @@ -148,11 +230,16 @@ 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_gmin; + m_G = step / m_L() + m_GParallel; set_mat( m_G, -m_G, -m_I, -m_G, m_G, m_I); //set(m_G, 0.0, m_I); @@ -167,8 +254,8 @@ NETLIB_RESET(D) nl_double Is = m_model.m_IS; nl_double n = m_model.m_N; - m_D.set_param(Is, n, exec().gmin(), constants::T0()); - set_G_V_I(m_D.G(), 0.0, m_D.Ieq()); + m_D.set_param(Is, n, netlist().gmin()); + set(m_D.G(), 0.0, m_D.Ieq()); } NETLIB_UPDATE_PARAM(D) @@ -176,7 +263,12 @@ NETLIB_UPDATE_PARAM(D) nl_double Is = m_model.m_IS; nl_double n = m_model.m_N; - m_D.set_param(Is, n, exec().gmin(), constants::T0()); + m_D.set_param(Is, n, netlist().gmin()); +} + +NETLIB_UPDATE(D) +{ + NETLIB_NAME(twoterm)::update(); } NETLIB_UPDATE_TERMINALS(D) @@ -189,18 +281,65 @@ 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, "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 + 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) + } } // namespace netlist diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h index 470fb35c96e..7778f5f4585 100644 --- a/src/lib/netlist/analog/nlid_twoterm.h +++ b/src/lib/netlist/analog/nlid_twoterm.h @@ -33,12 +33,8 @@ #ifndef NLID_TWOTERM_H_ #define NLID_TWOTERM_H_ -#include "netlist/nl_base.h" -#include "netlist/nl_setup.h" -#include "netlist/solver/nld_solver.h" -#include "plib/pfunction.h" - -#include <cmath> +#include "../nl_base.h" +#include "../plib/pfunction.h" // ----------------------------------------------------------------------------- // Implementation @@ -52,27 +48,14 @@ 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) - , m_N(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "2", &m_P) + , m_P(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "1") + , m_N(bselect(terminals_owned, owner, *this), (terminals_owned ? name + "." : "") + "2") { + m_P.m_otherterm = &m_N; + m_N.m_otherterm = &m_P; } terminal_t m_P; @@ -80,36 +63,36 @@ NETLIB_OBJECT(twoterm) //NETLIB_UPDATE_TERMINALSI() { } //NETLIB_RESETI() { } - -public: - 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) +public: + /* inline */ void set(const nl_double G, const nl_double V, const nl_double I) { /* GO, GT, I */ - m_P.set_go_gt_I( -G, G, ( V) * G - I); - m_N.set_go_gt_I( -G, G, ( -V) * G + I); + m_P.set( G, G, ( V) * G - I); + m_N.set( G, G, ( -V) * G + I); } - nl_double deltaV() const + /* inline */ 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 rhs1, - const nl_double a21, const nl_double a22, const nl_double rhs2) + 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) { /* GO, GT, I */ - m_P.set_go_gt_I(a12, a11, rhs1); - m_N.set_go_gt_I(a21, a22, rhs2); + m_P.set(-a12, a11, r1); + m_N.set(-a21, a22, r2); } 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; + } }; @@ -123,17 +106,17 @@ NETLIB_OBJECT_DERIVED(R_base, twoterm) { } - void set_R(const nl_double R) +public: + inline void set_R(const nl_double R) { - const nl_double G = plib::constants<nl_double>::one() / R; + const nl_double G = NL_FCONST(1.0) / R; set_mat( G, -G, 0.0, -G, G, 0.0); } - NETLIB_RESETI(); - protected: - //NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATEI(); }; @@ -144,6 +127,7 @@ NETLIB_OBJECT_DERIVED(R, R_base) { } + param_double_t m_R; protected: @@ -152,7 +136,6 @@ 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; }; @@ -168,8 +151,7 @@ NETLIB_OBJECT(POT) , m_R2(*this, "_R2") , m_R(*this, "R", 10000) , m_Dial(*this, "DIAL", 0.5) - , m_DialIsLog(*this, "DIALLOG", false) - , m_Reverse(*this, "REVERSE", false) + , m_DialIsLog(*this, "DIALLOG", 0) { register_subalias("1", m_R1.m_P); register_subalias("2", m_R1.m_N); @@ -190,7 +172,6 @@ private: param_double_t m_R; param_double_t m_Dial; param_logic_t m_DialIsLog; - param_logic_t m_Reverse; }; NETLIB_OBJECT(POT2) @@ -199,8 +180,8 @@ NETLIB_OBJECT(POT2) , m_R1(*this, "_R1") , m_R(*this, "R", 10000) , m_Dial(*this, "DIAL", 0.5) - , m_DialIsLog(*this, "DIALLOG", false) - , m_Reverse(*this, "REVERSE", false) + , m_DialIsLog(*this, "DIALLOG", 0) + , m_Reverse(*this, "REVERSE", 0) { register_subalias("1", m_R1.m_P); register_subalias("2", m_R1.m_N); @@ -220,83 +201,6 @@ 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 @@ -307,45 +211,25 @@ NETLIB_OBJECT_DERIVED(C, twoterm) public: NETLIB_CONSTRUCTOR_DERIVED(C, twoterm) , m_C(*this, "C", 1e-6) - , m_cap(*this, "m_cap") + , m_GParallel(0.0) { + //register_term("1", m_P); + //register_term("2", m_N); } NETLIB_IS_TIMESTEP(true) - 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); - } + NETLIB_TIMESTEPI(); param_double_t m_C; - NETLIB_RESETI() - { - m_cap.setparams(exec().gmin()); - } protected: - //NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI() { } + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_UPDATE_PARAMI(); private: - generic_capacitor<capacitor_e::CHARGE_CONSERVING> m_cap; - //generic_capacitor<capacitor_e::CONSTANT_CAPACITY> m_cap; + nl_double m_GParallel; + }; // ----------------------------------------------------------------------------- @@ -357,7 +241,7 @@ NETLIB_OBJECT_DERIVED(L, twoterm) public: NETLIB_CONSTRUCTOR_DERIVED(L, twoterm) , m_L(*this, "L", 1e-6) - , m_gmin(0.0) + , m_GParallel(0.0) , m_G(0.0) , m_I(0.0) { @@ -367,16 +251,16 @@ public: NETLIB_IS_TIMESTEP(true) NETLIB_TIMESTEPI(); - NETLIB_RESETI(); + + param_double_t m_L; protected: - //NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATEI(); NETLIB_UPDATE_PARAMI(); private: - param_double_t m_L; - - nl_double m_gmin; + nl_double m_GParallel; nl_double m_G; nl_double m_I; }; @@ -385,82 +269,14 @@ 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, 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; + generic_diode(device_t &dev, pstring name); - 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 update_diode(const double nVd); + void set_param(const double Is, const double n, double gmin); double I() const { return m_Id; } double G() const { return m_G; } @@ -551,15 +367,15 @@ public: NETLIB_IS_DYNAMIC(true) NETLIB_UPDATE_TERMINALSI(); - NETLIB_RESETI(); + + diode_model_t m_model; protected: - //NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATEI(); NETLIB_UPDATE_PARAMI(); -private: - diode_model_t m_model; - generic_diode<diode_e::BIPOLAR> m_D; + generic_diode m_D; }; @@ -573,11 +389,10 @@ 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->state().run_state_manager()) + , m_compiled(this->name() + ".FUNCC", this, this->netlist().state()) { register_subalias("P", m_P); register_subalias("N", m_N); @@ -586,26 +401,12 @@ public: } NETLIB_IS_TIMESTEP(m_func() != "") - - NETLIB_TIMESTEPI() - { - m_t += step; - this->set_G_V_I(1.0 / m_R(), - m_compiled.evaluate(std::vector<double>({m_t})), - 0.0); - } + NETLIB_TIMESTEPI(); protected: - // 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); - } + NETLIB_UPDATEI(); + NETLIB_RESETI(); -private: - state_var<double> m_t; param_double_t m_R; param_double_t m_V; param_str_t m_func; @@ -620,10 +421,9 @@ 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->state().run_state_manager()) + , m_compiled(this->name() + ".FUNCC", this, this->netlist().state()) { register_subalias("P", m_P); register_subalias("N", m_N); @@ -632,33 +432,19 @@ public: } NETLIB_IS_TIMESTEP(m_func() != "") - 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); - } - + NETLIB_TIMESTEPI(); protected: - //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()); - } + NETLIB_UPDATEI(); + NETLIB_RESETI(); -private: - state_var<double> m_t; param_double_t m_I; param_str_t m_func; plib::pfunction m_compiled; }; - } // namespace analog + } //namespace devices } // namespace netlist #endif /* NLD_TWOTERM_H_ */ diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile index 647c7df6f12..807ddbd6c7a 100644 --- a/src/lib/netlist/build/makefile +++ b/src/lib/netlist/build/makefile @@ -12,27 +12,6 @@ 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 @@ -44,7 +23,7 @@ endif # LTO = -flto=4 -fuse-linker-plugin -flto-partition=balanced -Wodr -CFLAGS = $(LTO) -g -O3 -std=c++11 -I$(CURDIR)/.. -I$(CURDIR)/../.. $(CEXTRAFLAGS) +CFLAGS = $(LTO) -g -O3 -std=c++11 -march=native -I../.. -Wall -Wpedantic -Wsign-compare -Wextra -Wno-unused-parameter $(CEXTRAFLAGS) LDFLAGS = $(LTO) -g -O3 -std=c++11 $(LDEXTRAFLAGS) LIBS = -lpthread -ldl @@ -53,7 +32,6 @@ LD = @g++ MD = @mkdir RM = @rm DOXYGEN = @doxygen -CLANG_TIDY = clang-tidy-9 TARGETS = nltool nlwav @@ -75,6 +53,7 @@ OBJS = $(POBJS) $(NLOBJS) POBJS := \ $(POBJ)/pstring.o \ + $(POBJ)/palloc.o \ $(POBJ)/pchrono.o \ $(POBJ)/pdynlib.o \ $(POBJ)/pexception.o \ @@ -94,7 +73,6 @@ 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 \ @@ -114,7 +92,6 @@ 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 \ @@ -176,12 +153,10 @@ 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 nvcc +MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean doc clang mingw # git archive HEAD --prefix=project-name-version/ \ @@ -225,33 +200,19 @@ maketree: $(sort $(OBJDIRS)) # Special targets #------------------------------------------------- -.PHONY: clang clang-5 mingw doc native - -native: - $(MAKE) CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra " +.PHONY: clang clang-5 mingw doc clang: - $(MAKE) CC=clang++-9 LD=clang++-9 CEXTRAFLAGS="-march=native -Weverything -Werror -Wno-padded -Wno-weak-vtables -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors" + $(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" 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" \ @@ -276,7 +237,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 @@ -287,18 +248,6 @@ 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 #------------------------------------------------- @@ -319,15 +268,3 @@ $(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 c0353f2489a..e0f0277daac 100644 --- a/src/lib/netlist/devices/net_lib.cpp +++ b/src/lib/netlist/devices/net_lib.cpp @@ -9,159 +9,152 @@ ****************************************************************************/ #include "net_lib.h" -#include "netlist/nl_factory.h" -#include "netlist/solver/nld_solver.h" +#include "../nl_factory.h" +#include "../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 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) } +#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) } namespace netlist { -namespace devices -{ - - void initialize_factory(factory::list_t &factory) + namespace devices { - 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) - } + void initialize_factory(factory::list_t &factory) +{ + 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 + } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/net_lib.h b/src/lib/netlist/devices/net_lib.h index abf58ccee16..4dead624fc2 100644 --- a/src/lib/netlist/devices/net_lib.h +++ b/src/lib/netlist/devices/net_lib.h @@ -35,8 +35,18 @@ #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" @@ -50,32 +60,21 @@ #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_mm5837.h" #include "nld_ne555.h" +#include "nld_mm5837.h" #include "nld_r2r_dac.h" @@ -85,17 +84,16 @@ #include "nld_log.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 "../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 "nld_legacy.h" #endif diff --git a/src/lib/netlist/devices/nld_2102A.cpp b/src/lib/netlist/devices/nld_2102A.cpp index 0ec7132b401..5296bf2d029 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 "netlist/nl_base.h" +#include "../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_array<uint8_t, 128> m_ram; // 1024x1 bits + state_var<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, "RAM_2102A", "+CEQ,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+RWQ,+DI") - NETLIB_DEVICE_IMPL(2102A_dip,"RAM_2102A_DIP","") + NETLIB_DEVICE_IMPL(2102A) + NETLIB_DEVICE_IMPL(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 aa53efde47d..52d892d4d40 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 "netlist/nl_setup.h" +#include "../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 b021bc95003..cb53d60e205 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -92,8 +92,8 @@ namespace netlist m_D[i].push((d >> i) & 1, delay); } - 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", "") + NETLIB_DEVICE_IMPL(2716) + NETLIB_DEVICE_IMPL(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 363086d6a37..f4776242e6a 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 "netlist/nl_setup.h" +#include "../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 13518f9d3cb..8403d42bef2 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(); } - NETLIB_FUNC_VOID(CD4020_sub, update_outputs, (const unsigned cnt)) + inline NETLIB_FUNC_VOID(CD4020_sub, update_outputs, (const unsigned cnt)) { - static constexpr const std::array<netlist_time, 14> out_delayQn = { + /* static */ const netlist_time out_delayQn[14] = { 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,8 +113,7 @@ namespace netlist m_Q[i].push((cnt >> i) & 1, out_delayQn[i]); } - NETLIB_DEVICE_IMPL(CD4020, "CD4020", "") - NETLIB_DEVICE_IMPL_ALIAS(CD4020_WI, CD4020, "CD4020_WI", "+IP,+RESET,+VDD,+VSS") + NETLIB_DEVICE_IMPL(CD4020) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_4020.h b/src/lib/netlist/devices/nld_4020.h index f24251fb1dc..fd6b234da46 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 "netlist/nl_setup.h" +#include "../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 0c7511ca438..ebd269a023a 100644 --- a/src/lib/netlist/devices/nld_4066.cpp +++ b/src/lib/netlist/devices/nld_4066.cpp @@ -5,11 +5,9 @@ * */ -#include "nld_4066.h" - -#include "netlist/analog/nlid_twoterm.h" -#include "netlist/solver/nld_solver.h" #include "nlid_cmos.h" +#include "../analog/nlid_twoterm.h" +#include "nld_4066.h" namespace netlist { @@ -29,7 +27,7 @@ namespace netlist NETLIB_RESETI(); NETLIB_UPDATEI(); - private: + public: NETLIB_SUB(vdd_vss) m_supply; analog::NETLIB_SUB(R_base) m_R; @@ -41,36 +39,45 @@ namespace netlist { // Start in off condition // FIXME: is ROFF correct? - m_R.set_R(plib::constants<nl_double>::one() / exec().gmin()); + m_R.set_R(NL_FCONST(1.0) / netlist().gmin()); } NETLIB_UPDATE(CD4066_GATE) { nl_double sup = (m_supply.vdd() - m_supply.vss()); - nl_double low = plib::constants<nl_double>::cast(0.45) * sup; - nl_double high = plib::constants<nl_double>::cast(0.55) * sup; + nl_double low = NL_FCONST(0.45) * sup; + nl_double high = NL_FCONST(0.55) * sup; nl_double in = m_control() - m_supply.vss(); - nl_double rON = m_base_r() * plib::constants<nl_double>::cast(5.0) / sup; + nl_double rON = m_base_r() * NL_FCONST(5.0) / sup; nl_double R = -1.0; if (in < low) { - R = plib::constants<nl_double>::one() / exec().gmin(); + R = NL_FCONST(1.0) / netlist().gmin(); } else if (in > high) { R = rON; } - if (R > plib::constants<nl_double>::zero()) + if (R > NL_FCONST(0.0)) { - m_R.update(); - m_R.set_R(R); - m_R.solve_later(); + // 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(); + } } } - NETLIB_DEVICE_IMPL(CD4066_GATE, "CD4066_GATE", "") + NETLIB_DEVICE_IMPL(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 d339464a108..e9fd579496c 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 "netlist/nl_setup.h" +#include "../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 c8ee1a90643..b9758ff036b 100644 --- a/src/lib/netlist/devices/nld_4316.cpp +++ b/src/lib/netlist/devices/nld_4316.cpp @@ -5,10 +5,9 @@ * */ -#include "nld_4316.h" -#include "netlist/analog/nlid_twoterm.h" -#include "netlist/solver/nld_solver.h" #include "nlid_cmos.h" +#include "../analog/nlid_twoterm.h" +#include "nld_4316.h" namespace netlist { namespace devices { @@ -38,20 +37,19 @@ namespace netlist { namespace devices { NETLIB_RESET(CD4316_GATE) { - m_R.set_R(plib::constants<nl_double>::one() / exec().gmin()); + m_R.set_R(NL_FCONST(1.0) / netlist().gmin()); } NETLIB_UPDATE(CD4316_GATE) { - m_R.update(); + m_R.update_dev(); if (m_S() && !m_E()) m_R.set_R(m_base_r()); else - m_R.set_R(plib::constants<nl_double>::one() / exec().gmin()); - m_R.solve_later(NLTIME_FROM_NS(1)); + m_R.set_R(NL_FCONST(1.0) / netlist().gmin()); + m_R.m_P.schedule_solve_after(NLTIME_FROM_NS(1)); } - NETLIB_DEVICE_IMPL(CD4316_GATE, "CD4316_GATE", "") + NETLIB_DEVICE_IMPL(CD4316_GATE) -} // namespace devices - } // namespace netlist +} } // namesapce netlist::devices diff --git a/src/lib/netlist/devices/nld_4316.h b/src/lib/netlist/devices/nld_4316.h index 278a2793a6f..eb1d13f5542 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 "netlist/nl_setup.h" +#include "../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 763760e2c6a..c5a12a15fb4 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { namespace devices { - 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) }; + 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) }; NETLIB_OBJECT(74107A) { @@ -22,12 +22,11 @@ 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); @@ -44,7 +43,7 @@ namespace netlist logic_output_t m_Q; logic_output_t m_QQ; - netlist_time m_delay[2]; + const netlist_time *m_delay; logic_input_t m_J; logic_input_t m_K; @@ -62,8 +61,7 @@ namespace netlist public: NETLIB_CONSTRUCTOR_DERIVED(74107, 74107A) { - m_delay[0] = delay_107[0]; - m_delay[1] = delay_107[1]; + m_delay = delay_107; } }; @@ -139,9 +137,9 @@ namespace netlist m_clk.activate_hl(); } - 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", "") + NETLIB_DEVICE_IMPL(74107) + NETLIB_DEVICE_IMPL(74107A) + NETLIB_DEVICE_IMPL(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 c6f8864610a..b59848cbb05 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 "netlist/nl_setup.h" +#include "../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 32e47a47ef2..9055c5ce140 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 "netlist/analog/nlid_twoterm.h" +#include "../analog/nlid_twoterm.h" #include <cmath> @@ -257,8 +257,8 @@ namespace netlist { m_KP = 1.0 / (1.0 + exp(m_K())); - m_RP.reset(); - m_RN.reset(); + m_RP.do_reset(); + m_RN.do_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.reset(); - //m_2.reset(); + //m_1.do_reset(); + //m_2.do_reset(); } NETLIB_UPDATE(9602_dip) @@ -289,8 +289,8 @@ namespace netlist NETLIB_RESET(9602_dip) { - //m_1.reset(); - //m_2.reset(); + //m_1.do_reset(); + //m_2.do_reset(); } NETLIB_UPDATE(4538_dip) @@ -302,14 +302,14 @@ namespace netlist NETLIB_RESET(4538_dip) { - m_1.reset(); - m_2.reset(); + m_1.do_reset(); + m_2.do_reset(); } - 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", "") + NETLIB_DEVICE_IMPL(74123) + NETLIB_DEVICE_IMPL(74123_dip) + NETLIB_DEVICE_IMPL(4538_dip) + NETLIB_DEVICE_IMPL(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 3eca141b613..dfd75f746c7 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 "netlist/nl_setup.h" +#include "../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 136fe61520b..b74c09f8cc0 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 "netlist/nl_base.h" +#include "../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(); + m_sub.update_dev(); } NETLIB_UPDATE(74153_dip) { m_2.m_chan = m_1.m_chan = (m_A() | (m_B()<<1)); - m_1.update(); - m_2.update(); + m_1.update_dev(); + m_2.update_dev(); } - NETLIB_DEVICE_IMPL(74153, "TTL_74153", "+C0,+C1,+C2,+C3,+A,+B,+G") - NETLIB_DEVICE_IMPL(74153_dip, "TTL_74153_DIP", "") + NETLIB_DEVICE_IMPL(74153) + NETLIB_DEVICE_IMPL(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 f1c0f056cf7..ee77d4224ce 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 "netlist/nl_setup.h" +#include "../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 7a3b54d6368..5eb711fb456 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -85,7 +85,7 @@ namespace netlist } // FIXME: Timing - static constexpr const netlist_time delay[4] = + static constexpr 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, "TTL_74161", "+A,+B,+C,+D,+CLRQ,+LOADQ,+CLK,+ENABLEP,+ENABLET") - NETLIB_DEVICE_IMPL(74161_dip, "TTL_74161_DIP", "") + NETLIB_DEVICE_IMPL(74161) + NETLIB_DEVICE_IMPL(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 f3fa3eab043..363bc3c7f0d 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 "netlist/nl_setup.h" +#include "../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 b1eb30bb1ba..5b2b1d8d080 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -97,8 +97,8 @@ namespace netlist } } - NETLIB_DEVICE_IMPL(74164, "TTL_74164", "+A,+B,+CLRQ,+CLK") - NETLIB_DEVICE_IMPL(74164_dip, "TTL_74164_DIP", "") + NETLIB_DEVICE_IMPL(74164) + NETLIB_DEVICE_IMPL(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 dd4e6bd1303..d7f29d386de 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 "netlist/nl_setup.h" +#include "../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 521bf4d63d2..678c1b1782e 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -86,7 +86,6 @@ namespace netlist } else if (!m_CLK() || m_CLKINH()) { - // FIXME: qh is overwritten below? qh = old_qh; } else if (!m_last_CLK) @@ -102,8 +101,8 @@ namespace netlist m_QH.push(qh, NLTIME_FROM_NS(20)); // FIXME: Timing } - 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", "") + NETLIB_DEVICE_IMPL(74165) + NETLIB_DEVICE_IMPL(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 d282bab622b..e38ca7bab86 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 "netlist/nl_setup.h" +#include "../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 a5049014576..32f075c4da5 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -121,8 +121,8 @@ namespace netlist m_QH.push(qh, delay); //FIXME } - 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", "") + NETLIB_DEVICE_IMPL(74166) + NETLIB_DEVICE_IMPL(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 80c86bb3422..b8a8a204374 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 "netlist/nl_setup.h" +#include "../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 83369075db6..5f4573942bd 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -134,8 +134,8 @@ namespace netlist //m_sub.do_reset(); } - NETLIB_DEVICE_IMPL(74174, "TTL_74174", "+CLK,+D1,+D2,+D3,+D4,+D5,+D6,+CLRQ") - NETLIB_DEVICE_IMPL(74174_dip,"TTL_74174_DIP", "") + NETLIB_DEVICE_IMPL(74174) + NETLIB_DEVICE_IMPL(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 f1854801291..66824abb7aa 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 "netlist/nl_setup.h" +#include "../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 a15adb5c60f..5955bcb389e 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -111,8 +111,8 @@ namespace netlist m_data = 0xFF; } - NETLIB_DEVICE_IMPL(74175, "TTL_74175", "+CLK,+D1,+D2,+D3,+D4,+CLRQ") - NETLIB_DEVICE_IMPL(74175_dip,"TTL_74175_DIP", "") + NETLIB_DEVICE_IMPL(74175) + NETLIB_DEVICE_IMPL(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 4bc8c1175ba..27e01b55b05 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 "netlist/nl_setup.h" +#include "../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 954fc351179..1af605d4776 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -110,7 +110,7 @@ namespace netlist } // FIXME: Timing - static constexpr const netlist_time delay[4] = + static constexpr 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, "TTL_74192", "+A,+B,+C,+D,+CLEAR,+LOADQ,+CU,+CD") - NETLIB_DEVICE_IMPL(74192_dip,"TTL_74192_DIP", "") + NETLIB_DEVICE_IMPL(74192) + NETLIB_DEVICE_IMPL(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 9b0139070b8..613d463cf47 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 "netlist/nl_setup.h" +#include "../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 16d7438d799..55d18f3dc1b 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -87,7 +87,7 @@ namespace netlist } // FIXME: Timing - static constexpr const netlist_time delay[4] = + static constexpr 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, "TTL_74193", "+A,+B,+C,+D,+CLEAR,+LOADQ,+CU,+CD") - NETLIB_DEVICE_IMPL(74193_dip, "TTL_74193_DIP", "") + NETLIB_DEVICE_IMPL(74193) + NETLIB_DEVICE_IMPL(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 a4c745d5386..bb14a301f38 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 "netlist/nl_setup.h" +#include "../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 9876aa6b170..d531e792885 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 "netlist/nl_base.h" +#include "../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, "TTL_74194", "+CLK,+S0,+S1,+SRIN,+A,+B,+C,+D,+SLIN,+CLRQ") - NETLIB_DEVICE_IMPL(74194_dip, "TTL_74194_DIP", "") + NETLIB_DEVICE_IMPL(74194) + NETLIB_DEVICE_IMPL(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 5a507982b81..5124a66bcc0 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 "netlist/nl_setup.h" +#include "../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 753f16bfd22..10456ebbc21 100644 --- a/src/lib/netlist/devices/nld_74365.cpp +++ b/src/lib/netlist/devices/nld_74365.cpp @@ -6,20 +6,12 @@ */ #include "nld_74365.h" -#include "netlist/nl_base.h" +#include "../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) @@ -76,8 +68,8 @@ namespace netlist } } - NETLIB_DEVICE_IMPL(74365, "TTL_74365", "+G1Q,+G2Q,+A1,+A2,+A3,+A4,+A5,+A6") - NETLIB_DEVICE_IMPL(74365_dip, "TTL_74365_DIP", "") + NETLIB_DEVICE_IMPL(74365) + NETLIB_DEVICE_IMPL(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 a50b535383f..ca0eacf6ba1 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 "netlist/nl_setup.h" +#include "../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 4500229a1c5..cc2e60f23b7 100644 --- a/src/lib/netlist/devices/nld_7448.cpp +++ b/src/lib/netlist/devices/nld_7448.cpp @@ -5,10 +5,8 @@ * */ +#include "nlid_truthtable.h" #include "nld_7448.h" -#include "nlid_truthtable.h" - -#include <array> namespace netlist { @@ -135,9 +133,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 const std::array<uint8_t, 16> tab7448 = + static constexpr uint8_t tab7448[16] = { BITS7( 1, 1, 1, 1, 1, 1, 0 ), /* 00 - not blanked ! */ BITS7( 0, 1, 1, 0, 0, 0, 0 ), /* 01 */ @@ -190,13 +188,11 @@ namespace netlist NETLIB_RESET(7448) { m_state = 0; -#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 + m_A.inactivate(); + m_B.inactivate(); + m_C.inactivate(); + m_D.inactivate(); + m_RBIQ.inactivate(); } NETLIB_FUNC_VOID(7448, update_outputs, (unsigned v)) @@ -215,8 +211,8 @@ namespace netlist #endif - NETLIB_DEVICE_IMPL(7448, "TTL_7448", "+A,+B,+C,+D,+LTQ,+BIQ,+RBIQ") - NETLIB_DEVICE_IMPL(7448_dip, "TTL_7448_DIP", "") + NETLIB_DEVICE_IMPL(7448) + NETLIB_DEVICE_IMPL(7448_dip) } //namespace devices diff --git a/src/lib/netlist/devices/nld_7448.h b/src/lib/netlist/devices/nld_7448.h index b9c03ae6360..89528707bc1 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 "netlist/nl_setup.h" +#include "../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 aacab46a021..af9b9afada1 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -68,10 +68,10 @@ namespace netlist m_B.activate(); m_C.activate(); m_D.activate(); - auto t1 = m_A() & m_B(); - auto t2 = m_C() & m_D(); + unsigned t1 = m_A() & m_B(); + unsigned t2 = m_C() & m_D(); - const netlist_time times[2] = { NLTIME_FROM_NS(15), NLTIME_FROM_NS(22) }; + const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; uint_fast8_t res = 0; if (t1 ^ 1) @@ -85,20 +85,18 @@ namespace netlist m_A.inactivate(); m_B.inactivate(); } - } - else - { + } else { if (t2 ^ 1) { m_C.inactivate(); m_D.inactivate(); } } - m_Q.push(res, times[res]);// ? 22000 : 15000); + m_Q.push(res, times[1 - res]);// ? 22000 : 15000); } - NETLIB_DEVICE_IMPL(7450, "TTL_7450_ANDORINVERT", "+A,+B,+C,+D") - NETLIB_DEVICE_IMPL(7450_dip, "TTL_7450_DIP", "") + NETLIB_DEVICE_IMPL(7450) + NETLIB_DEVICE_IMPL(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 6718afd8f9e..652516758ad 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 "netlist/nl_setup.h" +#include "../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 c8abd829264..d9efb9fb710 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 "netlist/nl_base.h" +#include "../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, "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", "") + NETLIB_DEVICE_IMPL(7473) + NETLIB_DEVICE_IMPL(7473A) + NETLIB_DEVICE_IMPL(7473_dip) + NETLIB_DEVICE_IMPL(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 3fbaaf4efbc..5313d18570c 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 "netlist/nl_setup.h" +#include "../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 740af6ad3c1..9d020663f46 100644 --- a/src/lib/netlist/devices/nld_7474.cpp +++ b/src/lib/netlist/devices/nld_7474.cpp @@ -1,4 +1,3 @@ - // license:GPL-2.0+ // copyright-holders:Couriersud /* @@ -7,47 +6,60 @@ */ #include "nld_7474.h" -#include "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { namespace devices { - - NETLIB_OBJECT(7474) + NETLIB_OBJECT(7474sub) { - NETLIB_CONSTRUCTOR(7474) - , m_D(*this, "D") - , m_CLRQ(*this, "CLRQ") - , m_PREQ(*this, "PREQ") - , m_CLK(*this, "CLK", NETLIB_DELEGATE(7474, clk)) + NETLIB_CONSTRUCTOR(7474sub) + , m_CLK(*this, "CLK") , m_Q(*this, "Q") , m_QQ(*this, "QQ") , m_nextD(*this, "m_nextD", 0) { } - private: NETLIB_RESETI(); NETLIB_UPDATEI(); - NETLIB_HANDLERI(clk); - logic_input_t m_D; - logic_input_t m_CLRQ; - logic_input_t m_PREQ; + public: 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); - state_var<netlist_sig_t> m_nextD; + private: + + }; - void newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ) + NETLIB_OBJECT(7474) + { + NETLIB_CONSTRUCTOR(7474) + , sub(*this, "sub") + , m_D(*this, "D") + , m_CLRQ(*this, "CLRQ") + , m_PREQ(*this, "PREQ") { - // 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]); + register_subalias("CLK", sub.m_CLK); + + register_subalias("Q", sub.m_Q); + register_subalias("QQ", sub.m_QQ); } + + 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) @@ -56,20 +68,20 @@ namespace netlist , m_1(*this, "1") , m_2(*this, "2") { - 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("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("7", ); ==> GND - 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("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("14", ); ==> VCC } NETLIB_UPDATEI(); @@ -80,47 +92,77 @@ namespace netlist NETLIB_SUB(7474) m_2; }; - NETLIB_HANDLER(7474, clk) + inline void NETLIB_NAME(7474sub)::newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ) { - newstate(m_nextD, !m_nextD); - m_CLK.inactivate(); + // 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(); + } } NETLIB_UPDATE(7474) { - const auto preq(m_PREQ()); - const auto clrq(m_CLRQ()); - if (preq & clrq) + if (m_PREQ() && m_CLRQ()) { m_D.activate(); - m_nextD = m_D(); - m_CLK.activate_lh(); + 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(); } else { - newstate(preq ^ 1, clrq ^ 1); - m_CLK.inactivate(); + sub.newstate(1, 1); + sub.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, "TTL_7474", "+CLK,+D,+CLRQ,+PREQ") - NETLIB_DEVICE_IMPL(7474_dip, "TTL_7474_DIP", "") + NETLIB_DEVICE_IMPL(7474) + NETLIB_DEVICE_IMPL(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 48fd4f3d842..aa48e240387 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 "netlist/nl_setup.h" +#include "../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 63fd355d406..b2d28048513 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -101,7 +101,7 @@ namespace netlist { unsigned start_q = m_last_Q; - NETLIB_NAME(7477)::update(); + NETLIB_PARENT_UPDATE(7477); for (std::size_t i=0; i<4; i++) { @@ -148,10 +148,10 @@ namespace netlist } - 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", "") + NETLIB_DEVICE_IMPL(7475) + NETLIB_DEVICE_IMPL(7475_dip) + NETLIB_DEVICE_IMPL(7477) + NETLIB_DEVICE_IMPL(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 b16fabe61b6..51d09e75a66 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 "netlist/nl_setup.h" +#include "../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 5f820162209..72c86c003d5 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -16,16 +16,14 @@ namespace netlist { NETLIB_CONSTRUCTOR(7483) , m_C0(*this, "C0") - , 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_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_lastr(*this, "m_lastr", 0) , m_S1(*this, "S1") , m_S2(*this, "S2") @@ -36,8 +34,6 @@ namespace netlist } NETLIB_RESETI(); NETLIB_UPDATEI(); - NETLIB_HANDLERI(upd_a); - NETLIB_HANDLERI(upd_b); protected: logic_input_t m_C0; @@ -50,9 +46,7 @@ namespace netlist logic_input_t m_B3; logic_input_t m_B4; - state_var_u8 m_a; - state_var_u8 m_b; - state_var_u8 m_lastr; + state_var<unsigned> m_lastr; logic_output_t m_S1; logic_output_t m_S2; @@ -93,21 +87,12 @@ namespace netlist m_lastr = 0; } - NETLIB_HANDLER(7483, upd_a) - { - m_a = static_cast<uint8_t>((m_A1() << 0) | (m_A2() << 1) | (m_A3() << 2) | (m_A4() << 3)); - NETLIB_NAME(7483)::update(); - } - - 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()); + 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); + + unsigned r = a + b + m_C0(); if (r != m_lastr) { @@ -120,8 +105,8 @@ namespace netlist } } - NETLIB_DEVICE_IMPL(7483, "TTL_7483", "+A1,+A2,+A3,+A4,+B1,+B2,+B3,+B4,+C0") - NETLIB_DEVICE_IMPL(7483_dip, "TTL_7483_DIP", "") + NETLIB_DEVICE_IMPL(7483) + NETLIB_DEVICE_IMPL(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 ba82d5bbb9c..24952bf0501 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 "netlist/nl_setup.h" +#include "../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 cadb73000ff..320cf762f26 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -101,8 +101,8 @@ namespace netlist update_outputs(1, 1, 0); } - 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", "") + NETLIB_DEVICE_IMPL(7485) + NETLIB_DEVICE_IMPL(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 7890f4dbd2a..61b87c37ba3 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 "netlist/nl_setup.h" +#include "../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 acbe0fa4d7a..13e69c6aa31 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 "netlist/nl_base.h" +#include "../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", "B"); - register_subalias("2", "R1"); - register_subalias("3", "R2"); + register_subalias("1", m_B); + register_subalias("2", m_R1); + register_subalias("3", m_R2); // register_subalias("4", ); --> NC // register_subalias("5", ); --> VCC - register_subalias("6", "R91"); - register_subalias("7", "R92"); + register_subalias("6", m_R91); + register_subalias("7", m_R92); - register_subalias("8", "QC"); - register_subalias("9", "QB"); + register_subalias("8", m_Q[2]); + register_subalias("9", m_Q[1]); // register_subalias("10", ); --> GND - register_subalias("11", "QD"); - register_subalias("12", "QA"); + register_subalias("11", m_Q[3]); + register_subalias("12", m_Q[0]); // register_subalias("13", ); --> NC - register_subalias("14", "A"); + register_subalias("14", m_A); } }; @@ -78,13 +78,12 @@ namespace netlist m_last_B = 0; } - static constexpr const netlist_time delay[4] = + static C14CONSTEXPR 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) { @@ -120,14 +119,14 @@ namespace netlist m_last_B = new_B; } - NETLIB_FUNC_VOID(7490, update_outputs, ()) + NETLIB_FUNC_VOID(7490, update_outputs, (void)) { for (std::size_t i=0; i<4; i++) m_Q[i].push((m_cnt >> i) & 1, delay[i]); } - NETLIB_DEVICE_IMPL(7490, "TTL_7490", "+A,+B,+R1,+R2,+R91,+R92") - NETLIB_DEVICE_IMPL(7490_dip, "TTL_7490_DIP", "") + NETLIB_DEVICE_IMPL(7490) + NETLIB_DEVICE_IMPL(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 e2fa5094911..5ff18543b03 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 "netlist/nl_setup.h" +#include "../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 f26e1c237d5..f3c68f7a5c2 100644 --- a/src/lib/netlist/devices/nld_7493.cpp +++ b/src/lib/netlist/devices/nld_7493.cpp @@ -6,22 +6,23 @@ */ #include "nld_7493.h" -#include "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { namespace devices { - 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); + 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); 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)) @@ -34,51 +35,35 @@ namespace netlist } private: - 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_RESETI(); + NETLIB_UPDATEI(); - NETLIB_UPDATEI() + NETLIB_HANDLERI(updA) { - if (!(m_R1() & m_R2())) - { - m_CLKA.activate_hl(); - m_CLKB.activate_hl(); - } - else + if (m_reset) { - 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; + m_a ^= 1; + m_QA.push(m_a, out_delay); } } - NETLIB_HANDLERI(updA) - { - m_a ^= 1; - m_QA.push(m_a, out_delay); - } - NETLIB_HANDLERI(updB) { - 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); + 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); + } } logic_input_t m_R1; logic_input_t m_R2; + state_var_sig m_reset; state_var_sig m_a; - state_var_u8 m_bcd; + state_var_sig m_bcd; logic_input_t m_CLKA; logic_input_t m_CLKB; @@ -112,9 +97,37 @@ 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, "TTL_7493", "+CLKA,+CLKB,+R1,+R2") - NETLIB_DEVICE_IMPL(7493_dip, "TTL_7493_DIP", "") + NETLIB_DEVICE_IMPL(7493) + NETLIB_DEVICE_IMPL(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 68ad90885ec..ce9566aa28f 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 "netlist/nl_setup.h" +#include "../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 deleted file mode 100644 index 1432884b8dd..00000000000 --- a/src/lib/netlist/devices/nld_7497.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// 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 deleted file mode 100644 index 8d14e08a49b..00000000000 --- a/src/lib/netlist/devices/nld_7497.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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 b7bb729b334..d6dc268ed28 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 "netlist/analog/nlid_twoterm.h" +#include "../analog/nlid_twoterm.h" namespace netlist { @@ -100,14 +100,11 @@ namespace netlist { m_R_FC.set_R(90000.0); m_R_RNG.set_R(90000.0); - m_clock.reset(); + m_clock.do_reset(); } NETLIB_UPDATEI(); - NETLIB_UPDATE_PARAMI() - { - /* update param may be called from anywhere, update_dev(time) is not a good idea */ - } + NETLIB_UPDATE_PARAMI() { update_dev(); } public: NETLIB_SUB(SN74LS629clk) m_clock; @@ -148,8 +145,8 @@ namespace netlist NETLIB_RESETI() { - m_1.reset(); - m_2.reset(); + m_1.do_reset(); + m_2.do_reset(); } private: @@ -210,7 +207,7 @@ namespace netlist freq += k9 * v_rng * v_freq_3; freq += k10 * v_rng * v_freq_4; - freq *= plib::constants<nl_double>::cast(0.1e-6) / m_CAP(); + freq *= NL_FCONST(0.1e-6) / m_CAP(); // FIXME: we need a possibility to remove entries from queue ... // or an exact model ... @@ -234,8 +231,8 @@ namespace netlist } } - NETLIB_DEVICE_IMPL(SN74LS629, "SN74LS629", "CAP") - NETLIB_DEVICE_IMPL(SN74LS629_dip, "SN74LS629_DIP", "1.CAP1,2.CAP2") + NETLIB_DEVICE_IMPL(SN74LS629) + NETLIB_DEVICE_IMPL(SN74LS629_dip) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_74ls629.h b/src/lib/netlist/devices/nld_74ls629.h index 30d15d70865..3351524a60b 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 "netlist/nl_setup.h" +#include "../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 8ae6cbb6097..2e24bbf9fed 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 "netlist/nl_base.h" +#include "../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, "PROM_82S115", "+CE1Q,+CE2,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+STROBE") - NETLIB_DEVICE_IMPL(82S115_dip, "PROM_82S115_DIP", "") + NETLIB_DEVICE_IMPL(82S115) + NETLIB_DEVICE_IMPL(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 8c13fd8b51e..ef7f1ec3910 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 "netlist/nl_setup.h" +#include "../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 4a80b57e349..a8a6bfc9b57 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -77,8 +77,8 @@ namespace netlist m_O[i].push((o >> i) & 1, delay); } - NETLIB_DEVICE_IMPL(82S123, "PROM_82S123", "+CEQ,+A0,+A1,+A2,+A3,+A4") - NETLIB_DEVICE_IMPL(82S123_dip, "PROM_82S123_DIP", "") + NETLIB_DEVICE_IMPL(82S123) + NETLIB_DEVICE_IMPL(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 2c18377934d..dbf6bf63180 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 "netlist/nl_setup.h" +#include "../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 b1752908645..dcacd1ec876 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -79,8 +79,8 @@ namespace netlist m_O[i].push((o >> i) & 1, delay); } - NETLIB_DEVICE_IMPL(82S126, "PROM_82S126", "+CE1Q,+CE2Q,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7") - NETLIB_DEVICE_IMPL(82S126_dip, "PROM_82S126_DIP", "") + NETLIB_DEVICE_IMPL(82S126) + NETLIB_DEVICE_IMPL(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 ed7aa131819..3079bb8e2e0 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 "netlist/nl_setup.h" +#include "../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 e3176c7b30f..7441f6c677e 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -15,55 +15,19 @@ namespace netlist NETLIB_OBJECT(82S16) { NETLIB_CONSTRUCTOR(82S16) - , 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_A(*this, {{"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7" }}) + , m_CE1Q(*this, "CE1Q") + , m_CE2Q(*this, "CE2Q") + , m_CE3Q(*this, "CE3Q") , 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; @@ -74,9 +38,7 @@ namespace netlist logic_input_t m_DIN; logic_output_t m_DOUTQ; - state_array<uint64_t, 4> m_ram; // 256 bits - state_var_u8 m_addr; // 256 bits - state_var_sig m_enq; + state_var<uint64_t[4]> m_ram; // 256 bits }; NETLIB_OBJECT_DERIVED(82S16_dip, 82S16) @@ -107,9 +69,22 @@ namespace netlist // FIXME: optimize device (separate address decoder!) NETLIB_UPDATE(82S16) { - if (!m_enq) + if (m_CE1Q() || m_CE2Q() || m_CE3Q()) { - const auto adr(m_addr); + // 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); + } + if (!m_WEQ()) { m_ram[adr >> 6] = (m_ram[adr >> 6] @@ -126,12 +101,10 @@ namespace netlist { m_ram[i] = 0; } - m_addr = 0; - m_enq = 0; } - NETLIB_DEVICE_IMPL(82S16, "TTL_82S16", "") - NETLIB_DEVICE_IMPL(82S16_dip, "TTL_82S16_DIP", "") + NETLIB_DEVICE_IMPL(82S16) + NETLIB_DEVICE_IMPL(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 47d6189a79b..d1117246d87 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 "netlist/nl_setup.h" +#include "../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 b416015df24..ad752adb605 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 "netlist/nl_base.h" +#include "../nl_base.h" #define MAXCNT 9 @@ -14,7 +14,6 @@ namespace netlist { namespace devices { - //FIXME: Convert sub devices into NETDEV_DELEGATE logic NETLIB_OBJECT(9310_subABCD) { NETLIB_CONSTRUCTOR(9310_subABCD) @@ -140,8 +139,8 @@ namespace netlist NETLIB_RESET(9310) { - sub.reset(); - subABCD.reset(); + sub.do_reset(); + subABCD.do_reset(); } NETLIB_RESET(9310_subABCD) @@ -158,35 +157,32 @@ namespace netlist NETLIB_UPDATE(9310_sub) { - auto cnt(m_cnt); - if (m_loadq) { - if (cnt < MAXCNT - 1) + if (m_cnt < MAXCNT - 1) { - ++cnt; - update_outputs(cnt); + ++m_cnt; + update_outputs(m_cnt); } - else if (cnt == MAXCNT - 1) + else if (m_cnt == MAXCNT - 1) { - cnt = MAXCNT; + m_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)); - cnt = 0; - update_outputs_all(cnt, NLTIME_FROM_NS(20)); + m_cnt = 0; + update_outputs_all(m_cnt, NLTIME_FROM_NS(20)); } } else { - 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 = 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)); } - m_cnt = cnt; } NETLIB_UPDATE(9310) @@ -227,10 +223,10 @@ namespace netlist #if 0 // for (int i=0; i<4; i++) // m_Q[i], (cnt >> i) & 1, delay[i]); - 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); + 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); #else if ((cnt & 1) == 1) m_QA.push(1, out_delay); @@ -266,8 +262,8 @@ namespace netlist #endif } - NETLIB_DEVICE_IMPL(9310, "TTL_9310", "") - NETLIB_DEVICE_IMPL(9310_dip, "TTL_9310_DIP", "") + NETLIB_DEVICE_IMPL(9310) + NETLIB_DEVICE_IMPL(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 65df9c04ce4..02cb45b2d86 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 "netlist/nl_setup.h" +#include "../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 2b17eabb3ec..7c478fd4b05 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -20,73 +20,32 @@ 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, 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_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_Q(*this, {{ "QA", "QB", "QC", "QD" }}) - , m_cnt(*this, "m_cnt", 0) - , m_abcd(*this, "m_abcd", 0) - , m_loadq(*this, "m_loadq", 0) - , m_ent(*this, "m_ent", 0) + , m_RC(*this, "RC") { } private: - NETLIB_RESETI() - { - m_CLK.set_state(logic_t::STATE_INP_LH); - m_cnt = 0; - m_abcd = 0; - } - - 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)); - } + NETLIB_RESETI(); + NETLIB_UPDATEI(); + NETLIB_HANDLERI(clk); + NETLIB_HANDLERI(noop) { } logic_input_t m_CLK; - logic_input_t m_ENT; - - logic_output_t m_RC; + logic_input_t m_ENT; logic_input_t m_LOADQ; + state_var<unsigned> m_cnt; + logic_input_t m_ENP; logic_input_t m_CLRQ; @@ -96,15 +55,12 @@ 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; - void update_outputs_all(unsigned cnt, netlist_time out_delay) noexcept + 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 { m_Q[0].push((cnt >> 0) & 1, out_delay); m_Q[1].push((cnt >> 1) & 1, out_delay); @@ -137,9 +93,63 @@ 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, "TTL_9316", "+CLK,+ENP,+ENT,+CLRQ,+LOADQ,+A,+B,+C,+D") - NETLIB_DEVICE_IMPL(9316_dip, "TTL_9316_DIP", "") + NETLIB_DEVICE_IMPL(9316) + NETLIB_DEVICE_IMPL(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 8ab1789d7c7..8deb21dfccd 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 "netlist/nl_setup.h" +#include "../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 abf9bf9f6ef..6c408498be7 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -105,14 +105,14 @@ namespace netlist NETLIB_UPDATE(9322) { - m_1.update(); - m_2.update(); - m_3.update(); - m_4.update(); + m_1.update_dev(); + m_2.update_dev(); + m_3.update_dev(); + m_4.update_dev(); } - NETLIB_DEVICE_IMPL(9322, "TTL_9322", "+SELECT,+A1,+B1,+A2,+B2,+A3,+B3,+A4,+B4,+STROBE") - NETLIB_DEVICE_IMPL(9322_dip, "TTL_9322_DIP", "") + NETLIB_DEVICE_IMPL(9322) + NETLIB_DEVICE_IMPL(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 986c6b9e7f7..7de0f053b05 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 "netlist/nl_setup.h" +#include "../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 825696f0938..5d0c5cb71a3 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -30,7 +30,7 @@ namespace netlist logic_input_t m_RC; logic_input_t m_IN; - state_array<uint16_t, 5> m_buffer; + state_var<uint16_t[5]> m_buffer; logic_output_t m_OUT; }; @@ -116,7 +116,7 @@ namespace netlist /* do nothing */ } - NETLIB_FUNC_VOID(Am2847_shifter, shift, ()) + inline NETLIB_FUNC_VOID(Am2847_shifter, shift, (void)) { 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, "TTL_AM2847", "+CP,+INA,+INB,+INC,+IND,+RCA,+RCB,+RCC,+RCD") - NETLIB_DEVICE_IMPL(AM2847_dip, "TTL_AM2847_DIP", "") + NETLIB_DEVICE_IMPL(AM2847) + NETLIB_DEVICE_IMPL(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 ff4a95b8e81..70d288d3eec 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 "netlist/nl_setup.h" +#include "../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 93b958de539..fd3b8666078 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -107,8 +107,8 @@ namespace netlist } } - NETLIB_DEVICE_IMPL(9314, "TTL_9314", "+EQ,+MRQ,+S0Q,+S1Q,+S2Q,+S3Q,+D0,+D1,+D2,+D3") - NETLIB_DEVICE_IMPL(9314_dip, "TTL_9314_DIP", "") + NETLIB_DEVICE_IMPL(9314) + NETLIB_DEVICE_IMPL(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 59c60591ce7..6188bbef42f 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 "netlist/nl_setup.h" +#include "../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 c08ce53efed..8dceded5390 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -143,8 +143,8 @@ namespace netlist m_Q[i].push((q >> i) & 1, delay); } - NETLIB_DEVICE_IMPL(9334, "TTL_9334", "+CQ,+EQ,+D,+A0,+A1,+A2") - NETLIB_DEVICE_IMPL(9334_dip, "TTL_9334_DIP", "") + NETLIB_DEVICE_IMPL(9334) + NETLIB_DEVICE_IMPL(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 e54208e3ba4..1a07e051333 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 "netlist/nl_setup.h" +#include "../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 738230646e0..28fe0ad8188 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -25,7 +25,7 @@ namespace netlist NETLIB_RESETI(); NETLIB_UPDATEI(); - private: + protected: logic_input_t m_S; logic_input_t m_R; @@ -49,7 +49,7 @@ namespace netlist NETLIB_RESETI(); NETLIB_UPDATEI(); - private: + protected: logic_input_t m_I; logic_output_t m_Q; @@ -100,8 +100,8 @@ namespace netlist m_last = nval; } - NETLIB_DEVICE_IMPL(nicRSFF, "NETDEV_RSFF", "") - NETLIB_DEVICE_IMPL(nicDelay, "NETDEV_DELAY", "") + NETLIB_DEVICE_IMPL(nicRSFF) + NETLIB_DEVICE_IMPL(nicDelay) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_legacy.h b/src/lib/netlist/devices/nld_legacy.h index aa3aec6f147..33f7d0caaf8 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/devices/nld_log.cpp b/src/lib/netlist/devices/nld_log.cpp index 6b1b3d8efc1..29218aaa09a 100644 --- a/src/lib/netlist/devices/nld_log.cpp +++ b/src/lib/netlist/devices/nld_log.cpp @@ -5,10 +5,10 @@ * */ -#include "netlist/nl_base.h" +#include "../nl_base.h" +#include "../plib/pstream.h" +#include "../plib/pfmtlog.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(pstring(plib::pfmt("{1}.log")(this->name()))) - , m_writer(&m_strm) + , m_strm(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(exec().time().as_double()).e(static_cast<double>(m_I()))); + m_writer.writeline(plib::pfmt("{1:.9} {2}").e(netlist().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(exec().time().as_double()).e(static_cast<double>(m_I() - m_I2()))); + m_writer.writeline(plib::pfmt("{1:.9} {2}").e(netlist().time().as_double()).e(static_cast<double>(m_I() - m_I2()))); } NETLIB_RESETI() { } @@ -89,8 +89,8 @@ namespace netlist #endif - NETLIB_DEVICE_IMPL(log, "LOG", "+I") - NETLIB_DEVICE_IMPL(logD, "LOGD", "+I,+I2") + NETLIB_DEVICE_IMPL(log) + NETLIB_DEVICE_IMPL(logD) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_log.h b/src/lib/netlist/devices/nld_log.h index 13c71ea7257..6364022cea2 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 "netlist/nl_setup.h" +#include "../nl_setup.h" #define LOG(name, cI) \ - NET_REGISTER_DEV(LOG, name) \ + NET_REGISTER_DEV(??PG, 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 f6c2566bd43..e97ae41e437 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 "netlist/analog/nlid_twoterm.h" -#include "netlist/solver/nld_matrix_solver.h" +#include "../solver/nld_matrix_solver.h" +#include "../analog/nlid_twoterm.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_G_V_I(plib::constants<nl_double>::one() / R_LOW, 0.0, 0.0); + m_RV.set(NL_FCONST(1.0) / 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()->has_timestep_devices(); + m_is_timestep = m_RV.m_P.net().solver()->is_timestep(); } 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(); - 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)); + 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)); } } - NETLIB_DEVICE_IMPL(MM5837_dip, "MM5837_DIP", "") + NETLIB_DEVICE_IMPL(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 8f764aa651f..4af397d9965 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 "netlist/nl_setup.h" +#include "../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 5e990d2e974..8795197bd57 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 "netlist/analog/nlid_twoterm.h" -#include "netlist/solver/nld_solver.h" +#include "../analog/nlid_twoterm.h" +#include "../solver/nld_solver.h" #define R_OFF (1E20) #define R_ON (25) // Datasheet states a maximum discharge of 200mA, R = 5V / 0.2 @@ -62,37 +62,31 @@ 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") // to Pin 3 via ROUT + , m_OUT(*this, "OUT") // Pin 3 , 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(); - private: + protected: 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; @@ -100,51 +94,52 @@ 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; - 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; - } + inline nl_double clamp(const nl_double v, const nl_double a, const nl_double b); + }; NETLIB_OBJECT_DERIVED(NE555_dip, NE555) { NETLIB_CONSTRUCTOR_DERIVED(NE555_dip, NE555) { - 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 + 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 } }; + 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.reset(); - m_R2.reset(); - m_R3.reset(); - m_ROUT.reset(); - m_RDIS.reset(); + m_R1.do_reset(); + m_R2.do_reset(); + m_R3.do_reset(); + m_RDIS.do_reset(); - /* FIXME make resistances a parameter, properly model other variants */ + /* FIXME make resistance 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; @@ -154,47 +149,39 @@ namespace netlist { // FIXME: assumes GND is connected to 0V. - const auto reset = m_RESET(); + 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)); - if (!reset && m_last_reset) + if (!btrig) { - m_ff = false; + m_ff = true; } - else + else if (bthresh) { - 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; + m_ff = false; } - const bool out = (!reset ? false : m_ff); + bool out = (!m_RESET() ? false : m_ff); if (m_last_out && !out) { - m_RDIS.update(); + m_RDIS.update_dev(); m_OUT.push(m_R3.m_N()); m_RDIS.set_R(R_ON); } else if (!m_last_out && out) { - m_RDIS.update(); + m_RDIS.update_dev(); // 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, "NE555", "") - NETLIB_DEVICE_IMPL(NE555_dip, "NE555_DIP", "") + NETLIB_DEVICE_IMPL(NE555) + NETLIB_DEVICE_IMPL(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 fc575d914b7..c629253f08f 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 "netlist/nl_setup.h" +#include "../nl_setup.h" #define NE555(name) \ NET_REGISTER_DEV(NE555, name) @@ -12,10 +12,4 @@ #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 284b6673f76..4c29389d491 100644 --- a/src/lib/netlist/devices/nld_r2r_dac.cpp +++ b/src/lib/netlist/devices/nld_r2r_dac.cpp @@ -5,9 +5,9 @@ * */ -#include "netlist/nl_base.h" -#include "netlist/analog/nlid_twoterm.h" -#include "netlist/nl_factory.h" +#include "../nl_base.h" +#include "../nl_factory.h" +#include "../analog/nlid_twoterm.h" namespace netlist { @@ -39,17 +39,17 @@ namespace netlist NETLIB_UPDATE_PARAM(r2r_dac) { - solve_now(); + update_dev(); double V = m_VIN() / static_cast<double>(1 << m_num()) * static_cast<double>(m_val()); - this->set_G_V_I(1.0 / m_R(), V, 0.0); + this->set(1.0 / m_R(), V, 0.0); } } //namespace analog namespace devices { - NETLIB_DEVICE_IMPL_NS(analog, r2r_dac, "R2R_DAC", "VIN,R,N") - } // namespace devices + NETLIB_DEVICE_IMPL_NS(analog, r2r_dac) + } } // namespace netlist diff --git a/src/lib/netlist/devices/nld_r2r_dac.h b/src/lib/netlist/devices/nld_r2r_dac.h index 8a4257a3cbf..18e5bddc053 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 "netlist/nl_setup.h" +#include "../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 f219d215520..4bc41075f89 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 "netlist/analog/nlid_twoterm.h" -#include "netlist/nl_base.h" -#include "netlist/nl_errstr.h" -#include "netlist/solver/nld_solver.h" +#include "../nl_base.h" +#include "../nl_errstr.h" +#include "../analog/nlid_twoterm.h" +#include "../solver/nld_solver.h" #include <cmath> @@ -82,11 +82,11 @@ namespace netlist NETLIB_RESETI() { m_last_state = 1; - m_RVI.reset(); - m_RVO.reset(); + m_RVI.do_reset(); + m_RVO.do_reset(); m_is_timestep = m_RVO.m_P.net().solver()->has_timestep_devices(); - 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); + 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); } NETLIB_UPDATEI() @@ -97,9 +97,9 @@ namespace netlist { m_last_state = 0; if (m_is_timestep) - 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(); + 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)); } } else @@ -108,9 +108,9 @@ namespace netlist { m_last_state = 1; if (m_is_timestep) - 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(); + 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)); } } } @@ -125,7 +125,7 @@ namespace netlist bool m_is_timestep; }; - NETLIB_DEVICE_IMPL(schmitt_trigger, "SCHMITT_TRIGGER", "MODEL") + NETLIB_DEVICE_IMPL(schmitt_trigger) } // namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_schmitt.h b/src/lib/netlist/devices/nld_schmitt.h index 20666b29cf7..ecce59be616 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ---------------------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp index 03aa5c678f1..eabc4b4fbff 100644 --- a/src/lib/netlist/devices/nld_system.cpp +++ b/src/lib/netlist/devices/nld_system.cpp @@ -5,8 +5,8 @@ * */ -#include "netlist/solver/nld_solver.h" -#include "netlist/solver/nld_matrix_solver.h" +#include "../solver/nld_solver.h" +#include "../solver/nld_matrix_solver.h" #include "nlid_system.h" namespace netlist @@ -40,40 +40,54 @@ 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_HANDLER(extclock, clk2) + NETLIB_UPDATE(extclock) { - m_Q.push((m_cnt & 1) ^ 1, m_inc[m_cnt]); + 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_HANDLER(extclock, clk2_pow2) + // ---------------------------------------------------------------------------------------- + // logic_input + // ---------------------------------------------------------------------------------------- + + NETLIB_RESET(logic_input) { - m_Q.push((m_cnt & 1) ^ 1, m_inc[m_cnt]); - m_cnt = (++m_cnt) & (m_size-1); + m_Q.initial(0); } - NETLIB_UPDATE(extclock) + NETLIB_UPDATE(logic_input) { - 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; + m_Q.push(m_IN() & 1, netlist_time::from_nsec(1)); + } - // continue with optimized clock handlers .... + NETLIB_UPDATE_PARAM(logic_input) + { + } + + // ---------------------------------------------------------------------------------------- + // 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); + NETLIB_RESET(analog_input) + { + m_Q.initial(0.0); } + NETLIB_UPDATE(analog_input) + { + m_Q.push(m_IN()); + } + + NETLIB_UPDATE_PARAM(analog_input) + { + } + + // ----------------------------------------------------------------------------- // nld_res_sw // ----------------------------------------------------------------------------- @@ -92,10 +106,19 @@ namespace netlist m_last_state = state; const nl_double R = state ? m_RON() : m_ROFF(); - // 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(); + // 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(); + } } } @@ -118,19 +141,17 @@ namespace netlist } - 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") + 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) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_system.h b/src/lib/netlist/devices/nld_system.h index 5158e098cfa..69a7c75dbf3 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 "netlist/nl_setup.h" +#include "../nl_setup.h" // ----------------------------------------------------------------------------- // Macros diff --git a/src/lib/netlist/devices/nld_tms4800.cpp b/src/lib/netlist/devices/nld_tms4800.cpp index 24729b10e72..29a9bd836ab 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 "netlist/nl_base.h" +#include "../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, "ROM_TMS4800", "+AR,+OE1,+OE2,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10") - NETLIB_DEVICE_IMPL(TMS4800_dip, "ROM_TMS4800_DIP", "") + NETLIB_DEVICE_IMPL(TMS4800) + NETLIB_DEVICE_IMPL(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 c5bcd1337f0..dc72354cb03 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 "netlist/nl_setup.h" +#include "../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 b05d09ea71e..74fbb206feb 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 "netlist/nl_base.h" +#include "../nl_base.h" namespace netlist { @@ -70,8 +70,8 @@ namespace netlist m_Q.push(q, NLTIME_FROM_NS(1)); } - NETLIB_DEVICE_IMPL(tristate, "TTL_TRISTATE", "+CEQ1,+D1,+CEQ2,+D2") - NETLIB_DEVICE_IMPL(tristate3, "TTL_TRISTATE3", "") + NETLIB_DEVICE_IMPL(tristate) + NETLIB_DEVICE_IMPL(tristate3) } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_tristate.h b/src/lib/netlist/devices/nld_tristate.h index 71f97d9812d..a5ff22fac96 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 "netlist/nl_setup.h" +#include "../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 d91d691453a..f9999aebcc0 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 "netlist/nl_base.h" -#include "netlist/nl_setup.h" +#include "../nl_setup.h" +#include "../nl_base.h" namespace netlist { diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp index a2fd18e85a7..4c3ec6f67aa 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 "netlist/solver/nld_solver.h" +#include "../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_state_t &anetlist, const pstring &name, + nld_base_proxy::nld_base_proxy(netlist_t &anetlist, const pstring &name, logic_t *inout_proxied, detail::core_terminal_t *proxy_inout) : device_t(anetlist, name) { @@ -29,23 +29,33 @@ 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_state_t &anetlist, const pstring &name, + nld_base_a_to_d_proxy::nld_base_a_to_d_proxy(netlist_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_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::~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_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) { } @@ -71,32 +81,39 @@ namespace netlist // nld_d_to_a_proxy // ---------------------------------------------------------------------------------------- - nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name, + nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(netlist_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_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::~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_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 std::vector<std::pair<pstring, pstring>> power_syms = { {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}; + 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); register_subalias("Q", m_RV.m_P); connect(m_RV.m_N, m_GNDHack); bool f = false; - for (auto & pwr_sym : power_syms) + for (int i = 0; i < 3; i++) { pstring devname = out_proxied->device().name(); - auto tp = setup().find_terminal(devname + "." + pwr_sym.first, + auto tp = netlist().setup().find_terminal(devname + "." + power_syms[i][0], detail::terminal_type::INPUT, false); - auto tn = setup().find_terminal(devname + "." + pwr_sym.second, + auto tn = netlist().setup().find_terminal(devname + "." + power_syms[i][1], detail::terminal_type::INPUT, false); if (tp != nullptr && tn != nullptr) { @@ -109,6 +126,11 @@ 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 } @@ -120,15 +142,15 @@ namespace netlist //m_Q.initial(0.0); m_last_state = -1; - m_RV.reset(); + m_RV.do_reset(); m_is_timestep = m_RV.m_P.net().solver()->has_timestep_devices(); - m_RV.set_G_V_I(plib::constants<nl_double>::one() / logic_family()->R_low(), + m_RV.set(NL_FCONST(1.0) / logic_family()->R_low(), logic_family()->low_V(0.0, supply_V), 0.0); } NETLIB_UPDATE(d_to_a_proxy) { - const auto state = static_cast<int>(m_I()); + const int state = static_cast<int>(m_I()); if (state != m_last_state) { // FIXME: Variable voltage @@ -141,10 +163,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(); + m_RV.update_dev(); } - m_RV.set_G_V_I(plib::constants<nl_double>::one() / R, V, 0.0); - m_RV.solve_later(); + m_RV.set(NL_FCONST(1.0) / R, V, 0.0); + m_RV.m_P.schedule_solve_after(NLTIME_FROM_NS(1)); } } diff --git a/src/lib/netlist/devices/nlid_proxy.h b/src/lib/netlist/devices/nlid_proxy.h index 9543b8db234..821cfa56d9d 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 "netlist/analog/nlid_twoterm.h" -#include "netlist/nl_setup.h" +#include "../nl_setup.h" +#include "../analog/nlid_twoterm.h" namespace netlist { @@ -26,9 +26,11 @@ namespace netlist NETLIB_OBJECT(base_proxy) { public: - nld_base_proxy(netlist_state_t &anetlist, const pstring &name, + nld_base_proxy(netlist_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; } @@ -47,11 +49,13 @@ 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_state_t &anetlist, const pstring &name, + nld_base_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied, detail::core_terminal_t *in_proxy); private: @@ -63,7 +67,9 @@ namespace netlist NETLIB_OBJECT_DERIVED(a_to_d_proxy, base_a_to_d_proxy) { public: - nld_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *in_proxied); + nld_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied); + + virtual ~nld_a_to_d_proxy() override; analog_input_t m_I; @@ -82,20 +88,24 @@ 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_state_t &anetlist, const pstring &name, + nld_base_d_to_a_proxy(netlist_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_state_t &anetlist, const pstring &name, logic_output_t *out_proxied); + nld_d_to_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *out_proxied); + virtual ~nld_d_to_a_proxy() override {} protected: diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index f1f2af1b31e..326cd3dbf2c 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 "netlist/analog/nlid_twoterm.h" -#include "netlist/nl_base.h" -#include "netlist/nl_setup.h" -#include "plib/putil.h" +#include "../nl_base.h" +#include "../nl_setup.h" +#include "../analog/nlid_twoterm.h" +#include "../plib/putil.h" namespace netlist { @@ -27,8 +27,7 @@ namespace netlist NETLIB_OBJECT(netlistparams) { NETLIB_CONSTRUCTOR(netlistparams) - , m_use_deactivate(*this, "USE_DEACTIVATE", false) - , m_startup_strategy(*this, "STARTUP_STRATEGY", 1) + , m_use_deactivate(*this, "USE_DEACTIVATE", 0) { } NETLIB_UPDATEI() { } @@ -36,7 +35,6 @@ namespace netlist //NETLIB_UPDATE_PARAMI() { } public: param_logic_t m_use_deactivate; - param_int_t m_startup_strategy; }; // ----------------------------------------------------------------------------- @@ -54,7 +52,7 @@ namespace netlist NETLIB_RESETI() { - m_Q.net().set_next_scheduled_time(netlist_time::zero()); + m_Q.net().set_time(netlist_time::zero()); } NETLIB_UPDATE_PARAMI() @@ -67,14 +65,16 @@ namespace netlist logic_net_t &net = m_Q.net(); // this is only called during setup ... net.toggle_new_Q(); - net.set_next_scheduled_time(exec().time() + m_inc); + net.set_time(netlist().time() + m_inc); } public: logic_output_t m_Q; - netlist_time m_inc; - private: + param_double_t m_freq; + netlist_time m_inc; + + inline static void mc_update(logic_net_t &net); }; // ----------------------------------------------------------------------------- @@ -96,7 +96,7 @@ namespace netlist //NETLIB_RESETI(); NETLIB_UPDATE_PARAMI(); - private: + protected: logic_input_t m_feedback; logic_output_t m_Q; @@ -127,35 +127,31 @@ namespace netlist std::vector<pstring> pat(plib::psplit(m_pattern(),",")); m_off = netlist_time::from_double(m_offset()); - std::array<std::int64_t, 32> pati = { 0 }; - + unsigned long pati[32]; + for (int pI = 0; pI < 32; pI++) + { + pati[pI] = 0; + } m_size = static_cast<std::uint8_t>(pat.size()); - netlist_time::mult_type total = 0; + unsigned long total = 0; for (unsigned i=0; i<m_size; i++) { - // FIXME: use pstonum_ne - //pati[i] = plib::pstonum<decltype(pati[i])>(pat[i]); - pati[i] = plib::pstonum<std::int64_t>(pat[i]); + pati[i] = static_cast<unsigned long>(pat[i].as_long()); total += pati[i]; } netlist_time ttotal = netlist_time::zero(); - auto sm1 = static_cast<uint8_t>(m_size - 1); - for (unsigned i=0; i < sm1; i++) + for (unsigned i=0; i<m_size - 1; i++) { m_inc[i] = base * pati[i]; ttotal += m_inc[i]; } - m_inc[sm1] = base * total - ttotal; + m_inc[m_size - 1] = base * total - ttotal; } } NETLIB_UPDATEI(); NETLIB_RESETI(); //NETLIB_UPDATE_PARAMI(); - - NETLIB_HANDLERI(clk2); - NETLIB_HANDLERI(clk2_pow2); - - private: + protected: param_double_t m_freq; param_str_t m_pattern; @@ -166,7 +162,7 @@ namespace netlist state_var_u8 m_cnt; std::uint8_t m_size; state_var<netlist_time> m_off; - std::array<netlist_time, 32> m_inc; + netlist_time m_inc[32]; }; // ----------------------------------------------------------------------------- @@ -177,19 +173,20 @@ namespace netlist { NETLIB_CONSTRUCTOR(logic_input) , m_Q(*this, "Q") - , m_IN(*this, "IN", false) + , m_IN(*this, "IN", 0) /* 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_UPDATEI() { } - NETLIB_RESETI() { m_Q.initial(0); } - NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN() & 1, netlist_time::from_nsec(1)); } + NETLIB_UPDATE_AFTER_PARAM_CHANGE() - private: + NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATE_PARAMI(); + + protected: logic_output_t m_Q; param_logic_t m_IN; @@ -203,12 +200,12 @@ namespace netlist , m_IN(*this, "IN", 0.0) { } + NETLIB_UPDATE_AFTER_PARAM_CHANGE() - NETLIB_UPDATEI() { } - NETLIB_RESETI() { m_Q.initial(0.0); } - NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN()); } - - private: + NETLIB_UPDATEI(); + NETLIB_RESETI(); + NETLIB_UPDATE_PARAMI(); + protected: analog_output_t m_Q; param_double_t m_IN; }; @@ -281,8 +278,8 @@ namespace netlist NETLIB_RESETI() { - 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); + m_RIN.set(1.0 / m_p_RIN(),0,0); + m_ROUT.set(1.0 / m_p_ROUT(),0,0); } NETLIB_UPDATEI() @@ -313,13 +310,13 @@ namespace netlist , m_N(*this, "N", 1) , m_func(*this, "FUNC", "A0") , m_Q(*this, "Q") - , m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager()) + , m_compiled(this->name() + ".FUNCC", this, this->netlist().state()) { std::vector<pstring> inps; for (int i=0; i < m_N(); i++) { pstring n = plib::pfmt("A{1}")(i); - m_I.push_back(pool().make_poolptr<analog_input_t>(*this, n)); + m_I.push_back(plib::make_unique<analog_input_t>(*this, n)); inps.push_back(n); m_vals.push_back(0.0); } @@ -336,7 +333,7 @@ namespace netlist param_int_t m_N; param_str_t m_func; analog_output_t m_Q; - std::vector<pool_owned_ptr<analog_input_t>> m_I; + std::vector<std::unique_ptr<analog_input_t>> m_I; std::vector<double> m_vals; plib::pfunction m_compiled; @@ -360,17 +357,16 @@ 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; - private: + 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 2221d855880..bf7d03fe3d7 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 "netlist/nl_setup.h" -#include "plib/palloc.h" -#include "plib/plists.h" +#include "../plib/plists.h" +#include "../nl_setup.h" +#include "../plib/palloc.h" #include <bitset> @@ -24,7 +24,7 @@ namespace netlist template <typename T> struct sbitset { - using type = T; + typedef T type; sbitset() : m_bs(0) { } /* explicit */ sbitset(T v) : m_bs(v) { } @@ -77,8 +77,8 @@ namespace netlist return ret; } - 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)); } + static constexpr sbitset all_bits() { return sbitset(~static_cast<T>(0)); } + static constexpr sbitset no_bits() { return sbitset(static_cast<T>(0)); } private: T m_bs; }; @@ -122,18 +122,8 @@ namespace netlist } } - 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 - } - } + uint_least64_t mask() const { return static_cast<uint_least64_t>(-1); } + private: void *m_data; size_t m_size; @@ -144,7 +134,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_out_state(outs), m_timing(timing), m_timing_nt(timing_nt), + m_outs(outs), m_timing(timing), m_timing_nt(timing_nt), m_num_bits(m_NI), m_size(1 << (m_num_bits)) { @@ -161,7 +151,7 @@ namespace netlist unsigned m_NO; unsigned m_NI; bool *m_initialized; - packed_int m_out_state; + packed_int m_outs; uint_least8_t *m_timing; netlist_time *m_timing_nt; @@ -188,27 +178,51 @@ 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> outputs(plib::psplit(io[1], ",")); - nl_assert_always(outputs.size() == m_NO, "output count wrong"); + std::vector<pstring> out(plib::psplit(io[1], ",")); + nl_assert_always(out.size() == m_NO, "output count wrong"); for (std::size_t i=0; i < m_NI; i++) { - inout[i] = plib::trim(inout[i]); + inout[i] = inout[i].trim(); m_I.emplace(i, *this, inout[i]); } for (std::size_t i=0; i < m_NO; 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]; + 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]; 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 } // ---------------------------------------------------------------------------------------- @@ -224,20 +238,15 @@ namespace netlist : netlist_base_factory_truthtable_t(name, classname, def_param, sourcefile) { } - pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) override + plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override { - using tt_type = nld_truthtable_t<m_NI, m_NO>; + typedef nld_truthtable_t<m_NI, m_NO> tt_type; truthtable_parser desc_s(m_NO, m_NI, &m_ttbl.m_initialized, - 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()); + packed_int(m_ttbl.m_outs, sizeof(m_ttbl.m_outs[0]) * 8), + m_ttbl.m_timing, m_ttbl.m_timing_nt); desc_s.parse(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); + return plib::owned_ptr<device_t>::Create<tt_type>(anetlist, name, m_family, m_ttbl, m_desc); } private: typename nld_truthtable_t<m_NI, m_NO>::truthtable_t m_ttbl; @@ -250,7 +259,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_out_state[state] == m_out_state[tt_bitset(state).set(j)]) + if (m_outs[state] == m_outs[tt_bitset(state).set(j)]) ignore.set(j); } @@ -276,7 +285,7 @@ namespace netlist { tt_bitset b = tign.expand_and(k); // will any of the inputs ignored change the output if changed? - if (m_out_state[state] != m_out_state[(state & tign.invert()) | b]) + if (m_outs[state] != m_outs[(state & tign.invert()) | b]) { t[j] = true; break; @@ -309,21 +318,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 = plib::trim(list[cur]); + pstring elem = list[cur].trim(); uint_least64_t start = 0; uint_least64_t end = 0; - if (elem == "0") + if (elem.equals("0")) { start = 0; end = 0; } - else if (elem == "1") + else if (elem.equals("1")) { start = 1; end = 1; } - else if (elem == "X") + else if (elem.equals("X")) { start = 0; end = 1; @@ -343,10 +352,10 @@ void truthtable_parser::parseline(unsigned cur, std::vector<pstring> list, else { // cutoff previous inputs and outputs for ignore - 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); + 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); for (std::size_t j=0; j<m_NO; j++) m_timing[nstate * m_NO + j] = timing_index[j]; } @@ -366,12 +375,12 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable) line++; for (unsigned j=0; j < m_size; j++) - m_out_state.set(j, tt_bitset::all_bits()); + m_outs.set(j, tt_bitset::all_bits()); for (int j=0; j < 16; j++) m_timing_nt[j] = netlist_time::zero(); - while (!(ttline == "")) + while (!ttline.equals("")) { std::vector<pstring> io(plib::psplit(ttline,"|")); // checks @@ -393,13 +402,12 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable) */ for (unsigned j=0; j<m_NO; j++) { - pstring outs = plib::trim(out[j]); - if (outs == "1") + pstring outs = out[j].trim(); + if (outs.equals("1")) val.set(j); else - 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]))); + 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())); uint_least8_t k=0; while (m_timing_nt[k] != netlist_time::zero() && m_timing_nt[k] != t) k++; @@ -442,9 +450,9 @@ void truthtable_parser::parse(const std::vector<pstring> &truthtable) } for (size_t i=0; i<m_size; i++) { - if (m_out_state[i] == m_out_state.mask()) + if (m_outs[i] == m_outs.mask()) throw nl_exception(plib::pfmt("truthtable: found element not set {1}\n").x(i) ); - m_out_state.set(i, m_out_state[i] | (ign[i] << m_NO)); + m_outs.set(i, m_outs[i] | (ign[i] << m_NO));; } *m_initialized = true; @@ -452,21 +460,26 @@ 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_desc(family_TTL()) +: factory::element_t(name, classname, def_param, sourcefile), m_family(family_TTL()) +{ +} + +netlist_base_factory_truthtable_t::~netlist_base_factory_truthtable_t() { } + #define ENTRYY(n, m, s) case (n * 100 + m): \ { using xtype = netlist_factory_truthtable_t<n, m>; \ - ret = plib::make_unique<xtype>(desc.name, desc.classname, desc.def_param, s); } break + ret = plib::palloc<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) -plib::unique_ptr<netlist_base_factory_truthtable_t> tt_factory_create(tt_desc &desc, const pstring &sourcefile) +void tt_factory_create(setup_t &setup, tt_desc &desc, const pstring &sourcefile) { - plib::unique_ptr<netlist_base_factory_truthtable_t> ret; + netlist_base_factory_truthtable_t *ret; switch (desc.ni * 100 + desc.no) { @@ -487,9 +500,9 @@ plib::unique_ptr<netlist_base_factory_truthtable_t> tt_factory_create(tt_desc &d nl_assert_always(false, msg); } ret->m_desc = desc.desc; - ret->m_family_name = desc.family; - - return ret; + 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)); } } //namespace devices diff --git a/src/lib/netlist/devices/nlid_truthtable.h b/src/lib/netlist/devices/nlid_truthtable.h index 1217d7ee873..311f5ebd8ca 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 "netlist/nl_base.h" -#include "netlist/nl_setup.h" -#include "plib/putil.h" +#include "../nl_setup.h" +#include "../nl_base.h" +#include "../plib/putil.h" #define NETLIB_TRUTHTABLE(cname, nIN, nOUT) \ class NETLIB_NAME(cname) : public nld_truthtable_t<nIN, nOUT> \ @@ -29,9 +29,17 @@ 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 { @@ -44,35 +52,11 @@ namespace devices }; template<unsigned bits> struct uint_for_size; - 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<> 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<std::size_t m_NI, std::size_t m_NO> NETLIB_OBJECT(truthtable_t) @@ -81,23 +65,22 @@ namespace devices detail::family_setter_t m_fam; public: - using type_t = typename uint_for_size<need_bytes_for_bits<m_NO + m_NI>::value>::type; + typedef typename uint_for_size<need_bytes_for_bits<m_NO + m_NI>::value>::type type_t; 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_timing_index{0} - , m_initialized(false) + : 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> @@ -107,6 +90,7 @@ namespace devices : 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); @@ -116,14 +100,13 @@ namespace devices NETLIB_RESETI() { - int active_outputs = 0; + m_active = 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) - active_outputs++; - set_active_outputs(active_outputs); + m_active++; } NETLIB_UPDATEI() @@ -133,14 +116,28 @@ namespace devices void inc_active() NL_NOEXCEPT override { - process<false>(); + if (m_NI >= m_min_devices_for_deactivate) + if (++m_active == 1) + { + process<false>(); + } } void dec_active() NL_NOEXCEPT override { - for (std::size_t i = 0; i< m_NI; i++) - m_I[i].inactivate(); - m_ign = (1<<m_NI)-1; + /* 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; + } } plib::uninitialised_array_t<logic_input_t, m_NI> m_I; @@ -156,44 +153,46 @@ namespace devices netlist_time mt(netlist_time::zero()); type_t nstate(0); - 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 (m_NI >= m_min_devices_for_deactivate) { - 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); + 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; + } } else - nstate = aa<m_NI, type_t>().f(m_I, ign); -#endif + { + 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); + } - const type_t outstate(m_ttp.m_out_state[nstate]); + const type_t outstate(m_ttp.m_outs[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_index[timebase]); - const auto *tim = m_ttp.m_timing_nt.data(); + const auto *t(&m_ttp.m_timing[timebase]); + const auto *tim = m_ttp.m_timing_nt; if (doOUT) for (std::size_t i = 0; i < m_NO; out >>= 1, ++i) @@ -202,14 +201,18 @@ namespace devices for (std::size_t i = 0; i < m_NO; out >>= 1, ++i) m_Q[i].set_Q_time(out & 1, mt + tim[t[i]]); - ign = m_ign; - for (auto I = m_I.begin(); ign != 0; ign >>= 1, ++I) - if (ign & 1) - I->inactivate(); + 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(); + } } /* FIXME: check width */ state_var<type_t> m_ign; + state_var_s32 m_active; const truthtable_t &m_ttp; }; @@ -219,15 +222,15 @@ namespace devices 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; - pstring m_family_name; - const logic_family_desc_t *m_family_desc; + const logic_family_desc_t *m_family; }; - /* 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); + void tt_factory_create(setup_t &setup, 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 86f2450d301..8ea6f148864 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 "netlist/nl_setup.h" -#include "netlist/devices/net_lib.h" +#include "../nl_setup.h" +#include "../devices/net_lib.h" #include "nlm_base.h" /* ---------------------------------------------------------------------------- @@ -12,14 +12,9 @@ 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)") @@ -31,16 +26,9 @@ 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 CJE=0 CJC=0)") - NET_MODEL("PNP _(IS=1e-15 BF=100 NF=1 BR=1 NR=1 CJE=0 CJC=0)") + 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("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)") @@ -58,8 +46,6 @@ 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() /* ---------------------------------------------------------------------------- @@ -88,22 +74,19 @@ 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(mosfet_models) - INCLUDE(family_models) - INCLUDE(TTL74XX_lib) - INCLUDE(CD4XXX_lib) - INCLUDE(OPAMP_lib) - INCLUDE(otheric_lib) + INCLUDE(diode_models); + INCLUDE(bjt_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 6a88ad5a1be..5ecf8071e98 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 "netlist/nl_setup.h" +#include "../nl_setup.h" /* ---------------------------------------------------------------------------- * Netlist Macros diff --git a/src/lib/netlist/macro/nlm_cd4xxx.cpp b/src/lib/netlist/macro/nlm_cd4xxx.cpp index 5ebd5593123..9ce786ca85e 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 "netlist/devices/nld_4020.h" -#include "netlist/devices/nld_4066.h" -#include "netlist/devices/nld_4316.h" -#include "netlist/devices/nld_system.h" +#include "../devices/nld_system.h" +#include "../devices/nld_4020.h" +#include "../devices/nld_4066.h" +#include "../devices/nld_4316.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 d4d9c97fdc2..527336c1e8e 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 "netlist/nl_setup.h" +#include "../nl_setup.h" /* * Devices: diff --git a/src/lib/netlist/macro/nlm_opamp.cpp b/src/lib/netlist/macro/nlm_opamp.cpp index 849f7820046..122b324f777 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 "netlist/devices/net_lib.h" +#include "../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 fbd7547c976..9cffbb29c87 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 "netlist/nl_setup.h" +#include "../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 ea0eb1539a8..7e31ae27bb4 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 "netlist/devices/nld_system.h" +#include "../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 ee231fbd6db..7c38d8ad363 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 "netlist/nl_setup.h" +#include "../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 58cab049ae7..df1b873a468 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 "netlist/devices/nld_schmitt.h" -#include "netlist/devices/nld_system.h" +#include "../devices/nld_schmitt.h" +#include "../devices/nld_system.h" /* @@ -825,9 +825,8 @@ 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("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 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 21ff99f2efe..c8868e45f7f 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 "netlist/nl_setup.h" +#include "../nl_setup.h" #ifndef __PLIB_PREPROCESSOR__ diff --git a/src/lib/netlist/netlist_types.h b/src/lib/netlist/netlist_types.h new file mode 100644 index 00000000000..0bd32be21be --- /dev/null +++ b/src/lib/netlist/netlist_types.h @@ -0,0 +1,54 @@ +// 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 ad048e899bf..9a513c00804 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -8,19 +8,18 @@ #include "solver/nld_matrix_solver.h" #include "solver/nld_solver.h" -#include "plib/palloc.h" -#include "plib/pmempool.h" #include "plib/putil.h" +#include "plib/palloc.h" -#include "devices/nlid_proxy.h" +#include "nl_base.h" #include "devices/nlid_system.h" +#include "devices/nlid_proxy.h" #include "macro/nlm_base.h" -#include "nl_base.h" #include "nl_errstr.h" -#include <cmath> #include <cstring> +#include <cmath> #include <limits> namespace netlist @@ -28,13 +27,14 @@ namespace netlist namespace detail { - //static plib::mempool *pool() - //{ - // static plib::mempool s_pool(655360, 32); - // return &s_pool; - //} + static plib::mempool *pool() + { + static plib::mempool *s_pool = nullptr; + if (s_pool == nullptr) + s_pool = new plib::mempool(65536, 16); + return s_pool; + } -#if 0 void * object_t::operator new (size_t size) { void *ret = nullptr; @@ -44,30 +44,38 @@ 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 -} // namespace detail +} + +nl_exception::~nl_exception() +{ +} // ---------------------------------------------------------------------------------------- // 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: @@ -82,17 +90,17 @@ public: m_R_low = 1.0; m_R_high = 130.0; } - 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; + 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> logic_family_ttl_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const +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 { - return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied); } -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 +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 { - return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied); + return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied); } class logic_family_cd4xxx_t : public logic_family_desc_t @@ -109,18 +117,17 @@ public: m_R_low = 10.0; m_R_high = 10.0; } - 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; + 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> logic_family_cd4xxx_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const +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 { - return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied); } - -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 +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 { - return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied); + return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<devices::nld_a_to_d_proxy>(anetlist, name, proxied); } const logic_family_desc_t *family_TTL() @@ -139,10 +146,10 @@ const logic_family_desc_t *family_CD4XXX() // queue_t // ---------------------------------------------------------------------------------------- -detail::queue_t::queue_t(netlist_state_t &nl) - : timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>(512) +detail::queue_t::queue_t(netlist_t &nl) + : timed_queue<pqentry_t<net_t *, netlist_time>, false>(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) @@ -151,56 +158,52 @@ detail::queue_t::queue_t(netlist_state_t &nl) void detail::queue_t::register_state(plib::state_manager_t &manager, const pstring &module) { - //state().log().debug("register_state\n"); + netlist().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(plib::state_manager_t &manager) +void detail::queue_t::on_pre_save() { - plib::unused_var(manager); + netlist().log().debug("on_pre_save\n"); 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] = state().find_net_id(this->listptr()[i].m_object); + m_net_ids[i] = netlist().find_net_id(this->listptr()[i].m_object); } } -void detail::queue_t::on_post_load(plib::state_manager_t &manager) +void detail::queue_t::on_post_load() { - 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 = state().nets()[m_net_ids[i]].get(); + detail::net_t *n = netlist().m_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(aname) + : m_name(plib::make_unique<pstring>(aname)) { - name_hash().insert({this, aname}); } -pstring detail::object_t::name() const +detail::object_t::~object_t() { - return name_hash().find(this)->second; - //return m_name; +} + +const pstring &detail::object_t::name() const +{ + return *m_name; } // ---------------------------------------------------------------------------------------- @@ -227,7 +230,7 @@ detail::terminal_type detail::core_terminal_t::type() const return terminal_type::OUTPUT; else { - state().log().fatal(MF_1_UNKNOWN_TYPE_FOR_OBJECT, name()); + netlist().log().fatal(MF_1_UNKNOWN_TYPE_FOR_OBJECT, name()); return terminal_type::TERMINAL; // please compiler } } @@ -236,37 +239,158 @@ detail::terminal_type detail::core_terminal_t::type() const // netlist_t // ---------------------------------------------------------------------------------------- -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_time(netlist_time::zero()) +netlist_t::netlist_t(const pstring &aname) + : m_time(netlist_time::zero()) + , m_queue(*this) , m_mainclock(nullptr) - , m_queue(*m_state) + , m_solver(nullptr) + , m_params(nullptr) + , m_name(aname) + , m_log(*this) + , m_lib(nullptr) + , m_state() { - 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"); + 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::~netlist_t() +{ + m_nets.clear(); + m_devices.clear(); +} -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)) +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_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() + ); +} + + + +void netlist_t::start() +{ + 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() { @@ -277,7 +401,7 @@ void netlist_t::stop() m_solver->stop(); } -detail::net_t *netlist_state_t::find_net(const pstring &name) const +detail::net_t *netlist_t::find_net(const pstring &name) const { for (auto & net : m_nets) if (net->name() == name) @@ -286,7 +410,7 @@ detail::net_t *netlist_state_t::find_net(const pstring &name) const return nullptr; } -std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const +std::size_t netlist_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) @@ -296,7 +420,7 @@ std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const -void netlist_state_t::rebuild_lists() +void netlist_t::rebuild_lists() { for (auto & net : m_nets) net->rebuild_list(); @@ -305,44 +429,32 @@ void netlist_state_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_next_scheduled_time(netlist_time::zero()); + m_mainclock->m_Q.net().set_time(netlist_time::zero()); //if (m_solver != nullptr) - // m_solver->reset(); - - m_state->reset(); -} + // m_solver->do_reset(); -void netlist_state_t::reset() -{ - //FIXME: never used ??? std::unordered_map<core_device_t *, bool> m; + for (auto &d : m_devices) + { + m[d.get()] = d->get_hint_deactivate(); + } + + // Reset all nets once ! - log().verbose("Call reset on all nets:"); - for (auto & n : nets()) + for (auto & n : m_nets) n->reset(); // Reset all devices once ! - log().verbose("Call reset on all devices:"); for (auto & dev : m_devices) - dev.second->reset(); + dev->do_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.second->update_param(); + dev->update_param(); // Step all devices once ! /* @@ -350,9 +462,9 @@ void netlist_state_t::reset() * variations are explicitly stated in the breakout manual. */ - auto *netlist_params = get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter"); + const unsigned startup_strategy = 1; //! \note make this a parameter - switch (netlist_params->m_startup_strategy()) + switch (startup_strategy) { case 0: { @@ -360,7 +472,7 @@ void netlist_state_t::reset() std::vector<nldelegate *> t; log().verbose("Using default startup strategy"); for (auto &n : m_nets) - for (auto & term : n->core_terms()) + for (auto & term : n->m_core_terms) if (term->m_delegate.has_object()) { if (!plib::container::contains(t, &term->m_delegate)) @@ -368,68 +480,70 @@ void netlist_state_t::reset() t.push_back(&term->m_delegate); term->m_delegate(); } - auto *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object()); + core_device_t *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object()); if (!plib::container::contains(d, dev)) d.push_back(dev); } - log().verbose("Devices not yet updated:"); - for (auto &dev : m_devices) - if (!plib::container::contains(d, dev.second.get())) + log().verbose("Call update on devices which need parameter update:"); + for (auto & dev : m_devices) + if (dev->needs_update_after_param_change()) { - log().verbose("\t ...{1}", dev.second->name()); - dev.second->update(); + 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(); } 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].second->update(); - - for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1 - n->update_inputs(); - + m_devices[--i]->update_dev(); } break; case 2: // brute force forward { - log().verbose("Using brute force forward startup strategy"); for (auto &d : m_devices) - d.second->update(); + d->update_dev(); } break; } #if 1 /* the above may screw up m_active and the list */ - rebuild_lists(); + for (auto &n : m_nets) + n->rebuild_list(); #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.pop()); + detail::queue_t::entry_t e(m_queue.top()); + 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.pop(); + e = m_queue.top(); + m_queue.pop(); m_time = e.m_exec_time; } } @@ -437,7 +551,9 @@ 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.next_scheduled_time()); + netlist_time mc_time(mc_net.time()); + + detail::queue_t::entry_t e; do { @@ -449,37 +565,37 @@ void netlist_t::process_queue(const netlist_time delta) NL_NOEXCEPT mc_time += inc; } - detail::queue_t::entry_t e(m_queue.pop()); + e = m_queue.top(); + m_queue.pop(); m_time = e.m_exec_time; if (e.m_object != nullptr) { e.m_object->update_devs(); m_perf_out_processed.inc(); } - else - break; - } while (true); //while (e.m_object != nullptr); - mc_net.set_next_scheduled_time(mc_time); + } while (e.m_object != nullptr); + mc_net.set_time(mc_time); } + m_stat_mainloop.stop(); } void netlist_t::print_stats() const { - if (nperftime_t<NL_KEEP_STATISTICS>::enabled) + if (nperftime_t::enabled) { std::vector<size_t> index; - for (size_t i=0; i < m_state->m_devices.size(); i++) + for (size_t i=0; i<m_devices.size(); i++) index.push_back(i); std::sort(index.begin(), index.end(), - [&](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(); }); + [&](size_t i1, size_t i2) { return m_devices[i1]->m_stat_total_time.total() < m_devices[i2]->m_stat_total_time.total(); }); - nperftime_t<NL_KEEP_STATISTICS>::type total_time(0); - nperftime_t<NL_KEEP_STATISTICS>::ctype total_count(0); + nperftime_t::type total_time(0); + uint_least64_t total_count(0); for (auto & j : index) { - auto entry = m_state->m_devices[j].second.get(); + auto entry = m_devices[j].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()); @@ -487,27 +603,22 @@ void netlist_t::print_stats() const total_count += entry->m_stat_total_time.count(); } - 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; + nperftime_t overhead; + nperftime_t test; + overhead.start(); + for (int j=0; j<100000;j++) { - auto overhead_guard(overhead.guard()); - for (int j=0; j<100000;j++) - { - auto test_guard(test.guard()); - } + test.start(); + test.stop(); } + overhead.stop(); - 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); + nperftime_t::type total_overhead = overhead() + * static_cast<nperftime_t::type>(total_count) + / static_cast<nperftime_t::type>(200000); - 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("Queue Pushes {1:15}", queue().m_prof_call()); + log().verbose("Queue Moves {1:15}", queue().m_prof_sortmove()); log().verbose("Total loop {1:15}", m_stat_mainloop()); /* Only one serialization should be counted in total time */ @@ -516,36 +627,29 @@ 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<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()); + 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()); log().verbose("Overhead per pop {1:11}", overhead_per_pop ); log().verbose(""); - - auto trigger = total_count * 200 / 1000000; // 200 ppm - for (auto &entry : m_state->m_devices) + for (auto &entry : m_devices) { - 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()); + if (entry->m_stat_inc_active() > 3 * entry->m_stat_total_time.count()) + log().verbose("HINT({}, NO_DEACTIVATE)", entry->name()); } } } -core_device_t *netlist_state_t::get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const +core_device_t *netlist_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.second.get())) + if (cc(d.get())) { if (ret != nullptr) - m_log.fatal(MF_1_MORE_THAN_ONE_1_DEVICE_FOUND, classname); + this->log().fatal(MF_1_MORE_THAN_ONE_1_DEVICE_FOUND, classname); else - ret = d.second.get(); + ret = d.get(); } } return ret; @@ -556,12 +660,11 @@ core_device_t *netlist_state_t::get_single_device(const pstring &classname, bool // core_device_t // ---------------------------------------------------------------------------------------- -core_device_t::core_device_t(netlist_state_t &owner, const pstring &name) +core_device_t::core_device_t(netlist_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()); @@ -570,14 +673,17 @@ core_device_t::core_device_t(netlist_state_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.state()) + , netlist_ref(owner.netlist()) , 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()); - state().add_dev(this->name(), pool_owned_ptr<core_device_t>(this, false)); + owner.netlist().register_dev(plib::owned_ptr<core_device_t>(this, false)); +} + +core_device_t::~core_device_t() +{ } void core_device_t::set_default_delegate(detail::core_terminal_t &term) @@ -586,16 +692,16 @@ void core_device_t::set_default_delegate(detail::core_terminal_t &term) term.m_delegate.set(&core_device_t::update, this); } -log_type & core_device_t::log() +plib::plog_base<netlist_t, NL_DEBUG> &core_device_t::log() { - return state().log(); + return netlist().log(); } // ---------------------------------------------------------------------------------------- // device_t // ---------------------------------------------------------------------------------------- -device_t::device_t(netlist_state_t &owner, const pstring &name) +device_t::device_t(netlist_t &owner, const pstring &name) : core_device_t(owner, name) { } @@ -605,14 +711,14 @@ device_t::device_t(core_device_t &owner, const pstring &name) { } -setup_t &device_t::setup() +device_t::~device_t() { - return state().setup(); + //log().debug("~net_device_t\n"); } -const setup_t &device_t::setup() const +setup_t &device_t::setup() { - return state().setup(); + return netlist().setup(); } void device_t::register_subalias(const pstring &name, detail::core_terminal_t &term) @@ -656,14 +762,9 @@ 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.setup().family_from_model(desc)); + dev.set_logic_family(dev.netlist().setup().family_from_model(desc)); } detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_desc_t *desc) @@ -675,45 +776,81 @@ detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_ // net_t // ---------------------------------------------------------------------------------------- -detail::net_t::net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *mr) +detail::net_t::net_t(netlist_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", queue_status::DELIVERED) - , m_next_scheduled_time(*this, "m_time", netlist_time::zero()) + , m_in_queue(*this, "m_in_queue", QS_DELIVERED) + , m_active(*this, "m_active", 0) + , m_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->terminal_state() != logic_t::STATE_INP_PASSIVE) + if (term->state() != logic_t::STATE_INP_PASSIVE) { m_list_active.push_back(term); - term->set_copied_input(m_cur_Q); + cnt++; } + m_active = cnt; } -template <typename T> -void detail::net_t::process(const T mask, netlist_sig_t sig) -{ - m_cur_Q = sig; +void detail::net_t::process(unsigned Mask) +{ for (auto & p : m_list_active) { - p.set_copied_input(sig); - p.device().m_stat_call_count.inc(); - if ((p.terminal_state() & mask)) + if ((p.state() & Mask) != 0) { - auto g(p.device().m_stat_total_time.guard()); - //p.device().m_stat_total_time.start(); + p.device().m_stat_total_time.start(); p.m_delegate(); - //p.device().m_stat_total_time.stop(); + p.device().m_stat_total_time.stop(); } } } @@ -722,59 +859,67 @@ void detail::net_t::update_devs() NL_NOEXCEPT { nl_assert(this->isRailNet()); - const auto new_Q(m_new_Q); + const unsigned mask((m_new_Q << core_terminal_t::INP_LH_SHIFT) + | (m_cur_Q<<core_terminal_t::INP_HL_SHIFT)); - const auto mask((new_Q << core_terminal_t::INP_LH_SHIFT) - | (m_cur_Q << core_terminal_t::INP_HL_SHIFT)); + m_in_queue = QS_DELIVERED; /* mark as taken ... */ - 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: - process(mask | core_terminal_t::STATE_INP_ACTIVE, new_Q); + m_cur_Q = m_new_Q; + process(core_terminal_t::STATE_INP_LH | core_terminal_t::STATE_INP_ACTIVE); break; default: - /* do nothing */ break; } } void detail::net_t::reset() { - m_next_scheduled_time = netlist_time::zero(); - m_in_queue = queue_status::DELIVERED; + m_time = netlist_time::zero(); + m_active = 0; + m_in_queue = QS_DELIVERED; m_new_Q = 0; m_cur_Q = 0; - auto *p = dynamic_cast<analog_net_t *>(this); + analog_net_t *p = dynamic_cast<analog_net_t *>(this); if (p != nullptr) p->m_cur_Analog = 0.0; - /* rebuild m_list and reset terminals to active or analog out state */ + /* rebuild m_list */ 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(); - if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE) - m_list_active.push_back(ct); - ct->set_copied_input(m_cur_Q); - } + + for (core_terminal_t *ct : m_core_terms) + if (ct->state() != logic_t::STATE_INP_PASSIVE) + m_active++; } void detail::net_t::add_terminal(detail::core_terminal_t &terminal) { for (auto &t : m_core_terms) if (t == &terminal) - state().log().fatal(MF_2_NET_1_DUPLICATE_TERMINAL_2, name(), + netlist().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) @@ -785,8 +930,10 @@ void detail::net_t::remove_terminal(detail::core_terminal_t &terminal) plib::container::remove(m_core_terms, &terminal); } else - state().log().fatal(MF_2_REMOVE_TERMINAL_1_FROM_NET_2, terminal.name(), + netlist().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) @@ -794,28 +941,37 @@ 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_state_t &nl, const pstring &aname, detail::core_terminal_t *mr) +logic_net_t::logic_net_t(netlist_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_state_t &nl, const pstring &aname, detail::core_terminal_t *mr) +analog_net_t::analog_net_t(netlist_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 // ---------------------------------------------------------------------------------------- @@ -825,19 +981,42 @@ 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) @@ -846,18 +1025,26 @@ 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 *otherterm) +terminal_t::terminal_t(core_device_t &dev, const pstring &aname) : analog_t(dev, aname, STATE_BIDIR) +, m_otherterm(nullptr) , m_Idr1(nullptr) , m_go1(nullptr) , m_gt1(nullptr) -, m_connected_terminal(otherterm) { - state().setup().register_term(*this); + netlist().setup().register_term(*this); +} + +terminal_t::~terminal_t() +{ } void terminal_t::solve_now() @@ -868,7 +1055,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()) @@ -890,12 +1077,16 @@ 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.state(), name() + ".net", this) + , m_my_net(dev.netlist(), name() + ".net", this) { this->set_net(&m_my_net); - state().register_net(pool_owned_ptr<logic_net_t>(&m_my_net, false)); + netlist().m_nets.push_back(plib::owned_ptr<logic_net_t>(&m_my_net, false)); set_logic_family(dev.logic_family()); - state().setup().register_term(*this); + netlist().setup().register_term(*this); +} + +logic_output_t::~logic_output_t() +{ } void logic_output_t::initial(const netlist_sig_t val) @@ -911,7 +1102,11 @@ 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) { - state().setup().register_term(*this); + netlist().setup().register_term(*this); +} + +analog_input_t::~analog_input_t() +{ } // ---------------------------------------------------------------------------------------- @@ -920,13 +1115,17 @@ analog_input_t::analog_input_t(core_device_t &dev, const pstring &aname) analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname) : analog_t(dev, aname, STATE_OUT) - , m_my_net(dev.state(), name() + ".net", this) + , m_my_net(dev.netlist(), name() + ".net", this) { - state().register_net(pool_owned_ptr<analog_net_t>(&m_my_net, false)); + netlist().m_nets.push_back(plib::owned_ptr<analog_net_t>(&m_my_net, false)); this->set_net(&m_my_net); //net().m_cur_Analog = NL_FCONST(0.0); - state().setup().register_term(*this); + netlist().setup().register_term(*this); +} + +analog_output_t::~analog_output_t() +{ } void analog_output_t::initial(const nl_double val) @@ -943,7 +1142,11 @@ 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()); - state().setup().register_term(*this); + netlist().setup().register_term(*this); +} + +logic_input_t::~logic_input_t() +{ } // ---------------------------------------------------------------------------------------- @@ -953,7 +1156,11 @@ logic_input_t::logic_input_t(core_device_t &dev, const pstring &aname, param_t::param_t(device_t &device, const pstring &name) : device_object_t(device, device.name() + "." + name) { - device.setup().register_param_t(this->name(), *this); + device.setup().register_param(this->name(), *this); +} + +param_t::~param_t() +{ } param_t::param_type_t param_t::param_type() const @@ -970,7 +1177,7 @@ param_t::param_type_t param_t::param_type() const return POINTER; else { - state().log().fatal(MF_1_UNKNOWN_PARAM_TYPE, name()); + netlist().log().fatal(MF_1_UNKNOWN_PARAM_TYPE, name()); return POINTER; /* Please compiler */ } } @@ -979,18 +1186,15 @@ param_t::param_type_t param_t::param_type() const void param_t::update_param() { device().update_param(); -} - -pstring param_t::get_initial(const device_t &dev, bool *found) -{ - pstring res = dev.setup().get_initial_param_val(this->name(), ""); - *found = (res != ""); - return res; + if (device().needs_update_after_param_change()) + device().update_dev(); } const pstring param_model_t::model_type() { - return state().setup().models().model_type(value()); + if (m_map.size() == 0) + netlist().setup().model_parse(this->Value(), m_map); + return m_map["COREMODEL"]; } param_str_t::param_str_t(device_t &device, const pstring &name, const pstring &val) @@ -999,10 +1203,35 @@ param_str_t::param_str_t(device_t &device, const pstring &name, const pstring &v 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) +{ + m_param = device.setup().get_initial_param_val(this->name(),val); + netlist().save(*this, m_param, "m_param"); +} + +param_int_t::param_int_t(device_t &device, const pstring &name, const int 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) +{ + 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) : param_t(device, name) { @@ -1012,25 +1241,53 @@ param_ptr_t::param_ptr_t(device_t &device, const pstring &name, uint8_t * val) void param_model_t::changed() { - state().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name()); + netlist().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name()); + m_map.clear(); } const pstring param_model_t::model_value_str(const pstring &entity) { - return state().setup().models().model_value_str(value(), entity); + if (m_map.size() == 0) + netlist().setup().model_parse(this->Value(), m_map); + return netlist().setup().model_value_str(m_map, entity); } nl_double param_model_t::model_value(const pstring &entity) { - return state().setup().models().model_value(value(), entity); + if (m_map.size() == 0) + netlist().setup().model_parse(this->Value(), m_map); + return netlist().setup().model_value(m_map, entity); } +param_data_t::param_data_t(device_t &device, const pstring &name) +: param_str_t(device, name, "") +{ +} + +void param_data_t::changed() +{ +} -plib::unique_ptr<plib::pistream> param_data_t::stream() +std::unique_ptr<plib::pistream> param_data_t::stream() { - return device().setup().get_data_stream(value()); + return device().netlist().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 9d0eed869e0..e56fde89f88 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -9,25 +9,27 @@ #ifndef NLBASE_H_ #define NLBASE_H_ -#ifdef NL_PROHIBIT_BASEH_INCLUDE -#error "nl_base.h included. Please correct." -#endif - +#include "nl_lists.h" +#include "nl_time.h" #include "plib/palloc.h" // owned_ptr #include "plib/pdynlib.h" -#include "plib/pfmtlog.h" -#include "plib/pmempool.h" -#include "plib/ppmf.h" #include "plib/pstate.h" +#include "plib/pfmtlog.h" #include "plib/pstream.h" - -#include "nl_errstr.h" -#include "nl_lists.h" -#include "nltypes.h" -#include "plib/ptime.h" +#include "plib/ppmf.h" #include <unordered_map> -#include <vector> + +#ifdef NL_PROHIBIT_BASEH_INCLUDE +#error "nl_base.h included. Please correct." +#endif + +// ---------------------------------------------------------------------------------------- +// Type definitions +// ---------------------------------------------------------------------------------------- + +/*! netlist_sig_t is the type used for logic signals. */ +using netlist_sig_t = std::uint32_t; //============================================================ // MACROS / New Syntax @@ -71,7 +73,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)() noexcept +#define NETLIB_DESTRUCTOR(name) public: virtual ~NETLIB_NAME(name)() /*! Define an extended constructor and add further parameters to it. * The macro allows to add further parameters to a device constructor. This is @@ -83,15 +85,14 @@ 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; } @@ -126,30 +127,36 @@ 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() 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_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_TIMESTEP(chip) void NETLIB_NAME(chip) :: timestep(const nl_double step) #define NETLIB_SUB(chip) nld_ ## chip -#define NETLIB_SUBXX(ns, chip) pool_owned_ptr< ns :: nld_ ## chip > +#define NETLIB_SUBXX(ns, chip) std::unique_ptr< ns :: nld_ ## chip > -#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name() NL_NOEXCEPT +#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name(void) 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() +#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param(void) #define NETLIB_FUNC_VOID(chip, name, params) void NETLIB_NAME(chip) :: name params -#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals() +#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals(void) //============================================================ // Asserts @@ -162,7 +169,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("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(plib::pfmt("Fatal error: {1}\nCaused by assert: {2}:{3}: {4}")(msg)(__FILE__)(__LINE__)(#x)); } while (0) //============================================================ // Namespace starts @@ -170,11 +177,6 @@ class NETLIB_NAME(name) : public device_t namespace netlist { - /*! Delegate type for device notification. - * - */ - using nldelegate = plib::pmfp<void>; - // ----------------------------------------------------------------------------- // forward definitions // ----------------------------------------------------------------------------- @@ -189,23 +191,27 @@ 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; - } // namespace detail + class net_t; + } 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 @@ -223,12 +229,9 @@ namespace netlist explicit nl_exception(const pstring &text //!< text to be passed ) : plib::pexception(text) { } - - 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)...)) { } + /*! Copy constructor. */ + nl_exception(const nl_exception &e) : plib::pexception(e) { } + virtual ~nl_exception(); }; /*! Logic families descriptors are used to create proxy devices. @@ -239,21 +242,18 @@ namespace netlist { public: logic_family_desc_t(); + virtual ~logic_family_desc_t(); - 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, + 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 = 0; - virtual pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, + 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 = 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 { 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 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 R_low() const { return m_R_low; } double R_high() const { return m_R_high; } @@ -282,14 +282,12 @@ 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() noexcept = default; // prohibit polymorphic destruction + ~logic_family_t() { } // prohibit polymorphic destruction const logic_family_desc_t *m_logic_family; }; @@ -319,15 +317,12 @@ 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) = default; + constexpr state_var(const state_var &rhs) noexcept = 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) = default; + C14CONSTEXPR state_var &operator=(const state_var &rhs) noexcept = 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. @@ -350,29 +345,25 @@ namespace netlist * Please refer to \ref state_var. */ template <typename T, std::size_t N> - struct state_array + struct state_var<T[N]> { public: //! Constructor. template <typename O> - state_array(O &owner, //!< owner must have a netlist() method. + state_var(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_array(const state_array &rhs) noexcept = default; - //! Destructor. - ~state_array() noexcept = default; + state_var(const state_var &rhs) NL_NOEXCEPT = default; //! Move Constructor. - 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]; } + 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]; } private: - std::array<T, N> m_value; + T m_value[N]; }; // ----------------------------------------------------------------------------- @@ -391,324 +382,164 @@ namespace netlist /*! predefined state variable type for sig_t */ using state_var_sig = state_var<netlist_sig_t>; - namespace detail { + // ----------------------------------------------------------------------------- + // object_t + // ----------------------------------------------------------------------------- - // ----------------------------------------------------------------------------- - // object_t - // ----------------------------------------------------------------------------- + /*! 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: - /*! The base class for netlist devices, terminals and parameters. + /*! Constructor. * - * 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. + * Every class derived from the object_t class must have a name. */ - class object_t - { - public: - - /*! 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 + explicit object_t(const pstring &aname /*!< string containing name of the object */); - 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; - } - }; - - struct netlist_ref - { - explicit netlist_ref(netlist_state_t &nl); + /*! return name of the object + * + * \returns name of the object. + */ + const pstring &name() const; - COPYASSIGNMOVE(netlist_ref, delete) + 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 - netlist_state_t & state() noexcept; - const netlist_state_t & state() const noexcept; + private: + std::unique_ptr<pstring> m_name; + }; - setup_t & setup() noexcept; - const setup_t & setup() const noexcept; + struct detail::netlist_ref + { + explicit constexpr netlist_ref(netlist_t &nl) : m_netlist(nl) { } - netlist_t & exec() noexcept { return m_netlist; } - const netlist_t & exec() const noexcept { return m_netlist; } + C14CONSTEXPR netlist_t & netlist() NL_NOEXCEPT { return m_netlist; } + constexpr const netlist_t & netlist() const NL_NOEXCEPT { return m_netlist; } - protected: - ~netlist_ref() noexcept = default; // prohibit polymorphic destruction + protected: + ~netlist_ref() = default; // prohibit polymorphic destruction - private: - netlist_t & m_netlist; + private: + netlist_t & m_netlist; - }; + }; - // ----------------------------------------------------------------------------- - // device_object_t - // ----------------------------------------------------------------------------- + // ----------------------------------------------------------------------------- + // 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. + /*! 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. * + * \param dev device owning the object. + * \param name string holding the name of the device */ - 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; + device_object_t(core_device_t &dev, const pstring &name); - private: - core_device_t & m_device; - }; - - // ----------------------------------------------------------------------------- - // core_terminal_t - // ----------------------------------------------------------------------------- - - /*! Base class for all terminals. - * - * All terminals are derived from this class. - * + /*! 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; } - class net_t; - - class core_terminal_t : public device_object_t, - public plib::linkedlist_t<core_terminal_t>::element_t - { - public: - - using list_t = std::vector<core_terminal_t *>; - - 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); } + /*! The netlist owning the owner of this object. + * \returns reference to netlist object. + */ + netlist_t &netlist() NL_NOEXCEPT; + const netlist_t &netlist() const NL_NOEXCEPT; - const net_t & net() const noexcept { return *m_net;} - net_t & net() noexcept { return *m_net;} + private: + core_device_t & m_device; +}; - bool is_logic() const NL_NOEXCEPT; - bool is_analog() const NL_NOEXCEPT; + /*! Delegate type for device notification. + * + */ + typedef plib::pmfp<void> nldelegate; - 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; } + // ----------------------------------------------------------------------------- + // core_terminal_t + // ----------------------------------------------------------------------------- - void reset() noexcept { set_state(is_type(OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); } + /*! 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: - nldelegate m_delegate; - #if USE_COPY_INSTEAD_OF_REFERENCE - void set_copied_input(netlist_sig_t val) - { - m_Q = val; - } + using list_t = std::vector<core_terminal_t *>; - state_var_sig m_Q; - #else - void set_copied_input(netlist_sig_t val) const { plib::unused_var(val); } - #endif + static constexpr const unsigned INP_HL_SHIFT = 0; + static constexpr const unsigned INP_LH_SHIFT = 1; + static constexpr const unsigned INP_ACTIVE_SHIFT = 2; - private: - net_t * m_net; - state_var<state_e> m_state; + 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 }; - // ----------------------------------------------------------------------------- - // net_t - // ----------------------------------------------------------------------------- - - class net_t : - public object_t, - public netlist_ref - { - public: - - enum class queue_status - { - DELAYED_DUE_TO_INACTIVE = 0, - QUEUED, - DELIVERED - }; - - net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *mr = nullptr); - - COPYASSIGNMOVE(net_t, delete) - - virtual ~net_t() noexcept = default; - - void reset(); - - void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); } - - 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: + core_terminal_t(core_device_t &dev, const pstring &aname, + const state_e state, nldelegate delegate = nldelegate()); + virtual ~core_terminal_t(); - /* only used for logic nets */ - netlist_sig_t Q() const noexcept { return m_cur_Q; } + /*! 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); } - /* only used for logic nets */ - void initial(const netlist_sig_t val) noexcept - { - m_cur_Q = m_new_Q = val; - update_inputs(); - } + void set_net(net_t *anet); + void clear_net(); + bool has_net() const NL_NOEXCEPT { return (m_net != nullptr); } - /* 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); - } - } + const net_t & net() const NL_NOEXCEPT { return *m_net;} + net_t & net() NL_NOEXCEPT { return *m_net;} - /* 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(); - } + bool is_logic() const NL_NOEXCEPT; + bool is_analog() const NL_NOEXCEPT; - /* 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(); } + 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; } - 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; + void reset(); - 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 ... + nldelegate m_delegate; - template <typename T> - void process(const T mask, netlist_sig_t sig); - }; - } // namespace detail + private: + net_t * m_net; + state_var<state_e> m_state; + }; // ----------------------------------------------------------------------------- // analog_t @@ -719,6 +550,7 @@ 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; @@ -732,44 +564,53 @@ namespace netlist { public: - terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm); + terminal_t(core_device_t &dev, const pstring &aname); + virtual ~terminal_t(); nl_double operator ()() const NL_NOEXCEPT; - void set_conductivity(const nl_double G) noexcept + void set(const nl_double &G) NL_NOEXCEPT { - set_go_gt_I(-G, G, 0.0); + set(G,G, 0.0); } - void set_go_gt(const nl_double GO, const nl_double GT) noexcept + void set(const nl_double &GO, const nl_double >) NL_NOEXCEPT { - set_go_gt_I(GO, GT, 0.0); + set(GO, GT, 0.0); } - void set_go_gt_I(const nl_double GO, const nl_double GT, const nl_double I) noexcept + void set(const nl_double &GO, const nl_double >, const nl_double &I) NL_NOEXCEPT { - 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; - } + set_ptr(m_Idr1, I); + set_ptr(m_go1, GO); + set_ptr(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) noexcept; + 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; - 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; - }; @@ -782,6 +623,7 @@ 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; } @@ -805,6 +647,7 @@ 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 { @@ -836,6 +679,9 @@ namespace netlist const pstring &aname /*!< name of terminal */ ); + /*! Destructor */ + virtual ~analog_input_t(); + /*! returns voltage at terminal. * \returns voltage at terminal. */ @@ -848,18 +694,124 @@ 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_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr); + 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(); } - 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; + protected: + private: }; @@ -871,7 +823,9 @@ namespace netlist friend class detail::net_t; - analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr); + analog_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr); + + virtual ~analog_net_t(); 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; } @@ -895,15 +849,21 @@ 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 set_Q_time(const netlist_sig_t newQ, const netlist_time at) NL_NOEXCEPT + 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 { m_my_net.set_Q_time(newQ, at); // take the shortcut } @@ -916,6 +876,7 @@ 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); @@ -943,17 +904,13 @@ namespace netlist param_t(device_t &device, const pstring &name); - COPYASSIGNMOVE(param_t, delete) - param_type_t param_type() const; protected: - virtual ~param_t() noexcept = default; /* not intended to be destroyed */ + virtual ~param_t(); /* 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) { @@ -966,51 +923,53 @@ namespace netlist }; - // ----------------------------------------------------------------------------- - // numeric parameter template - // ----------------------------------------------------------------------------- - - template <typename T> - class param_num_t final: public param_t + class param_ptr_t final: public param_t { public: - param_num_t(device_t &device, const pstring &name, const T val); - - const T operator()() const NL_NOEXCEPT { return m_param; } - void setTo(const T ¶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: - T m_param; + std::uint8_t* m_param; }; - /* 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_logic_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; + }; - class param_ptr_t final: public param_t + class param_int_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); } + 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); } private: - std::uint8_t* m_param; + int m_param; }; - // ----------------------------------------------------------------------------- - // string parameter - // ----------------------------------------------------------------------------- + class param_double_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); } + private: + double m_param; + }; 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) @@ -1022,16 +981,11 @@ 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: @@ -1043,8 +997,8 @@ namespace netlist : m_value(param.model_value(name)) { } - double operator()() const noexcept { return m_value; } - operator double() const noexcept { return m_value; } + const double &operator()() const NL_NOEXCEPT { return m_value; } + operator const double&() const NL_NOEXCEPT { return m_value; } private: const double m_value; }; @@ -1056,29 +1010,24 @@ 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: - void changed() override; + virtual 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_str_t(device, name, "") - { - } + param_data_t(device_t &device, const pstring &name); - plib::unique_ptr<plib::pistream> stream(); + std::unique_ptr<plib::pistream> stream(); protected: - void changed() override { } + virtual void changed() override; }; // ----------------------------------------------------------------------------- @@ -1092,15 +1041,15 @@ namespace netlist param_rom_t(device_t &device, const pstring &name); - ST operator[] (std::size_t n) const NL_NOEXCEPT { return m_data[n]; } + const ST & operator[] (std::size_t n) NL_NOEXCEPT { return m_data[n]; } protected: - void changed() override + virtual void changed() override { - stream()->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW); + stream()->read(&m_data[0],1<<AW); } private: - std::array<ST, 1 << AW> m_data; + ST m_data[1 << AW]; }; // ----------------------------------------------------------------------------- @@ -1113,67 +1062,68 @@ namespace netlist public detail::netlist_ref { public: - core_device_t(netlist_state_t &owner, const pstring &name); + core_device_t(netlist_t &owner, const pstring &name); core_device_t(core_device_t &owner, const pstring &name); - COPYASSIGNMOVE(core_device_t, delete) + virtual ~core_device_t(); - virtual ~core_device_t() noexcept = default; + void update_dev() NL_NOEXCEPT + { + do_update(); + } void do_inc_active() NL_NOEXCEPT { if (m_hint_deactivate) { - if (++m_active_outputs == 1) - { - m_stat_inc_active.inc(); - inc_active(); - } + m_stat_inc_active.inc(); + inc_active(); } } void do_dec_active() NL_NOEXCEPT { if (m_hint_deactivate) - if (--m_active_outputs == 0) - { - dec_active(); - } + 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<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; + nperftime_t m_stat_total_time; + nperfcount_t m_stat_call_count; + nperfcount_t 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() { } - log_type & log(); + void do_update() NL_NOEXCEPT + { + update(); + } + + plib::plog_base<netlist_t, NL_DEBUG> &log(); public: - virtual void timestep(const nl_double st) { plib::unused_var(st); } + virtual void timestep(ATTR_UNUSED const nl_double 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; - state_var_s32 m_active_outputs; + bool m_hint_deactivate; }; // ----------------------------------------------------------------------------- @@ -1184,20 +1134,17 @@ namespace netlist { public: - device_t(netlist_state_t &owner, const pstring &name); + device_t(netlist_t &owner, const pstring &name); device_t(core_device_t &owner, const pstring &name); - COPYASSIGNMOVE(device_t, delete) - - ~device_t() noexcept override = default; + virtual ~device_t() override; setup_t &setup(); - const setup_t &setup() const; template<class C, typename... Args> - void create_and_register_subdevice(const pstring &name, pool_owned_ptr<C> &dev, Args&&... args) + void register_sub(const pstring &name, std::unique_ptr<C> &dev, const Args&... args) { - dev = pool().make_poolptr<C>(*this, name, std::forward<Args>(args)...); + dev.reset(plib::palloc<C>(*this, name, args...)); } void register_subalias(const pstring &name, detail::core_terminal_t &term); @@ -1220,18 +1167,13 @@ namespace netlist struct detail::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() { } 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) @@ -1248,25 +1190,19 @@ namespace netlist * solvers will update inputs after parallel processing. */ class detail::queue_t : - public timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>, + public timed_queue<pqentry_t<net_t *, netlist_time>, false>, public detail::netlist_ref, public plib::state_manager_t::callback_t { public: - 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; + typedef pqentry_t<net_t *, netlist_time> entry_t; + explicit queue_t(netlist_t &nl); protected: void register_state(plib::state_manager_t &manager, const pstring &module) override; - void on_pre_save(plib::state_manager_t &manager) override; - void on_post_load(plib::state_manager_t &manager) override; + void on_pre_save() override; + void on_post_load() override; private: std::size_t m_qsize; @@ -1275,214 +1211,139 @@ namespace netlist }; // ----------------------------------------------------------------------------- - // netlist_state__t + // netlist_t // ----------------------------------------------------------------------------- - class netlist_state_t + + class netlist_t : private plib::nocopyassignmove { public: - using nets_collection_type = std::vector<pool_owned_ptr<detail::net_t>>; - - /* 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); - - COPYASSIGNMOVE(netlist_state_t, delete) - - ~netlist_state_t() noexcept = default; - - friend class netlist_t; // allow access to private members + explicit netlist_t(const pstring &aname); + virtual ~netlist_t(); - template<class C> - static bool check_class(core_device_t *p) - { - return dynamic_cast<C *>(p) != nullptr; - } + /* run functions */ - template<class C> - C *get_single_device(const pstring &classname) const - { - return dynamic_cast<C *>(get_single_device(classname, check_class<C>)); - } + const netlist_time &time() const NL_NOEXCEPT { return m_time; } + devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; } - /* logging and name */ + /* never use this in constructors! */ + nl_double gmin() const NL_NOEXCEPT; - pstring name() const { return m_name; } + 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)); } - log_type & log() { return m_log; } - const log_type &log() const { return m_log; } + /* Control functions */ - plib::dynlib &lib() { return *m_lib; } + void start(); + void stop(); + void reset(); - netlist_t &exec() { return m_netlist; } - const netlist_t &exec() const { return m_netlist; } + const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; } + detail::queue_t &queue() NL_NOEXCEPT { return m_queue; } - /* state handling */ - plib::state_manager_t &run_state_manager() { return m_state; } + /* netlist build functions */ - 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); - } + setup_t &setup() NL_NOEXCEPT { return *m_setup; } - core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const; + void register_dev(plib::owned_ptr<core_device_t> dev); + void remove_dev(core_device_t *dev); 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> - inline std::vector<device_class *> get_device_list() + std::vector<device_class *> get_device_list() const { std::vector<device_class *> tmp; for (auto &d : m_devices) { - auto dev = dynamic_cast<device_class *>(d.second.get()); + device_class *dev = dynamic_cast<device_class *>(d.get()); if (dev != nullptr) tmp.push_back(dev); } return tmp; } - template <typename T> - void add_dev(const pstring &name, pool_owned_ptr<T> &&dev) + template<class C> + static bool check_class(core_device_t *p) { - 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) }); + return dynamic_cast<C *>(p) != nullptr; } - /** - * @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) + template<class C> + C *get_single_device(const pstring &classname) const { - 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; - } + return dynamic_cast<C *>(get_single_device(classname, check_class<C>)); } - /* sole use is to manage lifetime of family objects */ - std::vector<std::pair<pstring, plib::unique_ptr<logic_family_desc_t>>> m_family_cache; - - setup_t &setup() NL_NOEXCEPT { return *m_setup; } - const setup_t &setup() const NL_NOEXCEPT { return *m_setup; } + /* logging and name */ - nets_collection_type & nets() { return m_nets; } - devices_collection_type & devices() { return m_devices; } + 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; } - // FIXME: make a postload member and include code there - void rebuild_lists(); /* must be called after post_load ! */ + /* state related */ - private: + plib::state_manager_t &state() { return m_state; } - void reset(); + 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); + } - 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; + plib::dynlib &lib() { return *m_lib; } - nets_collection_type m_nets; + // FIXME: find something better /* sole use is to manage lifetime of net objects */ - devices_collection_type m_devices; - - - - }; - - // ----------------------------------------------------------------------------- - // netlist_t - // ----------------------------------------------------------------------------- - - class netlist_t - { - public: - - explicit netlist_t(const pstring &aname, plib::unique_ptr<callbacks_t> callbacks); - - COPYASSIGNMOVE(netlist_t, delete) - - ~netlist_t() noexcept = default; - - /* run functions */ - - netlist_time time() const NL_NOEXCEPT { return m_time; } - - 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)); } - - const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; } - detail::queue_t &queue() NL_NOEXCEPT { return m_queue; } + 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; - /* Control functions */ + // FIXME: sort rebuild_lists out + void rebuild_lists(); /* must be called after post_load ! */ - void stop(); - void reset(); + /* logging callback */ + virtual void vlog(const plib::plog_level &l, const pstring &ls) const = 0; - /* state handling */ + protected: - plib::state_manager_t &run_state_manager() { return m_state->run_state_manager(); } + void print_stats() const; - /* only used by nltool to create static c-code */ - devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; } + private: - /* 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(); - } + /* 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; } - netlist_state_t &nlstate() NL_NOEXCEPT { return *m_state; } - const netlist_state_t &nlstate() const { return *m_state; } + core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const; - log_type & log() { return m_state->log(); } - const log_type &log() const { return m_state->log(); } + /* mostly rw */ + netlist_time m_time; + detail::queue_t m_queue; - void print_stats() const; + /* mostly ro */ - private: - plib::unique_ptr<netlist_state_t> m_state; - devices::NETLIB_NAME(solver) * m_solver; + devices::NETLIB_NAME(mainclock) * m_mainclock; + devices::NETLIB_NAME(solver) * m_solver; + devices::NETLIB_NAME(netlistparams) *m_params; - /* mostly rw */ - PALIGNAS_CACHELINE() - netlist_time m_time; - devices::NETLIB_NAME(mainclock) * m_mainclock; + 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 - PALIGNAS_CACHELINE() - detail::queue_t m_queue; + plib::state_manager_t m_state; // performance - nperftime_t<NL_KEEP_STATISTICS> m_stat_mainloop; - nperfcount_t<NL_KEEP_STATISTICS> m_perf_out_processed; + nperftime_t m_stat_mainloop; + nperfcount_t m_perf_out_processed; + + std::vector<plib::owned_ptr<core_device_t>> m_devices; }; // ----------------------------------------------------------------------------- @@ -1495,13 +1356,12 @@ namespace netlist public: struct init { - std::array<const char *, N> p; + const char *p[N]; }; - template<typename... Args> - object_array_t(core_device_t &dev, init names, Args&&... args) + object_array_t(core_device_t &dev, init names) { for (std::size_t i = 0; i<N; i++) - this->emplace(i, dev, pstring(names.p[i]), std::forward<Args>(args)...); + this->emplace(i, dev, pstring(names.p[i], pstring::UTF8)); } }; @@ -1509,56 +1369,15 @@ 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> - param_rom_t<ST, AW, DW>::param_rom_t(device_t &device, const pstring &name) + inline 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(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW); + f->read(&m_data[0],1<<AW); else - device.state().log().warning("Rom {1} not found", value()); + device.netlist().log().warning("Rom {1} not found", Value()); } inline void logic_input_t::inactivate() NL_NOEXCEPT @@ -1566,7 +1385,7 @@ namespace netlist if (!is_state(STATE_INP_PASSIVE)) { set_state(STATE_INP_PASSIVE); - net().remove_from_active_list(*this); + net().dec_active(*this); } } @@ -1574,7 +1393,7 @@ namespace netlist { if (is_state(STATE_INP_PASSIVE)) { - net().add_to_active_list(*this); + net().inc_active(*this); set_state(STATE_INP_ACTIVE); } } @@ -1583,7 +1402,7 @@ namespace netlist { if (is_state(STATE_INP_PASSIVE)) { - net().add_to_active_list(*this); + net().inc_active(*this); set_state(STATE_INP_HL); } } @@ -1592,68 +1411,24 @@ namespace netlist { if (is_state(STATE_INP_PASSIVE)) { - net().add_to_active_list(*this); + net().inc_active(*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()) - 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); + 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)); } } - 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()); @@ -1666,18 +1441,6 @@ 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()); @@ -1690,14 +1453,8 @@ namespace netlist inline netlist_sig_t logic_input_t::Q() const NL_NOEXCEPT { - 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 + nl_assert(state() != STATE_INP_PASSIVE); return net().Q(); -#endif } inline nl_double analog_input_t::Q_Analog() const NL_NOEXCEPT @@ -1714,24 +1471,14 @@ namespace netlist } } - 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 + inline netlist_t &detail::device_object_t::netlist() NL_NOEXCEPT { - return m_device.exec(); + return m_device.netlist(); } - inline const netlist_t &detail::device_object_t::exec() const NL_NOEXCEPT + inline const netlist_t &detail::device_object_t::netlist() const NL_NOEXCEPT { - return m_device.exec(); + return m_device.netlist(); } template <typename T> @@ -1739,18 +1486,18 @@ namespace netlist state_var<T>::state_var(O &owner, const pstring &name, const T &value) : m_value(value) { - owner.state().save(owner, m_value, owner.name(), name); + owner.netlist().save(owner, m_value, name); } template <typename T, std::size_t N> template <typename O> - state_array<T,N>::state_array(O &owner, const pstring &name, const T & value) + state_var<T[N]>::state_var(O &owner, const pstring &name, const T & value) { - owner.state().save(owner, m_value, owner.name(), name); + owner.netlist().save(owner, m_value, name); for (std::size_t i=0; i<N; i++) m_value[i] = value; } -} // namespace netlist +} namespace plib { @@ -1758,7 +1505,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 faa5008ff56..6a65abac40a 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -26,21 +26,10 @@ * 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 (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) +#define USE_MEMPOOL (0) /* * FIXME: Using truthtable is a lot slower than the explicit device @@ -54,13 +43,23 @@ #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 @@ -87,19 +86,24 @@ #endif // !defined(USE_OPENMP) // Use nano-second resolution - Sufficient for now - -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(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 48695e393ec..b0ebdb2e371 100644 --- a/src/lib/netlist/nl_dice_compat.h +++ b/src/lib/netlist/nl_dice_compat.h @@ -29,7 +29,6 @@ sed -e 's/#define \(.*\)"\(.*\)"[ \t]*,[ \t]*\(.*\)/NET_ALIAS(\1,\2.\3)/' src/ma #include "analog/nld_twoterm.h" #include <cmath> - #endif @@ -112,8 +111,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) @@ -132,9 +131,9 @@ public: NET_C(name.6, name ## _R.1) \ NET_C(name.6, name ## _C.1) \ NET_C(name ## _R.2, V5) \ - NET_C(name ## _C.2, GND) \ + NET_CSTR(# name "_C.2", "GND") \ NET_C(name.8, V5) \ - NET_C(name.1, GND) + NET_CSTR(# name ".1", "GND") #define CHIP_555_Astable(name, pdesc) \ NE555_DIP(name) \ @@ -147,9 +146,9 @@ public: NET_C(name.6, name ## _C.1) \ NET_C(name.2, name ## _C.1) \ NET_C(name ## _R1.2, V5) \ - NET_C(name ## _C.2, GND) \ + NET_CSTR(# name "_C.2", "GND") \ NET_C(name.8, V5) \ - NET_C(name.1, GND) + NET_CSTR(# name ".1", "GND") #define CHIP_9602_Mono(name, pdesc) \ CHIP(# name, 9602) \ @@ -179,13 +178,13 @@ public: #define CHIP_INPUT_ACTIVE_LOW(name) \ SWITCH2(name ## _SW) \ NET_C(name ## _SW.1, V5) \ - NET_C(name ## _SW.2, GND) \ + NET_CSTR(# 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_C(name ## _SW.1, GND) \ + NET_CSTR(# 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 ee3c47f3339..35b1e4f6c60 100644 --- a/src/lib/netlist/nl_errstr.h +++ b/src/lib/netlist/nl_errstr.h @@ -58,8 +58,7 @@ //#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_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_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 1f0ac35c6c4..2bb49590c4b 100644 --- a/src/lib/netlist/nl_factory.cpp +++ b/src/lib/netlist/nl_factory.cpp @@ -10,84 +10,102 @@ #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_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) +class NETLIB_NAME(wrapper) : public device_t +{ +public: + NETLIB_NAME(wrapper)(netlist_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) - : m_name(name), m_classname(classname), m_def_param(def_param), - m_sourcefile("<unknown>") - { - } - // ---------------------------------------------------------------------------------------- - // net_device_t_base_factory - // ---------------------------------------------------------------------------------------- - list_t::list_t(log_type &alog) - : m_log(alog) - { - } +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) +{ +} - 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)); - } +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>") +{ +} - 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 - } +element_t::~element_t() +{ +} - // ----------------------------------------------------------------------------- - // factory_lib_entry_t: factory class to wrap macro based chips/elements - // ----------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// net_device_t_base_factory +// ---------------------------------------------------------------------------------------- - 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); - } +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)); +} - void library_element_t::macro_actions(nlparse_t &nparser, const pstring &name) +factory::element_t * list_t::factory_by_name(const pstring &devname) +{ + for (auto & e : *this) { - nparser.namespace_push(name); - nparser.include(this->name()); - nparser.namespace_pop(); + 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 +// ----------------------------------------------------------------------------- + +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); +} + +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(); +} + +NETLIB_RESET(wrapper) +{ +} + +NETLIB_UPDATE(wrapper) +{ +} + -} // namespace factory - } // namespace netlist +} } diff --git a/src/lib/netlist/nl_factory.h b/src/lib/netlist/nl_factory.h index 271bf72bf90..6dad6c5e171 100644 --- a/src/lib/netlist/nl_factory.h +++ b/src/lib/netlist/nl_factory.h @@ -9,58 +9,46 @@ #ifndef NLFACTORY_H_ #define NLFACTORY_H_ -#include "nltypes.h" #include "plib/palloc.h" #include "plib/ptypes.h" -#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, p_name, p_def_param) \ - NETLIB_DEVICE_IMPL_BASE(ns, chip, chip, p_name, p_def_param) \ +#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); -#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) \ +#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) \ { \ - return plib::make_unique<factory::device_element_t<ns :: NETLIB_NAME(chip)>>(p_name, classname, p_def_param, pstring(__FILE__)); \ + return std::unique_ptr<factory::element_t>(plib::palloc<factory::device_element_t<ns :: NETLIB_NAME(chip)>>(name, classname, def_param, pstring(__FILE__))); \ } \ - \ - factory::constructor_ptr_t decl_ ## p_alias = NETLIB_NAME(p_alias ## _c); + factory::constructor_ptr_t decl_ ## chip = NETLIB_NAME(chip ## _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 + class element_t : plib::nocopyassignmove { 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() = default; + virtual ~element_t(); - 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); - } + virtual plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) = 0; + virtual void macro_actions(netlist_t &anetlist, const pstring &name) {} const pstring &name() const { return m_name; } const pstring &classname() const { return m_classname; } @@ -85,28 +73,26 @@ namespace factory { const pstring &def_param, const pstring &sourcefile) : element_t(name, classname, def_param, sourcefile) { } - pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) override + plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override { - return pool().make_poolptr<C>(anetlist, name); + return plib::owned_ptr<device_t>::Create<C>(anetlist, name); } }; - class list_t : public std::vector<plib::unique_ptr<element_t>> + class list_t : public std::vector<std::unique_ptr<element_t>> { public: - explicit list_t(log_type &alog); - ~list_t() = default; - - COPYASSIGNMOVE(list_t, delete) + explicit list_t(setup_t &m_setup); + ~list_t(); template<class device_class> void register_device(const pstring &name, const pstring &classname, const pstring &def_param) { - register_device(plib::make_unique<device_element_t<device_class>>(name, classname, def_param)); + register_device(std::unique_ptr<element_t>(plib::palloc<device_element_t<device_class>>(name, classname, def_param))); } - void register_device(plib::unique_ptr<element_t> &&factory); + void register_device(std::unique_ptr<element_t> &&factory); element_t * factory_by_name(const pstring &devname); @@ -117,20 +103,21 @@ namespace factory { } private: - log_type &m_log; + setup_t &m_setup; }; // ----------------------------------------------------------------------------- // factory_creator_ptr_t // ----------------------------------------------------------------------------- - using constructor_ptr_t = plib::unique_ptr<element_t> (*)(const pstring &classname); + using constructor_ptr_t = std::unique_ptr<element_t> (*)(const pstring &name, const pstring &classname, + const pstring &def_param); template <typename T> - plib::unique_ptr<element_t> constructor_t(const pstring &name, const pstring &classname, + std::unique_ptr<element_t> constructor_t(const pstring &name, const pstring &classname, const pstring &def_param) { - return plib::make_unique<device_element_t<T>>(name, classname, def_param); + return std::unique_ptr<element_t>(plib::palloc<device_element_t<T>>(name, classname, def_param)); } // ----------------------------------------------------------------------------- @@ -141,24 +128,22 @@ namespace factory { { public: - library_element_t(const pstring &name, const pstring &classname, + library_element_t(setup_t &setup, 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) { } - pool_owned_ptr<device_t> Create(netlist_state_t &anetlist, const pstring &name) override; + plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override; - void macro_actions(nlparse_t &nparser, const pstring &name) override; + void macro_actions(netlist_t &anetlist, 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 325f8a67c72..1eae38b25fb 100644 --- a/src/lib/netlist/nl_lists.h +++ b/src/lib/netlist/nl_lists.h @@ -10,24 +10,32 @@ #ifndef NLLISTS_H_ #define NLLISTS_H_ -#include "plib/pchrono.h" +#include "nl_config.h" +#include "netlist_types.h" #include "plib/plists.h" +#include "plib/pchrono.h" #include "plib/ptypes.h" -#include "nl_config.h" -#include "nltypes.h" - -#include <algorithm> #include <atomic> -#include <mutex> #include <thread> +#include <mutex> +#include <algorithm> #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 @@ -35,11 +43,10 @@ namespace netlist class pspin_mutex { public: - pspin_mutex() noexcept = default; + pspin_mutex() noexcept { } 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; }; @@ -55,11 +62,10 @@ 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) { } -#if 0 + constexpr pqentry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { } ~pqentry_t() = default; constexpr pqentry_t(const pqentry_t &e) noexcept = default; - constexpr pqentry_t(pqentry_t &&e) noexcept = default; + constexpr pqentry_t(pqentry_t &&e) = default; pqentry_t& operator=(pqentry_t && other) noexcept = default; pqentry_t& operator=(const pqentry_t &other) noexcept = default; @@ -68,97 +74,91 @@ namespace netlist std::swap(m_exec_time, other.m_exec_time); std::swap(m_object, other.m_object); } -#endif + struct QueueOp { - inline static constexpr bool less(const pqentry_t &lhs, const pqentry_t &rhs) noexcept + static constexpr bool less(const pqentry_t &lhs, const pqentry_t &rhs) noexcept { return (lhs.m_exec_time < rhs.m_exec_time); } - 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 + static constexpr bool equal(const pqentry_t &lhs, const pqentry_t &rhs) noexcept { return lhs.m_object == rhs.m_object; } - inline static constexpr bool equal(const pqentry_t &lhs, const Element &rhs) noexcept + static constexpr bool equal(const pqentry_t &lhs, const Element &rhs) noexcept { return lhs.m_object == rhs; } - inline static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); } + 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, bool KEEPSTAT, class QueueOp = typename T::QueueOp> - class timed_queue_linear : plib::nocopyassignmove + template <class T, bool TS, class QueueOp = typename T::QueueOp> + class timed_queue : plib::nocopyassignmove { public: - explicit timed_queue_linear(const std::size_t list_size) + explicit timed_queue(const std::size_t list_size) : m_list(list_size) { clear(); } - std::size_t capacity() const noexcept { return m_list.capacity() - 1; } - bool empty() const noexcept { return (m_end == &m_list[1]); } + constexpr std::size_t capacity() const noexcept { return m_list.capacity() - 1; } + constexpr bool empty() const noexcept { return (m_end == &m_list[1]); } - void push(T && e) noexcept + void push(T &&e) noexcept { /* Lock */ - lock_guard_type lck(m_lock); - T * i(m_end-1); - for (; QueueOp::less(*(i), e); --i) + tqlock lck(m_lock); + T * i(m_end); + for (; QueueOp::less(*(i - 1), e); --i) { - *(i+1) = *(i); + *(i) = std::move(*(i-1)); m_prof_sortmove.inc(); } - *(i+1) = std::move(e); + *i = std::move(e); ++m_end; m_prof_call.inc(); } - T pop() noexcept { return *(--m_end); } + void pop() noexcept { --m_end; } const T &top() const noexcept { return *(m_end-1); } template <class R> void remove(const R &elem) noexcept { /* Lock */ - lock_guard_type lck(m_lock); - m_prof_remove.inc(); - + tqlock lck(m_lock); for (T * i = m_end - 1; i > &m_list[0]; --i) { if (QueueOp::equal(*i, elem)) { - std::copy(i+1, m_end--, i); + --m_end; + for (;i < m_end; ++i) + *i = std::move(*(i+1)); return; } } } - void retime(T && elem) noexcept + void retime(const T &elem) noexcept { /* Lock */ - lock_guard_type lck(m_lock); - m_prof_retime.inc(); - + tqlock lck(m_lock); for (T * i = m_end - 1; i > &m_list[0]; --i) { if (QueueOp::equal(*i, elem)) // partial equal! { - *i = std::move(elem); + *i = elem; while (QueueOp::less(*(i-1), *i)) { std::swap(*(i-1), *i); @@ -174,9 +174,9 @@ namespace netlist } } - void clear() noexcept + void clear() { - lock_guard_type lck(m_lock); + tqlock 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,61 +188,55 @@ namespace netlist // save state support & mame disasm - 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]; } + 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]; } private: - using mutex_type = pspin_mutex<TS>; - using lock_guard_type = std::lock_guard<mutex_type>; + using tqmutex = pspin_mutex<TS>; + using tqlock = std::lock_guard<tqmutex>; - mutex_type m_lock; - PALIGNAS_CACHELINE() - T * m_end; - //std::vector<T> m_list; - plib::aligned_vector<T> m_list; + tqmutex m_lock; + T * m_end; + std::vector<T> m_list; public: // profiling - nperfcount_t<KEEPSTAT> m_prof_sortmove; - nperfcount_t<KEEPSTAT> m_prof_call; - nperfcount_t<KEEPSTAT> m_prof_remove; - nperfcount_t<KEEPSTAT> m_prof_retime; + nperfcount_t m_prof_sortmove; + nperfcount_t m_prof_call; }; - - template <class T, bool TS, bool KEEPSTAT, class QueueOp = typename T::QueueOp> - class timed_queue_heap : plib::nocopyassignmove +#else + template <class T, bool TS, class QueueOp = typename T::QueueOp> + class timed_queue : plib::nocopyassignmove { public: struct compare { - constexpr bool operator()(const T &a, const T &b) const { return QueueOp::lessequal(b,a); } + constexpr bool operator()(const T &a, const T &b) const { return QueueOp::less(b,a); } }; - explicit timed_queue_heap(const std::size_t list_size) + explicit timed_queue(const std::size_t list_size) : m_list(list_size) { clear(); } - std::size_t capacity() const noexcept { return m_list.capacity(); } - bool empty() const noexcept { return &m_list[0] == m_end; } + constexpr std::size_t capacity() const noexcept { return m_list.capacity(); } + constexpr bool empty() const noexcept { return &m_list[0] == m_end; } void push(T &&e) noexcept { /* Lock */ - lock_guard_type lck(m_lock); + tqlock lck(m_lock); *m_end++ = e; std::push_heap(&m_list[0], m_end, compare()); m_prof_call.inc(); } - T pop() noexcept + void 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]; } @@ -251,7 +245,7 @@ namespace netlist void remove(const R &elem) noexcept { /* Lock */ - lock_guard_type lck(m_lock); + tqlock lck(m_lock); for (T * i = m_end - 1; i >= &m_list[0]; i--) { if (QueueOp::equal(*i, elem)) @@ -268,7 +262,7 @@ namespace netlist void retime(const T &elem) noexcept { /* Lock */ - lock_guard_type lck(m_lock); + tqlock lck(m_lock); for (T * i = m_end - 1; i >= &m_list[0]; i--) { if (QueueOp::equal(*i, elem)) // partial equal! @@ -282,7 +276,7 @@ namespace netlist void clear() { - lock_guard_type lck(m_lock); + tqlock lck(m_lock); m_list.clear(); m_end = &m_list[0]; } @@ -293,28 +287,19 @@ 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 mutex_type = pspin_mutex<TS>; - using lock_guard_type = std::lock_guard<mutex_type>; + using tqmutex = pspin_mutex<TS>; + using tqlock = std::lock_guard<tqmutex>; - mutex_type m_lock; + tqmutex m_lock; std::vector<T> m_list; T *m_end; public: // profiling - nperfcount_t<KEEPSTAT> m_prof_sortmove; - nperfcount_t<KEEPSTAT> m_prof_call; + nperfcount_t m_prof_sortmove; + nperfcount_t m_prof_call; }; - - /* - * 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 +} #endif /* NLLISTS_H_ */ diff --git a/src/lib/netlist/nl_parser.cpp b/src/lib/netlist/nl_parser.cpp index cecfbe862bf..4685a13c354 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_base.h" -#include "nl_errstr.h" #include "nl_factory.h" +#include "nl_errstr.h" +#include "nl_base.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) { - 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("/*", "*/", "//"); + 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("/*", "*/", "//"); 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 (const pstring &tp : paramlist) + for (pstring tp : paramlist) { require_token(m_tok_comma); - if (plib::startsWith(tp, "+")) + if (tp.startsWith("+")) { pstring output_name = get_identifier(); m_setup.log().debug("Link: {1} {2}\n", tp, output_name); @@ -395,15 +395,18 @@ 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 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; + 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; nl_double ret; + pstring val; - for (std::size_t i=1; i<macs.size();i++) - if (tok.str() == macs[i]) + for (i=1; i<6;i++) + if (tok.str().equals(macs[i])) f = i; if (f>0) { @@ -413,13 +416,13 @@ nl_double parser_t::eval_param(const token_t &tok) } else { - bool err; - ret = plib::pstonum_ne<nl_double>(tok.str(), err); - if (err) - error(plib::pfmt("Parameter value <{1}> not double \n")(tok.str())); + val = tok.str(); + ret = val.as_double(&e); + if (e) + error(plib::pfmt("Parameter value <{1}> not double \n")(val)); } return ret * facs[f]; } -} // namespace netlist +} diff --git a/src/lib/netlist/nl_parser.h b/src/lib/netlist/nl_parser.h index 92459c4b87b..a813629faa0 100644 --- a/src/lib/netlist/nl_parser.h +++ b/src/lib/netlist/nl_parser.h @@ -16,12 +16,8 @@ namespace netlist class parser_t : public plib::ptokenizer { public: - template <typename T> - parser_t(T &&strm, nlparse_t &setup) - : plib::ptokenizer(std::forward<T>(strm)) - , m_setup(setup) - { - } + parser_t(plib::putf8_reader &strm, setup_t &setup) + : plib::ptokenizer(strm), m_setup(setup) {} bool parse(const pstring &nlname = ""); @@ -43,12 +39,12 @@ namespace netlist void net_truthtable_start(const pstring &nlname); /* for debugging messages */ - //netlist_state_t &netlist() { return m_setup.netlist(); } + netlist_t &netlist() { return m_setup.netlist(); } - void verror(const pstring &msg, int line_num, const pstring &line) override; + virtual 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; @@ -72,9 +68,9 @@ namespace netlist token_id_t m_tok_TT_LINE; token_id_t m_tok_TT_FAMILY; - nlparse_t &m_setup; + setup_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 b9300f5ad9c..df761bc3f88 100644 --- a/src/lib/netlist/nl_setup.cpp +++ b/src/lib/netlist/nl_setup.cpp @@ -6,243 +6,128 @@ */ #include "plib/palloc.h" -#include "analog/nld_twoterm.h" -#include "devices/nlid_proxy.h" -#include "devices/nlid_system.h" -#include "devices/nlid_truthtable.h" +#include "plib/putil.h" #include "nl_base.h" -#include "nl_factory.h" -#include "nl_parser.h" #include "nl_setup.h" -#include "plib/putil.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 "solver/nld_solver.h" +#include "devices/nlid_truthtable.h" -#include <cmath> +// ---------------------------------------------------------------------------------------- +// setup_t +// ---------------------------------------------------------------------------------------- namespace netlist { - // ---------------------------------------------------------------------------------------- - // nl_parse_t - // ---------------------------------------------------------------------------------------- - - nlparse_t::nlparse_t(setup_t &setup, log_type &log) - : m_factory(log) - , m_setup(setup) - , m_log(log) +setup_t::setup_t(netlist_t &netlist) + : m_netlist(netlist) + , m_factory(*this) + , m_proxy_cnt(0) , m_frontier_cnt(0) - { } - - 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); - } - - 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]); - } - } - - 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 nlparse_t::register_link(const pstring &sin, const pstring &sout) - { - register_link_fqn(build_fqn(sin), build_fqn(sout)); - } - - 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 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 nlparse_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::namespace_pop() - { - m_namespace_stack.pop(); - } - - 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 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; - } - } +{ + devices::initialize_factory(m_factory); +} - 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)); - } +setup_t::~setup_t() +{ + m_links.clear(); + m_alias.clear(); + m_params.clear(); + m_terminals.clear(); + m_param_values.clear(); - 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"); - } + m_sources.clear(); +} - 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 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; +} - 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 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_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 setup_t::namespace_pop() +{ + m_namespace_stack.pop(); +} - 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_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)); +} - bool nlparse_t::device_exists(const pstring &name) const - { - for (auto &d : m_device_factory) - if (d.first == name) - return true; - return false; - } +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 nlparse_t::parse_stream(plib::unique_ptr<plib::pistream> &&istrm, const pstring &name) +bool setup_t::device_exists(const pstring &name) const +{ + for (auto e : m_device_factory) { - return parser_t(std::move(plib::ppreprocessor(&m_defines).process(std::move(istrm))), *this).parse(name); + if (e.first == name) + return true; } + return false; +} - 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 - // ---------------------------------------------------------------------------------------- +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 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); +} -setup_t::setup_t(netlist_state_t &nlstate) - : nlparse_t(*this, nlstate.log()) - , m_nlstate(nlstate) - , m_netlist_params(nullptr) - , m_proxy_cnt(0) +void setup_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); } -setup_t::~setup_t() noexcept +void setup_t::register_dippins_arr(const pstring &terms) { - // FIXME: can't see a need any longer - m_links.clear(); - m_params.clear(); - m_terminals.clear(); - m_param_values.clear(); - m_sources.clear(); + 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::termtype_as_str(detail::core_terminal_t &in) const @@ -260,7 +145,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) const +pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def) { auto i = m_param_values.find(name); if (i != m_param_values.end()) @@ -269,6 +154,40 @@ 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) @@ -277,6 +196,30 @@ 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); @@ -298,14 +241,59 @@ 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_t(const pstring &name, param_t ¶m) +void setup_t::register_param(const pstring ¶m, const double 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); + register_param(param, plib::pfmt("{1:.9}").e(value)); } +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 { @@ -323,42 +311,6 @@ 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); @@ -425,7 +377,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(detail::core_terminal_t &out) { nl_assert(out.is_logic()); - auto &out_cast = static_cast<logic_output_t &>(out); + logic_output_t &out_cast = static_cast<logic_output_t &>(out); devices::nld_base_proxy *proxy = out_cast.get_proxy(); if (proxy == nullptr) @@ -433,25 +385,28 @@ 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(m_nlstate, x, &out_cast); + out_cast.logic_family()->create_d_a_proxy(netlist(), x, &out_cast); m_proxy_cnt++; + + //new_proxy->start_dev(); + /* connect all existing terminals to new net */ - for (auto & p : out.net().core_terms()) + for (auto & p : out.net().m_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().core_terms().clear(); // clear the list + out.net().m_core_terms.clear(); // clear the list out.net().add_terminal(new_proxy->in()); out_cast.set_proxy(proxy); proxy = new_proxy.get(); - m_nlstate.add_dev(new_proxy->name(), std::move(new_proxy)); + netlist().register_dev(std::move(new_proxy)); } return proxy; } @@ -460,7 +415,7 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp) { nl_assert(inp.is_logic()); - auto &incast = dynamic_cast<logic_input_t &>(inp); + logic_input_t &incast = dynamic_cast<logic_input_t &>(inp); devices::nld_base_proxy *proxy = incast.get_proxy(); if (proxy != nullptr) @@ -469,7 +424,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(m_nlstate, x, &incast); + auto new_proxy = incast.logic_family()->create_a_d_proxy(netlist(), 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++; @@ -480,17 +435,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().core_terms()) + for (auto & p : inp.net().m_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().core_terms().clear(); // clear the list + inp.net().m_core_terms.clear(); // clear the list } ret->out().net().add_terminal(inp); - m_nlstate.add_dev(new_proxy->name(), std::move(new_proxy)); + netlist().register_dev(std::move(new_proxy)); return ret; } } @@ -613,12 +568,11 @@ 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 = 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); + 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); } } @@ -626,7 +580,7 @@ static detail::core_terminal_t &resolve_proxy(detail::core_terminal_t &term) { if (term.is_logic()) { - auto &out = dynamic_cast<logic_t &>(term); + logic_t &out = dynamic_cast<logic_t &>(term); if (out.has_proxy()) return out.get_proxy()->proxy_term(); } @@ -642,7 +596,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().core_terms()) + for (auto & t : t1.net().m_core_terms) { if (t->is_type(detail::terminal_type::TERMINAL)) ret = connect(t2, *t); @@ -657,7 +611,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().core_terms()) + for (auto & t : t2.net().m_core_terms) { if (t->is_type(detail::terminal_type::TERMINAL)) ret = connect(t1, *t); @@ -669,6 +623,8 @@ 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()); @@ -756,7 +712,18 @@ void setup_t::resolve_inputs() // delete empty nets - 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()); pstring errstr(""); @@ -777,7 +744,7 @@ void setup_t::resolve_inputs() } -void setup_t::register_dynamic_log_devices() +void setup_t::start_devices() { pstring env = plib::util::environment("NL_LOGS", ""); @@ -785,43 +752,41 @@ void setup_t::register_dynamic_log_devices() { log().debug("Creating dynamic logs ..."); std::vector<pstring> loglist(plib::psplit(env, ":")); - for (const pstring &ll : loglist) + for (pstring ll : loglist) { pstring name = "log_" + ll; - auto nc = factory().factory_by_name("LOG")->Create(m_nlstate, name); + auto nc = factory().factory_by_name("LOG")->Create(netlist(), name); register_link(name + ".I", ll); log().debug(" dynamic link {1}: <{2}>\n",ll, name); - m_nlstate.add_dev(nc->name(), std::move(nc)); + netlist().register_dev(std::move(nc)); } } } -log_type &setup_t::log() +plib::plog_base<netlist_t, NL_DEBUG> &setup_t::log() { - return m_nlstate.log(); + return netlist().log(); } -const log_type &setup_t::log() const +const plib::plog_base<netlist_t, NL_DEBUG> &setup_t::log() const { - return m_nlstate.log(); + return netlist().log(); } // ---------------------------------------------------------------------------------------- -// Models +// Model // ---------------------------------------------------------------------------------------- -void models_t::register_model(pstring model_in) +static pstring model_string(detail::model_map_t &map) { - 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); + pstring ret = map["COREMODEL"] + "("; + for (auto & i : map) + ret = ret + i.first + "=" + i.second + " "; + + return ret + ")"; } -void models_t::model_parse(const pstring &model_in, model_map_t &map) +void setup_t::model_parse(const pstring &model_in, detail::model_map_t &map) { pstring model = model_in; std::size_t pos = 0; @@ -832,15 +797,15 @@ void models_t::model_parse(const pstring &model_in, model_map_t &map) pos = model.find("("); if (pos != pstring::npos) break; - key = plib::ucase(model); + key = model.ucase(); auto i = m_models.find(key); if (i == m_models.end()) - throw nl_exception(MF_1_MODEL_NOT_FOUND, model); + log().fatal(MF_1_MODEL_NOT_FOUND, model); model = i->second; } - pstring xmodel = plib::left(model, pos); + pstring xmodel = model.left(pos); - if (xmodel == "_") + if (xmodel.equals("_")) map["COREMODEL"] = key; else { @@ -848,65 +813,46 @@ void models_t::model_parse(const pstring &model_in, model_map_t &map) if (i != m_models.end()) model_parse(xmodel, map); else - throw nl_exception(MF_1_MODEL_NOT_FOUND, model_in); + log().fatal(MF_1_MODEL_NOT_FOUND, model_in); } - pstring remainder = plib::trim(model.substr(pos + 1)); - if (!plib::endsWith(remainder, ")")) - throw nl_exception(MF_1_MODEL_ERROR_1, model); + pstring remainder = model.substr(pos + 1).trim(); + if (!remainder.endsWith(")")) + log().fatal(MF_1_MODEL_ERROR_1, model); // FIMXE: Not optimal - remainder = plib::left(remainder, remainder.size() - 1); + remainder = remainder.left(remainder.length() - 1); std::vector<pstring> pairs(plib::psplit(remainder," ", true)); for (pstring &pe : pairs) { auto pose = pe.find("="); if (pose == pstring::npos) - throw nl_exception(MF_1_MODEL_ERROR_ON_PAIR_1, model); - map[plib::ucase(plib::left(pe, pose))] = pe.substr(pose + 1); + log().fatal(MF_1_MODEL_ERROR_ON_PAIR_1, model); + map[pe.left(pose).ucase()] = pe.substr(pose + 1); } } -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) +const pstring setup_t::model_value_str(detail::model_map_t &map, const pstring &entity) { - model_map_t &map = m_cache[model]; - - if (map.size() == 0) - model_parse(model , map); - pstring ret; - if (entity != plib::ucase(entity)) - throw nl_exception(MF_2_MODEL_PARAMETERS_NOT_UPPERCASE_1_2, entity, + if (entity != entity.ucase()) + log().fatal(MF_2_MODEL_PARAMETERS_NOT_UPPERCASE_1_2, entity, model_string(map)); if (map.find(entity) == map.end()) - throw nl_exception(MF_2_ENTITY_1_NOT_FOUND_IN_MODEL_2, entity, model_string(map)); + log().fatal(MF_2_ENTITY_1_NOT_FOUND_IN_MODEL_2, entity, model_string(map)); else ret = map[entity]; return ret; } -nl_double models_t::model_value(pstring model, pstring entity) +nl_double setup_t::model_value(detail::model_map_t &map, const pstring &entity) { - model_map_t &map = m_cache[model]; - - if (map.size() == 0) - model_parse(model , map); + pstring tmp = model_value_str(map, entity); - 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)); + nl_double factor = NL_FCONST(1.0); + auto p = std::next(tmp.begin(), static_cast<pstring::difference_type>(tmp.length() - 1)); switch (*p) { case 'M': factor = 1e6; break; @@ -919,69 +865,85 @@ nl_double models_t::model_value(pstring model, pstring entity) case 'a': factor = 1e-18; break; default: if (*p < '0' || *p > '9') - throw nl_exception(MF_1_UNKNOWN_NUMBER_FACTOR_IN_1, entity); + log().fatal(MF_1_UNKNOWN_NUMBER_FACTOR_IN_1, entity); } - 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; + if (factor != NL_FCONST(1.0)) + tmp = tmp.left(tmp.length() - 1); + return tmp.as_double() * factor; } class logic_family_std_proxy_t : public logic_family_desc_t { public: - logic_family_std_proxy_t() = default; - pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, + logic_family_std_proxy_t() { } + 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; - 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; + 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> logic_family_std_proxy_t::create_d_a_proxy(netlist_state_t &anetlist, +plib::owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_std_proxy_t::create_d_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *proxied) const { - return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + return plib::owned_ptr<devices::nld_base_d_to_a_proxy>::Create<devices::nld_d_to_a_proxy>(anetlist, name, proxied); } -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 +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 { - return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied); + return plib::owned_ptr<devices::nld_base_a_to_d_proxy>::Create<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 (m_models.model_value_str(model, "TYPE") == "TTL") + if (model_value_str(map, "TYPE") == "TTL") return family_TTL(); - if (m_models.model_value_str(model, "TYPE") == "CD4XXX") + if (model_value_str(map, "TYPE") == "CD4XXX") return family_CD4XXX(); - for (auto & e : m_nlstate.m_family_cache) + for (auto & e : netlist().m_family_cache) if (e.first == model) return e.second.get(); - auto ret = plib::make_unique<logic_family_std_proxy_t>(); + auto ret = plib::make_unique_base<logic_family_desc_t, logic_family_std_proxy_t>(); - 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"); + 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"); auto retp = ret.get(); - m_nlstate.m_family_cache.emplace_back(model, std::move(ret)); + netlist().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 // ---------------------------------------------------------------------------------------- -plib::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring &name) +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) { for (auto &source : m_sources) { @@ -993,189 +955,77 @@ plib::unique_ptr<plib::pistream> setup_t::get_data_stream(const pstring &name) } } log().warning(MW_1_DATA_1_NOT_FOUND, name); - return plib::unique_ptr<plib::pistream>(nullptr); + return std::unique_ptr<plib::pistream>(nullptr); } -// ---------------------------------------------------------------------------------------- -// Device handling -// ---------------------------------------------------------------------------------------- - -void setup_t::delete_empty_nets() +bool setup_t::parse_stream(plib::putf8_reader &istrm, const pstring &name) { - 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()); -} + plib::pomemstream ostrm; + plib::putf8_writer owrt(ostrm); -// ---------------------------------------------------------------------------------------- -// Run preparation -// ---------------------------------------------------------------------------------------- + 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::prepare_to_run() +void setup_t::register_define(pstring defstr) { - 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); - } + auto p = defstr.find("="); + if (p != pstring::npos) + register_define(defstr.left(p), defstr.substr(p+1)); else - 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); - } - + register_define(defstr, "1"); } // ---------------------------------------------------------------------------------------- // base sources // ---------------------------------------------------------------------------------------- -bool source_t::parse(nlparse_t &setup, const pstring &name) +bool source_t::parse(const pstring &name) { if (m_type != SOURCE) return false; else { - return setup.parse_stream(stream(name), name); + auto rstream = stream(name); + plib::putf8_reader reader(*rstream); + return m_setup.parse_stream(reader, name); } } -plib::unique_ptr<plib::pistream> source_string_t::stream(const pstring &name) +std::unique_ptr<plib::pistream> source_string_t::stream(const pstring &name) { - plib::unused_var(name); - return plib::make_unique<plib::pimemstream>(m_str.c_str(), std::strlen(m_str.c_str())); + return plib::make_unique_base<plib::pistream, plib::pimemstream>(m_str.c_str(), m_str.mem_t_size()); } -plib::unique_ptr<plib::pistream> source_mem_t::stream(const pstring &name) +std::unique_ptr<plib::pistream> source_mem_t::stream(const pstring &name) { - plib::unused_var(name); - return plib::make_unique<plib::pimemstream>(m_str.c_str(), std::strlen(m_str.c_str())); + return plib::make_unique_base<plib::pistream, plib::pimemstream>(m_str.c_str(), m_str.mem_t_size()); } -plib::unique_ptr<plib::pistream> source_file_t::stream(const pstring &name) +std::unique_ptr<plib::pistream> source_file_t::stream(const pstring &name) { - plib::unused_var(name); - return plib::make_unique<plib::pifilestream>(m_filename); + return plib::make_unique_base<plib::pistream, plib::pifilestream>(m_filename); } -bool source_proc_t::parse(nlparse_t &setup, const pstring &name) +bool source_proc_t::parse(const pstring &name) { if (name == m_setup_func_name) { - m_setup_func(setup); + m_setup_func(setup()); return true; } else return false; } -plib::unique_ptr<plib::pistream> source_proc_t::stream(const pstring &name) +std::unique_ptr<plib::pistream> source_proc_t::stream(const pstring &name) { - plib::unused_var(name); - plib::unique_ptr<plib::pistream> p(nullptr); + std::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 ed0248a48e6..d0359928711 100644 --- a/src/lib/netlist/nl_setup.h +++ b/src/lib/netlist/nl_setup.h @@ -8,20 +8,18 @@ #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_config.h" #include "nl_factory.h" -#include "nltypes.h" +#include "nl_config.h" +#include "netlist_types.h" -#include <memory> #include <stack> -#include <unordered_map> #include <vector> - +#include <memory> //============================================================ // MACROS / inline netlist definitions @@ -29,46 +27,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::nlparse_t &setup); + void NETLIST_NAME(name)(netlist::setup_t &setup); #define NETLIST_START(name) \ -void NETLIST_NAME(name)(netlist::nlparse_t &setup) \ +void NETLIST_NAME(name)(netlist::setup_t &setup) \ { #define NETLIST_END() } #define LOCAL_SOURCE(name) \ - setup.register_source(plib::make_unique<netlist::source_proc_t>(# name, &NETLIST_NAME(name))); + setup.register_source(plib::make_unique_base<netlist::source_t, netlist::source_proc_t>(setup, # name, &NETLIST_NAME(name))); #define LOCAL_LIB_ENTRY(name) \ LOCAL_SOURCE(name) \ @@ -82,7 +80,7 @@ void NETLIST_NAME(name)(netlist::nlparse_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); // ----------------------------------------------------------------------------- @@ -100,10 +98,10 @@ void NETLIST_NAME(name)(netlist::nlparse_t &setup) \ desc.family = ""; #define TT_HEAD(x) \ - desc.desc.emplace_back(x); + desc.desc.push_back(x); #define TT_LINE(x) \ - desc.desc.emplace_back(x); + desc.desc.push_back(x); #define TT_FAMILY(x) \ desc.family = x; @@ -112,23 +110,22 @@ void NETLIST_NAME(name)(netlist::nlparse_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; @@ -139,7 +136,6 @@ namespace netlist struct tt_desc { - tt_desc() : ni(0), no(0) { } pstring name; pstring classname; unsigned long ni; @@ -172,222 +168,138 @@ namespace netlist class source_t { public: - - friend class setup_t; - enum type_t { SOURCE, DATA }; - using list_t = std::vector<plib::unique_ptr<source_t>>; + using list_t = std::vector<std::unique_ptr<source_t>>; - source_t(const type_t type = SOURCE) - : m_type(type) + source_t(setup_t &setup, const type_t type = SOURCE) + : m_setup(setup), m_type(type) {} - COPYASSIGNMOVE(source_t, delete) - - virtual ~source_t() noexcept = default; + virtual ~source_t() { } - virtual bool parse(nlparse_t &setup, const pstring &name); + virtual bool parse(const pstring &name); + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) = 0; + 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; }; - // ---------------------------------------------------------------------------------------- - // Collection of models + // setup_t // ---------------------------------------------------------------------------------------- - class models_t + + class setup_t : plib::nocopyassignmove { public: - void register_model(pstring model_in); - /* model / family related */ - - pstring model_value_str(pstring model, pstring entity); - double model_value(pstring model, pstring entity); + using link_t = std::pair<pstring, pstring>; - pstring model_type(pstring model) { return model_value_str(model, "COREMODEL"); } + explicit setup_t(netlist_t &netlist); + ~setup_t(); - private: - using model_map_t = std::unordered_map<pstring, pstring>; + netlist_t &netlist() { return m_netlist; } + const netlist_t &netlist() const { return m_netlist; } - void model_parse(const pstring &model, model_map_t &map); - pstring model_string(model_map_t &map); + pstring build_fqn(const pstring &obj_name) const; - std::unordered_map<pstring, pstring> m_models; - std::unordered_map<pstring, model_map_t> m_cache; - }; + 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); - // ---------------------------------------------------------------------------------------- - // nlparse_t - // ---------------------------------------------------------------------------------------- + void register_term(detail::core_terminal_t &obj); - class nlparse_t - { - public: - using link_t = std::pair<pstring, pstring>; + void register_dev(const pstring &classname, const pstring &name); - nlparse_t(setup_t &netlist, log_type &log); + void register_lib_entry(const pstring &name, const pstring &sourcefile); - void register_model(const pstring &model_in) { m_models.register_model(model_in); } + void register_model(const pstring &model_in); void register_alias(const pstring &alias, const pstring &out); void register_dippins_arr(const pstring &terms); - void register_dev(const pstring &classname, const pstring &name); - void register_link(const pstring &sin, const pstring &sout); + + 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_link(const pstring &sin, const pstring &sout); + 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); - /* register a source */ - void register_source(plib::unique_ptr<source_t> &&src) - { - m_sources.push_back(std::move(src)); - } + void remove_connections(const pstring &attach); - void tt_factory_create(tt_desc &desc, const pstring &sourcefile); + 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; + + void start_devices(); + void resolve_inputs(); /* handle namespace */ void namespace_push(const pstring &aname); void namespace_pop(); - /* include other files */ + /* parse a source */ void include(const pstring &netlist_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); + std::unique_ptr<plib::pistream> get_data_stream(const pstring &name); - /* used from netlist.cpp (mame) */ - bool device_exists(const pstring &name) const; + bool parse_stream(plib::putf8_reader &istrm, const pstring &name); - /* FIXME: used by source_t - need a different approach at some time */ - bool parse_stream(plib::unique_ptr<plib::pistream> &&istrm, const pstring &name); + /* register a source */ - void add_define(const pstring &def, const pstring &val) + void register_source(std::unique_ptr<source_t> &&src) { - m_defines.insert({ def, plib::ppreprocessor::define_t(def, val)}); + m_sources.push_back(std::move(src)); } - void add_define(const pstring &defstr); + void register_define(pstring def, pstring val) { m_defines.push_back(plib::ppreprocessor::define_t(def, val)); } + void register_define(pstring defstr); factory::list_t &factory() { return m_factory; } const factory::list_t &factory() const { return m_factory; } - 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); + /* model / family related */ - bool connect(detail::core_terminal_t &t1, detail::core_terminal_t &t2); + const pstring model_value_str(detail::model_map_t &map, const pstring &entity); + double model_value(detail::model_map_t &map, const pstring &entity); - param_t *find_param(const pstring ¶m_in, bool required = true) const; + void model_parse(const pstring &model, detail::model_map_t &map); - /* get family */ const logic_family_desc_t *family_from_model(const pstring &model); - 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; } + void tt_factory_create(tt_desc &desc, const pstring &sourcefile); /* helper - also used by nltool */ const pstring resolve_alias(const pstring &name) const; - /* needed by nltool */ - std::vector<pstring> get_terminals_for_device_name(const pstring &devname); + 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; - log_type &log(); - const log_type &log() const; + 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; /* 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); @@ -406,30 +318,35 @@ 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); - std::unordered_map<pstring, detail::core_terminal_t *> m_terminals; - - netlist_state_t &m_nlstate; - devices::nld_netlistparams *m_netlist_params; + 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::stack<pstring> m_namespace_stack; + source_t::list_t m_sources; + std::vector<plib::ppreprocessor::define_t> m_defines; unsigned m_proxy_cnt; - }; + unsigned m_frontier_cnt; +}; // ---------------------------------------------------------------------------------------- // base sources // ---------------------------------------------------------------------------------------- + class source_string_t : public source_t { public: - source_string_t(const pstring &source) - : source_t(), m_str(source) + source_string_t(setup_t &setup, const pstring &source) + : source_t(setup), m_str(source) { } - protected: - plib::unique_ptr<plib::pistream> stream(const pstring &name) override; + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override; private: pstring m_str; @@ -439,13 +356,12 @@ namespace netlist { public: - source_file_t(const pstring &filename) - : source_t(), m_filename(filename) + source_file_t(setup_t &setup, const pstring &filename) + : source_t(setup), m_filename(filename) { } - protected: - plib::unique_ptr<plib::pistream> stream(const pstring &name) override; + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override; private: pstring m_filename; @@ -454,13 +370,12 @@ namespace netlist class source_mem_t : public source_t { public: - source_mem_t(const char *mem) - : source_t(), m_str(mem) + source_mem_t(setup_t &setup, const char *mem) + : source_t(setup), m_str(mem, pstring::UTF8) { } - protected: - plib::unique_ptr<plib::pistream> stream(const pstring &name) override; + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override; private: pstring m_str; @@ -469,28 +384,22 @@ namespace netlist class source_proc_t : public source_t { public: - source_proc_t(const pstring &name, void (*setup_func)(nlparse_t &)) - : source_t(), + source_proc_t(setup_t &setup, pstring name, void (*setup_func)(setup_t &)) + : source_t(setup), m_setup_func(setup_func), m_setup_func_name(name) { } - bool parse(nlparse_t &setup, const pstring &name) override; - - protected: - plib::unique_ptr<plib::pistream> stream(const pstring &name) override; + virtual bool parse(const pstring &name) override; + virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override; private: - void (*m_setup_func)(nlparse_t &); + void (*m_setup_func)(setup_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 new file mode 100644 index 00000000000..7c81f890e07 --- /dev/null +++ b/src/lib/netlist/nl_time.h @@ -0,0 +1,145 @@ +// 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 deleted file mode 100644 index 7d7582774b1..00000000000 --- a/src/lib/netlist/nltypes.h +++ /dev/null @@ -1,147 +0,0 @@ -// 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 deleted file mode 100644 index 2c357e97624..00000000000 --- a/src/lib/netlist/plib/gmres.h +++ /dev/null @@ -1,450 +0,0 @@ -// 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 deleted file mode 100644 index 4cc027f0d8f..00000000000 --- a/src/lib/netlist/plib/mat_cr.h +++ /dev/null @@ -1,530 +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 "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 new file mode 100644 index 00000000000..e4d31985b23 --- /dev/null +++ b/src/lib/netlist/plib/palloc.cpp @@ -0,0 +1,105 @@ +// 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 15fede3a99b..a35bc50ff17 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -8,427 +8,172 @@ #ifndef PALLOC_H_ #define PALLOC_H_ -#include "pconfig.h" #include "pstring.h" -#include "ptypes.h" -#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 +#include <memory> namespace plib { - //============================================================ - // 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 +//============================================================ +// 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) { - 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); + 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; } - //============================================================ - // Memory allocation - //============================================================ - - struct aligned_arena + owned_ptr(owned_ptr &&r) noexcept { - 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 + m_is_owned = r.m_is_owned; + m_ptr = r.m_ptr; + r.m_is_owned = false; + r.m_ptr = nullptr; } - template <typename T, std::size_t ALIGN> - constexpr const T *assume_aligned_ptr(const T *p) noexcept + template<typename DC> + owned_ptr(owned_ptr<DC> &&r) 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"); -#if (USE_ALIGNED_HINTS) - return reinterpret_cast<const T *>(__builtin_assume_aligned(p, ALIGN)); -#else - return p; -#endif + m_ptr = static_cast<SC *>(r.get()); + m_is_owned = r.is_owned(); + r.release(); } - // FIXME: remove - template<typename T, typename... Args> - inline T *pnew(Args&&... args) + ~owned_ptr() { - auto *p = aligned_arena::allocate(alignof(T), sizeof(T)); - return new(p) T(std::forward<Args>(args)...); + if (m_is_owned && (m_ptr != nullptr)) + delete m_ptr; + m_is_owned = false; + m_ptr = nullptr; } - - template<typename T> - inline void pdelete(T *ptr) + template<typename DC, typename... Args> + static owned_ptr Create(Args&&... args) { - ptr->~T(); - aligned_arena::deallocate(ptr); + owned_ptr a; + DC *x = new DC(std::forward<Args>(args)...); + a.m_ptr = static_cast<SC *>(x); + return std::move(a); } - - 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) + template<typename... Args> + static owned_ptr Create(Args&&... args) { - return plib::unique_ptr<T>(pnew<T>(std::forward<Args>(args)...)); + owned_ptr a; + a.m_ptr = new SC(std::forward<Args>(args)...); + return std::move(a); } - -#if 0 - template<typename T, typename... Args> - static owned_ptr<T> make_owned(Args&&... args) + SC * release() { - return owned_ptr<T>(pnew<T>(std::forward<Args>(args)...), true); + SC *tmp = m_ptr; + m_is_owned = false; + m_ptr = nullptr; + return tmp; } -#endif - - - template <class T, std::size_t ALIGN = alignof(T)> - using aligned_allocator = aligned_arena::allocator_type<T, ALIGN>; - - //============================================================ - // traits to determine alignment size and stride size - // from types supporting alignment - //============================================================ - PDEFINE_HAS_MEMBER(has_align, align_size); + bool is_owned() const { return m_is_owned; } - template <typename T, typename X = void> - struct align_traits - { - 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; - }; + 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; +}; - template <typename T> - struct align_traits<T, typename std::enable_if<has_align<T>::value, void>::type> +class mempool +{ +private: + struct 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; + 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; }; - //============================================================ - // Aligned vector - //============================================================ + size_t new_block(); + size_t mininfosize(); - // 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>> + struct info { - public: - using base = std::vector<T, aligned_allocator<T, ALIGN>>; + info() : m_block(0) { } + size_t m_block; + }; - 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; + size_t m_min_alloc; + size_t m_min_align; - using base::base; + std::vector<block> m_blocks; - 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]; - } +public: + mempool(size_t min_alloc, size_t min_align); + ~mempool(); - pointer data() noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); } - const_pointer data() const noexcept { return assume_aligned_ptr<T, ALIGN>(base::data()); } + void *alloc(size_t size); + void free(void *ptr); - }; +}; -} // namespace plib +} #endif /* PALLOC_H_ */ diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h deleted file mode 100644 index 1be37b908cd..00000000000 --- a/src/lib/netlist/plib/parray.h +++ /dev/null @@ -1,126 +0,0 @@ -// 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 953d948e062..971d19b3645 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 8ce0eca23b3..a229128e7b8 100644 --- a/src/lib/netlist/plib/pchrono.h +++ b/src/lib/netlist/plib/pchrono.h @@ -9,17 +9,16 @@ #define PCHRONO_H_ #include "pconfig.h" -#include "ptypes.h" -#include <chrono> #include <cstdint> +#include <chrono> namespace plib { namespace chrono { template <typename T> struct sys_ticks { - using type = typename T::rep; + typedef typename T::rep type; 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; } @@ -146,7 +145,7 @@ namespace chrono { struct counter { counter() : m_count(0) { } - using type = uint_least64_t; + typedef uint_least64_t type; type operator()() const { return m_count; } void inc() { ++m_count; } void reset() { m_count = 0; } @@ -158,7 +157,7 @@ namespace chrono { template<> struct counter<false> { - using type = uint_least64_t; + typedef uint_least64_t type; constexpr type operator()() const { return 0; } void inc() const { } void reset() const { } @@ -169,28 +168,15 @@ namespace chrono { template< typename T, bool enabled_ = true> struct timer { - 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; + typedef typename T::type type; + typedef uint_least64_t ctype; 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; } @@ -199,7 +185,7 @@ namespace chrono { double as_seconds() const { return static_cast<double>(total()) / static_cast<double>(T::per_second()); } - guard_t guard() { return guard_t(*this); } + constexpr static bool enabled = enabled_; private: type m_time; ctype m_count; @@ -208,31 +194,19 @@ namespace chrono { template<typename T> struct timer<T, false> { - 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() { } - }; - + typedef typename T::type type; + typedef uint_least64_t ctype; 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 d66b342f815..0200c305ecd 100644 --- a/src/lib/netlist/plib/pconfig.h +++ b/src/lib/netlist/plib/pconfig.h @@ -21,46 +21,18 @@ * if PHAS_RDTSCP == 1 */ #ifndef PUSE_ACCURATE_STATS -#define PUSE_ACCURATE_STATS (0) +#define PUSE_ACCURATE_STATS (1) #endif /* * Set this to one if you want to use 128 bit int for ptime. - * This is about 5% slower on a kaby lake processor. + * This is for tests only. */ #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 * @@ -75,13 +47,6 @@ * *============================================================*/ -#ifndef NVCCBUILD -#define NVCCBUILD (0) -#endif - -#if NVCCBUILD -#define C14CONSTEXPR -#else #if __cplusplus == 201103L #define C14CONSTEXPR #elif __cplusplus == 201402L @@ -93,7 +58,6 @@ #else #error "C++ version not supported" #endif -#endif #ifndef PHAS_INT128 #define PHAS_INT128 (0) @@ -104,6 +68,17 @@ 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 0d32bead51d..13827eaf24c 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 = new CHAR[char_count]; + result = palloc_array<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 = new WCHAR[char_count]; + result = palloc_array<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()); - delete [] buffer; + pfree_array(buffer); #elif defined(EMSCRIPTEN) //no-op #else @@ -88,11 +88,9 @@ 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()); @@ -106,7 +104,7 @@ dynlib::dynlib(const pstring &path, const pstring &libname) { //printf("win: library <%s> not found!\n", libname.c_str()); } - delete [] buffer; + pfree_array(buffer); #elif defined(EMSCRIPTEN) //no-op #else @@ -141,7 +139,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()); @@ -150,4 +148,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 1454c053298..7c9412593c9 100644 --- a/src/lib/netlist/plib/pdynlib.h +++ b/src/lib/netlist/plib/pdynlib.h @@ -8,31 +8,28 @@ #define PDYNLIB_H_ #include "pstring.h" -#include "ptypes.h" namespace plib { // ---------------------------------------------------------------------------------------- // pdynlib: dynamic loading of libraries ... // ---------------------------------------------------------------------------------------- -class dynlib : public nocopyassignmove +class dynlib { 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; @@ -67,6 +64,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 8d6907d66f2..a4ed8f367e0 100644 --- a/src/lib/netlist/plib/pexception.cpp +++ b/src/lib/netlist/plib/pexception.cpp @@ -9,7 +9,6 @@ #include "pfmtlog.h" #include <cfenv> -#include <iostream> #if (defined(__x86_64__) || defined(__i386__)) && defined(__linux__) #define HAS_FEENABLE_EXCEPT (1) @@ -18,113 +17,127 @@ #endif namespace plib { - - //============================================================ - // terminate - //============================================================ - - void terminate(const pstring &msg) noexcept - { - std::cerr << msg.c_str() << "\n"; - std::terminate(); - } - - - //============================================================ - // 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) - { - } - - - file_write_e::file_write_e(const pstring &filename) - : file_e("File write failed: {}", filename) +//============================================================ +// 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) { + 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 +} - 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() +fpsignalenabler::~fpsignalenabler() +{ +#if HAS_FEENABLE_EXCEPT + if (m_enable) { - #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 + 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::supported() +{ + return true; +} - bool fpsignalenabler::global_enable(bool enable) - { - bool old = m_enable; - m_enable = enable; - return old; - } +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 28a3ac1adf1..4827081b754 100644 --- a/src/lib/netlist/plib/pexception.h +++ b/src/lib/netlist/plib/pexception.h @@ -9,116 +9,118 @@ #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 af87251fbdf..b8b5fcb3b91 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -8,96 +8,83 @@ #include "pfmtlog.h" #include "palloc.h" -#include <algorithm> -#include <array> -#include <cstdarg> -#include <cstdio> -#include <cstdlib> #include <cstring> -#include <iostream> +#include <cstdlib> +#include <cstdarg> +#include <algorithm> #include <locale> +#include <iostream> namespace plib { pfmt &pfmt::format_element(const char *l, const unsigned cfmt_spec, ...) { va_list ap; - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) - std::array<char, 2048> buf; + va_start(ap, cfmt_spec); + pstring fmt("%"); + char buf[2048]; // FIXME std::size_t sl; - bool found_abs = false; m_arg++; - 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(); + pstring search("{"); + search += plib::to_string(m_arg); + sl = search.length(); - auto p = m_str.find(search + ":"); - sl++; // ":" - if (p == pstring::npos) // no further specifiers + 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 { - p = m_str.find(search + "}"); - if (p == pstring::npos) // not found try default - { - 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) - { - auto p1 = m_str.find("}", p); - if (p1 != pstring::npos) - { - sl = p1 - p + 1; - fmt += m_str.substr(p+1, p1 - p - 1); - } - } - } + sl = 2; + p = m_str.find("{}"); } - else + if (p == pstring::npos) { - // found absolute positional place holder - auto p1 = m_str.find("}", p); - if (p1 != pstring::npos) + sl=1; + p = m_str.find("{"); + if (p != 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; + auto p1 = m_str.find("}", p); + if (p1 != pstring::npos) + { + sl = p1 - p + 1; + fmt += m_str.substr(p+1, p1 - p - 1); + } } } - pstring::value_type pend = fmt.at(fmt.size() - 1); - if (pstring("duxo").find(cfmt_spec) != pstring::npos) + } + else + { + auto p1 = m_str.find("}", p); + if (p1 != pstring::npos) { - 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; + sl = p1 - p + 1; + fmt += ((m_arg>=10) ? m_str.substr(p+4, p1 - p - 4) : m_str.substr(p+3, p1 - p - 3)); } + } + 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; - 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); + } + 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); return *this; } -} // namespace plib +} diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index cb9b59c01ce..9b7a85d8d8d 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -9,7 +9,6 @@ #include "pstring.h" #include "ptypes.h" -#include "putil.h" #include <limits> @@ -35,6 +34,7 @@ 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,6 +136,7 @@ struct ptype_traits<double> : ptype_traits_base<double> static char32_t fmt_spec() { return 'f'; } }; + template<> struct ptype_traits<char *> : ptype_traits_base<char *> { @@ -143,13 +144,6 @@ 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: @@ -157,57 +151,44 @@ public: : m_str(fmt), m_arg(0) { } - COPYASSIGNMOVE(pfmt, default) - ~pfmt() noexcept = default; + pfmt(const pfmt &rhs) : m_str(rhs.m_str), m_arg(rhs.m_arg) { } + + ~pfmt() + { + } 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); } @@ -222,13 +203,11 @@ private: }; template <class T, bool build_enabled = true> -class pfmt_writer_t +class pfmt_writer_t : plib::nocopyassignmove { 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 @@ -258,7 +237,7 @@ public: bool is_enabled() const { return m_enabled; } protected: - ~pfmt_writer_t() noexcept = default; + ~pfmt_writer_t() { } private: pfmt &xlog(pfmt &fmt) const { return fmt; } @@ -279,10 +258,7 @@ 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) { } - - COPYASSIGNMOVE(plog_channel, delete) - - ~plog_channel() noexcept = default; + ~plog_channel() { } protected: void vdowrite(const pstring &ls) const @@ -307,9 +283,7 @@ public: error(proxy), fatal(proxy) {} - - COPYASSIGNMOVE(plog_base, default) - virtual ~plog_base() noexcept = default; + virtual ~plog_base() {} plog_channel<T, plog_level::DEBUG, debug_enabled> debug; plog_channel<T, plog_level::INFO> info; @@ -319,7 +293,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 6a2179e0e6f..79f09cb4a46 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 (plib::startsWith(expr, "rpn:")) + if (expr.startsWith("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 (std::size_t i = 0; i < inputs.size(); i++) + for (unsigned 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; - bool err; - rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); + rc.m_param = cmd.as_double(&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(const pstring &v) +static int get_prio(pstring v) { if (v == "(" || v == ")") return 1; - else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") + else if (v.left(1) >= "a" && v.left(1) <= "z") return 0; else if (v == "*" || v == "/") return 20; @@ -113,11 +113,12 @@ 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(plib::replace_all(expr, pstring(" "), pstring("")), sep)); + std::vector<pstring> sexpr(plib::psplit(expr.replace_all(" ",""), sep)); std::stack<pstring> opstk; std::vector<pstring> postfix; - for (std::size_t i = 0; i < sexpr.size(); i++) + //printf("dbg: %s\n", expr.c_str()); + for (unsigned i = 0; i < sexpr.size(); i++) { pstring &s = sexpr[i]; if (s=="(") @@ -181,15 +182,14 @@ 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) { - std::array<double, 20> stack = { 0 }; + double stack[20]; 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 fbb6c508333..7d5984f9d15 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 "pstate.h" #include "pstring.h" +#include "pstate.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 c2fee9c2f8e..5fefa658b83 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -12,8 +12,6 @@ #include "pstring.h" -#include <array> -#include <type_traits> #include <vector> namespace plib { @@ -31,13 +29,14 @@ class uninitialised_array_t { public: - using iterator = C *; - using const_iterator = const C *; + typedef C* iterator; + typedef const C* const_iterator; - uninitialised_array_t() noexcept = default; + uninitialised_array_t() + { + } - COPYASSIGNMOVE(uninitialised_array_t, delete) - ~uninitialised_array_t() noexcept + ~uninitialised_array_t() { for (std::size_t i=0; i<N; i++) (*this)[i].~C(); @@ -52,7 +51,7 @@ public: const C& operator[](const std::size_t &index) const noexcept { - return *reinterpret_cast<const C *>(&m_buf[index]); + return *reinterpret_cast<C *>(&m_buf[index]); } template<typename... Args> @@ -76,8 +75,7 @@ protected: private: /* ensure proper alignment */ - PALIGNAS_VECTOROPT() - std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf; + typename std::aligned_storage<sizeof(C), alignof(C)>::type m_buf[N]; }; // ---------------------------------------------------------------------------------------- @@ -85,7 +83,6 @@ private: // the list allows insertions / deletions if used properly // ---------------------------------------------------------------------------------------- -#if 0 template <class LC> class linkedlist_t { @@ -155,10 +152,9 @@ public: void remove(const LC *elem) noexcept { auto p = &m_head; - while(*p != elem) + for ( ; *p != elem; p = &((*p)->m_next)) { //nl_assert(*p != nullptr); - p = &((*p)->m_next); } (*p) = elem->m_next; } @@ -170,105 +166,7 @@ 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 b381d96dca7..93c4076bac2 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); + auto ret = pstring(buf, pstring::UTF8); delete [] buf; return ret; } @@ -37,13 +37,18 @@ namespace plib { : options() , pout_strm() , perr_strm() - , pout(&pout_strm) - , perr(&perr_strm) + , pout(pout_strm) + , perr(perr_strm) { } - int app::main_utfX(int argc, char **argv) + app::~app() + { + + } + + 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 4f4be779251..e2f84b90de6 100644 --- a/src/lib/netlist/plib/pmain.h +++ b/src/lib/netlist/plib/pmain.h @@ -10,21 +10,20 @@ #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 <cwchar> #include <memory> +#include <cwchar> #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 @@ -37,10 +36,7 @@ namespace plib { { public: app(); - - COPYASSIGNMOVE(app, delete) - - virtual ~app() = default; + virtual ~app(); virtual pstring usage() = 0; virtual int execute() = 0; @@ -52,21 +48,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 = plib::make_unique<C>(); + auto a = std::unique_ptr<C>(new 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 deleted file mode 100644 index eab533688d7..00000000000 --- a/src/lib/netlist/plib/pmatrix2d.h +++ /dev/null @@ -1,85 +0,0 @@ -// 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 deleted file mode 100644 index f55807c86dc..00000000000 --- a/src/lib/netlist/plib/pmempool.h +++ /dev/null @@ -1,187 +0,0 @@ -// 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 f8a516df485..6559207f09d 100644 --- a/src/lib/netlist/plib/pomp.h +++ b/src/lib/netlist/plib/pomp.h @@ -11,8 +11,6 @@ #include "pconfig.h" -#include <cstddef> - #if HAS_OPENMP #include "omp.h" #endif @@ -20,39 +18,29 @@ namespace plib { namespace omp { -template <typename I, class T> -void for_static(const I start, const I end, const T &what) +template <class T> +void for_static(const int start, const int 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 (I i = start; i < end; i++) + for (int i = start; i < end; i++) what(i); } } -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) +inline void set_num_threads(const int threads) { #if HAS_OPENMP && USE_OPENMP omp_set_num_threads(threads); -#else - plib::unused_var(threads); #endif } -inline std::size_t get_max_threads() +inline int get_max_threads() { #if HAS_OPENMP && USE_OPENMP return omp_get_max_threads(); @@ -66,7 +54,7 @@ inline std::size_t 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 4a3d32c4723..910660acb3d 100644 --- a/src/lib/netlist/plib/poptions.cpp +++ b/src/lib/netlist/plib/poptions.cpp @@ -6,39 +6,77 @@ */ #include "poptions.h" -#include "pexception.h" -#include "ptypes.h" namespace plib { /*************************************************************************** Options ***************************************************************************/ - option_base::option_base(options &parent, const pstring &help) + option_base::option_base(options &parent, pstring help) : m_help(help) { parent.register_option(this); } - option::option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument) + 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_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; @@ -47,88 +85,53 @@ namespace plib { } options::options() - : m_other_args(nullptr) { } - options::options(option **o) - : m_other_args(nullptr) + options::options(option *o[]) { int i=0; while (o[i] != nullptr) { - register_option(o[i]); + m_opts.push_back(o[i]); i++; } } - void options::register_option(option_base *opt) + options::~options() { - m_opts.push_back(opt); + m_opts.clear(); } - void options::check_consistency() + void options::register_option(option_base *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!" ); - } - } - } + m_opts.push_back(opt); } - int options::parse(int argc, char **argv) + int options::parse(int argc, char *argv[]) { - check_consistency(); - m_app = pstring(argv[0]); - bool seen_other_args = false; + m_app = pstring(argv[0], pstring::UTF8); for (int i=1; i<argc; ) { - pstring arg(argv[i]); + pstring arg(argv[i], pstring::UTF8); option *opt = nullptr; pstring opt_arg; bool has_equal_arg = false; - if (!seen_other_args && plib::startsWith(arg, "--")) + if (arg.startsWith("--")) { auto v = psplit(arg.substr(2),"="); - if (v.size() && v[0] != pstring("")) - { - 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 = getopt_long(v[0]); + has_equal_arg = (v.size() > 1); + if (has_equal_arg) { - opt = m_other_args; - seen_other_args = true; + for (unsigned j = 1; j < v.size() - 1; j++) + opt_arg = opt_arg + v[j] + "="; + opt_arg += v[v.size()-1]; } } - else if (!seen_other_args && plib::startsWith(arg, "-")) + else if (arg.startsWith("-")) { std::size_t p = 1; opt = getopt_short(arg.substr(p, 1)); @@ -141,11 +144,7 @@ namespace plib { } else { - seen_other_args = true; - if (m_other_args == nullptr) - return i; - opt = m_other_args; - i--; // we haven't had an option specifier; + return i; } if (opt == nullptr) return i; @@ -159,7 +158,7 @@ namespace plib { else { i++; // FIXME: are there more arguments? - if (opt->do_parse(pstring(argv[i])) != 0) + if (opt->do_parse(pstring(argv[i], pstring::UTF8)) != 0) return i - 1; } } @@ -174,7 +173,7 @@ namespace plib { return argc; } - pstring options::split_paragraphs(const pstring &text, unsigned width, unsigned indent, + pstring options::split_paragraphs(pstring text, unsigned width, unsigned indent, unsigned firstline_indent) { auto paragraphs = psplit(text,"\n"); @@ -182,13 +181,13 @@ namespace plib { for (auto &p : paragraphs) { - pstring line = plib::rpad(pstring(""), pstring(" "), firstline_indent); + pstring line = pstring("").rpad(" ", firstline_indent); for (auto &s : psplit(p, " ")) { if (line.length() + s.length() > width) { ret += line + "\n"; - line = plib::rpad(pstring(""), pstring(" "), indent); + line = pstring("").rpad(" ", indent); } line += s + " "; } @@ -197,8 +196,8 @@ namespace plib { return ret; } - pstring options::help(const pstring &description, const pstring &usage, - unsigned width, unsigned indent) const + pstring options::help(pstring description, pstring usage, + unsigned width, unsigned indent) { pstring ret; @@ -207,10 +206,6 @@ 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 = ""; @@ -226,20 +221,20 @@ namespace plib { if (opt->has_argument()) { line += "="; - auto *ol = dynamic_cast<option_str_limit_base *>(opt); + option_str_limit *ol = dynamic_cast<option_str_limit *>(opt); if (ol) { for (auto &v : ol->limit()) { line += v + "|"; } - line = plib::left(line, line.length() - 1); + line = line.left(line.length() - 1); } else line += "Value"; } } - line = plib::rpad(line, pstring(" "), indent - 2) + " "; + line = line.rpad(" ", indent - 2) + " "; if (line.length() > indent) { //ret += "TestGroup abc\n def gef\nxyz\n\n" ; @@ -255,7 +250,6 @@ namespace plib { if (grp->help() != "") ret += split_paragraphs(grp->help(), width, 4, 4) + "\n"; } } - // FIXME: other help ... pstring ex(""); for (auto & optbase : m_opts ) { @@ -272,22 +266,22 @@ namespace plib { return ret; } - option *options::getopt_short(const pstring &arg) const + option *options::getopt_short(pstring arg) { for (auto & optbase : m_opts) { auto opt = dynamic_cast<option *>(optbase); - if (opt && arg != "" && opt->short_opt() == arg) + if (opt && opt->short_opt() == arg) return opt; } return nullptr; } - option *options::getopt_long(const pstring &arg) const + option *options::getopt_long(pstring arg) { for (auto & optbase : m_opts) { auto opt = dynamic_cast<option *>(optbase); - if (opt && arg !="" && opt->long_opt() == arg) + if (opt && 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 086fe32fc8a..491ac0b4d91 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 "plists.h" #include "pstring.h" +#include "plists.h" #include "putil.h" namespace plib { @@ -24,12 +24,10 @@ class options; class option_base { public: - option_base(options &parent, const pstring &help); - virtual ~option_base() = default; - - COPYASSIGNMOVE(option_base, delete) + option_base(options &parent, pstring help); + virtual ~option_base(); - pstring help() const { return m_help; } + pstring help() { return m_help; } private: pstring m_help; }; @@ -37,10 +35,11 @@ private: class option_group : public option_base { public: - option_group(options &parent, const pstring &group, const pstring &help) + option_group(options &parent, pstring group, pstring help) : option_base(parent, help), m_group(group) { } + ~option_group(); - pstring group() const { return m_group; } + pstring group() { return m_group; } private: pstring m_group; }; @@ -48,10 +47,11 @@ private: class option_example : public option_base { public: - option_example(options &parent, const pstring &group, const pstring &help) + option_example(options &parent, pstring group, pstring help) : option_base(parent, help), m_example(group) { } + ~option_example(); - pstring example() const { return m_example; } + pstring example() { return m_example; } private: pstring m_example; }; @@ -60,7 +60,8 @@ private: class option : public option_base { public: - option(options &parent, const pstring &ashort, const pstring &along, const pstring &help, bool has_argument); + option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument); + ~option(); /* no_argument options will be called with "" argument */ @@ -88,177 +89,131 @@ private: class option_str : public option { public: - option_str(options &parent, const pstring &ashort, const pstring &along, const pstring &defval, const pstring &help) + option_str(options &parent, pstring ashort, pstring along, pstring defval, pstring help) : option(parent, ashort, along, help, true), m_val(defval) {} - pstring operator ()() const { return m_val; } + pstring operator ()() { return m_val; } protected: - int parse(const pstring &argument) override; + virtual int parse(const pstring &argument) override; private: pstring m_val; }; -class option_str_limit_base : public option +class option_str_limit : public option { public: - 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) + 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, ":")) { } - const std::vector<pstring> &limit() const { return m_limit; } + + pstring operator ()() { return m_val; } + const std::vector<pstring> &limit() { return m_limit; } protected: + virtual int parse(const pstring &argument) override; private: + pstring m_val; std::vector<pstring> m_limit; }; - -template <typename T> -class option_str_limit : public option_str_limit_base +class option_bool : public option { public: - 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; } + option_bool(options &parent, pstring ashort, pstring along, pstring help) + : option(parent, ashort, along, help, false), m_val(false) + {} - pstring as_string() const { return limit()[m_val]; } + bool operator ()() { return m_val; } protected: - 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; - } + virtual int parse(const pstring &argument) override; private: - T m_val; + bool m_val; }; -class option_bool : public option +class option_double : public option { public: - option_bool(options &parent, const pstring &ashort, const pstring &along, const pstring &help) - : option(parent, ashort, along, help, false), m_val(false) + option_double(options &parent, pstring ashort, pstring along, double defval, pstring help) + : option(parent, ashort, along, help, true), m_val(defval) {} - bool operator ()() const { return m_val; } + double operator ()() { return m_val; } protected: - int parse(const pstring &argument) override; + virtual int parse(const pstring &argument) override; private: - bool m_val; + double m_val; }; -template <typename T> -class option_num : public option +class option_long : public option { public: - 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) + option_long(options &parent, pstring ashort, pstring along, long defval, pstring help) + : option(parent, ashort, along, help, true), m_val(defval) {} - T operator ()() const { return m_val; } + long operator ()() { return m_val; } protected: - 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)); - } + virtual int parse(const pstring &argument) override; private: - T m_val; - T m_min; - T m_max; + long m_val; }; class option_vec : public option { public: - option_vec(options &parent, const pstring &ashort, const pstring &along, const pstring &help) + option_vec(options &parent, pstring ashort, pstring along, pstring help) : option(parent, ashort, along, help, true) {} - const std::vector<pstring> &operator ()() const { return m_val; } + std::vector<pstring> operator ()() { return m_val; } protected: - int parse(const pstring &argument) override; + virtual int parse(const pstring &argument) override; private: std::vector<pstring> m_val; }; -class option_args : public option_vec -{ -public: - option_args(options &parent, const pstring &help) - : option_vec(parent, "", "", help) - {} -}; - -class options : public nocopyassignmove +class options { public: options(); - explicit options(option **o); + explicit options(option *o[]); + + ~options(); void register_option(option_base *opt); - int parse(int argc, char **argv); + int parse(int argc, char *argv[]); - pstring help(const pstring &description, const pstring &usage, - unsigned width = 72, unsigned indent = 20) const; + pstring help(pstring description, pstring usage, + unsigned width = 72, unsigned indent = 20); - pstring app() const { return m_app; } + pstring app() { return m_app; } private: - static pstring split_paragraphs(const pstring &text, unsigned width, unsigned indent, + static pstring split_paragraphs(pstring text, unsigned width, unsigned indent, unsigned firstline_indent); - 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; + option *getopt_short(pstring arg); + option *getopt_long(pstring arg); 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 5e1a231da81..7547572192d 100644 --- a/src/lib/netlist/plib/pparser.cpp +++ b/src/lib/netlist/plib/pparser.cpp @@ -16,6 +16,16 @@ 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; @@ -24,7 +34,7 @@ pstring ptokenizer::currentline_str() void ptokenizer::skipeol() { - pstring::value_type c = getc(); + pstring::code_t c = getc(); while (c) { if (c == 10) @@ -39,11 +49,11 @@ void ptokenizer::skipeol() } -pstring::value_type ptokenizer::getc() +pstring::code_t ptokenizer::getc() { if (m_unget != 0) { - pstring::value_type c = m_unget; + pstring::code_t c = m_unget; m_unget = 0; return c; } @@ -56,11 +66,11 @@ pstring::value_type ptokenizer::getc() return 0; return '\n'; } - pstring::value_type c = *(m_px++); + pstring::code_t c = *(m_px++); return c; } -void ptokenizer::ungetc(pstring::value_type c) +void ptokenizer::ungetc(pstring::code_t c) { m_unget = c; } @@ -112,7 +122,6 @@ pstring ptokenizer::get_identifier_or_number() return tok.str(); } -// FIXME: combine into template double ptokenizer::get_number_double() { token_t tok = get_token(); @@ -120,8 +129,8 @@ double ptokenizer::get_number_double() { error(pfmt("Expected a number, got <{1}>")(tok.str()) ); } - bool err; - auto ret = plib::pstonum_ne<double>(tok.str(), err); + bool err = false; + double ret = tok.str().as_double(&err); if (err) error(pfmt("Expected a number, got <{1}>")(tok.str()) ); return ret; @@ -134,8 +143,8 @@ long ptokenizer::get_number_long() { error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); } - bool err; - auto ret = plib::pstonum_ne<long>(tok.str(), err); + bool err = false; + long ret = tok.str().as_long(&err); if (err) error(pfmt("Expected a long int, got <{1}>")(tok.str()) ); return ret; @@ -173,7 +182,7 @@ ptokenizer::token_t ptokenizer::get_token() ptokenizer::token_t ptokenizer::get_token_internal() { /* skip ws */ - pstring::value_type c = getc(); + pstring::code_t c = getc(); while (m_whitespace.find(c) != pstring::npos) { c = getc(); @@ -263,31 +272,28 @@ void ptokenizer::error(const pstring &errs) // A simple preprocessor // ---------------------------------------------------------------------------------------- -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) +ppreprocessor::ppreprocessor(std::vector<define_t> *defines) +: m_ifflag(0), m_level(0), m_lineno(0) { - 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_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"); - if (defines != nullptr) - m_defines = *defines; m_defines.insert({"__PLIB_PREPROCESSOR__", define_t("__PLIB_PREPROCESSOR__", "1")}); + if (defines != nullptr) + { + for (auto & p : *defines) + { + m_defines.insert({p.m_name, p}); + } + } } void ppreprocessor::error(const pstring &err) @@ -295,42 +301,35 @@ 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 -int ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio) +double ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, int prio) { - int val = 0; + double val; pstring tok=sexpr[start]; if (tok == "(") { start++; - val = expr(sexpr, start, /*prio*/ 255); + val = expr(sexpr, start, /*prio*/ 0); 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]; @@ -339,25 +338,36 @@ int ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, i // FIXME: catch error return val; } - else if (tok == "!") + else if (tok == "+") { - if (prio < 3) + if (prio > 10) return val; start++; - val = !expr(sexpr, start, 3); + val = val + expr(sexpr, start, 10); } - CHECKTOK2(*, 5) - CHECKTOK2(/, 5) - CHECKTOK2(+, 6) - CHECKTOK2(-, 6) - CHECKTOK2(==, 10) - CHECKTOK2(&&, 14) - CHECKTOK2(||, 15) - else + else if (tok == "-") { - // FIXME: error handling - val = plib::pstonum<decltype(val)>(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 == "==") + { + if (prio > 5) + return val; start++; + val = (val == expr(sexpr, start, 5)) ? 1.0 : 0.0; } } return val; @@ -366,7 +376,10 @@ int ppreprocessor::expr(const std::vector<pstring> &sexpr, std::size_t &start, i ppreprocessor::define_t *ppreprocessor::get_define(const pstring &name) { auto idx = m_defines.find(name); - return (idx != m_defines.end()) ? &idx->second : nullptr; + if (idx != m_defines.end()) + return &idx->second; + else + return nullptr; } pstring ppreprocessor::replace_macros(const pstring &line) @@ -376,135 +389,78 @@ pstring ppreprocessor::replace_macros(const pstring &line) for (auto & elem : elems) { define_t *def = get_define(elem); - ret += (def != nullptr) ? def->m_replace : elem; + if (def != nullptr) + ret += def->m_replace; + else + ret += elem; } return ret; } -static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, const pstring &sep) +static pstring catremainder(const std::vector<pstring> &elems, std::size_t start, pstring sep) { pstring ret(""); - for (std::size_t i = start; i < elems.size(); i++) + for (auto & elem : elems) { - ret += elems[i]; + ret += elem; ret += sep; } return ret; } -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 ppreprocessor::process_line(const pstring &line) { - 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 lt = line.replace_all("\t"," ").trim(); pstring ret; + m_lineno++; // FIXME ... revise and extend macro handling - if (plib::startsWith(lt, "#")) + if (lt.startsWith("#")) { std::vector<pstring> lti(psplit(lt, " ", true)); - if (lti[0] == "#if") + if (lti[0].equals("#if")) { m_level++; std::size_t start = 0; lt = replace_macros(lt); - std::vector<pstring> t(psplit(replace_all(lt.substr(3), pstring(" "), pstring("")), m_expr_sep)); - auto val = static_cast<int>(expr(t, start, 255)); + std::vector<pstring> t(psplit(lt.substr(3).replace_all(" ",""), m_expr_sep)); + int val = static_cast<int>(expr(t, start, 0)); if (val == 0) m_ifflag |= (1 << m_level); } - else if (lti[0] == "#ifdef") + else if (lti[0].equals("#ifdef")) { m_level++; if (get_define(lti[1]) == nullptr) m_ifflag |= (1 << m_level); } - else if (lti[0] == "#ifndef") + else if (lti[0].equals("#ifndef")) { m_level++; if (get_define(lti[1]) != nullptr) m_ifflag |= (1 << m_level); } - else if (lti[0] == "#else") + else if (lti[0].equals("#else")) { m_ifflag ^= (1 << m_level); } - else if (lti[0] == "#endif") + else if (lti[0].equals("#endif")) { m_ifflag &= ~(1 << m_level); m_level--; } - else if (lti[0] == "#include") + else if (lti[0].equals("#include")) { // ignore } - else if (lti[0] == "#pragma") + else if (lti[0].equals("#pragma")) { - if (m_ifflag == 0 && lti.size() > 3 && lti[1] == "NETLIST") + if (m_ifflag == 0 && lti.size() > 3 && lti[1].equals("NETLIST")) { - if (lti[2] == "warning") + if (lti[2].equals("warning")) error("NETLIST: " + catremainder(lti, 3, " ")); } } - else if (lti[0] == "#define") + else if (lti[0].equals("#define")) { if (m_ifflag == 0) { @@ -514,20 +470,28 @@ pstring ppreprocessor::process_line(pstring line) } } else - { - if (m_ifflag == 0) - error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(replace_macros(line))); - } + error(pfmt("unknown directive on line {1}: {2}")(m_lineno)(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 1eca20e99ad..7ec517255c8 100644 --- a/src/lib/netlist/plib/pparser.h +++ b/src/lib/netlist/plib/pparser.h @@ -8,27 +8,20 @@ #ifndef PPARSER_H_ #define PPARSER_H_ +#include "pstring.h" #include "plists.h" #include "pstream.h" -#include "pstring.h" -#include <cstdint> #include <unordered_map> - +#include <cstdint> namespace plib { -class ptokenizer +class ptokenizer : nocopyassignmove { public: - 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) + explicit ptokenizer(plib::putf8_reader &strm); - virtual ~ptokenizer() = default; + virtual ~ptokenizer(); enum token_type { @@ -98,23 +91,22 @@ 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(const pstring &token) + token_id_t register_token(pstring token) { token_id_t ret(m_tokens.size()); m_tokens.emplace(token, ret); return ret; } - 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) + 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) { 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(); @@ -126,17 +118,17 @@ protected: private: void skipeol(); - pstring::value_type getc(); - void ungetc(pstring::value_type c); + pstring::code_t getc(); + void ungetc(pstring::code_t 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::value_type m_unget; + pstring::code_t m_unget; /* tokenizer stuff follows ... */ @@ -145,7 +137,7 @@ private: pstring m_number_chars_start; std::unordered_map<pstring, token_id_t> m_tokens; pstring m_whitespace; - pstring::value_type m_string; + pstring::code_t m_string; token_id_t m_tok_comment_start; token_id_t m_tok_comment_end; @@ -153,7 +145,7 @@ private: }; -class ppreprocessor : public pistream +class ppreprocessor : plib::nocopyassignmove { public: @@ -166,80 +158,29 @@ public: pstring m_replace; }; - 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; + explicit ppreprocessor(std::vector<define_t> *defines = nullptr); + virtual ~ppreprocessor() {} - - 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) - { - } + void process(putf8_reader &istrm, putf8_writer &ostrm); protected: - - 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); + double 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: - enum state_e - { - PROCESS, - LINE_CONTINUATION - }; - pstring process_line(pstring line); - pstring process_comments(pstring line); + pstring process_line(const pstring &line); - defines_map_type m_defines; + std::unordered_map<pstring, define_t> 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 9c5329cccde..dc151d5d6a6 100644 --- a/src/lib/netlist/plib/ppmf.h +++ b/src/lib/netlist/plib/ppmf.h @@ -10,8 +10,9 @@ #include "pconfig.h" -#include <cstdint> #include <utility> +#include <cstdint> + /* * @@ -69,8 +70,7 @@ namespace plib { using generic_function = void (*)(); template<typename MemberFunctionType> - mfp(MemberFunctionType mftp) // NOLINT(cppcoreguidelines-pro-type-member-init) - + mfp(MemberFunctionType mftp) : 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); - auto robject = reinterpret_cast<generic_class *>(object); + generic_class *robject = reinterpret_cast<generic_class *>(object); mfpo.convert_to_generic(rfunc, robject); func = reinterpret_cast<FunctionType>(rfunc); object = reinterpret_cast<ObjectType *>(robject); @@ -95,8 +95,7 @@ namespace plib { if (PHAS_PMF_INTERNAL == 1) { // apply the "this" delta to the object first - // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) - auto o_p_delta = reinterpret_cast<generic_class *>(reinterpret_cast<std::uint8_t *>(object) + m_this_delta); + generic_class * 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)) @@ -242,28 +241,23 @@ namespace plib { { public: class generic_class; - - template <class C> - using MemberFunctionType = R (C::*)(Targs...); - pmfp() : pmfp_base<R, Targs...>(), m_obj(nullptr) {} - template<typename O> - pmfp(MemberFunctionType<O> mftp, O *object) + template<typename MemberFunctionType, typename O> + pmfp(MemberFunctionType mftp, O *object) : pmfp_base<R, Targs...>() { this->set(mftp, object); } - - template<typename O> - void set(MemberFunctionType<O> mftp, O *object) + template<typename MemberFunctionType, typename O> + void set(MemberFunctionType 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)...); } @@ -275,6 +269,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 3bd93ed4f8e..043033ed1ea 100644 --- a/src/lib/netlist/plib/pstate.cpp +++ b/src/lib/netlist/plib/pstate.cpp @@ -9,6 +9,17 @@ #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) { @@ -18,40 +29,46 @@ void state_manager_t::save_state_ptr(const void *owner, const pstring &stname, c void state_manager_t::remove_save_items(const void *owner) { - auto i = m_save.end(); - while (i != m_save.begin()) + for (auto i = m_save.begin(); i != m_save.end(); ) { - i--; if (i->get()->m_owner == owner) i = m_save.erase(i); + else + i++; } - i = m_custom.end(); - while (i > m_custom.begin()) + for (auto i = m_custom.begin(); i != m_custom.end(); ) { - 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(*this); + s->m_callback->on_pre_save(); } void state_manager_t::post_load() { for (auto & s : m_custom) - s->m_callback->on_post_load(*this); + s->m_callback->on_post_load(); } 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); } -} // namespace plib +state_manager_t::callback_t::~callback_t() +{ +} + + +} diff --git a/src/lib/netlist/plib/pstate.h b/src/lib/netlist/plib/pstate.h index ac75ca6b69e..9757d6408b7 100644 --- a/src/lib/netlist/plib/pstate.h +++ b/src/lib/netlist/plib/pstate.h @@ -8,13 +8,11 @@ #ifndef PSTATE_H_ #define PSTATE_H_ -#include "palloc.h" #include "pstring.h" #include "ptypes.h" -#include <array> -#include <memory> #include <vector> +#include <memory> // ---------------------------------------------------------------------------------------- // state saving ... @@ -40,31 +38,32 @@ public: const bool is_custom; }; - template<typename T> - static datatype_t dtype() + template<typename T> struct datatype_f { - return datatype_t(sizeof(T), - plib::is_integral<T>::value || std::is_enum<T>::value, - std::is_floating_point<T>::value); - } + 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); + } + }; 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(state_manager_t &manager) = 0; - virtual void on_post_load(state_manager_t &manager) = 0; + virtual void on_pre_save() = 0; + virtual void on_post_load() = 0; protected: - callback_t() = default; - ~callback_t() = default; - COPYASSIGNMOVE(callback_t, default) }; struct entry_t { - using list_t = std::vector<plib::unique_ptr<entry_t>>; + using list_t = std::vector<std::unique_ptr<entry_t>>; entry_t(const pstring &stname, const datatype_t &dt, const void *owner, const std::size_t count, void *ptr) @@ -73,6 +72,8 @@ 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; @@ -81,49 +82,35 @@ public: void * m_ptr; }; - state_manager_t() = default; + state_manager_t(); + ~state_manager_t(); - 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, dtype<C>(), 1, &state); + save_state_ptr( owner, stname, datatype_f<C>::f(), 1, &state); } - 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) + template<typename C, std::size_t N> void save_item(const void *owner, C (&state)[N], const pstring &stname) { - save_state_ptr(owner, stname, dtype<C>(), N, &(state[0])); + save_state_ptr(owner, stname, datatype_f<C>::f(), 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, dtype<C>(), count, state); + save_state_ptr(owner, stname, datatype_f<C>::f(), count, state); } template<typename C> void save_item(const void *owner, std::vector<C> &v, const pstring &stname) { - 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()); + save_state(v.data(), owner, stname, v.size()); } void pre_save(); void post_load(); void remove_save_items(const void *owner); - 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; - } + const entry_t::list_t &save_list() const { return m_save; } void save_state_ptr(const void *owner, const pstring &stname, const datatype_t &dt, const std::size_t count, void *ptr); @@ -137,6 +124,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 a7acdaafb52..420f63c9e5e 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,14 +21,34 @@ 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 // ----------------------------------------------------------------------------- @@ -71,7 +91,7 @@ pifilestream::~pifilestream() } } -pifilestream::pos_type pifilestream::vread(value_type *buf, const pos_type n) +pifilestream::pos_type pifilestream::vread(void *buf, const pos_type n) { pos_type r = fread(buf, 1, n, static_cast<FILE *>(m_file)); if (r < n) @@ -99,7 +119,7 @@ void pifilestream::vseek(const pos_type n) throw file_e("Generic file operation failed: {}", m_filename); } -pifilestream::pos_type pifilestream::vtell() const +pifilestream::pos_type pifilestream::vtell() { long ret = ftell(static_cast<FILE *>(m_file)); if (ret < 0) @@ -120,6 +140,10 @@ pstdin::pstdin() /* nothing to do */ } +pstdin::~pstdin() +{ +} + // ----------------------------------------------------------------------------- // Output file stream // ----------------------------------------------------------------------------- @@ -156,11 +180,12 @@ pofilestream::~pofilestream() } } -void pofilestream::vwrite(const value_type *buf, const pos_type n) +void pofilestream::vwrite(const void *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); } @@ -179,7 +204,7 @@ void pofilestream::vseek(const pos_type n) } } -pstream::pos_type pofilestream::vtell() const +pstream::pos_type pofilestream::vtell() { std::ptrdiff_t ret = ftell(static_cast<FILE *>(m_file)); if (ret < 0) @@ -190,6 +215,11 @@ pstream::pos_type pofilestream::vtell() const return static_cast<pos_type>(ret); } +postringstream::~postringstream() +{ +} + + // ----------------------------------------------------------------------------- // pstderr: write to stderr // ----------------------------------------------------------------------------- @@ -203,6 +233,10 @@ pstderr::pstderr() { } +pstderr::~pstderr() +{ +} + // ----------------------------------------------------------------------------- // pstdout: write to stdout // ----------------------------------------------------------------------------- @@ -216,32 +250,35 @@ 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 char *>(mem)) + : pistream(FLAG_SEEKABLE), m_pos(0), m_len(len), m_mem(static_cast<const pstring::mem_t *>(mem)) { } -pimemstream::pimemstream() - : pistream(FLAG_SEEKABLE), m_pos(0), m_len(0), m_mem(static_cast<const char *>(nullptr)) +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(const pomemstream &ostrm) -: pistream(FLAG_SEEKABLE), m_pos(0), m_len(ostrm.size()), m_mem(reinterpret_cast<const char *>(ostrm.memory())) +pimemstream::~pimemstream() { } -pimemstream::pos_type pimemstream::vread(value_type *buf, const pos_type n) +pimemstream::pos_type pimemstream::vread(void *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, reinterpret_cast<char *>(buf)); + std::copy(m_mem + m_pos, m_mem + m_pos + ret, static_cast<char *>(buf)); m_pos += ret; } @@ -258,45 +295,78 @@ void pimemstream::vseek(const pos_type n) } -pimemstream::pos_type pimemstream::vtell() const +pimemstream::pos_type pimemstream::vtell() { return m_pos; } +pistringstream::~pistringstream() +{ +} + // ----------------------------------------------------------------------------- // Output memory stream // ----------------------------------------------------------------------------- pomemstream::pomemstream() -: postream(FLAG_SEEKABLE), m_pos(0), m_mem(1024) +: postream(FLAG_SEEKABLE), m_pos(0), m_capacity(1024), m_size(0) +{ + m_mem = palloc_array<char>(m_capacity); +} + +pomemstream::~pomemstream() { - m_mem.clear(); + pfree_array(m_mem); } -void pomemstream::vwrite(const value_type *buf, const pos_type n) +void pomemstream::vwrite(const void *buf, const pos_type n) { - if (m_pos + n >= m_mem.size()) - m_mem.resize(m_pos + 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); + } - std::copy(buf, buf + n, &m_mem[0] + m_pos); + std::copy(static_cast<const char *>(buf), static_cast<const char *>(buf) + n, m_mem + m_pos); m_pos += n; + m_size = std::max(m_pos, m_size); } void pomemstream::vseek(const pos_type n) { m_pos = n; - if (m_pos>=m_mem.size()) - m_mem.resize(m_pos); + 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); + } } -pstream::pos_type pomemstream::vtell() const +pstream::pos_type pomemstream::vtell() { return m_pos; } bool putf8_reader::readline(pstring &line) { - putf8string::code_t c = 0; + pstring::code_t c = 0; m_linebuf = ""; if (!this->readcode(c)) { @@ -308,14 +378,23 @@ bool putf8_reader::readline(pstring &line) if (c == 10) break; else if (c != 13) /* ignore CR */ - m_linebuf += putf8string(c); + m_linebuf += pstring(c); if (!this->readcode(c)) break; } - line = m_linebuf.c_str(); + line = m_linebuf; 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 { @@ -324,4 +403,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 93497eb1423..3e9ee99cba0 100644 --- a/src/lib/netlist/plib/pstream.h +++ b/src/lib/netlist/plib/pstream.h @@ -7,76 +7,46 @@ #ifndef PSTREAM_H_ #define PSTREAM_H_ - -#include "palloc.h" #include "pconfig.h" -#include "pexception.h" -#include "pfmtlog.h" #include "pstring.h" +#include "pfmtlog.h" +#include "pexception.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 +class pstream : nocopyassignmove { 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 seekp(const pos_type n) + void seek(const pos_type n) { - vseek(n); + return vseek(n); } - pos_type tellp() const + pos_type tell() { return vtell(); } protected: - pstream() : m_flags(0) - { - } explicit pstream(const unsigned flags) : m_flags(flags) { } - pstream(pstream &&src) noexcept = default; - - virtual ~pstream() = default; + ~pstream(); virtual void vseek(const pos_type n) = 0; - virtual pos_type vtell() const = 0; + virtual pos_type vtell() = 0; static constexpr unsigned FLAG_EOF = 0x01; static constexpr unsigned FLAG_SEEKABLE = 0x04; @@ -99,71 +69,51 @@ private: // pistream: input stream // ----------------------------------------------------------------------------- -template <typename T> -class pistream_base : public pstream +class pistream : public pstream { public: - using value_type = T; - - ~pistream_base() noexcept override = default; - - COPYASSIGN(pistream_base, delete) - pistream_base &operator=(pistream_base &&src) noexcept = delete; + virtual ~pistream(); bool eof() const { return ((flags() & FLAG_EOF) != 0); } - pos_type read(T *buf, const pos_type n) + pos_type read(void *buf, const pos_type n) { return vread(buf, n); } protected: - pistream_base() : pstream(0) {} - explicit pistream_base(const unsigned flags) : pstream(flags) {} - pistream_base(pistream_base &&src) noexcept : pstream(std::move(src)) {} - + explicit pistream(const unsigned flags) : pstream(flags) {} /* read up to n bytes from stream */ - virtual size_type vread(T *buf, const size_type n) = 0; -}; + virtual pos_type vread(void *buf, const pos_type n) = 0; -using pistream = pistream_base<char>; +}; // ----------------------------------------------------------------------------- // postream: output stream // ----------------------------------------------------------------------------- -#if !USE_CSTREAM -template <typename T> -class postream_base : public pstream +class postream : public pstream { public: - using value_type = T; - - postream_base() = default; - ~postream_base() noexcept override = default; - - COPYASSIGN(postream_base, delete) - postream_base &operator=(postream_base &&src) noexcept = delete; + virtual ~postream(); - void write(const T *buf, const size_type n) + void write(const void *buf, const pos_type n) { vwrite(buf, n); } -protected: - explicit postream_base(unsigned flags) : pstream(flags) {} - postream_base(postream_base &&src) noexcept : pstream(std::move(src)) {} + void write(pistream &strm); +protected: + explicit postream(unsigned flags) : pstream(flags) {} /* write n bytes to stream */ - virtual void vwrite(const T *buf, const size_type n) = 0; + virtual void vwrite(const void *buf, const pos_type n) = 0; private: }; -using postream = postream_base<char>; - // ----------------------------------------------------------------------------- // pomemstream: output string stream // ----------------------------------------------------------------------------- @@ -173,31 +123,22 @@ class pomemstream : public postream public: pomemstream(); + virtual ~pomemstream() override; - 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(); } + char *memory() const { return m_mem; } + pos_type size() const { return m_size; } protected: /* write n bytes to stream */ - void vwrite(const value_type *buf, const pos_type) override; - void vseek(const pos_type n) override; - pos_type vtell() const override; + virtual void vwrite(const void *buf, const pos_type) override; + virtual void vseek(const pos_type n) override; + virtual pos_type vtell() override; private: pos_type m_pos; - std::vector<char> m_mem; + pos_type m_capacity; + pos_type m_size; + char *m_mem; }; class postringstream : public postream @@ -205,26 +146,18 @@ class postringstream : public postream public: postringstream() : postream(0) { } - 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; + virtual ~postringstream() override; const pstring &str() { return m_buf; } protected: /* write n bytes to stream */ - void vwrite(const value_type *buf, const pos_type n) override + virtual void vwrite(const void *buf, const pos_type n) override { - m_buf += pstring(reinterpret_cast<const pstring::mem_t *>(buf), n); + m_buf += pstring(static_cast<const pstring::mem_t *>(buf), n, pstring::UTF8); } - void vseek(const pos_type n) override { unused_var(n); } - pos_type vtell() const override { return m_buf.size(); } + virtual void vseek(const pos_type n) override { } + virtual pos_type vtell() override { return m_buf.mem_t_size(); } private: pstring m_buf; @@ -238,28 +171,15 @@ class pofilestream : public postream { public: - 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; + explicit pofilestream(const pstring &fname); + virtual ~pofilestream() override; protected: pofilestream(void *file, const pstring &name, const bool do_close); /* write n bytes to stream */ - void vwrite(const value_type *buf, const pos_type n) override; - void vseek(const pos_type n) override; - pos_type vtell() const override; + virtual void vwrite(const void *buf, const pos_type n) override; + virtual void vseek(const pos_type n) override; + virtual pos_type vtell() override; private: void *m_file; @@ -273,17 +193,12 @@ private: // ----------------------------------------------------------------------------- // pstderr: write to stderr // ----------------------------------------------------------------------------- -#endif class pstderr : public pofilestream { public: pstderr(); - pstderr(pstderr &&src) noexcept = default; - pstderr &operator=(pstderr &&src) = delete; - COPYASSIGN(pstderr, delete) - - ~pstderr() noexcept override= default; + virtual ~pstderr(); }; // ----------------------------------------------------------------------------- @@ -294,11 +209,7 @@ class pstdout : public pofilestream { public: pstdout(); - pstdout(pstdout &&src) noexcept = default; - pstdout &operator=(pstdout &&src) = delete; - COPYASSIGN(pstdout, delete) - - ~pstdout() noexcept override = default; + virtual ~pstdout(); }; // ----------------------------------------------------------------------------- @@ -309,29 +220,16 @@ class pifilestream : public pistream { public: - 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; + explicit pifilestream(const pstring &fname); + virtual ~pifilestream() override; protected: pifilestream(void *file, const pstring &name, const bool do_close); /* read up to n bytes from stream */ - pos_type vread(value_type *buf, const pos_type n) override; - void vseek(const pos_type n) override; - pos_type vtell() const override; + virtual pos_type vread(void *buf, const pos_type n) override; + virtual void vseek(const pos_type n) override; + virtual pos_type vtell() override; private: void *m_file; @@ -351,10 +249,7 @@ class pstdin : public pifilestream public: pstdin(); - pstdin(pstdin &&src) noexcept = default; - pstdin &operator=(pstdin &&src) = delete; - COPYASSIGN(pstdin, delete) - ~pstdin() override = default; + virtual ~pstdin() override; }; // ----------------------------------------------------------------------------- @@ -366,36 +261,15 @@ 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); - - ~pimemstream() override = default; + virtual ~pimemstream() override; 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 */ - pos_type vread(value_type *buf, const pos_type n) override; - void vseek(const pos_type n) override; - pos_type vtell() const override; + virtual pos_type vread(void *buf, const pos_type n) override; + virtual void vseek(const pos_type n) override; + virtual pos_type vtell() override; private: pos_type m_pos; @@ -410,25 +284,12 @@ private: class pistringstream : public pimemstream { public: - 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; + explicit pistringstream(const pstring &str) : pimemstream(str.c_str(), str.mem_t_size()), m_str(str) { } + virtual ~pistringstream() override; private: /* only needed for a reference till destruction */ - const pstring m_str; + pstring m_str; }; // ----------------------------------------------------------------------------- @@ -437,84 +298,47 @@ private: /* this digests linux & dos/windows text files */ - -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 +class putf8_reader : plib::nocopyassignmove { public: + explicit putf8_reader(pistream &strm) : m_strm(strm) {} + virtual ~putf8_reader() {} - 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 eof() const { return m_strm.eof(); } bool readline(pstring &line); - bool readbyte1(pistream::value_type &b) + bool readbyte1(char &b) { - return (m_strm->read(&b, 1) == 1); + return (m_strm.read(&b, 1) == 1); } - bool readcode(putf8string::traits_type::code_t &c) + bool readcode(pstring::code_t &c) { - std::array<pistream::value_type, 4> b{0}; - if (m_strm->read(&b[0], 1) != 1) + char b[4]; + if (m_strm.read(&b[0], 1) != 1) return false; - const std::size_t l = putf8string::traits_type::codelen(reinterpret_cast<putf8string::traits_type::mem_t *>(&b)); + const std::size_t l = pstring::traits_type::codelen(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 = putf8string::traits_type::code(reinterpret_cast<putf8string::traits_type::mem_t *>(&b)); + c = pstring::traits_type::code(b); return true; } private: - 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); } + pistream &m_strm; + pstring m_linebuf; }; - // ----------------------------------------------------------------------------- // putf8writer_t: writer on top of ostream // ----------------------------------------------------------------------------- -class putf8_writer +class putf8_writer : plib::nocopyassignmove { public: - 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; + explicit putf8_writer(postream &strm) : m_strm(strm) {} + virtual ~putf8_writer() {} void writeline(const pstring &line) const { @@ -524,34 +348,24 @@ public: void write(const pstring &text) const { - // 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()); + m_strm.write(text.c_str(), text.mem_t_size()); } - void write(const pstring::value_type c) const + void write(const pstring::code_t c) const { - pstring t = pstring("") + c; - write(t); + write(pstring(c)); } 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) - : pfmt_writer_t() - , putf8_writer(strm) - { - } - - COPYASSIGNMOVE(putf8_fmt_writer, delete) - - ~putf8_fmt_writer() override = default; + explicit putf8_fmt_writer(postream &strm); + virtual ~putf8_fmt_writer() override; //protected: void vdowrite(const pstring &ls) const; @@ -563,29 +377,22 @@ private: // pbinary_writer_t: writer on top of ostream // ----------------------------------------------------------------------------- -class pbinary_writer +class pbinary_writer : plib::nocopyassignmove { public: explicit pbinary_writer(postream &strm) : m_strm(strm) {} - 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; + virtual ~pbinary_writer() {} template <typename T> - void write(const T &val) + void write(const T val) { - m_strm.write(reinterpret_cast<const postream::value_type *>(&val), sizeof(T)); + m_strm.write(&val, sizeof(T)); } void write(const pstring &s) { - 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); + write(s.mem_t_size()); + m_strm.write(s.c_str(), s.mem_t_size()); } template <typename T> @@ -593,38 +400,34 @@ public: { std::size_t sz = val.size(); write(sz); - m_strm.write(reinterpret_cast<const postream::value_type *>(val.data()), sizeof(T) * sz); + m_strm.write(val.data(), sizeof(T) * sz); } private: postream &m_strm; }; -class pbinary_reader +class pbinary_reader : plib::nocopyassignmove { public: explicit pbinary_reader(pistream &strm) : m_strm(strm) {} - 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; + virtual ~pbinary_reader() {} template <typename T> void read(T &val) { - m_strm.read(reinterpret_cast<pistream::value_type *>(&val), sizeof(T)); + m_strm.read(&val, sizeof(T)); } void read( pstring &s) { std::size_t sz = 0; read(sz); - std::vector<plib::string_info<pstring>::mem_t> buf(sz+1); - m_strm.read(buf.data(), sz); + pstring::mem_t *buf = new pstring::mem_t[sz+1]; + m_strm.read(buf, sz); buf[sz] = 0; - s = pstring(buf.data()); + s = pstring(buf, pstring::UTF8); + delete [] buf; } template <typename T> @@ -633,38 +436,13 @@ public: std::size_t sz = 0; read(sz); val.resize(sz); - m_strm.read(reinterpret_cast<pistream::value_type *>(val.data()), sizeof(T) * sz); + m_strm.read(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 c304f11d1fd..47d35d7c82f 100644 --- a/src/lib/netlist/plib/pstring.cpp +++ b/src/lib/netlist/plib/pstring.cpp @@ -10,8 +10,17 @@ #include "plists.h" #include <algorithm> -#include <atomic> #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; +} template<typename F> int pstring_t<F>::compare(const pstring_t &right) const @@ -58,6 +67,18 @@ 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; @@ -129,6 +150,114 @@ 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 c4caeab8e8f..cabce0e7b93 100644 --- a/src/lib/netlist/plib/pstring.h +++ b/src/lib/netlist/plib/pstring.h @@ -7,50 +7,45 @@ #ifndef PSTRING_H_ #define PSTRING_H_ -#include "ptypes.h" - -#include <cstring> -#include <exception> #include <iterator> -#include <limits> -#include <stdexcept> +#include <exception> #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 sub-optimal for the use-cases I encounter. +// strings in std:: which I would consider usuable 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: - using value_type = typename T::ref_value_type; + typedef typename T::ref_value_type value_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; + 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; - constexpr pstring_const_iterator() noexcept : p() { } + 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; } - // NOLINTNEXTLINE(cert-dcl21-cpp) - pstring_const_iterator operator++(int) & noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; } + pstring_const_iterator operator++(int) noexcept { pstring_const_iterator tmp(*this); operator++(); return tmp; } - 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; } + 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; } reference operator*() const noexcept { return *reinterpret_cast<pointer>(&(*p)); } pointer operator->() const noexcept { return reinterpret_cast<pointer>(&(*p)); } @@ -65,21 +60,18 @@ template <typename F> struct pstring_t { public: - using traits_type = F; + typedef F traits_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; + 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; - // FIXME: this is ugly - struct ref_value_type final + class 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; @@ -88,27 +80,37 @@ public: private: const mem_t m; }; - using const_reference = const ref_value_type &; - using reference = const_reference; + typedef const ref_value_type& const_reference; + typedef const_reference reference; + + enum enc_t + { + UTF8, + UTF16 + }; // simple construction/destruction - pstring_t() = default; - ~pstring_t() noexcept = default; + pstring_t() + { + } + ~pstring_t() + { + } // FIXME: Do something with encoding - pstring_t(const mem_t *string) + pstring_t(const mem_t *string, const enc_t enc) : m_str(string) { } - pstring_t(const mem_t *string, const size_type len) + pstring_t(const mem_t *string, const size_type len, const enc_t enc) : 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]) // NOLINT(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) + pstring_t(C (&string)[N]) { static_assert(N > 0,"pstring from array of length 0"); if (string[N-1] != 0) @@ -116,15 +118,17 @@ 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) + explicit pstring_t(const string_type &string, const enc_t enc) : m_str(string) { } - 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; + pstring_t(pstring_t &&string) + : m_str(string.m_str) + { } explicit pstring_t(code_t code) { @@ -140,8 +144,7 @@ public: *this += static_cast<code_t>(c); // FIXME: codepage conversion for u8 } - operator string_type () const { return m_str; } - + pstring_t &operator=(const pstring_t &string) { m_str = string.m_str; return *this; } template <typename T, class = typename std::enable_if<!std::is_same<T, pstring_t::traits_type>::value>::type> @@ -154,8 +157,8 @@ public: } // no non-const const_iterator for now - using iterator = pstring_const_iterator<pstring_t<F> >; - using const_iterator = pstring_const_iterator<pstring_t<F> >; + typedef pstring_const_iterator<pstring_t> iterator; + typedef pstring_const_iterator<pstring_t> const_iterator; iterator begin() { return iterator(m_str.begin()); } iterator end() { return iterator(m_str.end()); } @@ -198,26 +201,67 @@ 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 constexpr const size_type npos = static_cast<size_type>(-1); + static const size_type npos = static_cast<size_type>(-1); -private: +protected: string_type m_str; + +private: }; struct pu8_traits { - using mem_t = char; - using code_t = char; - using string_type = std::string; + typedef char mem_t; + typedef char code_t; + typedef std::string string_type; static std::size_t len(const string_type &p) { return p.size(); } - 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 std::size_t codelen(const mem_t *p) { return 1; } + static std::size_t codelen(const code_t 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]); } @@ -226,9 +270,9 @@ struct pu8_traits /* No checking, this may deliver invalid codes */ struct putf8_traits { - using mem_t = char; - using code_t = char32_t; - using string_type = std::string; + typedef char mem_t; + typedef char32_t code_t; + typedef std::string string_type; static std::size_t len(const string_type &p) { std::size_t ret = 0; @@ -241,7 +285,7 @@ struct putf8_traits } static std::size_t codelen(const mem_t *p) { - const auto p1 = reinterpret_cast<const unsigned char *>(p); + const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p); if ((*p1 & 0x80) == 0x00) return 1; else if ((*p1 & 0xE0) == 0xC0) @@ -268,7 +312,7 @@ struct putf8_traits } static code_t code(const mem_t *p) { - const auto p1 = reinterpret_cast<const unsigned char *>(p); + const unsigned char *p1 = reinterpret_cast<const unsigned char *>(p); if ((*p1 & 0x80) == 0x00) return *p1; else if ((*p1 & 0xE0) == 0xC0) @@ -317,9 +361,9 @@ struct putf8_traits struct putf16_traits { - using mem_t = char16_t; - using code_t = char32_t; - using string_type = std::u16string; + typedef char16_t mem_t; + typedef char32_t code_t; + typedef std::u16string string_type; static std::size_t len(const string_type &p) { std::size_t ret = 0; @@ -327,7 +371,7 @@ struct putf16_traits while (i != p.end()) { // FIXME: check that size is equal - auto c = static_cast<uint16_t>(*i++); + uint16_t c = static_cast<uint16_t>(*i++); if (!((c & 0xd800) == 0xd800)) ret++; } @@ -335,7 +379,7 @@ struct putf16_traits } static std::size_t codelen(const mem_t *p) { - auto c = static_cast<uint16_t>(*p); + uint16_t c = static_cast<uint16_t>(*p); return ((c & 0xd800) == 0xd800) ? 2 : 1; } static std::size_t codelen(const code_t c) @@ -347,7 +391,7 @@ struct putf16_traits } static code_t code(const mem_t *p) { - auto c = static_cast<uint32_t>(*p++); + uint32_t c = static_cast<uint32_t>(*p++); if ((c & 0xd800) == 0xd800) { c = (c - 0xd800) << 10; @@ -357,7 +401,7 @@ struct putf16_traits } static void encode(code_t c, string_type &s) { - auto cu = static_cast<uint32_t>(c); + uint32_t cu = static_cast<uint32_t>(c); if (c > 0xffff) { //make a surrogate pair uint32_t t = ((cu - 0x10000) >> 10) + 0xd800; @@ -381,9 +425,9 @@ struct putf16_traits struct pwchar_traits { - using mem_t = wchar_t; - using code_t = char32_t; - using string_type = std::wstring; + typedef wchar_t mem_t; + typedef char32_t code_t; + typedef std::wstring string_type; static std::size_t len(const string_type &p) { if (sizeof(wchar_t) == 2) @@ -393,7 +437,7 @@ struct pwchar_traits while (i != p.end()) { // FIXME: check that size is equal - auto c = static_cast<uint32_t>(*i++); + uint32_t c = static_cast<uint32_t>(*i++); if (!((c & 0xd800) == 0xd800)) ret++; } @@ -407,7 +451,7 @@ struct pwchar_traits { if (sizeof(wchar_t) == 2) { - auto c = static_cast<uint16_t>(*p); + uint16_t c = static_cast<uint16_t>(*p); return ((c & 0xd800) == 0xd800) ? 2 : 1; } else @@ -426,7 +470,7 @@ struct pwchar_traits { if (sizeof(wchar_t) == 2) { - auto c = static_cast<uint32_t>(*p++); + uint32_t c = static_cast<uint32_t>(*p++); if ((c & 0xd800) == 0xd800) { c = (c - 0xd800) << 10; @@ -442,7 +486,7 @@ struct pwchar_traits { if (sizeof(wchar_t) == 2) { - auto cu = static_cast<uint32_t>(c); + uint32_t cu = static_cast<uint32_t>(c); if (c > 0xffff) { //make a surrogate pair uint32_t t = ((cu - 0x10000) >> 10) + 0xd800; @@ -475,280 +519,41 @@ extern template struct pstring_t<putf8_traits>; extern template struct pstring_t<putf16_traits>; extern template struct pstring_t<pwchar_traits>; -#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>; +typedef pstring_t<putf8_traits> pstring; +typedef pstring_t<putf16_traits> pu16string; +typedef pstring_t<pwchar_traits> pwstring; 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)); + return pstring(std::to_string(v), pstring::UTF8); } template<typename T> pwstring to_wstring(const T &v) { - 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); + return pwstring(std::to_wstring(v), pwstring::UTF16); } - - 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>> { - using argument_type = pstring_t<T>; - using result_type = std::size_t; + typedef pstring_t<T> argument_type; + typedef std::size_t result_type; result_type operator()(argument_type const& s) const { - const typename argument_type::mem_t *string = s.c_str(); + const pstring::mem_t *string = s.c_str(); result_type result = 5381; - for (typename argument_type::mem_t c = *string; c != 0; c = *string++) + for (pstring::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 deleted file mode 100644 index 32ccc4f7b0d..00000000000 --- a/src/lib/netlist/plib/ptime.h +++ /dev/null @@ -1,136 +0,0 @@ -// 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 bda62099150..0934a86fdf2 100644 --- a/src/lib/netlist/plib/ptypes.h +++ b/src/lib/netlist/plib/ptypes.h @@ -9,20 +9,10 @@ #define PTYPES_H_ #include "pconfig.h" +#include "pstring.h" -#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; \ +#include <limits> namespace plib { @@ -35,14 +25,14 @@ namespace plib template<> struct is_integral<INT128> { static constexpr bool value = true; }; template<> struct numeric_limits<UINT128> { - static constexpr UINT128 max() + static inline constexpr UINT128 max() { return ~((UINT128)0); } }; template<> struct numeric_limits<INT128> { - static constexpr INT128 max() + static inline constexpr INT128 max() { return (~((UINT128)0)) >> 1; } @@ -55,98 +45,56 @@ 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; - nocopyassign(nocopyassign &&) = default; - nocopyassign &operator=(nocopyassign &&) = default; + private: + nocopyassign(const nocopyassign &) = delete; + nocopyassign &operator=(const nocopyassign &) = delete; }; //============================================================ - // Avoid unused variable warnings + // penum - strongly typed enumeration //============================================================ - template<typename... Ts> - inline void unused_var(Ts&&...) {} - //============================================================ - // is_pow2 - //============================================================ - template <typename T> - constexpr bool is_pow2(T v) noexcept + struct penum_base { - 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 + protected: + static int from_string_int(const char *str, const char *x); + static pstring nthstr(int n, const char *str); + }; -//============================================================ -// Define a "has member" trait. -//============================================================ +} + +#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 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 b62cbf60865..c34102417ec 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 "plists.h" #include "ptypes.h" +#include "plists.h" -#include <algorithm> #include <cstdlib> -#include <cstring> +#include <algorithm> #include <initializer_list> +#include <cstring> namespace plib { @@ -17,7 +17,7 @@ namespace plib const pstring buildpath(std::initializer_list<pstring> list ) { pstring ret = ""; - for( const auto &elem : list ) + for( auto elem : list ) { if (ret == "") ret = elem; @@ -33,12 +33,12 @@ namespace plib const pstring environment(const pstring &var, const pstring &default_val) { - if (std::getenv(var.c_str()) == nullptr) + if (getenv(var.c_str()) == nullptr) return default_val; else - return pstring(std::getenv(var.c_str())); + return pstring(getenv(var.c_str()), pstring::UTF8); } - } // namespace util + } std::vector<pstring> psplit(const pstring &str, const pstring &onstr, bool ignore_empty) { @@ -64,36 +64,6 @@ 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 = ""; @@ -102,7 +72,7 @@ namespace plib auto i = str.begin(); while (i != str.end()) { - auto p = static_cast<std::size_t>(-1); + std::size_t 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)) @@ -122,7 +92,7 @@ namespace plib } else { - pstring::value_type c = *i; + pstring::code_t c = *i; col += c; i++; } @@ -161,8 +131,31 @@ namespace plib return cnt; return -1; } - std::string penum_base::nthstr(int n, const char *str) + pstring penum_base::nthstr(int n, const char *str) { - return psplit(str, ",", false)[static_cast<std::size_t>(n)]; + 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); } } // namespace plib diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index e8145361d9d..8d59c0357e2 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -5,32 +5,27 @@ * */ -#ifndef PUTIL_H_ -#define PUTIL_H_ +#ifndef P_UTIL_H_ +#define P_UTIL_H_ #include "pstring.h" -#include <algorithm> #include <initializer_list> -#include <vector> - -#define PSTRINGIFY_HELP(y) # y -#define PSTRINGIFY(x) PSTRINGIFY_HELP(x) - +#include <algorithm> +#include <vector> // <<= needed by windows build 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, class T> - bool contains(C &con, const T &elem) + template <class C> + bool contains(C &con, const typename C::value_type &elem) { return std::find(con.begin(), con.end(), elem) != con.end(); } @@ -56,51 +51,7 @@ 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 @@ -118,41 +69,7 @@ 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 /* PUTIL_H_ */ +#endif /* P_UTIL_H_ */ diff --git a/src/lib/netlist/plib/vector_ops.h b/src/lib/netlist/plib/vector_ops.h deleted file mode 100644 index 8043c48f61c..00000000000 --- a/src/lib/netlist/plib/vector_ops.h +++ /dev/null @@ -1,151 +0,0 @@ -// 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 4a1c8ac0315..a1d53d6792d 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -9,23 +9,21 @@ ****************************************************************************/ #include "netlist/plib/pmain.h" -#include "netlist/devices/net_lib.h" -#include "netlist/nl_parser.h" #include "netlist/nl_setup.h" -#include "netlist/solver/nld_solver.h" +#include "netlist/nl_parser.h" +#include "netlist/devices/net_lib.h" #include "netlist/tools/nl_convert.h" +#include "netlist/solver/nld_solver.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", 0, std::vector<pstring>({"run","convert","listdevices","static","header","docheader"}), "run|convert|listdevices|static|header|docheader"), + opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"), 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"), @@ -33,34 +31,25 @@ 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)\n\n abc def\n\n xyz"), + opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)"), 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", 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_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"), 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."), - opt_ex3(*this, "nltool --cmd=header --tab-width=8 --line-width=80", - "Create the header file needed for including netlists as code.") + "List all known devices.") {} plib::option_group opt_grp1; - plib::option_str_limit<unsigned> opt_cmd; + plib::option_str_limit opt_cmd; plib::option_str opt_file; plib::option_vec opt_defines; plib::option_vec opt_rfolders; @@ -71,22 +60,18 @@ public: plib::option_group opt_grp2; plib::option_str opt_name; plib::option_group opt_grp3; - plib::option_num<double> opt_ttr; + plib::option_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<unsigned> opt_type; - plib::option_group opt_grp5; - plib::option_num<unsigned> opt_tabwidth; - plib::option_num<unsigned> opt_linewidth; + plib::option_str_limit opt_type; plib::option_example opt_ex1; plib::option_example opt_ex2; - plib::option_example opt_ex3; - int execute() override; - pstring usage() override; + int execute(); + pstring usage(); private: void run(); @@ -101,8 +86,6 @@ private: void listdevices(); - std::vector<pstring> m_options; - }; static NETLIST_START(dummy) @@ -120,62 +103,51 @@ NETLIST_END() class netlist_data_folder_t : public netlist::source_t { public: - netlist_data_folder_t(const pstring &folder) - : netlist::source_t(netlist::source_t::DATA) + netlist_data_folder_t(netlist::setup_t &setup, + pstring folder) + : netlist::source_t(setup, netlist::source_t::DATA) , m_folder(folder) { } - plib::unique_ptr<plib::pistream> stream(const pstring &file) override; + virtual std::unique_ptr<plib::pistream> stream(const pstring &file) override; private: pstring m_folder; }; -plib::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file) +std::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file) { pstring name = m_folder + "/" + file; try { - auto strm = plib::make_unique<plib::pifilestream>(name); - return std::move(strm); + auto strm = plib::make_unique_base<plib::pistream, plib::pifilestream>(name); + return strm; } catch (const plib::pexception &e) { if (dynamic_cast<const plib::file_open_e *>(&e) == nullptr ) throw; } - return plib::unique_ptr<plib::pistream>(nullptr); + return std::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, plib::make_unique<netlist_tool_callbacks_t>(app)) + : netlist::netlist_t(aname), m_app(app) { } - void init() + virtual ~netlist_tool_t() override { } - netlist::setup_t &setup() { return nlstate().setup(); } + void init() + { + } void read_netlist(const pstring &filename, const pstring &name, const std::vector<pstring> &logs, @@ -185,22 +157,23 @@ public: // read the netlist ... for (auto & d : defines) - setup().add_define(d); + setup().register_define(d); for (auto & r : roms) - setup().register_source(plib::make_unique<netlist_data_folder_t>(r)); + setup().register_source(plib::make_unique_base<netlist::source_t, netlist_data_folder_t>(setup(), r)); - setup().register_source(plib::make_unique<netlist::source_file_t>(filename)); + setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_file_t>(setup(), filename)); setup().include(name); - create_dynamic_logs(logs); + log_setup(logs); // start devices - setup().prepare_to_run(); + this->start(); // reset this->reset(); } - void create_dynamic_logs(const std::vector<pstring> &logs) + void log_setup(const std::vector<pstring> &logs) { log().debug("Creating dynamic logs ...\n"); for (auto & log : logs) @@ -213,15 +186,15 @@ public: std::vector<char> save_state() { - run_state_manager().pre_save(); + state().pre_save(); std::size_t size = 0; - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) size += s->m_dt.size * s->m_count; std::vector<char> buf(size); char *p = buf.data(); - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) { std::size_t sz = s->m_dt.size * s->m_count; if (s->m_dt.is_float || s->m_dt.is_integral) @@ -237,7 +210,7 @@ public: void load_state(std::vector<char> &buf) { std::size_t size = 0; - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) size += s->m_dt.size * s->m_count; if (buf.size() != size) @@ -245,7 +218,7 @@ public: char *p = buf.data(); - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) { std::size_t sz = s->m_dt.size * s->m_count; if (s->m_dt.is_float || s->m_dt.is_integral) @@ -254,16 +227,19 @@ public: log().fatal("found unsupported save element {1}\n", s->m_name); p += sz; } - run_state_manager().post_load(); - nlstate().rebuild_lists(); + state().post_load(); + rebuild_lists(); } protected: + void vlog(const plib::plog_level &l, const pstring &ls) const override; + private: + tool_app_t &m_app; }; -void netlist_tool_callbacks_t::vlog(const plib::plog_level &l, const pstring &ls) const +void netlist_tool_t::vlog(const plib::plog_level &l, const pstring &ls) const { pstring err = plib::pfmt("{}: {}\n")(l.name())(ls.c_str()); // FIXME: ... @@ -272,19 +248,18 @@ void netlist_tool_callbacks_t::vlog(const plib::plog_level &l, const pstring &ls throw netlist::nl_exception(err); } + struct input_t { input_t(const netlist::setup_t &setup, const pstring &line) - : m_value(0.0) { - std::array<char, 400> buf; // NOLINT(cppcoreguidelines-pro-type-member-init) + char buf[400]; double t; - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) - int e = sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf.data(), &m_value); + int e = sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf, &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.data()), true); + m_param = setup.find_param(pstring(buf, pstring::UTF8), true); } void setparam() @@ -311,12 +286,13 @@ struct input_t double m_value; }; -static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstring &fname) +static std::vector<input_t> read_input(const netlist::setup_t &setup, pstring fname) { std::vector<input_t> ret; if (fname != "") { - plib::putf8_reader r = plib::putf8_reader(plib::pifilestream(fname)); + plib::pifilestream f(fname); + plib::putf8_reader r(f); pstring l; while (r.readline(l)) { @@ -333,82 +309,78 @@ static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstr void tool_app_t::run() { plib::chrono::timer<plib::chrono::system_ticks> t; - std::vector<input_t> inps; - netlist::netlist_time ttr; - netlist_tool_t nt(*this, "netlist"); + t.start(); - { - auto t_guard(t.guard()); - //plib::perftime_t<plib::exact_ticks> t; + netlist_tool_t nt(*this, "netlist"); + //plib::perftime_t<plib::exact_ticks> t; - nt.init(); + nt.init(); - if (!opt_verb()) - nt.log().verbose.set_enabled(false); - if (opt_quiet()) - nt.log().warning.set_enabled(false); + if (!opt_verb()) + nt.log().verbose.set_enabled(false); + if (opt_quiet()) + nt.log().warning.set_enabled(false); - nt.read_netlist(opt_file(), opt_name(), - opt_logs(), - m_options, opt_rfolders()); + nt.read_netlist(opt_file(), opt_name(), + opt_logs(), + opt_defines(), opt_rfolders()); - inps = read_input(nt.setup(), opt_inp()); - ttr = netlist::netlist_time::from_double(opt_ttr()); - } + std::vector<input_t> inps = read_input(nt.setup(), opt_inp()); + 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(); - netlist::netlist_time nlt = nt.time(); + // FIXME: error handling + if (opt_loadstate.was_specified()) { - auto t_guard(t.guard()); - - // 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()); - } + 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; + unsigned pos = 0; + netlist::netlist_time nlt = nt.time(); - 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++; - } + 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"); + pout("runnning ...\n"); - 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; - } + 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; + } - 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 (opt_savestate.was_specified()) + { + auto savestate = nt.save_state(); + plib::pofilestream strm(opt_savestate()); + plib::pbinary_writer writer(strm); + writer.write(savestate); } + nt.stop(); + + t.stop(); double emutime = t.as_seconds(); pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n", @@ -427,9 +399,9 @@ void tool_app_t::static_compile() nt.read_netlist(opt_file(), opt_name(), opt_logs(), - m_options, opt_rfolders()); + opt_defines(), 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); @@ -445,26 +417,13 @@ 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 pos = 0; - pstring r; + unsigned adj = 0; for (const auto &x : s) - { - 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)); + adj += (x == '\t' ? 3 : 0); + pout("{1}\\\n", s.rpad(" ", RIGHT-1-adj)); } else pout("{1}\n", s); @@ -474,15 +433,15 @@ void tool_app_t::cmac(const netlist::factory::element_t *e) { auto v = plib::psplit(e->param_desc(), ","); pstring vs; - for (const auto &s : v) - vs += ", p" + plib::replace_all(plib::replace_all(s, "+", ""), ".", "_"); + for (auto s : v) + vs += ", p" + s.replace_all("+", "").replace_all(".", "_"); mac_out("#define " + e->name() + "(name" + vs + ")"); mac_out("\tNET_REGISTER_DEV(" + e->name() +", name)"); - for (const auto &s : v) + for (auto s : v) { - pstring r(plib::replace_all(plib::replace_all(s, "+", ""), ".", "_")); - if (plib::startsWith(s, "+")) + pstring r(s.replace_all("+", "").replace_all(".", "_")); + if (s.startsWith("+")) mac_out("\tNET_CONNECT(name, " + r + ", p" + r + ")"); else mac_out("\tNETDEV_PARAMI(name, " + r + ", p" + r + ")"); @@ -494,18 +453,18 @@ void tool_app_t::mac(const netlist::factory::element_t *e) { auto v = plib::psplit(e->param_desc(), ","); pstring vs; - for (const auto &s : v) + for (auto s : v) { - vs += ", " + plib::replace_all(plib::replace_all(s, "+", ""), ".", "_"); + vs += ", " + s.replace_all("+", "").replace_all(".", "_"); } pout("{1}(name{2})\n", e->name(), vs); if (v.size() > 0) { pout("/*\n"); - for (const auto &s : v) + for (auto s : v) { - pstring r(plib::replace_all(plib::replace_all(s, "+", ""), ".", "_")); - if (plib::startsWith(s, "+")) + pstring r(s.replace_all("+", "").replace_all(".", "_")); + if (s.startsWith("+")) pout("{1:10}: Terminal\n",r); else pout("{1:10}: Parameter\n", r); @@ -523,7 +482,8 @@ 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<netlist::source_proc_t>("dummy", &netlist_dummy)); + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); nt.setup().include("dummy"); pout("// license:GPL-2.0+\n"); @@ -546,9 +506,9 @@ void tool_app_t::create_header() if (last_source != e->sourcefile()) { last_source = e->sourcefile(); - 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())); + pout("{1}\n", pstring("// ").rpad("-", 72)); + pout("{1}{2}\n", pstring("// Source: "), e->sourcefile().replace_all("../", "")); + pout("{1}\n", pstring("// ").rpad("-", 72)); } cmac(e.get()); } @@ -567,7 +527,8 @@ 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<netlist::source_proc_t>("dummy", &netlist_dummy)); + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); nt.setup().include("dummy"); std::vector<pstring> devs; @@ -619,42 +580,73 @@ void tool_app_t::listdevices() netlist::factory::list_t &list = nt.setup().factory(); - nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy)); + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); nt.setup().include("dummy"); - nt.setup().prepare_to_run(); + nt.start(); - std::vector<netlist::pool_owned_ptr<netlist::core_device_t>> devs; + std::vector<plib::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(), f->name() + "_lc"); - auto d = f->Create(nt.nlstate(), f->name() + "_lc"); + f->macro_actions(nt.setup().netlist(), f->name() + "_lc"); + auto d = f->Create(nt.setup().netlist(), f->name() + "_lc"); // get the list of terminals ... - std::vector<pstring> terms(nt.setup().get_terminals_for_device_name(d->name())); + 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); + } + } + } + } out += "," + f->param_desc(); - for (const auto &p : plib::psplit(f->param_desc(),",") ) + for (auto p : plib::psplit(f->param_desc(),",") ) { - if (plib::startsWith(p, "+")) + if (p.startsWith("+")) { plib::container::remove(terms, p.substr(1)); } } out += ")"; - pout("{}\n", out); + printf("%s\n", out.c_str()); if (terms.size() > 0) { pstring t = ""; for (auto & j : terms) t += "," + j; - pout("\tTerminals: {}\n", t.substr(1)); + printf("\tTerminals: %s\n", t.substr(1).c_str()); } - devs.emplace_back(std::move(d)); + devs.push_back(std::move(d)); } } @@ -689,6 +681,10 @@ 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()); @@ -698,8 +694,8 @@ int tool_app_t::execute() if (opt_version()) { pout( - "nltool (netlist) " PSTRINGIFY(NLTOOL_VERSION) "\n" - "Copyright (C) 2019 Couriersud\n" + "nltool (netlist) 0.1\n" + "Copyright (C) 2018 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" @@ -707,12 +703,9 @@ 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.as_string(); + pstring cmd = opt_cmd(); if (cmd == "listdevices") listdevices(); else if (cmd == "run") @@ -730,29 +723,29 @@ int tool_app_t::execute() if (opt_file() == "-") { plib::pstdin f; - plib::copystream(ostrm, f); + ostrm.write(f); } else { plib::pifilestream f(opt_file()); - plib::copystream(ostrm, f); + ostrm.write(f); } contents = ostrm.str(); pstring result; - if (opt_type.as_string() == "spice") + if (opt_type().equals("spice")) { nl_convert_spice_t c; c.convert(contents); result = c.result(); } - else if (opt_type.as_string() == "eagle") + else if (opt_type().equals("eagle")) { nl_convert_eagle_t c; c.convert(contents); result = c.result(); } - else if (opt_type.as_string() == "rinf") + else if (opt_type().equals("rinf")) { nl_convert_rinf_t c; c.convert(contents); @@ -778,6 +771,13 @@ 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 683bb8a1c55..23491e88349 100644 --- a/src/lib/netlist/prg/nlwav.cpp +++ b/src/lib/netlist/prg/nlwav.cpp @@ -1,13 +1,45 @@ // license:GPL-2.0+ // copyright-holders:Couriersud -#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> +#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); +}; + /* 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 @@ -19,470 +51,324 @@ * and data chunk length to the file. */ /* http://de.wikipedia.org/wiki/RIFF_WAVE */ - class wav_t { public: - // 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) + wav_t(plib::postream &strm, unsigned sr) : m_f(strm) { - - write(m_fh); - write(m_fmt); - write(m_data); + 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)); } - - 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.seekp(0); - write(m_fh); - write(m_fmt); + m_f.seek(0); + m_f.write(&m_fh, sizeof(m_fh)); + m_f.write(&m_fmt, sizeof(m_fmt)); //data.len = fmt.block_align * n; - write(m_data); + m_f.write(&m_data, sizeof(m_data)); } } - 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)); - } + unsigned channels() { return m_fmt.channels; } + unsigned sample_rate() { return m_fmt.sample_rate; } - void write_sample(int *sample) + void write_sample(int sample) { m_data.len += m_fmt.block_align; - for (std::size_t i = 0; i < channels(); i++) - { - auto ps = static_cast<int16_t>(sample[i]); /* 16 bit sample, FIXME: Endianess? */ - write(ps); - } + int16_t ps = static_cast<int16_t>(sample); /* 16 bit sample, FIXME: Endianess? */ + m_f.write(&ps, sizeof(ps)); } private: struct riff_chunk_t { - uint8_t group_id[4] = {'R','I','F','F'}; - uint32_t filelen = 0; - uint8_t rifftype[4] = {'W','A','V','E'}; + uint8_t group_id[4]; + uint32_t filelen; + uint8_t rifftype[4]; }; struct riff_format_t { - 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 + uint8_t signature[4]; + uint32_t fmt_length; + uint16_t format_tag; uint16_t channels; uint32_t sample_rate; uint32_t bytes_per_second; uint16_t block_align; - uint16_t bits_sample = 16; + uint16_t bits_sample; }; struct riff_data_t { - riff_data_t(uint32_t alen) : len(alen) {} - uint8_t signature[4] = {'d','a','t','a'}; + uint8_t signature[4]; uint32_t len; // data follows }; - plib::postream &m_f; + 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); + + } riff_chunk_t m_fh; riff_format_t m_fmt; riff_data_t m_data; + plib::postream &m_f; + }; class log_processor { public: - 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; - } + typedef plib::pmfp<void, double, double> callback_type; + log_processor(plib::pistream &is, callback_type cb) : m_is(is), m_cb(cb) { } - void process(std::vector<plib::unique_ptr<plib::pistream>> &is) + void process() { - std::vector<plib::putf8_reader> readers; - for (auto &i : is) - { - plib::putf8_reader r(std::move(i)); - readers.push_back(std::move(r)); - } - + plib::putf8_reader reader(m_is); pstring line; - bool more = readmore(readers); - while (more) + while(reader.readline(line)) { - 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); + double t = 0.0; double v = 0.0; + sscanf(line.c_str(), "%lf %lf", &t, &v); + m_cb(t, v); } } private: + plib::pistream &m_is; callback_type m_cb; - std::vector<elem> m_e; }; struct aggregator { - using callback_type = plib::pmfp<void, std::size_t, double, double>; + typedef plib::pmfp<void, double, double> callback_type; - aggregator(std::size_t channels, double quantum, callback_type cb) - : m_channels(channels) - , m_quantum(quantum) + aggregator(double quantum, callback_type cb) + : m_quantum(quantum) , m_cb(cb) , ct(0.0) , lt(0.0) - , outsam(channels, 0.0) - , cursam(channels, 0.0) + , outsam(0.0) + , cursam(0.0) { } - void process(std::size_t chan, double time, double val) + void process(double time, double val) { - while (time >= ct + m_quantum) + while (time >= ct) { - 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; - } + outsam += (ct - lt) * cursam; + outsam = outsam / m_quantum; + m_cb(ct, outsam); + outsam = 0.0; lt = ct; ct += m_quantum; } - for (std::size_t i=0; i< m_channels; i++) - outsam[i] += (time-lt)*cursam[i]; + outsam += (time-lt)*cursam; lt = time; - cursam[chan] = val; + cursam = val; } private: - std::size_t m_channels; double m_quantum; callback_type m_cb; double ct; double lt; - std::vector<double> outsam; - std::vector<double> cursam; + double outsam; + double cursam; }; class wavwriter { public: - 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) + wavwriter(plib::postream &fo, unsigned sample_rate, double ampa) + : mean(0.0) + , means(0.0) + , maxsam(-1e9) + , minsam(1e9) + , n(0) , m_fo(fo) - , m_amp(ampa) - , m_wo(m_fo, sample_rate, channels) + , amp(ampa) + , m_wo(m_fo, sample_rate) { } - void process(std::size_t chan, double time, double outsam) + void process(double time, double outsam) { - 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; + 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; outsam = std::max(-32000.0, outsam); outsam = std::min(32000.0, outsam); - m_samples[chan] = static_cast<int>(outsam); + m_wo.write_sample(static_cast<int>(outsam)); } - 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; + double mean; + double means; + double maxsam; + double minsam; + std::size_t n; private: - plib::postream &m_fo; - double m_amp; + double amp; wav_t m_wo; }; -class vcdwriter +void nlwav_app::convert(long sample_rate) { -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) - { - 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) - { - // $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"); - } - write("$enddefinitions $end\n"); - if (format == ANALOG) - { - write("$dumpvars\n"); - //r0.0 N1X1 - for (i = 0; i < channels.size(); i++) - write(pstring("r0.0 ") + m_ids[i] + "\n"); - write("$end\n"); - } - - } - - void process(std::size_t chan, double time, double outsam) + 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)) { - if (time > m_last_time) +#if 1 + double t = 0.0; double v = 0.0; + sscanf(line.c_str(), "%lf %lf", &t, &v); + while (t >= ct) { - write(pstring("#") + plib::to_string(static_cast<std::int64_t>(m_last_time * 1e9)) + " "); - write(m_buf + "\n"); - m_buf = ""; - m_last_time = time; + 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; } - if (m_format == ANALOG) - m_buf += "r" + plib::to_string(outsam)+ " " + m_ids[chan] + " "; - else + 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) { - 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] + " "; + wo.write_sample(sample); + n++; + ct += dt; } + 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 } - -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); - } - - 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 -{ -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) - {} - - int execute() override; - pstring usage() override; - -private: - void convert_wav(); - void convert_vcd(vcdwriter::format_e format); - - 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); + plib::pfree(wo); + if (opt_inp() != "-") + plib::pfree(fin); + if (opt_out() != "-") + plib::pfree(fo); 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 + 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)); } } -void nlwav_app::convert_vcd(vcdwriter::format_e format) +void nlwav_app::convert1(long sample_rate) { + 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::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()); + double dt = 1.0 / static_cast<double>(sample_rate); - log_processor lp(m_instrms.size(), agcb); + 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)); - lp.process(m_instrms); + lp.process(); 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("Mean (static): {}\n", wo->means / static_cast<double>(wo->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); + } pstring nlwav_app::usage() { return help("Convert netlist log files into wav files.\n", - "nlwav [OPTION] ... [FILE] ..."); + "nltool [options]"); } int nlwav_app::execute() { - for (auto &i : opt_args()) - pout(pstring("Hello : ") + i + "\n"); if (opt_help()) { pout(usage()); @@ -493,7 +379,7 @@ int nlwav_app::execute() { pout( "nlwav (netlist) 0.1\n" - "Copyright (C) 2019 Couriersud\n" + "Copyright (C) 2018 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" @@ -501,31 +387,10 @@ int nlwav_app::execute() return 0; } - 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); + if ((1)) + convert1(opt_rate()); + else + convert(opt_rate()); return 0; } diff --git a/src/lib/netlist/solver/mat_cr.h b/src/lib/netlist/solver/mat_cr.h new file mode 100644 index 00000000000..8693c49c3e1 --- /dev/null +++ b/src/lib/netlist/solver/mat_cr.h @@ -0,0 +1,175 @@ +// 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 1fe14b0f5e1..87c9b46ba21 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.cpp +++ b/src/lib/netlist/solver/nld_matrix_solver.cpp @@ -6,623 +6,552 @@ */ #include "nld_matrix_solver.h" -#include "plib/putil.h" +#include "../plib/putil.h" #include <cmath> // <<= needed by windows build namespace netlist { -namespace devices + namespace devices + { + +proxied_analog_output_t::~proxied_analog_output_t() { +} - 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::add(terminal_t *term, int net_other, bool sorted) - { - if (sorted) - for (std::size_t i=0; i < m_connected_net_idx.size(); i++) +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) { - 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; - } + 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; } - 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.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++) { - connect_post_start(m_fb_sync, m_Q_sync); + 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(); } +} + +// ---------------------------------------------------------------------------------------- +// 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); +} - void matrix_solver_t::setup_base(analog_net_t::list_t &nets) - { +matrix_solver_t::~matrix_solver_t() +{ +} - log().debug("New solver setup\n"); +void matrix_solver_t::setup_base(analog_net_t::list_t &nets) +{ - m_nets.clear(); - m_terms.clear(); + log().debug("New solver setup\n"); - 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>()); - } + m_nets.clear(); + m_terms.clear(); - for (std::size_t k = 0; k < nets.size(); k++) - { - analog_net_t *net = nets[k]; + 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>()); + } - log().debug("setting up net\n"); + for (std::size_t k = 0; k < nets.size(); k++) + { + analog_net_t *net = nets[k]; - net->set_solver(this); + log().debug("setting up net\n"); - 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()); - } + net->set_solver(this); - /* 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) + for (auto &p : net->m_core_terms) { - case PREFER_BAND_MATRIX: - { - for (std::size_t k = 0; k < iN - 1; k++) + 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 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); - } - } + terminal_t *pterm = dynamic_cast<terminal_t *>(p); + add_term(k, pterm); } - } - break; - case PREFER_IDENTITY_TOP_LEFT: - { - for (std::size_t k = 0; k < iN - 1; k++) + log().debug("Added terminal {1}\n", p->name()); + break; + case detail::terminal_type::INPUT: { - 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) + proxied_analog_output_t *net_proxy_output = nullptr; + for (auto & input : m_inps) + if (input->m_proxied_net == &p->net()) { - std::swap(m_terms[i], m_terms[k]); - std::swap(m_nets[i], m_nets[k]); - pk = get_left_right_of_diag(k,k); + net_proxy_output = input.get(); + break; } - } - } - } - break; - case ASCENDING: - case DESCENDING: - { - int sort_order = (m_sort == DESCENDING ? 1 : -1); - for (std::size_t k = 0; k < iN - 1; k++) - for (std::size_t i = k+1; i < iN; i++) + if (net_proxy_output == nullptr) { - 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]); - } + 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()); } - } - 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()); + 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->m_core_terms.size()); } - void matrix_solver_t::setup_matrix() - { - const std::size_t iN = m_nets.size(); + /* now setup the matrix */ + setup_matrix(); +} - 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); - } - - // free all - no longer needed - m_rails_temp.clear(); - - sort_terms(m_sort); - - this->set_pointers(); +void matrix_solver_t::setup_matrix() +{ + const std::size_t iN = m_nets.size(); - /* 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(); + 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); - t->m_nz.clear(); + m_terms[k]->set_pointers(); + } - 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])); + for (terms_for_net_t *rt : m_rails_temp) + { + rt->clear(); // no longer needed + plib::pfree(rt); // no longer needed + } - t->m_nz.push_back(k); // add diagonal + m_rails_temp.clear(); - /* and sort */ - std::sort(t->m_nz.begin(), t->m_nz.end()); - } + /* 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. + * + */ - /* 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(); + if (m_sort != NOSORT) + { + int sort_order = (m_sort == DESCENDING ? 1 : -1); - if (k==0) - t->m_nzrd.clear(); - else + for (unsigned k = 0; k < iN - 1; k++) + for (unsigned i = k+1; i < iN; i++) { - t->m_nzrd = m_terms[k-1]->m_nzrd; - for (auto j = t->m_nzrd.begin(); j != t->m_nzrd.end(); ) + if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0) { - if (*j < k + 1) - j = t->m_nzrd.erase(j); - else - ++j; + std::swap(m_terms[i], m_terms[k]); + std::swap(m_nets[i], m_nets[k]); } } - 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])); - - /* and sort */ - std::sort(t->m_nzrd.begin(), t->m_nzrd.end()); - } - - /* create a list of non zero elements below diagonal k - * This should reduce cache misses ... - */ - - std::vector<std::vector<bool>> touched(iN, std::vector<bool>(iN)); - - 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; - } - - m_ops = 0; - for (unsigned k = 0; k < iN; k++) - { - 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 (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); - - 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); - } - - /* - * save states - */ - for (std::size_t k = 0; k < iN; k++) + for (auto &term : m_terms) { - pstring num = plib::pfmt("{1}")(k); - - 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); - - // 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()); + 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()); } } - void matrix_solver_t::update_inputs() + /* create a list of non zero elements. */ + for (unsigned k = 0; k < iN; k++) { - // avoid recursive calls. Inputs are updated outside this call - for (auto &inp : m_inps) - inp->push(inp->proxied_net()->Q_Analog()); - } + terms_for_net_t * t = m_terms[k].get(); + /* pretty brutal */ + int *other = t->connected_net_idx(); - void matrix_solver_t::update_dynamic() - { - /* update all non-linear devices */ - for (auto &dyn : m_dynamic_devices) - dyn->update_terminals(); - } + t->m_nz.clear(); - void matrix_solver_t::reset() - { - m_last_step = netlist_time::zero(); - } + 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])); - void matrix_solver_t::update() NL_NOEXCEPT - { - const netlist_time new_timestep = solve(exec().time()); - update_inputs(); + t->m_nz.push_back(k); // add diagonal - 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); - } + /* and sort */ + std::sort(t->m_nz.begin(), t->m_nz.end()); } - /* update_forced is called from within param_update - * - * this should only occur outside of execution and thus - * using time should be safe. - * + /* create a list of non zero elements right of the diagonal + * These list anticipate the population of array elements by + * Gaussian elimination. */ - void matrix_solver_t::update_forced() + for (unsigned k = 0; k < iN; k++) { - const netlist_time new_timestep = solve(exec().time()); - plib::unused_var(new_timestep); - - update_inputs(); + terms_for_net_t * t = m_terms[k].get(); + /* pretty brutal */ + int *other = t->connected_net_idx(); - if (m_params.m_dynamic_ts && has_timestep_devices()) + if (k==0) + t->m_nzrd.clear(); + else { - m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_min_timestep)); + t->m_nzrd = m_terms[k-1]->m_nzrd; + for (auto j = t->m_nzrd.begin(); j != t->m_nzrd.end(); ) + { + if (*j < k + 1) + j = t->m_nzrd.erase(j); + else + ++j; + } } + + 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])); + + /* and sort */ + std::sort(t->m_nzrd.begin(), t->m_nzrd.end()); } - void matrix_solver_t::step(const netlist_time &delta) + /* create a list of non zero elements below diagonal k + * This should reduce cache misses ... + */ + + bool **touched = plib::palloc_array<bool *>(iN); + for (unsigned k=0; k<iN; k++) + touched[k] = plib::palloc_array<bool>(iN); + + for (unsigned k = 0; k < iN; k++) { - const nl_double dd = delta.as_double(); - for (auto &d : m_step_devices) - d->timestep(dd); + 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; } - void matrix_solver_t::solve_base() + m_ops = 0; + for (unsigned k = 0; k < iN; k++) { - ++m_stat_vsolver_calls; - if (has_dynamic_devices()) + m_ops++; // 1/A(k,k) + for (unsigned row = k + 1; row < iN; row++) { - 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()) + if (touched[row][k]) { - 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); + 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; + } } } - else + } + log().verbose("Number of mults/adds for {1}: {2}", name(), m_ops); + + if ((0)) + for (unsigned k = 0; k < iN; k++) { - this->vsolve_non_dynamic(false); + 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); } - } - const netlist_time matrix_solver_t::solve(netlist_time now) + /* + * save states + */ + for (unsigned k = 0; k < iN; k++) { - const netlist_time delta = now - m_last_step; - - // We are already up to date. Avoid oscillations. - // FIXME: Make this a parameter! - if (delta < netlist_time::quantum()) - return netlist_time::zero(); + pstring num = plib::pfmt("{1}")(k); - /* 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()); + 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); - return next_time_step; + 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()); } - 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; - } + for (unsigned k=0; k<iN; k++) + plib::pfree_array(touched[k]); + plib::pfree_array(touched); +} - std::pair<int, int> matrix_solver_t::get_left_right_of_diag(std::size_t irow, std::size_t idiag) - { - /* - * 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) - */ +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()); +} - const auto row = static_cast<int>(irow); - const auto diag = static_cast<int>(idiag); +void matrix_solver_t::update_dynamic() +{ + /* update all non-linear devices */ + for (auto &dyn : m_dynamic_devices) + dyn->update_terminals(); +} - int colmax = -1; - int colmin = 999999; +void matrix_solver_t::reset() +{ + m_last_step = netlist_time::zero(); +} - auto &term = m_terms[irow]; +void matrix_solver_t::update() NL_NOEXCEPT +{ + const netlist_time new_timestep = solve(); + update_inputs(); - 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; + 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); + } +} - if (col > diag && col < colmin) - colmin = col; - else if (col < diag && col > colmax) - colmax = col; - } - } - return {colmax, colmin}; +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()) + { + m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_min_timestep)); } +} - double matrix_solver_t::get_weight_around_diag(std::size_t row, std::size_t diag) +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()) { + unsigned this_resched; + unsigned newton_loops = 0; + do { - /* - * return average absolute distance - */ + 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); + } +} - std::vector<bool> touched(1024, false); // FIXME! +const netlist_time matrix_solver_t::solve() +{ + const netlist_time now = netlist().time(); + const netlist_time delta = now - m_last_step; - 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); + // We are already up to date. Avoid oscillations. + // FIXME: Make this a parameter! + if (delta < netlist_time::quantum()) + return netlist_time::zero(); - weight = weight + std::abs(static_cast<double>(colu) - static_cast<double>(diag)); - touched[colu] = true; - } - } - } - return weight; // / static_cast<double>(term->m_railstart); - } - } + /* 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()); + + return next_time_step; +} - void matrix_solver_t::add_term(std::size_t k, terminal_t *term) +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; +} + +void matrix_solver_t::add_term(std::size_t k, terminal_t *term) +{ + if (term->m_otherterm->net().isRailNet()) { - if (term->connected_terminal()->net().isRailNet()) + m_rails_temp[k]->add(term, -1, false); + } + else + { + int ot = get_net_idx(&term->m_otherterm->net()); + if (ot>=0) { - m_rails_temp[k]->add(term, -1, false); + m_terms[k]->add(term, ot, true); } - else + /* Should this be allowed ? */ + else // if (ot<0) { - 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()); - } + 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; +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) + if (m_params.m_dynamic_ts) + { + for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++) { - 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(); + 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; - 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; + //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; - 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; + 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; - 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() + + +void matrix_solver_t::log_stats() +{ + if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats) { - 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)); - } + 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)); } +} + -} // 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 f76660e1cb9..da44370d0d9 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.h +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -10,367 +10,282 @@ #include "netlist/nl_base.h" #include "netlist/nl_errstr.h" -#include "plib/palloc.h" -#include "plib/pmatrix2d.h" -#include "plib/putil.h" -#include "plib/vector_ops.h" - -#include <cmath> +#include "netlist/plib/putil.h" namespace netlist { -namespace devices -{ + namespace devices + { /* FIXME: these should become proper devices */ struct solver_parameters_t { - bool m_pivot; + int 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; - std::size_t m_gs_loops; - std::size_t m_nr_loops; + unsigned m_gs_loops; + unsigned 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(); - - void clear(); +class terms_for_net_t : plib::nocopyassignmove +{ +public: + terms_for_net_t(); - void add(terminal_t *term, int net_other, bool sorted); + void clear(); - std::size_t count() const { return m_terms.size(); } + void add(terminal_t *term, int net_other, bool sorted); - terminal_t **terms() { return m_terms.data(); } + inline std::size_t count() const { return m_terms.size(); } - std::size_t m_railstart; + 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(); } - 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 */ + void set_pointers(); - /* state */ - nl_double m_last_V; - nl_double m_DD_n_m_1; - nl_double m_h_n_m_1; + std::size_t m_railstart; - std::vector<int> m_connected_net_idx; - private: - std::vector<terminal_t *> m_terms; + 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; - class proxied_analog_output_t : public analog_output_t - { - public: +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; - proxied_analog_output_t(core_device_t &dev, const pstring &aname, analog_net_t *pnet) - : analog_output_t(dev, aname) - , m_proxied_net(pnet) - { } +}; - 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 - }; +class proxied_analog_output_t : public analog_output_t +{ +public: - class matrix_solver_t : public device_t - { - public: - using list_t = std::vector<matrix_solver_t *>; + 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(); - enum eSortType - { - NOSORT, - ASCENDING, - DESCENDING, - PREFER_IDENTITY_TOP_LEFT, - PREFER_BAND_MATRIX - }; - - void setup(analog_net_t::list_t &nets) - { - vsetup(nets); - } + analog_net_t *m_proxied_net; // only for proxy nets in analog input logic +}; - void solve_base(); - /* 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(); +class matrix_solver_t : public device_t +{ +public: + using list_t = std::vector<matrix_solver_t *>; - bool has_dynamic_devices() const { return m_dynamic_devices.size() > 0; } - bool has_timestep_devices() const { return m_step_devices.size() > 0; } + enum eSortType + { + NOSORT, + ASCENDING, + DESCENDING + }; - void update_forced(); - void update_after(const netlist_time after) - { - m_Q_sync.net().toggle_and_push_to_queue(after); - } + virtual ~matrix_solver_t() override; - /* netdevice functions */ - NETLIB_UPDATEI(); - NETLIB_RESETI(); + void setup(analog_net_t::list_t &nets) + { + vsetup(nets); + } - 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); + void solve_base(); - virtual void log_stats(); + /* 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(); - virtual std::pair<pstring, pstring> create_solver_code() - { - return std::pair<pstring, pstring>("", plib::pfmt("/* solver doesn't support static compile */\n\n")); - } + inline bool has_dynamic_devices() const { return m_dynamic_devices.size() > 0; } + inline bool has_timestep_devices() const { return m_step_devices.size() > 0; } - /* return number of floating point operations for solve */ - std::size_t ops() { return m_ops; } + void update_forced(); + void update_after(const netlist_time &after) + { + m_Q_sync.net().toggle_and_push_to_queue(after); + } - protected: + /* netdevice functions */ + NETLIB_UPDATEI(); + NETLIB_RESETI(); - matrix_solver_t(netlist_state_t &anetlist, const pstring &name, - eSortType sort, const solver_parameters_t *params); +public: + int get_net_idx(detail::net_t *net); - void sort_terms(eSortType sort); + virtual void log_stats(); - void setup_base(analog_net_t::list_t &nets); - void update_dynamic(); + virtual std::pair<pstring, pstring> create_solver_code() + { + return std::pair<pstring, pstring>("", plib::pfmt("/* solver doesn't support static compile */\n\n")); + } - virtual void vsetup(analog_net_t::list_t &nets) = 0; - virtual unsigned vsolve_non_dynamic(const bool newton_raphson) = 0; + /* return number of floating point operations for solve */ + std::size_t ops() { return m_ops; } - netlist_time compute_next_timestep(const double cur_ts); - /* virtual */ void add_term(std::size_t net_idx, terminal_t *term); +protected: - template <typename T> - void store(const T & V); + matrix_solver_t(netlist_t &anetlist, const pstring &name, + const eSortType sort, const solver_parameters_t *params); - template <typename T> - auto delta(const T & V) -> typename std::decay<decltype(V[0])>::type; + void setup_base(analog_net_t::list_t &nets); + void update_dynamic(); - template <typename T> - void build_LE_A(T &child); - template <typename T> - void build_LE_RHS(T &child); + virtual void vsetup(analog_net_t::list_t &nets) = 0; + virtual unsigned vsolve_non_dynamic(const bool newton_raphson) = 0; - 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(); - } - } - } + netlist_time compute_next_timestep(const double cur_ts); + /* virtual */ void add_term(std::size_t net_idx, terminal_t *term); - 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; - } + template <typename T> + void store(const T * RESTRICT V); + template <typename T> + T delta(const T * RESTRICT V); - } + template <typename T> + void build_LE_A(); + template <typename T> + void build_LE_RHS(); - template <typename T> - using aligned_alloc = plib::aligned_allocator<T, PALIGN_VECTOROPT>; + 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; - 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; + std::vector<terms_for_net_t *> m_rails_temp; - plib::pmatrix2d<nl_double> m_test; + const solver_parameters_t &m_params; - 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<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; - std::vector<plib::unique_ptr<terms_for_net_t>> m_rails_temp; +private: - const solver_parameters_t &m_params; + state_var<netlist_time> m_last_step; + std::vector<core_device_t *> m_step_devices; + std::vector<core_device_t *> m_dynamic_devices; - 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; + logic_input_t m_fb_sync; + logic_output_t m_Q_sync; - private: + /* calculate matrix */ + void setup_matrix(); - state_var<netlist_time> m_last_step; - std::vector<core_device_t *> m_step_devices; - std::vector<core_device_t *> m_dynamic_devices; + void step(const netlist_time &delta); - logic_input_t m_fb_sync; - logic_output_t m_Q_sync; + std::size_t m_ops; + const eSortType m_sort; +}; - /* calculate matrix */ - void setup_matrix(); +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]); +} - void step(const netlist_time &delta); +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"); - std::size_t m_ops; - const eSortType m_sort; - }; + T &child = static_cast<T &>(*this); - template <typename T> - auto matrix_solver_t::delta(const T & V) -> typename std::decay<decltype(V[0])>::type + const std::size_t iN = child.N(); + for (std::size_t k = 0; k < iN; k++) { - /* 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; - } + terms_for_net_t *terms = m_terms[k].get(); + nl_double * Ak = &child.A(k, 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]); - } + for (std::size_t i=0; i < iN; i++) + Ak[i] = 0.0; - 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 terms_count = terms->count(); + const std::size_t railstart = terms->m_railstart; + const nl_double * const RESTRICT gt = terms->gt(); - const std::size_t iN = child.size(); - for (std::size_t k = 0; k < iN; k++) { - terms_for_net_t *terms = m_terms[k].get(); - float_type * Ak = &child.A(k, 0ul); - - for (std::size_t i=0; i < iN; i++) - Ak[i] = 0.0; - - const std::size_t terms_count = terms->count(); - const std::size_t railstart = terms->m_railstart; - const float_type * const gt = m_gtn[k]; - - { - float_type akk = 0.0; - for (std::size_t i = 0; i < terms_count; i++) - akk += gt[i]; + nl_double akk = 0.0; + for (std::size_t i = 0; i < terms_count; i++) + akk += gt[i]; - Ak[k] = akk; - } + Ak[k] = akk; + } - const float_type * const go = m_gonn[k]; - int * net_other = terms->m_connected_net_idx.data(); + const nl_double * const RESTRICT go = terms->go(); + int * RESTRICT net_other = terms->connected_net_idx(); - for (std::size_t i = 0; i < railstart; i++) - Ak[net_other[i]] += go[i]; - } + for (std::size_t i = 0; i < railstart; i++) + Ak[net_other[i]] -= go[i]; } +} - template <typename T> - void matrix_solver_t::build_LE_RHS(T &child) - { - 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; +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); - 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; + const std::size_t iN = child.N(); + for (std::size_t k = 0; k < iN; k++) + { + nl_double rhsk_a = 0.0; + nl_double rhsk_b = 0.0; - 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]; + 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(); - for (std::size_t i = 0; i < terms_count; i++) - rhsk_a = rhsk_a + Idr[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]; + 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 2501742218d..f03cb738028 100644 --- a/src/lib/netlist/solver/nld_ms_direct.h +++ b/src/lib/netlist/solver/nld_ms_direct.h @@ -8,228 +8,286 @@ #ifndef NLD_MS_DIRECT_H_ #define NLD_MS_DIRECT_H_ -#include "nld_matrix_solver.h" +#include <algorithm> + #include "nld_solver.h" -#include "plib/mat_cr.h" -#include "plib/vector_ops.h" +#include "nld_matrix_solver.h" +#include "vector_base.h" -#include <algorithm> -#include <cmath> +/* 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) namespace netlist { -namespace devices -{ - - template <typename FT, int SIZE> - class matrix_solver_direct_t: public matrix_solver_t + namespace devices { - friend class matrix_solver_t; - public: - - using float_type = FT; +//#define nl_ext_double _float128 // slow, very slow +//#define nl_ext_double long double // slightly slower +#define nl_ext_double nl_double - 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); - void vsetup(analog_net_t::list_t &nets) override; - void reset() override { matrix_solver_t::reset(); } - - protected: - unsigned vsolve_non_dynamic(const bool newton_raphson) override; - unsigned solve_non_dynamic(const bool newton_raphson); +template <std::size_t m_N, std::size_t storage_N> +class matrix_solver_direct_t: public matrix_solver_t +{ + friend class matrix_solver_t; +public: - constexpr std::size_t size() const { return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim; } + 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); - void LE_solve(); + virtual ~matrix_solver_direct_t() override; - template <typename T> - void LE_back_subst(T & x); + virtual void vsetup(analog_net_t::list_t &nets) override; + virtual void reset() override { matrix_solver_t::reset(); } - 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; +protected: + virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; + unsigned solve_non_dynamic(const bool newton_raphson); - 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; + constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; } - const std::size_t m_dim; - const std::size_t m_pitch; - plib::parray<FT, SIZE * int(m_pitch_ABS)> m_A; + void LE_solve(); - }; + 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 +} - // ---------------------------------------------------------------------------------------- - // matrix_solver_direct - // ---------------------------------------------------------------------------------------- +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 FT, int SIZE> - void matrix_solver_direct_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) + /* add RHS element */ + for (std::size_t k = 0; k < N(); k++) { - matrix_solver_t::setup_base(nets); + terms_for_net_t * t = m_terms[k].get(); - /* add RHS element */ - for (std::size_t k = 0; k < size(); k++) - { - terms_for_net_t * t = m_terms[k].get(); + if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(N()))) + t->m_nzrd.push_back(static_cast<unsigned>(N())); + } - if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(size()))) - t->m_nzrd.push_back(static_cast<unsigned>(size())); - } + netlist().save(*this, m_last_RHS, "m_last_RHS"); - // 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)); - } + for (std::size_t k = 0; k < N(); k++) + netlist().save(*this, RHS(k), plib::pfmt("RHS.{1}")(k)); +} - template <typename FT, int SIZE> - void matrix_solver_direct_t<FT, SIZE>::LE_solve() + +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) { - const std::size_t kN = size(); - if (!m_params.m_pivot) + for (std::size_t i = 0; i < kN; i++) { - for (std::size_t i = 0; i < kN; i++) - { - /* 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; - 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; - } + /* 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; + + 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; } } - else + } + else + { + for (std::size_t i = 0; i < kN; i++) { - 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++) { - /* 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; - } + //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; + } - 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)); + 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)); } - /* FIXME: Singular matrix? */ - const FT f = 1.0 / A(i,i); + //std::swap(RHS(i), RHS(maxrow)); + } + /* FIXME: Singular matrix? */ + const nl_double f = 1.0 / A(i,i); - /* Eliminate column i from row j */ + /* Eliminate column i from row j */ - for (std::size_t j = i + 1; j < kN; j++) + for (std::size_t j = i + 1; j < kN; j++) + { + const nl_double f1 = - A(j,i) * f; + if (f1 != NL_FCONST(0.0)) { - 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 - } + 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 } } } } +} - template <typename FT, int SIZE> - template <typename T> - void matrix_solver_direct_t<FT, SIZE>::LE_back_subst( - T & x) - { - const std::size_t kN = size(); +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) + /* back substitution */ + if (m_params.m_pivot) + { + for (std::size_t j = kN; j-- > 0; ) { - 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); - } + 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); } - else + } + else + { + for (std::size_t j = kN; j-- > 0; ) { - for (std::size_t j = kN; j-- > 0; ) + 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++) { - 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); + const auto pk = p[k]; + tmp += Aj[pk] * x[pk]; } + 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); - const FT err = (newton_raphson ? delta(m_new_V) : 0.0); - store(m_new_V); - return (err > this->m_params.m_accuracy) ? 2 : 1; - } +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 }; - 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->LE_solve(); + this->LE_back_subst(new_V); - this->m_stat_calculations++; - return this->solve_non_dynamic(newton_raphson); - } + 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> - 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) +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>(); + + 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_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++) { + m_last_RHS[k] = 0.0; } +} - 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) +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++) { + 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 fbbb8ecb098..6e1f99bad7d 100644 --- a/src/lib/netlist/solver/nld_ms_direct1.h +++ b/src/lib/netlist/solver/nld_ms_direct1.h @@ -13,41 +13,37 @@ namespace netlist { -namespace devices -{ - template <typename FT> - class matrix_solver_direct1_t: public matrix_solver_direct_t<FT, 1> + namespace devices { - public: - - 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) - {} +class matrix_solver_direct1_t: public matrix_solver_direct_t<1,1> +{ +public: - // ---------------------------------------------------------------------------------------- - // 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]); + 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; - 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; - } +// ---------------------------------------------------------------------------------------- +// matrix_solver - Direct1 +// ---------------------------------------------------------------------------------------- - }; +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]); + 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 01f77c3bc3c..4004bce9cc4 100644 --- a/src/lib/netlist/solver/nld_ms_direct2.h +++ b/src/lib/netlist/solver/nld_ms_direct2.h @@ -13,46 +13,43 @@ namespace netlist { -namespace devices + namespace devices + { +class matrix_solver_direct2_t: public matrix_solver_direct_t<2,2> { +public: - // ---------------------------------------------------------------------------------------- - // matrix_solver - Direct2 - // ---------------------------------------------------------------------------------------- - - template <typename FT> - class matrix_solver_direct2_t: public matrix_solver_direct_t<FT, 2> - { - 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; - using float_type = FT; +}; - 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); +// ---------------------------------------------------------------------------------------- +// matrix_solver - Direct2 +// ---------------------------------------------------------------------------------------- - 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); +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 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}; + 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); - 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; - } + 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; - }; + 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 e7cedc1dd29..c379cf8d055 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(); } - unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } + inline unsigned N() const { if (m_N == 0) return m_dim; else return m_N; } - int vsolve_non_dynamic(const bool newton_raphson); + inline int vsolve_non_dynamic(const bool newton_raphson); protected: virtual void add_term(int net_idx, terminal_t *term) override; @@ -139,10 +139,12 @@ protected: nl_double compute_next_timestep(); template <typename T1, typename T2> - nl_ext_double &A(const T1 r, const T2 c) { return m_A[r][c]; } + inline 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; @@ -353,6 +355,7 @@ 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++) @@ -587,10 +590,13 @@ unsigned matrix_solver_direct_t<m_N, storage_N>::solve_non_dynamic(const bool ne } template <unsigned m_N, unsigned storage_N> -int matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(const bool newton_raphson) +inline 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_RHS); + this->build_LE_RHS(m_last_RHS); + + for (unsigned i=0, iN=N(); i < iN; i++) + m_RHS[i] = m_last_RHS[i]; return this->solve_non_dynamic(newton_raphson); } @@ -602,6 +608,11 @@ 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> @@ -615,6 +626,7 @@ 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 f3e56a342d6..a17ca1ec282 100644 --- a/src/lib/netlist/solver/nld_ms_gcr.h +++ b/src/lib/netlist/solver/nld_ms_gcr.h @@ -10,201 +10,390 @@ #ifndef NLD_MS_GCR_H_ #define NLD_MS_GCR_H_ -#include "plib/mat_cr.h" +#include <algorithm> +#include "../plib/pdynlib.h" +#include "mat_cr.h" #include "nld_ms_direct.h" #include "nld_solver.h" -#include "plib/pdynlib.h" -#include "plib/pstream.h" -#include "plib/vector_ops.h" - -#include <algorithm> +#include "vector_base.h" +#include "../plib/pstream.h" namespace netlist { -namespace devices + namespace devices + { +template <std::size_t m_N, std::size_t storage_N> +class matrix_solver_GCR_t: public matrix_solver_t { +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() + { + } - template <typename FT, int SIZE> - class matrix_solver_GCR_t: public matrix_solver_t + virtual ~matrix_solver_GCR_t() 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() - { - } + } + + constexpr std::size_t N() const { return (m_N == 0) ? m_dim : m_N; } - constexpr std::size_t N() const { return m_dim; } + 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; + virtual std::pair<pstring, pstring> create_solver_code() override; - std::pair<pstring, pstring> create_solver_code() override; +private: - private: + //typedef typename mat_cr_t<storage_N>::type mattype; + typedef typename mat_cr_t<storage_N>::index_type mattype; - using mat_index_type = typename plib::matrix_compressed_rows_t<FT, SIZE>::index_type; + void csc_private(plib::putf8_fmt_writer &strm); - void csc_private(plib::putf8_fmt_writer &strm); + using extsolver = void (*)(double * RESTRICT m_A, double * RESTRICT RHS, double * RESTRICT V); - using extsolver = void (*)(double * m_A, double * RHS, double * V); + pstring static_compile_name(); - pstring static_compile_name(); + const std::size_t m_dim; + std::vector<unsigned> m_term_cr[storage_N]; + mat_cr_t<storage_N> mat; - const std::size_t m_dim; - plib::parray<FT, SIZE> RHS; - plib::parray<FT, SIZE> new_V; + //extsolver m_proc; + plib::dynproc<void, double * RESTRICT, double * RESTRICT, double * RESTRICT> m_proc; - mat_type mat; +}; - //extsolver m_proc; - plib::dynproc<void, double * , double * , double * > m_proc; +// ---------------------------------------------------------------------------------------- +// matrix_solver - GCR +// ---------------------------------------------------------------------------------------- + +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); - }; + mattype nz = 0; + const std::size_t iN = this->N(); - // ---------------------------------------------------------------------------------------- - // matrix_solver - GCR - // ---------------------------------------------------------------------------------------- + /* build the final matrix */ - // FIXME: namespace or static class member - template <typename V> - std::size_t inline get_level(const V &v, std::size_t k) + bool touched[storage_N][storage_N] = { { false } }; + for (std::size_t k = 0; k < iN; k++) { - 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"); + for (auto &j : this->m_terms[k]->m_nz) + touched[k][j] = true; } - template <typename FT, int SIZE> - void matrix_solver_GCR_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) - { - setup_base(nets); + unsigned fc = 0; - const std::size_t iN = this->N(); + unsigned ops = 0; - /* build the final matrix */ + 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; + } + } + } + } - std::vector<std::vector<unsigned>> fill(iN); - std::size_t raw_elements = 0; + for (mattype k=0; k<iN; k++) + { + mat.ia[k] = nz; - for (std::size_t k = 0; k < iN; k++) + for (mattype j=0; j<iN; j++) { - fill[k].resize(iN, decltype(mat)::FILL_INFINITY); - for (auto &j : this->m_terms[k]->m_nz) + if (touched[k][j]) { - fill[k][j] = 0; - raw_elements++; + mat.ja[nz] = j; + if (j == k) + mat.diag[k] = nz; + nz++; } + } + 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); + } - auto gr = mat.gaussian_extend_fill_mat(fill); + mat.ia[iN] = nz; + mat.nz_num = nz; - /* FIXME: move this to the cr matrix class and use computed - * parallel ordering once it makes sense. - */ + 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 + } - std::vector<unsigned> levL(iN, 0); - std::vector<unsigned> levU(iN, 0); +} +#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; - // parallel scheme for L x = y - for (std::size_t k = 0; k < iN; k++) + if (nzbd.size() > 0) { - 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; + 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); + } } + } - // parallel scheme for U x = y - for (std::size_t k = iN; k-- > 0; ) + //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++) { - 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("\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]); + } +} +#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 k = 0; k < iN; k++) + for (std::size_t i = 0; i < iN - 1; i++) + { + const auto &nzbd = this->m_terms[i]->m_nzbd; + + if (nzbd.size() > 0) { - unsigned fm = 0; - pstring ml = ""; - for (std::size_t j = 0; j < iN; j++) + 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) { - 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]; + // 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); } - 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()); +} - mat.build_from_fill_mat(fill); +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]; - for (mat_index_type k=0; k<iN; k++) + 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++) { - 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]]; + gtot_t += gt[i]; + RHS_t += Idr[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)); + for (std::size_t i = railstart; i < term_count; i++) + RHS_t += go[i] * *other_cur_analog[i]; - // FIXME: Move me + RHS[k] = RHS_t; - if (state().lib().isLoaded()) + // 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++) { - 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); + gtot_t += gt[i]; + RHS_t += Idr[i]; } - } + for (std::size_t i = railstart; i < term_count; i++) + { + RHS_t += (Idr[i] + go[i] * *other_cur_analog[i]); + gtot_t += gt[i]; + } - 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(); + RHS[k] = RHS_t; + mat.A[mat.diag[k]] += gtot_t; + } +#endif + mat.ia[iN] = static_cast<mattype>(mat.nz_num); - for (std::size_t i = 0; i < mat.nz_num; i++) - strm("double m_A{1} = m_A[{2}];\n", i, i); + /* 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 + { for (std::size_t i = 0; i < iN - 1; i++) { const auto &nzbd = this->m_terms[i]->m_nzbd; @@ -212,114 +401,61 @@ namespace devices 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]; - //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) + for (std::size_t j : nzbd) // for (std::size_t j = i + 1; j < iN; j++) { // proceed to column i - std::size_t pj = mat.row_idx[j]; + //__builtin_prefetch(&m_A[mat.diag[j+1]], 1); + std::size_t pj = mat.ia[j]; - while (mat.col_idx[pj] < i) + while (mat.ja[pj] < i) pj++; - //const FT f1 = - m_A[pj++] * f; - strm("\tconst double f{1}_{2} = -f{3} * m_A{4};\n", i, j, i, pj); - pj++; + const nl_double f1 = - mat.A[pj++] * f; // subtract row i from j */ for (std::size_t pii = pi; pii<piie; ) { - while (mat.col_idx[pj] < mat.col_idx[pii]) + 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++; + mat.A[pj++] += mat.A[pii++] * f1; } - //RHS[j] += f1 * RHS[i]; - strm("\tRHS[{1}] += f{2}_{3} * RHS[{4}];\n", j, i, j, i); + RHS[j] += f1 * RHS[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;) { - 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++) + //__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("\ttmp{1} += m_A{2} * V[{3}];\n", j, pk, mat.col_idx[pk]); + tmp += mat.A[pk] * new_V[mat.ja[pk]]; } - strm("\tV[{1}] = (RHS[{1}] - tmp{1}) / m_A{4};\n", j, j, j, mat.diag[j]); + new_V[j] = (RHS[j] - tmp) / mat.A[jdiag]; } } - 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); - } + this->m_stat_calculations++; - 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; - } + 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_GCR_H_ */ diff --git a/src/lib/netlist/solver/nld_ms_gmres.h b/src/lib/netlist/solver/nld_ms_gmres.h index 2ff515ebda7..2e4e447d14f 100644 --- a/src/lib/netlist/solver/nld_ms_gmres.h +++ b/src/lib/netlist/solver/nld_ms_gmres.h @@ -1,145 +1,387 @@ // license:GPL-2.0+ // copyright-holders:Couriersud /* - * nld_ms_gmres.h + * nld_ms_sor.h + * + * Generic successive over relaxation solver. + * + * Fow w==1 we will do the classic Gauss-Seidel approach * */ #ifndef NLD_MS_GMRES_H_ #define NLD_MS_GMRES_H_ -#include "nld_ms_direct.h" -#include "nld_solver.h" -#include "plib/gmres.h" -#include "plib/mat_cr.h" -#include "plib/parray.h" -#include "plib/vector_ops.h" - #include <algorithm> -#include <cmath> +#include "mat_cr.h" +#include "nld_ms_direct.h" +#include "nld_solver.h" +#include "vector_base.h" namespace netlist { -namespace devices + 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> { +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) + { + } - template <typename FT, int SIZE> - class matrix_solver_GMRES_t: public matrix_solver_direct_t<FT, SIZE> + virtual ~matrix_solver_GMRES_t() override { - public: + } - using float_type = FT; + virtual void vsetup(analog_net_t::list_t &nets) override; + virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; - /* 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) - { - } +private: + + //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 - void vsetup(analog_net_t::list_t &nets) override; - unsigned vsolve_non_dynamic(const bool newton_raphson) override; + mat_cr_t<storage_N> mat; - private: + nl_double m_LU[storage_N * storage_N]; - using mattype = typename plib::matrix_compressed_rows_t<FT, SIZE>::index_type; + 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 */ - plib::mat_precondition_ILU<FT, SIZE> m_ops; - plib::gmres_t<FT, SIZE> m_gmres; - }; +}; - // ---------------------------------------------------------------------------------------- - // matrix_solver - GMRES - // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// matrix_solver - GMRES +// ---------------------------------------------------------------------------------------- - template <typename FT, int SIZE> - void matrix_solver_GMRES_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) +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); + + mattype nz = 0; + const std::size_t iN = this->N(); + + for (std::size_t k=0; k<iN; k++) { - matrix_solver_direct_t<FT, SIZE>::vsetup(nets); + terms_for_net_t * RESTRICT row = this->m_terms[k].get(); + mat.ia[k] = nz; - const std::size_t iN = this->size(); + 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++; + } - std::vector<std::vector<unsigned>> fill(iN); + /* build pointers into the compressed row format matrix for each terminal */ - for (std::size_t k=0; k<iN; k++) + for (unsigned j=0; j< this->m_terms[k]->m_railstart;j++) { - 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 (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); } + } - m_ops.build(fill); + mat.ia[iN] = nz; + mat.nz_num = nz; +} - /* build pointers into the compressed row format matrix for each terminal */ +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)) + */ - for (std::size_t k=0; k<iN; k++) + //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++) { - 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]]; + gtot_t = gtot_t + gt[i]; + RHS_t = RHS_t + Idr[i]; } + + for (std::size_t i = railstart; i < term_count; i++) + RHS_t = RHS_t + go[i] * *other_cur_analog[i]; + + RHS[k] = RHS_t; + + // add diagonal element + mat.A[mat.diag[k]] = gtot_t; + + for (std::size_t i = 0; i < railstart; i++) + { + const std::size_t pi = m_term_cr[k][i]; + mat.A[pi] -= go[i]; + } + + 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; - template <typename FT, int SIZE> - unsigned matrix_solver_GMRES_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson) + 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) { - const std::size_t iN = this->size(); + /* 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)); - plib::parray<FT, SIZE> RHS(iN); - //float_type new_V[storage_N]; + if (rho < rho_delta) + return itr_used + 1; - m_ops.m_mat.set_scalar(0.0); + vec_set(mr+1, NL_FCONST(0.0), m_g); + m_g[0] = rho; - /* populate matrix and V for first estimate */ - this->fill_matrix(iN, this->m_mat_ptr, RHS); + for (std::size_t i = 0; i < mr; i++) + vec_set(mr + 1, NL_FCONST(0.0), m_ht[i]); - for (std::size_t k = 0; k < iN; k++) + vec_mult_scalar(n, residual, NL_FCONST(1.0) / rho, m_v[0]); + + for (std::size_t k = 0; k < mr; k++) { - this->m_new_V[k] = this->m_nets[k]->Q_Analog(); + 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; + } } - const float_type accuracy = this->m_params.m_accuracy; + if (last_k >= mr) + /* didn't converge within accuracy */ + last_k = mr - 1; - 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); + /* 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); - this->m_iterative_total += gsl; - this->m_stat_calculations++; +#if 1 + if (rho <= rho_delta) + { + break; + } +#else + /* we try to approximate the x difference between to steps using m_v[last_k] */ - if (gsl > iter) + double xdelta = m_y[last_k] * vec_maxabs(n, m_v[last_k]); + if (xdelta < accuracy) { - this->m_iterative_fail++; - return matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(newton_raphson); + if (m_accuracy_mult < 16384.0) + m_accuracy_mult = m_accuracy_mult * 2.0; + break; } + else + m_accuracy_mult = m_accuracy_mult / 2.0; - 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; +#endif } + 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 d85ab0044f4..ed95cd2dc03 100644 --- a/src/lib/netlist/solver/nld_ms_sm.h +++ b/src/lib/netlist/solver/nld_ms_sm.h @@ -33,275 +33,293 @@ #ifndef NLD_MS_SM_H_ #define NLD_MS_SM_H_ -#include "nld_matrix_solver.h" -#include "nld_solver.h" -#include "plib/vector_ops.h" - #include <algorithm> +#include "nld_solver.h" +#include "nld_matrix_solver.h" +#include "vector_base.h" + namespace netlist { -namespace devices + 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 { + friend class matrix_solver_t; - template <typename FT, int SIZE> - class matrix_solver_sm_t: public matrix_solver_t - { - friend class matrix_solver_t; +public: - public: + matrix_solver_sm_t(netlist_t &anetlist, const pstring &name, + const solver_parameters_t *params, const std::size_t size); - 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; + virtual ~matrix_solver_sm_t() override; - matrix_solver_sm_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 solve_non_dynamic(const bool newton_raphson); - protected: - 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(); - void LE_invert(); + template <typename T> + void LE_compute_x(T * RESTRICT x); - template <typename T> - void LE_compute_x(T * x); + 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]; } - 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]; } + 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]; } - 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]; } + 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; - 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 +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_lA[storage_N][m_pitch]; - float_ext_type m_lAinv[storage_N][m_pitch]; + nl_ext_double m_lA[storage_N][m_pitch]; + nl_ext_double m_lAinv[storage_N][m_pitch]; - //float_ext_type m_RHSx[storage_N]; + //nl_ext_double m_RHSx[storage_N]; - const std::size_t m_dim; - std::size_t m_cnt; + const std::size_t m_dim; + std::size_t m_cnt; - }; +}; - // ---------------------------------------------------------------------------------------- - // matrix_solver_direct - // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// matrix_solver_direct +// ---------------------------------------------------------------------------------------- - template <typename FT, int SIZE> - void matrix_solver_sm_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) - { - matrix_solver_t::setup_base(nets); +template <std::size_t m_N, std::size_t storage_N> +matrix_solver_sm_t<m_N, storage_N>::~matrix_solver_sm_t() +{ +} + +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); + + 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: 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)); - } - template <typename FT, int SIZE> - void matrix_solver_sm_t<FT, SIZE>::LE_invert() - { - const std::size_t kN = size(); - for (std::size_t i = 0; i < kN; i++) +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(); + + for (std::size_t i = 0; i < kN; i++) + { + for (std::size_t j = 0; j < kN; j++) { - 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; + W(i,j) = lA(i,j) = A(i,j); + Ainv(i,j) = 0.0; } - /* down */ - for (std::size_t i = 0; i < kN; i++) - { - /* 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(); + Ainv(i,i) = 1.0; + } + /* 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 */ + /* 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++) + 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++) + { + const unsigned j = pb[jb]; + const nl_double f1 = - W(j,i) * f; + if (f1 != 0.0) { - 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 < 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; } } - /* up */ - for (std::size_t i = kN; i-- > 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; ) { - /* FIXME: Singular matrix? */ - 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; + if (f1 != 0.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); + 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 <typename FT, int SIZE> - template <typename T> - void matrix_solver_sm_t<FT, SIZE>::LE_compute_x( - T * x) - { - const std::size_t kN = size(); +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 i=0; i<kN; i++) + x[i] = 0.0; - for (std::size_t k=0; k<kN; k++) - { - const float_type f = RHS(k); + for (std::size_t k=0; k<kN; k++) + { + const nl_double f = RHS(k); - for (std::size_t i=0; i<kN; i++) - x[i] += Ainv(i,k) * f; - } + for (std::size_t i=0; i<kN; i++) + x[i] += Ainv(i,k) * f; } +} - template <typename FT, int SIZE> - unsigned matrix_solver_sm_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphson) - { - static constexpr const bool incremental = true; - const std::size_t iN = size(); - float_type new_V[storage_N]; // = { 0.0 }; +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(); + + nl_double new_V[storage_N]; // = { 0.0 }; - if ((m_cnt % 50) == 0) + if ((m_cnt % 50) == 0) + { + /* complete calculation */ + this->LE_invert(); + } + else + { + if (!incremental) { - /* complete calculation */ - this->LE_invert(); + for (std::size_t row = 0; row < iN; row ++) + for (std::size_t k = 0; k < iN; k++) + Ainv(row,k) = lAinv(row, k); } - else + for (std::size_t row = 0; row < iN; row ++) { - if (!incremental) + 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) { - for (std::size_t row = 0; row < iN; row ++) - for (std::size_t k = 0; k < iN; k++) - Ainv(row,k) = lAinv(row, k); + 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 ++) + + if (colcount > 0) { - float_type v[m_pitch] = {0}; - std::size_t cols[m_pitch]; - std::size_t colcount = 0; + 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 */ - auto &nz = m_terms[row]->m_nz; - for (unsigned & col : nz) + 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++) { - v[col] = A(row,col) - lA(row,col); - if (incremental) - lA(row,col) = A(row,col); - if (v[col] != 0.0) - cols[colcount++] = col; + 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 */ } - if (colcount > 0) + lamba = -1.0 / (1.0 + lamba); + for (std::size_t i=0; i<iN; i++) { - 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]; + const nl_double f = lamba * z[i]; + if (f != 0.0) for (std::size_t k = 0; k < iN; 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]; - } + Ainv(i,k) += f * w[k]; } - } - } - - m_cnt++; - - this->LE_compute_x(new_V); - const float_type 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> - unsigned matrix_solver_sm_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson) - { - this->build_LE_A(*this); - this->build_LE_RHS(*this); + m_cnt++; - this->m_stat_calculations++; - return this->solve_non_dynamic(newton_raphson); - } + 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; +} - 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) +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++) { + 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 c31aaa6d46a..eea692d6c47 100644 --- a/src/lib/netlist/solver/nld_ms_sor.h +++ b/src/lib/netlist/solver/nld_ms_sor.h @@ -12,42 +12,33 @@ #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 <typename FT, int SIZE> -class matrix_solver_SOR_t: public matrix_solver_direct_t<FT, SIZE> + { +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> { public: - 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) + 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) , 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) { } - void vsetup(analog_net_t::list_t &nets) override; - unsigned vsolve_non_dynamic(const bool newton_raphson) override; + 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; private: - 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; + state_var<nl_double> m_lp_fact; }; // ---------------------------------------------------------------------------------------- @@ -55,16 +46,16 @@ private: // ---------------------------------------------------------------------------------------- -template <typename FT, int SIZE> -void matrix_solver_SOR_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) +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) { - matrix_solver_direct_t<FT, SIZE>::vsetup(nets); + matrix_solver_direct_t<m_N, storage_N>::vsetup(nets); } -template <typename FT, int SIZE> -unsigned matrix_solver_SOR_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson) +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) { - const std::size_t iN = this->size(); + const std::size_t iN = this->N(); bool resched = false; unsigned resched_cnt = 0; @@ -76,21 +67,26 @@ unsigned matrix_solver_SOR_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_rap * omega = 2.0 / (1.0 + std::sqrt(1-rho)) */ - const float_type ws = this->m_params.m_gs_sor; + 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]; for (std::size_t k = 0; k < iN; k++) { - float_type gtot_t = 0.0; - float_type gabs_t = 0.0; - float_type RHS_t = 0.0; + nl_double gtot_t = 0.0; + nl_double gabs_t = 0.0; + nl_double RHS_t = 0.0; const std::size_t term_count = this->m_terms[k]->count(); - 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]; + 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(); - this->m_new_V[k] = this->m_nets[k]->Q_Analog(); + new_V[k] = this->m_nets[k]->Q_Analog(); for (std::size_t i = 0; i < term_count; i++) { @@ -99,60 +95,61 @@ unsigned matrix_solver_SOR_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_rap } 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 (this->m_params.m_use_gabs) + if (USE_GABS) { for (std::size_t i = 0; i < term_count; i++) gabs_t = gabs_t + std::abs(go[i]); - gabs_t *= plib::constants<nl_double>::cast(0.5); // derived by try and error + gabs_t *= NL_FCONST(0.5); // derived by try and error if (gabs_t <= gtot_t) { w[k] = ws / gtot_t; - one_m_w[k] = plib::constants<FT>::one() - ws; + one_m_w[k] = NL_FCONST(1.0) - ws; } else { - 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); + 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); } } else { w[k] = ws / gtot_t; - one_m_w[k] = plib::constants<FT>::one() - ws; + one_m_w[k] = NL_FCONST(1.0) - ws; } } - const float_type accuracy = this->m_params.m_accuracy; + const nl_double accuracy = this->m_params.m_accuracy; do { resched = false; - float_type err = 0; + nl_double err = 0; for (std::size_t k = 0; k < iN; k++) { - const int * net_other = this->m_terms[k]->m_connected_net_idx.data(); + const int * RESTRICT net_other = this->m_terms[k]->connected_net_idx(); const std::size_t railstart = this->m_terms[k]->m_railstart; - const float_type * go = this->m_gonn[k]; + const nl_double * RESTRICT go = this->m_terms[k]->go(); - float_type Idrive = 0.0; + nl_double Idrive = 0.0; for (std::size_t i = 0; i < railstart; i++) - Idrive = Idrive - go[i] * this->m_new_V[static_cast<std::size_t>(net_other[i])]; + Idrive = Idrive + go[i] * new_V[net_other[i]]; - const float_type new_val = this->m_new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k]; + const nl_double new_val = new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k]; - err = std::max(std::abs(new_val - this->m_new_V[k]), err); - this->m_new_V[k] = new_val; + err = std::max(std::abs(new_val - new_V[k]), err); + 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++; @@ -161,12 +158,13 @@ unsigned matrix_solver_SOR_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_rap { // Fallback to direct solver ... this->m_iterative_fail++; - return matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(newton_raphson); + return matrix_solver_direct_t<m_N, storage_N>::vsolve_non_dynamic(newton_raphson); } - 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; + for (std::size_t k = 0; k < iN; k++) + this->m_nets[k]->set_Q_Analog(new_V[k]); + + return resched_cnt; } } //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 83e4870cf28..50bcac1a52d 100644 --- a/src/lib/netlist/solver/nld_ms_sor_mat.h +++ b/src/lib/netlist/solver/nld_ms_sor_mat.h @@ -12,220 +12,212 @@ #ifndef NLD_MS_SOR_MAT_H_ #define NLD_MS_SOR_MAT_H_ -#include "nld_matrix_solver.h" +#include <algorithm> + #include "nld_ms_direct.h" +#include "nld_matrix_solver.h" #include "nld_solver.h" -#include <algorithm> - namespace netlist { -namespace devices -{ - - template <typename FT, int SIZE> - class matrix_solver_SOR_mat_t: public matrix_solver_direct_t<FT, SIZE> + namespace devices { - friend class matrix_solver_t; +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> +{ + friend class matrix_solver_t; - public: +public: - using float_type = FT; + 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) + { + } - 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 ~matrix_solver_SOR_mat_t() override {} - void vsetup(analog_net_t::list_t &nets) override; + virtual void vsetup(analog_net_t::list_t &nets) override; - unsigned vsolve_non_dynamic(const bool newton_raphson) override; + virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; - private: - //state_var<float_type[storage_N]> m_Vdelta; - state_var<std::vector<float_type>> m_Vdelta; +private: + state_var<nl_double[storage_N]> m_Vdelta; - state_var<float_type> m_omega; - state_var<float_type> m_lp_fact; + 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; +}; - }; +// ---------------------------------------------------------------------------------------- +// matrix_solver - Gauss - Seidel +// ---------------------------------------------------------------------------------------- - // ---------------------------------------------------------------------------------------- - // matrix_solver - Gauss - Seidel - // ---------------------------------------------------------------------------------------- +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); +} - template <typename FT, int SIZE> - void matrix_solver_SOR_mat_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) - { - matrix_solver_direct_t<FT, SIZE>::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 + */ - #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; - } + 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); + this->solve_base(this); - if (this->m_params->use_linear_prediction) + if (USE_LINEAR_PREDICTION) + { + 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++) { - 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); + 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; } - - return this->compute_next_timestep(); + // 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); } - #endif - template <typename FT, int SIZE> - unsigned matrix_solver_SOR_mat_t<FT, SIZE>::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. - */ + 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. + */ - const std::size_t iN = this->size(); - this->build_LE_A(*this); - this->build_LE_RHS(*this); + nl_double new_v[storage_N] = { 0.0 }; + const std::size_t iN = this->N(); - bool resched = false; + matrix_solver_t::build_LE_A<matrix_solver_SOR_mat_t>(); + matrix_solver_t::build_LE_RHS<matrix_solver_SOR_mat_t>(); - unsigned resched_cnt = 0; + bool resched = false; + unsigned resched_cnt = 0; - #if 0 - static int ws_cnt = 0; - ws_cnt++; - if (1 && ws_cnt % 200 == 0) + +#if 0 + static int ws_cnt = 0; + ws_cnt++; + if (1 && ws_cnt % 200 == 0) + { + // update omega + nl_double lambdaN = 0; + nl_double lambda1 = 1e9; + for (int k = 0; k < iN; k++) { - // 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); - } + #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)) ); + + //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(); + + do { + resched = false; + nl_double cerr = 0.0; 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) { - 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); + nl_double 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]) * 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 (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; + this->m_gs_total += 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; + if (resched) + { + this->m_iterative_fail++; + //this->netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS"); + this->m_gs_fail++; + 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 3372b50c7c5..0d4e7781eed 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 "nld_matrix_solver.h" -#include "nld_solver.h" -#include "plib/vector_ops.h" - #include <algorithm> +#include "nld_solver.h" +#include "nld_matrix_solver.h" +#include "vector_base.h" + 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 <typename FT, int SIZE> +template <std::size_t m_N, std::size_t storage_N> class matrix_solver_w_t: public matrix_solver_t { friend class matrix_solver_t; - public: - 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_w_t(netlist_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size); - matrix_solver_w_t(netlist_state_t &anetlist, const pstring &name, const solver_parameters_t *params, const std::size_t size); + virtual ~matrix_solver_w_t() override; - void vsetup(analog_net_t::list_t &nets) override; - void reset() override { matrix_solver_t::reset(); } + virtual void vsetup(analog_net_t::list_t &nets) override; + virtual void reset() override { matrix_solver_t::reset(); } protected: - unsigned vsolve_non_dynamic(const bool newton_raphson) override; + virtual unsigned vsolve_non_dynamic(const bool newton_raphson) override; unsigned solve_non_dynamic(const bool newton_raphson); - constexpr std::size_t size() const { return m_dim; } + 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 * x); + void LE_compute_x(T * RESTRICT x); template <typename T1, typename T2> - float_ext_type &A(const T1 &r, const T2 &c) { return m_A[r][c]; } + inline nl_ext_double &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]; } + inline nl_ext_double &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> - float_ext_type &Ainv(const T1 &r, const T2 &c) { return m_Ainv[c][r]; } + inline nl_ext_double &Ainv(const T1 &r, const T2 &c) { return m_Ainv[c][r]; } template <typename T1> - float_ext_type &RHS(const T1 &r) { return m_RHS[r]; } + inline nl_ext_double &RHS(const T1 &r) { return m_RHS[r]; } template <typename T1, typename T2> - float_ext_type &lA(const T1 &r, const T2 &c) { return m_lA[r][c]; } + inline nl_ext_double &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; - 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_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_lA[storage_N][m_pitch]; + nl_ext_double m_lA[storage_N][m_pitch]; /* temporary */ - float_type H[storage_N][m_pitch] ; + nl_double H[storage_N][m_pitch] ; unsigned rows[storage_N]; unsigned cols[storage_N][m_pitch]; unsigned colcount[storage_N]; unsigned m_cnt; - //float_ext_type m_RHSx[storage_N]; + //nl_ext_double m_RHSx[storage_N]; const std::size_t m_dim; @@ -123,22 +123,28 @@ private: // matrix_solver_direct // ---------------------------------------------------------------------------------------- -template <typename FT, int SIZE> -void matrix_solver_w_t<FT, SIZE>::vsetup(analog_net_t::list_t &nets) +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) { matrix_solver_t::setup_base(nets); - // 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)); + 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)); } -template <typename FT, int SIZE> -void matrix_solver_w_t<FT, SIZE>::LE_invert() +template <std::size_t m_N, std::size_t storage_N> +void matrix_solver_w_t<m_N, storage_N>::LE_invert() { - const std::size_t kN = size(); + const std::size_t kN = N(); for (std::size_t i = 0; i < kN; i++) { @@ -153,18 +159,18 @@ void matrix_solver_w_t<FT, SIZE>::LE_invert() for (std::size_t i = 0; i < kN; i++) { /* FIXME: Singular matrix? */ - const float_type f = 1.0 / W(i,i); - const auto * const p = m_terms[i]->m_nzrd.data(); + const nl_double f = 1.0 / W(i,i); + const auto * RESTRICT 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 * const pb = m_terms[i]->m_nzbd.data(); + const auto * RESTRICT 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 float_type f1 = - W(j,i) * f; + const nl_double f1 = - W(j,i) * f; if (f1 != 0.0) { for (std::size_t k = 0; k < e; k++) @@ -178,10 +184,10 @@ void matrix_solver_w_t<FT, SIZE>::LE_invert() for (std::size_t i = kN; i-- > 0; ) { /* FIXME: Singular matrix? */ - const float_type f = 1.0 / W(i,i); + const nl_double f = 1.0 / W(i,i); for (std::size_t j = i; j-- > 0; ) { - const float_type f1 = - W(j,i) * f; + const nl_double f1 = - W(j,i) * f; if (f1 != 0.0) { for (std::size_t k = i; k < kN; k++) @@ -197,19 +203,19 @@ void matrix_solver_w_t<FT, SIZE>::LE_invert() } } -template <typename FT, int SIZE> +template <std::size_t m_N, std::size_t storage_N> template <typename T> -void matrix_solver_w_t<FT, SIZE>::LE_compute_x( - T * x) +void matrix_solver_w_t<m_N, storage_N>::LE_compute_x( + T * RESTRICT x) { - const std::size_t kN = size(); + 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++) { - const float_type f = RHS(k); + const nl_double f = RHS(k); for (std::size_t i=0; i<kN; i++) x[i] += Ainv(i,k) * f; @@ -217,14 +223,14 @@ void matrix_solver_w_t<FT, SIZE>::LE_compute_x( } -template <typename FT, int SIZE> -unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphson) +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) { - const auto iN = size(); + const auto iN = N(); - float_type new_V[storage_N]; // = { 0.0 }; + nl_double new_V[storage_N]; // = { 0.0 }; - if ((m_cnt % 50) == 0) + if ((m_cnt % 100) == 0) { /* complete calculation */ this->LE_invert(); @@ -260,7 +266,7 @@ unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphso /* construct w = transform(V) * y * dim: rowcount x iN * */ - float_type w[storage_N]; + nl_double w[storage_N]; for (unsigned i = 0; i < rowcount; i++) { const unsigned r = rows[i]; @@ -281,7 +287,7 @@ unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphso for (unsigned k=0; k< colcount[i]; k++) { const unsigned col = cols[i][k]; - float_type f = VT(rows[i],col); + nl_double f = VT(rows[i],col); if (f!=0.0) for (unsigned j= 0; j < rowcount; j++) H[i][j] += f * Ainv(col,rows[j]); @@ -291,16 +297,16 @@ unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphso for (unsigned i = 0; i < rowcount; i++) { if (H[i][i] == 0.0) - plib::perrlogger("{} H singular\n", this->name()); - const float_type f = 1.0 / H[i][i]; + printf("%s H singular\n", this->name().c_str()); + const nl_double f = 1.0 / H[i][i]; for (unsigned j = i+1; j < rowcount; j++) { - const float_type f1 = - f * H[j][i]; + const nl_double f1 = - f * H[j][i]; if (f1!=0.0) { - float_type *pj = &H[j][i+1]; - const float_type *pi = &H[i][i+1]; + nl_double *pj = &H[j][i+1]; + const nl_double *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]; @@ -310,12 +316,12 @@ unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphso } /* Back substitution */ //inv(H) w = t w = H t - float_type t[storage_N]; // FIXME: convert to member + nl_double t[storage_N]; // FIXME: convert to member for (unsigned j = rowcount; j-- > 0; ) { - float_type tmp = 0; - const float_type *pj = &H[j][j+1]; - const float_type *tj = &t[j+1]; + nl_double tmp = 0; + const nl_double *pj = &H[j][j+1]; + const nl_double *tj = &t[j+1]; for (unsigned k = 0; k < rowcount-j-1; k++) tmp += pj[k] * tj[k]; //tmp += H[j][k] * t[k]; @@ -325,7 +331,7 @@ unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphso /* x = y - Zt */ for (unsigned i=0; i<iN; i++) { - float_type tmp = 0.0; + nl_double tmp = 0.0; for (unsigned j=0; j<rowcount;j++) { const unsigned row = rows[j]; @@ -337,40 +343,47 @@ unsigned matrix_solver_w_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphso } m_cnt++; - if (false) + if (0) for (unsigned i=0; i<iN; i++) { - float_type tmp = 0.0; + nl_double 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) - plib::perrlogger("{} failed on row {}: {} RHS: {}\n", this->name(), i, std::abs(tmp-RHS(i)), RHS(i)); + printf("%s failed on row %d: %f RHS: %f\n", this->name().c_str(), i, std::abs(tmp-RHS(i)), RHS(i)); } - const float_type err = (newton_raphson ? delta(new_V) : 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; } -template <typename FT, int SIZE> -unsigned matrix_solver_w_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson) +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) { - this->build_LE_A(*this); - this->build_LE_RHS(*this); + 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->m_stat_calculations++; return this->solve_non_dynamic(newton_raphson); } -template <typename FT, int SIZE> -matrix_solver_w_t<FT, SIZE>::matrix_solver_w_t(netlist_state_t &anetlist, const pstring &name, +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, 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 4734cc3624d..cae76caab1a 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -31,398 +31,393 @@ #pragma GCC optimize "ivopts" #endif -#include "netlist/nl_lists.h" -#include "netlist/nl_factory.h" +#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 "nld_matrix_solver.h" + +#if 1 #include "nld_ms_direct.h" -#include "nld_ms_direct1.h" -#include "nld_ms_direct2.h" #include "nld_ms_gcr.h" -#include "nld_ms_gmres.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_sor.h" #include "nld_ms_sor_mat.h" -#include "nld_ms_w.h" -#include "nld_solver.h" -#include "plib/pomp.h" - -#include <algorithm> -#include <cmath> +#include "nld_ms_gmres.h" namespace netlist { -namespace devices -{ + namespace devices + { - // ---------------------------------------------------------------------------------------- - // solver - // ---------------------------------------------------------------------------------------- - NETLIB_RESET(solver) - { - for (auto &s : m_mat_solvers) - s->reset(); - } - void NETLIB_NAME(solver)::stop() - { - for (auto &s : m_mat_solvers) - s->log_stats(); - } +// ---------------------------------------------------------------------------------------- +// solver +// ---------------------------------------------------------------------------------------- - NETLIB_UPDATE(solver) - { - if (m_params.m_dynamic_ts) - return; +NETLIB_RESET(solver) +{ + for (std::size_t i = 0; i < m_mat_solvers.size(); i++) + m_mat_solvers[i]->do_reset(); +} - 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)); +void NETLIB_NAME(solver)::stop() +{ + for (std::size_t i = 0; i < m_mat_solvers.size(); i++) + m_mat_solvers[i]->log_stats(); +} - std::size_t nthreads = std::min(static_cast<std::size_t>(m_parallel()), plib::omp::get_max_threads()); +NETLIB_NAME(solver)::~NETLIB_NAME(solver)() +{ +} - std::vector<matrix_solver_t *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_timestepping); +NETLIB_UPDATE(solver) +{ + if (m_params.m_dynamic_ts) + return; - 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); - } + /* 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)); - for (auto & solver : solvers) - solver->update_inputs(); + 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; - /* 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)); - } + 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(); + + for (auto & solver : m_mat_solvers) + if (solver->has_timestep_devices() || force_solve) + solver->update_inputs(); - 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) + /* step circuit */ + if (!m_Q_step.net().is_queued()) { - return pool().make_poolptr<C>(nl, name, ¶ms, size); + m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_double(m_params.m_max_timestep)); } +} - template <typename FT, int SIZE> - pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver(std::size_t size, const pstring &solvername) +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())) { - 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") - { - /* 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 - { - log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method()); - return pool_owned_ptr<matrix_solver_t>(); - } + 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); } - - template <typename FT, int SIZE> - pool_owned_ptr<matrix_solver_t> NETLIB_NAME(solver)::create_solver_x(std::size_t size, const pstring &solvername) + else if (pstring("MAT_CR").equals(m_method())) { - if (SIZE > 0) + if (size > 0) // GCR always outperforms MAT solver { - if (size == SIZE) - return create_solver<FT, SIZE>(size, solvername); - else - return this->create_solver_x<FT, SIZE-1>(size, solvername); + typedef matrix_solver_GCR_t<m_N,storage_N> solver_mat; + return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); } else { - if (size * 2 > -SIZE ) - return create_solver<FT, SIZE>(size, solvername); - else - return this->create_solver_x<FT, SIZE / 2>(size, solvername); + typedef matrix_solver_direct_t<m_N,storage_N> solver_mat; + return plib::make_unique<solver_mat>(netlist(), solvername, &m_params, size); } } - - struct net_splitter + 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 + { + log().fatal(MF_1_UNKNOWN_SOLVER_TYPE, m_method()); + return nullptr; + } +} - bool already_processed(const analog_net_t &n) const - { - /* no need to process rail nets - these are known variables */ - if (n.isRailNet()) +struct net_splitter +{ + + bool already_processed(analog_net_t *n) + { + if (n->isRailNet()) + return true; + for (auto & grp : groups) + if (plib::container::contains(grp, n)) return true; - /* if it's already processed - no need to continue */ - for (auto & grp : groups) - if (plib::container::contains(grp, &n)) - return true; - return false; - } + return false; + } - void process_net(analog_net_t &n) + 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) { - /* 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()) + if (p->is_type(detail::terminal_type::TERMINAL)) { - /* 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); - } + 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); } } + } - void run(netlist_state_t &netlist) + void run(netlist_t &netlist) + { + for (auto & net : netlist.m_nets) { - for (auto & net : netlist.nets()) + netlist.log().debug("processing {1}\n", net->name()); + if (!net->isRailNet() && net->num_cons() > 0) { - netlist.log().debug("processing {1}\n", net->name()); - if (!net->isRailNet() && net->num_cons() > 0) + 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(" ==> 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); - } + groups.push_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() +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) { - 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_use_gabs = m_use_gabs(); - m_params.m_use_linear_prediction = m_use_linear_prediction(); - + m_params.m_max_timestep *= 1;//NL_FCONST(1000.0); + } + else + { + m_params.m_min_timestep = m_params.m_max_timestep; + } - 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; - } + //m_params.m_max_timestep = std::max(m_params.m_max_timestep, m_params.m_max_timestep::) - //m_params.m_max_timestep = std::max(m_params.m_max_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(); - // 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(); + log().verbose("Scanning net groups ..."); + // determine net groups - log().verbose("Scanning net groups ..."); - // determine net groups + net_splitter splitter; - net_splitter splitter; + splitter.run(netlist()); - splitter.run(state()); + // 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()); - // setup the solvers - log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size()); - for (auto & grp : splitter.groups) + switch (net_count) { - pool_owned_ptr<matrix_solver_t> ms; - std::size_t net_count = grp.size(); - pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size()); +#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 */ + } - 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; - } + 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("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("Net {1}", n->name()); - for (const auto &pcore : n->core_terms()) - { - log().verbose(" {1}", pcore->name()); - } + log().verbose(" {1}", pcore->name()); } - - 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)); } + + m_mat_solvers.push_back(std::move(ms)); } +} - void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp) +void NETLIB_NAME(solver)::create_solver_code(std::map<pstring, pstring> &mp) +{ + for (auto & s : m_mat_solvers) { - for (auto & s : m_mat_solvers) - { - auto r = s->create_solver_code(); - mp[r.first] = r.second; // automatically overwrites identical names - } + auto r = s->create_solver_code(); + mp[r.first] = r.second; // automatically overwrites identical names } +} - NETLIB_DEVICE_IMPL(solver, "SOLVER", "FREQ") + NETLIB_DEVICE_IMPL(solver) -} // 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 c9ec967a72a..986d14f401a 100644 --- a/src/lib/netlist/solver/nld_solver.h +++ b/src/lib/netlist/solver/nld_solver.h @@ -8,13 +8,11 @@ #ifndef NLD_SOLVER_H_ #define NLD_SOLVER_H_ -#include "netlist/nl_base.h" -#include "nld_matrix_solver.h" -#include "plib/pstream.h" - #include <map> -#include <memory> -#include <vector> + +#include "../nl_base.h" +#include "../plib/pstream.h" +#include "nld_matrix_solver.h" //#define ATTR_ALIGNED(N) __attribute__((aligned(N))) #define ATTR_ALIGNED(N) ATTR_ALIGN @@ -25,97 +23,89 @@ namespace netlist { -namespace devices -{ - class NETLIB_NAME(solver); + namespace devices + { +class NETLIB_NAME(solver); - class matrix_solver_t; - NETLIB_OBJECT(solver) +class matrix_solver_t; + +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", 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() { - 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 + // internal staff + + connect(m_fb_step, m_Q_step); + } + + virtual ~NETLIB_NAME(solver)() override; + + void post_start(); + void stop(); + + 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 } // namespace netlist #endif /* NLD_SOLVER_H_ */ diff --git a/src/lib/netlist/solver/vector_base.h b/src/lib/netlist/solver/vector_base.h new file mode 100644 index 00000000000..28f5fa0dd44 --- /dev/null +++ b/src/lib/netlist/solver/vector_base.h @@ -0,0 +1,144 @@ +// 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 0acf5041c91..bedddba3cda 100644 --- a/src/lib/netlist/tools/nl_convert.cpp +++ b/src/lib/netlist/tools/nl_convert.cpp @@ -5,20 +5,19 @@ * */ -#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 char * s_lib_map = +static const pstring s_lib_map = "SN74LS00D, TTL_7400_DIP, 74LSXX\n" "SN74LS04D, TTL_7404_DIP, 74LSXX\n" "SN74ALS08D, TTL_7408_DIP, 74ALSXX\n" @@ -43,13 +42,14 @@ using lib_map_t = std::unordered_map<pstring, lib_map_entry>; static lib_map_t read_lib_map(const pstring &lm) { - auto reader = plib::putf8_reader(plib::pistringstream(lm)); + plib::pistringstream istrm(lm); + plib::putf8_reader reader(istrm); lib_map_t m; pstring line; while (reader.readline(line)) { std::vector<pstring> split(plib::psplit(line, ",")); - m[plib::trim(split[0])] = { plib::trim(split[1]), plib::trim(split[2]) }; + m[split[0].trim()] = { split[1].trim(), split[2].trim() }; } 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(plib::unique_ptr<dev_t> dev) +void nl_convert_base_t::add_device(std::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(const pstring &netname, const pstring &termname) +void nl_convert_base_t::add_term(pstring netname, pstring termname) { net_t * net = nullptr; auto idx = m_nets.find(netname); @@ -130,11 +130,11 @@ void nl_convert_base_t::add_term(const pstring &netname, const pstring &termname void nl_convert_base_t::dump_nl() { - for (auto & alias : m_ext_alias) + for (std::size_t i=0; i<m_ext_alias.size(); i++) { - net_t *net = m_nets[alias].get(); + net_t *net = m_nets[m_ext_alias[i]].get(); // use the first terminal ... - out("ALIAS({}, {})\n", alias.c_str(), net->terminals()[0].c_str()); + out("ALIAS({}, {})\n", m_ext_alias[i].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,6 +166,7 @@ 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++) { @@ -184,25 +185,25 @@ const pstring nl_convert_base_t::get_nl_val(const double val) { { int i = 0; - while (pstring(m_units[i].m_unit) != "-" ) + while (pstring(m_units[i].m_unit, pstring::UTF8) != "-" ) { if (m_units[i].m_mult <= std::abs(val)) break; i++; } - return plib::pfmt(pstring(m_units[i].m_func))(val / m_units[i].m_mult); + return plib::pfmt(pstring(m_units[i].m_func, pstring::UTF8))(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) != "-") + while (pstring(m_units[i].m_unit, pstring::UTF8) != "-") { - if (pstring(m_units[i].m_unit) == unit) + if (pstring(m_units[i].m_unit, pstring::UTF8) == unit) return m_units[i].m_mult; i++; } - plib::perrlogger("Unit {} unknown\n", unit); + fprintf(stderr, "Unit %s unknown\n", unit.c_str()); return 0.0; } @@ -211,9 +212,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 = plib::left(sin, p); + pstring val = sin.left(p); pstring unit = sin.substr(p); - double ret = get_sp_unit(unit) * plib::pstonum<double>(val); + double ret = get_sp_unit(unit) * val.as_double(); return ret; } @@ -251,11 +252,11 @@ void nl_convert_spice_t::convert(const pstring &contents) pstring line = ""; - for (const auto &i : spnl) + for (std::size_t i=0; i < spnl.size(); i++) { // Basic preprocessing - pstring inl = plib::ucase(plib::trim(i)); - if (plib::startsWith(inl, "+")) + pstring inl = spnl[i].trim().ucase(); + if (inl.startsWith("+")) line = line + inl.substr(1); else { @@ -284,13 +285,13 @@ void nl_convert_spice_t::process_line(const pstring &line) out("// {}\n", line.substr(1).c_str()); break; case '.': - if (tt[0] == ".SUBCKT") + if (tt[0].equals(".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] == ".ENDS") + else if (tt[0].equals(".ENDS")) { dump_nl(); out("NETLIST_END()\n"); @@ -300,16 +301,15 @@ 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 ((err || plib::startsWith(tt[4], "N")) && tt.size() > 5) + if ((!cerr || tt[4].startsWith("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) - plib::perrlogger("error with model desc {}\n", model); - pins = plib::left(m[1], 3); + fprintf(stderr, "error with model desc %s\n", model.c_str()); + pins = m[1].left(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 (plib::startsWith(tt[0], "RV")) + if (tt[0].startsWith("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] == "0") + if (tt[2].equals("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 - plib::perrlogger("Voltage Source {} not connected to GND\n", tt[0]); + fprintf(stderr, "Voltage Source %s not connected to GND\n", tt[0].c_str()); 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 = plib::replace_all(tt[0], pstring("."), pstring("_")); + pstring xname = tt[0].replace_all(".", "_"); 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(std::move(strm)) +nl_convert_eagle_t::tokenizer::tokenizer(nl_convert_eagle_t &convert, plib::putf8_reader &strm) + : plib::ptokenizer(strm) , m_convert(convert) { - 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('\''); + 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('\''); m_tok_ADD = register_token("ADD"); m_tok_VALUE = register_token("VALUE"); m_tok_SIGNAL = register_token("SIGNAL"); @@ -428,8 +428,9 @@ 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) { - - tokenizer tok(*this, plib::putf8_reader(plib::pistringstream(contents))); + plib::pistringstream istrm(contents); + plib::putf8_reader reader(istrm); + tokenizer tok(*this, reader); out("NETLIST_START(dummy)\n"); add_term("GND", "GND"); @@ -486,12 +487,12 @@ void nl_convert_eagle_t::convert(const pstring &contents) } break; case 'P': - if (plib::ucase(sval) == "HIGH") + if (sval.ucase() == "HIGH") add_device("TTL_INPUT", name, 1); - else if (plib::ucase(sval) == "LOW") + else if (sval.ucase() == "LOW") add_device("TTL_INPUT", name, 0); else - add_device("ANALOG_INPUT", name, plib::pstonum<double>(sval)); + add_device("ANALOG_INPUT", name, sval.as_double()); add_pin_alias(name, "1", "Q"); break; case 'D': @@ -537,16 +538,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(std::move(strm)) +nl_convert_rinf_t::tokenizer::tokenizer(nl_convert_rinf_t &convert, plib::putf8_reader &strm) + : plib::ptokenizer(strm) , m_convert(convert) { - 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('"'); + 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('"'); m_tok_HEA = register_token(".HEA"); m_tok_APP = register_token(".APP"); m_tok_TIM = register_token(".TIM"); @@ -576,7 +577,9 @@ void nl_convert_rinf_t::tokenizer::verror(const pstring &msg, int line_num, cons void nl_convert_rinf_t::convert(const pstring &contents) { - tokenizer tok(*this, plib::putf8_reader(plib::pistringstream(contents))); + plib::pistringstream istrm(contents); + plib::putf8_reader reader(istrm); + tokenizer tok(*this, reader); 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 5cdae8e372d..d3881320678 100644 --- a/src/lib/netlist/tools/nl_convert.h +++ b/src/lib/netlist/tools/nl_convert.h @@ -10,12 +10,10 @@ #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 @@ -25,8 +23,6 @@ class nl_convert_base_t { public: - COPYASSIGNMOVE(nl_convert_base_t, delete) - virtual ~nl_convert_base_t(); const pstring &result() { return m_buf.str(); } @@ -44,7 +40,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(const pstring &netname, const pstring &termname); + void add_term(pstring netname, pstring termname); void dump_nl(); @@ -59,8 +55,8 @@ private: struct net_t { public: - explicit net_t(pstring aname) - : m_name(std::move(aname)), m_no_export(false) {} + explicit net_t(const pstring &aname) + : m_name(aname), m_no_export(false) {} const pstring &name() { return m_name;} std::vector<pstring> &terminals() { return m_terminals; } @@ -76,28 +72,16 @@ private: struct dev_t { public: - 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, 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, 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, double aval) + : m_type(atype), m_name(aname), m_model(""), m_val(aval), m_has_val(true) {} - 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) + dev_t(const pstring &atype, const pstring &aname) + : m_type(atype), m_name(aname), m_model(""), m_val(0.0), m_has_val(false) {} const pstring &name() { return m_name;} @@ -125,8 +109,8 @@ private: struct pin_alias_t { public: - pin_alias_t(pstring name, pstring alias) - : m_name(std::move(name)), m_alias(std::move(alias)) + pin_alias_t(const pstring &name, const pstring &alias) + : m_name(name), m_alias(alias) {} const pstring &name() { return m_name; } const pstring &alias() { return m_alias; } @@ -137,14 +121,14 @@ private: private: - void add_device(plib::unique_ptr<dev_t> dev); + void add_device(std::unique_ptr<dev_t> dev); plib::postringstream m_buf; - std::vector<plib::unique_ptr<dev_t>> m_devs; - std::unordered_map<pstring, plib::unique_ptr<net_t> > m_nets; + std::vector<std::unique_ptr<dev_t>> m_devs; + std::unordered_map<pstring, std::unique_ptr<net_t> > m_nets; std::vector<pstring> m_ext_alias; - std::unordered_map<pstring, plib::unique_ptr<pin_alias_t>> m_pins; + std::unordered_map<pstring, std::unique_ptr<pin_alias_t>> m_pins; static unit_t m_units[]; pstring m_numberchars; @@ -156,6 +140,9 @@ 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; @@ -172,11 +159,14 @@ 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; @@ -185,7 +175,7 @@ public: protected: - void verror(const pstring &msg, int line_num, const pstring &line) override; + virtual void verror(const pstring &msg, int line_num, const pstring &line) override; private: nl_convert_eagle_t &m_convert; @@ -205,11 +195,14 @@ 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; @@ -223,7 +216,7 @@ public: protected: - void verror(const pstring &msg, int line_num, const pstring &line) override; + virtual void verror(const pstring &msg, int line_num, const pstring &line) override; private: nl_convert_rinf_t &m_convert; |