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:
couriersud 2022-06-20 20:01:03 +02:00 committed by GitHub
parent 3fbfe0b1d7
commit 0dad442511
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 3667 additions and 2900 deletions

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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); });
}
}

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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

View 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.+'

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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;
};

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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_

View File

@ -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 &param) noexcept { set_and_update_param(m_param, param); }
void set(const T &param) 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 &param) noexcept { set_and_update_param(m_param, param); }
constexpr operator T() const noexcept { return m_param; }
void set(const T &param) 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 &param)
void set(const pstring &param)
{
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 &param, 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 &param, 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 &param) = 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_

View File

@ -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_

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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", "")

View File

@ -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;

View File

@ -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", "")

View File

@ -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")

View File

@ -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);

View File

@ -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

View File

@ -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")

View File

@ -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;

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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()));

View File

@ -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;

View File

@ -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);
}
};

View File

@ -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")

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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 "

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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();
}

View File

@ -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

View File

@ -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> &params_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)
{

View File

@ -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_

View File

@ -20,7 +20,7 @@ namespace plib {
// terminate
//============================================================
void terminate(const char *msg) noexcept
[[noreturn]] void terminate(const char *msg) noexcept
{
try
{

View File

@ -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)

View File

@ -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('.'));

View File

@ -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)...));
}
}

View File

@ -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));
}

View File

@ -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

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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(&params);
})).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++;
}

View File

@ -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()

View File

@ -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_

View File

@ -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++)
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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() ));
}

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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)