mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
netlist: fix bug, prepare for future changes and improve readability (#9947)
* netlist: fix bug, prepare for future changes and improve readability - fix a bug where a net processing error may trigger a nullptr access - applied some clang-tidy recommendations - add no_return to plib::terminate - properly encapsulate dynamic_cast usage - more review of noexcept - added a clang-format file. Over time, all source files will be processed with clang-format - Used clang format on a number of files - Rewrote 74174 - all device constructors now use a struct to pass data on to base classes. Neither netlist state nor the name are intended to be used in a constructor. After the base class was constructed, they can be accessed by state() and name(). - The device construction macros can now be removed. Changes to the core will not need to be reflected in constructors. - Change truth table macros so that going forward NETLIST_END and TRUTH_TABLE_END can be replaced by a closing curly brace. netlists can than use curly braces enclosed blocks. - more clang-format - removed some macros completely - all derived classes from base_device_t now don't use macros any longer. - as a result, delegator_t was removed. This class was only used to support macros :-(
This commit is contained in:
parent
3fbfe0b1d7
commit
0dad442511
@ -1252,6 +1252,16 @@ uint64_t netlist_mame_cpu_device::execute_cycles_to_clocks(uint64_t cycles) cons
|
||||
return cycles;
|
||||
}
|
||||
|
||||
netlist::netlist_time_ext netlist_mame_cpu_device::nltime_ext_from_clocks(unsigned c) const noexcept
|
||||
{
|
||||
return (m_div * c).shr(MDIV_SHIFT);
|
||||
}
|
||||
|
||||
netlist::netlist_time netlist_mame_cpu_device::nltime_from_clocks(unsigned c) const noexcept
|
||||
{
|
||||
return static_cast<netlist::netlist_time>((m_div * c).shr(MDIV_SHIFT));
|
||||
}
|
||||
|
||||
void netlist_mame_cpu_device::execute_run()
|
||||
{
|
||||
//m_ppc = m_pc; // copy PC to previous PC
|
||||
|
@ -193,16 +193,6 @@ public:
|
||||
void update_icount(netlist::netlist_time_ext time) noexcept;
|
||||
void check_mame_abort_slice() noexcept;
|
||||
|
||||
netlist::netlist_time_ext nltime_ext_from_clocks(unsigned c) const noexcept
|
||||
{
|
||||
return (m_div * c).shr(MDIV_SHIFT);
|
||||
}
|
||||
|
||||
netlist::netlist_time nltime_from_clocks(unsigned c) const noexcept
|
||||
{
|
||||
return static_cast<netlist::netlist_time>((m_div * c).shr(MDIV_SHIFT));
|
||||
}
|
||||
|
||||
protected:
|
||||
// netlist_mame_device
|
||||
virtual void nl_register_devices(netlist::nlparse_t &parser) const override;
|
||||
@ -229,6 +219,9 @@ protected:
|
||||
address_space_config m_program_config;
|
||||
|
||||
private:
|
||||
netlist::netlist_time_ext nltime_ext_from_clocks(unsigned c) const noexcept;
|
||||
netlist::netlist_time nltime_from_clocks(unsigned c) const noexcept;
|
||||
|
||||
int m_icount;
|
||||
netlist::netlist_time_ext m_div;
|
||||
netlist::netlist_time_ext m_rem;
|
||||
@ -255,6 +248,8 @@ private:
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// netlist_mame_sound_input_buffer
|
||||
//
|
||||
// This is a wrapper device to provide operator[] on read_stream_view.
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
class netlist_mame_sound_input_buffer : public read_stream_view
|
||||
|
@ -19,9 +19,14 @@
|
||||
#include "render.h"
|
||||
#include "ui/uimain.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
// for quick and dirty debugging
|
||||
#define VERBOSE 0
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
|
||||
#define LOG_OUTPUT_STREAM std::cerr
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -130,32 +130,6 @@ namespace analog
|
||||
|
||||
};
|
||||
|
||||
// Have a common start for transistors
|
||||
|
||||
NETLIB_BASE_OBJECT(QBJT)
|
||||
{
|
||||
public:
|
||||
|
||||
NETLIB_CONSTRUCTOR_EX(QBJT, const pstring &model = "NPN")
|
||||
, m_model(*this, "MODEL", model)
|
||||
, m_qtype(bjt_type::BJT_NPN)
|
||||
{
|
||||
}
|
||||
|
||||
NETLIB_IS_DYNAMIC(true)
|
||||
|
||||
//NETLIB_RESETI();
|
||||
|
||||
bjt_type qtype() const noexcept { return m_qtype; }
|
||||
bool is_qtype(bjt_type atype) const noexcept { return m_qtype == atype; }
|
||||
void set_qtype(bjt_type atype) noexcept { m_qtype = atype; }
|
||||
protected:
|
||||
|
||||
param_model_t m_model;
|
||||
private:
|
||||
bjt_type m_qtype;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// nld_QBJT_switch
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -174,9 +148,12 @@ namespace analog
|
||||
// E
|
||||
//
|
||||
|
||||
NETLIB_OBJECT_DERIVED(QBJT_switch, QBJT)
|
||||
class nld_QBJT_switch : public base_device_t
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(QBJT_switch)
|
||||
public: \
|
||||
nld_QBJT_switch(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_model(*this, "MODEL", "NPN")
|
||||
, m_bjt_model(m_model)
|
||||
, m_RB(*this, "m_RB", NETLIB_DELEGATE(terminal_handler))
|
||||
, m_RC(*this, "m_RC", NETLIB_DELEGATE(terminal_handler))
|
||||
@ -205,14 +182,17 @@ namespace analog
|
||||
m_RC.solver()->solve_now();
|
||||
}
|
||||
|
||||
NETLIB_IS_DYNAMIC(true)
|
||||
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
NETLIB_UPDATE_TERMINALSI();
|
||||
|
||||
private:
|
||||
param_model_t m_model;
|
||||
bjt_model_t m_bjt_model;
|
||||
nld_two_terminal m_RB;
|
||||
nld_two_terminal m_RC;
|
||||
nld_two_terminal m_BC;
|
||||
NETLIB_NAME(two_terminal) m_RB;
|
||||
NETLIB_NAME(two_terminal) m_RC;
|
||||
NETLIB_NAME(two_terminal) m_BC;
|
||||
|
||||
nl_fptype m_gB; // base conductance / switch on
|
||||
nl_fptype m_gC; // collector conductance / switch on
|
||||
@ -226,10 +206,12 @@ namespace analog
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
NETLIB_OBJECT_DERIVED(QBJT_EB, QBJT)
|
||||
class nld_QBJT_EB : public base_device_t
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(QBJT_EB)
|
||||
public: \
|
||||
nld_QBJT_EB(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_model(*this, "MODEL", "NPN")
|
||||
, m_bjt_model(m_model)
|
||||
, m_gD_BC(*this, "m_D_BC")
|
||||
, m_gD_BE(*this, "m_D_BE")
|
||||
@ -275,17 +257,20 @@ namespace analog
|
||||
m_D_CB.solver()->solve_now();
|
||||
}
|
||||
|
||||
NETLIB_IS_DYNAMIC(true)
|
||||
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
NETLIB_UPDATE_TERMINALSI();
|
||||
|
||||
private:
|
||||
param_model_t m_model;
|
||||
bjt_model_t m_bjt_model;
|
||||
generic_diode<diode_e::BIPOLAR> m_gD_BC;
|
||||
generic_diode<diode_e::BIPOLAR> m_gD_BE;
|
||||
|
||||
nld_two_terminal m_D_CB; // gcc, gce - gcc, gec - gcc, gcc - gce | Ic
|
||||
nld_two_terminal m_D_EB; // gee, gec - gee, gce - gee, gee - gec | Ie
|
||||
nld_two_terminal m_D_EC; // 0, -gec, -gcc, 0 | 0
|
||||
NETLIB_NAME(two_terminal) m_D_CB; // gcc, gce - gcc, gec - gcc, gcc - gce | Ic
|
||||
NETLIB_NAME(two_terminal) m_D_EB; // gee, gec - gee, gce - gee, gee - gec | Ie
|
||||
NETLIB_NAME(two_terminal) m_D_EC; // 0, -gec, -gcc, 0 | 0
|
||||
|
||||
nl_fptype m_alpha_f;
|
||||
nl_fptype m_alpha_r;
|
||||
@ -304,8 +289,8 @@ namespace analog
|
||||
{
|
||||
if (m_RB.solver() == nullptr && m_RC.solver() == nullptr)
|
||||
throw nl_exception(MF_DEVICE_FRY_1(this->name()));
|
||||
NETLIB_NAME(QBJT)::reset();
|
||||
const auto zero(nlconst::zero());
|
||||
|
||||
static constexpr const auto zero(nlconst::zero());
|
||||
|
||||
m_state_on = 0;
|
||||
|
||||
@ -323,9 +308,6 @@ namespace analog
|
||||
nl_fptype NF = m_bjt_model.m_NF;
|
||||
//nl_fptype VJE = m_bjt_model.dValue("VJE", 0.75);
|
||||
|
||||
// FIXME: check for PNP as well and bail out
|
||||
set_qtype(m_bjt_model.m_type);
|
||||
|
||||
nl_fptype alpha = BF / (nlconst::one() + BF);
|
||||
|
||||
diode d(IS, NF);
|
||||
@ -349,7 +331,7 @@ namespace analog
|
||||
|
||||
NETLIB_UPDATE_TERMINALS(QBJT_switch)
|
||||
{
|
||||
const nl_fptype m = (is_qtype( bjt_type::BJT_NPN) ? 1 : -1);
|
||||
const nl_fptype m = (m_bjt_model.m_type == bjt_type::BJT_NPN) ? nlconst::one() : -nlconst::one();
|
||||
|
||||
const unsigned new_state = (m_RB.deltaV() * m > m_V ) ? 1 : 0;
|
||||
if (m_state_on ^ new_state)
|
||||
@ -374,7 +356,7 @@ namespace analog
|
||||
{
|
||||
if (m_D_EB.solver() == nullptr && m_D_CB.solver() == nullptr)
|
||||
throw nl_exception(MF_DEVICE_FRY_1(this->name()));
|
||||
NETLIB_NAME(QBJT)::reset();
|
||||
|
||||
if (m_CJE)
|
||||
{
|
||||
m_CJE->reset();
|
||||
@ -389,7 +371,7 @@ namespace analog
|
||||
|
||||
NETLIB_UPDATE_TERMINALS(QBJT_EB)
|
||||
{
|
||||
const nl_fptype polarity(qtype() == bjt_type::BJT_NPN ? nlconst::one() : -nlconst::one());
|
||||
const nl_fptype polarity(m_bjt_model.m_type == bjt_type::BJT_NPN ? nlconst::one() : -nlconst::one());
|
||||
|
||||
m_gD_BE.update_diode(-m_D_EB.deltaV() * polarity);
|
||||
m_gD_BC.update_diode(-m_D_CB.deltaV() * polarity);
|
||||
@ -422,9 +404,6 @@ namespace analog
|
||||
nl_fptype NR = m_bjt_model.m_NR;
|
||||
//nl_fptype VJE = m_m_bjt_model.dValue("VJE", 0.75);
|
||||
|
||||
// FIXME: check for PNP as well and bail out
|
||||
set_qtype(m_bjt_model.m_type);
|
||||
|
||||
m_alpha_f = BF / (nlconst::one() + BF);
|
||||
m_alpha_r = BR / (nlconst::one() + BR);
|
||||
|
||||
|
@ -149,44 +149,17 @@ namespace analog
|
||||
param_model_t::value_base_t<int> m_CAPMOD; //!< Capacitance model (0=no model 2=Meyer)
|
||||
};
|
||||
|
||||
// Have a common start for mosfets
|
||||
// -----------------------------------------------------------------------------
|
||||
// nld_MOSFET
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NETLIB_BASE_OBJECT(FET)
|
||||
class nld_MOSFET : public base_device_t
|
||||
{
|
||||
public:
|
||||
enum q_type {
|
||||
FET_NMOS,
|
||||
FET_PMOS
|
||||
};
|
||||
|
||||
NETLIB_CONSTRUCTOR(FET)
|
||||
public: \
|
||||
nld_MOSFET(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_model(*this, "MODEL", "NMOS")
|
||||
, m_qtype(FET_NMOS)
|
||||
{
|
||||
}
|
||||
|
||||
NETLIB_IS_DYNAMIC(true)
|
||||
|
||||
//NETLIB_RESETI();
|
||||
|
||||
q_type qtype() const noexcept { return m_qtype; }
|
||||
bool is_qtype(q_type atype) const noexcept { return m_qtype == atype; }
|
||||
void set_qtype(q_type atype) noexcept { m_qtype = atype; }
|
||||
protected:
|
||||
|
||||
param_model_t m_model;
|
||||
private:
|
||||
q_type m_qtype;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// nld_QBJT_EB
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(MOSFET, FET)
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(MOSFET)
|
||||
, m_DG(*this, "m_DG", NETLIB_DELEGATE(terminal_handler))
|
||||
, m_SG(*this, "m_SG", NETLIB_DELEGATE(terminal_handler))
|
||||
, m_SD(*this, "m_SD", NETLIB_DELEGATE(terminal_handler))
|
||||
@ -204,7 +177,7 @@ namespace analog
|
||||
, m_lambda(nlconst::zero())
|
||||
, m_Leff(nlconst::zero())
|
||||
, m_CoxWL(nlconst::zero())
|
||||
, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
|
||||
//S, m_polarity(qtype() == FET_NMOS ? nlconst::one() : -nlconst::one())
|
||||
, m_Cgb(nlconst::zero())
|
||||
, m_Cgs(nlconst::zero())
|
||||
, m_Cgd(nlconst::zero())
|
||||
@ -222,8 +195,7 @@ namespace analog
|
||||
connect(m_SG.N(), m_DG.N());
|
||||
connect(m_DG.P(), m_SD.N());
|
||||
|
||||
set_qtype((m_model.type() == "NMOS_DEFAULT") ? FET_NMOS : FET_PMOS);
|
||||
m_polarity = (qtype() == FET_NMOS ? nlconst::one() : -nlconst::one());
|
||||
m_polarity = (m_model.type() == "NMOS_DEFAULT" ? nlconst::one() : -nlconst::one());
|
||||
|
||||
m_capacitor_model = m_model_acc.m_CAPMOD;
|
||||
//# printf("capmod %d %g %g\n", m_capacitor_model, (nl_fptype)m_model_acc.m_VTO, m_polarity);
|
||||
@ -296,6 +268,7 @@ namespace analog
|
||||
//#printf("Cox: %g\n", m_Cox);
|
||||
}
|
||||
|
||||
NETLIB_IS_DYNAMIC(true)
|
||||
NETLIB_IS_TIMESTEP(true || m_capacitor_model != 0)
|
||||
|
||||
NETLIB_TIMESTEPI()
|
||||
@ -328,7 +301,6 @@ namespace analog
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
NETLIB_NAME(FET)::reset();
|
||||
// Bulk diodes
|
||||
|
||||
m_D_BD.set_param(m_model_acc.m_ISD, m_model_acc.m_N, exec().gmin(), constants::T0());
|
||||
@ -351,9 +323,11 @@ namespace analog
|
||||
|
||||
private:
|
||||
|
||||
nld_two_terminal m_DG;
|
||||
nld_two_terminal m_SG;
|
||||
nld_two_terminal m_SD;
|
||||
param_model_t m_model;
|
||||
|
||||
NETLIB_NAME(two_terminal) m_DG;
|
||||
NETLIB_NAME(two_terminal) m_SG;
|
||||
NETLIB_NAME(two_terminal) m_SD;
|
||||
|
||||
generic_diode<diode_e::MOS> m_D_BD;
|
||||
#if (!BODY_CONNECTED_TO_SOURCE)
|
||||
@ -594,14 +568,14 @@ namespace analog
|
||||
const nl_fptype gSSBB = gSS + gBB + gBS + gSB;
|
||||
const auto zero(nlconst::zero());
|
||||
// S G
|
||||
m_SG.set_mat( gSSBB, gSG + gBG, +(IS + IB), // S
|
||||
gGS + gGB, gGG, IG ); // 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, zero, zero ); // G
|
||||
m_DG.set_mat( gDD, gDG, +ID, // D
|
||||
gGD, zero, zero ); // G
|
||||
// S D
|
||||
m_SD.set_mat( zero, gSD + gBD, zero, // S
|
||||
gDS + gDB, zero, zero); // D
|
||||
m_SD.set_mat( zero, gSD + gBD, zero, // S
|
||||
gDS + gDB, zero, zero ); // D
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(MOSFET)
|
||||
|
@ -101,9 +101,11 @@ namespace netlist
|
||||
};
|
||||
|
||||
|
||||
NETLIB_BASE_OBJECT(opamp)
|
||||
class nld_opamp : public base_device_t
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(opamp)
|
||||
public:
|
||||
nld_opamp(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_RP(*this, "RP1")
|
||||
, m_G1(*this, "G1")
|
||||
, m_VCC(*this, "VCC", NETLIB_DELEGATE(supply))
|
||||
@ -113,8 +115,8 @@ namespace netlist
|
||||
, m_VH(*this, "VH")
|
||||
, m_VL(*this, "VL")
|
||||
, m_VREF(*this, "VREF")
|
||||
, m_type(plib::narrow_cast<int>(m_modacc.m_TYPE))
|
||||
{
|
||||
m_type = plib::narrow_cast<int>(m_modacc.m_TYPE);
|
||||
if (m_type < 1 || m_type > 3)
|
||||
{
|
||||
log().fatal(MF_OPAMP_UNKNOWN_TYPE(m_type));
|
||||
@ -201,8 +203,8 @@ namespace netlist
|
||||
|
||||
private:
|
||||
|
||||
analog::NETLIB_SUB(R_base) m_RP;
|
||||
analog::NETLIB_SUB(VCCS) m_G1;
|
||||
NETLIB_SUB_NS(analog, R_base) m_RP;
|
||||
NETLIB_SUB_NS(analog, VCCS) m_G1;
|
||||
NETLIB_SUB_UPTR(analog, C) m_CP;
|
||||
#if TEST_ALT_OUTPUT
|
||||
NETLIB_SUB_UPTR(analog, R_base) m_RO;
|
||||
@ -226,14 +228,14 @@ namespace netlist
|
||||
|
||||
NETLIB_UPDATE_PARAM(opamp)
|
||||
{
|
||||
m_G1.m_RI.set(m_modacc.m_RI);
|
||||
m_G1().m_RI.set(m_modacc.m_RI);
|
||||
|
||||
if (m_type == 1)
|
||||
{
|
||||
nl_fptype RO = m_modacc.m_RO;
|
||||
nl_fptype G = m_modacc.m_UGF / m_modacc.m_FPF / RO;
|
||||
m_RP.set_R(RO);
|
||||
m_G1.m_G.set(G);
|
||||
m_RP().set_R(RO);
|
||||
m_G1().m_G.set(G);
|
||||
}
|
||||
if (m_type == 3 || m_type == 2)
|
||||
{
|
||||
@ -246,8 +248,8 @@ namespace netlist
|
||||
log().warning(MW_OPAMP_FAIL_CONVERGENCE(this->name()));
|
||||
|
||||
m_CP->set_cap_embedded(CP);
|
||||
m_RP.set_R(RP);
|
||||
m_G1.m_G.set(G);
|
||||
m_RP().set_R(RP);
|
||||
m_G1().m_G.set(G);
|
||||
|
||||
}
|
||||
if (m_type == 2)
|
||||
|
@ -19,65 +19,69 @@ namespace netlist
|
||||
// SWITCH
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_BASE_OBJECT(switch1)
|
||||
class nld_switch1 : public base_device_t
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(switch1)
|
||||
public:
|
||||
nld_switch1(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_R(*this, "R")
|
||||
, m_POS(*this, "POS", false)
|
||||
{
|
||||
register_sub_alias("1", m_R.P());
|
||||
register_sub_alias("2", m_R.N());
|
||||
register_sub_alias("1", m_R().P());
|
||||
register_sub_alias("2", m_R().N());
|
||||
}
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_R.set_R(R_OFF);
|
||||
m_R().set_R(R_OFF);
|
||||
}
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
m_R.change_state([this]()
|
||||
m_R().change_state([this]()
|
||||
{
|
||||
m_R.set_R(m_POS() ? R_ON : R_OFF);
|
||||
m_R().set_R(m_POS() ? R_ON : R_OFF);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
analog::NETLIB_SUB(R_base) m_R;
|
||||
param_logic_t m_POS;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R;
|
||||
param_logic_t m_POS;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// SWITCH2
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_BASE_OBJECT(switch2)
|
||||
class nld_switch2 : public base_device_t
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(switch2)
|
||||
public:
|
||||
nld_switch2(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_R1(*this, "R1")
|
||||
, m_R2(*this, "R2")
|
||||
, m_POS(*this, "POS", false)
|
||||
{
|
||||
connect(m_R1.N(), m_R2.N());
|
||||
connect(m_R1().N(), m_R2().N());
|
||||
|
||||
register_sub_alias("1", m_R1.P());
|
||||
register_sub_alias("2", m_R2.P());
|
||||
register_sub_alias("1", m_R1().P());
|
||||
register_sub_alias("2", m_R2().P());
|
||||
|
||||
register_sub_alias("Q", m_R1.N());
|
||||
register_sub_alias("Q", m_R1().N());
|
||||
}
|
||||
|
||||
NETLIB_RESETI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
private:
|
||||
analog::NETLIB_SUB(R_base) m_R1;
|
||||
analog::NETLIB_SUB(R_base) m_R2;
|
||||
param_logic_t m_POS;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R1;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R2;
|
||||
param_logic_t m_POS;
|
||||
};
|
||||
|
||||
NETLIB_RESET(switch2)
|
||||
{
|
||||
m_R1.set_R(R_ON);
|
||||
m_R2.set_R(R_OFF);
|
||||
m_R1().set_R(R_ON);
|
||||
m_R2().set_R(R_OFF);
|
||||
}
|
||||
|
||||
#ifdef FIXMELATER
|
||||
@ -103,12 +107,12 @@ namespace netlist
|
||||
nl_fptype r1 = m_POS() ? R_OFF : R_ON;
|
||||
nl_fptype r2 = m_POS() ? R_ON : R_OFF;
|
||||
|
||||
if (m_R1.solver() == m_R2.solver())
|
||||
m_R1.change_state([this, &r1, &r2]() { m_R1.set_R(r1); m_R2.set_R(r2); });
|
||||
if (m_R1().solver() == m_R2().solver())
|
||||
m_R1().change_state([this, &r1, &r2]() { m_R1().set_R(r1); m_R2().set_R(r2); });
|
||||
else
|
||||
{
|
||||
m_R1.change_state([this, &r1]() { m_R1.set_R(r1); });
|
||||
m_R2.change_state([this, &r2]() { m_R2.set_R(r2); });
|
||||
m_R1().change_state([this, &r1]() { m_R1().set_R(r1); });
|
||||
m_R2().change_state([this, &r2]() { m_R2().set_R(r2); });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,139 +1,129 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
#include "solver/nld_solver.h"
|
||||
#include "nl_factory.h"
|
||||
#include "nlid_fourterm.h"
|
||||
|
||||
namespace netlist
|
||||
#include "nl_factory.h"
|
||||
|
||||
#include "solver/nld_solver.h"
|
||||
|
||||
namespace netlist::analog
|
||||
{
|
||||
namespace analog
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_VCCS
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(VCCS)
|
||||
{
|
||||
const nl_fptype m_mult = m_G() * m_gfac; // 1.0 ==> 1V ==> 1A
|
||||
const nl_fptype GI = plib::reciprocal(m_RI());
|
||||
|
||||
m_IP.set_conductivity(GI);
|
||||
m_IN.set_conductivity(GI);
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_VCCS
|
||||
// ----------------------------------------------------------------------------------------
|
||||
m_OP.set_go_gt(-m_mult, nlconst::zero());
|
||||
m_OP1.set_go_gt(m_mult, nlconst::zero());
|
||||
|
||||
NETLIB_RESET(VCCS)
|
||||
m_ON.set_go_gt(m_mult, nlconst::zero());
|
||||
m_ON1.set_go_gt(-m_mult, nlconst::zero());
|
||||
}
|
||||
|
||||
NETLIB_HANDLER(VCCS, terminal_handler)
|
||||
{
|
||||
solver::matrix_solver_t *solv = nullptr;
|
||||
// only called if connected to a rail net ==> notify the solver to
|
||||
// recalculate
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
if ((solv = m_IP.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
else if ((solv = m_IN.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
else if ((solv = m_OP.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
else if ((solv = m_ON.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_LVCCS
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(LVCCS) { NETLIB_NAME(VCCS)::reset(); }
|
||||
|
||||
NETLIB_UPDATE_PARAM(LVCCS) { NETLIB_NAME(VCCS)::update_param(); }
|
||||
|
||||
NETLIB_UPDATE_TERMINALS(LVCCS)
|
||||
{
|
||||
const nl_fptype m_mult = m_G() * get_gfac(); // 1.0 ==> 1V ==> 1A
|
||||
const nl_fptype vi = m_IP.net().Q_Analog() - m_IN.net().Q_Analog();
|
||||
const auto c1(nlconst::magic(0.2));
|
||||
|
||||
if (plib::abs(m_mult / m_cur_limit() * vi) > nlconst::half())
|
||||
m_vi = m_vi + c1 * plib::tanh((vi - m_vi) / c1);
|
||||
else
|
||||
m_vi = vi;
|
||||
|
||||
const nl_fptype x = m_mult / m_cur_limit() * m_vi;
|
||||
const nl_fptype tanhx = plib::tanh(x);
|
||||
|
||||
const nl_fptype beta = m_mult * (nlconst::one() - tanhx * tanhx);
|
||||
const nl_fptype I = m_cur_limit() * tanhx - beta * m_vi;
|
||||
|
||||
m_OP.set_go_gt_I(-beta, nlconst::zero(), I);
|
||||
m_OP1.set_go_gt(beta, nlconst::zero());
|
||||
|
||||
m_ON.set_go_gt_I(beta, nlconst::zero(), -I);
|
||||
m_ON1.set_go_gt(-beta, nlconst::zero());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_CCCS
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(CCCS) { NETLIB_NAME(VCCS)::reset(); }
|
||||
|
||||
NETLIB_UPDATE_PARAM(CCCS) { NETLIB_NAME(VCCS)::update_param(); }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_VCVS
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(VCVS)
|
||||
{
|
||||
const auto gfac(plib::reciprocal(m_RO()));
|
||||
set_gfac(gfac);
|
||||
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
|
||||
m_OP2.set_conductivity(gfac);
|
||||
m_ON2.set_conductivity(gfac);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_CCVS
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(CCVS)
|
||||
{
|
||||
const auto gfac(plib::reciprocal(m_RO()));
|
||||
set_gfac(gfac);
|
||||
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
|
||||
m_OP2.set_conductivity(gfac);
|
||||
m_ON2.set_conductivity(gfac);
|
||||
}
|
||||
|
||||
} // namespace netlist::analog
|
||||
|
||||
namespace netlist::devices
|
||||
{
|
||||
const nl_fptype m_mult = m_G() * m_gfac; // 1.0 ==> 1V ==> 1A
|
||||
const nl_fptype GI = plib::reciprocal(m_RI());
|
||||
|
||||
m_IP.set_conductivity(GI);
|
||||
m_IN.set_conductivity(GI);
|
||||
|
||||
m_OP.set_go_gt(-m_mult, nlconst::zero());
|
||||
m_OP1.set_go_gt(m_mult, nlconst::zero());
|
||||
|
||||
m_ON.set_go_gt(m_mult, nlconst::zero());
|
||||
m_ON1.set_go_gt(-m_mult, nlconst::zero());
|
||||
}
|
||||
|
||||
NETLIB_HANDLER(VCCS, terminal_handler)
|
||||
{
|
||||
solver::matrix_solver_t *solv = nullptr;
|
||||
// only called if connected to a rail net ==> notify the solver to recalculate
|
||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||
if ((solv = m_IP.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
else if ((solv = m_IN.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
else if ((solv = m_OP.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
else if ((solv = m_ON.solver()) != nullptr)
|
||||
solv->solve_now();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_LVCCS
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(LVCCS)
|
||||
{
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(LVCCS)
|
||||
{
|
||||
NETLIB_NAME(VCCS)::update_param();
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_TERMINALS(LVCCS)
|
||||
{
|
||||
const nl_fptype m_mult = m_G() * get_gfac(); // 1.0 ==> 1V ==> 1A
|
||||
const nl_fptype vi = m_IP.net().Q_Analog() - m_IN.net().Q_Analog();
|
||||
const auto c1(nlconst::magic(0.2));
|
||||
|
||||
if (plib::abs(m_mult / m_cur_limit() * vi) > nlconst::half())
|
||||
m_vi = m_vi + c1 * plib::tanh((vi - m_vi) / c1);
|
||||
else
|
||||
m_vi = vi;
|
||||
|
||||
const nl_fptype x = m_mult / m_cur_limit() * m_vi;
|
||||
const nl_fptype tanhx = plib::tanh(x);
|
||||
|
||||
const nl_fptype beta = m_mult * (nlconst::one() - tanhx*tanhx);
|
||||
const nl_fptype I = m_cur_limit() * tanhx - beta * m_vi;
|
||||
|
||||
m_OP.set_go_gt_I(-beta, nlconst::zero(), I);
|
||||
m_OP1.set_go_gt(beta, nlconst::zero());
|
||||
|
||||
m_ON.set_go_gt_I(beta, nlconst::zero(), -I);
|
||||
m_ON1.set_go_gt(-beta, nlconst::zero());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_CCCS
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(CCCS)
|
||||
{
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(CCCS)
|
||||
{
|
||||
NETLIB_NAME(VCCS)::update_param();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_VCVS
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(VCVS)
|
||||
{
|
||||
const auto gfac(plib::reciprocal(m_RO()));
|
||||
set_gfac(gfac);
|
||||
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
|
||||
m_OP2.set_conductivity(gfac);
|
||||
m_ON2.set_conductivity(gfac);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_CCVS
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(CCVS)
|
||||
{
|
||||
const auto gfac(plib::reciprocal(m_RO()));
|
||||
set_gfac(gfac);
|
||||
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
|
||||
m_OP2.set_conductivity(gfac);
|
||||
m_ON2.set_conductivity(gfac);
|
||||
}
|
||||
|
||||
} //namespace analog
|
||||
|
||||
namespace devices {
|
||||
NETLIB_DEVICE_IMPL_NS(analog, VCVS, "VCVS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, VCCS, "VCCS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, CCCS, "CCCS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, CCVS, "CCVS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, LVCCS, "LVCCS", "")
|
||||
} // namespace devices
|
||||
} // namespace netlist
|
||||
// clang-format off
|
||||
NETLIB_DEVICE_IMPL_NS(analog, VCVS, "VCVS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, VCCS, "VCCS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, CCCS, "CCCS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, CCVS, "CCVS", "G")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, LVCCS, "LVCCS", "")
|
||||
// clang-format on
|
||||
} // namespace netlist::devices
|
||||
|
@ -9,9 +9,11 @@
|
||||
///
|
||||
|
||||
#include "nl_base.h"
|
||||
|
||||
#include "plib/putil.h"
|
||||
|
||||
namespace netlist::analog {
|
||||
namespace netlist::analog
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_VCCS
|
||||
@ -32,26 +34,27 @@ namespace netlist::analog {
|
||||
//
|
||||
// RI = 1 / NETLIST_GMIN
|
||||
//
|
||||
NETLIB_BASE_OBJECT(VCCS)
|
||||
class nld_VCCS : public base_device_t
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_EX(VCCS, nl_fptype ri = nlconst::magic(1e9))
|
||||
nld_VCCS(constructor_param_t data, nl_fptype ri = nlconst::magic(1e9))
|
||||
: base_device_t(data)
|
||||
, m_G(*this, "G", nlconst::one())
|
||||
, m_RI(*this, "RI", ri)
|
||||
, m_OP(*this, "OP", &m_IP, {&m_ON, &m_IN}, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_ON(*this, "ON", &m_IP, {&m_OP, &m_IN}, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_IP(*this, "IP", &m_IN, {&m_OP, &m_ON}, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_IN(*this, "IN", &m_IP, {&m_OP, &m_ON}, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_OP(*this, "OP", &m_IP, {&m_ON, &m_IN},
|
||||
NETLIB_DELEGATE(terminal_handler))
|
||||
, m_ON(*this, "ON", &m_IP, {&m_OP, &m_IN},
|
||||
NETLIB_DELEGATE(terminal_handler))
|
||||
, m_IP(*this, "IP", &m_IN, {&m_OP, &m_ON},
|
||||
NETLIB_DELEGATE(terminal_handler))
|
||||
, m_IN(*this, "IN", &m_IP, {&m_OP, &m_ON},
|
||||
NETLIB_DELEGATE(terminal_handler))
|
||||
, m_OP1(*this, "_OP1", &m_IN, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_ON1(*this, "_ON1", &m_IN, NETLIB_DELEGATE(terminal_handler))
|
||||
//, m_IPx(*this, "_IPx", &m_OP, NETLIB_DELEGATE(terminal_handler)) // <= this should be NULL and terminal be filtered out prior to solving...
|
||||
//, m_INx(*this, "_INx", &m_ON, NETLIB_DELEGATE(terminal_handler)) // <= this should be NULL and terminal be filtered out prior to solving...
|
||||
, m_gfac(nlconst::one())
|
||||
{
|
||||
connect(m_OP, m_OP1);
|
||||
connect(m_ON, m_ON1);
|
||||
//connect(m_IP, m_IPx);
|
||||
//connect(m_IN, m_INx);
|
||||
}
|
||||
|
||||
NETLIB_RESETI();
|
||||
@ -61,20 +64,11 @@ namespace netlist::analog {
|
||||
|
||||
protected:
|
||||
NETLIB_HANDLERI(terminal_handler);
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
}
|
||||
NETLIB_UPDATE_PARAMI() { NETLIB_NAME(VCCS)::reset(); }
|
||||
|
||||
void set_gfac(nl_fptype g) noexcept
|
||||
{
|
||||
m_gfac = g;
|
||||
}
|
||||
void set_gfac(nl_fptype g) noexcept { m_gfac = g; }
|
||||
|
||||
nl_fptype get_gfac() const noexcept
|
||||
{
|
||||
return m_gfac;
|
||||
}
|
||||
nl_fptype get_gfac() const noexcept { return m_gfac; }
|
||||
|
||||
terminal_t m_OP;
|
||||
terminal_t m_ON;
|
||||
@ -85,19 +79,17 @@ namespace netlist::analog {
|
||||
terminal_t m_OP1;
|
||||
terminal_t m_ON1;
|
||||
|
||||
//terminal_t m_IPx;
|
||||
//terminal_t m_INx;
|
||||
|
||||
private:
|
||||
nl_fptype m_gfac;
|
||||
};
|
||||
|
||||
// Limited Current source
|
||||
|
||||
NETLIB_OBJECT_DERIVED(LVCCS, VCCS)
|
||||
class nld_LVCCS : public nld_VCCS
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(LVCCS)
|
||||
nld_LVCCS(constructor_param_t data)
|
||||
: nld_VCCS(data)
|
||||
, m_cur_limit(*this, "CURLIM", nlconst::magic(1000.0))
|
||||
, m_vi(nlconst::zero())
|
||||
{
|
||||
@ -106,14 +98,13 @@ namespace netlist::analog {
|
||||
NETLIB_IS_DYNAMIC(true)
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
NETLIB_RESETI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
NETLIB_UPDATE_TERMINALSI();
|
||||
|
||||
private:
|
||||
param_fp_t m_cur_limit; // current limit
|
||||
nl_fptype m_vi;
|
||||
nl_fptype m_vi;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -140,10 +131,11 @@ namespace netlist::analog {
|
||||
// This needs high levels of accuracy to work with 1 Ohm RI.
|
||||
//
|
||||
|
||||
NETLIB_OBJECT_DERIVED(CCCS, VCCS)
|
||||
class nld_CCCS : public nld_VCCS
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_PASS(CCCS, nlconst::one())
|
||||
nld_CCCS(constructor_param_t data)
|
||||
: nld_VCCS(data, nlconst::one())
|
||||
{
|
||||
set_gfac(-plib::reciprocal(m_RI()));
|
||||
}
|
||||
@ -151,11 +143,9 @@ namespace netlist::analog {
|
||||
NETLIB_RESETI();
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// nld_VCVS
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -182,10 +172,11 @@ namespace netlist::analog {
|
||||
// Internal GI = G / RO
|
||||
//
|
||||
|
||||
NETLIB_OBJECT_DERIVED(VCVS, VCCS)
|
||||
class nld_VCVS : public nld_VCCS
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(VCVS)
|
||||
nld_VCVS(constructor_param_t data)
|
||||
: nld_VCCS(data)
|
||||
, m_RO(*this, "RO", nlconst::one())
|
||||
, m_OP2(*this, "_OP2", &m_ON2, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_ON2(*this, "_ON2", &m_OP2, NETLIB_DELEGATE(terminal_handler))
|
||||
@ -199,16 +190,14 @@ namespace netlist::analog {
|
||||
param_fp_t m_RO;
|
||||
|
||||
private:
|
||||
//NETLIB_UPDATE_PARAMI();
|
||||
// NETLIB_UPDATE_PARAMI();
|
||||
NETLIB_HANDLERI(terminal_handler)
|
||||
{
|
||||
NETLIB_NAME(VCCS) :: terminal_handler();
|
||||
NETLIB_NAME(VCCS)::terminal_handler();
|
||||
}
|
||||
|
||||
terminal_t m_OP2;
|
||||
terminal_t m_ON2;
|
||||
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -225,7 +214,7 @@ namespace netlist::analog {
|
||||
// IP ---+ +--+---- OP
|
||||
// | | |
|
||||
// RI I RO
|
||||
// RI => G => I RO V(OP) - V(ON) = (V(IP)-V(IN)) / RI * G
|
||||
// RI => G => I RO V(OP) - V(ON) = (V(IP)-V(IN)) / RI * G
|
||||
// RI I RO
|
||||
// | | |
|
||||
// IN ---+ +--+---- ON
|
||||
@ -237,10 +226,11 @@ namespace netlist::analog {
|
||||
// Internal GI = G / RO
|
||||
//
|
||||
|
||||
NETLIB_OBJECT_DERIVED(CCVS, VCCS)
|
||||
class nld_CCVS : public nld_VCCS
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_PASS(CCVS, nlconst::one())
|
||||
nld_CCVS(constructor_param_t data)
|
||||
: nld_VCCS(data, nlconst::one())
|
||||
, m_RO(*this, "RO", nlconst::one())
|
||||
, m_OP2(*this, "_OP2", &m_ON2, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_ON2(*this, "_ON2", &m_OP2, NETLIB_DELEGATE(terminal_handler))
|
||||
@ -254,18 +244,17 @@ namespace netlist::analog {
|
||||
param_fp_t m_RO;
|
||||
|
||||
private:
|
||||
//NETLIB_UPDATE_PARAMI();
|
||||
// NETLIB_UPDATE_PARAMI();
|
||||
|
||||
NETLIB_HANDLERI(terminal_handler)
|
||||
{
|
||||
NETLIB_NAME(VCCS) :: terminal_handler();
|
||||
NETLIB_NAME(VCCS)::terminal_handler();
|
||||
}
|
||||
|
||||
terminal_t m_OP2;
|
||||
terminal_t m_ON2;
|
||||
};
|
||||
|
||||
|
||||
} // namespace netlist::analog
|
||||
|
||||
#endif // NLD_FOURTERM_H_
|
||||
|
@ -1,21 +1,20 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
#include "solver/nld_solver.h"
|
||||
|
||||
#include "nl_factory.h"
|
||||
#include "nlid_twoterm.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
namespace analog
|
||||
#include "nl_factory.h"
|
||||
|
||||
#include "solver/nld_solver.h"
|
||||
|
||||
namespace netlist::analog
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_twoterm
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
solver::matrix_solver_t * NETLIB_NAME(two_terminal)::solver() const noexcept
|
||||
solver::matrix_solver_t *nld_two_terminal::solver() const noexcept
|
||||
{
|
||||
auto *solv(m_P.solver());
|
||||
if (solv != nullptr)
|
||||
@ -23,8 +22,7 @@ namespace analog
|
||||
return m_N.solver();
|
||||
}
|
||||
|
||||
|
||||
void NETLIB_NAME(two_terminal)::solve_now() const
|
||||
void nld_two_terminal::solve_now() const
|
||||
{
|
||||
auto *solv(solver());
|
||||
if (solv != nullptr)
|
||||
@ -33,92 +31,97 @@ namespace analog
|
||||
|
||||
NETLIB_HANDLER(two_terminal, terminal_handler)
|
||||
{
|
||||
// only called if connected to a rail net ==> notify the solver to recalculate
|
||||
//printf("%s update\n", this->name().c_str());
|
||||
// only called if connected to a rail net ==> notify the solver to
|
||||
// recalculate
|
||||
// printf("%s update\n", this->name().c_str());
|
||||
solve_now();
|
||||
}
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_POT
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(POT)
|
||||
{
|
||||
nl_fptype v = m_Dial();
|
||||
if (m_DialIsLog())
|
||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||
v = (plib::exp(v) - nlconst::one())
|
||||
/ (plib::exp(nlconst::one()) - nlconst::one());
|
||||
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
m_R2.set_R(std::max(m_R() * (nlconst::one() - v), exec().gmin()));
|
||||
m_R1().set_R(std::max(m_R() * v, exec().gmin()));
|
||||
m_R2().set_R(std::max(m_R() * (nlconst::one() - v), exec().gmin()));
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(POT)
|
||||
{
|
||||
nl_fptype v = m_Dial();
|
||||
if (m_DialIsLog())
|
||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||
v = (plib::exp(v) - nlconst::one())
|
||||
/ (plib::exp(nlconst::one()) - nlconst::one());
|
||||
if (m_Reverse())
|
||||
v = nlconst::one() - v;
|
||||
|
||||
nl_fptype r1(std::max(m_R() * v, exec().gmin()));
|
||||
nl_fptype r2(std::max(m_R() * (nlconst::one() - v), exec().gmin()));
|
||||
|
||||
if (m_R1.solver() == m_R2.solver())
|
||||
m_R1.change_state([this, &r1, &r2]() { m_R1.set_R(r1); m_R2.set_R(r2); });
|
||||
if (m_R1().solver() == m_R2().solver())
|
||||
m_R1().change_state(
|
||||
[this, &r1, &r2]()
|
||||
{
|
||||
m_R1().set_R(r1);
|
||||
m_R2().set_R(r2);
|
||||
});
|
||||
else
|
||||
{
|
||||
m_R1.change_state([this, &r1]() { m_R1.set_R(r1); });
|
||||
m_R2.change_state([this, &r2]() { m_R2.set_R(r2); });
|
||||
m_R1().change_state([this, &r1]() { m_R1().set_R(r1); });
|
||||
m_R2().change_state([this, &r2]() { m_R2().set_R(r2); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_POT2
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(POT2)
|
||||
{
|
||||
nl_fptype v = m_Dial();
|
||||
|
||||
if (m_DialIsLog())
|
||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||
v = (plib::exp(v) - nlconst::one())
|
||||
/ (plib::exp(nlconst::one()) - nlconst::one());
|
||||
if (m_Reverse())
|
||||
v = nlconst::one() - v;
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
m_R1().set_R(std::max(m_R() * v, exec().gmin()));
|
||||
}
|
||||
|
||||
|
||||
NETLIB_UPDATE_PARAM(POT2)
|
||||
{
|
||||
nl_fptype v = m_Dial();
|
||||
|
||||
if (m_DialIsLog())
|
||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||
v = (plib::exp(v) - nlconst::one())
|
||||
/ (plib::exp(nlconst::one()) - nlconst::one());
|
||||
if (m_Reverse())
|
||||
v = nlconst::one() - v;
|
||||
|
||||
m_R1.change_state([this, &v]()
|
||||
{
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
});
|
||||
m_R1().change_state(
|
||||
[this, &v]() { m_R1().set_R(std::max(m_R() * v, exec().gmin())); });
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_L
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(L)
|
||||
{
|
||||
m_gmin = exec().gmin();
|
||||
m_I = nlconst::zero();
|
||||
m_G = m_gmin;
|
||||
set_mat( m_G, -m_G, -m_I,
|
||||
-m_G, m_G, m_I);
|
||||
set_mat(m_G, -m_G, -m_I, //
|
||||
-m_G, m_G, m_I);
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(L)
|
||||
{
|
||||
}
|
||||
NETLIB_UPDATE_PARAM(L) {}
|
||||
|
||||
NETLIB_TIMESTEP(L)
|
||||
{
|
||||
@ -129,8 +132,8 @@ namespace analog
|
||||
// Gpar should support convergence
|
||||
m_I += m_G * deltaV();
|
||||
m_G = step / m_L() + m_gmin;
|
||||
set_mat( m_G, -m_G, -m_I,
|
||||
-m_G, m_G, m_I);
|
||||
set_mat(m_G, -m_G, -m_I, //
|
||||
-m_G, m_G, m_I);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -139,9 +142,9 @@ namespace analog
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_D
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(D)
|
||||
{
|
||||
@ -165,29 +168,37 @@ namespace analog
|
||||
m_D.update_diode(deltaV());
|
||||
const nl_fptype G(m_D.G());
|
||||
const nl_fptype I(m_D.Ieq());
|
||||
set_mat( G, -G, -I,
|
||||
-G, G, I);
|
||||
//set(m_D.G(), 0.0, m_D.Ieq());
|
||||
set_mat(G, -G, -I, //
|
||||
-G, G, I);
|
||||
// set(m_D.G(), 0.0, m_D.Ieq());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_Z
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_RESET(Z)
|
||||
{
|
||||
nl_fptype IsBV = m_modacc.m_IBV / (plib::exp(m_modacc.m_BV / nlconst::np_VT(m_modacc.m_NBV)) - nlconst::one());
|
||||
nl_fptype IsBV = m_modacc.m_IBV
|
||||
/ (plib::exp(m_modacc.m_BV
|
||||
/ nlconst::np_VT(m_modacc.m_NBV))
|
||||
- nlconst::one());
|
||||
|
||||
m_D.set_param(m_modacc.m_IS, m_modacc.m_N, exec().gmin(), nlconst::T0());
|
||||
m_D.set_param(m_modacc.m_IS, m_modacc.m_N, exec().gmin(),
|
||||
nlconst::T0());
|
||||
m_R.set_param(IsBV, m_modacc.m_NBV, exec().gmin(), nlconst::T0());
|
||||
set_G_V_I(m_D.G(), nlconst::zero(), m_D.Ieq());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(Z)
|
||||
{
|
||||
nl_fptype IsBV = m_modacc.m_IBV / (plib::exp(m_modacc.m_BV / nlconst::np_VT(m_modacc.m_NBV)) - nlconst::one());
|
||||
nl_fptype IsBV = m_modacc.m_IBV
|
||||
/ (plib::exp(m_modacc.m_BV
|
||||
/ nlconst::np_VT(m_modacc.m_NBV))
|
||||
- nlconst::one());
|
||||
|
||||
m_D.set_param(m_modacc.m_IS, m_modacc.m_N, exec().gmin(), nlconst::T0());
|
||||
m_D.set_param(m_modacc.m_IS, m_modacc.m_N, exec().gmin(),
|
||||
nlconst::T0());
|
||||
m_R.set_param(IsBV, m_modacc.m_NBV, exec().gmin(), nlconst::T0());
|
||||
set_G_V_I(m_D.G(), nlconst::zero(), m_D.Ieq());
|
||||
}
|
||||
@ -198,15 +209,15 @@ namespace analog
|
||||
m_R.update_diode(-deltaV());
|
||||
const nl_fptype G(m_D.G() + m_R.G());
|
||||
const nl_fptype I(m_D.Ieq() - m_R.Ieq());
|
||||
set_mat( G, -G, -I,
|
||||
-G, G, I);
|
||||
set_mat(G, -G, -I, //
|
||||
-G, G, I);
|
||||
}
|
||||
|
||||
} // namespace netlist::analog
|
||||
|
||||
|
||||
} //namespace analog
|
||||
|
||||
namespace devices {
|
||||
namespace netlist::devices
|
||||
{
|
||||
// clang-format off
|
||||
NETLIB_DEVICE_IMPL_NS(analog, R, "RES", "R")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, POT, "POT", "R")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, POT2, "POT2", "R")
|
||||
@ -216,6 +227,5 @@ namespace devices {
|
||||
NETLIB_DEVICE_IMPL_NS(analog, Z, "ZDIODE", "MODEL")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, VS, "VS", "V")
|
||||
NETLIB_DEVICE_IMPL_NS(analog, CS, "CS", "I")
|
||||
} // namespace devices
|
||||
|
||||
} // namespace netlist
|
||||
// clang-format on
|
||||
} // namespace netlist::devices
|
||||
|
@ -37,9 +37,11 @@
|
||||
#include "../nl_setup.h"
|
||||
#include "nl_base.h"
|
||||
#include "nld_generic_models.h"
|
||||
#include "plib/pfunction.h"
|
||||
|
||||
#include "solver/nld_solver.h"
|
||||
|
||||
#include "plib/pfunction.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -47,45 +49,37 @@
|
||||
namespace netlist::analog
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_two_terminal
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <class C>
|
||||
static inline core_device_t &bselect(bool b, C &d1, core_device_t &d2)
|
||||
class nld_two_terminal : public base_device_t
|
||||
{
|
||||
auto *h = dynamic_cast<core_device_t *>(&d1);
|
||||
return b ? *h : d2;
|
||||
}
|
||||
template <>
|
||||
inline core_device_t &bselect(bool b, [[maybe_unused]] netlist_state_t &d1, core_device_t &d2)
|
||||
{
|
||||
if (b)
|
||||
throw nl_exception("bselect with netlist and b==true");
|
||||
return d2;
|
||||
}
|
||||
|
||||
NETLIB_BASE_OBJECT(two_terminal)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(two_terminal)
|
||||
public:
|
||||
nld_two_terminal(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_P(*this, "1", &m_N, NETLIB_DELEGATE(terminal_handler))
|
||||
, m_N(*this, "2", &m_P, NETLIB_DELEGATE(terminal_handler))
|
||||
{
|
||||
}
|
||||
//#NETLIB_CONSTRUCTOR_EX(twoterm, nldelegate owner_delegate)
|
||||
template <class C>
|
||||
NETLIB_NAME(two_terminal)(C &owner, const pstring &name, nl_delegate owner_delegate) \
|
||||
: base_type(owner, name)
|
||||
|
||||
// This constructor covers the case in which the terminals are "owned"
|
||||
// by the device using a two_terminal. In this case it passes
|
||||
// the terminal handler on to the terminals.
|
||||
|
||||
nld_two_terminal(base_device_t &owner, const pstring &name,
|
||||
nl_delegate owner_delegate)
|
||||
: base_device_t(
|
||||
constructor_data_t{owner.state(), owner.name() + "." + name})
|
||||
, m_P(owner, name + ".1", &m_N, owner_delegate)
|
||||
, m_N(owner, name + ".2", &m_P, owner_delegate)
|
||||
{
|
||||
}
|
||||
|
||||
//NETLIB_UPDATE_TERMINALSI() { }
|
||||
//NETLIB_RESETI() {}
|
||||
// NETLIB_UPDATE_TERMINALSI() { }
|
||||
// NETLIB_RESETI() {}
|
||||
|
||||
public:
|
||||
|
||||
NETLIB_HANDLERI(terminal_handler);
|
||||
|
||||
solver::matrix_solver_t *solver() const noexcept;
|
||||
@ -112,18 +106,13 @@ namespace netlist::analog
|
||||
return m_P.net().Q_Analog() - m_N.net().Q_Analog();
|
||||
}
|
||||
|
||||
nl_fptype V1P() const noexcept
|
||||
{
|
||||
return m_P.net().Q_Analog();
|
||||
}
|
||||
nl_fptype V1P() const noexcept { return m_P.net().Q_Analog(); }
|
||||
|
||||
nl_fptype V2N() const noexcept
|
||||
{
|
||||
return m_N.net().Q_Analog();
|
||||
}
|
||||
nl_fptype V2N() const noexcept { return m_N.net().Q_Analog(); }
|
||||
|
||||
void set_mat(nl_fptype a11, nl_fptype a12, nl_fptype rhs1,
|
||||
nl_fptype a21, nl_fptype a22, nl_fptype rhs2) const noexcept
|
||||
void set_mat(nl_fptype a11, nl_fptype a12, nl_fptype rhs1, //
|
||||
nl_fptype a21, nl_fptype a22, nl_fptype rhs2 //
|
||||
) const noexcept
|
||||
{
|
||||
// GO, GT, I
|
||||
m_P.set_go_gt_I(a12, a11, rhs1);
|
||||
@ -173,78 +162,75 @@ namespace netlist::analog
|
||||
private:
|
||||
terminal_t m_P;
|
||||
terminal_t m_N;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_R
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(R_base, two_terminal)
|
||||
class nld_R_base : public nld_two_terminal
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(R_base)
|
||||
public:
|
||||
nld_R_base(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
{
|
||||
}
|
||||
|
||||
void set_R(nl_fptype R) const noexcept
|
||||
{
|
||||
const nl_fptype G = plib::reciprocal(R);
|
||||
set_mat( G, -G, nlconst::zero(),
|
||||
-G, G, nlconst::zero());
|
||||
set_mat(G, -G, nlconst::zero(), //
|
||||
-G, G, nlconst::zero());
|
||||
}
|
||||
|
||||
void set_G(nl_fptype G) const noexcept
|
||||
{
|
||||
set_mat( G, -G, nlconst::zero(),
|
||||
-G, G, nlconst::zero());
|
||||
set_mat(G, -G, nlconst::zero(), //
|
||||
-G, G, nlconst::zero());
|
||||
}
|
||||
|
||||
//NETLIB_RESETI();
|
||||
// NETLIB_RESETI();
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
|
||||
// NETLIB_UPDATEI();
|
||||
};
|
||||
|
||||
NETLIB_OBJECT_DERIVED(R, R_base)
|
||||
class nld_R : public nld_R_base
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(R)
|
||||
public:
|
||||
nld_R(constructor_param_t data)
|
||||
: nld_R_base(data)
|
||||
, m_R(*this, "R", nlconst::magic(1e9))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
set_R(std::max(m_R(), exec().gmin()));
|
||||
}
|
||||
NETLIB_RESETI() { set_R(std::max(m_R(), exec().gmin())); }
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
// FIXME: We only need to update the net first if this is a time stepping net
|
||||
change_state([this]()
|
||||
{
|
||||
set_R(std::max(m_R(), exec().gmin()));
|
||||
});
|
||||
// FIXME: We only need to update the net first if this is a time
|
||||
// stepping net
|
||||
change_state([this]() { set_R(std::max(m_R(), exec().gmin())); });
|
||||
}
|
||||
|
||||
private:
|
||||
param_fp_t m_R;
|
||||
// protect set_R ... it's a recipe to disaster when used to bypass the parameter
|
||||
using NETLIB_NAME(R_base)::set_R;
|
||||
using NETLIB_NAME(R_base)::set_G;
|
||||
// protect set_R ... it's a recipe to disaster when used to bypass the
|
||||
// parameter
|
||||
using nld_R_base::set_G;
|
||||
using nld_R_base::set_R;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_POT
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_BASE_OBJECT(POT)
|
||||
class nld_POT : public base_device_t
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(POT)
|
||||
public:
|
||||
nld_POT(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_R1(*this, "_R1")
|
||||
, m_R2(*this, "_R2")
|
||||
, m_R(*this, "R", 10000)
|
||||
@ -252,63 +238,65 @@ namespace netlist::analog
|
||||
, m_DialIsLog(*this, "DIALLOG", false)
|
||||
, m_Reverse(*this, "REVERSE", false)
|
||||
{
|
||||
register_sub_alias("1", m_R1.P());
|
||||
register_sub_alias("2", m_R1.N());
|
||||
register_sub_alias("3", m_R2.N());
|
||||
|
||||
connect(m_R2.P(), m_R1.N());
|
||||
register_sub_alias("1", m_R1().P());
|
||||
register_sub_alias("2", m_R1().N());
|
||||
register_sub_alias("3", m_R2().N());
|
||||
|
||||
connect(m_R2().P(), m_R1().N());
|
||||
}
|
||||
|
||||
//NETLIB_UPDATEI();
|
||||
// NETLIB_UPDATEI();
|
||||
NETLIB_RESETI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
private:
|
||||
NETLIB_SUB(R_base) m_R1;
|
||||
NETLIB_SUB(R_base) m_R2;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R1;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R2;
|
||||
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_Dial;
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_Dial;
|
||||
param_logic_t m_DialIsLog;
|
||||
param_logic_t m_Reverse;
|
||||
};
|
||||
|
||||
NETLIB_BASE_OBJECT(POT2)
|
||||
class nld_POT2 : public base_device_t
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(POT2)
|
||||
public:
|
||||
nld_POT2(constructor_param_t data)
|
||||
: base_device_t(data)
|
||||
, m_R1(*this, "_R1")
|
||||
, m_R(*this, "R", nlconst::magic(10000.0))
|
||||
, m_Dial(*this, "DIAL", nlconst::half())
|
||||
, m_DialIsLog(*this, "DIALLOG", false)
|
||||
, m_Reverse(*this, "REVERSE", false)
|
||||
{
|
||||
register_sub_alias("1", m_R1.P());
|
||||
register_sub_alias("2", m_R1.N());
|
||||
|
||||
register_sub_alias("1", m_R1().P());
|
||||
register_sub_alias("2", m_R1().N());
|
||||
}
|
||||
|
||||
//NETLIB_UPDATEI();
|
||||
// NETLIB_UPDATEI();
|
||||
NETLIB_RESETI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
private:
|
||||
NETLIB_SUB(R_base) m_R1;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R1;
|
||||
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_Dial;
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_Dial;
|
||||
param_logic_t m_DialIsLog;
|
||||
param_logic_t m_Reverse;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_C
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
#if 1
|
||||
NETLIB_OBJECT_DERIVED(C, two_terminal)
|
||||
class nld_C : public nld_two_terminal
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(C)
|
||||
nld_C(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
, m_C(*this, "C", nlconst::magic(1e-6))
|
||||
, m_cap(*this, "m_cap")
|
||||
{
|
||||
@ -320,20 +308,17 @@ namespace netlist::analog
|
||||
if (ts_type == time_step_type::FORWARD)
|
||||
{
|
||||
// G, Ieq
|
||||
const auto res(m_cap.time_step(m_C(), deltaV(), step));
|
||||
const auto res(m_cap.time_step(m_C(), deltaV(), step));
|
||||
const nl_fptype G = res.first;
|
||||
const nl_fptype I = res.second;
|
||||
set_mat( G, -G, -I,
|
||||
-G, G, I);
|
||||
set_mat(G, -G, -I, //
|
||||
-G, G, I);
|
||||
}
|
||||
else
|
||||
m_cap.restore_state();
|
||||
}
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_cap.set_parameters(exec().gmin());
|
||||
}
|
||||
NETLIB_RESETI() { m_cap.set_parameters(exec().gmin()); }
|
||||
|
||||
/// \brief Set capacitance
|
||||
///
|
||||
@ -343,27 +328,25 @@ namespace netlist::analog
|
||||
///
|
||||
/// \param val Capacitance value
|
||||
///
|
||||
void set_cap_embedded(nl_fptype val)
|
||||
{
|
||||
m_C.set(val);
|
||||
}
|
||||
void set_cap_embedded(nl_fptype val) { m_C.set(val); }
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
//FIXME: should be able to change
|
||||
NETLIB_UPDATE_PARAMI() { }
|
||||
// NETLIB_UPDATEI();
|
||||
// FIXME: should be able to change
|
||||
NETLIB_UPDATE_PARAMI() {}
|
||||
|
||||
private:
|
||||
param_fp_t m_C;
|
||||
param_fp_t m_C;
|
||||
generic_capacitor_const m_cap;
|
||||
};
|
||||
|
||||
#else
|
||||
// Code preserved as a basis for a current/voltage controlled capacitor
|
||||
NETLIB_OBJECT_DERIVED(C, two_terminal)
|
||||
class nld_C : public nld_two_terminal)
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(C, two_terminal)
|
||||
nld_C(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
, m_C(*this, "C", nlconst::magic(1e-6))
|
||||
, m_cap(*this, "m_cap")
|
||||
{
|
||||
@ -377,8 +360,8 @@ namespace netlist::analog
|
||||
{
|
||||
const nl_fptype I = m_cap.Ieq(m_C(), deltaV());
|
||||
const nl_fptype G = m_cap.G(m_C());
|
||||
set_mat( G, -G, -I,
|
||||
-G, G, I);
|
||||
set_mat(G, -G, -I, //
|
||||
-G, G, I);
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,34 +370,33 @@ namespace netlist::analog
|
||||
{
|
||||
const nl_fptype I = m_cap.Ieq(m_C(), deltaV());
|
||||
const nl_fptype G = m_cap.G(m_C());
|
||||
set_mat( G, -G, -I,
|
||||
-G, G, I);
|
||||
set_mat(G, -G, -I, //
|
||||
-G, G, I);
|
||||
}
|
||||
|
||||
param_fp_t m_C;
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_cap.set_parameters(exec().gmin());
|
||||
}
|
||||
NETLIB_RESETI() { m_cap.set_parameters(exec().gmin()); }
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
//FIXME: should be able to change
|
||||
NETLIB_UPDATE_PARAMI() { }
|
||||
// NETLIB_UPDATEI();
|
||||
// FIXME: should be able to change
|
||||
NETLIB_UPDATE_PARAMI() {}
|
||||
|
||||
private:
|
||||
//generic_capacitor<capacitor_e::VARIABLE_CAPACITY> m_cap;
|
||||
// generic_capacitor<capacitor_e::VARIABLE_CAPACITY> m_cap;
|
||||
generic_capacitor<capacitor_e::CONSTANT_CAPACITY> m_cap;
|
||||
};
|
||||
#endif
|
||||
// -----------------------------------------------------------------------------
|
||||
// nld_L
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(L, two_terminal)
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_L
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class nld_L : public nld_two_terminal
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(L)
|
||||
nld_L(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
, m_L(*this, "L", nlconst::magic(1e-6))
|
||||
, m_gmin(nlconst::zero())
|
||||
, m_G(*this, "m_G", nlconst::zero())
|
||||
@ -422,8 +404,8 @@ namespace netlist::analog
|
||||
, m_last_I(*this, "m_last_I", nlconst::zero())
|
||||
, m_last_G(*this, "m_last_G", nlconst::zero())
|
||||
{
|
||||
//register_term("1", m_P);
|
||||
//register_term("2", m_N);
|
||||
// register_term("1", m_P);
|
||||
// register_term("2", m_N);
|
||||
}
|
||||
|
||||
NETLIB_IS_TIMESTEP(true)
|
||||
@ -431,13 +413,13 @@ namespace netlist::analog
|
||||
NETLIB_RESETI();
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
// NETLIB_UPDATEI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
private:
|
||||
param_fp_t m_L;
|
||||
|
||||
nl_fptype m_gmin;
|
||||
nl_fptype m_gmin;
|
||||
state_var<nl_fptype> m_G;
|
||||
state_var<nl_fptype> m_I;
|
||||
state_var<nl_fptype> m_last_I;
|
||||
@ -446,9 +428,9 @@ namespace netlist::analog
|
||||
|
||||
/// \brief Class representing the diode model parameters.
|
||||
///
|
||||
/// This is the model representation of the diode model. Typically, SPICE uses
|
||||
/// the following parameters. A "Y" in the first column indicates that the
|
||||
/// parameter is actually used in netlist.
|
||||
/// This is the model representation of the diode model. Typically, SPICE
|
||||
/// uses the following parameters. A "Y" in the first column indicates that
|
||||
/// the parameter is actually used in netlist.
|
||||
///
|
||||
/// NBV, BV and IBV are only used in the ZDIODE model. It is assumed
|
||||
/// that DIODEs are not modeled up to their breakdown voltage.
|
||||
@ -478,10 +460,11 @@ namespace netlist::analog
|
||||
diode_model_t(param_model_t &model)
|
||||
: m_IS(model, "IS")
|
||||
, m_N(model, "N")
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
param_model_t::value_t m_IS; //!< saturation current.
|
||||
param_model_t::value_t m_N; //!< emission coefficient.
|
||||
param_model_t::value_t m_IS; //!< saturation current.
|
||||
param_model_t::value_t m_N; //!< emission coefficient.
|
||||
};
|
||||
|
||||
class zdiode_model_t : public diode_model_t
|
||||
@ -492,21 +475,23 @@ namespace netlist::analog
|
||||
, m_NBV(model, "NBV")
|
||||
, m_BV(model, "BV")
|
||||
, m_IBV(model, "IBV")
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
param_model_t::value_t m_NBV; //!< reverse emission coefficient.
|
||||
param_model_t::value_t m_BV; //!< reverse breakdown voltage.
|
||||
param_model_t::value_t m_IBV; //!< current at breakdown voltage.
|
||||
param_model_t::value_t m_NBV; //!< reverse emission coefficient.
|
||||
param_model_t::value_t m_BV; //!< reverse breakdown voltage.
|
||||
param_model_t::value_t m_IBV; //!< current at breakdown voltage.
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_D
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(D, two_terminal)
|
||||
class nld_D : public nld_two_terminal
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_EX(D, const pstring &model = "D")
|
||||
nld_D(constructor_param_t data, const pstring &model = "D")
|
||||
: nld_two_terminal(data)
|
||||
, m_model(*this, "MODEL", model)
|
||||
, m_modacc(m_model)
|
||||
, m_D(*this, "m_D")
|
||||
@ -520,23 +505,24 @@ namespace netlist::analog
|
||||
NETLIB_RESETI();
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
// NETLIB_UPDATEI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
private:
|
||||
param_model_t m_model;
|
||||
diode_model_t m_modacc;
|
||||
param_model_t m_model;
|
||||
diode_model_t m_modacc;
|
||||
generic_diode<diode_e::BIPOLAR> m_D;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_Z - Zener Diode
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(Z, two_terminal)
|
||||
class nld_Z : public nld_two_terminal
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_EX(Z, const pstring &model = "D")
|
||||
nld_Z(constructor_param_t data, const pstring &model = "D")
|
||||
: nld_two_terminal(data)
|
||||
, m_model(*this, "MODEL", model)
|
||||
, m_modacc(m_model)
|
||||
, m_D(*this, "m_D")
|
||||
@ -551,38 +537,40 @@ namespace netlist::analog
|
||||
NETLIB_RESETI();
|
||||
|
||||
protected:
|
||||
//NETLIB_UPDATEI();
|
||||
// NETLIB_UPDATEI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
private:
|
||||
param_model_t m_model;
|
||||
zdiode_model_t m_modacc;
|
||||
param_model_t m_model;
|
||||
zdiode_model_t m_modacc;
|
||||
generic_diode<diode_e::BIPOLAR> m_D;
|
||||
// REVERSE diode
|
||||
generic_diode<diode_e::BIPOLAR> m_R;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_VS - Voltage source
|
||||
//
|
||||
// netlist voltage source must have inner resistance
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(VS, two_terminal)
|
||||
class nld_VS : public nld_two_terminal
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(VS)
|
||||
nld_VS(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
, m_t(*this, "m_t", nlconst::zero())
|
||||
, m_R(*this, "RI", nlconst::magic(0.1))
|
||||
, m_V(*this, "V", nlconst::zero())
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_func(*this, "FUNC", "")
|
||||
, m_compiled(*this, "m_compiled")
|
||||
, m_funcparam({nlconst::zero()})
|
||||
{
|
||||
register_sub_alias("P", P());
|
||||
register_sub_alias("N", N());
|
||||
if (!m_func().empty())
|
||||
m_compiled->compile(m_func(), std::vector<pstring>({{pstring("T")}}));
|
||||
m_compiled->compile(m_func(),
|
||||
std::vector<pstring>({{pstring("T")}}));
|
||||
}
|
||||
|
||||
NETLIB_IS_TIMESTEP(!m_func().empty())
|
||||
@ -594,48 +582,49 @@ namespace netlist::analog
|
||||
m_t += step;
|
||||
m_funcparam[0] = m_t;
|
||||
this->set_G_V_I(plib::reciprocal(m_R()),
|
||||
m_compiled->evaluate(m_funcparam),
|
||||
nlconst::zero());
|
||||
m_compiled->evaluate(m_funcparam),
|
||||
nlconst::zero());
|
||||
}
|
||||
else
|
||||
m_t -= step; // only need to restore state, will be called again
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
NETLIB_NAME(two_terminal)::reset();
|
||||
nld_two_terminal::reset();
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), m_V(), nlconst::zero());
|
||||
}
|
||||
|
||||
private:
|
||||
state_var<nl_fptype> m_t;
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_V;
|
||||
param_str_t m_func;
|
||||
state_var<nl_fptype> m_t;
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_V;
|
||||
param_str_t m_func;
|
||||
state_var<plib::pfunction<nl_fptype>> m_compiled;
|
||||
std::vector<nl_fptype> m_funcparam;
|
||||
std::vector<nl_fptype> m_funcparam;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// nld_CS - Current source
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT_DERIVED(CS, two_terminal)
|
||||
class nld_CS : public nld_two_terminal
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(CS)
|
||||
nld_CS(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
, m_t(*this, "m_t", nlconst::zero())
|
||||
, m_I(*this, "I", nlconst::one())
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_func(*this, "FUNC", "")
|
||||
, m_compiled(*this, "m_compiled")
|
||||
, m_funcparam({nlconst::zero()})
|
||||
{
|
||||
register_sub_alias("P", "1");
|
||||
register_sub_alias("N", "2");
|
||||
if (!m_func().empty())
|
||||
m_compiled->compile(m_func(), std::vector<pstring>({{pstring("T")}}));
|
||||
m_compiled->compile(m_func(),
|
||||
std::vector<pstring>({{pstring("T")}}));
|
||||
}
|
||||
|
||||
NETLIB_IS_TIMESTEP(!m_func().empty())
|
||||
@ -646,42 +635,43 @@ namespace netlist::analog
|
||||
m_t += step;
|
||||
m_funcparam[0] = m_t;
|
||||
const nl_fptype I = m_compiled->evaluate(m_funcparam);
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -I,
|
||||
zero, zero, I);
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -I, //
|
||||
zero, zero, I);
|
||||
}
|
||||
else
|
||||
m_t -= step;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
NETLIB_NAME(two_terminal)::reset();
|
||||
nld_two_terminal::reset();
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -m_I(),
|
||||
zero, zero, m_I());
|
||||
set_mat(zero, zero, -m_I(), //
|
||||
zero, zero, m_I());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
// FIXME: We only need to update the net first if this is a time stepping net
|
||||
//FIXME: works only for CS without function
|
||||
change_state([this]()
|
||||
{
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -m_I(),
|
||||
zero, zero, m_I());
|
||||
});
|
||||
// FIXME: We only need to update the net first if this is a time
|
||||
// stepping net
|
||||
// FIXME: works only for CS without function
|
||||
change_state(
|
||||
[this]()
|
||||
{
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -m_I(), //
|
||||
zero, zero, m_I());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
state_var<nl_fptype> m_t;
|
||||
param_fp_t m_I;
|
||||
param_str_t m_func;
|
||||
state_var<nl_fptype> m_t;
|
||||
param_fp_t m_I;
|
||||
param_str_t m_func;
|
||||
state_var<plib::pfunction<nl_fptype>> m_compiled;
|
||||
std::vector<nl_fptype> m_funcparam;
|
||||
std::vector<nl_fptype> m_funcparam;
|
||||
};
|
||||
|
||||
} // namespace netlist::analog
|
||||
|
102
src/lib/netlist/build/.clang-format
Normal file
102
src/lib/netlist/build/.clang-format
Normal file
@ -0,0 +1,102 @@
|
||||
Language: Cpp
|
||||
Standard: c++17
|
||||
UseTab: ForContinuationAndIndentation
|
||||
TabWidth: 4
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 80
|
||||
ContinuationIndentWidth: 4
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
NamespaceIndentation: All
|
||||
CompactNamespaces: true
|
||||
FixNamespaceComments: true
|
||||
|
||||
IndentAccessModifiers: false
|
||||
AccessModifierOffset: -4
|
||||
IndentCaseLabels: true
|
||||
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
# Currentline doesn't work
|
||||
# PackConstructorInitializers: CurrentLine >= 14
|
||||
BreakStringLiterals: false
|
||||
# Multiline does not work in clang-format 13
|
||||
# AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
# AfterComma does not work <= 13
|
||||
#BreakInheritanceList: AfterComma
|
||||
#BreakInheritanceList: BeforeComma
|
||||
#BreakInheritanceList: false
|
||||
SpaceBeforeInheritanceColon: true
|
||||
|
||||
#AlignAfterOpenBracket: DontAlign
|
||||
AlignAfterOpenBracket: Align
|
||||
PointerAlignment: Right
|
||||
SpacesInAngles: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
|
||||
PenaltyBreakComment: 1
|
||||
PenaltyBreakAssignment: 1000
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
|
||||
PenaltyReturnTypeOnItsOwnLine: 1
|
||||
|
||||
# SortIncludes: CaseSensitive # >= 13!
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
|
||||
IncludeCategories:
|
||||
- Regex: '^(("|"../)core)/'
|
||||
Priority: 20
|
||||
- Regex: '^(("|"../)analog)/'
|
||||
Priority: 21
|
||||
- Regex: '^(("|"../)devices)/'
|
||||
Priority: 22
|
||||
- Regex: '^(("|"../)solver)/'
|
||||
Priority: 23
|
||||
- Regex: '^(("|"../)plib)/'
|
||||
Priority: 30
|
||||
- Regex: '<[([:alnum:]|_).]+>'
|
||||
Priority: 40
|
||||
- Regex: '.*'
|
||||
Priority: 10
|
||||
|
||||
StatementMacros:
|
||||
- "NETLIB_DEVICE_IMPL_NS"
|
||||
- "TTL_7400_NAND"
|
||||
- "TTL_7402_NOR"
|
||||
- "NET_C"
|
||||
- "TRUTHTABLE_ENTRY"
|
||||
- "LOCAL_LIB_ENTRY"
|
||||
- "TT_HEAD"
|
||||
- "TT_LINE"
|
||||
- "TT_FAMILY"
|
||||
- "DIPPINS"
|
||||
|
||||
#StatementAttributeLikeMacros:
|
||||
# - "NETLIST_NAME"
|
||||
# - "NETLIB_NAME"
|
||||
|
||||
TypenameMacros:
|
||||
- "NETLIST_NAME"
|
||||
- "NETLIB_NAME"
|
||||
|
||||
IndentPPDirectives: BeforeHash
|
||||
MacroBlockBegin: "^static NETLIST_START\\(.*\\)|static TRUTHTABLE_START\\(.*\\)$"
|
||||
MacroBlockEnd: "^NETLIST_END\\(\\)|TRUTHTABLE_END\\(\\)$"
|
||||
# ReferenceAlignment: Middle
|
||||
# Avoid formatting (breaking) doxygen
|
||||
CommentPragmas: '^\\.+'
|
||||
# Avoid formatting cspell ignored comments
|
||||
CommentPragmas: '^#.+'
|
||||
# Avoid breaking tables
|
||||
CommentPragmas: '^\|.+'
|
||||
# Avoid breaking clang-tidy
|
||||
CommentPragmas: '^ NOLINT.+'
|
||||
|
@ -55,6 +55,7 @@ TIDY_FLAGSX += -modernize-use-auto,
|
||||
#TIDY_FLAGSX += -modernize-use-transparent-functors,
|
||||
TIDY_FLAGSX += -readability-function-cognitive-complexity,
|
||||
TIDY_FLAGSX += -readability-uppercase-literal-suffix
|
||||
TIDY_FLAGSX += -cert-err58-cpp
|
||||
|
||||
|
||||
#TIDY_FLAGSX += -cppcoreguidelines-avoid-non-const-global-variables
|
||||
@ -113,7 +114,7 @@ TIDY_DB = $(OBJ)/compile_commands.json
|
||||
#LTO decreases performance :-(
|
||||
#LTO = -flto=4 -fuse-linker-plugin -Wodr
|
||||
|
||||
CCOREFLAGS = -g -O3 -std=c++17 -I$(SRC) -I$(SRC)/..
|
||||
CCOREFLAGS = -g -O3 -std=c++17 -I$(SRC) -I$(SRC)/.. -I$(SRC)/../..
|
||||
|
||||
CFLAGS = $(LTO) $(CCOREFLAGS) $(CEXTRAFLAGS)
|
||||
LDFLAGS = $(LTO) -g -O3 -std=c++17 $(LDEXTRAFLAGS)
|
||||
@ -289,22 +290,20 @@ native:
|
||||
$(MAKE) CEXTRAFLAGS="-march=native -msse4.2 -Wall -Wpedantic -Wsign-compare -Wextra"
|
||||
|
||||
gcc9:
|
||||
$(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -Wall -pedantic -Wpedantic -fext-numeric-literals -Wsign-compare -Wextra" EXTRALIBS="-lquadmath" OBJ=obj/gcc9
|
||||
$(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -Wall -Wextra -pedantic -Wpedantic -pedantic-errors -fext-numeric-literals -Wsign-compare" EXTRALIBS="-lquadmath" OBJ=obj/gcc9
|
||||
|
||||
clang:
|
||||
#$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native -msse4.2 -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field -Wno-padded -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++-13 LD=clang++-13 OBJ=obj/clang CEXTRAFLAGS="-march=native \
|
||||
-mllvm -inline-threshold=2000 \
|
||||
-mllvm -inline-threshold=2000 \
|
||||
-Wunknown-warning-option \
|
||||
-Weverything -Wall -pedantic -Wpedantic -Wunused-private-field \
|
||||
-Weverything -Wall -pedantic -Wpedantic \
|
||||
-Werror -Wno-padded -Wno-weak-vtables -Wno-weak-template-vtables -Wunused-template \
|
||||
-Wmissing-variable-declarations -Wno-float-equal -Wconversion \
|
||||
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wformat-nonliteral \
|
||||
-Wno-exit-time-destructors -Winconsistent-missing-destructor-override \
|
||||
-Wno-embedded-directive \
|
||||
-Wno-float-equal \
|
||||
-Wno-c++98-compat -Wno-c++98-compat-pedantic \
|
||||
-Wno-exit-time-destructors \
|
||||
-Wno-undefined-reinterpret-cast -Wno-error=unused-macros \
|
||||
-Wunreachable-code \
|
||||
-Wmissing-prototypes -Wno-error=deprecated"
|
||||
-Wno-error=deprecated"
|
||||
|
||||
clang-libc:
|
||||
#clang-11 currently broken
|
||||
|
@ -20,23 +20,22 @@
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// analog_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class analog_t : public detail::core_terminal_t
|
||||
{
|
||||
public:
|
||||
|
||||
analog_t(core_device_t &dev, const pstring &aname, state_e state,
|
||||
nl_delegate delegate);
|
||||
|
||||
const analog_net_t & net() const noexcept
|
||||
const analog_net_t &net() const noexcept
|
||||
{
|
||||
return plib::downcast<const analog_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
|
||||
analog_net_t & net() noexcept
|
||||
analog_net_t &net() noexcept
|
||||
{
|
||||
return plib::downcast<analog_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
@ -53,24 +52,23 @@ namespace netlist
|
||||
class terminal_t : public analog_t
|
||||
{
|
||||
public:
|
||||
|
||||
/// \brief constructor
|
||||
///
|
||||
/// \param dev object owning the terminal
|
||||
/// \param aname name of this terminal
|
||||
/// \param other_terminal pointer to the sibling terminal
|
||||
terminal_t(core_device_t &dev, const pstring &aname, terminal_t *other_terminal, nl_delegate delegate);
|
||||
terminal_t(core_device_t &dev, const pstring &aname,
|
||||
terminal_t *other_terminal, nl_delegate delegate);
|
||||
|
||||
terminal_t(core_device_t &dev, const pstring &aname, terminal_t *other_terminal,
|
||||
const std::array<terminal_t *, 2> &splitter_terms, nl_delegate delegate);
|
||||
terminal_t(core_device_t &dev, const pstring &aname,
|
||||
terminal_t * other_terminal,
|
||||
const std::array<terminal_t *, 2> &splitter_terms,
|
||||
nl_delegate delegate);
|
||||
|
||||
/// \brief Returns voltage of connected net
|
||||
///
|
||||
/// \return voltage of net this terminal is connected to
|
||||
nl_fptype operator ()() const noexcept
|
||||
{
|
||||
return net().Q_Analog();
|
||||
}
|
||||
nl_fptype operator()() const noexcept { return net().Q_Analog(); }
|
||||
|
||||
/// \brief sets conductivity value of this terminal
|
||||
///
|
||||
@ -85,42 +83,33 @@ namespace netlist
|
||||
set_go_gt_I(GO, GT, nlconst::zero());
|
||||
}
|
||||
|
||||
void set_go_gt_I(nl_fptype GO, nl_fptype GT, nl_fptype I) const noexcept
|
||||
{
|
||||
// Check for rail nets ...
|
||||
if (m_go != nullptr)
|
||||
{
|
||||
*m_Idr = I;
|
||||
*m_go = GO;
|
||||
*m_gt = GT;
|
||||
}
|
||||
}
|
||||
void set_go_gt_I(nl_fptype GO, nl_fptype GT,
|
||||
nl_fptype I) const noexcept;
|
||||
|
||||
void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false);
|
||||
void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(
|
||||
false);
|
||||
|
||||
private:
|
||||
nl_fptype *m_Idr; ///< drive current
|
||||
nl_fptype *m_go; ///< conductance for Voltage from other term
|
||||
nl_fptype *m_gt; ///< conductance for total conductance
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// analog_input_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// \brief terminal providing analog input voltage.
|
||||
///
|
||||
/// This terminal class provides a voltage measurement. The conductance against
|
||||
/// ground is infinite.
|
||||
|
||||
/// This terminal class provides a voltage measurement. The conductance
|
||||
/// against ground is infinite.
|
||||
class analog_input_t : public analog_t
|
||||
{
|
||||
public:
|
||||
/// \brief Constructor
|
||||
analog_input_t(core_device_t &dev, ///< owning device
|
||||
const pstring &aname, ///< name of terminal
|
||||
nl_delegate delegate ///< delegate
|
||||
analog_input_t(core_device_t &dev, ///< owning device
|
||||
const pstring & aname, ///< name of terminal
|
||||
nl_delegate delegate ///< delegate
|
||||
);
|
||||
|
||||
/// \brief returns voltage at terminal.
|
||||
@ -129,29 +118,19 @@ namespace netlist
|
||||
|
||||
/// \brief returns voltage at terminal.
|
||||
/// \returns voltage at terminal.
|
||||
nl_fptype Q_Analog() const noexcept
|
||||
{
|
||||
return net().Q_Analog();
|
||||
}
|
||||
nl_fptype Q_Analog() const noexcept { return net().Q_Analog(); }
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// analog_output_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class analog_output_t : public analog_t
|
||||
{
|
||||
public:
|
||||
analog_output_t(core_device_t &dev, const pstring &aname);
|
||||
|
||||
void push(nl_fptype val) noexcept
|
||||
{
|
||||
if (val != m_my_net.Q_Analog())
|
||||
{
|
||||
m_my_net.set_Q_Analog(val);
|
||||
m_my_net.toggle_and_push_to_queue(netlist_time::quantum());
|
||||
}
|
||||
}
|
||||
void push(nl_fptype val) noexcept;
|
||||
|
||||
void initial(nl_fptype val) noexcept;
|
||||
|
||||
@ -159,12 +138,36 @@ namespace netlist
|
||||
analog_net_t m_my_net;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// out of class
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
inline solver::matrix_solver_t *analog_t::solver() const noexcept
|
||||
{
|
||||
return (this->has_net() ? net().solver() : nullptr);
|
||||
}
|
||||
|
||||
inline void terminal_t::set_go_gt_I(nl_fptype GO, nl_fptype GT,
|
||||
nl_fptype I) const noexcept
|
||||
{
|
||||
// Check for rail nets ...
|
||||
if (m_go != nullptr)
|
||||
{
|
||||
*m_Idr = I;
|
||||
*m_go = GO;
|
||||
*m_gt = GT;
|
||||
}
|
||||
}
|
||||
|
||||
inline void analog_output_t::push(nl_fptype val) noexcept
|
||||
{
|
||||
if (val != m_my_net.Q_Analog())
|
||||
{
|
||||
m_my_net.set_Q_Analog(val);
|
||||
m_my_net.toggle_and_push_to_queue(netlist_time::quantum());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_ANALOG_H_
|
||||
|
@ -8,11 +8,10 @@
|
||||
#ifndef NL_CORE_BASE_OBJECTS_H_
|
||||
#define NL_CORE_BASE_OBJECTS_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "netlist_state.h"
|
||||
#include "state_var.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "../plib/palloc.h"
|
||||
#include "../plib/pchrono.h"
|
||||
#include "../plib/pexception.h"
|
||||
@ -21,7 +20,8 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace netlist::detail {
|
||||
namespace netlist::detail
|
||||
{
|
||||
|
||||
template <typename C, typename T>
|
||||
struct property_store_t
|
||||
@ -30,30 +30,44 @@ namespace netlist::detail {
|
||||
using key_type = const C *;
|
||||
using store_type = std::unordered_map<key_type, value_type>;
|
||||
|
||||
static void add(key_type obj, const value_type &aname) noexcept
|
||||
static void add(key_type obj, const value_type &value) noexcept
|
||||
{
|
||||
store().insert({obj, aname});
|
||||
try
|
||||
{
|
||||
store().insert({obj, value});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
plib::terminate("exception in property_store_t.add()");
|
||||
}
|
||||
}
|
||||
|
||||
static value_type *get(key_type obj) noexcept
|
||||
static const value_type &get(key_type obj) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
typename store_type::iterator ret(store().find(obj));
|
||||
if (ret == store().end())
|
||||
return nullptr;
|
||||
return &ret->second;
|
||||
plib::terminate(
|
||||
"object not found in property_store_t.get()");
|
||||
return ret->second;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
plib::terminate("exception in property_store_t.get()");
|
||||
return static_cast<value_type *>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove(key_type obj) noexcept
|
||||
{
|
||||
store().erase(store().find(obj));
|
||||
try
|
||||
{
|
||||
store().erase(store().find(obj));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
plib::terminate("exception in property_store_t.remove()");
|
||||
}
|
||||
}
|
||||
|
||||
static store_type &store() noexcept
|
||||
@ -61,12 +75,11 @@ namespace netlist::detail {
|
||||
static store_type static_store;
|
||||
return static_store;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// object_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// \brief The base class for netlist devices, terminals and parameters.
|
||||
///
|
||||
@ -76,36 +89,25 @@ namespace netlist::detail {
|
||||
class object_t
|
||||
{
|
||||
public:
|
||||
|
||||
/// \brief Constructor.
|
||||
/// Every class derived from the object_t class must have a name.
|
||||
///
|
||||
/// \param aname string containing name of the object
|
||||
|
||||
explicit object_t(const pstring &aname)
|
||||
{
|
||||
props::add(this, aname);
|
||||
}
|
||||
explicit object_t(const pstring &aname) { props::add(this, aname); }
|
||||
|
||||
PCOPYASSIGNMOVE(object_t, delete)
|
||||
/// \brief return name of the object
|
||||
///
|
||||
/// \returns name of the object.
|
||||
|
||||
const pstring &name() const noexcept
|
||||
{
|
||||
return *props::get(this);
|
||||
}
|
||||
const pstring &name() const noexcept { return props::get(this); }
|
||||
|
||||
protected:
|
||||
|
||||
using props = property_store_t<object_t, pstring>;
|
||||
|
||||
// only childs should be destructible
|
||||
~object_t() noexcept
|
||||
{
|
||||
props::remove(this);
|
||||
}
|
||||
~object_t() noexcept { props::remove(this); }
|
||||
|
||||
private:
|
||||
};
|
||||
@ -122,33 +124,34 @@ namespace netlist::detail {
|
||||
explicit netlist_object_t(netlist_t &nl, const pstring &name)
|
||||
: object_t(name)
|
||||
, m_netlist(nl)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
~netlist_object_t() = default;
|
||||
|
||||
PCOPYASSIGNMOVE(netlist_object_t, delete)
|
||||
|
||||
netlist_state_t & state() noexcept;
|
||||
const netlist_state_t & state() const noexcept;
|
||||
netlist_state_t & state() noexcept;
|
||||
const netlist_state_t &state() const noexcept;
|
||||
|
||||
constexpr netlist_t & exec() noexcept { return m_netlist; }
|
||||
constexpr const netlist_t & exec() const noexcept { return m_netlist; }
|
||||
constexpr netlist_t & exec() noexcept { return m_netlist; }
|
||||
constexpr const netlist_t &exec() const noexcept { return m_netlist; }
|
||||
|
||||
// to ease template design
|
||||
template <typename T, typename... Args>
|
||||
device_arena::unique_ptr<T> make_pool_object(Args&&... args)
|
||||
device_arena::unique_ptr<T> make_pool_object(Args &&...args) noexcept(
|
||||
false)
|
||||
{
|
||||
return state().make_pool_object<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
netlist_t & m_netlist;
|
||||
|
||||
netlist_t &m_netlist;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// device_object_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// \brief Base class for all objects being owned by a device.
|
||||
///
|
||||
@ -171,31 +174,32 @@ namespace netlist::detail {
|
||||
/// \brief returns reference to owning device.
|
||||
/// \returns reference to owning device.
|
||||
|
||||
core_device_t &device() noexcept { return *m_device; }
|
||||
core_device_t & device() noexcept { return *m_device; }
|
||||
const core_device_t &device() const noexcept { return *m_device; }
|
||||
|
||||
/// \brief The netlist owning the owner of this object.
|
||||
/// \returns reference to netlist object.
|
||||
|
||||
netlist_state_t &state() noexcept;
|
||||
netlist_state_t & state() noexcept;
|
||||
const netlist_state_t &state() const noexcept;
|
||||
|
||||
private:
|
||||
core_device_t * m_device;
|
||||
core_device_t *m_device;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// core_terminal_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// \brief Base class for all terminals.
|
||||
///
|
||||
/// All terminals are derived from this class.
|
||||
///
|
||||
class core_terminal_t : public device_object_t
|
||||
, public plib::linked_list_t<core_terminal_t, 0>::element_t
|
||||
class core_terminal_t
|
||||
: public device_object_t
|
||||
, public plib::linked_list_t<core_terminal_t, 0>::element_t
|
||||
#if NL_USE_INPLACE_CORE_TERMS
|
||||
, public plib::linked_list_t<core_terminal_t, 1>::element_t
|
||||
, public plib::linked_list_t<core_terminal_t, 1>::element_t
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
@ -213,19 +217,21 @@ namespace netlist::detail {
|
||||
|
||||
static constexpr netlist_sig_t OUT_TRISTATE() { return INP_MASK; }
|
||||
|
||||
static_assert(INP_BITS * 2 <= sizeof(netlist_sig_t) * 8, "netlist_sig_t size not sufficient");
|
||||
static_assert(INP_BITS * 2 <= sizeof(netlist_sig_t) * 8,
|
||||
"netlist_sig_t size not sufficient");
|
||||
|
||||
enum state_e {
|
||||
enum state_e
|
||||
{
|
||||
STATE_INP_PASSIVE = 0,
|
||||
STATE_INP_HL = (INP_MASK << INP_HL_SHIFT),
|
||||
STATE_INP_LH = (INP_MASK << INP_LH_SHIFT),
|
||||
STATE_INP_ACTIVE = STATE_INP_HL | STATE_INP_LH,
|
||||
STATE_OUT = (1 << (2*INP_BITS)),
|
||||
STATE_BIDIR = (1 << (2*INP_BITS + 1))
|
||||
STATE_INP_HL = (INP_MASK << INP_HL_SHIFT),
|
||||
STATE_INP_LH = (INP_MASK << INP_LH_SHIFT),
|
||||
STATE_INP_ACTIVE = STATE_INP_HL | STATE_INP_LH,
|
||||
STATE_OUT = (1 << (2 * INP_BITS)),
|
||||
STATE_BIDIR = (1 << (2 * INP_BITS + 1))
|
||||
};
|
||||
|
||||
core_terminal_t(core_device_t &dev, const pstring &aname,
|
||||
state_e state, nl_delegate delegate);
|
||||
core_terminal_t(core_device_t &dev, const pstring &aname, state_e state,
|
||||
nl_delegate delegate);
|
||||
virtual ~core_terminal_t() noexcept = default;
|
||||
|
||||
PCOPYASSIGNMOVE(core_terminal_t, delete)
|
||||
@ -237,13 +243,16 @@ namespace netlist::detail {
|
||||
/// \brief 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(false) { return (type() == atype); }
|
||||
bool is_type(const terminal_type atype) const noexcept(false)
|
||||
{
|
||||
return (type() == atype);
|
||||
}
|
||||
|
||||
void set_net(net_t *anet) noexcept { m_net = anet; }
|
||||
void clear_net() noexcept { m_net = nullptr; }
|
||||
void set_net(net_t *anet) noexcept { m_net = anet; }
|
||||
void clear_net() noexcept { m_net = nullptr; }
|
||||
constexpr bool has_net() const noexcept { return (m_net != nullptr); }
|
||||
|
||||
constexpr net_t & net() const noexcept { return *m_net;}
|
||||
constexpr net_t &net() const noexcept { return *m_net; }
|
||||
|
||||
bool is_logic() const noexcept;
|
||||
bool is_logic_input() const noexcept;
|
||||
@ -253,13 +262,21 @@ namespace netlist::detail {
|
||||
bool is_analog_input() const noexcept;
|
||||
bool is_analog_output() const noexcept;
|
||||
|
||||
constexpr bool is_state(state_e state) const noexcept { return (m_state == state); }
|
||||
constexpr bool is_state(state_e state) const noexcept
|
||||
{
|
||||
return (m_state == state);
|
||||
}
|
||||
constexpr state_e terminal_state() const noexcept { return m_state; }
|
||||
constexpr void set_state(state_e state) noexcept { m_state = state; }
|
||||
constexpr void set_state(state_e state) noexcept { m_state = state; }
|
||||
|
||||
void reset() noexcept { set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); }
|
||||
void reset() noexcept
|
||||
{
|
||||
set_state(
|
||||
is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE);
|
||||
}
|
||||
|
||||
constexpr void set_copied_input([[maybe_unused]] netlist_sig_t val) noexcept
|
||||
constexpr void set_copied_input(
|
||||
[[maybe_unused]] netlist_sig_t val) noexcept
|
||||
{
|
||||
if constexpr (config::use_copy_instead_of_reference::value)
|
||||
{
|
||||
@ -267,20 +284,24 @@ namespace netlist::detail {
|
||||
}
|
||||
}
|
||||
|
||||
void set_delegate(const nl_delegate &delegate) noexcept { m_delegate = delegate; }
|
||||
void set_delegate(const nl_delegate &delegate) noexcept
|
||||
{
|
||||
m_delegate = delegate;
|
||||
}
|
||||
const nl_delegate &delegate() const noexcept { return m_delegate; }
|
||||
void run_delegate() const noexcept { return m_delegate(); }
|
||||
|
||||
protected:
|
||||
//std::conditional_t<config::use_copy_instead_of_reference::value, state_var_sig, void *> m_Q;
|
||||
// std::conditional_t<config::use_copy_instead_of_reference::value,
|
||||
// state_var_sig, void *> m_Q;
|
||||
state_var_sig m_Q_CIR;
|
||||
|
||||
private:
|
||||
nl_delegate m_delegate;
|
||||
net_t * m_net;
|
||||
nl_delegate m_delegate;
|
||||
net_t * m_net;
|
||||
state_var<state_e> m_state;
|
||||
};
|
||||
|
||||
|
||||
} // namespace netlist::detail
|
||||
|
||||
|
||||
#endif // NL_CORE_BASE_OBJECTS_H_
|
||||
|
@ -9,21 +9,60 @@
|
||||
#define NL_CORE_DEVICE_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/pstring.h"
|
||||
#include "base_objects.h"
|
||||
#include "logic_family.h"
|
||||
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// core_device_t construction parameters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
struct core_device_data_t
|
||||
{
|
||||
friend class core_device_t;
|
||||
friend class base_device_t;
|
||||
friend class analog::NETLIB_NAME(two_terminal);
|
||||
friend class logic_family_std_proxy_t;
|
||||
|
||||
template <unsigned m_NI, unsigned m_NO>
|
||||
friend class devices::factory_truth_table_t;
|
||||
|
||||
template <class C, typename... Args>
|
||||
friend class factory::device_element_t;
|
||||
friend class factory::library_element_t;
|
||||
|
||||
template <typename CX>
|
||||
friend struct sub_device_wrapper;
|
||||
|
||||
friend class solver::matrix_solver_t;
|
||||
|
||||
private:
|
||||
core_device_data_t(netlist_state_t &o, const pstring &n)
|
||||
: owner(o)
|
||||
, name(n)
|
||||
{
|
||||
}
|
||||
netlist_state_t &owner;
|
||||
const pstring & name;
|
||||
};
|
||||
|
||||
// The type use to pass data on
|
||||
using core_device_param_t = const core_device_data_t &;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// core_device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// FIXME: belongs into detail namespace
|
||||
|
||||
class core_device_t : public detail::netlist_object_t
|
||||
{
|
||||
public:
|
||||
core_device_t(netlist_state_t &owner, const pstring &name);
|
||||
core_device_t(core_device_t &owner, const pstring &name);
|
||||
using constructor_data_t = core_device_data_t;
|
||||
using constructor_param_t = core_device_param_t;
|
||||
|
||||
core_device_t(core_device_param_t data);
|
||||
|
||||
core_device_t(const core_device_t &) = delete;
|
||||
core_device_t &operator=(const core_device_t &) = delete;
|
||||
@ -50,25 +89,25 @@ namespace netlist
|
||||
plib::pperfcount_t<true> m_stat_inc_active;
|
||||
};
|
||||
|
||||
stats_t * stats() const noexcept { return m_stats.get(); }
|
||||
stats_t *stats() const noexcept { return m_stats.get(); }
|
||||
|
||||
virtual void reset() { }
|
||||
virtual void reset() {}
|
||||
|
||||
void handler_noop()
|
||||
{
|
||||
}
|
||||
void handler_noop() {}
|
||||
|
||||
protected:
|
||||
using activate_delegate = plib::pmfp<void (bool)>;
|
||||
using activate_delegate = plib::pmfp<void(bool)>;
|
||||
|
||||
activate_delegate m_activate;
|
||||
|
||||
log_type & log();
|
||||
log_type &log();
|
||||
|
||||
public:
|
||||
virtual void time_step([[maybe_unused]] time_step_type ts_type,
|
||||
[[maybe_unused]] nl_fptype st) noexcept { }
|
||||
virtual void update_terminals() noexcept { }
|
||||
[[maybe_unused]] nl_fptype st) noexcept
|
||||
{
|
||||
}
|
||||
virtual void update_terminals() noexcept {}
|
||||
|
||||
virtual void update_param() noexcept {}
|
||||
virtual bool is_dynamic() const noexcept { return false; }
|
||||
@ -76,8 +115,8 @@ namespace netlist
|
||||
|
||||
private:
|
||||
// FIXME: should this be a state_var?
|
||||
bool m_hint_deactivate;
|
||||
state_var_s32 m_active_outputs;
|
||||
bool m_hint_deactivate;
|
||||
state_var_s32 m_active_outputs;
|
||||
device_arena::unique_ptr<stats_t> m_stats;
|
||||
};
|
||||
|
||||
@ -91,7 +130,7 @@ namespace netlist
|
||||
{
|
||||
if (m_stats)
|
||||
m_stats->m_stat_inc_active.inc();
|
||||
m_activate(true);//inc_active();
|
||||
m_activate(true); // inc_active();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,44 +142,62 @@ namespace netlist
|
||||
if (!m_activate.isnull() && m_hint_deactivate)
|
||||
if (--m_active_outputs == 0)
|
||||
{
|
||||
m_activate(false); //dec_active();
|
||||
m_activate(false); // dec_active();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// core_device_t construction parameters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
using base_device_data_t = core_device_data_t;
|
||||
// The type use to pass data on
|
||||
using base_device_param_t = const base_device_data_t &;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// base_device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class base_device_t : public core_device_t
|
||||
class base_device_t : public core_device_t
|
||||
{
|
||||
public:
|
||||
base_device_t(netlist_state_t &owner, const pstring &name);
|
||||
base_device_t(base_device_t &owner, const pstring &name);
|
||||
using constructor_data_t = base_device_data_t;
|
||||
using constructor_param_t = base_device_param_t;
|
||||
|
||||
base_device_t(base_device_param_t data);
|
||||
|
||||
PCOPYASSIGNMOVE(base_device_t, delete)
|
||||
|
||||
~base_device_t() noexcept override = default;
|
||||
|
||||
template <class O, class C, typename... Args>
|
||||
void create_and_register_sub_device(O& owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args)
|
||||
void create_and_register_sub_device(O &owner, const pstring &name,
|
||||
device_arena::unique_ptr<C> &dev, Args &&...args)
|
||||
{
|
||||
dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...);
|
||||
// dev = state().make_pool_object<C>(owner, name,
|
||||
// std::forward<Args>(args)...);
|
||||
using dev_constructor_data_t = typename C::constructor_data_t;
|
||||
dev = state().make_pool_object<C>(
|
||||
dev_constructor_data_t{state(), owner.name() + "." + name},
|
||||
std::forward<Args>(args)...);
|
||||
state().register_device(dev->name(),
|
||||
device_arena::owned_ptr<core_device_t>(dev.get(), false));
|
||||
}
|
||||
|
||||
void register_sub_alias(const pstring &name, const detail::core_terminal_t &term);
|
||||
void register_sub_alias(const pstring &name,
|
||||
const detail::core_terminal_t & term);
|
||||
void register_sub_alias(const pstring &name, const pstring &aliased);
|
||||
|
||||
void connect(const pstring &t1, const pstring &t2);
|
||||
void connect(const detail::core_terminal_t &t1, const detail::core_terminal_t &t2);
|
||||
protected:
|
||||
void connect(const detail::core_terminal_t &t1,
|
||||
const detail::core_terminal_t & t2);
|
||||
|
||||
//NETLIB_UPDATE_TERMINALSI() { }
|
||||
protected:
|
||||
// NETLIB_UPDATE_TERMINALSI() { }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_DEVICE_H_
|
||||
|
@ -9,29 +9,35 @@
|
||||
#define NL_DEVICE_H_
|
||||
|
||||
#include "core_device.h"
|
||||
#include "logic_family.h"
|
||||
#include "param.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class device_t : public base_device_t,
|
||||
public logic_family_t
|
||||
// -------------------------------------------------------------------------
|
||||
// device_t construction parameters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
using device_data_t = base_device_data_t;
|
||||
// The type use to pass data on
|
||||
using device_param_t = const device_data_t &;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// device_t
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class device_t : public base_device_t, public logic_family_t
|
||||
{
|
||||
public:
|
||||
device_t(netlist_state_t &owner, const pstring &name);
|
||||
device_t(netlist_state_t &owner, const pstring &name,
|
||||
const pstring &model);
|
||||
// only needed by proxies
|
||||
device_t(netlist_state_t &owner, const pstring &name,
|
||||
const logic_family_desc_t *desc);
|
||||
using constructor_data_t = device_data_t;
|
||||
using constructor_param_t = device_param_t;
|
||||
|
||||
device_t(device_t &owner, const pstring &name);
|
||||
// pass in a default model - this may be overwritten by PARAM(DEVICE.MODEL, "XYZ(...)")
|
||||
device_t(device_t &owner, const pstring &name,
|
||||
const pstring &model);
|
||||
device_t(device_param_t data);
|
||||
|
||||
device_t(device_param_t data, const pstring &model);
|
||||
// only needed by proxies
|
||||
device_t(device_param_t data, const logic_family_desc_t *desc);
|
||||
|
||||
device_t(const device_t &) = delete;
|
||||
device_t &operator=(const device_t &) = delete;
|
||||
@ -42,8 +48,9 @@ namespace netlist
|
||||
|
||||
protected:
|
||||
template <typename T1, typename T2>
|
||||
void push_two(T1 &term1, netlist_sig_t newQ1, const netlist_time &delay1,
|
||||
T2 &term2, netlist_sig_t newQ2, const netlist_time &delay2) noexcept
|
||||
void push_two(T1 &term1, netlist_sig_t newQ1,
|
||||
const netlist_time &delay1, T2 &term2, netlist_sig_t newQ2,
|
||||
const netlist_time &delay2) noexcept
|
||||
{
|
||||
if (delay2 < delay1)
|
||||
{
|
||||
@ -57,13 +64,51 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//NETLIB_UPDATE_TERMINALSI() { }
|
||||
// NETLIB_UPDATE_TERMINALSI() { }
|
||||
private:
|
||||
param_model_t m_model;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// FIXME: Rename
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
template <typename CX>
|
||||
struct sub_device_wrapper
|
||||
{
|
||||
using constructor_data_t = typename CX::constructor_data_t;
|
||||
using constructor_param_t = typename CX::constructor_param_t;
|
||||
|
||||
template <typename... Args>
|
||||
sub_device_wrapper(base_device_t &owner, const pstring &name,
|
||||
Args &&...args)
|
||||
{
|
||||
// m_dev = owner.state().make_pool_object<CX>(owner, name,
|
||||
// std::forward<Args>(args)...);
|
||||
m_dev = owner.state().make_pool_object<CX>(
|
||||
constructor_data_t{owner.state(), owner.name() + "." + name},
|
||||
std::forward<Args>(args)...);
|
||||
owner.state().register_device(m_dev->name(),
|
||||
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
|
||||
}
|
||||
template <typename... Args>
|
||||
sub_device_wrapper(device_t &owner, const pstring &name, Args &&...args)
|
||||
{
|
||||
// m_dev = owner.state().make_pool_object<CX>(owner, name,
|
||||
// std::forward<Args>(args)...);
|
||||
m_dev = owner.state().make_pool_object<CX>(
|
||||
constructor_data_t{owner.state(), owner.name() + "." + name},
|
||||
std::forward<Args>(args)...);
|
||||
owner.state().register_device(m_dev->name(),
|
||||
device_arena::owned_ptr<core_device_t>(m_dev.get(), false));
|
||||
}
|
||||
CX & operator()() { return *m_dev; }
|
||||
const CX &operator()() const { return *m_dev; }
|
||||
|
||||
private:
|
||||
device_arena::unique_ptr<CX> m_dev;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_DEVICE_H_
|
||||
|
@ -8,9 +8,9 @@
|
||||
/// \file device_macros.h
|
||||
///
|
||||
|
||||
//============================================================
|
||||
// -----------------------------------------------------------------------------
|
||||
// MACROS / New Syntax
|
||||
//============================================================
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// \brief Start a netlist device class.
|
||||
///
|
||||
@ -25,45 +25,20 @@
|
||||
///
|
||||
/// Also refer to #NETLIB_CONSTRUCTOR.
|
||||
#define NETLIB_OBJECT(name) \
|
||||
class NETLIB_NAME(name) : public delegator_t<device_t>
|
||||
|
||||
/// \brief Start a derived netlist device class.
|
||||
///
|
||||
/// Used to define a derived device class based on `plcass`.
|
||||
/// The simplest device without inputs or outputs would look like this:
|
||||
///
|
||||
/// NETLIB_OBJECT_DERIVED(some_object, parent_object)
|
||||
/// {
|
||||
/// public:
|
||||
/// NETLIB_CONSTRUCTOR(some_object) { }
|
||||
/// };
|
||||
///
|
||||
/// Also refer to #NETLIB_CONSTRUCTOR.
|
||||
#define NETLIB_OBJECT_DERIVED(name, pclass) \
|
||||
class NETLIB_NAME(name) : public delegator_t<NETLIB_NAME(pclass)>
|
||||
|
||||
|
||||
|
||||
// Only used for analog objects like diodes and resistors
|
||||
|
||||
#define NETLIB_BASE_OBJECT(name) \
|
||||
class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
|
||||
#define NETLIB_CONSTRUCTOR_PASS(cname, ...) \
|
||||
using this_type = NETLIB_NAME(cname); \
|
||||
public: template <class CLASS> NETLIB_NAME(cname)(CLASS &owner, const pstring &name) \
|
||||
: base_type(owner, name, __VA_ARGS__)
|
||||
class NETLIB_NAME(name) \
|
||||
: public device_t
|
||||
|
||||
/// \brief Used to define the constructor of a netlist device.
|
||||
///
|
||||
/// Use this to define the constructor of a netlist device. Please refer to
|
||||
/// #NETLIB_OBJECT for an example.
|
||||
#define NETLIB_CONSTRUCTOR(cname) \
|
||||
using this_type = NETLIB_NAME(cname); \
|
||||
public: template <class CLASS> NETLIB_NAME(cname)(CLASS &owner, const pstring &name)\
|
||||
: base_type(owner, name)
|
||||
public: \
|
||||
NETLIB_NAME(cname)(constructor_param_t data) \
|
||||
: device_t(data)
|
||||
|
||||
/// \brief Used to define the constructor of a netlist device and define a default model.
|
||||
/// \brief Used to define the constructor of a netlist device and define a
|
||||
/// default model.
|
||||
///
|
||||
///
|
||||
/// NETLIB_CONSTRUCTOR_MODEL(some_object, "TTL")
|
||||
@ -72,22 +47,16 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
/// NETLIB_CONSTRUCTOR(some_object) { }
|
||||
/// };
|
||||
///
|
||||
#define NETLIB_CONSTRUCTOR_MODEL(cname, cmodel) \
|
||||
using this_type = NETLIB_NAME(cname); \
|
||||
public: template <class CLASS> NETLIB_NAME(cname)(CLASS &owner, const pstring &name) \
|
||||
: base_type(owner, name, cmodel)
|
||||
|
||||
/// \brief Define an extended constructor and add further parameters to it.
|
||||
/// The macro allows to add further parameters to a device constructor. This is
|
||||
/// normally used for sub-devices and system devices only.
|
||||
#define NETLIB_CONSTRUCTOR_EX(cname, ...) \
|
||||
using this_type = NETLIB_NAME(cname); \
|
||||
public: template <class CLASS> NETLIB_NAME(cname)(CLASS &owner, const pstring &name, __VA_ARGS__) \
|
||||
: base_type(owner, name)
|
||||
#define NETLIB_CONSTRUCTOR_MODEL(cname, cmodel) \
|
||||
public: \
|
||||
NETLIB_NAME(cname)(constructor_param_t data) \
|
||||
: device_t(data, cmodel)
|
||||
|
||||
/// \brief 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 override
|
||||
#define NETLIB_DESTRUCTOR(name) \
|
||||
public: \
|
||||
virtual ~NETLIB_NAME(name)() noexcept override
|
||||
|
||||
/// \brief Add this to a device definition to mark the device as dynamic.
|
||||
///
|
||||
@ -102,9 +71,11 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
/// \param expr boolean expression
|
||||
///
|
||||
#define NETLIB_IS_DYNAMIC(expr) \
|
||||
public: virtual bool is_dynamic() const noexcept override { return expr; }
|
||||
public: \
|
||||
virtual bool is_dynamic() const noexcept override { return expr; }
|
||||
|
||||
/// \brief Add this to a device definition to mark the device as a time-stepping device.
|
||||
/// \brief Add this to a device definition to mark the device as a time-stepping
|
||||
/// device.
|
||||
///
|
||||
/// You have to implement NETLIB_TIMESTEP in this case as well. Currently, only
|
||||
/// the capacitor and inductor devices uses this.
|
||||
@ -127,14 +98,17 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
/// \endcode
|
||||
|
||||
#define NETLIB_IS_TIMESTEP(expr) \
|
||||
public: virtual bool is_time_step() const noexcept override { return expr; }
|
||||
public: \
|
||||
virtual bool is_time_step() const noexcept override { return expr; }
|
||||
|
||||
/// \brief Used to implement the time stepping code.
|
||||
///
|
||||
/// Please see \ref NETLIB_IS_TIMESTEP for an example.
|
||||
|
||||
#define NETLIB_TIMESTEPI() \
|
||||
public: virtual void time_step(time_step_type ts_type, nl_fptype step) noexcept override
|
||||
public: \
|
||||
virtual void time_step(time_step_type ts_type, \
|
||||
nl_fptype step) noexcept override
|
||||
|
||||
/// \brief Used to implement the body of the time stepping code.
|
||||
///
|
||||
@ -145,26 +119,36 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
/// \param cname Name of object as given to \ref NETLIB_OBJECT
|
||||
///
|
||||
#define NETLIB_TIMESTEP(cname) \
|
||||
void NETLIB_NAME(cname) :: time_step(time_step_type ts_type, nl_fptype step) noexcept
|
||||
void NETLIB_NAME(cname)::time_step(time_step_type ts_type, \
|
||||
nl_fptype step) noexcept
|
||||
|
||||
#define NETLIB_DELEGATE(name) nl_delegate(&this_type :: name, this)
|
||||
//#define NETLIB_DELEGATE(name) nl_delegate(&this_type :: name, this)
|
||||
#define NETLIB_DELEGATE(name) \
|
||||
nl_delegate(&std::remove_pointer_t<decltype(this)>::name, this)
|
||||
|
||||
#define NETLIB_DELEGATE_NOOP() nl_delegate(&core_device_t::handler_noop, static_cast<core_device_t *>(this))
|
||||
#define NETLIB_DELEGATE_NOOP() \
|
||||
nl_delegate(&core_device_t::handler_noop, \
|
||||
static_cast<core_device_t *>(this))
|
||||
|
||||
#define NETLIB_UPDATE_TERMINALSI() virtual void update_terminals() noexcept override
|
||||
#define NETLIB_UPDATE_TERMINALSI() \
|
||||
virtual void update_terminals() noexcept override
|
||||
#define NETLIB_HANDLERI(name) void name() noexcept
|
||||
#define NETLIB_UPDATE_PARAMI() virtual void update_param() noexcept override
|
||||
#define NETLIB_RESETI() virtual void reset() override
|
||||
|
||||
#define NETLIB_SUB(chip) nld_ ## chip
|
||||
#define NETLIB_SUB_UPTR(ns, chip) device_arena::unique_ptr< ns :: nld_ ## chip >
|
||||
#define NETLIB_SUB(chip) sub_device_wrapper<nld_##chip>
|
||||
#define NETLIB_SUB_NS(ns, chip) sub_device_wrapper<ns ::nld_##chip>
|
||||
|
||||
#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name() noexcept
|
||||
#define NETLIB_SUB_UPTR(ns, chip) device_arena::unique_ptr<ns ::nld_##chip>
|
||||
|
||||
#define NETLIB_RESET(chip) void NETLIB_NAME(chip) :: reset(void)
|
||||
#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip)::name() noexcept
|
||||
|
||||
#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param() noexcept
|
||||
#define NETLIB_RESET(chip) void NETLIB_NAME(chip)::reset(void)
|
||||
|
||||
#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals() noexcept
|
||||
#define NETLIB_UPDATE_PARAM(chip) \
|
||||
void NETLIB_NAME(chip)::update_param() noexcept
|
||||
|
||||
#define NETLIB_UPDATE_TERMINALS(chip) \
|
||||
void NETLIB_NAME(chip)::update_terminals() noexcept
|
||||
|
||||
#endif // NL_CORE_DEVICE_MACROS_H_
|
||||
|
@ -30,25 +30,23 @@ namespace netlist::devices
|
||||
NETLIB_OBJECT(mainclock)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(mainclock)
|
||||
, m_Q(*this, "Q")
|
||||
, m_freq(*this, "FREQ", nlconst::magic(7159000.0 * 5))
|
||||
, m_Q(*this, "Q"), m_freq(*this, "FREQ", nlconst::magic(7159000.0 * 5))
|
||||
{
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*nlconst::two()));
|
||||
m_inc = netlist_time::from_fp(
|
||||
plib::reciprocal(m_freq() * nlconst::two()));
|
||||
}
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_Q.net().set_next_scheduled_time(exec().time());
|
||||
}
|
||||
NETLIB_RESETI() { m_Q.net().set_next_scheduled_time(exec().time()); }
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*nlconst::two()));
|
||||
m_inc = netlist_time::from_fp(
|
||||
plib::reciprocal(m_freq() * nlconst::two()));
|
||||
}
|
||||
|
||||
public:
|
||||
logic_output_t m_Q; // NOLINT: needed in core
|
||||
netlist_time m_inc; // NOLINT: needed in core
|
||||
logic_output_t m_Q; // NOLINT: needed in core
|
||||
netlist_time m_inc; // NOLINT: needed in core
|
||||
private:
|
||||
param_fp_t m_freq;
|
||||
};
|
||||
@ -65,7 +63,7 @@ namespace netlist::devices
|
||||
class nld_power_pins
|
||||
{
|
||||
public:
|
||||
using this_type = nld_power_pins;
|
||||
using constructor_type = nld_power_pins;
|
||||
|
||||
explicit nld_power_pins(device_t &owner)
|
||||
: m_VCC(owner, owner.logic_family()->vcc_pin(), NETLIB_DELEGATE(noop))
|
||||
@ -80,33 +78,26 @@ namespace netlist::devices
|
||||
}
|
||||
|
||||
// Some devices like the 74LS629 have two pairs of supply pins.
|
||||
explicit nld_power_pins(device_t &owner,
|
||||
const pstring &vcc, const pstring &gnd)
|
||||
explicit nld_power_pins(device_t &owner, const pstring &vcc,
|
||||
const pstring &gnd)
|
||||
: m_VCC(owner, vcc, NETLIB_DELEGATE(noop))
|
||||
, m_GND(owner, gnd, NETLIB_DELEGATE(noop))
|
||||
{
|
||||
}
|
||||
|
||||
// Some devices like the 74LS629 have two pairs of supply pins.
|
||||
explicit nld_power_pins(device_t &owner,
|
||||
const pstring &vcc, const pstring &gnd,
|
||||
nl_delegate delegate)
|
||||
explicit nld_power_pins(device_t &owner, const pstring &vcc,
|
||||
const pstring &gnd, nl_delegate delegate)
|
||||
: m_VCC(owner, vcc, delegate)
|
||||
, m_GND(owner, gnd, delegate)
|
||||
{
|
||||
}
|
||||
|
||||
const analog_input_t &VCC() const noexcept
|
||||
{
|
||||
return m_VCC;
|
||||
}
|
||||
const analog_input_t &GND() const noexcept
|
||||
{
|
||||
return m_GND;
|
||||
}
|
||||
const analog_input_t &VCC() const noexcept { return m_VCC; }
|
||||
const analog_input_t &GND() const noexcept { return m_GND; }
|
||||
|
||||
private:
|
||||
void noop() { }
|
||||
void noop() {}
|
||||
analog_input_t m_VCC;
|
||||
analog_input_t m_GND;
|
||||
};
|
||||
@ -124,14 +115,14 @@ namespace netlist::devices
|
||||
, m_max_link_loops(*this, "MAX_LINK_RESOLVE_LOOPS", 100)
|
||||
{
|
||||
}
|
||||
//NETLIB_RESETI() {}
|
||||
//NETLIB_UPDATE_PARAMI() { }
|
||||
// NETLIB_RESETI() {}
|
||||
// NETLIB_UPDATE_PARAMI() { }
|
||||
public:
|
||||
param_logic_t m_use_deactivate;
|
||||
param_num_t<unsigned> m_startup_strategy;
|
||||
param_num_t<unsigned> m_mos_cap_model;
|
||||
param_logic_t m_use_deactivate;
|
||||
param_num_t<unsigned> m_startup_strategy;
|
||||
param_num_t<unsigned> m_mos_cap_model;
|
||||
//! How many times do we try to resolve links (connections)
|
||||
param_num_t<unsigned> m_max_link_loops;
|
||||
param_num_t<unsigned> m_max_link_loops;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -145,16 +136,13 @@ namespace netlist::devices
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(nc_pin)
|
||||
, m_I(*this, "I", NETLIB_DELEGATE_NOOP())
|
||||
{
|
||||
}
|
||||
, m_I(*this, "I", NETLIB_DELEGATE_NOOP()) {}
|
||||
|
||||
protected:
|
||||
//NETLIB_RESETI() {}
|
||||
// NETLIB_RESETI() {}
|
||||
|
||||
private:
|
||||
analog_input_t m_I;
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -164,16 +152,11 @@ namespace netlist::devices
|
||||
NETLIB_OBJECT(gnd)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(gnd)
|
||||
, m_Q(*this, "Q")
|
||||
{
|
||||
}
|
||||
, m_Q(*this, "Q") {}
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
m_Q.push(nlconst::zero());
|
||||
}
|
||||
NETLIB_UPDATE_PARAMI() { m_Q.push(nlconst::zero()); }
|
||||
|
||||
//NETLIB_RESETI() {}
|
||||
// NETLIB_RESETI() {}
|
||||
protected:
|
||||
analog_output_t m_Q;
|
||||
};
|
||||
|
@ -8,23 +8,22 @@
|
||||
#ifndef NL_CORE_EXEC_H_
|
||||
#define NL_CORE_EXEC_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "base_objects.h"
|
||||
#include "state_var.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// netlist_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class netlist_t // NOLINT(clang-analyzer-optin.performance.Padding)
|
||||
{
|
||||
public:
|
||||
|
||||
explicit netlist_t(netlist_state_t &state, const pstring &aname);
|
||||
|
||||
netlist_t(const netlist_t &) = delete;
|
||||
@ -36,7 +35,10 @@ namespace netlist
|
||||
|
||||
// run functions
|
||||
|
||||
constexpr const netlist_time_ext &time() const noexcept { return m_time; }
|
||||
constexpr const netlist_time_ext &time() const noexcept
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
void process_queue(netlist_time_ext delta) noexcept;
|
||||
void abort_current_queue_slice() noexcept
|
||||
@ -45,15 +47,20 @@ namespace netlist
|
||||
queue_push(m_time, nullptr);
|
||||
}
|
||||
|
||||
constexpr const detail::queue_t &queue() const noexcept { return m_queue; }
|
||||
constexpr const detail::queue_t &queue() const noexcept
|
||||
{
|
||||
return m_queue;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void queue_push(Args&&...args) noexcept
|
||||
void queue_push(Args &&...args) noexcept
|
||||
{
|
||||
if (config::use_queue_stats::value && m_use_stats)
|
||||
m_queue.emplace<true>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
|
||||
m_queue.emplace<true>(std::forward<Args>(
|
||||
args)...); // NOLINT(performance-move-const-arg)
|
||||
else
|
||||
m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
|
||||
m_queue.emplace<false>(std::forward<Args>(
|
||||
args)...); // NOLINT(performance-move-const-arg)
|
||||
}
|
||||
|
||||
template <class R>
|
||||
@ -80,40 +87,38 @@ namespace netlist
|
||||
return static_cast<X *>(m_solver)->gmin();
|
||||
}
|
||||
|
||||
netlist_state_t &nl_state() noexcept { return m_state; }
|
||||
netlist_state_t & nl_state() noexcept { return m_state; }
|
||||
const netlist_state_t &nl_state() const noexcept { return m_state; }
|
||||
|
||||
log_type & log() noexcept { return m_state.log(); }
|
||||
log_type & log() noexcept { return m_state.log(); }
|
||||
const log_type &log() const noexcept { return m_state.log(); }
|
||||
|
||||
void print_stats() const;
|
||||
|
||||
constexpr bool stats_enabled() const noexcept { return m_use_stats; }
|
||||
void enable_stats(bool val) noexcept { m_use_stats = val; }
|
||||
void enable_stats(bool val) noexcept { m_use_stats = val; }
|
||||
|
||||
private:
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
void process_queue_stats(netlist_time_ext delta) noexcept;
|
||||
|
||||
netlist_state_t & m_state;
|
||||
devices::nld_solver * m_solver;
|
||||
netlist_state_t & m_state;
|
||||
devices::nld_solver *m_solver;
|
||||
|
||||
// mostly rw
|
||||
//PALIGNAS(16)
|
||||
netlist_time_ext m_time;
|
||||
devices::nld_mainclock * m_main_clock;
|
||||
// PALIGNAS(16)
|
||||
netlist_time_ext m_time;
|
||||
devices::nld_mainclock *m_main_clock;
|
||||
|
||||
//PALIGNAS_CACHELINE()
|
||||
//PALIGNAS(16)
|
||||
bool m_use_stats;
|
||||
detail::queue_t m_queue;
|
||||
// PALIGNAS_CACHELINE()
|
||||
// PALIGNAS(16)
|
||||
bool m_use_stats;
|
||||
detail::queue_t m_queue;
|
||||
// performance
|
||||
plib::pperftime_t<true> m_stat_mainloop;
|
||||
plib::pperfcount_t<true> m_perf_out_processed;
|
||||
plib::pperftime_t<true> m_stat_mainloop;
|
||||
plib::pperfcount_t<true> m_perf_out_processed;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_EXEC_H_
|
||||
|
@ -2,7 +2,7 @@
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
///
|
||||
/// \file param.h
|
||||
/// \file logic.h
|
||||
///
|
||||
|
||||
#ifndef NL_CORE_LOGIC_H_
|
||||
@ -22,37 +22,39 @@
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// logic_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class logic_t : public detail::core_terminal_t, public logic_family_t
|
||||
class logic_t
|
||||
: public detail::core_terminal_t
|
||||
, public logic_family_t
|
||||
{
|
||||
public:
|
||||
logic_t(device_t &dev, const pstring &aname,
|
||||
state_e terminal_state, nl_delegate delegate);
|
||||
logic_t(device_t &dev, const pstring &aname, state_e terminal_state,
|
||||
nl_delegate delegate);
|
||||
|
||||
logic_net_t & net() noexcept
|
||||
logic_net_t &net() noexcept
|
||||
{
|
||||
return plib::downcast<logic_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
constexpr const logic_net_t & net() const noexcept
|
||||
constexpr const logic_net_t &net() const noexcept
|
||||
{
|
||||
return plib::downcast<const logic_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// logic_input_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class logic_input_t : public logic_t
|
||||
{
|
||||
public:
|
||||
logic_input_t(device_t &dev, const pstring &aname,
|
||||
nl_delegate delegate);
|
||||
nl_delegate delegate);
|
||||
|
||||
//const netlist_sig_t &operator()() const noexcept
|
||||
// const netlist_sig_t &operator()() const noexcept
|
||||
constexpr netlist_sig_t operator()() const noexcept
|
||||
{
|
||||
gsl_Expects(terminal_state() != STATE_INP_PASSIVE);
|
||||
@ -97,17 +99,15 @@ namespace netlist
|
||||
set_state(STATE_INP_LH);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// logic_output_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class logic_output_t : public logic_t
|
||||
{
|
||||
public:
|
||||
|
||||
/// \brief logic output constructor
|
||||
///
|
||||
/// The third parameter does nothing. It is provided only for
|
||||
@ -115,7 +115,8 @@ namespace netlist
|
||||
///
|
||||
/// \param dev Device owning this output
|
||||
/// \param aname The name of this output
|
||||
/// \param dummy Dummy parameter to allow construction like tristate output
|
||||
/// \param dummy Dummy parameter to allow construction like tristate
|
||||
/// output
|
||||
///
|
||||
logic_output_t(device_t &dev, const pstring &aname, bool dummy = false);
|
||||
|
||||
@ -142,17 +143,20 @@ namespace netlist
|
||||
/// This function terminates if actually called.
|
||||
///
|
||||
[[noreturn]] static void set_tristate([[maybe_unused]] netlist_sig_t v,
|
||||
[[maybe_unused]] netlist_time ts_off_on, [[maybe_unused]] netlist_time ts_on_off)
|
||||
[[maybe_unused]] netlist_time ts_off_on,
|
||||
[[maybe_unused]] netlist_time ts_on_off)
|
||||
{
|
||||
plib::terminate("set_tristate on logic_output should never be called!");
|
||||
plib::terminate(
|
||||
"set_tristate on logic_output should never be called!");
|
||||
}
|
||||
|
||||
private:
|
||||
logic_net_t m_my_net;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// tristate_output_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// \brief Tristate output
|
||||
///
|
||||
@ -170,8 +174,8 @@ namespace netlist
|
||||
class tristate_output_t : public logic_output_t
|
||||
{
|
||||
public:
|
||||
|
||||
tristate_output_t(device_t &dev, const pstring &aname, bool force_logic);
|
||||
tristate_output_t(device_t &dev, const pstring &aname,
|
||||
bool force_logic);
|
||||
|
||||
void push(netlist_sig_t newQ, netlist_time delay) noexcept
|
||||
{
|
||||
@ -180,31 +184,29 @@ namespace netlist
|
||||
m_last_logic = newQ;
|
||||
}
|
||||
|
||||
void set_tristate(netlist_sig_t v,
|
||||
netlist_time ts_off_on, netlist_time ts_on_off) noexcept
|
||||
void set_tristate(netlist_sig_t v, netlist_time ts_off_on,
|
||||
netlist_time ts_on_off) noexcept
|
||||
{
|
||||
if (!m_force_logic)
|
||||
if (v != m_tristate)
|
||||
{
|
||||
logic_output_t::push((v != 0) ? OUT_TRISTATE() : m_last_logic, v ? ts_off_on : ts_on_off);
|
||||
logic_output_t::push((v != 0) ? OUT_TRISTATE()
|
||||
: m_last_logic,
|
||||
v ? ts_off_on : ts_on_off);
|
||||
m_tristate = v;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_force_logic() const noexcept
|
||||
{
|
||||
return m_force_logic;
|
||||
}
|
||||
bool is_force_logic() const noexcept { return m_force_logic; }
|
||||
|
||||
private:
|
||||
using logic_output_t::initial;
|
||||
using logic_output_t::set_Q_time;
|
||||
state_var<netlist_sig_t> m_last_logic;
|
||||
state_var<netlist_sig_t> m_tristate;
|
||||
bool m_force_logic;
|
||||
bool m_force_logic;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_LOGIC_H_
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define NL_CORE_LOGIC_FAMILY_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
@ -20,52 +21,78 @@ namespace netlist
|
||||
class logic_family_desc_t
|
||||
{
|
||||
public:
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, modernize-use-equals-default)
|
||||
logic_family_desc_t()
|
||||
{
|
||||
}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,
|
||||
// modernize-use-equals-default)
|
||||
logic_family_desc_t() = default;
|
||||
|
||||
logic_family_desc_t(const logic_family_desc_t &) = delete;
|
||||
logic_family_desc_t &operator=(const logic_family_desc_t &) = delete;
|
||||
|
||||
// FOXME: Should be move constructible
|
||||
logic_family_desc_t(logic_family_desc_t &&) noexcept = delete;
|
||||
logic_family_desc_t &operator=(logic_family_desc_t &&) noexcept = delete;
|
||||
logic_family_desc_t &operator=(
|
||||
logic_family_desc_t &&) noexcept = delete;
|
||||
|
||||
virtual ~logic_family_desc_t() noexcept = default;
|
||||
|
||||
virtual device_arena::unique_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_output_t *proxied) const = 0;
|
||||
virtual device_arena::unique_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_input_t *proxied) const = 0;
|
||||
virtual device_arena::unique_ptr<devices::nld_base_d_to_a_proxy>
|
||||
create_d_a_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_output_t *proxied) const = 0;
|
||||
virtual device_arena::unique_ptr<devices::nld_base_a_to_d_proxy>
|
||||
create_a_d_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_input_t *proxied) const = 0;
|
||||
|
||||
nl_fptype low_threshold_V(nl_fptype VN, nl_fptype VP) const noexcept{ return VN + (VP - VN) * m_low_threshold_PCNT; }
|
||||
nl_fptype high_threshold_V(nl_fptype VN, nl_fptype VP) const noexcept{ return VN + (VP - VN) * m_high_threshold_PCNT; }
|
||||
nl_fptype low_offset_V() const noexcept{ return m_low_VO; }
|
||||
nl_fptype high_offset_V() const noexcept{ return m_high_VO; }
|
||||
nl_fptype R_low() const noexcept{ return m_R_low; }
|
||||
nl_fptype R_high() const noexcept{ return m_R_high; }
|
||||
nl_fptype low_threshold_V(nl_fptype VN, nl_fptype VP) const noexcept
|
||||
{
|
||||
return VN + (VP - VN) * m_low_threshold_PCNT;
|
||||
}
|
||||
nl_fptype high_threshold_V(nl_fptype VN, nl_fptype VP) const noexcept
|
||||
{
|
||||
return VN + (VP - VN) * m_high_threshold_PCNT;
|
||||
}
|
||||
nl_fptype low_offset_V() const noexcept { return m_low_VO; }
|
||||
nl_fptype high_offset_V() const noexcept { return m_high_VO; }
|
||||
nl_fptype R_low() const noexcept { return m_R_low; }
|
||||
nl_fptype R_high() const noexcept { return m_R_high; }
|
||||
|
||||
bool is_above_high_threshold_V(nl_fptype V, nl_fptype VN, nl_fptype VP) const noexcept
|
||||
{ return V > high_threshold_V(VN, VP); }
|
||||
bool is_above_high_threshold_V(nl_fptype V, nl_fptype VN,
|
||||
nl_fptype VP) const noexcept
|
||||
{
|
||||
return V > high_threshold_V(VN, VP);
|
||||
}
|
||||
|
||||
bool is_below_low_threshold_V(nl_fptype V, nl_fptype VN, nl_fptype VP) const noexcept
|
||||
{ return V < low_threshold_V(VN, VP); }
|
||||
bool is_below_low_threshold_V(nl_fptype V, nl_fptype VN,
|
||||
nl_fptype VP) const noexcept
|
||||
{
|
||||
return V < low_threshold_V(VN, VP);
|
||||
}
|
||||
|
||||
pstring vcc_pin() const { return pstring(m_vcc); }
|
||||
pstring gnd_pin() const { return pstring(m_gnd); }
|
||||
|
||||
nl_fptype m_low_threshold_PCNT; //!< low input threshold offset. If the input voltage is below this value times supply voltage, a "0" input is signalled
|
||||
nl_fptype m_high_threshold_PCNT; //!< high input threshold offset. If the input voltage is above the value times supply voltage, a "0" input is signalled
|
||||
nl_fptype m_low_VO; //!< low output voltage offset. This voltage is output if the ouput is "0"
|
||||
nl_fptype m_high_VO; //!< high output voltage offset. The supply voltage minus this offset is output if the ouput is "1"
|
||||
nl_fptype m_R_low; //!< low output resistance. Value of series resistor used for low output
|
||||
nl_fptype m_R_high; //!< high output resistance. Value of series resistor used for high output
|
||||
const char *m_vcc; //!< default power pin name for positive supply
|
||||
const char *m_gnd; //!< default power pin name for negative supply
|
||||
nl_fptype m_low_threshold_PCNT; //!< low input threshold offset. If the
|
||||
//!< input voltage is below this value
|
||||
//!< times supply voltage, a "0" input
|
||||
//!< is signalled
|
||||
nl_fptype m_high_threshold_PCNT; //!< high input threshold offset. If
|
||||
//!< the input voltage is above the
|
||||
//!< value times supply voltage, a "0"
|
||||
//!< input is signalled
|
||||
nl_fptype m_low_VO; //!< low output voltage offset. This voltage is
|
||||
//!< output if the ouput is "0"
|
||||
nl_fptype m_high_VO; //!< high output voltage offset. The supply voltage
|
||||
//!< minus this offset is output if the ouput is
|
||||
//!< "1"
|
||||
nl_fptype m_R_low; //!< low output resistance. Value of series resistor
|
||||
//!< used for low output
|
||||
nl_fptype m_R_high; //!< high output resistance. Value of series
|
||||
//!< resistor used for high output
|
||||
const char *m_vcc; //!< default power pin name for positive supply
|
||||
const char *m_gnd; //!< default power pin name for negative supply
|
||||
};
|
||||
|
||||
/// \brief Base class for devices, terminals, outputs and inputs which support
|
||||
/// \brief Base class for devices, terminals, outputs and inputs which
|
||||
/// support
|
||||
/// logic families.
|
||||
/// This class is a storage container to store the logic family for a
|
||||
/// netlist object. You will not directly use it. Please refer to
|
||||
@ -79,8 +106,14 @@ namespace netlist
|
||||
class logic_family_t
|
||||
{
|
||||
public:
|
||||
logic_family_t() : m_logic_family(nullptr) {}
|
||||
logic_family_t(const logic_family_desc_t *d) : m_logic_family(d) {}
|
||||
logic_family_t()
|
||||
: m_logic_family(nullptr)
|
||||
{
|
||||
}
|
||||
logic_family_t(const logic_family_desc_t *d)
|
||||
: m_logic_family(d)
|
||||
{
|
||||
}
|
||||
|
||||
logic_family_t(const logic_family_t &) = delete;
|
||||
logic_family_t &operator=(const logic_family_t &) = delete;
|
||||
@ -89,16 +122,22 @@ namespace netlist
|
||||
logic_family_t(logic_family_t &&) noexcept = delete;
|
||||
logic_family_t &operator=(logic_family_t &&) noexcept = delete;
|
||||
|
||||
const logic_family_desc_t *logic_family() const noexcept { return m_logic_family; }
|
||||
void set_logic_family(const logic_family_desc_t *fam) noexcept { m_logic_family = fam; }
|
||||
const logic_family_desc_t *logic_family() const noexcept
|
||||
{
|
||||
return m_logic_family;
|
||||
}
|
||||
void set_logic_family(const logic_family_desc_t *fam) noexcept
|
||||
{
|
||||
m_logic_family = fam;
|
||||
}
|
||||
|
||||
protected:
|
||||
~logic_family_t() noexcept = default; // prohibit polymorphic destruction
|
||||
~logic_family_t() noexcept = default; // prohibit polymorphic
|
||||
// destruction
|
||||
private:
|
||||
const logic_family_desc_t *m_logic_family;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_LOGIC_FAMILY_H_
|
||||
|
@ -8,9 +8,8 @@
|
||||
#ifndef NL_CORE_NETLIST_STATE_H_
|
||||
#define NL_CORE_NETLIST_STATE_H_
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pstate.h"
|
||||
@ -30,12 +29,14 @@ namespace netlist
|
||||
class netlist_state_t
|
||||
{
|
||||
public:
|
||||
|
||||
using nets_collection_type = std::vector<device_arena::owned_ptr<detail::net_t>>;
|
||||
using family_collection_type = std::unordered_map<pstring, host_arena::unique_ptr<logic_family_desc_t>>;
|
||||
using nets_collection_type = std::vector<
|
||||
device_arena::owned_ptr<detail::net_t>>;
|
||||
using family_collection_type = std::unordered_map<pstring,
|
||||
host_arena::unique_ptr<logic_family_desc_t>>;
|
||||
|
||||
// need to preserve order of device creation ...
|
||||
using devices_collection_type = std::vector<std::pair<pstring, device_arena::owned_ptr<core_device_t>>>;
|
||||
using devices_collection_type = std::vector<
|
||||
std::pair<pstring, device_arena::owned_ptr<core_device_t>>>;
|
||||
|
||||
netlist_state_t(const pstring &name, plib::plog_delegate logger);
|
||||
|
||||
@ -51,10 +52,11 @@ namespace netlist
|
||||
template <class C>
|
||||
static bool check_class(core_device_t *p) noexcept
|
||||
{
|
||||
return dynamic_cast<C *>(p) != nullptr;
|
||||
return bool(plib::dynamic_downcast<C *>(p));
|
||||
}
|
||||
|
||||
core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const noexcept(false);
|
||||
core_device_t *get_single_device(const pstring &classname,
|
||||
bool (*cc)(core_device_t *)) const noexcept(false);
|
||||
|
||||
/// \brief Get single device filtered by class and name
|
||||
///
|
||||
@ -81,19 +83,21 @@ namespace netlist
|
||||
std::vector<C *> tmp;
|
||||
for (const auto &d : m_devices)
|
||||
{
|
||||
auto * const dev = dynamic_cast<C *>(d.second.get());
|
||||
if (dev != nullptr)
|
||||
tmp.push_back(dev);
|
||||
if (auto dev = plib::dynamic_downcast<C *>(d.second.get()))
|
||||
tmp.push_back(*dev);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// logging
|
||||
|
||||
log_type & log() noexcept { return m_log; }
|
||||
log_type & log() noexcept { return m_log; }
|
||||
const log_type &log() const noexcept { return m_log; }
|
||||
|
||||
plib::dynamic_library_base &static_solver_lib() const noexcept { return *m_lib; }
|
||||
plib::dynamic_library_base &static_solver_lib() const noexcept
|
||||
{
|
||||
return *m_lib;
|
||||
}
|
||||
|
||||
/// \brief provide library with static solver implementations.
|
||||
///
|
||||
@ -101,32 +105,41 @@ namespace netlist
|
||||
/// determined by the specific use case. You can pass such a collection
|
||||
/// of symbols with this method.
|
||||
///
|
||||
void set_static_solver_lib(std::unique_ptr<plib::dynamic_library_base> &&lib);
|
||||
void set_static_solver_lib(
|
||||
std::unique_ptr<plib::dynamic_library_base> &&lib);
|
||||
|
||||
netlist_t &exec() noexcept { return *m_netlist; }
|
||||
netlist_t & exec() noexcept { return *m_netlist; }
|
||||
const netlist_t &exec() const noexcept { return *m_netlist; }
|
||||
|
||||
// state handling
|
||||
plib::state_manager_t &run_state_manager() noexcept { return m_state; }
|
||||
|
||||
template <typename O, typename C>
|
||||
void save(O &owner, C &state, const pstring &module, const pstring &stname)
|
||||
void save(O &owner, C &state, const pstring &module,
|
||||
const pstring &stname)
|
||||
{
|
||||
this->run_state_manager().save_item(plib::void_ptr_cast(&owner), state, module + "." + stname);
|
||||
this->run_state_manager().save_item(plib::void_ptr_cast(&owner),
|
||||
state, module + "." + stname);
|
||||
}
|
||||
|
||||
template <typename O, typename C>
|
||||
void save(O &owner, C *state, const pstring &module, const pstring &stname, const std::size_t count)
|
||||
void save(O &owner, C *state, const pstring &module,
|
||||
const pstring &stname, const std::size_t count)
|
||||
{
|
||||
this->run_state_manager().save_state_ptr(plib::void_ptr_cast(&owner), module + "." + stname, plib::state_manager_t::dtype<C>(), count, state);
|
||||
this->run_state_manager().save_state_ptr(
|
||||
plib::void_ptr_cast(&owner), module + "." + stname,
|
||||
plib::state_manager_t::dtype<C>(), count, state);
|
||||
}
|
||||
|
||||
// FIXME: only used by queue_t save state
|
||||
std::size_t find_net_id(const detail::net_t *net) const;
|
||||
std::size_t find_net_id(const detail::net_t *net) const;
|
||||
detail::net_t *net_by_id(std::size_t id) const;
|
||||
|
||||
template <typename T>
|
||||
void register_net(device_arena::owned_ptr<T> &&net) { m_nets.push_back(std::move(net)); }
|
||||
void register_net(device_arena::owned_ptr<T> &&net)
|
||||
{
|
||||
m_nets.push_back(std::move(net));
|
||||
}
|
||||
|
||||
/// \brief Get device pointer by name
|
||||
///
|
||||
@ -137,7 +150,7 @@ namespace netlist
|
||||
|
||||
core_device_t *find_device(const pstring &name) const
|
||||
{
|
||||
for (const auto & d : m_devices)
|
||||
for (const auto &d : m_devices)
|
||||
if (d.first == name)
|
||||
return d.second.get();
|
||||
return nullptr;
|
||||
@ -145,24 +158,25 @@ namespace netlist
|
||||
|
||||
/// \brief Register device using owned_ptr
|
||||
///
|
||||
/// Used to register owned devices. These are devices declared as objects
|
||||
/// in another devices.
|
||||
/// Used to register owned devices. These are devices declared as
|
||||
/// objects in another devices.
|
||||
///
|
||||
/// \param name Name of the device
|
||||
/// \param dev Device to be registered
|
||||
|
||||
template <typename T>
|
||||
void register_device(const pstring &name, device_arena::owned_ptr<T> &&dev) noexcept(false)
|
||||
void register_device(const pstring &name,
|
||||
device_arena::owned_ptr<T> && dev) noexcept(false)
|
||||
{
|
||||
for (auto & d : m_devices)
|
||||
for (auto &d : m_devices)
|
||||
if (d.first == name)
|
||||
{
|
||||
dev.release();
|
||||
log().fatal(MF_DUPLICATE_NAME_DEVICE_LIST(name));
|
||||
throw nl_exception(MF_DUPLICATE_NAME_DEVICE_LIST(name));
|
||||
}
|
||||
//m_devices.push_back(std::move(dev));
|
||||
m_devices.insert(m_devices.end(), { name, std::move(dev) });
|
||||
// m_devices.push_back(std::move(dev));
|
||||
m_devices.insert(m_devices.end(), {name, std::move(dev)});
|
||||
}
|
||||
|
||||
/// \brief Register device using unique_ptr
|
||||
@ -173,9 +187,11 @@ namespace netlist
|
||||
/// \param dev Device to be registered
|
||||
|
||||
template <typename T>
|
||||
void register_device(const pstring &name, device_arena::unique_ptr<T> &&dev)
|
||||
void register_device(const pstring &name,
|
||||
device_arena::unique_ptr<T> && dev)
|
||||
{
|
||||
register_device(name, device_arena::owned_ptr<T>(dev.release(), true, dev.get_deleter()));
|
||||
register_device(name, device_arena::owned_ptr<T>(dev.release(),
|
||||
true, dev.get_deleter()));
|
||||
}
|
||||
|
||||
/// \brief Remove device
|
||||
@ -187,41 +203,45 @@ namespace netlist
|
||||
|
||||
void remove_device(core_device_t *dev);
|
||||
|
||||
setup_t &setup() noexcept { return *m_setup; }
|
||||
setup_t & setup() noexcept { return *m_setup; }
|
||||
const setup_t &setup() const noexcept { return *m_setup; }
|
||||
|
||||
nlparse_t &parser();
|
||||
const nlparse_t &parser() const;
|
||||
nlparse_t & parser() noexcept;
|
||||
const nlparse_t &parser() const noexcept;
|
||||
|
||||
// FIXME: make a post load member and include code there
|
||||
void rebuild_lists(); // must be called after post_load !
|
||||
|
||||
static void compile_defines(std::vector<std::pair<pstring, pstring>> &defs);
|
||||
static void compile_defines(
|
||||
std::vector<std::pair<pstring, pstring>> &defs);
|
||||
static pstring version();
|
||||
static pstring version_patchlevel();
|
||||
|
||||
nets_collection_type & nets() noexcept { return m_nets; }
|
||||
const nets_collection_type & nets() const noexcept { return m_nets; }
|
||||
nets_collection_type & nets() noexcept { return m_nets; }
|
||||
const nets_collection_type &nets() const noexcept { return m_nets; }
|
||||
|
||||
devices_collection_type & devices() noexcept { return m_devices; }
|
||||
const devices_collection_type & devices() const noexcept { return m_devices; }
|
||||
devices_collection_type & devices() noexcept { return m_devices; }
|
||||
const devices_collection_type &devices() const noexcept
|
||||
{
|
||||
return m_devices;
|
||||
}
|
||||
|
||||
family_collection_type &family_cache() { return m_family_cache; }
|
||||
|
||||
template <typename T, typename... Args>
|
||||
device_arena::unique_ptr<T> make_pool_object(Args&&... args)
|
||||
device_arena::unique_ptr<T> make_pool_object(Args &&...args)
|
||||
{
|
||||
return plib::make_unique<T>(m_pool, std::forward<Args>(args)...);
|
||||
}
|
||||
// memory pool - still needed in some places
|
||||
device_arena &pool() noexcept { return m_pool; }
|
||||
device_arena & pool() noexcept { return m_pool; }
|
||||
const device_arena &pool() const noexcept { return m_pool; }
|
||||
|
||||
struct stats_info
|
||||
{
|
||||
const detail::queue_t &m_queue;// performance
|
||||
const plib::pperftime_t<true> &m_stat_mainloop;
|
||||
const plib::pperfcount_t<true> &m_perf_out_processed;
|
||||
const detail::queue_t & m_queue; // performance
|
||||
const plib::pperftime_t<true> & m_stat_mainloop;
|
||||
const plib::pperfcount_t<true> &m_perf_out_processed;
|
||||
};
|
||||
|
||||
/// \brief print statistics gathered during run
|
||||
@ -236,37 +256,38 @@ namespace netlist
|
||||
///
|
||||
void free_setup_resources();
|
||||
#if !(NL_USE_INPLACE_CORE_TERMS)
|
||||
std::vector<detail::core_terminal_t *> &core_terms(const detail::net_t &net)
|
||||
std::vector<detail::core_terminal_t *> &core_terms(
|
||||
const detail::net_t &net)
|
||||
{
|
||||
return m_core_terms[&net];
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
device_arena m_pool; // must be deleted last!
|
||||
|
||||
device_arena m_pool; // must be deleted last!
|
||||
|
||||
device_arena::unique_ptr<netlist_t> m_netlist;
|
||||
std::unique_ptr<plib::dynamic_library_base> m_lib;
|
||||
plib::state_manager_t m_state;
|
||||
log_type m_log;
|
||||
device_arena::unique_ptr<netlist_t> m_netlist;
|
||||
std::unique_ptr<plib::dynamic_library_base> m_lib;
|
||||
plib::state_manager_t m_state;
|
||||
log_type m_log;
|
||||
|
||||
// FIXME: should only be available during device construction
|
||||
host_arena::unique_ptr<setup_t> m_setup;
|
||||
host_arena::unique_ptr<setup_t> m_setup;
|
||||
|
||||
nets_collection_type m_nets;
|
||||
nets_collection_type m_nets;
|
||||
// sole use is to manage lifetime of net objects
|
||||
devices_collection_type m_devices;
|
||||
devices_collection_type m_devices;
|
||||
// sole use is to manage lifetime of family objects
|
||||
family_collection_type m_family_cache;
|
||||
family_collection_type m_family_cache;
|
||||
#if !(NL_USE_INPLACE_CORE_TERMS)
|
||||
// all terms for a net
|
||||
std::unordered_map<const detail::net_t *, std::vector<detail::core_terminal_t *>> m_core_terms;
|
||||
std::unordered_map<const detail::net_t *,
|
||||
std::vector<detail::core_terminal_t *>>
|
||||
m_core_terms;
|
||||
#endif
|
||||
// dummy version
|
||||
int m_dummy_version;
|
||||
int m_dummy_version;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_NETLIST_STATE_H_
|
||||
|
@ -8,12 +8,12 @@
|
||||
#ifndef NL_CORE_NETS_H_
|
||||
#define NL_CORE_NETS_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "base_objects.h"
|
||||
#include "core_device.h"
|
||||
#include "exec.h"
|
||||
#include "state_var.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
@ -21,16 +21,16 @@
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
namespace detail {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
// net_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
class net_t : public netlist_object_t
|
||||
{
|
||||
public:
|
||||
|
||||
enum class queue_status
|
||||
{
|
||||
DELAYED_DUE_TO_INACTIVE = 0,
|
||||
@ -38,7 +38,8 @@ namespace netlist
|
||||
DELIVERED
|
||||
};
|
||||
|
||||
net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *rail_terminal = nullptr);
|
||||
net_t(netlist_state_t &nl, const pstring &aname,
|
||||
core_terminal_t *rail_terminal = nullptr);
|
||||
|
||||
net_t(const net_t &) = delete;
|
||||
net_t &operator=(const net_t &) = delete;
|
||||
@ -49,16 +50,13 @@ namespace netlist
|
||||
|
||||
virtual void reset() noexcept;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// Hot section
|
||||
//
|
||||
// Any changes below will impact performance.
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
constexpr void toggle_new_Q() noexcept
|
||||
{
|
||||
m_new_Q = (m_cur_Q ^ 1);
|
||||
}
|
||||
constexpr void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); }
|
||||
|
||||
void toggle_and_push_to_queue(const netlist_time &delay) noexcept
|
||||
{
|
||||
@ -73,30 +71,44 @@ namespace netlist
|
||||
return m_in_queue == queue_status::QUEUED;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// Very hot
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
void update_devs() noexcept;
|
||||
|
||||
constexpr const netlist_time_ext &next_scheduled_time() const noexcept { return m_next_scheduled_time; }
|
||||
void set_next_scheduled_time(const netlist_time_ext &next_time) noexcept { m_next_scheduled_time = next_time; }
|
||||
constexpr const netlist_time_ext &
|
||||
next_scheduled_time() const noexcept
|
||||
{
|
||||
return m_next_scheduled_time;
|
||||
}
|
||||
void set_next_scheduled_time(
|
||||
const netlist_time_ext &next_time) noexcept
|
||||
{
|
||||
m_next_scheduled_time = next_time;
|
||||
}
|
||||
|
||||
bool is_rail_net() const noexcept { return !(m_rail_terminal == nullptr); }
|
||||
core_terminal_t & rail_terminal() const noexcept { return *m_rail_terminal; }
|
||||
bool is_rail_net() const noexcept
|
||||
{
|
||||
return !(m_rail_terminal == nullptr);
|
||||
}
|
||||
core_terminal_t &rail_terminal() const noexcept
|
||||
{
|
||||
return *m_rail_terminal;
|
||||
}
|
||||
|
||||
void add_to_active_list(core_terminal_t &term) noexcept;
|
||||
void remove_from_active_list(core_terminal_t &term) noexcept;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// setup stuff - cold
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
bool is_logic() const noexcept;
|
||||
bool is_analog() const noexcept;
|
||||
|
||||
void rebuild_list(); // rebuild m_list after a load
|
||||
void rebuild_list() noexcept(false); // rebuild m_list after a load
|
||||
|
||||
void update_inputs() noexcept
|
||||
{
|
||||
@ -107,26 +119,36 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
// net management
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
const std::vector<detail::core_terminal_t *> core_terms_copy()
|
||||
std::vector<detail::core_terminal_t *>
|
||||
core_terms_copy() noexcept(false)
|
||||
{
|
||||
std::vector<detail::core_terminal_t *> ret(core_terms_ref().size());
|
||||
std::copy(core_terms_ref().begin(), core_terms_ref().end(), ret.begin());
|
||||
std::vector<detail::core_terminal_t *> ret(
|
||||
core_terms_ref().size());
|
||||
std::copy(core_terms_ref().begin(), core_terms_ref().end(),
|
||||
ret.begin());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void remove_terminal(detail::core_terminal_t &term);
|
||||
void remove_all_terminals();
|
||||
void add_terminal(detail::core_terminal_t &terminal);
|
||||
void remove_terminal(detail::core_terminal_t &term) noexcept(false);
|
||||
void remove_all_terminals() noexcept(false);
|
||||
void add_terminal(detail::core_terminal_t &terminal) noexcept(
|
||||
false);
|
||||
|
||||
bool core_terms_empty() noexcept(false)
|
||||
{
|
||||
return core_terms_ref().empty();
|
||||
}
|
||||
|
||||
bool core_terms_empty() noexcept { return core_terms_ref().empty(); }
|
||||
protected:
|
||||
|
||||
// only used for logic nets
|
||||
constexpr const netlist_sig_t &Q() const noexcept { return m_cur_Q; }
|
||||
constexpr const netlist_sig_t &Q() const noexcept
|
||||
{
|
||||
return m_cur_Q;
|
||||
}
|
||||
|
||||
// only used for logic nets
|
||||
void initial(netlist_sig_t val) noexcept
|
||||
@ -136,15 +158,17 @@ namespace netlist
|
||||
}
|
||||
|
||||
// only used for logic nets
|
||||
void set_Q_and_push(netlist_sig_t newQ, const netlist_time &delay) noexcept;
|
||||
void set_Q_and_push(netlist_sig_t newQ,
|
||||
const netlist_time & delay) noexcept;
|
||||
|
||||
// only used for logic nets
|
||||
void set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept;
|
||||
|
||||
void set_Q_time(netlist_sig_t newQ,
|
||||
const netlist_time_ext & at) noexcept;
|
||||
|
||||
private:
|
||||
#if NL_USE_INPLACE_CORE_TERMS
|
||||
const plib::linked_list_t<core_terminal_t, 1> &core_terms_ref() const noexcept
|
||||
const plib::linked_list_t<core_terminal_t, 1> &
|
||||
core_terms_ref() const noexcept
|
||||
{
|
||||
return m_core_terms;
|
||||
}
|
||||
@ -154,14 +178,14 @@ namespace netlist
|
||||
return state().core_terms(*this);
|
||||
}
|
||||
#endif
|
||||
state_var<netlist_sig_t> m_new_Q;
|
||||
state_var<netlist_sig_t> m_cur_Q;
|
||||
state_var<queue_status> m_in_queue;
|
||||
state_var<netlist_sig_t> m_new_Q;
|
||||
state_var<netlist_sig_t> m_cur_Q;
|
||||
state_var<queue_status> m_in_queue;
|
||||
// FIXME: this needs to be saved as well
|
||||
plib::linked_list_t<core_terminal_t, 0> m_list_active;
|
||||
state_var<netlist_time_ext> m_next_scheduled_time;
|
||||
state_var<netlist_time_ext> m_next_scheduled_time;
|
||||
|
||||
core_terminal_t * m_rail_terminal;
|
||||
core_terminal_t *m_rail_terminal;
|
||||
#if NL_USE_INPLACE_CORE_TERMS
|
||||
plib::linked_list_t<core_terminal_t, 1> m_core_terms;
|
||||
#endif
|
||||
@ -174,10 +198,15 @@ namespace netlist
|
||||
|
||||
m_next_scheduled_time = exec().time() + delay;
|
||||
if constexpr (config::avoid_noop_queue_pushes::value)
|
||||
m_in_queue = (m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE
|
||||
: (m_new_Q != m_cur_Q ? queue_status::QUEUED : queue_status::DELIVERED));
|
||||
m_in_queue = (m_list_active.empty()
|
||||
? queue_status::DELAYED_DUE_TO_INACTIVE
|
||||
: (m_new_Q != m_cur_Q
|
||||
? queue_status::QUEUED
|
||||
: queue_status::DELIVERED));
|
||||
else
|
||||
m_in_queue = m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE : queue_status::QUEUED;
|
||||
m_in_queue = m_list_active.empty()
|
||||
? queue_status::DELAYED_DUE_TO_INACTIVE
|
||||
: queue_status::QUEUED;
|
||||
|
||||
if (m_in_queue == queue_status::QUEUED)
|
||||
exec().queue_push(m_next_scheduled_time, this);
|
||||
@ -194,15 +223,16 @@ namespace netlist
|
||||
|
||||
const netlist_sig_t new_Q(m_new_Q);
|
||||
const netlist_sig_t cur_Q(m_cur_Q);
|
||||
if (config::avoid_noop_queue_pushes::value || ((new_Q ^ cur_Q) != 0))
|
||||
if (config::avoid_noop_queue_pushes::value
|
||||
|| ((new_Q ^ cur_Q) != 0))
|
||||
{
|
||||
m_cur_Q = new_Q;
|
||||
const auto mask = (new_Q << core_terminal_t::INP_LH_SHIFT)
|
||||
| (cur_Q << core_terminal_t::INP_HL_SHIFT);
|
||||
| (cur_Q << core_terminal_t::INP_HL_SHIFT);
|
||||
|
||||
if (!KEEP_STATS)
|
||||
{
|
||||
for (core_terminal_t * p: m_list_active)
|
||||
for (core_terminal_t *p : m_list_active)
|
||||
{
|
||||
p->set_copied_input(new_Q);
|
||||
if ((p->terminal_state() & mask) != 0)
|
||||
@ -211,7 +241,7 @@ namespace netlist
|
||||
}
|
||||
else
|
||||
{
|
||||
for (core_terminal_t * p : m_list_active)
|
||||
for (core_terminal_t *p : m_list_active)
|
||||
{
|
||||
p->set_copied_input(new_Q);
|
||||
auto *stats(p->device().stats());
|
||||
@ -239,11 +269,13 @@ namespace netlist
|
||||
rail_terminal().device().do_inc_active();
|
||||
if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
|
||||
{
|
||||
// if we avoid queue pushes we must test if m_cur_Q and m_new_Q are equal
|
||||
if ((!config::avoid_noop_queue_pushes::value || (m_cur_Q != m_new_Q))
|
||||
// if we avoid queue pushes we must test if m_cur_Q and
|
||||
// m_new_Q are equal
|
||||
if ((!config::avoid_noop_queue_pushes::value
|
||||
|| (m_cur_Q != m_new_Q))
|
||||
&& (m_next_scheduled_time > exec().time()))
|
||||
{
|
||||
m_in_queue = queue_status::QUEUED; // pending
|
||||
m_in_queue = queue_status::QUEUED; // pending
|
||||
exec().queue_push(m_next_scheduled_time, this);
|
||||
}
|
||||
else
|
||||
@ -258,7 +290,8 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
inline void net_t::remove_from_active_list(core_terminal_t &term) noexcept
|
||||
inline void net_t::remove_from_active_list(
|
||||
core_terminal_t &term) noexcept
|
||||
{
|
||||
gsl_Expects(!m_list_active.empty());
|
||||
m_list_active.remove(&term);
|
||||
@ -269,7 +302,8 @@ namespace netlist
|
||||
// All our connected outputs have signalled they no longer
|
||||
// will act on input. We thus remove any potentially queued
|
||||
// events and mark them.
|
||||
// FIXME: May cause regression test to fail - revisit in this case
|
||||
// FIXME: May cause regression test to fail - revisit in
|
||||
// this case
|
||||
//
|
||||
// This code is definitively needed for the
|
||||
// AVOID_NOOP_QUEUE_PUSHES code path - therefore I left
|
||||
@ -285,7 +319,8 @@ namespace netlist
|
||||
}
|
||||
|
||||
// only used for logic nets
|
||||
inline void net_t::set_Q_and_push(netlist_sig_t newQ, const netlist_time &delay) noexcept
|
||||
inline void net_t::set_Q_and_push(netlist_sig_t newQ,
|
||||
const netlist_time & delay) noexcept
|
||||
{
|
||||
gsl_Expects(delay >= netlist_time::zero());
|
||||
|
||||
@ -297,7 +332,8 @@ namespace netlist
|
||||
}
|
||||
|
||||
// only used for logic nets
|
||||
inline void net_t::set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept
|
||||
inline void net_t::set_Q_time(netlist_sig_t newQ,
|
||||
const netlist_time_ext & at) noexcept
|
||||
{
|
||||
gsl_Expects(at >= netlist_time_ext::zero());
|
||||
|
||||
@ -317,12 +353,11 @@ namespace netlist
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
class analog_net_t : public detail::net_t
|
||||
{
|
||||
public:
|
||||
|
||||
analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *rail_terminal = nullptr);
|
||||
analog_net_t(netlist_state_t &nl, const pstring &aname,
|
||||
detail::core_terminal_t *rail_terminal = nullptr);
|
||||
|
||||
void reset() noexcept override;
|
||||
|
||||
@ -331,11 +366,15 @@ namespace netlist
|
||||
// used by solver code ...
|
||||
nl_fptype *Q_Analog_state_ptr() noexcept { return *m_cur_Analog; }
|
||||
|
||||
//FIXME: needed by current solver code
|
||||
// FIXME: needed by current solver code
|
||||
solver::matrix_solver_t *solver() const noexcept { return m_solver; }
|
||||
void set_solver(solver::matrix_solver_t *solver) noexcept { m_solver = solver; }
|
||||
void set_solver(solver::matrix_solver_t *solver) noexcept
|
||||
{
|
||||
m_solver = solver;
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(const analog_net_t &lhs, const analog_net_t &rhs) noexcept
|
||||
friend constexpr bool operator==(const analog_net_t &lhs,
|
||||
const analog_net_t & rhs) noexcept
|
||||
{
|
||||
return &lhs == &rhs;
|
||||
}
|
||||
@ -348,17 +387,15 @@ namespace netlist
|
||||
class logic_net_t : public detail::net_t
|
||||
{
|
||||
public:
|
||||
logic_net_t(netlist_state_t &nl, const pstring &aname,
|
||||
detail::core_terminal_t *rail_terminal = nullptr);
|
||||
|
||||
logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *rail_terminal = nullptr);
|
||||
|
||||
using detail::net_t::Q;
|
||||
using detail::net_t::initial;
|
||||
using detail::net_t::Q;
|
||||
using detail::net_t::set_Q_and_push;
|
||||
using detail::net_t::set_Q_time;
|
||||
};
|
||||
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_NETS_H_
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define NL_CORE_PARAM_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "base_objects.h"
|
||||
#include "core_device.h"
|
||||
#include "setup.h"
|
||||
@ -30,16 +29,17 @@ namespace netlist
|
||||
class param_t : public detail::device_object_t
|
||||
{
|
||||
public:
|
||||
|
||||
enum param_type_t {
|
||||
enum param_type_t
|
||||
{
|
||||
STRING,
|
||||
DOUBLE,
|
||||
INTEGER,
|
||||
LOGIC,
|
||||
POINTER // Special-case which is always initialized at MAME startup time
|
||||
POINTER // Special-case which is always initialized at MAME startup
|
||||
// time
|
||||
};
|
||||
|
||||
//device-less, it's the responsibility of the owner to register!
|
||||
// device-less, it's the responsibility of the owner to register!
|
||||
param_t(const pstring &name);
|
||||
|
||||
param_t(core_device_t &device, const pstring &name);
|
||||
@ -52,7 +52,6 @@ namespace netlist
|
||||
virtual pstring value_string() const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
pstring get_initial(const core_device_t *dev, bool *found) const;
|
||||
|
||||
template <typename C>
|
||||
@ -64,7 +63,6 @@ namespace netlist
|
||||
device().update_param();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -72,17 +70,21 @@ namespace netlist
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
class param_num_t final: public param_t
|
||||
class param_num_t final : public param_t
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
param_num_t(core_device_t &device, const pstring &name, T val) noexcept(false);
|
||||
param_num_t(core_device_t &device, const pstring &name, T val) noexcept(
|
||||
false);
|
||||
|
||||
constexpr const T &operator()() const noexcept { return m_param; }
|
||||
constexpr operator const T& () const noexcept { return m_param; }
|
||||
constexpr operator const T &() const noexcept { return m_param; }
|
||||
|
||||
void set(const T ¶m) noexcept { set_and_update_param(m_param, param); }
|
||||
void set(const T ¶m) noexcept
|
||||
{
|
||||
set_and_update_param(m_param, param);
|
||||
}
|
||||
|
||||
pstring value_string() const override
|
||||
{
|
||||
@ -94,22 +96,27 @@ namespace netlist
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class param_enum_t final: public param_t
|
||||
class param_enum_t final : public param_t
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
param_enum_t(core_device_t &device, const pstring &name, T val) noexcept(false);
|
||||
param_enum_t(core_device_t &device, const pstring &name,
|
||||
T val) noexcept(false);
|
||||
|
||||
constexpr T operator()() const noexcept { return m_param; }
|
||||
constexpr operator T() const noexcept { return m_param; }
|
||||
void set(const T ¶m) noexcept { set_and_update_param(m_param, param); }
|
||||
constexpr operator T() const noexcept { return m_param; }
|
||||
void set(const T ¶m) noexcept
|
||||
{
|
||||
set_and_update_param(m_param, param);
|
||||
}
|
||||
|
||||
pstring value_string() const override
|
||||
{
|
||||
// returns the numerical value
|
||||
return plib::pfmt("{}")(static_cast<int>(m_param));
|
||||
}
|
||||
|
||||
private:
|
||||
T m_param;
|
||||
};
|
||||
@ -119,21 +126,25 @@ namespace netlist
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// FIXME: not a core component -> legacy
|
||||
class param_ptr_t final: public param_t
|
||||
class param_ptr_t final : public param_t
|
||||
{
|
||||
public:
|
||||
param_ptr_t(core_device_t &device, const pstring &name, std::uint8_t* val);
|
||||
std::uint8_t * operator()() const noexcept { return m_param; }
|
||||
void set(std::uint8_t *param) noexcept { set_and_update_param(m_param, param); }
|
||||
param_ptr_t(core_device_t &device, const pstring &name,
|
||||
std::uint8_t *val);
|
||||
std::uint8_t *operator()() const noexcept { return m_param; }
|
||||
void set(std::uint8_t *param) noexcept
|
||||
{
|
||||
set_and_update_param(m_param, param);
|
||||
}
|
||||
|
||||
pstring value_string() const override
|
||||
{
|
||||
// returns something which errors
|
||||
return { "PTRERROR" };
|
||||
return {"PTRERROR"};
|
||||
}
|
||||
|
||||
private:
|
||||
std::uint8_t* m_param;
|
||||
std::uint8_t *m_param;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -143,11 +154,16 @@ namespace netlist
|
||||
class param_str_t : public param_t
|
||||
{
|
||||
public:
|
||||
param_str_t(core_device_t &device, const pstring &name, const pstring &val);
|
||||
param_str_t(netlist_state_t &state, const pstring &name, const pstring &val);
|
||||
param_str_t(core_device_t &device, const pstring &name,
|
||||
const pstring &val);
|
||||
// FIXME: The device less constructor is only used by macro parameters
|
||||
// Every macro device gets a nld_wrapper object as the owner.
|
||||
// Use this as the owner and get rid of this constructor.
|
||||
param_str_t(netlist_state_t &state, const pstring &name,
|
||||
const pstring &val);
|
||||
|
||||
pstring operator()() const noexcept { return str(); }
|
||||
void set(const pstring ¶m)
|
||||
void set(const pstring ¶m)
|
||||
{
|
||||
if (*m_param != param)
|
||||
{
|
||||
@ -156,14 +172,12 @@ namespace netlist
|
||||
device().update_param();
|
||||
}
|
||||
}
|
||||
pstring value_string() const override
|
||||
{
|
||||
return *m_param;
|
||||
}
|
||||
pstring value_string() const override { return *m_param; }
|
||||
|
||||
protected:
|
||||
virtual void changed() noexcept;
|
||||
pstring str() const noexcept { return *m_param; }
|
||||
pstring str() const noexcept { return *m_param; }
|
||||
|
||||
private:
|
||||
host_arena::unique_ptr<pstring> m_param;
|
||||
};
|
||||
@ -175,23 +189,26 @@ namespace netlist
|
||||
class param_model_t : public param_str_t
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
class value_base_t
|
||||
{
|
||||
public:
|
||||
template <typename P, typename Y=T, typename DUMMY = std::enable_if_t<plib::is_arithmetic<Y>::value>>
|
||||
template <typename P, typename Y = T,
|
||||
typename DUMMY = std::enable_if_t<
|
||||
plib::is_arithmetic<Y>::value>>
|
||||
value_base_t(P ¶m, const pstring &name)
|
||||
: m_value(gsl::narrow<T>(param.value(name)))
|
||||
{
|
||||
}
|
||||
template <typename P, typename Y=T, std::enable_if_t<!plib::is_arithmetic<Y>::value, int> = 0>
|
||||
template <typename P, typename Y = T,
|
||||
std::enable_if_t<!plib::is_arithmetic<Y>::value, int> = 0>
|
||||
value_base_t(P ¶m, const pstring &name)
|
||||
: m_value(static_cast<T>(param.value_str(name)))
|
||||
{
|
||||
}
|
||||
T operator()() const noexcept { return m_value; }
|
||||
operator T() const noexcept { return m_value; }
|
||||
operator T() const noexcept { return m_value; }
|
||||
|
||||
private:
|
||||
const T m_value;
|
||||
};
|
||||
@ -199,18 +216,21 @@ namespace netlist
|
||||
using value_t = value_base_t<nl_fptype>;
|
||||
using value_str_t = value_base_t<pstring>;
|
||||
|
||||
param_model_t(core_device_t &device, const pstring &name, const pstring &val)
|
||||
param_model_t(core_device_t &device, const pstring &name,
|
||||
const pstring &val)
|
||||
: param_str_t(device, name, val)
|
||||
{
|
||||
}
|
||||
|
||||
pstring value_str(const pstring &entity);
|
||||
pstring value_str(const pstring &entity);
|
||||
nl_fptype value(const pstring &entity);
|
||||
pstring type();
|
||||
pstring type();
|
||||
// hide this
|
||||
void set(const pstring ¶m) = delete;
|
||||
|
||||
protected:
|
||||
void changed() noexcept override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
@ -227,8 +247,9 @@ namespace netlist
|
||||
}
|
||||
|
||||
plib::istream_uptr stream();
|
||||
|
||||
protected:
|
||||
void changed() noexcept override { }
|
||||
void changed() noexcept override {}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -236,17 +257,17 @@ namespace netlist
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <typename ST, std::size_t AW, std::size_t DW>
|
||||
class param_rom_t final: public param_data_t
|
||||
class param_rom_t final : public param_data_t
|
||||
{
|
||||
public:
|
||||
|
||||
param_rom_t(core_device_t &device, const pstring &name);
|
||||
|
||||
const ST & operator[] (std::size_t n) const noexcept { return m_data[n]; }
|
||||
const ST &operator[](std::size_t n) const noexcept { return m_data[n]; }
|
||||
|
||||
protected:
|
||||
void changed() noexcept override
|
||||
{
|
||||
plib::istream_read(*stream(), m_data.data(), 1<<AW);
|
||||
plib::istream_read(*stream(), m_data.data(), 1 << AW);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -254,11 +275,12 @@ namespace netlist
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
param_num_t<T>::param_num_t(core_device_t &device, const pstring &name, const T val)
|
||||
param_num_t<T>::param_num_t(core_device_t &device, const pstring &name,
|
||||
const T val)
|
||||
: param_t(device, name)
|
||||
, m_param(val)
|
||||
{
|
||||
bool found = false;
|
||||
bool found = false;
|
||||
pstring p = this->get_initial(&device, &found);
|
||||
if (found)
|
||||
{
|
||||
@ -267,7 +289,8 @@ namespace netlist
|
||||
auto valx = func.evaluate();
|
||||
if (plib::is_integral<T>::value)
|
||||
if (plib::abs(valx - plib::trunc(valx)) > nlconst::magic(1e-6))
|
||||
throw nl_exception(MF_INVALID_NUMBER_CONVERSION_1_2(device.name() + "." + name, p));
|
||||
throw nl_exception(MF_INVALID_NUMBER_CONVERSION_1_2(
|
||||
device.name() + "." + name, p));
|
||||
m_param = plib::narrow_cast<T>(valx);
|
||||
}
|
||||
|
||||
@ -275,19 +298,21 @@ namespace netlist
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
param_enum_t<T>::param_enum_t(core_device_t &device, const pstring &name, const T val)
|
||||
param_enum_t<T>::param_enum_t(core_device_t &device, const pstring &name,
|
||||
const T val)
|
||||
: param_t(device, name)
|
||||
, m_param(val)
|
||||
{
|
||||
bool found = false;
|
||||
bool found = false;
|
||||
pstring p = this->get_initial(&device, &found);
|
||||
if (found)
|
||||
{
|
||||
T temp(val);
|
||||
T temp(val);
|
||||
bool ok = temp.set_from_string(p);
|
||||
if (!ok)
|
||||
{
|
||||
device.state().log().fatal(MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
device.state().log().fatal(
|
||||
MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
throw nl_exception(MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
}
|
||||
m_param = temp;
|
||||
@ -297,13 +322,14 @@ namespace netlist
|
||||
}
|
||||
|
||||
template <typename ST, std::size_t AW, std::size_t DW>
|
||||
param_rom_t<ST, AW, DW>::param_rom_t(core_device_t &device, const pstring &name)
|
||||
param_rom_t<ST, AW, DW>::param_rom_t(core_device_t &device,
|
||||
const pstring & name)
|
||||
: param_data_t(device, name)
|
||||
{
|
||||
auto f = this->stream();
|
||||
if (!f.empty())
|
||||
{
|
||||
plib::istream_read(*f, m_data.data(), 1<<AW);
|
||||
plib::istream_read(*f, m_data.data(), 1 << AW);
|
||||
// FIXME: check for failbit if not in validation.
|
||||
}
|
||||
else
|
||||
@ -338,5 +364,4 @@ namespace netlist
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_PARAM_H_
|
||||
|
@ -8,10 +8,9 @@
|
||||
#ifndef NL_CORE_QUEUE_H_
|
||||
#define NL_CORE_QUEUE_H_
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
#include "../nl_errstr.h"
|
||||
#include "../nltypes.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "../plib/pstate.h"
|
||||
#include "../plib/pstring.h"
|
||||
@ -33,17 +32,18 @@ namespace netlist::detail
|
||||
// solvers will update inputs after parallel processing.
|
||||
|
||||
template <typename A, typename O>
|
||||
class queue_base :
|
||||
public config::timed_queue<A, plib::queue_entry_t<netlist_time_ext, O *>>,
|
||||
public plib::state_manager_t::callback_t
|
||||
class queue_base
|
||||
: public config::timed_queue<A, plib::queue_entry_t<netlist_time_ext, O *>>
|
||||
, public plib::state_manager_t::callback_t
|
||||
{
|
||||
public:
|
||||
using entry_t = plib::queue_entry_t<netlist_time_ext, O *>;
|
||||
using base_queue = config::timed_queue<A, entry_t>;
|
||||
using id_delegate = plib::pmfp<std::size_t (const O *)>;
|
||||
using obj_delegate = plib::pmfp<O * (std::size_t)>;
|
||||
using id_delegate = plib::pmfp<std::size_t(const O *)>;
|
||||
using obj_delegate = plib::pmfp<O *(std::size_t)>;
|
||||
|
||||
explicit queue_base(A &arena, std::size_t size, id_delegate get_id, obj_delegate get_obj)
|
||||
explicit queue_base(A &arena, std::size_t size, id_delegate get_id,
|
||||
obj_delegate get_obj)
|
||||
: base_queue(arena, size)
|
||||
, m_size(0)
|
||||
, m_times(size)
|
||||
@ -61,43 +61,47 @@ namespace netlist::detail
|
||||
queue_base &operator=(queue_base &&) = delete;
|
||||
|
||||
protected:
|
||||
|
||||
void register_state(plib::state_manager_t &manager, const pstring &module) override
|
||||
void register_state(plib::state_manager_t &manager,
|
||||
const pstring & module) override
|
||||
{
|
||||
manager.save_item(this, m_size, module + "." + "size");
|
||||
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());
|
||||
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 on_pre_save([[maybe_unused]] plib::state_manager_t &manager) override
|
||||
void on_pre_save(
|
||||
[[maybe_unused]] plib::state_manager_t &manager) override
|
||||
{
|
||||
m_size = this->size();
|
||||
for (std::size_t i = 0; i < m_size; i++ )
|
||||
for (std::size_t i = 0; i < m_size; i++)
|
||||
{
|
||||
m_times[i] = this->list_pointer()[i].exec_time().as_raw();
|
||||
m_times[i] = this->list_pointer()[i].exec_time().as_raw();
|
||||
m_net_ids[i] = m_get_id(this->list_pointer()[i].object());
|
||||
}
|
||||
}
|
||||
void on_post_load([[maybe_unused]] plib::state_manager_t &manager) override
|
||||
void on_post_load(
|
||||
[[maybe_unused]] plib::state_manager_t &manager) override
|
||||
{
|
||||
this->clear();
|
||||
for (std::size_t i = 0; i < m_size; i++ )
|
||||
for (std::size_t i = 0; i < m_size; i++)
|
||||
{
|
||||
O *n = m_obj_by_id(m_net_ids[i]);
|
||||
this->template push<false>(entry_t(netlist_time_ext::from_raw(m_times[i]),n));
|
||||
this->template push<false>(
|
||||
entry_t(netlist_time_ext::from_raw(m_times[i]), n));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_size;
|
||||
std::size_t m_size;
|
||||
std::vector<netlist_time_ext::internal_type> m_times;
|
||||
std::vector<std::size_t> m_net_ids;
|
||||
id_delegate m_get_id;
|
||||
obj_delegate m_obj_by_id;
|
||||
std::vector<std::size_t> m_net_ids;
|
||||
id_delegate m_get_id;
|
||||
obj_delegate m_obj_by_id;
|
||||
};
|
||||
|
||||
using queue_t = queue_base<device_arena, net_t>;
|
||||
|
||||
} // namespace netlist::detail
|
||||
|
||||
|
||||
#endif // NL_CORE_QUEUE_H_
|
||||
|
@ -179,11 +179,11 @@ namespace netlist
|
||||
models_t &models() noexcept { return m_models; }
|
||||
const models_t &models() const noexcept { return m_models; }
|
||||
|
||||
netlist_state_t &nlstate() { return m_nlstate; }
|
||||
const netlist_state_t &nlstate() const { return m_nlstate; }
|
||||
netlist_state_t &nlstate() noexcept { return m_nlstate; }
|
||||
const netlist_state_t &nlstate() const noexcept { return m_nlstate; }
|
||||
|
||||
nlparse_t &parser() { return m_parser; }
|
||||
const nlparse_t &parser() const { return m_parser; }
|
||||
nlparse_t &parser() noexcept { return m_parser; }
|
||||
const nlparse_t &parser() const noexcept { return m_parser; }
|
||||
|
||||
log_type &log() noexcept;
|
||||
const log_type &log() const noexcept;
|
||||
@ -196,10 +196,10 @@ namespace netlist
|
||||
void merge_nets(detail::net_t &this_net, detail::net_t &other_net);
|
||||
|
||||
void connect_terminals(detail::core_terminal_t &t1, detail::core_terminal_t &t2);
|
||||
void connect_input_output(detail::core_terminal_t &in, detail::core_terminal_t &out);
|
||||
void connect_terminal_output(terminal_t &in, detail::core_terminal_t &out);
|
||||
void connect_terminal_input(terminal_t &term, detail::core_terminal_t &inp);
|
||||
bool connect_input_input(detail::core_terminal_t &t1, detail::core_terminal_t &t2);
|
||||
void connect_input_output(detail::core_terminal_t &input, detail::core_terminal_t &output);
|
||||
void connect_terminal_output(detail::core_terminal_t &terminal, detail::core_terminal_t &output);
|
||||
void connect_terminal_input(detail::core_terminal_t &terminal, detail::core_terminal_t &input);
|
||||
bool connect_input_input(detail::core_terminal_t &input1, detail::core_terminal_t &input2);
|
||||
|
||||
bool connect(detail::core_terminal_t &t1, detail::core_terminal_t &t2);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define NL_CORE_STATE_VAR_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
@ -31,20 +32,19 @@ namespace netlist
|
||||
struct state_var
|
||||
{
|
||||
public:
|
||||
|
||||
using value_type = T;
|
||||
|
||||
template <typename O>
|
||||
//! Constructor.
|
||||
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
|
||||
);
|
||||
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
|
||||
);
|
||||
|
||||
template <typename O>
|
||||
//! Constructor.
|
||||
state_var(O &owner, //!< owner must have a netlist() method.
|
||||
const pstring &name //!< identifier/name for this state variable
|
||||
state_var(O & owner, //!< owner must have a netlist() method.
|
||||
const pstring &name //!< identifier/name for this state variable
|
||||
);
|
||||
|
||||
state_var(state_var &&) noexcept = delete;
|
||||
@ -63,38 +63,47 @@ namespace netlist
|
||||
return *this;
|
||||
} // OSX doesn't like noexcept
|
||||
//! Assignment operator to assign value of type T.
|
||||
constexpr state_var &operator=(const T &rhs) noexcept { m_value = rhs; return *this; }
|
||||
constexpr state_var &operator=(const T &rhs) noexcept
|
||||
{
|
||||
m_value = rhs;
|
||||
return *this;
|
||||
}
|
||||
//! Assignment move operator to assign value of type T.
|
||||
//constexpr state_var &operator=(T &&rhs) noexcept { std::swap(m_value, rhs); return *this; }
|
||||
constexpr state_var &operator=(T &&rhs) noexcept { m_value = std::move(rhs); return *this; }
|
||||
// constexpr state_var &operator=(T &&rhs) noexcept { std::swap(m_value,
|
||||
// rhs); return *this; }
|
||||
constexpr state_var &operator=(T &&rhs) noexcept
|
||||
{
|
||||
m_value = std::move(rhs);
|
||||
return *this;
|
||||
}
|
||||
//! Return non-const value of state variable.
|
||||
constexpr operator T & () noexcept { return m_value; }
|
||||
constexpr operator T &() noexcept { return m_value; }
|
||||
//! Return const value of state variable.
|
||||
constexpr operator const T & () const noexcept { return m_value; }
|
||||
constexpr operator const T &() const noexcept { return m_value; }
|
||||
//! Return non-const value of state variable.
|
||||
constexpr T & var() noexcept { return m_value; }
|
||||
constexpr T &var() noexcept { return m_value; }
|
||||
//! Return const value of state variable.
|
||||
constexpr const T & var() const noexcept { return m_value; }
|
||||
constexpr const T &var() const noexcept { return m_value; }
|
||||
//! Return non-const value of state variable.
|
||||
constexpr T & operator ()() noexcept { return m_value; }
|
||||
constexpr T &operator()() noexcept { return m_value; }
|
||||
//! Return const value of state variable.
|
||||
constexpr const T & operator ()() const noexcept { return m_value; }
|
||||
constexpr const T &operator()() const noexcept { return m_value; }
|
||||
//! Access state variable by ->.
|
||||
constexpr T * operator->() noexcept { return &m_value; }
|
||||
constexpr T *operator->() noexcept { return &m_value; }
|
||||
//! Access state variable by const ->.
|
||||
constexpr const T * operator->() const noexcept{ return &m_value; }
|
||||
constexpr const T *operator->() const noexcept { return &m_value; }
|
||||
//! Access state variable by *.
|
||||
constexpr T * operator *() noexcept { return &m_value; }
|
||||
constexpr T *operator*() noexcept { return &m_value; }
|
||||
//! Access state variable by const *.
|
||||
constexpr const T * operator *() const noexcept{ return &m_value; }
|
||||
constexpr const T *operator*() const noexcept { return &m_value; }
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
/// \brief A persistent array template.
|
||||
/// Use this state_var template to define an array whose contents are saved.
|
||||
/// Please refer to \ref state_var.
|
||||
/// Use this state_var template to define an array whose contents are
|
||||
/// saved. Please refer to \ref state_var.
|
||||
///
|
||||
/// \tparam C container class to use.
|
||||
|
||||
@ -105,24 +114,25 @@ namespace netlist
|
||||
using value_type = typename C::value_type;
|
||||
//! Constructor.
|
||||
template <typename O>
|
||||
state_container(O &owner, //!< owner must have a netlist() method.
|
||||
const pstring &name, //!< identifier/name for this state variable
|
||||
const value_type &value //!< Initial value after construction
|
||||
);
|
||||
state_container(O & owner, //!< owner must have a netlist() method.
|
||||
const pstring & name, //!< identifier/name for this state variable
|
||||
const value_type &value //!< Initial value after construction
|
||||
);
|
||||
//! Constructor.
|
||||
template <typename O>
|
||||
state_container(O &owner, //!< owner must have a netlist() method.
|
||||
const pstring &name, //!< identifier/name for this state variable
|
||||
std::size_t n, //!< number of elements to allocate
|
||||
const value_type &value //!< Initial value after construction
|
||||
);
|
||||
state_container(O & owner, //!< owner must have a netlist() method.
|
||||
const pstring & name, //!< identifier/name for this state variable
|
||||
std::size_t n, //!< number of elements to allocate
|
||||
const value_type &value //!< Initial value after construction
|
||||
);
|
||||
//! Copy Constructor.
|
||||
state_container(const state_container &rhs) noexcept = default;
|
||||
//! Destructor.
|
||||
~state_container() noexcept = default;
|
||||
//! Move Constructor.
|
||||
state_container(state_container &&rhs) noexcept = default;
|
||||
state_container &operator=(const state_container &rhs) noexcept = default;
|
||||
state_container &operator=(
|
||||
const state_container &rhs) noexcept = default;
|
||||
state_container &operator=(state_container &&rhs) noexcept = default;
|
||||
};
|
||||
|
||||
@ -160,17 +170,17 @@ namespace netlist
|
||||
template <typename C>
|
||||
template <typename O>
|
||||
state_container<C>::state_container(O &owner, const pstring &name,
|
||||
const state_container<C>::value_type & value)
|
||||
const state_container<C>::value_type &value)
|
||||
{
|
||||
owner.state().save(owner, static_cast<C &>(*this), owner.name(), name);
|
||||
for (std::size_t i=0; i < this->size(); i++)
|
||||
for (std::size_t i = 0; i < this->size(); i++)
|
||||
(*this)[i] = value;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
template <typename O>
|
||||
state_container<C>::state_container(O &owner, const pstring &name,
|
||||
std::size_t n, const state_container<C>::value_type & value)
|
||||
std::size_t n, const state_container<C>::value_type &value)
|
||||
: C(n, value)
|
||||
{
|
||||
owner.state().save(owner, static_cast<C &>(*this), owner.name(), name);
|
||||
@ -190,7 +200,6 @@ namespace netlist
|
||||
extern template struct state_var<std::int64_t>;
|
||||
extern template struct state_var<bool>;
|
||||
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
namespace plib
|
||||
|
@ -108,63 +108,11 @@ namespace netlist::devices {
|
||||
nld_power_pins m_supply;
|
||||
};
|
||||
|
||||
NETLIB_OBJECT(CD4020)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR_MODEL(CD4020, "CD4XXX")
|
||||
, m_sub(*this, "A")
|
||||
{
|
||||
register_sub_alias("IP", "A.IP");
|
||||
register_sub_alias("RESET", "A.RESET");
|
||||
register_sub_alias("Q1", "A.Q1");
|
||||
register_sub_alias("Q4", "A.Q4");
|
||||
register_sub_alias("Q5", "A.Q5");
|
||||
register_sub_alias("Q6", "A.Q6");
|
||||
register_sub_alias("Q7", "A.Q7");
|
||||
register_sub_alias("Q8", "A.Q8");
|
||||
register_sub_alias("Q9", "A.Q9");
|
||||
register_sub_alias("Q10", "A.Q10");
|
||||
register_sub_alias("Q11", "A.Q11");
|
||||
register_sub_alias("Q12", "A.Q12");
|
||||
register_sub_alias("Q13", "A.Q13");
|
||||
register_sub_alias("Q14", "A.Q14");
|
||||
register_sub_alias("VDD", "A.VDD");
|
||||
register_sub_alias("VSS", "A.VSS");
|
||||
}
|
||||
// FIXME: Exposes Q2 and Q3 as well
|
||||
using NETLIB_NAME(CD4020_impl) = nld_CD4020_sub<14, 0x3ff9>;
|
||||
NETLIB_DEVICE_IMPL_ALIAS(CD4020, CD4020_impl,"CD4020", "+IP,+RESET,+VDD,+VSS")
|
||||
|
||||
//NETLIB_RESETI() {}
|
||||
|
||||
private:
|
||||
NETLIB_SUB(CD4020_sub)<14, 0x3ff9> m_sub;
|
||||
};
|
||||
|
||||
NETLIB_OBJECT(CD4024)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR_MODEL(CD4024, "CD4XXX")
|
||||
, m_sub(*this, "A")
|
||||
{
|
||||
register_sub_alias("IP", "A.IP");
|
||||
register_sub_alias("RESET", "A.RESET");
|
||||
register_sub_alias("Q1", "A.Q1");
|
||||
register_sub_alias("Q2", "A.Q2");
|
||||
register_sub_alias("Q3", "A.Q3");
|
||||
register_sub_alias("Q4", "A.Q4");
|
||||
register_sub_alias("Q5", "A.Q5");
|
||||
register_sub_alias("Q6", "A.Q6");
|
||||
register_sub_alias("Q7", "A.Q7");
|
||||
register_sub_alias("VDD", "A.VDD");
|
||||
register_sub_alias("VSS", "A.VSS");
|
||||
}
|
||||
|
||||
//NETLIB_RESETI() {}
|
||||
|
||||
private:
|
||||
NETLIB_SUB(CD4020_sub)<7, 0x7f> m_sub;
|
||||
};
|
||||
|
||||
|
||||
|
||||
NETLIB_DEVICE_IMPL(CD4020, "CD4020", "+IP,+RESET,+VDD,+VSS")
|
||||
|
||||
NETLIB_DEVICE_IMPL(CD4024, "CD4024", "")
|
||||
using NETLIB_NAME(CD4024_impl) = nld_CD4020_sub<7, 0x7f>;
|
||||
NETLIB_DEVICE_IMPL_ALIAS(CD4024, CD4024_impl, "CD4024", "")
|
||||
|
||||
} // namespace netlist::devices
|
||||
|
@ -101,40 +101,40 @@ namespace netlist::devices {
|
||||
const nl_fptype Roff = plib::reciprocal(exec().gmin());
|
||||
const nl_fptype RX = newx ? Ron : Roff;
|
||||
const nl_fptype RY = newy ? Ron : Roff;
|
||||
if (m_RX.solver() == m_RY.solver())
|
||||
if (m_RX().solver() == m_RY().solver())
|
||||
{
|
||||
m_RX.change_state([this, &RX, &RY]()
|
||||
m_RX().change_state([this, &RX, &RY]()
|
||||
{
|
||||
m_RX.set_R(RX);
|
||||
m_RY.set_R(RY);
|
||||
m_RX().set_R(RX);
|
||||
m_RY().set_R(RY);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RX.change_state([this, &RX]()
|
||||
m_RX().change_state([this, &RX]()
|
||||
{
|
||||
m_RX.set_R(RX);
|
||||
m_RX().set_R(RX);
|
||||
});
|
||||
m_RY.change_state([this, &RY]()
|
||||
m_RY().change_state([this, &RY]()
|
||||
{
|
||||
m_RY.set_R(RY);
|
||||
m_RY().set_R(RY);
|
||||
});
|
||||
}
|
||||
m_last_x = newx;
|
||||
m_last_y = newy;
|
||||
}
|
||||
|
||||
analog::NETLIB_SUB(R_base) m_RX;
|
||||
analog::NETLIB_SUB(R_base) m_RY;
|
||||
analog_input_t m_select;
|
||||
analog_input_t m_inhibit;
|
||||
analog_input_t m_VEE;
|
||||
param_fp_t m_base_r;
|
||||
state_var<bool> m_last_x;
|
||||
state_var<bool> m_last_y;
|
||||
state_var<bool> m_select_state;
|
||||
state_var<bool> m_inhibit_state;
|
||||
nld_power_pins m_supply;
|
||||
NETLIB_SUB_NS(analog, R_base) m_RX;
|
||||
NETLIB_SUB_NS(analog, R_base) m_RY;
|
||||
analog_input_t m_select;
|
||||
analog_input_t m_inhibit;
|
||||
analog_input_t m_VEE;
|
||||
param_fp_t m_base_r;
|
||||
state_var<bool> m_last_x;
|
||||
state_var<bool> m_last_y;
|
||||
state_var<bool> m_select_state;
|
||||
state_var<bool> m_inhibit_state;
|
||||
nld_power_pins m_supply;
|
||||
};
|
||||
|
||||
NETLIB_DEVICE_IMPL(CD4053_GATE, "CD4053_GATE", "")
|
||||
|
@ -42,7 +42,7 @@ namespace netlist::devices {
|
||||
{
|
||||
// Start in off condition
|
||||
// FIXME: is ROFF correct?
|
||||
m_R.set_R(plib::reciprocal(exec().gmin()));
|
||||
m_R().set_R(plib::reciprocal(exec().gmin()));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -67,11 +67,11 @@ namespace netlist::devices {
|
||||
if (R > nlconst::zero() && (m_last != new_state))
|
||||
{
|
||||
m_last = new_state;
|
||||
m_R.change_state([this, &R]() -> void { this->m_R.set_R(R);});
|
||||
m_R().change_state([this, &R]() -> void { this->m_R().set_R(R);});
|
||||
}
|
||||
}
|
||||
|
||||
analog::NETLIB_SUB(R_base) m_R;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R;
|
||||
analog_input_t m_control;
|
||||
param_fp_t m_base_r;
|
||||
state_var<bool> m_last;
|
||||
|
@ -42,27 +42,27 @@ namespace netlist::devices {
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_R.set_R(plib::reciprocal(exec().gmin()));
|
||||
m_R().set_R(plib::reciprocal(exec().gmin()));
|
||||
}
|
||||
|
||||
NETLIB_HANDLERI(inputs)
|
||||
{
|
||||
m_R.change_state([this]()
|
||||
m_R().change_state([this]()
|
||||
{
|
||||
if (m_S() && !m_E())
|
||||
m_R.set_R(m_base_r());
|
||||
m_R().set_R(m_base_r());
|
||||
else
|
||||
m_R.set_R(plib::reciprocal(exec().gmin()));
|
||||
m_R().set_R(plib::reciprocal(exec().gmin()));
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
analog::NETLIB_SUB(R_base) m_R;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R;
|
||||
|
||||
logic_input_t m_S;
|
||||
logic_input_t m_E;
|
||||
param_fp_t m_base_r;
|
||||
nld_power_pins m_supply;
|
||||
logic_input_t m_S;
|
||||
logic_input_t m_E;
|
||||
param_fp_t m_base_r;
|
||||
nld_power_pins m_supply;
|
||||
};
|
||||
|
||||
NETLIB_DEVICE_IMPL(CD4316_GATE, "CD4316_GATE", "")
|
||||
|
@ -134,11 +134,7 @@ namespace netlist::devices {
|
||||
nld_power_pins m_power_pins;
|
||||
};
|
||||
|
||||
NETLIB_OBJECT_DERIVED(74113A, 74113)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(74113A) { }
|
||||
|
||||
};
|
||||
using NETLIB_NAME(74113A) = NETLIB_NAME(74113);
|
||||
|
||||
NETLIB_DEVICE_IMPL(74113, "TTL_74113", "+CLK,+J,+K,+CLRQ,@VCC,@GND")
|
||||
NETLIB_DEVICE_IMPL(74113A, "TTL_74113A", "+CLK,+J,+K,+CLRQ,@VCC,@GND")
|
||||
|
@ -128,8 +128,8 @@ namespace netlist::devices {
|
||||
connect("RN.1", "RP.2");
|
||||
connect("_CV", "RN.1");
|
||||
|
||||
m_RP.m_RON.set(D::RI());
|
||||
m_RN.m_RON.set(D::RI());
|
||||
m_RP().m_RON.set(D::RI());
|
||||
m_RN().m_RON.set(D::RI());
|
||||
}
|
||||
|
||||
NETLIB_HANDLERI(ab_clear)
|
||||
@ -169,7 +169,7 @@ namespace netlist::devices {
|
||||
{
|
||||
if (m_state == 1)
|
||||
{
|
||||
const nl_fptype vLow = m_KP * m_RP.P()();
|
||||
const nl_fptype vLow = m_KP * m_RP().P()();
|
||||
if (m_CV() < vLow)
|
||||
{
|
||||
m_RN_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
|
||||
@ -178,7 +178,7 @@ namespace netlist::devices {
|
||||
}
|
||||
if (m_state == 2)
|
||||
{
|
||||
const nl_fptype vHigh = (nlconst::one() - m_KP) * m_RP.P()();
|
||||
const nl_fptype vHigh = (nlconst::one() - m_KP) * m_RP().P()();
|
||||
if (m_CV() > vHigh)
|
||||
{
|
||||
m_RP_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
|
||||
@ -192,8 +192,8 @@ namespace netlist::devices {
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_RP.reset();
|
||||
m_RN.reset();
|
||||
m_RP().reset();
|
||||
m_RN().reset();
|
||||
|
||||
//m_RP.set_R(R_OFF);
|
||||
//m_RN.set_R(R_OFF);
|
||||
|
@ -37,15 +37,15 @@
|
||||
|
||||
namespace netlist::devices {
|
||||
|
||||
NETLIB_OBJECT(74174_GATE)
|
||||
NETLIB_OBJECT(74174)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(74174_GATE)
|
||||
NETLIB_CONSTRUCTOR(74174)
|
||||
, m_CLK(*this, "CLK", NETLIB_DELEGATE(clk))
|
||||
, m_Q(*this, "Q")
|
||||
, m_Q(*this, 1, "Q{}")
|
||||
, m_clrq(*this, "m_clr", 0)
|
||||
, m_data(*this, "m_data", 0)
|
||||
, m_D(*this, "D", NETLIB_DELEGATE(other))
|
||||
, m_CLRQ(*this, "CLRQ", NETLIB_DELEGATE(other))
|
||||
, m_D(*this, 1, "D{}", NETLIB_DELEGATE(other))
|
||||
, m_CLRQ(*this, "CLRQ", NETLIB_DELEGATE(clrq))
|
||||
, m_power_pins(*this)
|
||||
{
|
||||
}
|
||||
@ -57,22 +57,27 @@ namespace netlist::devices {
|
||||
m_data = 0xFF;
|
||||
}
|
||||
|
||||
NETLIB_HANDLERI(other)
|
||||
private:
|
||||
NETLIB_HANDLERI(clrq)
|
||||
{
|
||||
netlist_sig_t d = m_D();
|
||||
m_clrq = m_CLRQ();
|
||||
if (!m_clrq)
|
||||
{
|
||||
m_Q.push(0, NLTIME_FROM_NS(40));
|
||||
m_data = 0;
|
||||
} else if (d != m_data)
|
||||
{
|
||||
m_data = d;
|
||||
m_CLK.activate_lh();
|
||||
m_Q.push(m_data, NLTIME_FROM_NS(40));
|
||||
m_CLK.inactivate();
|
||||
}
|
||||
else
|
||||
m_CLK.activate_lh();
|
||||
}
|
||||
|
||||
NETLIB_HANDLERI(other)
|
||||
{
|
||||
m_data = m_D();
|
||||
if (m_clrq)
|
||||
m_CLK.activate_lh();
|
||||
}
|
||||
|
||||
private:
|
||||
NETLIB_HANDLERI(clk)
|
||||
{
|
||||
if (m_clrq)
|
||||
@ -83,82 +88,16 @@ namespace netlist::devices {
|
||||
}
|
||||
|
||||
logic_input_t m_CLK;
|
||||
logic_output_t m_Q;
|
||||
object_array_t<logic_output_t, 6> m_Q;
|
||||
|
||||
state_var<netlist_sig_t> m_clrq;
|
||||
state_var<netlist_sig_t> m_data;
|
||||
|
||||
logic_input_t m_D;
|
||||
object_array_t<logic_input_t, 6> m_D;
|
||||
logic_input_t m_CLRQ;
|
||||
nld_power_pins m_power_pins;
|
||||
};
|
||||
|
||||
NETLIB_OBJECT(74174)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(74174)
|
||||
, A(*this, "A")
|
||||
, B(*this, "B")
|
||||
, C(*this, "C")
|
||||
, D(*this, "D")
|
||||
, E(*this, "E")
|
||||
, F(*this, "F")
|
||||
{
|
||||
register_sub_alias("CLRQ", "A.CLRQ");
|
||||
connect("A.CLRQ", "B.CLRQ");
|
||||
connect("A.CLRQ", "C.CLRQ");
|
||||
connect("A.CLRQ", "D.CLRQ");
|
||||
connect("A.CLRQ", "E.CLRQ");
|
||||
connect("A.CLRQ", "F.CLRQ");
|
||||
|
||||
register_sub_alias("CLK", "A.CLK");
|
||||
connect("A.CLK", "B.CLK");
|
||||
connect("A.CLK", "C.CLK");
|
||||
connect("A.CLK", "D.CLK");
|
||||
connect("A.CLK", "E.CLK");
|
||||
connect("A.CLK", "F.CLK");
|
||||
|
||||
register_sub_alias("D1", "A.D");
|
||||
register_sub_alias("Q1", "A.Q");
|
||||
|
||||
register_sub_alias("D2", "B.D");
|
||||
register_sub_alias("Q2", "B.Q");
|
||||
|
||||
register_sub_alias("D3", "C.D");
|
||||
register_sub_alias("Q3", "C.Q");
|
||||
|
||||
register_sub_alias("D4", "D.D");
|
||||
register_sub_alias("Q4", "D.Q");
|
||||
|
||||
register_sub_alias("D5", "E.D");
|
||||
register_sub_alias("Q5", "E.Q");
|
||||
|
||||
register_sub_alias("D6", "F.D");
|
||||
register_sub_alias("Q6", "F.Q");
|
||||
|
||||
register_sub_alias("GND", "A.GND");
|
||||
connect("A.GND", "B.GND");
|
||||
connect("A.GND", "C.GND");
|
||||
connect("A.GND", "D.GND");
|
||||
connect("A.GND", "E.GND");
|
||||
connect("A.GND", "F.GND");
|
||||
|
||||
register_sub_alias("VCC", "A.VCC");
|
||||
connect("A.VCC", "B.VCC");
|
||||
connect("A.VCC", "C.VCC");
|
||||
connect("A.VCC", "D.VCC");
|
||||
connect("A.VCC", "E.VCC");
|
||||
connect("A.VCC", "F.VCC");
|
||||
}
|
||||
//NETLIB_RESETI() {}
|
||||
private:
|
||||
NETLIB_SUB(74174_GATE) A;
|
||||
NETLIB_SUB(74174_GATE) B;
|
||||
NETLIB_SUB(74174_GATE) C;
|
||||
NETLIB_SUB(74174_GATE) D;
|
||||
NETLIB_SUB(74174_GATE) E;
|
||||
NETLIB_SUB(74174_GATE) F;
|
||||
};
|
||||
|
||||
NETLIB_DEVICE_IMPL(74174, "TTL_74174", "+CLK,+D1,+D2,+D3,+D4,+D5,+D6,+CLRQ,@VCC,@GND")
|
||||
|
||||
} // namespace netlist::devices
|
||||
|
@ -127,10 +127,7 @@ namespace netlist::devices {
|
||||
nld_power_pins m_power_pins;
|
||||
};
|
||||
|
||||
NETLIB_OBJECT_DERIVED(7473A, 7473)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(7473A) { }
|
||||
};
|
||||
using NETLIB_NAME(7473A) = NETLIB_NAME(7473);
|
||||
|
||||
NETLIB_DEVICE_IMPL(7473, "TTL_7473", "+CLK,+J,+K,+CLRQ,@VCC,@GND")
|
||||
NETLIB_DEVICE_IMPL(7473A, "TTL_7473A", "+CLK,+J,+K,+CLRQ,@VCC,@GND")
|
||||
|
@ -121,8 +121,8 @@ namespace netlist::devices {
|
||||
private:
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_R_FC.set_R( nlconst::magic(90000.0));
|
||||
m_R_RNG.set_R(nlconst::magic(90000.0));
|
||||
m_R_FC().set_R( nlconst::magic(90000.0));
|
||||
m_R_RNG().set_R(nlconst::magic(90000.0));
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
@ -131,8 +131,8 @@ namespace netlist::devices {
|
||||
}
|
||||
|
||||
SN74LS629clk m_clock;
|
||||
analog::NETLIB_SUB(R_base) m_R_FC;
|
||||
analog::NETLIB_SUB(R_base) m_R_RNG;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R_FC;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R_RNG;
|
||||
|
||||
logic_input_t m_ENQ;
|
||||
analog_input_t m_RNG;
|
||||
|
@ -114,8 +114,8 @@ namespace netlist::devices {
|
||||
{
|
||||
if (!m_RESET())
|
||||
{
|
||||
m_A.reset_shifter();
|
||||
m_B.reset_shifter();
|
||||
m_A().reset_shifter();
|
||||
m_B().reset_shifter();
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,8 +123,8 @@ namespace netlist::devices {
|
||||
{
|
||||
if (!m_last_CLK && m_CLK())
|
||||
{
|
||||
m_A.shift();
|
||||
m_B.shift();
|
||||
m_A().shift();
|
||||
m_B().shift();
|
||||
}
|
||||
m_last_CLK = m_CLK();
|
||||
m_last_CLKA = m_CLKA();
|
||||
@ -135,7 +135,7 @@ namespace netlist::devices {
|
||||
{
|
||||
if (!m_last_CLKA && m_CLKA())
|
||||
{
|
||||
m_A.shift();
|
||||
m_A().shift();
|
||||
}
|
||||
m_last_CLKA = m_CLKA();
|
||||
}
|
||||
@ -144,7 +144,7 @@ namespace netlist::devices {
|
||||
{
|
||||
if (!m_last_CLKB && m_CLKB())
|
||||
{
|
||||
m_B.shift();
|
||||
m_B().shift();
|
||||
}
|
||||
m_last_CLKB = m_CLKB();
|
||||
}
|
||||
|
@ -107,10 +107,10 @@ namespace netlist::devices {
|
||||
{
|
||||
if (m_last_CP && !m_CP())
|
||||
{
|
||||
m_A.shift();
|
||||
m_B.shift();
|
||||
m_C.shift();
|
||||
m_D.shift();
|
||||
m_A().shift();
|
||||
m_B().shift();
|
||||
m_C().shift();
|
||||
m_D().shift();
|
||||
}
|
||||
m_last_CP = m_CP();
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ namespace netlist::devices {
|
||||
static constexpr std::size_t BUF_SIZE=16384;
|
||||
static constexpr std::size_t BUFFERS=4;
|
||||
analog_input_t m_I;
|
||||
private:
|
||||
plib::ofstream m_strm;
|
||||
plib::putf8_writer m_writer;
|
||||
bool m_reset;
|
||||
@ -129,14 +130,17 @@ namespace netlist::devices {
|
||||
std::thread m_write_thread;
|
||||
};
|
||||
|
||||
NETLIB_OBJECT_DERIVED(logD, log)
|
||||
class NETLIB_NAME(logD) : public NETLIB_NAME(log)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(logD)
|
||||
public:
|
||||
NETLIB_NAME(logD)(constructor_param_t data)
|
||||
: NETLIB_NAME(log)(data)
|
||||
, m_I2(*this, "I2", nl_delegate(&NETLIB_NAME(logD)::input, this))
|
||||
{
|
||||
m_I.set_delegate(nl_delegate(&NETLIB_NAME(logD)::input, this));
|
||||
}
|
||||
|
||||
private:
|
||||
NETLIB_HANDLERI(input)
|
||||
{
|
||||
log_value(static_cast<nl_fptype>(m_I() - m_I2()));
|
||||
|
@ -48,7 +48,7 @@ namespace netlist::devices {
|
||||
{
|
||||
//m_V0.initial(0.0);
|
||||
//m_RV.do_reset();
|
||||
m_RV.set_G_V_I(plib::reciprocal(m_R_LOW()),
|
||||
m_RV().set_G_V_I(plib::reciprocal(m_R_LOW()),
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_FREQ()));
|
||||
@ -86,15 +86,15 @@ namespace netlist::devices {
|
||||
const nl_fptype R = state ? m_R_HIGH : m_R_LOW;
|
||||
const nl_fptype V = state ? m_VDD() : m_VSS();
|
||||
|
||||
m_RV.change_state([this, &R, &V]()
|
||||
m_RV().change_state([this, &R, &V]()
|
||||
{
|
||||
m_RV.set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
|
||||
m_RV().set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
analog::NETLIB_SUB(two_terminal) m_RV;
|
||||
NETLIB_SUB_NS(analog, two_terminal) m_RV;
|
||||
analog_input_t m_VDD;
|
||||
analog_input_t m_VGG;
|
||||
analog_input_t m_VSS;
|
||||
|
@ -46,11 +46,11 @@ namespace netlist::devices {
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
/* FIXME make resistances a parameter, properly model other variants */
|
||||
m_R1.set_R(nlconst::magic(5000));
|
||||
m_R2.set_R(nlconst::magic(5000));
|
||||
m_R3.set_R(nlconst::magic(5000));
|
||||
m_ROUT.set_R(nlconst::magic(20));
|
||||
m_RDIS.set_R(nlconst::magic(R_OFF));
|
||||
m_R1().set_R(nlconst::magic(5000));
|
||||
m_R2().set_R(nlconst::magic(5000));
|
||||
m_R3().set_R(nlconst::magic(5000));
|
||||
m_ROUT().set_R(nlconst::magic(20));
|
||||
m_RDIS().set_R(nlconst::magic(R_OFF));
|
||||
|
||||
m_last_out = true;
|
||||
// Check for astable setup, usually TRIG AND THRES connected. Enable
|
||||
@ -66,8 +66,8 @@ namespace netlist::devices {
|
||||
|
||||
const auto reset = m_RESET();
|
||||
|
||||
const nl_fptype v_threshold = clamp_hl(m_R2.P()(), nlconst::magic(0.7), nlconst::magic(1.4));
|
||||
const nl_fptype v_trigger = clamp_hl(m_R2.N()(), nlconst::magic(0.7), nlconst::magic(1.4));
|
||||
const nl_fptype v_threshold = clamp_hl(m_R2().P()(), nlconst::magic(0.7), nlconst::magic(1.4));
|
||||
const nl_fptype v_trigger = clamp_hl(m_R2().N()(), nlconst::magic(0.7), nlconst::magic(1.4));
|
||||
|
||||
// avoid artificial oscillation due to overshoot compensation when
|
||||
// the control input is used.
|
||||
@ -106,11 +106,11 @@ namespace netlist::devices {
|
||||
m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), overshoot_limit);
|
||||
//if (this->name() == "IC6_2")
|
||||
// printf("%f %s %f %f %f\n", exec().time().as_double(), this->name().c_str(), m_overshoot(), m_R2.P()(), m_THRES());
|
||||
m_RDIS.change_state([this]()
|
||||
m_RDIS().change_state([this]()
|
||||
{
|
||||
m_RDIS.set_R(nlconst::magic(R_ON));
|
||||
m_RDIS().set_R(nlconst::magic(R_ON));
|
||||
});
|
||||
m_OUT.push(m_R3.N()());
|
||||
m_OUT.push(m_R3().N()());
|
||||
}
|
||||
else if (!m_last_out && out)
|
||||
{
|
||||
@ -121,21 +121,21 @@ namespace netlist::devices {
|
||||
m_undershoot += (v_trigger - m_TRIG());
|
||||
m_undershoot = plib::clamp(m_undershoot(), nlconst::zero(), overshoot_limit);
|
||||
#endif
|
||||
m_RDIS.change_state([this]()
|
||||
m_RDIS().change_state([this]()
|
||||
{
|
||||
m_RDIS.set_R(nlconst::magic(R_OFF));
|
||||
m_RDIS().set_R(nlconst::magic(R_OFF));
|
||||
});
|
||||
// FIXME: Should be delayed by 100ns
|
||||
m_OUT.push(m_R1.P()());
|
||||
m_OUT.push(m_R1().P()());
|
||||
}
|
||||
m_last_reset = reset;
|
||||
m_last_out = out;
|
||||
}
|
||||
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;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R1;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R2;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R3;
|
||||
NETLIB_SUB_NS(analog, R_base) m_ROUT;
|
||||
NETLIB_SUB_NS(analog, R_base) m_RDIS;
|
||||
|
||||
logic_input_t m_RESET;
|
||||
analog_input_t m_THRES;
|
||||
@ -151,7 +151,7 @@ namespace netlist::devices {
|
||||
|
||||
nl_fptype clamp_hl(const nl_fptype v, const nl_fptype a, const nl_fptype b) noexcept
|
||||
{
|
||||
const nl_fptype vcc = m_R1.P()();
|
||||
const nl_fptype vcc = m_R1().P()();
|
||||
return plib::clamp(v, b, vcc - a);
|
||||
}
|
||||
};
|
||||
|
@ -44,14 +44,18 @@
|
||||
*/
|
||||
|
||||
#include "nl_base.h"
|
||||
#include "analog/nlid_twoterm.h"
|
||||
#include "nl_factory.h"
|
||||
|
||||
namespace netlist::analog {
|
||||
#include "analog/nlid_twoterm.h"
|
||||
|
||||
NETLIB_OBJECT_DERIVED(r2r_dac, two_terminal)
|
||||
namespace netlist::analog
|
||||
{
|
||||
|
||||
class nld_r2r_dac : public nld_two_terminal
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(r2r_dac)
|
||||
public:
|
||||
nld_r2r_dac(constructor_param_t data)
|
||||
: nld_two_terminal(data)
|
||||
, m_VIN(*this, "VIN", nlconst::one())
|
||||
, m_R(*this, "R", nlconst::one())
|
||||
, m_num(*this, "N", 1)
|
||||
@ -62,31 +66,28 @@ namespace netlist::analog {
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
//NETLIB_RESETI();
|
||||
//NETLIB_UPDATEI();
|
||||
// NETLIB_RESETI();
|
||||
|
||||
protected:
|
||||
param_fp_t m_VIN;
|
||||
param_fp_t m_R;
|
||||
param_fp_t m_VIN;
|
||||
param_fp_t m_R;
|
||||
param_int_t m_num;
|
||||
param_int_t m_val;
|
||||
};
|
||||
|
||||
|
||||
NETLIB_UPDATE_PARAM(r2r_dac)
|
||||
{
|
||||
nl_fptype V = m_VIN() / static_cast<nl_fptype>(1 << m_num())
|
||||
* static_cast<nl_fptype>(m_val());
|
||||
change_state([this, &V]()
|
||||
{
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), V, nlconst::zero());
|
||||
}
|
||||
);
|
||||
* static_cast<nl_fptype>(m_val());
|
||||
change_state(
|
||||
[this, &V]()
|
||||
{ this->set_G_V_I(plib::reciprocal(m_R()), V, nlconst::zero()); });
|
||||
}
|
||||
|
||||
} // namespace netlist::analog
|
||||
|
||||
namespace netlist::devices {
|
||||
namespace netlist::devices
|
||||
{
|
||||
|
||||
NETLIB_DEVICE_IMPL_NS(analog, r2r_dac, "R2R_DAC", "VIN,R,N")
|
||||
|
||||
|
@ -169,9 +169,13 @@ namespace netlist::devices {
|
||||
, m_A(*this, 0, "A{}", NETLIB_DELEGATE(addr))
|
||||
, m_CEQ(*this, 1,
|
||||
D::chip_enable_mask::value ^ static_cast<size_t>(0xffff), pstring("CE{}"),
|
||||
std::array<nl_delegate, 3>{ NETLIB_DELEGATE(ce<0>),
|
||||
NETLIB_DELEGATE(ce<1>),
|
||||
NETLIB_DELEGATE(ce<2>)})
|
||||
// Causes a expected primary expression before { with gcc9
|
||||
//std::array<nl_delegate, 3>{NETLIB_DELEGATE(ce<0>),
|
||||
// NETLIB_DELEGATE(ce<1>),
|
||||
// NETLIB_DELEGATE(ce<2>)})
|
||||
std::array<nl_delegate, 3>{nl_delegate(& NETLIB_NAME(generic_prom) :: ce<0>, this),
|
||||
nl_delegate(& NETLIB_NAME(generic_prom) :: ce<1>, this),
|
||||
nl_delegate(& NETLIB_NAME(generic_prom) :: ce<2>, this)})
|
||||
, m_O(*this, D::data_name_offset::value, "O{}", m_TE())
|
||||
, m_ROM(*this, "ROM")
|
||||
, m_power_pins(*this)
|
||||
|
@ -66,18 +66,18 @@ namespace netlist::devices {
|
||||
|
||||
connect("A", "RVI.1");
|
||||
// FIXME: need a symbolic reference from connect as well
|
||||
connect(m_supply.GND(), m_RVI.N());
|
||||
connect(m_supply.GND(), m_RVO.N());
|
||||
connect(m_supply.GND(), m_RVI().N());
|
||||
connect(m_supply.GND(), m_RVO().N());
|
||||
}
|
||||
|
||||
protected:
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_last_state = 1;
|
||||
m_RVI.reset();
|
||||
m_RVO.reset();
|
||||
m_RVI.set_G_V_I(plib::reciprocal(m_modacc.m_RI()), m_modacc.m_VI, nlconst::zero());
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_modacc.m_ROL()), m_modacc.m_VOL, nlconst::zero());
|
||||
m_RVI().reset();
|
||||
m_RVO().reset();
|
||||
m_RVI().set_G_V_I(plib::reciprocal(m_modacc.m_RI()), m_modacc.m_VI, nlconst::zero());
|
||||
m_RVO().set_G_V_I(plib::reciprocal(m_modacc.m_ROL()), m_modacc.m_VOL, nlconst::zero());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -89,9 +89,9 @@ namespace netlist::devices {
|
||||
if (va < m_modacc.m_VTM)
|
||||
{
|
||||
m_last_state = 0;
|
||||
m_RVO.change_state([this]()
|
||||
m_RVO().change_state([this]()
|
||||
{
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_modacc.m_ROH()), m_modacc.m_VOH, nlconst::zero());
|
||||
m_RVO().set_G_V_I(plib::reciprocal(m_modacc.m_ROH()), m_modacc.m_VOH, nlconst::zero());
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -100,9 +100,9 @@ namespace netlist::devices {
|
||||
if (va > m_modacc.m_VTP)
|
||||
{
|
||||
m_last_state = 1;
|
||||
m_RVO.change_state([this]()
|
||||
m_RVO().change_state([this]()
|
||||
{
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_modacc.m_ROL()), m_modacc.m_VOL, nlconst::zero());
|
||||
m_RVO().set_G_V_I(plib::reciprocal(m_modacc.m_ROL()), m_modacc.m_VOL, nlconst::zero());
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -110,8 +110,8 @@ namespace netlist::devices {
|
||||
|
||||
analog_input_t m_A;
|
||||
NETLIB_NAME(power_pins) m_supply;
|
||||
analog::NETLIB_SUB(two_terminal) m_RVI;
|
||||
analog::NETLIB_SUB(two_terminal) m_RVO;
|
||||
NETLIB_SUB_NS(analog, two_terminal) m_RVI;
|
||||
NETLIB_SUB_NS(analog, two_terminal) m_RVO;
|
||||
param_model_t m_stmodel;
|
||||
schmitt_trigger_model_t m_modacc;
|
||||
state_var<int> m_last_state;
|
||||
|
@ -21,9 +21,9 @@ namespace netlist::devices {
|
||||
|
||||
static constexpr std::array<std::pair<const char *, const char *>, 3> power_syms = {{ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}};
|
||||
|
||||
nld_base_proxy::nld_base_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
nld_base_proxy::nld_base_proxy(device_param_t data,
|
||||
const logic_t *inout_proxied)
|
||||
: device_t(anetlist, name, inout_proxied->logic_family())
|
||||
: device_t(data, inout_proxied->logic_family())
|
||||
, m_tp(nullptr)
|
||||
, m_tn(nullptr)
|
||||
{
|
||||
@ -32,15 +32,14 @@ namespace netlist::devices {
|
||||
throw nl_exception(MF_NULLPTR_FAMILY_NP("nld_base_proxy"));
|
||||
}
|
||||
|
||||
|
||||
bool f = false;
|
||||
for (const auto & pwr_sym : power_syms)
|
||||
{
|
||||
pstring devname = inout_proxied->device().name();
|
||||
|
||||
auto *tp_ct(anetlist.setup().find_terminal(devname + "." + pstring(pwr_sym.first),
|
||||
auto *tp_ct(state().setup().find_terminal(devname + "." + pstring(pwr_sym.first),
|
||||
/*detail::terminal_type::INPUT,*/ false));
|
||||
auto *tp_cn(anetlist.setup().find_terminal(devname + "." + pstring(pwr_sym.second),
|
||||
auto *tp_cn(state().setup().find_terminal(devname + "." + pstring(pwr_sym.second),
|
||||
/*detail::terminal_type::INPUT,*/ false));
|
||||
if ((tp_ct != nullptr) && (tp_cn != nullptr))
|
||||
{
|
||||
@ -49,23 +48,23 @@ namespace netlist::devices {
|
||||
if (!tp_cn->is_analog())
|
||||
throw nl_exception(plib::pfmt("Not an analog terminal: {1}")(tp_cn->name()));
|
||||
|
||||
auto *tp_t = dynamic_cast<analog_t* >(tp_ct);
|
||||
auto *tn_t = dynamic_cast<analog_t *>(tp_cn);
|
||||
if (f && (tp_t != nullptr && tn_t != nullptr))
|
||||
auto tp_t = plib::dynamic_downcast<analog_t* >(tp_ct);
|
||||
auto tn_t = plib::dynamic_downcast<analog_t *>(tp_cn);
|
||||
if (f && (tp_t && tn_t))
|
||||
log().warning(MI_MULTIPLE_POWER_TERMINALS_ON_DEVICE(inout_proxied->device().name(),
|
||||
m_tp->name(), m_tn->name(),
|
||||
tp_t != nullptr ? tp_t->name() : "",
|
||||
tn_t != nullptr ? tn_t->name() : ""));
|
||||
else if (tp_t != nullptr && tn_t != nullptr)
|
||||
tp_t ? (*tp_t)->name() : "",
|
||||
tn_t ? (*tn_t)->name() : ""));
|
||||
else if (tp_t && tn_t)
|
||||
{
|
||||
m_tp = tp_t;
|
||||
m_tn = tn_t;
|
||||
m_tp = *tp_t;
|
||||
m_tn = *tn_t;
|
||||
f = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!f)
|
||||
throw nl_exception(MF_NO_POWER_TERMINALS_ON_DEVICE_2(name, anetlist.setup().de_alias(inout_proxied->device().name())));
|
||||
throw nl_exception(MF_NO_POWER_TERMINALS_ON_DEVICE_2(name(), state().setup().de_alias(inout_proxied->device().name())));
|
||||
|
||||
log().verbose("D/A Proxy: Found power terminals on device {1}", inout_proxied->device().name());
|
||||
}
|
||||
@ -74,14 +73,14 @@ namespace netlist::devices {
|
||||
// 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(device_param_t data,
|
||||
const logic_input_t *in_proxied)
|
||||
: nld_base_proxy(anetlist, name, in_proxied)
|
||||
: nld_base_proxy(data, in_proxied)
|
||||
{
|
||||
}
|
||||
|
||||
nld_a_to_d_proxy::nld_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name, const logic_input_t *in_proxied)
|
||||
: nld_base_a_to_d_proxy(anetlist, name, in_proxied)
|
||||
nld_a_to_d_proxy::nld_a_to_d_proxy(device_param_t data, const logic_input_t *in_proxied)
|
||||
: nld_base_a_to_d_proxy(data, in_proxied)
|
||||
, m_Q(*this, "Q")
|
||||
, m_I(*this, "I", nl_delegate(&nld_a_to_d_proxy::input, this))
|
||||
{
|
||||
@ -107,14 +106,14 @@ namespace netlist::devices {
|
||||
// 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(device_param_t data,
|
||||
const logic_output_t *out_proxied)
|
||||
: nld_base_proxy(anetlist, name, out_proxied)
|
||||
: nld_base_proxy(data, out_proxied)
|
||||
{
|
||||
}
|
||||
|
||||
nld_d_to_a_proxy::nld_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name, const logic_output_t *out_proxied)
|
||||
: nld_base_d_to_a_proxy(anetlist, name, out_proxied)
|
||||
nld_d_to_a_proxy::nld_d_to_a_proxy(device_param_t data, const logic_output_t *out_proxied)
|
||||
: nld_base_d_to_a_proxy(data, out_proxied)
|
||||
, m_I(*this, "I", nl_delegate(&nld_d_to_a_proxy :: input, this))
|
||||
, m_RP(*this, "RP")
|
||||
, m_RN(*this, "RN")
|
||||
@ -122,10 +121,10 @@ namespace netlist::devices {
|
||||
{
|
||||
register_sub_alias("Q", "RN.1");
|
||||
|
||||
connect(m_RN.N(), *m_tn);
|
||||
connect(m_RP.P(), *m_tp);
|
||||
connect(m_RN().N(), *m_tn);
|
||||
connect(m_RP().P(), *m_tp);
|
||||
|
||||
connect(m_RN.P(), m_RP.N());
|
||||
connect(m_RN().P(), m_RP().N());
|
||||
}
|
||||
|
||||
|
||||
@ -133,11 +132,11 @@ namespace netlist::devices {
|
||||
{
|
||||
//m_Q.initial(0.0);
|
||||
m_last_state = terminal_t::OUT_TRISTATE();
|
||||
m_RN.reset();
|
||||
m_RP.reset();
|
||||
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||
m_RN().reset();
|
||||
m_RP().reset();
|
||||
m_RN().set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||
logic_family()->low_offset_V(), nlconst::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
m_RP().set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
}
|
||||
@ -148,29 +147,29 @@ namespace netlist::devices {
|
||||
if (state != m_last_state)
|
||||
{
|
||||
// RN, RP are connected ...
|
||||
m_RN.change_state([this, &state]()
|
||||
m_RN().change_state([this, &state]()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||
m_RN().set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||
logic_family()->low_offset_V(), nlconst::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
m_RP().set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
break;
|
||||
case 1:
|
||||
m_RN.set_G_V_I(G_OFF,
|
||||
m_RN().set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
m_RP.set_G_V_I(plib::reciprocal(logic_family()->R_high()),
|
||||
m_RP().set_G_V_I(plib::reciprocal(logic_family()->R_high()),
|
||||
logic_family()->high_offset_V(), nlconst::zero());
|
||||
break;
|
||||
case terminal_t::OUT_TRISTATE():
|
||||
m_RN.set_G_V_I(G_OFF,
|
||||
m_RN().set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
m_RP().set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
break;
|
||||
|
@ -25,8 +25,7 @@ namespace netlist::devices {
|
||||
class nld_base_proxy : public device_t
|
||||
{
|
||||
public:
|
||||
nld_base_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_t *inout_proxied);
|
||||
nld_base_proxy(device_param_t data, const logic_t *inout_proxied);
|
||||
|
||||
// only used during setup
|
||||
virtual detail::core_terminal_t &proxy_term() noexcept = 0;
|
||||
@ -49,16 +48,14 @@ namespace netlist::devices {
|
||||
virtual logic_output_t &out() noexcept = 0;
|
||||
|
||||
protected:
|
||||
nld_base_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_input_t *in_proxied);
|
||||
nld_base_a_to_d_proxy(device_param_t data, const logic_input_t *in_proxied);
|
||||
|
||||
};
|
||||
|
||||
class nld_a_to_d_proxy : public nld_base_a_to_d_proxy
|
||||
{
|
||||
public:
|
||||
nld_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_input_t *in_proxied);
|
||||
nld_a_to_d_proxy(device_param_t data, const logic_input_t *in_proxied);
|
||||
|
||||
logic_output_t &out() noexcept override { return m_Q; }
|
||||
|
||||
@ -87,22 +84,20 @@ namespace netlist::devices {
|
||||
virtual logic_input_t &in() noexcept = 0;
|
||||
|
||||
protected:
|
||||
nld_base_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_output_t *out_proxied);
|
||||
nld_base_d_to_a_proxy(device_param_t data, const logic_output_t *out_proxied);
|
||||
|
||||
};
|
||||
|
||||
class nld_d_to_a_proxy : public nld_base_d_to_a_proxy
|
||||
{
|
||||
public:
|
||||
nld_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name,
|
||||
const logic_output_t *out_proxied);
|
||||
nld_d_to_a_proxy(device_param_t data, const logic_output_t *out_proxied);
|
||||
|
||||
logic_input_t &in() noexcept override { return m_I; }
|
||||
|
||||
detail::core_terminal_t &proxy_term() noexcept override
|
||||
{
|
||||
return m_RN.setup_P();
|
||||
return m_RN().setup_P();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -115,8 +110,8 @@ namespace netlist::devices {
|
||||
static constexpr const nl_fptype G_OFF = nlconst::cgmin();
|
||||
|
||||
logic_input_t m_I;
|
||||
analog::NETLIB_NAME(two_terminal) m_RP;
|
||||
analog::NETLIB_NAME(two_terminal) m_RN;
|
||||
NETLIB_SUB_NS(analog, two_terminal) m_RP;
|
||||
NETLIB_SUB_NS(analog, two_terminal) m_RN;
|
||||
state_var<netlist_sig_t> m_last_state;
|
||||
};
|
||||
|
||||
|
@ -84,7 +84,7 @@ namespace netlist::devices {
|
||||
for (std::uint64_t i=0; i < m_N(); i++)
|
||||
{
|
||||
pstring input_name = plib::pfmt("A{1}")(i);
|
||||
m_I.push_back(owner.template make_pool_object<analog_input_t>(*this, input_name, NETLIB_DELEGATE(fb)));
|
||||
m_I.push_back(state().make_pool_object<analog_input_t>(*this, input_name, NETLIB_DELEGATE(fb)));
|
||||
inputs.push_back(input_name);
|
||||
m_vals.push_back(nlconst::zero());
|
||||
}
|
||||
@ -303,7 +303,7 @@ namespace netlist::devices {
|
||||
for (uint64_t i=0; i < m_N(); i++)
|
||||
{
|
||||
pstring input_name = plib::pfmt("A{1}")(i);
|
||||
m_I.push_back(owner.template make_pool_object<analog_input_t>(*this, input_name, NETLIB_DELEGATE(inputs)));
|
||||
m_I.push_back(state().make_pool_object<analog_input_t>(*this, input_name, NETLIB_DELEGATE(inputs)));
|
||||
inputs.push_back(input_name);
|
||||
m_values.push_back(nlconst::zero());
|
||||
}
|
||||
@ -364,15 +364,15 @@ namespace netlist::devices {
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_last_state = 0;
|
||||
m_R.set_R(m_ROFF());
|
||||
m_R().set_R(m_ROFF());
|
||||
}
|
||||
|
||||
//NETLIB_UPDATE_PARAMI();
|
||||
|
||||
//FIXME: used by 74123
|
||||
|
||||
const terminal_t &P() const noexcept { return m_R.P(); }
|
||||
const terminal_t &N() const noexcept { return m_R.N(); }
|
||||
const terminal_t &P() const noexcept { return m_R().P(); }
|
||||
const terminal_t &N() const noexcept { return m_R().N(); }
|
||||
const logic_input_t &I() const noexcept { return m_I; }
|
||||
|
||||
param_fp_t m_RON;
|
||||
@ -387,14 +387,14 @@ namespace netlist::devices {
|
||||
m_last_state = state;
|
||||
const nl_fptype R = (state != 0) ? m_RON() : m_ROFF();
|
||||
|
||||
m_R.change_state([this, &R]()
|
||||
m_R().change_state([this, &R]()
|
||||
{
|
||||
m_R.set_R(R);
|
||||
m_R().set_R(R);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
analog::NETLIB_SUB(R_base) m_R;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R;
|
||||
logic_input_t m_I;
|
||||
|
||||
state_var<netlist_sig_t> m_last_state;
|
||||
@ -424,8 +424,8 @@ namespace netlist::devices {
|
||||
private:
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_R1.set_G(m_GOFF());
|
||||
m_R2.set_G(m_GON());
|
||||
m_R1().set_G(m_GOFF());
|
||||
m_R2().set_G(m_GON());
|
||||
}
|
||||
|
||||
//NETLIB_UPDATE_PARAMI();
|
||||
@ -437,29 +437,29 @@ namespace netlist::devices {
|
||||
//printf("Here %d\n", state);
|
||||
const nl_fptype G1 = (state != 0) ? m_GON() : m_GOFF();
|
||||
const nl_fptype G2 = (state != 0) ? m_GOFF() : m_GON();
|
||||
if (m_R1.solver() == m_R2.solver())
|
||||
if (m_R1().solver() == m_R2().solver())
|
||||
{
|
||||
m_R1.change_state([this, &G1, &G2]()
|
||||
m_R1().change_state([this, &G1, &G2]()
|
||||
{
|
||||
m_R1.set_G(G1);
|
||||
m_R2.set_G(G2);
|
||||
m_R1().set_G(G1);
|
||||
m_R2().set_G(G2);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_R1.change_state([this, &G1]()
|
||||
m_R1().change_state([this, &G1]()
|
||||
{
|
||||
m_R1.set_G(G1);
|
||||
m_R1().set_G(G1);
|
||||
});
|
||||
m_R2.change_state([this, &G2]()
|
||||
m_R2().change_state([this, &G2]()
|
||||
{
|
||||
m_R2.set_G(G2);
|
||||
m_R2().set_G(G2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
analog::NETLIB_SUB(R_base) m_R1;
|
||||
analog::NETLIB_SUB(R_base) m_R2;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R1;
|
||||
NETLIB_SUB_NS(analog, R_base) m_R2;
|
||||
logic_input_t m_I;
|
||||
param_fp_t m_GON;
|
||||
param_fp_t m_GOFF;
|
||||
@ -570,18 +570,18 @@ namespace netlist::devices {
|
||||
NETLIB_HANDLERI(input)
|
||||
{
|
||||
nl_fptype val = m_dis()(m_mt());
|
||||
m_T.change_state([this, val]()
|
||||
m_T().change_state([this, val]()
|
||||
{
|
||||
m_T.set_G_V_I(plib::reciprocal(m_RI()), val, nlconst::zero());
|
||||
m_T().set_G_V_I(plib::reciprocal(m_RI()), val, nlconst::zero());
|
||||
});
|
||||
}
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_T.set_G_V_I(plib::reciprocal(m_RI()), nlconst::zero(), nlconst::zero());
|
||||
m_T().set_G_V_I(plib::reciprocal(m_RI()), nlconst::zero(), nlconst::zero());
|
||||
}
|
||||
|
||||
analog::NETLIB_SUB(two_terminal) m_T;
|
||||
NETLIB_SUB_NS(analog, two_terminal) m_T;
|
||||
logic_input_t m_I;
|
||||
param_fp_t m_RI;
|
||||
param_fp_t m_sigma;
|
||||
|
@ -36,11 +36,9 @@ namespace netlist::devices {
|
||||
std::array<netlist_time, 16> m_timing_nt;
|
||||
};
|
||||
|
||||
template <class C>
|
||||
nld_truth_table_t(C &owner, const pstring &name,
|
||||
const pstring &model,
|
||||
nld_truth_table_t(device_param_t data, const pstring &model,
|
||||
truth_table_t &ttp, const std::vector<pstring> &desc)
|
||||
: device_t(owner, name, model)
|
||||
: device_t(data, model)
|
||||
#if NL_USE_TT_ALTERNATIVE
|
||||
, m_state(*this, "m_state", 0)
|
||||
#endif
|
||||
@ -272,8 +270,8 @@ namespace netlist::devices {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static constexpr const pbitset all_bits() noexcept { return pbitset(~static_cast<T>(0)); }
|
||||
static constexpr const pbitset no_bits() noexcept{ return pbitset(static_cast<T>(0)); }
|
||||
static constexpr pbitset all_bits() noexcept { return pbitset(~static_cast<T>(0)); }
|
||||
static constexpr pbitset no_bits() noexcept{ return pbitset(static_cast<T>(0)); }
|
||||
private:
|
||||
T m_bs;
|
||||
};
|
||||
@ -414,7 +412,7 @@ namespace netlist::devices {
|
||||
// Connect output "Q" to input "_Q" if this exists
|
||||
// This enables timed state without having explicit state ....
|
||||
pstring tmp = "_" + outputs[i];
|
||||
const std::size_t idx = plib::container::indexof(inout, tmp);
|
||||
const std::size_t idx = plib::container::index_of(inout, tmp);
|
||||
if (idx != plib::container::npos)
|
||||
connect(m_Q[i], m_I[idx]);
|
||||
}
|
||||
@ -426,10 +424,10 @@ namespace netlist::devices {
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<unsigned m_NI, unsigned m_NO>
|
||||
class netlist_factory_truth_table_t : public factory::truth_table_base_element_t
|
||||
class factory_truth_table_t : public factory::truth_table_base_element_t
|
||||
{
|
||||
public:
|
||||
netlist_factory_truth_table_t(const pstring &name,
|
||||
factory_truth_table_t(const pstring &name,
|
||||
factory::properties &&props)
|
||||
: truth_table_base_element_t(name, std::move(props))
|
||||
{ }
|
||||
@ -448,7 +446,7 @@ namespace netlist::devices {
|
||||
desc_s.parse(m_desc);
|
||||
}
|
||||
|
||||
return plib::make_unique<tt_type>(pool, anetlist, name, m_family_name, *m_table, m_desc);
|
||||
return plib::make_unique<tt_type>(pool, device_data_t{anetlist, name}, m_family_name, *m_table, m_desc);
|
||||
}
|
||||
private:
|
||||
device_arena::unique_ptr<typename nld_truth_table_t<m_NI, m_NO>::truth_table_t> m_table;
|
||||
@ -667,7 +665,7 @@ namespace netlist::factory {
|
||||
}
|
||||
|
||||
#define ENTRYY(n, m, s) case (n * 100 + m): \
|
||||
{ using dev_type = devices::netlist_factory_truth_table_t<n, m>; \
|
||||
{ using dev_type = devices::factory_truth_table_t<n, m>; \
|
||||
auto cs=s; \
|
||||
ret = plib::make_unique<dev_type, host_arena>(desc.name, std::move(cs)); } \
|
||||
break
|
||||
|
@ -21,6 +21,7 @@
|
||||
//- +---+---++---+
|
||||
//-
|
||||
static NETLIST_START(TTL_7400_DIP)
|
||||
{
|
||||
TTL_7400_NAND(A)
|
||||
TTL_7400_NAND(B)
|
||||
TTL_7400_NAND(C)
|
||||
@ -39,6 +40,7 @@ static NETLIST_START(TTL_7400_DIP)
|
||||
A.GND, /* GND |7 8| Y3 */ C.Q
|
||||
/* +--------------+ */
|
||||
)
|
||||
}
|
||||
NETLIST_END()
|
||||
|
||||
//- Identifier: TTL_7402_DIP
|
||||
@ -2091,20 +2093,15 @@ NETLIST_END()
|
||||
//-
|
||||
static NETLIST_START(TTL_74174_DIP)
|
||||
TTL_74174(A)
|
||||
TTL_74174(B)
|
||||
TTL_74174(C)
|
||||
TTL_74174(D)
|
||||
TTL_74174(E)
|
||||
TTL_74174(F)
|
||||
|
||||
DIPPINS( /* +--------------+ */
|
||||
A.CLRQ, /* CLRQ |1 ++ 16| VCC */ A.VCC,
|
||||
A.Q, /* Q1 |2 15| Q6 */ F.Q,
|
||||
A.D, /* D1 |3 14| D6 */ F.D,
|
||||
B.D, /* D2 |4 74174 13| D5 */ E.D,
|
||||
B.Q, /* Q2 |5 12| Q5 */ E.Q,
|
||||
C.D, /* D3 |6 11| D4 */ D.D,
|
||||
C.Q, /* Q3 |7 10| Q4 */ D.Q,
|
||||
A.CLRQ, /* CLRQ |1 ++ 16| VCC */ A.VCC
|
||||
A.Q1, /* Q1 |2 15| Q6 */ A.Q6,
|
||||
A.D1, /* D1 |3 14| D6 */ A.D6,
|
||||
A.D2, /* D2 |4 74174 13| D5 */ A.D5,
|
||||
A.Q2, /* Q2 |5 12| Q5 */ A.Q5,
|
||||
A.D3, /* D3 |6 11| D4 */ A.D4,
|
||||
A.Q3, /* Q3 |7 10| Q4 */ A.Q4,
|
||||
A.GND, /* GND |8 9| CLK */ A.CLK
|
||||
/* +--------------+ */
|
||||
)
|
||||
@ -3147,6 +3144,7 @@ static TRUTHTABLE_START(TTL_74279B, 4, 1, "")
|
||||
TRUTHTABLE_END()
|
||||
|
||||
static TRUTHTABLE_START(TTL_9312, 12, 2, "+A,+B,+C,+G,+D0,+D1,+D2,+D3,+D4,+D5,+D6,+D7,@VCC,@GND")
|
||||
{
|
||||
TT_HEAD(" C, B, A, G,D0,D1,D2,D3,D4,D5,D6,D7| Y,YQ")
|
||||
TT_LINE(" X, X, X, 1, X, X, X, X, X, X, X, X| 0, 1|33,19")
|
||||
TT_LINE(" 0, 0, 0, 0, 0, X, X, X, X, X, X, X| 0, 1|33,28")
|
||||
@ -3166,6 +3164,7 @@ static TRUTHTABLE_START(TTL_9312, 12, 2, "+A,+B,+C,+G,+D0,+D1,+D2,+D3,+D4,+D5,+D
|
||||
TT_LINE(" 1, 1, 1, 0, X, X, X, X, X, X, X, 0| 0, 1|33,28")
|
||||
TT_LINE(" 1, 1, 1, 0, X, X, X, X, X, X, X, 1| 1, 0|33,28")
|
||||
TT_FAMILY("74XX")
|
||||
}
|
||||
TRUTHTABLE_END()
|
||||
|
||||
NETLIST_START(ttl74xx_lib)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,22 +18,22 @@
|
||||
///
|
||||
/// \brief Version - Major.
|
||||
///
|
||||
#define NL_VERSION_MAJOR 0
|
||||
#define NL_VERSION_MAJOR 0
|
||||
///
|
||||
/// \brief Version - Minor.
|
||||
///
|
||||
#define NL_VERSION_MINOR 14
|
||||
#define NL_VERSION_MINOR 14
|
||||
/// \brief Version - Patch level.
|
||||
///
|
||||
#define NL_VERSION_PATCHLEVEL 0
|
||||
#define NL_VERSION_PATCHLEVEL 0
|
||||
|
||||
///
|
||||
/// \addtogroup compiledefine
|
||||
/// \{
|
||||
|
||||
//============================================================
|
||||
// GENERAL
|
||||
//============================================================
|
||||
// -----------------------------------------------------------------------------
|
||||
// General
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// \brief Compile in academic solvers
|
||||
///
|
||||
@ -48,20 +48,19 @@
|
||||
/// time significantly.
|
||||
///
|
||||
#ifndef NL_USE_ACADEMIC_SOLVERS
|
||||
#define NL_USE_ACADEMIC_SOLVERS (1)
|
||||
#define NL_USE_ACADEMIC_SOLVERS (1)
|
||||
#endif
|
||||
|
||||
/// \brief Use backward Euler integration
|
||||
///
|
||||
/// This will use backward Euler instead of trapezoidal integration.
|
||||
///
|
||||
/// FIXME: Long term this will become a runtime setting. Only the capacitor model
|
||||
/// currently has a trapezoidal version and there is no support currently for
|
||||
/// variable capacitors.
|
||||
/// The change will have impact on timings since trapezoidal improves timing
|
||||
/// accuracy.
|
||||
/// FIXME: Long term this will become a runtime setting. Only the capacitor
|
||||
/// model currently has a trapezoidal version and there is no support currently
|
||||
/// for variable capacitors. The change will have impact on timings since
|
||||
/// trapezoidal improves timing accuracy.
|
||||
#ifndef NL_USE_BACKWARD_EULER
|
||||
#define NL_USE_BACKWARD_EULER (1) // FIXME: Move to config struct later
|
||||
#define NL_USE_BACKWARD_EULER (1) // FIXME: Move to config struct later
|
||||
#endif
|
||||
|
||||
/// \brief Compile with core terminals owned by net_t
|
||||
@ -78,7 +77,7 @@
|
||||
/// By default the setting is currently disabled.
|
||||
///
|
||||
#ifndef NL_USE_INPLACE_CORE_TERMS
|
||||
#define NL_USE_INPLACE_CORE_TERMS (0)
|
||||
#define NL_USE_INPLACE_CORE_TERMS (0)
|
||||
#endif
|
||||
|
||||
/// \brief Use alternative truth table execution approach
|
||||
@ -90,26 +89,25 @@
|
||||
/// Unfortunately this has to be macro since it needs another member variable.
|
||||
///
|
||||
#ifndef NL_USE_TT_ALTERNATIVE
|
||||
#define NL_USE_TT_ALTERNATIVE (0)
|
||||
#define NL_USE_TT_ALTERNATIVE (0)
|
||||
#endif
|
||||
|
||||
/// \brief Compile matrix solvers using the __float128 type.
|
||||
///
|
||||
/// Defaults to \ref PUSE_FLOAT128
|
||||
#ifndef NL_USE_FLOAT128
|
||||
#define NL_USE_FLOAT128 PUSE_FLOAT128
|
||||
#define NL_USE_FLOAT128 PUSE_FLOAT128
|
||||
#endif
|
||||
|
||||
|
||||
//============================================================
|
||||
// -----------------------------------------------------------------------------
|
||||
// DEBUGGING
|
||||
//============================================================
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// \brief Enable compile time debugging code
|
||||
///
|
||||
|
||||
#ifndef NL_DEBUG
|
||||
#define NL_DEBUG (false)
|
||||
#define NL_DEBUG (false)
|
||||
#endif
|
||||
|
||||
///
|
||||
@ -118,9 +116,9 @@
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
//============================================================
|
||||
// GENERAL
|
||||
//============================================================
|
||||
// -------------------------------------------------------------------------
|
||||
// GENERAL
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
struct config_default
|
||||
{
|
||||
@ -136,10 +134,11 @@ namespace netlist
|
||||
/// brief default minimum alignment of mempool_arena
|
||||
///
|
||||
/// 256 is the best compromise between logic applications like MAME
|
||||
/// TTL games (e.g. pong) and analog applications like e.g. kidnikik sound.
|
||||
/// TTL games (e.g. pong) and analog applications like e.g. kidnikik
|
||||
/// sound.
|
||||
///
|
||||
/// Best performance for pong is achieved with a value of 16, but this degrades
|
||||
/// kidniki performance by ~10%.
|
||||
/// Best performance for pong is achieved with a value of 16, but this
|
||||
/// degrades kidniki performance by ~10%.
|
||||
///
|
||||
/// More work is needed here.
|
||||
using mempool_align = std::integral_constant<std::size_t, 16>;
|
||||
@ -159,9 +158,9 @@ namespace netlist
|
||||
///
|
||||
using use_queue_stats = std::integral_constant<bool, false>;
|
||||
|
||||
//============================================================
|
||||
// ---------------------------------------------------------------------
|
||||
// Time resolution
|
||||
//============================================================
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// \brief Resolution as clocks per second for timing
|
||||
///
|
||||
@ -178,15 +177,17 @@ namespace netlist
|
||||
/// | 63 | 100,000,000,000 | 92,233,720 | 1,068| 2.9 |
|
||||
/// | 63 | 1,000,000,000,000 | 9,223,372 | 107| 0.3 |
|
||||
///
|
||||
using INTERNAL_RES = std::integral_constant<long long int, 10'000'000'000LL>; // NOLINT
|
||||
using INTERNAL_RES = std::integral_constant<long long int,
|
||||
10'000'000'000LL>; // NOLINT
|
||||
|
||||
/// \brief Recommended clock to be used
|
||||
///
|
||||
/// This is the recommended clock to be used in fixed clock applications limited
|
||||
/// to 32 bit clock resolution. The MAME code (netlist.cpp) contains code
|
||||
/// illustrating how to deal with remainders if \ref INTERNAL_RES is bigger than
|
||||
/// NETLIST_CLOCK.
|
||||
using DEFAULT_CLOCK = std::integral_constant<int, 1'000'000'000>; // NOLINT
|
||||
/// This is the recommended clock to be used in fixed clock applications
|
||||
/// limited to 32 bit clock resolution. The MAME code (netlist.cpp)
|
||||
/// contains code illustrating how to deal with remainders if \ref
|
||||
/// INTERNAL_RES is bigger than NETLIST_CLOCK.
|
||||
using DEFAULT_CLOCK = std::integral_constant<int,
|
||||
1'000'000'000>; // NOLINT
|
||||
|
||||
/// \brief Default logic family
|
||||
///
|
||||
@ -194,23 +195,28 @@ namespace netlist
|
||||
|
||||
/// \brief Maximum queue size
|
||||
///
|
||||
using max_queue_size = std::integral_constant<std::size_t, 1024>; // NOLINT
|
||||
using max_queue_size = std::integral_constant<std::size_t,
|
||||
1024>; // NOLINT
|
||||
|
||||
/// \brief Maximum queue size for solvers
|
||||
///
|
||||
using max_solver_queue_size = std::integral_constant<std::size_t, 512>; // NOLINT
|
||||
using max_solver_queue_size = std::integral_constant<std::size_t,
|
||||
512>; // NOLINT
|
||||
|
||||
/// \brief Support float type for matrix calculations.
|
||||
///
|
||||
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
||||
using use_float_matrix = std::integral_constant<bool, NL_USE_ACADEMIC_SOLVERS>;
|
||||
using use_float_matrix = std::integral_constant<bool,
|
||||
NL_USE_ACADEMIC_SOLVERS>;
|
||||
|
||||
/// \brief Support long double type for matrix calculations.
|
||||
///
|
||||
/// Defaults to NL_USE_ACADEMIC_SOLVERS to provide faster build times
|
||||
using use_long_double_matrix = std::integral_constant<bool, NL_USE_ACADEMIC_SOLVERS>;
|
||||
using use_long_double_matrix = std::integral_constant<bool,
|
||||
NL_USE_ACADEMIC_SOLVERS>;
|
||||
|
||||
using use_float128_matrix = std::integral_constant<bool, NL_USE_FLOAT128>;
|
||||
using use_float128_matrix = std::integral_constant<bool,
|
||||
NL_USE_FLOAT128>;
|
||||
|
||||
/// \brief Floating point types used
|
||||
///
|
||||
@ -235,7 +241,8 @@ namespace netlist
|
||||
/// By default it is disabled since it is not as fast as
|
||||
/// the default approach. It is ~20% slower.
|
||||
///
|
||||
using use_copy_instead_of_reference = std::integral_constant<bool, false>;
|
||||
using use_copy_instead_of_reference = std::integral_constant<bool,
|
||||
false>;
|
||||
|
||||
/// \brief Avoid unnecessary queue pushes
|
||||
///
|
||||
@ -268,9 +275,10 @@ namespace netlist
|
||||
///
|
||||
struct config : public config_default
|
||||
{
|
||||
//using mempool_align = std::integral_constant<std::size_t, 32>;
|
||||
//using avoid_noop_queue_pushes = std::integral_constant<bool, true>;
|
||||
//using use_copy_instead_of_reference = std::integral_constant<bool, true>;
|
||||
// using mempool_align = std::integral_constant<std::size_t, 32>;
|
||||
// using avoid_noop_queue_pushes = std::integral_constant<bool, true>;
|
||||
// using use_copy_instead_of_reference = std::integral_constant<bool,
|
||||
// true>;
|
||||
};
|
||||
|
||||
using nl_fptype = config::fptype;
|
||||
@ -281,21 +289,34 @@ namespace netlist
|
||||
///
|
||||
template <typename FT>
|
||||
struct fp_constants
|
||||
{ };
|
||||
{
|
||||
};
|
||||
|
||||
/// \brief Specific constants for long double floating point type
|
||||
///
|
||||
template <>
|
||||
struct fp_constants<long double>
|
||||
{
|
||||
static constexpr long double DIODE_MAXDIFF() noexcept { return 1e100L; } // NOLINT
|
||||
static constexpr long double DIODE_MAXVOLT() noexcept { return 300.0L; } // NOLINT
|
||||
static constexpr long double DIODE_MAXDIFF() noexcept
|
||||
{
|
||||
return 1e100L;
|
||||
} // NOLINT
|
||||
static constexpr long double DIODE_MAXVOLT() noexcept
|
||||
{
|
||||
return 300.0L;
|
||||
} // NOLINT
|
||||
|
||||
static constexpr long double TIMESTEP_MAXDIFF() noexcept { return 1e100L; } // NOLINT
|
||||
static constexpr long double TIMESTEP_MINDIV() noexcept { return 1e-60L; } // NOLINT
|
||||
static constexpr long double TIMESTEP_MAXDIFF() noexcept
|
||||
{
|
||||
return 1e100L;
|
||||
} // NOLINT
|
||||
static constexpr long double TIMESTEP_MINDIV() noexcept
|
||||
{
|
||||
return 1e-60L;
|
||||
} // NOLINT
|
||||
|
||||
static constexpr const char * name() noexcept { return "long double"; }
|
||||
static constexpr const char * suffix() noexcept { return "L"; }
|
||||
static constexpr const char *name() noexcept { return "long double"; }
|
||||
static constexpr const char *suffix() noexcept { return "L"; }
|
||||
};
|
||||
|
||||
/// \brief Specific constants for double floating point type
|
||||
@ -303,14 +324,26 @@ namespace netlist
|
||||
template <>
|
||||
struct fp_constants<double>
|
||||
{
|
||||
static constexpr double DIODE_MAXDIFF() noexcept { return 1e100; } // NOLINT
|
||||
static constexpr double DIODE_MAXVOLT() noexcept { return 300.0; } // NOLINT
|
||||
static constexpr double DIODE_MAXDIFF() noexcept
|
||||
{
|
||||
return 1e100;
|
||||
} // NOLINT
|
||||
static constexpr double DIODE_MAXVOLT() noexcept
|
||||
{
|
||||
return 300.0;
|
||||
} // NOLINT
|
||||
|
||||
static constexpr double TIMESTEP_MAXDIFF() noexcept { return 1e100; } // NOLINT
|
||||
static constexpr double TIMESTEP_MINDIV() noexcept { return 1e-60; } // NOLINT
|
||||
static constexpr double TIMESTEP_MAXDIFF() noexcept
|
||||
{
|
||||
return 1e100;
|
||||
} // NOLINT
|
||||
static constexpr double TIMESTEP_MINDIV() noexcept
|
||||
{
|
||||
return 1e-60;
|
||||
} // NOLINT
|
||||
|
||||
static constexpr const char * name() noexcept { return "double"; }
|
||||
static constexpr const char * suffix() noexcept { return ""; }
|
||||
static constexpr const char *name() noexcept { return "double"; }
|
||||
static constexpr const char *suffix() noexcept { return ""; }
|
||||
};
|
||||
|
||||
/// \brief Specific constants for float floating point type
|
||||
@ -318,14 +351,26 @@ namespace netlist
|
||||
template <>
|
||||
struct fp_constants<float>
|
||||
{
|
||||
static constexpr float DIODE_MAXDIFF() noexcept { return 1e20F; } // NOLINT
|
||||
static constexpr float DIODE_MAXVOLT() noexcept { return 90.0F; } // NOLINT
|
||||
static constexpr float DIODE_MAXDIFF() noexcept
|
||||
{
|
||||
return 1e20F;
|
||||
} // NOLINT
|
||||
static constexpr float DIODE_MAXVOLT() noexcept
|
||||
{
|
||||
return 90.0F;
|
||||
} // NOLINT
|
||||
|
||||
static constexpr float TIMESTEP_MAXDIFF() noexcept { return 1e30F; } // NOLINT
|
||||
static constexpr float TIMESTEP_MINDIV() noexcept { return 1e-8F; } // NOLINT
|
||||
static constexpr float TIMESTEP_MAXDIFF() noexcept
|
||||
{
|
||||
return 1e30F;
|
||||
} // NOLINT
|
||||
static constexpr float TIMESTEP_MINDIV() noexcept
|
||||
{
|
||||
return 1e-8F;
|
||||
} // NOLINT
|
||||
|
||||
static constexpr const char * name() noexcept { return "float"; }
|
||||
static constexpr const char * suffix() noexcept { return "f"; }
|
||||
static constexpr const char *name() noexcept { return "float"; }
|
||||
static constexpr const char *suffix() noexcept { return "f"; }
|
||||
};
|
||||
|
||||
#if (NL_USE_FLOAT128)
|
||||
@ -334,7 +379,7 @@ namespace netlist
|
||||
template <>
|
||||
struct fp_constants<FLOAT128>
|
||||
{
|
||||
#if 0
|
||||
#if 0
|
||||
// MAME compile doesn't support Q
|
||||
static constexpr FLOAT128 DIODE_MAXDIFF() noexcept { return 1e100Q; }
|
||||
static constexpr FLOAT128 DIODE_MAXVOLT() noexcept { return 300.0Q; }
|
||||
@ -344,17 +389,29 @@ namespace netlist
|
||||
|
||||
static constexpr const char * name() noexcept { return "FLOAT128"; }
|
||||
static constexpr const char * suffix() noexcept { return "Q"; }
|
||||
#else
|
||||
static constexpr FLOAT128 DIODE_MAXDIFF() noexcept { return static_cast<FLOAT128>(1e100L); }
|
||||
static constexpr FLOAT128 DIODE_MAXVOLT() noexcept { return static_cast<FLOAT128>(300.0L); }
|
||||
#else
|
||||
static constexpr FLOAT128 DIODE_MAXDIFF() noexcept
|
||||
{
|
||||
return static_cast<FLOAT128>(1e100L);
|
||||
}
|
||||
static constexpr FLOAT128 DIODE_MAXVOLT() noexcept
|
||||
{
|
||||
return static_cast<FLOAT128>(300.0L);
|
||||
}
|
||||
|
||||
static constexpr FLOAT128 TIMESTEP_MAXDIFF() noexcept { return static_cast<FLOAT128>(1e100L); }
|
||||
static constexpr FLOAT128 TIMESTEP_MINDIV() noexcept { return static_cast<FLOAT128>(1e-60L); }
|
||||
static constexpr FLOAT128 TIMESTEP_MAXDIFF() noexcept
|
||||
{
|
||||
return static_cast<FLOAT128>(1e100L);
|
||||
}
|
||||
static constexpr FLOAT128 TIMESTEP_MINDIV() noexcept
|
||||
{
|
||||
return static_cast<FLOAT128>(1e-60L);
|
||||
}
|
||||
|
||||
static constexpr const char * name() noexcept { return "__float128"; }
|
||||
static constexpr const char * suffix() noexcept { return "Q"; }
|
||||
static constexpr const char *name() noexcept { return "__float128"; }
|
||||
static constexpr const char *suffix() noexcept { return "Q"; }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
} // namespace netlist
|
||||
@ -363,7 +420,12 @@ namespace netlist
|
||||
// Asserts
|
||||
//============================================================
|
||||
|
||||
#define nl_assert(x) do { if (NL_DEBUG) passert_always(x); } while (0)
|
||||
#define nl_assert(x) \
|
||||
do \
|
||||
{ \
|
||||
if (NL_DEBUG) \
|
||||
passert_always(x); \
|
||||
} while (0)
|
||||
#define nl_assert_always(x, msg) passert_always_msg(x, msg)
|
||||
|
||||
#endif // NLCONFIG_H_
|
||||
|
@ -108,6 +108,7 @@ namespace netlist
|
||||
PERRMSGV(MW_TERMINAL_1_WITHOUT_CONNECTIONS, 1, "Found terminal {1} without connections")
|
||||
|
||||
PERRMSGV(ME_TERMINAL_1_WITHOUT_NET, 1, "Found terminal {1} without a net")
|
||||
PERRMSGV(ME_TERMINALS_1_2_WITHOUT_NET, 2, "Found terminals {1} and {2} without a net")
|
||||
PERRMSGV(MF_TERMINALS_WITHOUT_NET, 0, "Found terminals without a net")
|
||||
PERRMSGV(ME_TRISTATE_NO_PROXY_FOUND_2, 2,
|
||||
"Tristate output {1} on device {2} is not connected to a proxy. You "
|
||||
|
@ -5,26 +5,30 @@
|
||||
/// \file nl_factory.cpp
|
||||
///
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nl_factory.h"
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nl_setup.h"
|
||||
|
||||
#include "core/core_device.h"
|
||||
|
||||
#include "plib/putil.h"
|
||||
|
||||
namespace netlist::factory {
|
||||
namespace netlist::factory
|
||||
{
|
||||
|
||||
// FIXME: this doesn't do anything, check how to remove
|
||||
class NETLIB_NAME(wrapper) : public base_device_t
|
||||
class NETLIB_NAME(wrapper)
|
||||
: public base_device_t
|
||||
{
|
||||
public:
|
||||
NETLIB_NAME(wrapper)(netlist_state_t &anetlist, const pstring &name)
|
||||
: base_device_t(anetlist, name)
|
||||
NETLIB_NAME(wrapper)(base_device_param_t data)
|
||||
: base_device_t(data)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
//NETLIB_RESETI() {}
|
||||
// NETLIB_RESETI() {}
|
||||
};
|
||||
|
||||
element_t::element_t(const pstring &name, properties &&props)
|
||||
@ -33,9 +37,9 @@ namespace netlist::factory {
|
||||
{
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// net_device_t_base_factory
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
list_t::list_t(log_type &alog)
|
||||
: m_log(alog)
|
||||
@ -46,7 +50,7 @@ namespace netlist::factory {
|
||||
|
||||
bool list_t::exists(const pstring &name) const noexcept
|
||||
{
|
||||
for (const auto & e : *this)
|
||||
for (const auto &e : *this)
|
||||
if (e->name() == name)
|
||||
return true;
|
||||
return false;
|
||||
@ -62,9 +66,9 @@ namespace netlist::factory {
|
||||
push_back(std::move(factory));
|
||||
}
|
||||
|
||||
factory::element_t * list_t::factory_by_name(const pstring &devname)
|
||||
factory::element_t *list_t::factory_by_name(const pstring &devname)
|
||||
{
|
||||
for (auto & e : *this)
|
||||
for (auto &e : *this)
|
||||
{
|
||||
if (e->name() == devname)
|
||||
return e.get();
|
||||
@ -74,19 +78,22 @@ namespace netlist::factory {
|
||||
throw nl_exception(MF_CLASS_1_NOT_FOUND(devname));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// library_element_t: factory class to wrap macro based chips/elements
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
library_element_t::library_element_t(const pstring &name, properties &&props)
|
||||
: element_t(name, std::move(properties(props).set_type(element_type::MACRO)))
|
||||
library_element_t::library_element_t(const pstring &name,
|
||||
properties && props)
|
||||
: element_t(name,
|
||||
std::move(properties(props).set_type(element_type::MACRO)))
|
||||
{
|
||||
}
|
||||
|
||||
device_arena::unique_ptr<core_device_t> library_element_t::make_device(device_arena &pool, netlist_state_t &anetlist, const pstring &name)
|
||||
device_arena::unique_ptr<core_device_t> library_element_t::make_device(
|
||||
device_arena &pool, netlist_state_t &anetlist, const pstring &name)
|
||||
{
|
||||
return plib::make_unique<NETLIB_NAME(wrapper)>(pool, anetlist, name);
|
||||
return plib::make_unique<NETLIB_NAME(wrapper)>(pool,
|
||||
base_device_data_t{anetlist, name});
|
||||
}
|
||||
|
||||
|
||||
} // namespace netlist::factory
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define NLFACTORY_H_
|
||||
|
||||
#include "nltypes.h"
|
||||
|
||||
#include "plib/palloc.h"
|
||||
#include "plib/pmempool.h"
|
||||
#include "plib/psource.h"
|
||||
@ -18,30 +19,28 @@
|
||||
#include <utility>
|
||||
#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_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) \
|
||||
#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_NS(ns, chip, p_name, p_def_param) \
|
||||
NETLIB_DEVICE_IMPL_BASE(ns, chip, chip, p_name, p_def_param)
|
||||
|
||||
#define NETLIB_DEVICE_IMPL_BASE(ns, p_alias, chip, p_name, p_def_param) \
|
||||
static factory::element_t::uptr NETLIB_NAME(p_alias ## _c) () \
|
||||
{ \
|
||||
using devtype = factory::device_element_t<ns :: NETLIB_NAME(chip)>; \
|
||||
factory::properties sl(p_def_param, PSOURCELOC()); \
|
||||
return devtype::create(p_name, std::move(sl)); \
|
||||
} \
|
||||
\
|
||||
extern factory::constructor_ptr_t decl_ ## p_alias; \
|
||||
factory::constructor_ptr_t decl_ ## p_alias = NETLIB_NAME(p_alias ## _c);
|
||||
|
||||
namespace netlist {
|
||||
|
||||
namespace factory {
|
||||
#define NETLIB_DEVICE_IMPL_BASE(ns, p_alias, chip, p_name, p_def_param) \
|
||||
static factory::element_t::uptr NETLIB_NAME(p_alias##_c)() \
|
||||
{ \
|
||||
using devtype = factory::device_element_t<ns ::NETLIB_NAME(chip)>; \
|
||||
factory::properties sl(p_def_param, PSOURCELOC()); \
|
||||
return devtype::create(p_name, std::move(sl)); \
|
||||
} \
|
||||
\
|
||||
extern factory::constructor_ptr_t decl_##p_alias; \
|
||||
factory::constructor_ptr_t decl_##p_alias = NETLIB_NAME(p_alias##_c);
|
||||
|
||||
namespace netlist::factory
|
||||
{
|
||||
enum class element_type
|
||||
{
|
||||
BUILTIN,
|
||||
@ -50,11 +49,13 @@ namespace factory {
|
||||
|
||||
struct properties
|
||||
{
|
||||
properties(const pstring &default_parameter, plib::source_location &&location)
|
||||
properties(const pstring & default_parameter,
|
||||
plib::source_location &&location)
|
||||
: m_default_parameter(default_parameter)
|
||||
, m_location(std::move(location))
|
||||
, m_type(element_type::BUILTIN)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
~properties() = default;
|
||||
PCOPYASSIGNMOVE(properties, default)
|
||||
@ -64,10 +65,7 @@ namespace factory {
|
||||
return m_default_parameter;
|
||||
}
|
||||
|
||||
plib::source_location source() const noexcept
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
plib::source_location source() const noexcept { return m_location; }
|
||||
|
||||
element_type type() const noexcept { return m_type; }
|
||||
|
||||
@ -76,20 +74,20 @@ namespace factory {
|
||||
m_type = t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
pstring m_default_parameter;
|
||||
pstring m_default_parameter;
|
||||
plib::source_location m_location;
|
||||
element_type m_type;
|
||||
element_type m_type;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// net_dev class factory
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class element_t
|
||||
{
|
||||
public:
|
||||
|
||||
using dev_uptr = device_arena::unique_ptr<core_device_t>;
|
||||
using uptr = host_arena::unique_ptr<element_t>;
|
||||
using pointer = element_t *;
|
||||
@ -99,57 +97,71 @@ namespace factory {
|
||||
|
||||
PCOPYASSIGNMOVE(element_t, default)
|
||||
|
||||
virtual dev_uptr make_device(device_arena &pool,
|
||||
netlist_state_t &anetlist,
|
||||
const pstring &name) = 0;
|
||||
virtual dev_uptr
|
||||
make_device(device_arena &pool, netlist_state_t &anetlist,
|
||||
const pstring &name)
|
||||
= 0;
|
||||
|
||||
pstring name() const noexcept { return m_name; }
|
||||
pstring param_desc() const noexcept { return m_properties.default_parameter(); }
|
||||
plib::source_location source() const noexcept { return m_properties.source(); }
|
||||
pstring param_desc() const noexcept
|
||||
{
|
||||
return m_properties.default_parameter();
|
||||
}
|
||||
plib::source_location source() const noexcept
|
||||
{
|
||||
return m_properties.source();
|
||||
}
|
||||
element_type type() const noexcept { return m_properties.type(); }
|
||||
|
||||
private:
|
||||
pstring m_name; ///< device name
|
||||
properties m_properties; ///< source file and other information and settings
|
||||
pstring m_name; ///< device name
|
||||
properties m_properties; ///< source file and other information and
|
||||
///< settings
|
||||
};
|
||||
|
||||
template <class C, typename... Args>
|
||||
class device_element_t : public element_t
|
||||
{
|
||||
public:
|
||||
using constructor_data_t = typename C::constructor_data_t;
|
||||
|
||||
device_element_t(const pstring &name, properties &&props, Args&&... args)
|
||||
device_element_t(const pstring &name, properties &&props,
|
||||
Args &&...args)
|
||||
: element_t(name, std::move(props))
|
||||
, m_args(std::forward<Args>(args)...)
|
||||
{ }
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t... Is>
|
||||
dev_uptr make_device(device_arena &pool,
|
||||
netlist_state_t &anetlist,
|
||||
const pstring &name, std::tuple<Args...>& args, std::index_sequence<Is...>)
|
||||
dev_uptr make_device(device_arena &pool, netlist_state_t &anetlist,
|
||||
const pstring &name, std::tuple<Args...> &args,
|
||||
std::index_sequence<Is...>)
|
||||
{
|
||||
return plib::make_unique<C>(pool, anetlist, name, std::forward<Args>(std::get<Is>(args))...);
|
||||
return plib::make_unique<C>(
|
||||
pool, constructor_data_t{anetlist, name},
|
||||
std::forward<Args>(std::get<Is>(args))...);
|
||||
}
|
||||
|
||||
dev_uptr make_device(device_arena &pool,
|
||||
netlist_state_t &anetlist,
|
||||
const pstring &name, std::tuple<Args...>& args)
|
||||
dev_uptr make_device(device_arena &pool, netlist_state_t &anetlist,
|
||||
const pstring &name, std::tuple<Args...> &args)
|
||||
{
|
||||
return make_device(pool, anetlist, name, args, std::index_sequence_for<Args...>{});
|
||||
return make_device(pool, anetlist, name, args,
|
||||
std::index_sequence_for<Args...>{});
|
||||
}
|
||||
|
||||
dev_uptr make_device(device_arena &pool,
|
||||
netlist_state_t &anetlist,
|
||||
const pstring &name) override
|
||||
dev_uptr make_device(device_arena &pool, netlist_state_t &anetlist,
|
||||
const pstring &name) override
|
||||
{
|
||||
return make_device(pool, anetlist, name, m_args);
|
||||
}
|
||||
|
||||
static uptr create(const pstring &name, properties &&props, Args&&... args)
|
||||
static uptr
|
||||
create(const pstring &name, properties &&props, Args &&...args)
|
||||
{
|
||||
return plib::make_unique<device_element_t<C, Args...>, host_arena>(name,
|
||||
std::move(props), std::forward<Args>(args)...);
|
||||
return plib::make_unique<device_element_t<C, Args...>, host_arena>(
|
||||
name, std::move(props), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<Args...> m_args;
|
||||
};
|
||||
@ -162,60 +174,61 @@ namespace factory {
|
||||
|
||||
PCOPYASSIGNMOVE(list_t, delete)
|
||||
|
||||
template<class device_class, typename... Args>
|
||||
void add(const pstring &name, properties &&props, Args&&... args)
|
||||
template <class device_class, typename... Args>
|
||||
void add(const pstring &name, properties &&props, Args &&...args)
|
||||
{
|
||||
add(device_element_t<device_class, Args...>::create(name, std::move(props),
|
||||
std::forward<Args>(args)...));
|
||||
add(device_element_t<device_class, Args...>::create(
|
||||
name, std::move(props), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
void add(element_t::uptr &&factory) noexcept(false);
|
||||
|
||||
element_t::pointer factory_by_name(const pstring &devname) noexcept(false);
|
||||
element_t::pointer
|
||||
factory_by_name(const pstring &devname) noexcept(false);
|
||||
|
||||
template <class C>
|
||||
bool is_class(element_t::pointer f) noexcept
|
||||
{
|
||||
return dynamic_cast<device_element_t<C> *>(f) != nullptr;
|
||||
return bool(plib::dynamic_downcast<device_element_t<C> *>(f));
|
||||
}
|
||||
|
||||
bool exists(const pstring &name) const noexcept;
|
||||
|
||||
private:
|
||||
log_type &m_log;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// factory_creator_ptr_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
using constructor_ptr_t = element_t::uptr (*const)();
|
||||
|
||||
template <typename T>
|
||||
element_t::uptr constructor_t(const pstring &name, properties &&props)
|
||||
{
|
||||
return plib::make_unique<device_element_t<T>, host_arena>(name, std::move(props));
|
||||
return plib::make_unique<device_element_t<T>, host_arena>(
|
||||
name, std::move(props));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// library_element_t: factory class to wrap macro based chips/elements
|
||||
// -----------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class library_element_t : public element_t
|
||||
{
|
||||
public:
|
||||
|
||||
library_element_t(const pstring &name, properties &&props);
|
||||
|
||||
dev_uptr make_device(device_arena &pool,
|
||||
netlist_state_t &anetlist,
|
||||
const pstring &name) override;
|
||||
dev_uptr make_device(device_arena &pool, netlist_state_t &anetlist,
|
||||
const pstring &name) override;
|
||||
};
|
||||
|
||||
} // namespace factory
|
||||
} // namespace netlist::factory
|
||||
|
||||
namespace devices {
|
||||
void initialize_factory(factory::list_t &factory);
|
||||
} // namespace devices
|
||||
} // namespace netlist
|
||||
namespace netlist::devices
|
||||
{
|
||||
void initialize_factory(factory::list_t &factory);
|
||||
} // namespace netlist::devices
|
||||
|
||||
#endif // NLFACTORY_H_
|
||||
|
@ -11,232 +11,238 @@
|
||||
#define NLINTERFACE_H_
|
||||
|
||||
#include "nl_setup.h"
|
||||
|
||||
#include "core/analog.h"
|
||||
#include "core/device.h"
|
||||
#include "core/device_macros.h"
|
||||
#include "core/logic.h"
|
||||
#include "core/setup.h"
|
||||
|
||||
#include <memory>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace netlist
|
||||
namespace netlist::interface
|
||||
{
|
||||
/// \brief analog_callback device
|
||||
///
|
||||
/// This device is used to call back into the application which
|
||||
/// is controlling the execution of the netlist.
|
||||
///
|
||||
/// The device will call the provided lambda with a reference to
|
||||
/// itself and the current value of the net it is connected to.
|
||||
///
|
||||
/// The following code is an example on how to add the device to
|
||||
/// the netlist factory.
|
||||
///
|
||||
/// ```
|
||||
/// const pstring pin(m_in);
|
||||
/// pstring dname = pstring("OUT_") + pin;
|
||||
///
|
||||
/// const auto lambda = [this](auto &in, netlist::nl_fptype val)
|
||||
/// {
|
||||
/// this->cpu()->update_icount(in.exec().time());
|
||||
/// this->m_delegate(val, this->cpu()->local_time());
|
||||
/// this->cpu()->check_mame_abort_slice();
|
||||
/// };
|
||||
///
|
||||
/// using lb_t = decltype(lambda);
|
||||
/// using cb_t =
|
||||
/// netlist::interface::NETLIB_NAME(analog_callback)<lb_t>;
|
||||
///
|
||||
/// parser.factory().add<cb_t, netlist::nl_fptype, lb_t>(dname,
|
||||
/// netlist::factory::properties("-", PSOURCELOC()), 1e-6,
|
||||
/// std::forward<lb_t>(lambda));
|
||||
/// ```
|
||||
|
||||
namespace interface
|
||||
template <typename FUNC>
|
||||
class nld_analog_callback : public device_t
|
||||
{
|
||||
/// \brief analog_callback device
|
||||
///
|
||||
/// This device is used to call back into the application which
|
||||
/// is controlling the execution of the netlist.
|
||||
///
|
||||
/// The device will call the provided lambda with a reference to
|
||||
/// itself and the current value of the net it is connected to.
|
||||
///
|
||||
/// The following code is an example on how to add the device to
|
||||
/// the netlist factory.
|
||||
///
|
||||
/// ```
|
||||
/// const pstring pin(m_in);
|
||||
/// pstring dname = pstring("OUT_") + pin;
|
||||
///
|
||||
/// const auto lambda = [this](auto &in, netlist::nl_fptype val)
|
||||
/// {
|
||||
/// this->cpu()->update_icount(in.exec().time());
|
||||
/// this->m_delegate(val, this->cpu()->local_time());
|
||||
/// this->cpu()->check_mame_abort_slice();
|
||||
/// };
|
||||
///
|
||||
/// using lb_t = decltype(lambda);
|
||||
/// using cb_t = netlist::interface::NETLIB_NAME(analog_callback)<lb_t>;
|
||||
///
|
||||
/// parser.factory().add<cb_t, netlist::nl_fptype, lb_t>(dname,
|
||||
/// netlist::factory::properties("-", PSOURCELOC()), 1e-6, std::forward<lb_t>(lambda));
|
||||
/// ```
|
||||
|
||||
template <typename FUNC>
|
||||
NETLIB_OBJECT(analog_callback)
|
||||
public:
|
||||
nld_analog_callback(constructor_param_t data, nl_fptype threshold,
|
||||
FUNC &&func)
|
||||
: device_t(data)
|
||||
, m_in(*this, "IN", NETLIB_DELEGATE(in))
|
||||
, m_threshold(threshold)
|
||||
, m_last(*this, "m_last", 0)
|
||||
, m_func(func)
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_EX(analog_callback, nl_fptype threshold, FUNC &&func)
|
||||
, m_in(*this, "IN", NETLIB_DELEGATE(in))
|
||||
, m_threshold(threshold)
|
||||
, m_last(*this, "m_last", 0)
|
||||
, m_func(func)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_last = 0.0;
|
||||
}
|
||||
NETLIB_RESETI() { m_last = 0.0; }
|
||||
|
||||
NETLIB_HANDLERI(in)
|
||||
{
|
||||
const nl_fptype cur = m_in();
|
||||
if (plib::abs(cur - m_last) > m_threshold)
|
||||
{
|
||||
m_last = cur;
|
||||
m_func(*this, cur);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
analog_input_t m_in;
|
||||
nl_fptype m_threshold;
|
||||
state_var<nl_fptype> m_last;
|
||||
FUNC m_func;
|
||||
};
|
||||
|
||||
|
||||
/// \brief logic_callback device
|
||||
///
|
||||
/// This device must be connected to a logic net. It has no power terminals
|
||||
/// and conversion with proxies will not work.
|
||||
///
|
||||
/// Background: This device may be inserted later into the driver and should
|
||||
/// not modify the resulting analog representation of the netlist.
|
||||
///
|
||||
/// If you get error messages on missing power terminals you have to use the
|
||||
/// analog callback device instead.
|
||||
|
||||
template <typename FUNC>
|
||||
NETLIB_OBJECT(logic_callback)
|
||||
NETLIB_HANDLERI(in)
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_EX(logic_callback, FUNC &&func)
|
||||
, m_in(*this, "IN", NETLIB_DELEGATE(in))
|
||||
, m_func(func)
|
||||
const nl_fptype cur = m_in();
|
||||
if (plib::abs(cur - m_last) > m_threshold)
|
||||
{
|
||||
}
|
||||
|
||||
NETLIB_HANDLERI(in)
|
||||
{
|
||||
const netlist_sig_t cur = m_in();
|
||||
m_last = cur;
|
||||
m_func(*this, cur);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
logic_input_t m_in;
|
||||
FUNC m_func;
|
||||
};
|
||||
private:
|
||||
analog_input_t m_in;
|
||||
nl_fptype m_threshold;
|
||||
state_var<nl_fptype> m_last;
|
||||
FUNC m_func;
|
||||
};
|
||||
|
||||
/// \brief Set parameters to buffers contents at regular intervals
|
||||
///
|
||||
/// This device will update a parameter from a buffers passed to the device.
|
||||
/// It is the responsibility of the controlling application to ensure that
|
||||
/// the buffer is filled at regular intervals.
|
||||
///
|
||||
/// \tparam T The buffer type
|
||||
/// \tparam N Maximum number of supported buffers
|
||||
///
|
||||
template <typename T>
|
||||
NETLIB_OBJECT(buffered_param_setter)
|
||||
/// \brief logic_callback device
|
||||
///
|
||||
/// This device must be connected to a logic net. It has no power
|
||||
/// terminals and conversion with proxies will not work.
|
||||
///
|
||||
/// Background: This device may be inserted later into the driver and
|
||||
/// should not modify the resulting analog representation of the
|
||||
/// netlist.
|
||||
///
|
||||
/// If you get error messages on missing power terminals you have to use
|
||||
/// the analog callback device instead.
|
||||
|
||||
template <typename FUNC>
|
||||
class nld_logic_callback : public device_t
|
||||
{
|
||||
public:
|
||||
nld_logic_callback(constructor_param_t data, FUNC &&func)
|
||||
: device_t(data)
|
||||
, m_in(*this, "IN", NETLIB_DELEGATE(in))
|
||||
, m_func(func)
|
||||
{
|
||||
public:
|
||||
}
|
||||
|
||||
NETLIB_CONSTRUCTOR(buffered_param_setter)
|
||||
, m_sample_time(netlist_time::zero())
|
||||
, m_feedback(*this, "FB", NETLIB_DELEGATE(feedback)) // clock part
|
||||
, m_Q(*this, "Q")
|
||||
, m_pos(0)
|
||||
, m_samples(0)
|
||||
, m_param_name(*this, "CHAN", "")
|
||||
, m_param_mult(*this, "MULT", 1.0)
|
||||
, m_param_offset(*this, "OFFSET", 0.0)
|
||||
, m_param(nullptr)
|
||||
, m_id(*this, "ID", 0)
|
||||
{
|
||||
connect("FB", "Q");
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
NETLIB_HANDLERI(in)
|
||||
{
|
||||
const netlist_sig_t cur = m_in();
|
||||
m_func(*this, cur);
|
||||
}
|
||||
|
||||
protected:
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
}
|
||||
private:
|
||||
logic_input_t m_in;
|
||||
FUNC m_func;
|
||||
};
|
||||
|
||||
NETLIB_HANDLERI(feedback)
|
||||
/// \brief Set parameters to buffers contents at regular intervals
|
||||
///
|
||||
/// This device will update a parameter from a buffer passed to the
|
||||
/// device. It is the responsibility of the controlling application to
|
||||
/// ensure that the buffer is filled at regular intervals.
|
||||
///
|
||||
/// \tparam T The buffer type
|
||||
/// \tparam N Maximum number of supported buffers
|
||||
///
|
||||
template <typename T>
|
||||
class nld_buffered_param_setter : public device_t
|
||||
{
|
||||
public:
|
||||
nld_buffered_param_setter(constructor_param_t data)
|
||||
: device_t(data)
|
||||
, m_sample_time(netlist_time::zero())
|
||||
, m_feedback(*this, "FB", NETLIB_DELEGATE(feedback)) // clock part
|
||||
, m_Q(*this, "Q")
|
||||
, m_pos(0)
|
||||
, m_samples(0)
|
||||
, m_param_name(*this, "CHAN", "")
|
||||
, m_param_mult(*this, "MULT", 1.0)
|
||||
, m_param_offset(*this, "OFFSET", 0.0)
|
||||
, m_param(nullptr)
|
||||
, m_id(*this, "ID", 0)
|
||||
{
|
||||
connect("FB", "Q");
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
NETLIB_RESETI() {}
|
||||
|
||||
NETLIB_HANDLERI(feedback)
|
||||
{
|
||||
if (m_pos < m_samples)
|
||||
{
|
||||
if (m_pos < m_samples)
|
||||
// check if called outside of stream_update
|
||||
if (m_buffer != nullptr)
|
||||
{
|
||||
// check if called outside of stream_update
|
||||
if (m_buffer != nullptr)
|
||||
{
|
||||
const nl_fptype v = (*m_buffer)[m_pos];
|
||||
m_param_setter(v * m_param_mult() + m_param_offset());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: The logic has a rounding issue because time resolution divided
|
||||
// by 48,000 is not a natural number. The fractional part
|
||||
// adds up to one samples every 13 seconds for 100 ps resolution.
|
||||
// Fixing this is possible but complicated and expensive.
|
||||
}
|
||||
m_pos++;
|
||||
|
||||
m_Q.net().toggle_and_push_to_queue(m_sample_time);
|
||||
}
|
||||
|
||||
public:
|
||||
/// \brief resolve parameter names to pointers
|
||||
///
|
||||
/// This function must be called after all device were constructed but
|
||||
/// before reset is called.
|
||||
void resolve_params(netlist_time sample_time)
|
||||
{
|
||||
m_pos = 0;
|
||||
m_sample_time = sample_time;
|
||||
if (m_param_name() != pstring(""))
|
||||
{
|
||||
param_t *p = &state().setup().find_param(m_param_name()).param();
|
||||
m_param = p;
|
||||
if (dynamic_cast<param_fp_t *>(p) != nullptr)
|
||||
m_param_setter = setter_t(&NETLIB_NAME(buffered_param_setter)::setter<param_fp_t>, this);
|
||||
else if (dynamic_cast<param_logic_t *>(p) != nullptr)
|
||||
m_param_setter = setter_t(&NETLIB_NAME(buffered_param_setter)::setter<param_logic_t>, this);
|
||||
const nl_fptype v = (*m_buffer)[m_pos];
|
||||
m_param_setter(v * m_param_mult() + m_param_offset());
|
||||
}
|
||||
}
|
||||
|
||||
void buffer_reset(netlist_time sample_time, std::size_t num_samples, T *inputs)
|
||||
else
|
||||
{
|
||||
m_samples = num_samples;
|
||||
m_sample_time = sample_time;
|
||||
m_pos = 0;
|
||||
m_buffer = inputs;
|
||||
// FIXME: The logic has a rounding issue because time
|
||||
// resolution divided by 48,000 is not a natural
|
||||
// number. The fractional part adds up to one samples
|
||||
// every 13 seconds for 100 ps resolution. Fixing
|
||||
// this is possible but complicated and expensive.
|
||||
}
|
||||
m_pos++;
|
||||
|
||||
std::size_t id() const { return m_id; }
|
||||
private:
|
||||
using setter_t = plib::pmfp<void (nl_fptype)>;
|
||||
m_Q.net().toggle_and_push_to_queue(m_sample_time);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
void setter(nl_fptype v)
|
||||
public:
|
||||
/// \brief resolve parameter names to pointers
|
||||
///
|
||||
/// This function must be called after all device were constructed
|
||||
/// but before reset is called.
|
||||
void resolve_params(netlist_time sample_time)
|
||||
{
|
||||
m_pos = 0;
|
||||
m_sample_time = sample_time;
|
||||
if (m_param_name() != pstring(""))
|
||||
{
|
||||
static_cast<S *>(m_param)->set(v);
|
||||
param_t *p = &state()
|
||||
.setup()
|
||||
.find_param(m_param_name())
|
||||
.param();
|
||||
m_param = p;
|
||||
if (plib::dynamic_downcast<param_fp_t *>(p))
|
||||
m_param_setter = setter_t(
|
||||
&NETLIB_NAME(buffered_param_setter)::setter<param_fp_t>,
|
||||
this);
|
||||
else if (plib::dynamic_downcast<param_logic_t *>(p))
|
||||
m_param_setter = setter_t(
|
||||
&NETLIB_NAME(buffered_param_setter)::setter<
|
||||
param_logic_t>,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
netlist_time m_sample_time;
|
||||
void buffer_reset(netlist_time sample_time, std::size_t num_samples,
|
||||
T *inputs)
|
||||
{
|
||||
m_samples = num_samples;
|
||||
m_sample_time = sample_time;
|
||||
m_pos = 0;
|
||||
m_buffer = inputs;
|
||||
}
|
||||
|
||||
logic_input_t m_feedback;
|
||||
logic_output_t m_Q;
|
||||
std::size_t id() const { return m_id; }
|
||||
|
||||
std::size_t m_pos;
|
||||
std::size_t m_samples;
|
||||
private:
|
||||
using setter_t = plib::pmfp<void(nl_fptype)>;
|
||||
|
||||
param_str_t m_param_name;
|
||||
param_fp_t m_param_mult;
|
||||
param_fp_t m_param_offset;
|
||||
param_t * m_param;
|
||||
setter_t m_param_setter;
|
||||
T * m_buffer;
|
||||
param_num_t<std::size_t> m_id;
|
||||
};
|
||||
template <typename S>
|
||||
void setter(nl_fptype v)
|
||||
{
|
||||
static_cast<S *>(m_param)->set(v);
|
||||
}
|
||||
|
||||
} // namespace interface
|
||||
netlist_time m_sample_time;
|
||||
|
||||
} // namespace netlist
|
||||
logic_input_t m_feedback;
|
||||
logic_output_t m_Q;
|
||||
|
||||
std::size_t m_pos;
|
||||
std::size_t m_samples;
|
||||
|
||||
param_str_t m_param_name;
|
||||
param_fp_t m_param_mult;
|
||||
param_fp_t m_param_offset;
|
||||
param_t * m_param;
|
||||
setter_t m_param_setter;
|
||||
T * m_buffer;
|
||||
param_num_t<std::size_t> m_id;
|
||||
};
|
||||
|
||||
} // namespace netlist::interface
|
||||
|
||||
#endif // NLINTERFACE_H_
|
||||
|
@ -1,16 +1,17 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
#include "nl_parser.h"
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nl_factory.h"
|
||||
#include "nl_parser.h"
|
||||
#include "nl_setup.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// A netlist parser
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
void parser_t::verror(const pstring &msg)
|
||||
{
|
||||
@ -19,12 +20,16 @@ namespace netlist
|
||||
}
|
||||
|
||||
parser_t::parser_t(nlparse_t &setup)
|
||||
: m_setup(setup)
|
||||
, m_cur_local(nullptr)
|
||||
: m_setup(setup)
|
||||
, m_cur_local(nullptr)
|
||||
{
|
||||
m_tokenizer.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))
|
||||
m_tokenizer
|
||||
.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))
|
||||
.comment("/*", "*/", "//");
|
||||
m_tok_paren_left = m_tokenizer.register_token("(");
|
||||
m_tok_paren_right = m_tokenizer.register_token(")");
|
||||
@ -43,7 +48,8 @@ namespace netlist
|
||||
m_tok_INCLUDE = m_tokenizer.register_token("INCLUDE");
|
||||
m_tok_LOCAL_SOURCE = m_tokenizer.register_token("LOCAL_SOURCE");
|
||||
m_tok_LOCAL_LIB_ENTRY = m_tokenizer.register_token("LOCAL_LIB_ENTRY");
|
||||
m_tok_EXTERNAL_LIB_ENTRY = m_tokenizer.register_token("EXTERNAL_LIB_ENTRY");
|
||||
m_tok_EXTERNAL_LIB_ENTRY = m_tokenizer.register_token(
|
||||
"EXTERNAL_LIB_ENTRY");
|
||||
m_tok_SUBMODEL = m_tokenizer.register_token("SUBMODEL");
|
||||
m_tok_NETLIST_START = m_tokenizer.register_token("NETLIST_START");
|
||||
m_tok_NETLIST_END = m_tokenizer.register_token("NETLIST_END");
|
||||
@ -62,7 +68,6 @@ namespace netlist
|
||||
m_tokenizer.register_token("CAP_U");
|
||||
m_tokenizer.register_token("CAP_N");
|
||||
m_tokenizer.register_token("CAP_P");
|
||||
|
||||
}
|
||||
|
||||
bool parser_t::parse(plib::istream_uptr &&strm, const pstring &nlname)
|
||||
@ -72,15 +77,16 @@ namespace netlist
|
||||
return parse(tokstor, nlname);
|
||||
}
|
||||
|
||||
void parser_t::parse_tokens(plib::istream_uptr &&strm, token_store_t &tokstor)
|
||||
void parser_t::parse_tokens(plib::istream_uptr &&strm,
|
||||
token_store_t & tokstor)
|
||||
{
|
||||
plib::putf8_reader u8reader(strm.release_stream());
|
||||
m_tokenizer.append_to_store(&u8reader, tokstor);
|
||||
}
|
||||
|
||||
bool parser_t::parse(const token_store_t &tokstor, const pstring &nlname)
|
||||
bool parser_t::parse(const token_store_t &store, const pstring &nlname)
|
||||
{
|
||||
set_token_source(&tokstor);
|
||||
set_token_source(&store);
|
||||
|
||||
bool in_nl = false;
|
||||
|
||||
@ -97,7 +103,7 @@ namespace netlist
|
||||
if (token.is(m_tok_NETLIST_END) || token.is(m_tok_TRUTHTABLE_END))
|
||||
{
|
||||
if (!in_nl)
|
||||
error (MF_PARSER_UNEXPECTED_1(token.str()));
|
||||
error(MF_PARSER_UNEXPECTED_1(token.str()));
|
||||
else
|
||||
{
|
||||
in_nl = false;
|
||||
@ -108,15 +114,16 @@ namespace netlist
|
||||
m_cur_local->push_back(token);
|
||||
m_cur_local->push_back(token_t(m_tok_paren_left));
|
||||
m_cur_local->push_back(token_t(m_tok_paren_right));
|
||||
|
||||
}
|
||||
else if (token.is(m_tok_NETLIST_START) || token.is(m_tok_TRUTHTABLE_START))
|
||||
else if (token.is(m_tok_NETLIST_START)
|
||||
|| token.is(m_tok_TRUTHTABLE_START))
|
||||
{
|
||||
if (in_nl)
|
||||
error (MF_PARSER_UNEXPECTED_1(token.str()));
|
||||
error(MF_PARSER_UNEXPECTED_1(token.str()));
|
||||
require_token(m_tok_paren_left);
|
||||
token_t name = get_token();
|
||||
if (token.is(m_tok_NETLIST_START) && (name.str() == nlname || nlname.empty()))
|
||||
if (token.is(m_tok_NETLIST_START)
|
||||
&& (name.str() == nlname || nlname.empty()))
|
||||
{
|
||||
require_token(m_tok_paren_right);
|
||||
parse_netlist();
|
||||
@ -132,29 +139,32 @@ namespace netlist
|
||||
m_local.emplace(name.str(), token_store_t());
|
||||
m_cur_local = &m_local[name.str()];
|
||||
auto sl = location();
|
||||
auto li = plib::pfmt("# {1} \"{2}\"")(sl.line(), sl.file_name());
|
||||
auto li = plib::pfmt(
|
||||
"# {1} \"{2}\"")(sl.line(), sl.file_name());
|
||||
|
||||
m_cur_local->push_back(token_t(token_type::LINEMARKER, li));
|
||||
m_cur_local->push_back(token);
|
||||
m_cur_local->push_back(token_t(m_tok_paren_left));
|
||||
m_cur_local->push_back(name);
|
||||
//m_cur_local->push_back(token_t(m_tok_paren_right));
|
||||
// m_cur_local->push_back(token_t(m_tok_paren_right));
|
||||
in_nl = true;
|
||||
}
|
||||
// FIXME: do we really need this going forward ? there should be no need
|
||||
// FIXME: do we really need this going forward ? there should be no
|
||||
// need
|
||||
// for NETLIST_EXTERNAL in netlist files
|
||||
else if (token.is(m_tok_NETLIST_EXTERNAL))
|
||||
{
|
||||
if (in_nl)
|
||||
error (MF_UNEXPECTED_NETLIST_EXTERNAL());
|
||||
error(MF_UNEXPECTED_NETLIST_EXTERNAL());
|
||||
require_token(m_tok_paren_left);
|
||||
token_t name = get_token();
|
||||
require_token(m_tok_paren_right);
|
||||
}
|
||||
else if (!in_nl)
|
||||
{
|
||||
if (!token.is(m_tok_static) && !token.is_type(token_type::SOURCELINE)
|
||||
&& !token.is_type(token_type::LINEMARKER))
|
||||
if (!token.is(m_tok_static)
|
||||
&& !token.is_type(token_type::SOURCELINE)
|
||||
&& !token.is_type(token_type::LINEMARKER))
|
||||
error(MF_EXPECTED_NETLIST_START_1(token.str()));
|
||||
}
|
||||
else
|
||||
@ -171,7 +181,7 @@ namespace netlist
|
||||
token_t token = get_token();
|
||||
|
||||
if (token.is_type(token_type::ENDOFFILE))
|
||||
error (MF_UNEXPECTED_END_OF_FILE());
|
||||
error(MF_UNEXPECTED_END_OF_FILE());
|
||||
|
||||
m_setup.log().debug("Parser: Device: {1}\n", token.str());
|
||||
|
||||
@ -237,7 +247,8 @@ namespace netlist
|
||||
else if (m_local.find(name) != m_local.end())
|
||||
error(MF_EXTERNAL_SOURCE_IS_LOCAL_1(name));
|
||||
|
||||
// FIXME: Need to pass in parameter definition FIXME: get line number right
|
||||
// FIXME: Need to pass in parameter definition FIXME: get line number
|
||||
// right
|
||||
m_setup.register_lib_entry(name, "", location());
|
||||
require_token(m_tok_paren_right);
|
||||
}
|
||||
@ -376,7 +387,6 @@ namespace netlist
|
||||
require_token(m_tok_paren_left);
|
||||
pstring name(get_identifier());
|
||||
require_token(m_tok_paren_right);
|
||||
|
||||
}
|
||||
|
||||
void parser_t::net_alias()
|
||||
@ -403,7 +413,7 @@ namespace netlist
|
||||
while (true)
|
||||
{
|
||||
pstring t1 = get_identifier();
|
||||
m_setup.register_link(first , t1);
|
||||
m_setup.register_link(first, t1);
|
||||
m_setup.log().debug("Parser: Connect: {1} {2}\n", first, t1);
|
||||
token_t n = get_token();
|
||||
if (n.is(m_tok_paren_right))
|
||||
@ -411,7 +421,6 @@ namespace netlist
|
||||
if (!n.is(m_tok_comma))
|
||||
error(MF_EXPECTED_COMMA_OR_RP_1(n.str()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void parser_t::dip_pins()
|
||||
@ -437,8 +446,8 @@ namespace netlist
|
||||
std::size_t n = pins.size();
|
||||
for (std::size_t i = 0; i < n / 2; i++)
|
||||
{
|
||||
m_setup.register_alias(plib::pfmt("{1}")(i+1), pins[i*2]);
|
||||
m_setup.register_alias(plib::pfmt("{1}")(n-i), pins[i*2 + 1]);
|
||||
m_setup.register_alias(plib::pfmt("{1}")(i + 1), pins[i * 2]);
|
||||
m_setup.register_alias(plib::pfmt("{1}")(n - i), pins[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,7 +480,8 @@ namespace netlist
|
||||
token_t tok = get_token();
|
||||
if (tok.is_type(token_type::STRING))
|
||||
{
|
||||
m_setup.log().debug("Parser: DefParam: {1} {2}\n", param, tok.str());
|
||||
m_setup.log().debug("Parser: DefParam: {1} {2}\n", param,
|
||||
tok.str());
|
||||
m_setup.register_default_param(param, tok.str());
|
||||
require_token(m_tok_paren_right);
|
||||
}
|
||||
@ -535,13 +545,13 @@ namespace netlist
|
||||
m_setup.register_dev(dev_type, devname, params);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// private
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
pstring parser_t::stringify_expression(token_t &tok)
|
||||
{
|
||||
int pc(0);
|
||||
int pc(0);
|
||||
pstring ret;
|
||||
while (!tok.is(m_tok_comma))
|
||||
{
|
||||
@ -549,7 +559,7 @@ namespace netlist
|
||||
pc++;
|
||||
else if (tok.is(m_tok_paren_right))
|
||||
{
|
||||
if (pc<=0)
|
||||
if (pc <= 0)
|
||||
break;
|
||||
pc--;
|
||||
}
|
||||
@ -559,9 +569,9 @@ namespace netlist
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// source_token_t
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
bool source_token_t::parse(nlparse_t &setup, const pstring &name)
|
||||
{
|
||||
@ -574,7 +584,8 @@ namespace netlist
|
||||
return false;
|
||||
}
|
||||
|
||||
plib::istream_uptr source_token_t::stream([[maybe_unused]] const pstring &name)
|
||||
plib::istream_uptr source_token_t::stream(
|
||||
[[maybe_unused]] const pstring &name)
|
||||
{
|
||||
return plib::istream_uptr();
|
||||
}
|
||||
|
@ -8,8 +8,10 @@
|
||||
#ifndef NL_PARSER_H_
|
||||
#define NL_PARSER_H_
|
||||
|
||||
#include "core/setup.h"
|
||||
#include "nltypes.h" // for setup_t
|
||||
|
||||
#include "core/setup.h"
|
||||
|
||||
#include "plib/ptokenizer.h"
|
||||
|
||||
#include <unordered_map>
|
||||
@ -51,6 +53,7 @@ namespace netlist
|
||||
void net_truth_table_start(const pstring &nlname);
|
||||
|
||||
void verror(const pstring &msg) override;
|
||||
|
||||
private:
|
||||
void register_local_as_source(const pstring &name);
|
||||
|
||||
@ -86,16 +89,17 @@ namespace netlist
|
||||
token_id_t m_tok_TT_FAMILY;
|
||||
|
||||
plib::tokenizer_t m_tokenizer;
|
||||
nlparse_t &m_setup;
|
||||
nlparse_t & m_setup;
|
||||
|
||||
std::unordered_map<pstring, token_store_t> m_local;
|
||||
token_store_t *m_cur_local;
|
||||
token_store_t * m_cur_local;
|
||||
};
|
||||
|
||||
class source_token_t : public source_netlist_t
|
||||
{
|
||||
public:
|
||||
source_token_t(const pstring &name, const parser_t::token_store_t &store)
|
||||
source_token_t(const pstring & name,
|
||||
const parser_t::token_store_t &store)
|
||||
: m_store(store)
|
||||
, m_name(name)
|
||||
{
|
||||
@ -108,10 +112,9 @@ namespace netlist
|
||||
|
||||
private:
|
||||
parser_t::token_store_t m_store;
|
||||
pstring m_name;
|
||||
pstring m_name;
|
||||
};
|
||||
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
#endif // NL_PARSER_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -107,15 +107,26 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
|
||||
// truth table defines
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
#define TRUTHTABLE_START(cname, in, out, pdef_params) \
|
||||
NETLIST_START(cname) \
|
||||
netlist::tt_desc desc; \
|
||||
desc.name = #cname ; \
|
||||
desc.ni = in; \
|
||||
desc.no = out; \
|
||||
desc.family = ""; \
|
||||
void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc); \
|
||||
static NETLIST_START(cname) \
|
||||
netlist::tt_desc xdesc{ #cname, in, out, "" }; \
|
||||
auto sloc = PSOURCELOC(); \
|
||||
const pstring def_params = pdef_params;
|
||||
const pstring def_params = pdef_params; \
|
||||
NETLIST_NAME(cname ## _impl)(xdesc); \
|
||||
setup.truth_table_create(xdesc, def_params, std::move(sloc)); \
|
||||
NETLIST_END() \
|
||||
static void NETLIST_NAME(cname ## _impl)(netlist::tt_desc &desc) \
|
||||
{
|
||||
#else
|
||||
#define TRUTHTABLE_START(cname, in, out, pdef_params) \
|
||||
NETLIST_START(cname) \
|
||||
netlist::tt_desc desc{ #cname, in, out, "", {} }; \
|
||||
auto sloc = PSOURCELOC(); \
|
||||
const pstring def_params = pdef_params; \
|
||||
plib::functor_guard lg([&](){ setup.truth_table_create(desc, def_params, std::move(sloc)); });
|
||||
#endif
|
||||
|
||||
#define TT_HEAD(x) \
|
||||
desc.desc.emplace_back(x);
|
||||
@ -127,7 +138,6 @@ void NETLIST_NAME(name)([[maybe_unused]] netlist::nlparse_t &setup) \
|
||||
desc.family = x;
|
||||
|
||||
#define TRUTHTABLE_END() \
|
||||
setup.truth_table_create(desc, def_params, std::move(sloc)); \
|
||||
NETLIST_END()
|
||||
|
||||
#define TRUTHTABLE_ENTRY(name) \
|
||||
@ -143,12 +153,11 @@ namespace netlist
|
||||
|
||||
struct tt_desc
|
||||
{
|
||||
tt_desc() : ni(0), no(0) { }
|
||||
pstring name;
|
||||
unsigned long ni;
|
||||
unsigned long no;
|
||||
std::vector<pstring> desc;
|
||||
pstring family;
|
||||
std::vector<pstring> desc;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -174,7 +183,7 @@ namespace netlist
|
||||
// last argument only needed by nltool
|
||||
void register_dev(const pstring &classname, const pstring &name,
|
||||
const std::vector<pstring> ¶ms_and_connections,
|
||||
factory::element_t **felem = nullptr);
|
||||
factory::element_t **factory_element = nullptr);
|
||||
void register_dev(const pstring &classname, std::initializer_list<const char *> more_parameters);
|
||||
void register_dev(const pstring &classname, const pstring &name)
|
||||
{
|
||||
|
@ -24,8 +24,7 @@
|
||||
|
||||
/// \brief Construct a netlist device name
|
||||
///
|
||||
#define NETLIB_NAME(chip) nld_ ## chip
|
||||
|
||||
#define NETLIB_NAME(chip) nld_##chip
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
@ -43,14 +42,24 @@ namespace netlist
|
||||
class netlist_t;
|
||||
class netlist_state_t;
|
||||
class core_device_t;
|
||||
class base_device_t;
|
||||
class device_t;
|
||||
class netlist_state_t;
|
||||
class param_t;
|
||||
class logic_family_desc_t;
|
||||
class logic_family_std_proxy_t;
|
||||
class terminal_t;
|
||||
|
||||
template <typename CX>
|
||||
struct sub_device_wrapper;
|
||||
|
||||
class models_t;
|
||||
|
||||
namespace analog
|
||||
{
|
||||
class NETLIB_NAME(two_terminal);
|
||||
} // namespace analog
|
||||
|
||||
namespace devices
|
||||
{
|
||||
class nld_solver;
|
||||
@ -59,6 +68,9 @@ namespace netlist
|
||||
class nld_base_d_to_a_proxy;
|
||||
class nld_base_a_to_d_proxy;
|
||||
class nld_netlistparams;
|
||||
|
||||
template <unsigned m_NI, unsigned m_NO>
|
||||
class factory_truth_table_t;
|
||||
} // namespace devices
|
||||
|
||||
namespace solver
|
||||
@ -76,20 +88,15 @@ namespace netlist
|
||||
|
||||
namespace factory
|
||||
{
|
||||
template <class C, typename... Args>
|
||||
class device_element_t;
|
||||
class library_element_t;
|
||||
|
||||
class list_t;
|
||||
class element_t;
|
||||
struct properties;
|
||||
} // namespace factory
|
||||
|
||||
template <class CX>
|
||||
class delegator_t : public CX
|
||||
{
|
||||
protected:
|
||||
using base_type = delegator_t<CX>;
|
||||
using delegated_type = CX;
|
||||
using delegated_type::delegated_type;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
@ -98,15 +105,20 @@ namespace netlist
|
||||
|
||||
/// \brief Constants and const calculations for the library
|
||||
///
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct nlconst_base : public plib::constants<T>
|
||||
{
|
||||
using BC = plib::constants<T>;
|
||||
|
||||
static constexpr T np_VT(T n=BC::one(), T temp=BC::T0()) noexcept
|
||||
{ return n * temp * BC::k_b() / BC::Q_e(); }
|
||||
static constexpr T np_VT(T n = BC::one(), T temp = BC::T0()) noexcept
|
||||
{
|
||||
return n * temp * BC::k_b() / BC::Q_e();
|
||||
}
|
||||
|
||||
static constexpr T np_Is() noexcept { return static_cast<T>(1e-15); } // NOLINT
|
||||
static constexpr T np_Is() noexcept
|
||||
{
|
||||
return static_cast<T>(1e-15);
|
||||
} // NOLINT
|
||||
|
||||
/// \brief constant startup gmin
|
||||
///
|
||||
@ -114,20 +126,32 @@ namespace netlist
|
||||
/// conductivities with a reasonable value.
|
||||
/// During reset, the object should than make use of exec().gmin()
|
||||
/// to use the actual gmin() value.
|
||||
static constexpr T cgmin() noexcept { return BC::magic(1e-9); } // NOLINT
|
||||
static constexpr T cgmin() noexcept
|
||||
{
|
||||
return BC::magic(1e-9);
|
||||
} // NOLINT
|
||||
|
||||
// FIXME: Some objects used 1e-15 for initial gmin. Needs to be
|
||||
// aligned with cgmin
|
||||
static constexpr T cgminalt() noexcept { return BC::magic(1e-15); } // NOLINT
|
||||
static constexpr T cgminalt() noexcept
|
||||
{
|
||||
return BC::magic(1e-15);
|
||||
} // NOLINT
|
||||
|
||||
/// \brief Multiplier applied to VT in np diode models to determine range for constant model
|
||||
/// \brief Multiplier applied to VT in np diode models to determine
|
||||
/// range for constant model
|
||||
///
|
||||
static constexpr T diode_min_cutoff_mult() noexcept { return BC::magic(-5.0); } // NOLINT
|
||||
static constexpr T diode_min_cutoff_mult() noexcept
|
||||
{
|
||||
return BC::magic(-5.0);
|
||||
} // NOLINT
|
||||
|
||||
/// \brief Startup voltage used by np diode models
|
||||
///
|
||||
static constexpr T diode_start_voltage() noexcept { return BC::magic(0.7); } // NOLINT
|
||||
|
||||
static constexpr T diode_start_voltage() noexcept
|
||||
{
|
||||
return BC::magic(0.7);
|
||||
} // NOLINT
|
||||
};
|
||||
|
||||
/// \brief nlconst_base struct specialized for nl_fptype.
|
||||
@ -149,11 +173,12 @@ namespace netlist
|
||||
///
|
||||
|
||||
using device_arena = std::conditional_t<config::use_mempool::value,
|
||||
plib::mempool_arena<plib::aligned_arena<>, config::mempool_align::value>,
|
||||
plib::mempool_arena<plib::aligned_arena<>,
|
||||
config::mempool_align::value>,
|
||||
plib::aligned_arena<>>;
|
||||
using host_arena = plib::aligned_arena<>;
|
||||
using host_arena = plib::aligned_arena<>;
|
||||
|
||||
using log_type = plib::plog_base<NL_DEBUG>;
|
||||
using log_type = plib::plog_base<NL_DEBUG>;
|
||||
|
||||
//============================================================
|
||||
// Types needed by various includes
|
||||
@ -165,49 +190,69 @@ namespace netlist
|
||||
///
|
||||
enum class time_step_type
|
||||
{
|
||||
FORWARD, ///< forward time
|
||||
RESTORE ///< restore state before last forward
|
||||
FORWARD, ///< forward time
|
||||
RESTORE ///< restore state before last forward
|
||||
};
|
||||
|
||||
/// \brief Delegate type for device notification.
|
||||
///
|
||||
using nl_delegate = plib::pmfp<void ()>;
|
||||
using nl_delegate_ts = plib::pmfp<void (time_step_type, nl_fptype)>;
|
||||
using nl_delegate_dyn = plib::pmfp<void ()>;
|
||||
using nl_delegate = plib::pmfp<void()>;
|
||||
using nl_delegate_ts = plib::pmfp<void(time_step_type, nl_fptype)>;
|
||||
using nl_delegate_dyn = plib::pmfp<void()>;
|
||||
|
||||
namespace detail {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// \brief Enum specifying the type of object
|
||||
///
|
||||
enum class terminal_type {
|
||||
enum class terminal_type
|
||||
{
|
||||
TERMINAL = 0, ///< object is an analog terminal
|
||||
INPUT = 1, ///< object is an input
|
||||
OUTPUT = 2, ///< object is an output
|
||||
INPUT = 1, ///< object is an input
|
||||
OUTPUT = 2, ///< object is an output
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using netlist_time = plib::ptime<std::int64_t, config::INTERNAL_RES::value>;
|
||||
using netlist_time_ext = plib::ptime<std::conditional<config::prefer_int128::value && plib::compile_info::has_int128::value, INT128, std::int64_t>::type, config::INTERNAL_RES::value>;
|
||||
using netlist_time_ext = plib::ptime<
|
||||
std::conditional<config::prefer_int128::value
|
||||
&& plib::compile_info::has_int128::value,
|
||||
INT128, std::int64_t>::type,
|
||||
config::INTERNAL_RES::value>;
|
||||
|
||||
static_assert(noexcept(netlist_time::from_nsec(1)), "Not evaluated as constexpr");
|
||||
static_assert(noexcept(netlist_time::from_nsec(1)),
|
||||
"Not evaluated as constexpr");
|
||||
|
||||
//============================================================
|
||||
// MACROS
|
||||
//============================================================
|
||||
|
||||
template <typename T> constexpr netlist_time NLTIME_FROM_NS(T &&t) noexcept { return netlist_time::from_nsec(t); }
|
||||
template <typename T> constexpr netlist_time NLTIME_FROM_US(T &&t) noexcept { return netlist_time::from_usec(t); }
|
||||
template <typename T> constexpr netlist_time NLTIME_FROM_MS(T &&t) noexcept { return netlist_time::from_msec(t); }
|
||||
template <typename T>
|
||||
constexpr netlist_time NLTIME_FROM_NS(T &&t) noexcept
|
||||
{
|
||||
return netlist_time::from_nsec(t);
|
||||
}
|
||||
template <typename T>
|
||||
constexpr netlist_time NLTIME_FROM_US(T &&t) noexcept
|
||||
{
|
||||
return netlist_time::from_usec(t);
|
||||
}
|
||||
template <typename T>
|
||||
constexpr netlist_time NLTIME_FROM_MS(T &&t) noexcept
|
||||
{
|
||||
return netlist_time::from_msec(t);
|
||||
}
|
||||
|
||||
struct desc_base
|
||||
{
|
||||
/// \brief: used to hold one static netlist_time value
|
||||
///
|
||||
template<netlist_time::internal_type value0>
|
||||
template <netlist_time::internal_type value0>
|
||||
struct times_ns1
|
||||
{
|
||||
static constexpr netlist_time value([[maybe_unused]] std::size_t N = 0)
|
||||
static constexpr netlist_time value(
|
||||
[[maybe_unused]] std::size_t N = 0)
|
||||
{
|
||||
return NLTIME_FROM_NS(value0);
|
||||
}
|
||||
@ -218,8 +263,8 @@ namespace netlist
|
||||
|
||||
/// \brief: used to hold two static netlist_time values
|
||||
///
|
||||
template<netlist_time::internal_type value0,
|
||||
netlist_time::internal_type value1>
|
||||
template <netlist_time::internal_type value0,
|
||||
netlist_time::internal_type value1>
|
||||
struct times_ns2
|
||||
{
|
||||
static constexpr netlist_time value(std::size_t N)
|
||||
@ -230,16 +275,16 @@ namespace netlist
|
||||
|
||||
/// \brief: used to hold three static netlist_time values
|
||||
///
|
||||
template<netlist_time::internal_type value0,
|
||||
netlist_time::internal_type value1,
|
||||
netlist_time::internal_type value2>
|
||||
template <netlist_time::internal_type value0,
|
||||
netlist_time::internal_type value1,
|
||||
netlist_time::internal_type value2>
|
||||
struct times_ns3
|
||||
{
|
||||
static constexpr netlist_time value(std::size_t N)
|
||||
{
|
||||
return N == 0 ? NLTIME_FROM_NS(value0) :
|
||||
N == 1 ? NLTIME_FROM_NS(value1) :
|
||||
NLTIME_FROM_NS(value2);
|
||||
return N == 0 ? NLTIME_FROM_NS(value0)
|
||||
: N == 1 ? NLTIME_FROM_NS(value1)
|
||||
: NLTIME_FROM_NS(value2);
|
||||
}
|
||||
};
|
||||
|
||||
@ -248,10 +293,10 @@ namespace netlist
|
||||
/// See the 74125 implementation
|
||||
///
|
||||
template <std::size_t V>
|
||||
using desc_const = std::integral_constant<const std::size_t, V>;
|
||||
using desc_const = std::integral_constant<const std::size_t, V>;
|
||||
|
||||
template <typename T, T V>
|
||||
using desc_const_t = std::integral_constant<const T, V>;
|
||||
using desc_const_t = std::integral_constant<const T, V>;
|
||||
};
|
||||
|
||||
//============================================================
|
||||
@ -268,20 +313,24 @@ namespace netlist
|
||||
/// Allows a descriptive text to be passed to the exception
|
||||
|
||||
explicit nl_exception(const pstring &text //!< text to be passed
|
||||
)
|
||||
: plib::pexception(text) { }
|
||||
)
|
||||
: plib::pexception(text)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief Constructor.
|
||||
/// Allows to use \ref plib::pfmt logic to be used in exception
|
||||
|
||||
template<typename... Args>
|
||||
template <typename... Args>
|
||||
explicit nl_exception(const pstring &fmt //!< format to be used
|
||||
, Args&&... args //!< arguments to be passed
|
||||
,
|
||||
Args &&...args //!< arguments to be passed
|
||||
)
|
||||
: plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...)) { }
|
||||
: plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NLTYPES_H_
|
||||
|
@ -20,7 +20,7 @@ namespace plib {
|
||||
// terminate
|
||||
//============================================================
|
||||
|
||||
void terminate(const char *msg) noexcept
|
||||
[[noreturn]] void terminate(const char *msg) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -104,7 +104,7 @@ namespace plib {
|
||||
class fp_signal_enabler
|
||||
{
|
||||
public:
|
||||
explicit fp_signal_enabler(unsigned fpexceptions);
|
||||
explicit fp_signal_enabler(unsigned fp_exceptions);
|
||||
|
||||
PCOPYASSIGNMOVE(fp_signal_enabler, delete)
|
||||
|
||||
|
@ -39,7 +39,7 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
pfmt::rtype pfmt::set_format(std::stringstream &strm, char32_t cfmt_spec)
|
||||
pfmt::rtype pfmt::set_format(std::stringstream &strm, char32_t char_format)
|
||||
{
|
||||
pstring fmt;
|
||||
pstring search("{");
|
||||
@ -92,18 +92,18 @@ pfmt::rtype pfmt::set_format(std::stringstream &strm, char32_t cfmt_spec)
|
||||
// a.b format here ...
|
||||
char32_t pend(0);
|
||||
int width(0);
|
||||
if (!fmt.empty() && pstring("duxofge").find(static_cast<pstring::value_type>(cfmt_spec)) != pstring::npos)
|
||||
if (!fmt.empty() && pstring("duxofge").find(static_cast<pstring::value_type>(char_format)) != pstring::npos)
|
||||
{
|
||||
//pend = static_cast<char32_t>(fmt.at(fmt.size() - 1));
|
||||
pend = plib::right(fmt, 1).at(0);
|
||||
if (pstring("duxofge").find(static_cast<pstring::value_type>(pend)) == pstring::npos)
|
||||
pend = cfmt_spec;
|
||||
pend = char_format;
|
||||
else
|
||||
fmt = plib::left(fmt, fmt.length() - 1);
|
||||
}
|
||||
else
|
||||
// FIXME: Error
|
||||
pend = cfmt_spec;
|
||||
pend = char_format;
|
||||
|
||||
auto pdot(fmt.find('.'));
|
||||
|
||||
|
@ -375,7 +375,7 @@ namespace plib {
|
||||
if (build_enabled && enabled && m_enabled)
|
||||
{
|
||||
pfmt pf(fmt);
|
||||
dynamic_cast<T &>(*this).upstream_write(log_translate(pf, std::forward<Args>(args)...));
|
||||
plib::dynamic_downcast<T &>(*this).upstream_write(log_translate(pf, std::forward<Args>(args)...));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ptypes.h"
|
||||
|
||||
#include <exception>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@ -101,6 +102,54 @@ namespace plib {
|
||||
|
||||
} // namespace pgsl
|
||||
|
||||
/// \brief dynamic downcast from base type pointer to derived type pointer
|
||||
///
|
||||
/// This is a `noexcept` dynamic_cast implementation. It will return the cast
|
||||
/// wrapped into a std::optional type forcing the caller to
|
||||
/// examine if the conversion was successful.
|
||||
///
|
||||
/// \tparam D Derived type
|
||||
/// \tparam B Base type
|
||||
/// \param base pointer to type B
|
||||
/// \returns return_success_t
|
||||
///
|
||||
template <typename D, typename B>
|
||||
std::enable_if_t<std::is_pointer_v<D> && std::is_pointer_v<std::remove_reference_t<B>>,
|
||||
std::optional<D>>
|
||||
dynamic_downcast(B base) noexcept
|
||||
{
|
||||
D ret = dynamic_cast<D>(base);
|
||||
if (ret != nullptr)
|
||||
return ret;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// \brief dynamic downcast from base type reference to derived type pointer
|
||||
///
|
||||
/// This is a `noexcept` dynamic_cast implementation. It will return the
|
||||
/// pointer cast wrapped into a std::optional type forcing the caller to
|
||||
/// examine if the conversion was successful.
|
||||
///
|
||||
/// The return value is a pointer cast since there is no std::optional for
|
||||
/// references. Such a construct is considered ill-formed according to
|
||||
/// the std::optional specification (Section 5.2, p1).
|
||||
///
|
||||
/// \tparam D Derived type
|
||||
/// \tparam B Base type
|
||||
/// \param base reference of type B
|
||||
/// \returns return_success_t
|
||||
///
|
||||
template <typename D, typename B>
|
||||
std::enable_if_t<std::is_pointer_v<D> &&!std::is_pointer_v<std::remove_reference_t<B>> ,
|
||||
std::optional<D>>
|
||||
dynamic_downcast(B &base) noexcept
|
||||
{
|
||||
D ret = dynamic_cast<D>(&base);
|
||||
if (ret != nullptr)
|
||||
return ret;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// \brief downcast from base type to derived type
|
||||
///
|
||||
/// The cpp core guidelines require a very careful use of static cast
|
||||
@ -110,8 +159,8 @@ namespace plib {
|
||||
template <typename D, typename B>
|
||||
constexpr D downcast(B && b) noexcept
|
||||
{
|
||||
static_assert(std::is_pointer<D>::value || std::is_reference<D>::value, "downcast only supports pointers or reference for derived");
|
||||
static_assert(std::is_pointer<B>::value || std::is_reference<B>::value, "downcast only supports pointers or reference for base");
|
||||
static_assert((std::is_pointer<D>::value && std::is_pointer<B>::value)
|
||||
|| (std::is_reference<D>::value && std::is_reference<B>::value), "downcast only supports pointers or reference for derived");
|
||||
return static_cast<D>(std::forward<B>(b));
|
||||
}
|
||||
|
||||
|
@ -505,7 +505,7 @@ namespace plib
|
||||
~pLUmatrix_cr() = default;
|
||||
|
||||
template <typename M>
|
||||
void build(M &fill, std::size_t ilup) noexcept
|
||||
void build(M &fill, std::size_t ilup) noexcept(false)
|
||||
{
|
||||
std::size_t p(0);
|
||||
// build ilu_rows
|
||||
|
@ -132,7 +132,7 @@ namespace plib {
|
||||
protected:
|
||||
int parse(const pstring &argument) override
|
||||
{
|
||||
auto raw = plib::container::indexof(limit(), argument);
|
||||
auto raw = plib::container::index_of(limit(), argument);
|
||||
|
||||
if (raw != plib::container::npos)
|
||||
{
|
||||
|
@ -83,8 +83,8 @@ namespace plib {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(byteptr);
|
||||
// and add offset to virtual base from vtable
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
if (sizeof(unknown_base_equiv) == m_size)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
byteptr += *reinterpret_cast<int const *>(vptr + m_vt_index);
|
||||
}
|
||||
|
||||
|
@ -577,7 +577,7 @@ namespace plib {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
auto p = reinterpret_cast<const typename late_pmfp<T>::traits::template specific_member_function<O> *>(raw);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
auto o = reinterpret_cast<O *>(obj);
|
||||
auto *o = reinterpret_cast<O *>(obj);
|
||||
return return_type(*p, o);
|
||||
}
|
||||
|
||||
|
@ -140,10 +140,9 @@ namespace plib
|
||||
{
|
||||
for (auto &s : m_collection)
|
||||
{
|
||||
auto *source(dynamic_cast<S *>(s.get()));
|
||||
if (source)
|
||||
if (auto source = plib::dynamic_downcast<S *>(s.get()))
|
||||
{
|
||||
auto strm = source->stream(name);
|
||||
auto strm = (*source)->stream(name);
|
||||
if (!strm.empty())
|
||||
return strm;
|
||||
}
|
||||
@ -156,10 +155,9 @@ namespace plib
|
||||
{
|
||||
for (auto &s : m_collection)
|
||||
{
|
||||
auto *source(dynamic_cast<S *>(s.get()));
|
||||
if (source)
|
||||
if (auto source = plib::dynamic_downcast<S *>(s.get()))
|
||||
{
|
||||
if (lambda(source))
|
||||
if (lambda(*source))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +175,14 @@ namespace plib::testing
|
||||
reg_entry_base(const char *n, const char *d, test_location l)
|
||||
: name(n), desc(d), location(l)
|
||||
{
|
||||
registry().push_back(this);
|
||||
try
|
||||
{
|
||||
registry().push_back(this);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
reg_entry_base(const reg_entry_base &) = delete;
|
||||
@ -253,22 +260,22 @@ namespace plib::testing
|
||||
t->set_parameters(¶ms);
|
||||
})).first)
|
||||
{
|
||||
stream_error(std::cout, e->location) << "unexpected exception thrown during instantiation" << (r.second != "" ? ": " + r.second : "") << std::endl;
|
||||
stream_error(std::cout, e->location) << "unexpected exception thrown during instantiation" << (!r.second.empty() ? ": " + r.second : "") << std::endl;
|
||||
total_errors++;
|
||||
}
|
||||
else if ((r = catch_exception([&]{ t->SetUp(); })).first)
|
||||
{
|
||||
stream_error(std::cout, e->location) << "unexpected exception thrown during Setup" << (r.second != "" ? ": " + r.second : "") << std::endl;
|
||||
stream_error(std::cout, e->location) << "unexpected exception thrown during Setup" << (!r.second.empty() ? ": " + r.second : "") << std::endl;
|
||||
total_errors++;
|
||||
}
|
||||
else if ((r = catch_exception([&]{ t->run(); })).first)
|
||||
{
|
||||
stream_error(std::cout, params.m_last_source) << "unexpected exception thrown during run after this line" << (r.second != "" ? ": " + r.second : "") << std::endl;
|
||||
stream_error(std::cout, params.m_last_source) << "unexpected exception thrown during run after this line" << (!r.second.empty() ? ": " + r.second : "") << std::endl;
|
||||
total_errors++;
|
||||
}
|
||||
else if ((r = catch_exception([&]{ t->TearDown(); })).first)
|
||||
{
|
||||
stream_error(std::cout, e->location) << "unexpected exception thrown during Teardown" << (r.second != "" ? ": " + r.second : "") << std::endl;
|
||||
stream_error(std::cout, e->location) << "unexpected exception thrown during Teardown" << (!r.second.empty() ? ": " + r.second : "") << std::endl;
|
||||
total_errors++;
|
||||
}
|
||||
|
||||
|
@ -69,16 +69,16 @@ namespace plib {
|
||||
m_unget = c;
|
||||
}
|
||||
|
||||
void tokenizer_t::append_to_store(putf8_reader *reader, token_store_t &tokstor)
|
||||
void tokenizer_t::append_to_store(putf8_reader *reader, token_store_t &store)
|
||||
{
|
||||
clear();
|
||||
m_strm = reader;
|
||||
// Process tokens into queue
|
||||
token_t ret(token_type::UNKNOWN);
|
||||
m_token_queue = &tokstor;
|
||||
m_token_queue = &store;
|
||||
do {
|
||||
ret = get_token_comment();
|
||||
tokstor.push_back(ret);
|
||||
store.push_back(ret);
|
||||
} while (!ret.is_type(token_type::token_type::ENDOFFILE));
|
||||
m_token_queue = nullptr;
|
||||
}
|
||||
@ -300,28 +300,26 @@ namespace plib {
|
||||
}
|
||||
return { token_type::STRING, tokstr };
|
||||
}
|
||||
else
|
||||
|
||||
// read identifier till first identifier char or ws
|
||||
pstring tokstr = "";
|
||||
while ((m_identifier_chars.find(c) == pstring::npos) && (m_whitespace.find(c) == pstring::npos))
|
||||
{
|
||||
// read identifier till first identifier char or ws
|
||||
pstring tokstr = "";
|
||||
while ((m_identifier_chars.find(c) == pstring::npos) && (m_whitespace.find(c) == pstring::npos))
|
||||
tokstr += c;
|
||||
// expensive, check for single char tokens
|
||||
if (tokstr.length() == 1)
|
||||
{
|
||||
tokstr += c;
|
||||
// expensive, check for single char tokens
|
||||
if (tokstr.length() == 1)
|
||||
{
|
||||
auto id = m_tokens.find(tokstr);
|
||||
if (id != m_tokens.end())
|
||||
return { id->second, tokstr };
|
||||
}
|
||||
c = getc();
|
||||
auto id = m_tokens.find(tokstr);
|
||||
if (id != m_tokens.end())
|
||||
return { id->second, tokstr };
|
||||
}
|
||||
ungetc(c);
|
||||
auto id = m_tokens.find(tokstr);
|
||||
return (id != m_tokens.end()) ?
|
||||
token_t(id->second, tokstr)
|
||||
: token_t(token_type::UNKNOWN, tokstr);
|
||||
c = getc();
|
||||
}
|
||||
ungetc(c);
|
||||
auto id = m_tokens.find(tokstr);
|
||||
return (id != m_tokens.end()) ?
|
||||
token_t(id->second, tokstr)
|
||||
: token_t(token_type::UNKNOWN, tokstr);
|
||||
}
|
||||
|
||||
token_reader_t::token_t tokenizer_t::get_token_comment()
|
||||
|
@ -17,15 +17,18 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#define PSTRINGIFY_HELP(y) # y
|
||||
#define PSTRINGIFY_HELP(y) #y
|
||||
#define PSTRINGIFY(x) PSTRINGIFY_HELP(x)
|
||||
|
||||
// Discussion and background of this MSVC bug: https://github.com/mamedev/mame/issues/6106
|
||||
// Discussion and background of this MSVC bug:
|
||||
// https://github.com/mamedev/mame/issues/6106
|
||||
///
|
||||
/// \brief Macro to work around a bug in MSVC treatment of __VA_ARGS__
|
||||
///
|
||||
#define PMSVC_VARARG_BUG(MACRO, ARGS) MACRO ARGS
|
||||
|
||||
// clang-format off
|
||||
|
||||
/// \brief Determine number of arguments in __VA_ARGS__
|
||||
///
|
||||
/// This macro works up to 16 arguments in __VA_ARGS__
|
||||
@ -70,13 +73,16 @@
|
||||
#define PSTRINGIFY_16(x, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, x10) \
|
||||
#x, #x2, #x3, #x4, #x5, #x6, #x7, #x8, #x9, #xa, #xb, #xc, #xd, #xe, #xf, #x10
|
||||
|
||||
// clang-format on
|
||||
|
||||
/// \brief Individually stringify up to 16 arguments
|
||||
///
|
||||
/// PSTRINGIFY_VA(a, b, c) will be expanded to "a", "b", "c"
|
||||
///
|
||||
/// \returns List of stringified individual arguments
|
||||
///
|
||||
#define PSTRINGIFY_VA(...) PMSVC_VARARG_BUG(PCONCAT, (PSTRINGIFY_, PNARGS(__VA_ARGS__)))(__VA_ARGS__)
|
||||
#define PSTRINGIFY_VA(...) \
|
||||
PMSVC_VARARG_BUG(PCONCAT, (PSTRINGIFY_, PNARGS(__VA_ARGS__)))(__VA_ARGS__)
|
||||
|
||||
/// \brief Dispatch VARARG macro to specialized macros
|
||||
///
|
||||
@ -93,7 +99,8 @@
|
||||
///
|
||||
/// \returns result of specialized macro
|
||||
///
|
||||
#define PCALLVARARG(MAC, ...) PMSVC_VARARG_BUG(PCONCAT, (MAC, PNARGS(__VA_ARGS__)))(__VA_ARGS__)
|
||||
#define PCALLVARARG(MAC, ...) \
|
||||
PMSVC_VARARG_BUG(PCONCAT, (MAC, PNARGS(__VA_ARGS__)))(__VA_ARGS__)
|
||||
|
||||
// FIXME:: __FUNCTION__ may be not be supported by all compilers.
|
||||
|
||||
@ -107,7 +114,7 @@ namespace plib
|
||||
pstring basename(const pstring &filename, const pstring &suffix = "");
|
||||
pstring path(const pstring &filename);
|
||||
bool exists(const pstring &filename);
|
||||
pstring build_path(std::initializer_list<pstring> list );
|
||||
pstring build_path(std::initializer_list<pstring> list);
|
||||
pstring environment(const pstring &var, const pstring &default_val);
|
||||
} // namespace util
|
||||
|
||||
@ -121,7 +128,7 @@ namespace plib
|
||||
|
||||
static constexpr const std::size_t npos = static_cast<std::size_t>(-1);
|
||||
template <class C>
|
||||
std::size_t indexof(C &con, const typename C::value_type &elem)
|
||||
std::size_t index_of(C &con, const typename C::value_type &elem)
|
||||
{
|
||||
auto it = std::find(con.begin(), con.end(), elem);
|
||||
if (it != con.end())
|
||||
@ -130,7 +137,8 @@ namespace plib
|
||||
}
|
||||
|
||||
template <class C>
|
||||
void insert_at(C &con, const std::size_t index, const typename C::value_type &elem)
|
||||
void insert_at(C &con, const std::size_t index,
|
||||
const typename C::value_type &elem)
|
||||
{
|
||||
con.insert(con.begin() + narrow_cast<std::ptrdiff_t>(index), elem);
|
||||
}
|
||||
@ -142,19 +150,72 @@ namespace plib
|
||||
}
|
||||
} // namespace container
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// simple hash
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
/// \brief Consistent hash implementation
|
||||
///
|
||||
/// Hash implementations in c++ standard libraries may differ and deliver
|
||||
/// different results. This hash can be used as a replacement hash in e.g.
|
||||
/// std::map to deliver consistent results.
|
||||
///
|
||||
/// \tparam V result type
|
||||
/// \tparam T buffer element type
|
||||
/// \param buf pointer to buffer for which hash should be calculated
|
||||
/// \param size number of buffer elements
|
||||
/// \return the hash of the buffer
|
||||
///
|
||||
template <typename V, typename T>
|
||||
constexpr V hash(const T *buf, std::size_t size) noexcept
|
||||
{
|
||||
V result = 5381; // NOLINT
|
||||
for (const T* p = buf; p != buf + size; p++)
|
||||
result = ((result << 5) + result ) ^ (result >> (32 - 5)) ^ narrow_cast<std::size_t>(*p); // NOLINT
|
||||
for (const T *p = buf; p != buf + size; p++)
|
||||
result = ((result << 5) + result) ^ (result >> (32 - 5))
|
||||
^ narrow_cast<std::size_t>(*p); // NOLINT
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \brief Execute code at end of block
|
||||
///
|
||||
/// The class can be used to execute code at the end of a block. It follows
|
||||
/// the same design as std::lock_guard.
|
||||
///
|
||||
/// Since the functor is executed in the destructor of the class the
|
||||
/// execution is protected by a try catch block. If an exception is raised,
|
||||
/// \ref plib::terminate is called.
|
||||
///
|
||||
/// \tparam F type of functor - will be derived by template deduction guide
|
||||
///
|
||||
template <typename F>
|
||||
struct functor_guard
|
||||
{
|
||||
/// \brief constructor
|
||||
///
|
||||
/// \param f functor to execute
|
||||
functor_guard(F &&f)
|
||||
: m_f(std::move(f))
|
||||
{
|
||||
}
|
||||
/// \brief destructor
|
||||
///
|
||||
~functor_guard()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_f();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
plib::terminate("exception raised in lambda_guard");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
F m_f;
|
||||
};
|
||||
|
||||
/// \brief template deduction guide
|
||||
///
|
||||
template <class F>
|
||||
functor_guard(F f) -> functor_guard<F>;
|
||||
|
||||
} // namespace plib
|
||||
|
||||
#endif // PUTIL_H_
|
||||
|
@ -50,7 +50,8 @@ namespace netlist::solver
|
||||
matrix_solver_t::matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
|
||||
const net_list_t &nets,
|
||||
const solver::solver_parameters_t *params)
|
||||
: device_t(static_cast<device_t &>(main_solver), name)
|
||||
//: device_t(static_cast<device_t &>(main_solver), name)
|
||||
: device_t(device_data_t{main_solver.state(), main_solver.name() + "." + name})
|
||||
, m_params(*params)
|
||||
, m_gonn(m_arena)
|
||||
, m_gtn(m_arena)
|
||||
@ -126,9 +127,9 @@ namespace netlist::solver
|
||||
if (!plib::container::contains(dynamic_devices, &p->device()))
|
||||
dynamic_devices.push_back(&p->device());
|
||||
{
|
||||
auto *pterm = dynamic_cast<terminal_t *>(p);
|
||||
nl_assert(pterm != nullptr);
|
||||
add_term(k, pterm);
|
||||
auto pterm = plib::dynamic_downcast<terminal_t *>(p);
|
||||
nl_assert_always(bool(pterm), "cast to terminal_t * failed");
|
||||
add_term(k, *pterm);
|
||||
}
|
||||
log().debug("Added terminal {1}\n", p->name());
|
||||
break;
|
||||
@ -145,8 +146,9 @@ namespace netlist::solver
|
||||
if (net_proxy_output == nullptr)
|
||||
{
|
||||
pstring new_name(this->name() + "." + pstring(plib::pfmt("m{1}")(m_inputs.size())));
|
||||
nl_assert_always(net.is_analog(), "Net is not an analog net");
|
||||
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, new_name, &dynamic_cast<analog_net_t &>(p->net()));
|
||||
auto proxied_net = plib::dynamic_downcast<analog_net_t *>(p->net());
|
||||
nl_assert_always(proxied_net, "Net is not an analog net");
|
||||
auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, new_name, *proxied_net);
|
||||
net_proxy_output = net_proxy_output_u.get();
|
||||
m_inputs.emplace_back(std::move(net_proxy_output_u));
|
||||
}
|
||||
@ -366,6 +368,8 @@ namespace netlist::solver
|
||||
}
|
||||
log().verbose("Number of multiplications/additions for {1}: {2}", name(), m_ops);
|
||||
|
||||
// Dumps non zero elements right of diagonal -> to much output, disabled
|
||||
// NOLINTNEXTLINE(readability-simplify-boolean-expr)
|
||||
if ((false))
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
{
|
||||
|
@ -320,8 +320,8 @@ namespace netlist::solver
|
||||
std::size_t max_rail_start() const noexcept
|
||||
{
|
||||
std::size_t max_rail = 0;
|
||||
for (std::size_t k = 0; k < m_terms.size(); k++)
|
||||
max_rail = std::max(max_rail, m_terms[k].rail_start());
|
||||
for (const auto &term : m_terms)
|
||||
max_rail = std::max(max_rail, term.rail_start());
|
||||
return max_rail;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace netlist::solver
|
||||
|
||||
// FIXME: Not yet working, mat_cr.h needs some more work
|
||||
#if 0
|
||||
auto mat_GE = dynamic_cast<plib::pGEmatrix_cr_t<typename M::base> *>(&mat);
|
||||
auto mat_GE = plib::dynamic_downcast<plib::pGEmatrix_cr_t<typename M::base> *>(&mat);
|
||||
#endif
|
||||
std::vector<unsigned> levL(iN, 0);
|
||||
std::vector<unsigned> levU(iN, 0);
|
||||
|
@ -327,7 +327,7 @@ namespace netlist::solver
|
||||
t.imbue(std::locale::classic());
|
||||
plib::putf8_fmt_writer w(&t);
|
||||
generate_code(w);
|
||||
//std::hash<typename std::remove_const<std::remove_reference<decltype(t.str())>::type>::type> h;
|
||||
//#std::hash<typename std::remove_const<std::remove_reference<decltype(t.str())>::type>::type> h;
|
||||
return plib::pfmt("nl_gcr_{1}_{2}_{3}_{4:x}")(mat.nz_num)(str_fptype)(str_floattype)(plib::hash<uint64_t>( t.str().c_str(), t.str().size() ));
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,10 @@
|
||||
// Names
|
||||
// spell-checker: words Woodbury,
|
||||
|
||||
#include "nl_factory.h"
|
||||
#include "core/setup.h"
|
||||
#include "nld_solver.h"
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nl_factory.h"
|
||||
#include "nl_setup.h" // FIXME: only needed for splitter code
|
||||
#include "nld_matrix_solver.h"
|
||||
#include "nld_ms_direct.h"
|
||||
@ -18,7 +19,9 @@
|
||||
#include "nld_ms_sor.h"
|
||||
#include "nld_ms_sor_mat.h"
|
||||
#include "nld_ms_w.h"
|
||||
#include "nld_solver.h"
|
||||
|
||||
#include "core/setup.h"
|
||||
|
||||
#include "plib/pomp.h"
|
||||
#include "plib/ptimed_queue.h"
|
||||
|
||||
@ -28,9 +31,27 @@
|
||||
namespace netlist::devices
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// solver
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
nld_solver::nld_solver(constructor_param_t data)
|
||||
: device_t(data)
|
||||
, m_fb_step(*this, "FB_step", NETLIB_DELEGATE(fb_step<false>))
|
||||
, m_Q_step(*this, "Q_step")
|
||||
, m_params(*this, "", solver::solver_parameter_defaults::get_instance())
|
||||
, m_queue(
|
||||
this->state().pool(), config::max_solver_queue_size(),
|
||||
queue_type::id_delegate(&NETLIB_NAME(solver)::get_solver_id, this),
|
||||
queue_type::obj_delegate(&NETLIB_NAME(solver)::solver_by_id, this))
|
||||
{
|
||||
// internal stuff
|
||||
state().save(*this,
|
||||
static_cast<plib::state_manager_t::callback_t &>(m_queue),
|
||||
this->name(), "m_queue");
|
||||
|
||||
connect("FB_step", "Q_step");
|
||||
}
|
||||
|
||||
NETLIB_RESET(solver)
|
||||
{
|
||||
@ -54,16 +75,28 @@ namespace netlist::devices
|
||||
NETLIB_HANDLER(solver, fb_step)
|
||||
{
|
||||
const netlist_time_ext now(exec().time());
|
||||
const std::size_t nthreads = m_params.m_parallel() < 2 ? 1 : std::min(static_cast<std::size_t>(m_params.m_parallel()), plib::omp::get_max_threads());
|
||||
const netlist_time_ext sched(now + (nthreads <= 1 ? netlist_time_ext::zero() : netlist_time_ext::from_nsec(100)));
|
||||
plib::uninitialised_array<solver::matrix_solver_t *, config::max_solver_queue_size::value> tmp; //NOLINT
|
||||
plib::uninitialised_array<netlist_time, config::max_solver_queue_size::value> nt; //NOLINT
|
||||
std::size_t p=0;
|
||||
const std::size_t nthreads = m_params.m_parallel() < 2
|
||||
? 1
|
||||
: std::min(
|
||||
static_cast<std::size_t>(
|
||||
m_params.m_parallel()),
|
||||
plib::omp::get_max_threads());
|
||||
const netlist_time_ext sched(
|
||||
now
|
||||
+ (nthreads <= 1 ? netlist_time_ext::zero()
|
||||
: netlist_time_ext::from_nsec(100)));
|
||||
plib::uninitialised_array<solver::matrix_solver_t *,
|
||||
config::max_solver_queue_size::value>
|
||||
tmp; // NOLINT
|
||||
plib::uninitialised_array<netlist_time,
|
||||
config::max_solver_queue_size::value>
|
||||
nt; // NOLINT
|
||||
std::size_t p = 0;
|
||||
|
||||
while (!m_queue.empty())
|
||||
{
|
||||
const auto t = m_queue.top().exec_time();
|
||||
auto *o = m_queue.top().object();
|
||||
auto * o = m_queue.top().object();
|
||||
if (t != now)
|
||||
if (t > sched)
|
||||
break;
|
||||
@ -71,14 +104,15 @@ namespace netlist::devices
|
||||
m_queue.pop();
|
||||
}
|
||||
|
||||
// FIXME: Disabled for now since parallel processing will decrease performance
|
||||
// FIXME: Disabled for now since parallel processing will decrease
|
||||
// performance
|
||||
// for tested applications. More testing required here
|
||||
if (true || nthreads < 2)
|
||||
{
|
||||
if (!KEEP_STATS)
|
||||
{
|
||||
for (std::size_t i = 0; i < p; i++)
|
||||
nt[i] = tmp[i]->solve(now, "no-parallel");
|
||||
nt[i] = tmp[i]->solve(now, "no-parallel");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -102,10 +136,9 @@ namespace netlist::devices
|
||||
else
|
||||
{
|
||||
plib::omp::set_num_threads(nthreads);
|
||||
plib::omp::for_static(static_cast<std::size_t>(0), p, [&tmp, &nt,now](std::size_t i)
|
||||
{
|
||||
nt[i] = tmp[i]->solve(now, "parallel");
|
||||
});
|
||||
plib::omp::for_static(static_cast<std::size_t>(0), p,
|
||||
[&tmp, &nt, now](std::size_t i)
|
||||
{ nt[i] = tmp[i]->solve(now, "parallel"); });
|
||||
for (std::size_t i = 0; i < p; i++)
|
||||
{
|
||||
if (nt[i] != netlist_time::zero())
|
||||
@ -114,10 +147,12 @@ namespace netlist::devices
|
||||
}
|
||||
}
|
||||
if (!m_queue.empty())
|
||||
m_Q_step.net().toggle_and_push_to_queue(static_cast<netlist_time>(m_queue.top().exec_time() - now));
|
||||
m_Q_step.net().toggle_and_push_to_queue(
|
||||
static_cast<netlist_time>(m_queue.top().exec_time() - now));
|
||||
}
|
||||
|
||||
void NETLIB_NAME(solver) :: reschedule(solver::matrix_solver_t *solv, netlist_time ts)
|
||||
void NETLIB_NAME(solver)::reschedule(solver::matrix_solver_t *solv,
|
||||
netlist_time ts)
|
||||
{
|
||||
const netlist_time_ext now(exec().time());
|
||||
const netlist_time_ext sched(now + ts);
|
||||
@ -141,78 +176,101 @@ namespace netlist::devices
|
||||
netlist_time_ext 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_ext::from_fp<decltype(m_params.m_max_time_step)>(2 * m_params.m_max_time_step));
|
||||
bool force_solve = (now < netlist_time_ext::from_fp<
|
||||
decltype(m_params.m_max_time_step)>(
|
||||
2 * m_params.m_max_time_step));
|
||||
|
||||
std::size_t nthreads = std::min(static_cast<std::size_t>(m_params.m_parallel()), plib::omp::get_max_threads());
|
||||
std::size_t nthreads = std::min(
|
||||
static_cast<std::size_t>(m_params.m_parallel()),
|
||||
plib::omp::get_max_threads());
|
||||
|
||||
std::vector<solver_entry *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_time_stepping);
|
||||
std::vector<solver_entry *>
|
||||
&solvers = (force_solve ? m_mat_solvers_all
|
||||
: m_mat_solvers_time_stepping);
|
||||
|
||||
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)
|
||||
{
|
||||
[[maybe_unused]] const netlist_time ts = solvers[i]->ptr->solve(now);
|
||||
plib::omp::for_static(
|
||||
static_cast<std::size_t>(0), solvers.size(),
|
||||
[&solvers, now](std::size_t i) {
|
||||
[[maybe_unused]] const netlist_time ts = solvers[i]
|
||||
->ptr->solve(
|
||||
now);
|
||||
});
|
||||
}
|
||||
else
|
||||
for (auto & solver : solvers)
|
||||
for (auto &solver : solvers)
|
||||
{
|
||||
[[maybe_unused]] const netlist_time ts = solver->ptr->solve(now);
|
||||
[[maybe_unused]] const netlist_time ts = solver->ptr->solve(
|
||||
now);
|
||||
}
|
||||
|
||||
for (auto & solver : solvers)
|
||||
for (auto &solver : solvers)
|
||||
solver->ptr->update_inputs();
|
||||
|
||||
// step circuit
|
||||
if (!m_Q_step.net().is_queued())
|
||||
{
|
||||
m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_max_time_step));
|
||||
m_Q_step.net().toggle_and_push_to_queue(
|
||||
netlist_time::from_fp(m_params.m_max_time_step));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// FIXME: should be created in device space
|
||||
template <class C, class A>
|
||||
NETLIB_NAME(solver)::solver_ptr create_it(A &arena, NETLIB_NAME(solver) &main_solver, pstring name,
|
||||
NETLIB_NAME(solver)::net_list_t &nets,
|
||||
const solver::solver_parameters_t *params, std::size_t size)
|
||||
NETLIB_NAME(solver)::solver_ptr
|
||||
create_it(A &arena, NETLIB_NAME(solver) &main_solver, pstring name,
|
||||
NETLIB_NAME(solver)::net_list_t & nets,
|
||||
const solver::solver_parameters_t *params, std::size_t size)
|
||||
{
|
||||
return plib::make_unique<C>(arena, main_solver, name, nets, params, size);
|
||||
return plib::make_unique<C>(arena, main_solver, name, nets, params,
|
||||
size);
|
||||
}
|
||||
|
||||
template <typename FT, int SIZE>
|
||||
NETLIB_NAME(solver)::solver_ptr NETLIB_NAME(solver)::create_solver(std::size_t size,
|
||||
const pstring &solver_name, const solver::solver_parameters_t *params,
|
||||
NETLIB_NAME(solver)::net_list_t &nets)
|
||||
NETLIB_NAME(solver)::solver_ptr NETLIB_NAME(solver)::create_solver(
|
||||
std::size_t size, const pstring &solver_name,
|
||||
const solver::solver_parameters_t *params,
|
||||
NETLIB_NAME(solver)::net_list_t & nets)
|
||||
{
|
||||
switch (params->m_method())
|
||||
{
|
||||
case solver::matrix_type_e::MAT_CR:
|
||||
return create_it<solver::matrix_solver_GCR_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_GCR_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
case solver::matrix_type_e::MAT:
|
||||
return create_it<solver::matrix_solver_direct_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_direct_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
case solver::matrix_type_e::GMRES:
|
||||
return create_it<solver::matrix_solver_GMRES_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_GMRES_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
#if (NL_USE_ACADEMIC_SOLVERS)
|
||||
case solver::matrix_type_e::SOR:
|
||||
return create_it<solver::matrix_solver_SOR_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_SOR_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
case solver::matrix_type_e::SOR_MAT:
|
||||
return create_it<solver::matrix_solver_SOR_mat_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_SOR_mat_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
case solver::matrix_type_e::SM:
|
||||
// Sherman-Morrison Formula
|
||||
return create_it<solver::matrix_solver_sm_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_sm_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
case solver::matrix_type_e::W:
|
||||
// Woodbury Formula
|
||||
return create_it<solver::matrix_solver_w_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
return create_it<solver::matrix_solver_w_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
#else
|
||||
//case solver::matrix_type_e::GMRES:
|
||||
// case solver::matrix_type_e::GMRES:
|
||||
case solver::matrix_type_e::SOR:
|
||||
case solver::matrix_type_e::SOR_MAT:
|
||||
case solver::matrix_type_e::SM:
|
||||
case solver::matrix_type_e::W:
|
||||
state().log().warning(MW_SOLVER_METHOD_NOT_SUPPORTED(params->m_method().name(), "MAT_CR"));
|
||||
return create_it<solver::matrix_solver_GCR_t<FT, SIZE>>(state().pool(), *this, solver_name, nets, params, size);
|
||||
state().log().warning(MW_SOLVER_METHOD_NOT_SUPPORTED(
|
||||
params->m_method().name(), "MAT_CR"));
|
||||
return create_it<solver::matrix_solver_GCR_t<FT, SIZE>>(
|
||||
state().pool(), *this, solver_name, nets, params, size);
|
||||
#endif
|
||||
}
|
||||
return solver_ptr();
|
||||
@ -228,47 +286,49 @@ namespace netlist::devices
|
||||
{
|
||||
#if !defined(__EMSCRIPTEN__)
|
||||
case 1:
|
||||
return plib::make_unique<solver::matrix_solver_direct1_t<FT>>(state().pool(), *this, sname, nets, params);
|
||||
return plib::make_unique<solver::matrix_solver_direct1_t<FT>>(
|
||||
state().pool(), *this, sname, nets, params);
|
||||
case 2:
|
||||
return plib::make_unique<solver::matrix_solver_direct2_t<FT>>(state().pool(), *this, sname, nets, params);
|
||||
case 3:
|
||||
return create_solver<FT, 3>(3, sname, params, nets);
|
||||
case 4:
|
||||
return create_solver<FT, 4>(4, sname, params, nets);
|
||||
case 5:
|
||||
return create_solver<FT, 5>(5, sname, params, nets);
|
||||
case 6:
|
||||
return create_solver<FT, 6>(6, sname, params, nets);
|
||||
case 7:
|
||||
return create_solver<FT, 7>(7, sname, params, nets);
|
||||
case 8:
|
||||
return create_solver<FT, 8>(8, sname, params, nets);
|
||||
return plib::make_unique<solver::matrix_solver_direct2_t<FT>>(
|
||||
state().pool(), *this, sname, nets, params);
|
||||
case 3: return create_solver<FT, 3>(3, sname, params, nets);
|
||||
case 4: return create_solver<FT, 4>(4, sname, params, nets);
|
||||
case 5: return create_solver<FT, 5>(5, sname, params, nets);
|
||||
case 6: return create_solver<FT, 6>(6, sname, params, nets);
|
||||
case 7: return create_solver<FT, 7>(7, sname, params, nets);
|
||||
case 8: return create_solver<FT, 8>(8, sname, params, nets);
|
||||
#endif
|
||||
default:
|
||||
log().info(MI_NO_SPECIFIC_SOLVER(net_count));
|
||||
if (net_count <= 16)
|
||||
{
|
||||
return create_solver<FT, -16>(net_count, sname, params, nets);
|
||||
return create_solver<FT, -16>(net_count, sname, params,
|
||||
nets);
|
||||
}
|
||||
if (net_count <= 32)
|
||||
{
|
||||
return create_solver<FT, -32>(net_count, sname, params, nets);
|
||||
return create_solver<FT, -32>(net_count, sname, params,
|
||||
nets);
|
||||
}
|
||||
if (net_count <= 64)
|
||||
{
|
||||
return create_solver<FT, -64>(net_count, sname, params, nets);
|
||||
return create_solver<FT, -64>(net_count, sname, params,
|
||||
nets);
|
||||
}
|
||||
if (net_count <= 128)
|
||||
{
|
||||
return create_solver<FT, -128>(net_count, sname, params, nets);
|
||||
return create_solver<FT, -128>(net_count, sname, params,
|
||||
nets);
|
||||
}
|
||||
if (net_count <= 256)
|
||||
{
|
||||
return create_solver<FT, -256>(net_count, sname, params, nets);
|
||||
return create_solver<FT, -256>(net_count, sname, params,
|
||||
nets);
|
||||
}
|
||||
if (net_count <= 512)
|
||||
{
|
||||
return create_solver<FT, -512>(net_count, sname, params, nets);
|
||||
return create_solver<FT, -512>(net_count, sname, params,
|
||||
nets);
|
||||
}
|
||||
return create_solver<FT, 0>(net_count, sname, params, nets);
|
||||
}
|
||||
@ -278,18 +338,21 @@ namespace netlist::devices
|
||||
{
|
||||
void run(netlist_state_t &nl_state)
|
||||
{
|
||||
for (auto & net : nl_state.nets())
|
||||
for (auto &net : nl_state.nets())
|
||||
{
|
||||
nl_state.log().verbose("processing {1}", net->name());
|
||||
if (!net->is_rail_net() && !net->core_terms_empty())
|
||||
{
|
||||
nl_state.log().verbose(" ==> not a rail net");
|
||||
// Must be an analog net
|
||||
auto &n = dynamic_cast<analog_net_t &>(*net);
|
||||
if (!already_processed(n))
|
||||
auto n = plib::dynamic_downcast<analog_net_t *>(net.get());
|
||||
nl_assert_always(bool(n),
|
||||
"Unable to cast to analog_net_t &");
|
||||
if (!already_processed(*(*n)))
|
||||
{
|
||||
groupspre.emplace_back(NETLIB_NAME(solver)::net_list_t());
|
||||
process_net(nl_state, n);
|
||||
groupspre.emplace_back(
|
||||
NETLIB_NAME(solver)::net_list_t());
|
||||
process_net(nl_state, *(*n));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,14 +364,13 @@ namespace netlist::devices
|
||||
std::vector<NETLIB_NAME(solver)::net_list_t> groups;
|
||||
|
||||
private:
|
||||
|
||||
bool already_processed(const analog_net_t &n) const
|
||||
{
|
||||
// no need to process rail nets - these are known variables
|
||||
if (n.is_rail_net())
|
||||
return true;
|
||||
// if it's already processed - no need to continue
|
||||
for (const auto & grp : groups)
|
||||
for (const auto &grp : groups)
|
||||
if (plib::container::contains(grp, &n))
|
||||
return true;
|
||||
return false;
|
||||
@ -323,12 +385,13 @@ namespace netlist::devices
|
||||
// In this case we need to merge this group into the current group
|
||||
if (groupspre.size() > 1)
|
||||
{
|
||||
for (std::size_t i = 0; i<groupspre.size() - 1; i++)
|
||||
for (std::size_t i = 0; i < groupspre.size() - 1; i++)
|
||||
if (plib::container::contains(groupspre[i], &n))
|
||||
{
|
||||
// copy all nets
|
||||
for (auto & cn : groupspre[i])
|
||||
if (!plib::container::contains(groupspre.back(), cn))
|
||||
for (auto &cn : groupspre[i])
|
||||
if (!plib::container::contains(groupspre.back(),
|
||||
cn))
|
||||
groupspre.back().push_back(cn);
|
||||
// clear
|
||||
groupspre[i].clear();
|
||||
@ -336,7 +399,8 @@ namespace netlist::devices
|
||||
}
|
||||
}
|
||||
// if it's already processed - no need to continue
|
||||
if (!groupspre.empty() && plib::container::contains(groupspre.back(), &n))
|
||||
if (!groupspre.empty()
|
||||
&& plib::container::contains(groupspre.back(), &n))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -353,20 +417,26 @@ namespace netlist::devices
|
||||
// add the net
|
||||
groupspre.back().push_back(&n);
|
||||
// process all terminals connected to this net
|
||||
for (detail::core_terminal_t * term : terminals)
|
||||
for (detail::core_terminal_t *term : terminals)
|
||||
{
|
||||
nl_state.log().verbose("Term {} {}", term->name(), static_cast<int>(term->type()));
|
||||
nl_state.log().verbose("Term {} {}", term->name(),
|
||||
static_cast<int>(term->type()));
|
||||
// only process analog terminals
|
||||
if (term->is_type(detail::terminal_type::TERMINAL))
|
||||
{
|
||||
auto &pt = dynamic_cast<terminal_t &>(*term);
|
||||
auto pt = plib::dynamic_downcast<terminal_t *>(term);
|
||||
nl_assert_always(bool(pt),
|
||||
"Error casting *term to terminal_t &");
|
||||
// check the connected terminal
|
||||
const auto *const connected_terminals = nl_state.setup().get_connected_terminals(pt);
|
||||
const auto *const connected_terminals
|
||||
= nl_state.setup().get_connected_terminals(*(*pt));
|
||||
// NOLINTNEXTLINE proposal does not work for VS
|
||||
for (auto ct = connected_terminals->begin(); *ct != nullptr; ct++)
|
||||
for (auto ct = connected_terminals->begin();
|
||||
*ct != nullptr; ct++)
|
||||
{
|
||||
analog_net_t &connected_net = (*ct)->net();
|
||||
nl_state.log().verbose(" Connected net {}", connected_net.name());
|
||||
nl_state.log().verbose(" Connected net {}",
|
||||
connected_net.name());
|
||||
if (!check_if_processed_and_join(connected_net))
|
||||
process_net(nl_state, connected_net);
|
||||
}
|
||||
@ -386,40 +456,48 @@ namespace netlist::devices
|
||||
net_splitter splitter;
|
||||
|
||||
splitter.run(state());
|
||||
log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size());
|
||||
log().verbose("Found {1} net groups in {2} nets\n",
|
||||
splitter.groups.size(), state().nets().size());
|
||||
|
||||
int num_errors = 0;
|
||||
|
||||
log().verbose("checking net consistency ...");
|
||||
for (const auto &grp : splitter.groups)
|
||||
{
|
||||
int rail_terminals = 0;
|
||||
int rail_terminals = 0;
|
||||
pstring nets_in_grp;
|
||||
for (const auto &n : grp)
|
||||
{
|
||||
nets_in_grp += (n->name() + " ");
|
||||
if (!n->is_analog())
|
||||
{
|
||||
state().log().error(ME_SOLVER_CONSISTENCY_NOT_ANALOG_NET(n->name()));
|
||||
state().log().error(
|
||||
ME_SOLVER_CONSISTENCY_NOT_ANALOG_NET(n->name()));
|
||||
num_errors++;
|
||||
}
|
||||
if (n->is_rail_net())
|
||||
{
|
||||
state().log().error(ME_SOLVER_CONSISTENCY_RAIL_NET(n->name()));
|
||||
state().log().error(
|
||||
ME_SOLVER_CONSISTENCY_RAIL_NET(n->name()));
|
||||
num_errors++;
|
||||
}
|
||||
for (detail::core_terminal_t * t : n->core_terms_copy())
|
||||
for (detail::core_terminal_t *t : n->core_terms_copy())
|
||||
{
|
||||
if (!t->has_net())
|
||||
{
|
||||
state().log().error(ME_SOLVER_TERMINAL_NO_NET(t->name()));
|
||||
state().log().error(
|
||||
ME_SOLVER_TERMINAL_NO_NET(t->name()));
|
||||
num_errors++;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto *other_terminal = dynamic_cast<terminal_t *>(t);
|
||||
if (other_terminal != nullptr)
|
||||
if (state().setup().get_connected_terminal(*other_terminal)->net().is_rail_net())
|
||||
if (auto other_terminal = plib::dynamic_downcast<
|
||||
terminal_t *>(t))
|
||||
if (state()
|
||||
.setup()
|
||||
.get_connected_terminal(*(*other_terminal))
|
||||
->net()
|
||||
.is_rail_net())
|
||||
rail_terminals++;
|
||||
}
|
||||
}
|
||||
@ -433,43 +511,56 @@ namespace netlist::devices
|
||||
if (num_errors > 0)
|
||||
throw nl_exception(MF_SOLVER_CONSISTENCY_ERRORS(num_errors));
|
||||
|
||||
|
||||
// setup the solvers
|
||||
for (auto & grp : splitter.groups)
|
||||
for (auto &grp : splitter.groups)
|
||||
{
|
||||
solver_ptr ms;
|
||||
pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size());
|
||||
params_uptr params = plib::make_unique<solver::solver_parameters_t>(state().pool(), *this, sname + ".", m_params);
|
||||
solver_ptr ms;
|
||||
pstring sname = plib::pfmt("Solver_{1}")(m_mat_solvers.size());
|
||||
params_uptr params = plib::make_unique<solver::solver_parameters_t>(
|
||||
state().pool(), *this, sname + ".", m_params);
|
||||
|
||||
switch (params->m_fp_type())
|
||||
{
|
||||
case solver::matrix_fp_type_e::FLOAT:
|
||||
if (!config::use_float_matrix::value)
|
||||
log().info("FPTYPE {1} not supported. Using DOUBLE", params->m_fp_type().name());
|
||||
ms = create_solvers<std::conditional_t<config::use_float_matrix::value, float, double>>(sname, params.get(), grp);
|
||||
log().info("FPTYPE {1} not supported. Using DOUBLE",
|
||||
params->m_fp_type().name());
|
||||
ms = create_solvers<std::conditional_t<
|
||||
config::use_float_matrix::value, float, double>>(
|
||||
sname, params.get(), grp);
|
||||
break;
|
||||
case solver::matrix_fp_type_e::DOUBLE:
|
||||
ms = create_solvers<double>(sname, params.get(), grp);
|
||||
break;
|
||||
case solver::matrix_fp_type_e::LONGDOUBLE:
|
||||
if (!config::use_long_double_matrix::value)
|
||||
log().info("FPTYPE {1} not supported. Using DOUBLE", params->m_fp_type().name());
|
||||
ms = create_solvers<std::conditional_t<config::use_long_double_matrix::value, long double, double>>(sname, params.get(), grp);
|
||||
log().info("FPTYPE {1} not supported. Using DOUBLE",
|
||||
params->m_fp_type().name());
|
||||
ms = create_solvers<std::conditional_t<
|
||||
config::use_long_double_matrix::value, long double,
|
||||
double>>(sname, params.get(), grp);
|
||||
break;
|
||||
case solver::matrix_fp_type_e::FLOATQ128:
|
||||
#if (NL_USE_FLOAT128)
|
||||
ms = create_solvers<FLOAT128>(sname, params.get(), grp);
|
||||
#else
|
||||
log().info("FPTYPE {1} not supported. Using DOUBLE", params->m_fp_type().name());
|
||||
log().info("FPTYPE {1} not supported. Using DOUBLE",
|
||||
params->m_fp_type().name());
|
||||
ms = create_solvers<double>(sname, params.get(), grp);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
state().register_device(
|
||||
ms->name(),
|
||||
device_arena::owned_ptr<core_device_t>(ms.get(), false));
|
||||
|
||||
log().verbose("Solver {1}", ms->name());
|
||||
log().verbose(" ==> {1} nets", grp.size());
|
||||
log().verbose(" has {1} dynamic elements", ms->dynamic_device_count());
|
||||
log().verbose(" has {1} time step elements", ms->time_step_device_count());
|
||||
log().verbose(" has {1} dynamic elements",
|
||||
ms->dynamic_device_count());
|
||||
log().verbose(" has {1} time step elements",
|
||||
ms->time_step_device_count());
|
||||
for (auto &n : grp)
|
||||
{
|
||||
log().verbose("Net {1}", n->name());
|
||||
@ -482,35 +573,37 @@ namespace netlist::devices
|
||||
m_mat_params.push_back(std::move(params));
|
||||
m_mat_solvers.push_back(std::move(ms));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
solver::static_compile_container NETLIB_NAME(solver)::create_solver_code(solver::static_compile_target target)
|
||||
solver::static_compile_container NETLIB_NAME(solver)::create_solver_code(
|
||||
solver::static_compile_target target)
|
||||
{
|
||||
solver::static_compile_container mp;
|
||||
for (auto & s : m_mat_solvers)
|
||||
for (auto &s : m_mat_solvers)
|
||||
{
|
||||
auto r = s->create_solver_code(target);
|
||||
if (!r.first.empty()) // ignore solvers not supporting static compile
|
||||
if (!r.first.empty()) // ignore solvers not supporting static
|
||||
// compile
|
||||
mp.push_back(r);
|
||||
}
|
||||
return mp;
|
||||
}
|
||||
|
||||
std::size_t NETLIB_NAME(solver)::get_solver_id(const solver::matrix_solver_t *net) const
|
||||
std::size_t NETLIB_NAME(solver)::get_solver_id(
|
||||
const solver::matrix_solver_t *net) const
|
||||
{
|
||||
for (std::size_t i=0; i < m_mat_solvers.size(); i++)
|
||||
for (std::size_t i = 0; i < m_mat_solvers.size(); i++)
|
||||
if (m_mat_solvers[i].get() == net)
|
||||
return i;
|
||||
return std::numeric_limits<std::size_t>::max();
|
||||
}
|
||||
|
||||
solver::matrix_solver_t * NETLIB_NAME(solver)::solver_by_id(std::size_t id) const
|
||||
solver::matrix_solver_t *NETLIB_NAME(solver)::solver_by_id(
|
||||
std::size_t id) const
|
||||
{
|
||||
return m_mat_solvers[id].get();
|
||||
}
|
||||
|
||||
|
||||
NETLIB_DEVICE_IMPL(solver, "SOLVER", "FREQ")
|
||||
|
||||
} // namespace netlist::devices
|
||||
|
@ -8,49 +8,43 @@
|
||||
/// \file nld_solver.h
|
||||
///
|
||||
|
||||
#include "../plib/pstream.h"
|
||||
#include "nld_matrix_solver.h"
|
||||
|
||||
#include "core/core_device.h"
|
||||
#include "core/logic.h"
|
||||
#include "core/state_var.h"
|
||||
#include "nld_matrix_solver.h"
|
||||
|
||||
#include "../plib/pstream.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// solver
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
namespace netlist::devices
|
||||
{
|
||||
NETLIB_OBJECT(solver)
|
||||
// -------------------------------------------------------------------------
|
||||
// solver
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
class nld_solver : public device_t
|
||||
{
|
||||
public:
|
||||
using solver_arena = device_arena;
|
||||
using queue_type = detail::queue_base<solver_arena, solver::matrix_solver_t>;
|
||||
using queue_type = detail::queue_base<solver_arena,
|
||||
solver::matrix_solver_t>;
|
||||
|
||||
NETLIB_CONSTRUCTOR(solver)
|
||||
, m_fb_step(*this, "FB_step", NETLIB_DELEGATE(fb_step<false>))
|
||||
, m_Q_step(*this, "Q_step")
|
||||
, m_params(*this, "", solver::solver_parameter_defaults::get_instance())
|
||||
, m_queue(this->state().pool(), config::max_solver_queue_size(),
|
||||
queue_type::id_delegate(&NETLIB_NAME(solver) :: get_solver_id, this),
|
||||
queue_type::obj_delegate(&NETLIB_NAME(solver) :: solver_by_id, this))
|
||||
{
|
||||
// internal stuff
|
||||
state().save(*this, static_cast<plib::state_manager_t::callback_t &>(m_queue), this->name(), "m_queue");
|
||||
|
||||
connect("FB_step", "Q_step");
|
||||
}
|
||||
nld_solver(constructor_param_t data);
|
||||
|
||||
void post_start();
|
||||
void stop();
|
||||
|
||||
auto gmin() const -> decltype(solver::solver_parameters_t::m_gmin()) { return m_params.m_gmin(); }
|
||||
auto gmin() const -> decltype(solver::solver_parameters_t::m_gmin())
|
||||
{
|
||||
return m_params.m_gmin();
|
||||
}
|
||||
|
||||
solver::static_compile_container create_solver_code(solver::static_compile_target target);
|
||||
solver::static_compile_container
|
||||
create_solver_code(solver::static_compile_target target);
|
||||
|
||||
NETLIB_RESETI();
|
||||
// NETLIB_UPDATE_PARAMI();
|
||||
@ -62,32 +56,34 @@ namespace netlist::devices
|
||||
void reschedule(solver::matrix_solver_t *solv, netlist_time ts);
|
||||
|
||||
private:
|
||||
using params_uptr = solver_arena::unique_ptr<solver::solver_parameters_t>;
|
||||
using params_uptr = solver_arena::unique_ptr<
|
||||
solver::solver_parameters_t>;
|
||||
|
||||
template<bool KEEP_STATS>
|
||||
template <bool KEEP_STATS>
|
||||
NETLIB_HANDLERI(fb_step);
|
||||
|
||||
logic_input_t m_fb_step;
|
||||
logic_input_t m_fb_step;
|
||||
logic_output_t m_Q_step;
|
||||
|
||||
// FIXME: these should be created in device space
|
||||
std::vector<params_uptr> m_mat_params;
|
||||
std::vector<solver_ptr> m_mat_solvers;
|
||||
std::vector<solver_ptr> m_mat_solvers;
|
||||
|
||||
solver::solver_parameters_t m_params;
|
||||
queue_type m_queue;
|
||||
queue_type m_queue;
|
||||
|
||||
template <typename FT, int SIZE>
|
||||
solver_ptr create_solver(std::size_t size, const pstring &solver_name,
|
||||
const solver::solver_parameters_t *params,net_list_t &nets);
|
||||
const solver::solver_parameters_t *params,
|
||||
net_list_t & nets);
|
||||
|
||||
template <typename FT>
|
||||
solver_ptr create_solvers(const pstring &sname,
|
||||
const solver::solver_parameters_t *params, net_list_t &nets);
|
||||
solver_ptr create_solvers(const pstring & sname,
|
||||
const solver::solver_parameters_t *params,
|
||||
net_list_t & nets);
|
||||
|
||||
std::size_t get_solver_id(const solver::matrix_solver_t *net) const;
|
||||
solver::matrix_solver_t *solver_by_id(std::size_t id) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace netlist::devices
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
|
||||
#if 0
|
||||
namespace plib
|
||||
@ -166,6 +167,58 @@ operator == (const E &lhs, const char * rhs)
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
template <typename T>
|
||||
struct ret_t
|
||||
{
|
||||
bool success;
|
||||
T value;
|
||||
};
|
||||
|
||||
template <typename T, T BASE>
|
||||
constexpr ret_t<T> stl_h(std::string_view sv)
|
||||
{
|
||||
T r(0);
|
||||
for (const auto &c : sv)
|
||||
{
|
||||
if (c >= '0' && c < '0' + std::min(10,BASE))
|
||||
{
|
||||
r = r * BASE + (c - '0');
|
||||
}
|
||||
else if (c >= 'A' && c < ('A' + BASE - 10))
|
||||
{
|
||||
r = r * BASE + (10 + c - 'A');
|
||||
}
|
||||
else if (c >= 'a' && c < ('a' + BASE - 10))
|
||||
{
|
||||
r = r * BASE + (10 + c - 'a');
|
||||
}
|
||||
else
|
||||
return { false, T(0) };
|
||||
}
|
||||
return { true, r };
|
||||
}
|
||||
|
||||
template <typename T, T BASE = 0>
|
||||
constexpr ret_t<T> stl(std::string_view sv)
|
||||
{
|
||||
if constexpr (BASE == 0)
|
||||
{
|
||||
if (sv.size() > 2)
|
||||
{
|
||||
if (sv.substr(0,2) == "0x" || sv.substr(0,2) == "0X")
|
||||
return stl_h<T,16>(sv.substr(2));
|
||||
if (sv.substr(0,2) == "0b")
|
||||
return stl_h<T,2>(sv.substr(2));
|
||||
}
|
||||
if (sv.size() > 1 && sv.substr(0,1) == "0" )
|
||||
return stl_h<T,8>(sv.substr(1));
|
||||
return stl_h<T, 10>(sv);
|
||||
}
|
||||
return stl_h<T, BASE>(sv);
|
||||
}
|
||||
|
||||
#include "plib/ptests.h"
|
||||
|
||||
//PENUM_NS(plibx, teste, A, B, C)
|
||||
@ -179,6 +232,12 @@ PENUM(testf, A, B, C)
|
||||
|
||||
PTEST(penum, conversion)
|
||||
{
|
||||
static_assert(stl<int,0>("0xa0bc").success,"no");
|
||||
static_assert(stl<int,0>("0xa0bc").value==0xa0bc,"no");
|
||||
static_assert(stl<int,0>("0b1010").value==0b1010,"no");
|
||||
static_assert(stl<int,0>("0123").value==0123,"no");
|
||||
//const auto x(stl<int,0>("123"));
|
||||
//static_assert(x.value==123,"no");
|
||||
|
||||
plibx::teste x = plib::functor<plibx::teste>("A");
|
||||
PEXPECT_NE(x, plibx::teste::B);
|
||||
|
@ -7,10 +7,10 @@
|
||||
/// tests for `plib::pmfp`
|
||||
///
|
||||
|
||||
#include "plib/pconfig.h"
|
||||
#include "plib/ppmf.h"
|
||||
#include "netlist/nl_config.h"
|
||||
|
||||
#include "plib/pconfig.h"
|
||||
#include "plib/ppmf.h"
|
||||
#include "plib/ptests.h"
|
||||
|
||||
PTEST(test_precommit, precommit)
|
||||
|
Loading…
Reference in New Issue
Block a user