summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/nl_base.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/nl_base.cpp')
-rw-r--r--src/lib/netlist/nl_base.cpp1834
1 files changed, 975 insertions, 859 deletions
diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp
index 851c7b8059f..ddb4f1bca6a 100644
--- a/src/lib/netlist/nl_base.cpp
+++ b/src/lib/netlist/nl_base.cpp
@@ -1,1083 +1,1199 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
-/*
- * nlbase.c
- *
- */
+
+#include "nl_errstr.h"
+
+#include "core/devices.h"
+#include "core/logic.h"
+#include "core/setup.h"
+
+#include "devices/nlid_proxy.h"
#include "solver/nld_matrix_solver.h"
#include "solver/nld_solver.h"
#include "plib/palloc.h"
+#include "plib/pdynlib.h"
+#include "plib/pfmtlog.h"
#include "plib/pmempool.h"
#include "plib/putil.h"
-#include "devices/nlid_proxy.h"
-#include "devices/nlid_system.h"
-#include "macro/nlm_base.h"
-#include "nl_base.h"
-
-#include "nl_errstr.h"
-
-#include <cmath>
-//#include <cstring>
#include <limits>
-namespace netlist
-{
-
-// ----------------------------------------------------------------------------------------
-// logic_family_ttl_t
-// ----------------------------------------------------------------------------------------
-
-// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, modernize-use-equals-default)
-logic_family_desc_t::logic_family_desc_t()
-{
-}
-
-class logic_family_ttl_t : public logic_family_desc_t
-{
-public:
- logic_family_ttl_t() : logic_family_desc_t()
- {
- m_fixed_V = 5.0;
- m_low_thresh_PCNT = 0.8 / 5.0;
- m_high_thresh_PCNT = 2.0 / 5.0;
- // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
- m_low_VO = 0.1;
- m_high_VO = 1.0; // 4.0
- m_R_low = 1.0;
- m_R_high = 130.0;
- }
- pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
- pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
-};
-
-pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_ttl_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const
-{
- return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
-}
-pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_ttl_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
-{
- return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
-}
-
-class logic_family_cd4xxx_t : public logic_family_desc_t
-{
-public:
- logic_family_cd4xxx_t() : logic_family_desc_t()
- {
- m_fixed_V = 0.0;
- m_low_thresh_PCNT = 1.5 / 5.0;
- m_high_thresh_PCNT = 3.5 / 5.0;
- // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
- m_low_VO = 0.05;
- m_high_VO = 0.05; // 4.95
- m_R_low = 10.0;
- m_R_high = 10.0;
- }
- pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
- pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
-};
-
-pool_owned_ptr<devices::nld_base_d_to_a_proxy> logic_family_cd4xxx_t::create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const
-{
- return pool().make_poolptr<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
-}
-
-pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_cd4xxx_t::create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const
-{
- return pool().make_poolptr<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
-}
+NETLIST_EXTERNAL(base_lib)
-const logic_family_desc_t *family_TTL()
-{
- static logic_family_ttl_t obj;
- return &obj;
-}
-const logic_family_desc_t *family_CD4XXX()
+namespace netlist
{
- static logic_family_cd4xxx_t obj;
- return &obj;
-}
+ // -------------------------------------------------------------------------
+ // detail::core_terminal_t
+ // -------------------------------------------------------------------------
-// ----------------------------------------------------------------------------------------
-// queue_t
-// ----------------------------------------------------------------------------------------
+ detail::terminal_type detail::core_terminal_t::type() const noexcept(false)
+ {
+ if (plib::dynamic_downcast<const terminal_t *>(this))
+ return terminal_type::TERMINAL;
+ if (plib::dynamic_downcast<const logic_input_t *>(this)
+ || plib::dynamic_downcast<const analog_input_t *>(this))
+ return terminal_type::INPUT;
+ if (plib::dynamic_downcast<const logic_output_t *>(this)
+ || plib::dynamic_downcast<const analog_output_t *>(this))
+ return terminal_type::OUTPUT;
-detail::queue_t::queue_t(netlist_state_t &nl)
- : timed_queue<pqentry_t<net_t *, netlist_time>, false, true>(512)
- , netlist_ref(nl)
- , m_qsize(0)
- , m_times(512)
- , m_net_ids(512)
-{
-}
+ state().log().fatal(MF_UNKNOWN_TYPE_FOR_OBJECT(name()));
+ throw nl_exception(MF_UNKNOWN_TYPE_FOR_OBJECT(name()));
+ // return terminal_type::TERMINAL; // please compiler
+ }
-void detail::queue_t::register_state(plib::state_manager_t &manager, const pstring &module)
-{
- //state().log().debug("register_state\n");
- manager.save_item(this, m_qsize, module + "." + "qsize");
- manager.save_item(this, &m_times[0], module + "." + "times", m_times.size());
- manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size());
-}
+ // -------------------------------------------------------------------------
+ // detail::device_object_t
+ // -------------------------------------------------------------------------
-void detail::queue_t::on_pre_save(plib::state_manager_t &manager)
-{
- plib::unused_var(manager);
- m_qsize = this->size();
- for (std::size_t i = 0; i < m_qsize; i++ )
+ detail::device_object_t::device_object_t(core_device_t *dev,
+ const pstring &aname)
+ : object_t(aname)
+ , m_device(dev)
{
- m_times[i] = this->listptr()[i].m_exec_time.as_raw();
- m_net_ids[i] = state().find_net_id(this->listptr()[i].m_object);
}
-}
-
-void detail::queue_t::on_post_load(plib::state_manager_t &manager)
-{
- plib::unused_var(manager);
- this->clear();
- for (std::size_t i = 0; i < m_qsize; i++ )
+ netlist_state_t &detail::device_object_t::state() noexcept
{
- detail::net_t *n = state().nets()[m_net_ids[i]].get();
- this->push(queue_t::entry_t(netlist_time::from_raw(m_times[i]),n));
+ return m_device->state();
}
-}
-
-// ----------------------------------------------------------------------------------------
-// netlist_ref_t
-// ----------------------------------------------------------------------------------------
-detail::netlist_ref::netlist_ref(netlist_state_t &nl)
-: m_netlist(nl.exec()) { }
+ const netlist_state_t &detail::device_object_t::state() const noexcept
+ {
+ return m_device->state();
+ }
-// ----------------------------------------------------------------------------------------
-// device_object_t
-// ----------------------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
+ // detail::netlist_object_t
+ // -------------------------------------------------------------------------
-detail::device_object_t::device_object_t(core_device_t &dev, const pstring &aname)
-: object_t(aname)
-, m_device(dev)
-{
-}
+ netlist_state_t &detail::netlist_object_t::state() noexcept
+ {
+ return m_netlist.nl_state();
+ }
-detail::terminal_type detail::core_terminal_t::type() const
-{
- if (dynamic_cast<const terminal_t *>(this) != nullptr)
- return terminal_type::TERMINAL;
- else if (dynamic_cast<const logic_input_t *>(this) != nullptr)
- return terminal_type::INPUT;
- else if (dynamic_cast<const logic_output_t *>(this) != nullptr)
- return terminal_type::OUTPUT;
- else if (dynamic_cast<const analog_input_t *>(this) != nullptr)
- return terminal_type::INPUT;
- else if (dynamic_cast<const analog_output_t *>(this) != nullptr)
- return terminal_type::OUTPUT;
- else
+ const netlist_state_t &detail::netlist_object_t::state() const noexcept
{
- state().log().fatal(MF_UNKNOWN_TYPE_FOR_OBJECT(name()));
- return terminal_type::TERMINAL; // please compiler
+ return m_netlist.nl_state();
}
-}
-// ----------------------------------------------------------------------------------------
-// netlist_t
-// ----------------------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
+ // netlist_t
+ // -------------------------------------------------------------------------
-netlist_t::netlist_t(const pstring &aname, plib::unique_ptr<callbacks_t> callbacks)
- : m_state(plib::make_unique<netlist_state_t>(aname, *this, std::move(callbacks)))
+ netlist_t::netlist_t(netlist_state_t &state, const pstring &aname)
+ : m_state(state)
, m_solver(nullptr)
- , m_time(netlist_time::zero())
- , m_mainclock(nullptr)
- , m_queue(*m_state)
- , m_stats(false)
-{
- devices::initialize_factory(nlstate().setup().factory());
- NETLIST_NAME(base)(nlstate().setup());
- run_state_manager().save_item(this, static_cast<plib::state_manager_t::callback_t &>(m_queue), "m_queue");
- run_state_manager().save_item(this, m_time, "m_time");
-}
-
-// ----------------------------------------------------------------------------------------
-// netlist_t
-// ----------------------------------------------------------------------------------------
-
-netlist_state_t::netlist_state_t(const pstring &aname,
- netlist_t & anetlist,
- plib::unique_ptr<callbacks_t> &&callbacks)
-: m_name(aname)
-, m_netlist(anetlist)
-, m_state()
-, m_callbacks(std::move(callbacks)) // Order is important here
-, m_log(*m_callbacks)
-, m_setup(plib::make_unique<setup_t>(*this))
-{
- pstring libpath = plib::util::environment("NL_BOOSTLIB", plib::util::buildpath({".", "nlboost.so"}));
- m_lib = plib::make_unique<plib::dynlib>(libpath);
-}
-
-
-void netlist_t::stop()
-{
- log().debug("Printing statistics ...\n");
- print_stats();
- log().debug("Stopping solver device ...\n");
- if (m_solver != nullptr)
- m_solver->stop();
-}
-
-detail::net_t *netlist_state_t::find_net(const pstring &name) const
-{
- for (auto & net : m_nets)
- if (net->name() == name)
- return net.get();
-
- return nullptr;
-}
-
-std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const
-{
- for (std::size_t i = 0; i < m_nets.size(); i++)
- if (m_nets[i].get() == net)
- return i;
- return std::numeric_limits<std::size_t>::max();
-}
-
-
-
-void netlist_state_t::rebuild_lists()
-{
- for (auto & net : m_nets)
- net->rebuild_list();
-}
-
-
-void netlist_state_t::compile_defines(std::vector<std::pair<pstring, pstring>> &defs)
-{
-//#define ENTRY(x) { #x, PSTRINGIFY(x) }
-#define ENTRY(x) std::pair<pstring, pstring>(#x, PSTRINGIFY(x))
- defs.emplace_back(ENTRY(PHAS_RDTSCP));
- defs.emplace_back(ENTRY(PUSE_ACCURATE_STATS));
- defs.emplace_back(ENTRY(PHAS_INT128));
- defs.emplace_back(ENTRY(USE_ALIGNED_OPTIMIZATIONS));
- defs.emplace_back(ENTRY(NVCCBUILD));
- defs.emplace_back(ENTRY(USE_MEMPOOL));
- defs.emplace_back(ENTRY(USE_QUEUE_STATS));
- defs.emplace_back(ENTRY(USE_COPY_INSTEAD_OF_REFERENCE));
- defs.emplace_back(ENTRY(USE_TRUTHTABLE_7448));
- defs.emplace_back(ENTRY(NL_DEBUG));
- defs.emplace_back(ENTRY(HAS_OPENMP));
- defs.emplace_back(ENTRY(USE_OPENMP));
-
- defs.emplace_back(ENTRY(PPMF_TYPE));
- defs.emplace_back(ENTRY(PHAS_PMF_INTERNAL));
-
-#undef ENTRY
-}
-
-void netlist_t::reset()
-{
- log().debug("Searching for mainclock\n");
- m_mainclock = m_state->get_single_device<devices::NETLIB_NAME(mainclock)>("mainclock");
-
- log().debug("Searching for solver\n");
- m_solver = m_state->get_single_device<devices::NETLIB_NAME(solver)>("solver");
+ , m_time(netlist_time_ext::zero())
+ , m_main_clock(nullptr)
+ , m_use_stats(false)
+ , m_queue(
+ state.pool(), config::max_queue_size::value,
+ detail::queue_t::id_delegate(&netlist_state_t ::find_net_id, &state),
+ detail::queue_t::obj_delegate(&netlist_state_t ::net_by_id, &state))
+ {
+ state.save(*this,
+ static_cast<plib::state_manager_t::callback_t &>(m_queue),
+ aname, "m_queue");
+ state.save(*this, m_time, aname, "m_time");
+ }
- m_time = netlist_time::zero();
- m_queue.clear();
- if (m_mainclock != nullptr)
- m_mainclock->m_Q.net().set_next_scheduled_time(netlist_time::zero());
- //if (m_solver != nullptr)
- // m_solver->reset();
+ void netlist_t::reset()
+ {
+ log().debug("Searching for main clock\n");
+ m_main_clock = m_state
+ .get_single_device<devices::NETLIB_NAME(mainclock)>(
+ "mainclock");
+
+ log().debug("Searching for solver\n");
+ m_solver = m_state.get_single_device<devices::NETLIB_NAME(solver)>(
+ "solver");
+
+ // Don't reset time
+ // m_time = netlist_time_ext::zero();
+ m_queue.clear();
+ if (m_main_clock != nullptr)
+ m_main_clock->m_Q.net().set_next_scheduled_time(m_time);
+ // if (m_solver != nullptr)
+ // m_solver->reset();
+
+ m_state.reset();
+ }
- m_state->reset();
-}
+ void netlist_t::stop()
+ {
+ log().debug("Printing statistics ...\n");
+ print_stats();
+ log().debug("Stopping solver device ...\n");
+ if (m_solver != nullptr)
+ m_solver->stop();
+ }
-void netlist_state_t::reset()
-{
- //FIXME: never used ???
- std::unordered_map<core_device_t *, bool> m;
+ void netlist_t::print_stats() const
+ {
+ if (m_use_stats)
+ {
+ netlist_state_t::stats_info si{m_queue, m_stat_mainloop,
+ m_perf_out_processed};
+ m_state.print_stats(si);
+ }
+ log().verbose("Current pool memory allocated: {1:12} kB",
+ nl_state().pool().cur_alloc() >> 10);
+ log().verbose("Maximum pool memory allocated: {1:12} kB",
+ nl_state().pool().max_alloc() >> 10);
+ }
- // Reset all nets once !
- log().verbose("Call reset on all nets:");
- for (auto & n : nets())
- n->reset();
+ // -------------------------------------------------------------------------
+ // netlist_state_t
+ // -------------------------------------------------------------------------
- // Reset all devices once !
- log().verbose("Call reset on all devices:");
- for (auto & dev : m_devices)
- dev.second->reset();
+ netlist_state_t::netlist_state_t(const pstring & name,
+ plib::plog_delegate logger)
+ : m_log(logger)
+ , m_dummy_version(1)
+ {
+ m_setup = plib::make_unique<setup_t, host_arena>(*this);
+ // create the run interface
+ m_netlist = plib::make_unique<netlist_t>(m_pool, *this, name);
+
+ // Make sure save states are invalidated when a new version is deployed
+
+ m_state.save_item(this, m_dummy_version, pstring("V") + version());
+
+ // Initialize factory
+ devices::initialize_factory(m_setup->parser().factory());
+
+ // Add default include file
+ const pstring content
+ = "#define RES_R(res) (res) \n"
+ "#define RES_K(res) ((res) * 1e3) \n"
+ "#define RES_M(res) ((res) * 1e6) \n"
+ "#define CAP_U(cap) ((cap) * 1e-6) \n"
+ "#define CAP_N(cap) ((cap) * 1e-9) \n"
+ "#define CAP_P(cap) ((cap) * 1e-12) \n"
+ "#define IND_U(ind) ((ind) * 1e-6) \n"
+ "#define IND_N(ind) ((ind) * 1e-9) \n"
+ "#define IND_P(ind) ((ind) * 1e-12) \n";
+ m_setup->parser().add_include<plib::psource_str_t>(
+ "netlist/devices/net_lib.h", content);
+
+ // This is for core macro libraries
+ m_setup->parser().add_include<plib::psource_str_t>("devices/net_lib.h",
+ content);
+#if 1
+ NETLIST_NAME(base_lib)(m_setup->parser());
+ //#m_setup->parser().register_source<source_pattern_t>("../macro/modules/nlmod_{1}.cpp");
+ //#m_setup->parser().register_source<source_pattern_t>("../macro/nlm_{1}.cpp");
+#else
+ #if 1
+ pstring dir = "src/lib/netlist/";
+ m_setup->parser().register_source<source_pattern_t>(
+ dir + "/macro/nlm_{1}.cpp", true);
+ m_setup->parser().register_source<source_pattern_t>(
+ dir + "/generated/nlm_{1}.cpp", true);
+ m_setup->parser().register_source<source_pattern_t>(
+ dir + "/macro/modules/nlmod_{1}.cpp", true);
+ m_setup->parser().include("base_lib");
+ #else
+ // FIXME: This is very slow - need optimized parsing scanning
+ pstring dir = "src/lib/netlist/macro/";
+ // m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/macro/nlm_{}.cpp");
+ m_setup->parser().register_source<source_file_t>(dir
+ + "nlm_base_lib.cpp");
+ m_setup->parser().register_source<source_file_t>(dir
+ + "nlm_opamp_lib.cpp");
+ m_setup->parser().register_source<source_file_t>(dir
+ + "nlm_roms_lib.cpp");
+ m_setup->parser().register_source<source_file_t>(
+ dir + "nlm_cd4xxx_lib.cpp");
+ m_setup->parser().register_source<source_file_t>(
+ dir + "nlm_otheric_lib.cpp");
+ m_setup->parser().register_source<source_file_t>(
+ dir + "nlm_ttl74xx_lib.cpp");
+ m_setup->parser().include("base_lib");
+ #endif
+#endif
+ }
- // Make sure everything depending on parameters is set
- // Currently analog input and logic input also
- // push their outputs to queue.
+ void netlist_state_t::set_static_solver_lib(
+ std::unique_ptr<plib::dynamic_library_base> &&lib)
+ {
+ m_lib = std::move(lib);
+ }
- log().verbose("Call update_param on all devices:");
- for (auto & dev : m_devices)
- dev.second->update_param();
+ std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const
+ {
+ // special case for queue end processing items
+ if (net == nullptr)
+ return std::numeric_limits<std::size_t>::max() - 1;
- // Step all devices once !
- /*
- * INFO: The order here affects power up of e.g. breakout. However, such
- * variations are explicitly stated in the breakout manual.
- */
+ for (std::size_t i = 0; i < m_nets.size(); i++)
+ if (m_nets[i].get() == net)
+ return i;
- auto *netlist_params = get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
+ return std::numeric_limits<std::size_t>::max();
+ }
- switch (netlist_params->m_startup_strategy())
+ detail::net_t *netlist_state_t::net_by_id(std::size_t id) const
{
- case 0:
- {
- std::vector<core_device_t *> d;
- std::vector<nldelegate *> t;
- log().verbose("Using default startup strategy");
- for (auto &n : m_nets)
- for (auto & term : n->core_terms())
- if (term->m_delegate.has_object())
- {
- if (!plib::container::contains(t, &term->m_delegate))
- {
- t.push_back(&term->m_delegate);
- term->m_delegate();
- }
- auto *dev = reinterpret_cast<core_device_t *>(term->m_delegate.object());
- if (!plib::container::contains(d, dev))
- d.push_back(dev);
- }
- log().verbose("Devices not yet updated:");
- for (auto &dev : m_devices)
- if (!plib::container::contains(d, dev.second.get()))
- {
- log().verbose("\t ...{1}", dev.second->name());
- dev.second->update();
- }
- }
- break;
- case 1: // brute force backward
- {
- log().verbose("Using brute force backward startup strategy");
+ // special case for queue end processing items
+ if (id == std::numeric_limits<std::size_t>::max() - 1)
+ return nullptr;
- for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
- n->update_inputs();
+ return m_nets[id].get();
+ }
- std::size_t i = m_devices.size();
- while (i>0)
- m_devices[--i].second->update();
+ void netlist_state_t::rebuild_lists()
+ {
+ for (auto &net : m_nets)
+ net->rebuild_list();
+ }
- for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
- n->update_inputs();
+ void netlist_state_t::compile_defines(
+ std::vector<std::pair<pstring, pstring>> &defs)
+ {
+#define ENTRY(x) \
+ if (pstring(#x) != PSTRINGIFY(x)) \
+ defs.emplace_back(std::pair<pstring, pstring>(#x, PSTRINGIFY(x))); \
+ else \
+ defs.emplace_back(std::pair<pstring, pstring>(#x, "<NOT DEFINED>"));
+#define ENTRY_EX(x) \
+ defs.emplace_back(std::pair<pstring, pstring>(#x, plib::pfmt("{}")(x)));
+ ENTRY(NL_VERSION_MAJOR)
+ ENTRY(NL_VERSION_MINOR)
+ ENTRY(NL_VERSION_PATCHLEVEL)
+
+ ENTRY(PUSE_ACCURATE_STATS)
+ ENTRY(PHAS_INT128)
+ ENTRY(PUSE_ALIGNED_OPTIMIZATIONS)
+ ENTRY(PHAS_OPENMP)
+ ENTRY(PUSE_OPENMP)
+ ENTRY(PUSE_FLOAT128)
+ ENTRY_EX(config::use_mempool::value)
+ ENTRY_EX(config::use_queue_stats::value)
+ ENTRY(NL_USE_COPY_INSTEAD_OF_REFERENCE)
+ ENTRY(NL_USE_FLOAT128)
+ ENTRY_EX(config::use_float_matrix::value)
+ ENTRY_EX(config::use_long_double_matrix::value)
+ ENTRY(NL_DEBUG)
+ ENTRY(__NVCC__)
+
+ ENTRY(__cplusplus)
+ ENTRY(__VERSION__)
+
+ ENTRY(__GNUC__)
+ ENTRY(__GNUC_MINOR__)
+ ENTRY(__GNUC_PATCHLEVEL__)
+
+ ENTRY(__clang__)
+ ENTRY(__clang_major__)
+ ENTRY(__clang_minor__)
+ ENTRY(__clang_patchlevel__)
+ ENTRY(__clang_version__)
+
+ ENTRY(OPENMP)
+ ENTRY(_OPENMP)
+
+ ENTRY(__x86_64__)
+ ENTRY(__i386__)
+ ENTRY(_WIN32)
+ ENTRY(_MSC_VER)
+ ENTRY(__APPLE__)
+ ENTRY(__unix__)
+ ENTRY(__linux__)
+
+ ENTRY_EX(sizeof(base_device_t))
+ ENTRY_EX(sizeof(device_t))
+ ENTRY_EX(sizeof(logic_t))
+ ENTRY_EX(sizeof(logic_input_t))
+ ENTRY_EX(sizeof(logic_output_t))
+ ENTRY_EX(sizeof(param_model_t))
+ ENTRY_EX(sizeof(param_logic_t))
+ ENTRY_EX(sizeof(state_var<int>))
+ ENTRY_EX(sizeof(pstring))
+ ENTRY_EX(sizeof(core_device_t::stats_t))
+ ENTRY_EX(sizeof(std::vector<detail::core_terminal_t *>))
+ ENTRY_EX(sizeof(plib::plog_level))
+
+ ENTRY_EX(sizeof(nl_delegate))
+ ENTRY(PPMF_FORCE_TYPE)
+ ENTRY(PHAS_PMF_INTERNAL)
- }
- break;
- case 2: // brute force forward
- {
- log().verbose("Using brute force forward startup strategy");
- for (auto &d : m_devices)
- d.second->update();
- }
- break;
+#undef ENTRY
+#undef ENTRY_EX
}
-#if 1
- /* the above may screw up m_active and the list */
- rebuild_lists();
-#endif
-}
-
-void netlist_t::process_queue(const netlist_time delta) NL_NOEXCEPT
-{
- if (!m_stats)
- process_queue_stats<false>(delta);
- else
+ pstring netlist_state_t::version()
{
- auto sm_guard(m_stat_mainloop.guard());
- process_queue_stats<true>(delta);
+ return plib::pfmt("{1}.{2}")(NL_VERSION_MAJOR, NL_VERSION_MINOR);
}
-}
-template <bool KEEP_STATS>
-void netlist_t::process_queue_stats(const netlist_time delta) NL_NOEXCEPT
-{
- netlist_time stop(m_time + delta);
+ pstring netlist_state_t::version_patchlevel()
+ {
+ return plib::pfmt("{1}.{2}.{3}")(NL_VERSION_MAJOR, NL_VERSION_MINOR,
+ NL_VERSION_PATCHLEVEL);
+ }
- qpush(detail::queue_t::entry_t(stop, nullptr));
+ void netlist_state_t::free_setup_resources() { m_setup = nullptr; }
- if (m_mainclock == nullptr)
+ void netlist_state_t::reset()
{
- detail::queue_t::entry_t e(m_queue.pop());
- m_time = e.m_exec_time;
- while (e.m_object != nullptr)
+ // Reset all nets once !
+ log().verbose("Call reset on all nets:");
+ for (auto &n : nets())
+ n->reset();
+
+ // Reset all devices once !
+ log().verbose("Call reset on all devices:");
+ for (auto &dev : m_devices)
+ dev.second->reset();
+
+ // Make sure everything depending on parameters is set
+ // Currently analog input and logic input also
+ // push their outputs to queue.
+
+ std::vector<core_device_t *> devices_called;
+ log().verbose("Call update_param on all devices:");
+ for (auto &dev : m_devices)
{
- e.m_object->template update_devs<KEEP_STATS>();
- if (KEEP_STATS) m_perf_out_processed.inc();
- e = m_queue.pop();
- m_time = e.m_exec_time;
+ dev.second->update_param();
+ if (!plib::container::contains(devices_called, dev.second.get()))
+ devices_called.push_back(dev.second.get());
}
- }
- else
- {
- logic_net_t &mc_net(m_mainclock->m_Q.net());
- const netlist_time inc(m_mainclock->m_inc);
- netlist_time mc_time(mc_net.next_scheduled_time());
- do
+ // Step all devices once !
+ //
+ // INFO: The order here affects power up of e.g. breakout. However, such
+ // variations are explicitly stated in the breakout manual.
+
+ auto *netlist_params = get_single_device<
+ devices::NETLIB_NAME(netlistparams)>("parameter");
+
+ switch (netlist_params->m_startup_strategy())
{
- while (m_queue.top().m_exec_time > mc_time)
+ case 0:
{
- m_time = mc_time;
- mc_net.toggle_new_Q();
- mc_net.update_devs<KEEP_STATS>();
- mc_time += inc;
+ std::vector<const nl_delegate *> t;
+ log().verbose("Using default startup strategy");
+ for (auto &n : m_nets)
+ {
+ n->update_inputs(); // only used if
+ // USE_COPY_INSTEAD_OF_REFERENCE == 1
+ for (detail::core_terminal_t *term : n->core_terms_copy())
+ {
+ if (!plib::container::contains(t, &term->delegate()))
+ {
+ t.push_back(&term->delegate());
+ term->run_delegate();
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto *dev = reinterpret_cast<core_device_t *>(
+ term->delegate().object());
+ if (!plib::container::contains(devices_called, dev))
+ devices_called.push_back(dev);
+ }
+ }
+ log().verbose("Devices not yet updated:");
+ for (auto &dev : m_devices)
+ if (!plib::container::contains(devices_called,
+ dev.second.get()))
+ {
+ // FIXME: doesn't seem to be needed, use cases include
+ // analog output devices. Check and remove
+ log().error("\t Device {1} not yet updated",
+ dev.second->name());
+ // dev.second->update();
+ }
}
+ break;
+ }
- detail::queue_t::entry_t e(m_queue.pop());
- m_time = e.m_exec_time;
- if (e.m_object != nullptr)
- {
- e.m_object->template update_devs<KEEP_STATS>();
- if (KEEP_STATS) m_perf_out_processed.inc();
- }
- else
- break;
- } while (true); //while (e.m_object != nullptr);
- mc_net.set_next_scheduled_time(mc_time);
+ // the above may screw up m_active and the list
+ rebuild_lists();
}
-}
-void netlist_t::print_stats() const
-{
- if (m_stats)
+ void netlist_state_t::print_stats(stats_info &si) const
{
std::vector<size_t> index;
- for (size_t i=0; i < m_state->m_devices.size(); i++)
+ for (size_t i = 0; i < this->m_devices.size(); i++)
index.push_back(i);
std::sort(index.begin(), index.end(),
- [&](size_t i1, size_t i2) { return m_state->m_devices[i1].second->m_stats->m_stat_total_time.total() < m_state->m_devices[i2].second->m_stats->m_stat_total_time.total(); });
-
- nperftime_t<true>::type total_time(0);
- nperftime_t<true>::ctype total_count(0);
-
- for (auto & j : index)
+ [&](size_t i1, size_t i2)
+ {
+ return this->m_devices[i1]
+ .second->stats()
+ ->m_stat_total_time.total()
+ < this->m_devices[i2]
+ .second->stats()
+ ->m_stat_total_time.total();
+ });
+
+ plib::pperftime_t<true>::type total_time(0);
+ plib::pperftime_t<true>::ctype total_count(0);
+
+ for (auto &j : index)
{
- auto entry = m_state->m_devices[j].second.get();
- auto stats = m_state->m_devices[j].second.get()->m_stats.get();
- log().verbose("Device {1:20} : {2:12} {3:12} {4:15} {5:12}", entry->name(),
- stats->m_stat_call_count(), stats->m_stat_total_time.count(),
- stats->m_stat_total_time.total(), stats->m_stat_inc_active());
+ auto *entry = this->m_devices[j].second.get();
+ auto *stats = entry->stats();
+ log().verbose(
+ "Device {1:20} : {2:12} {3:12} {4:15} {5:12}", entry->name(),
+ stats->m_stat_call_count(), stats->m_stat_total_time.count(),
+ stats->m_stat_total_time.total(), stats->m_stat_inc_active());
total_time += stats->m_stat_total_time.total();
total_count += stats->m_stat_total_time.count();
}
log().verbose("Total calls : {1:12} {2:12} {3:12}", total_count,
- total_time, total_time / static_cast<decltype(total_time)>(total_count));
+ total_time,
+ total_time
+ / gsl::narrow<decltype(total_time)>(
+ (total_count > 0) ? total_count : 1));
- log().verbose("Total loop {1:15}", m_stat_mainloop());
+ log().verbose("Total loop {1:15}", si.m_stat_mainloop());
log().verbose("Total time {1:15}", total_time);
// FIXME: clang complains about unreachable code without
- const auto clang_workaround_unreachable_code = USE_QUEUE_STATS;
+ const bool clang_workaround_unreachable_code(
+ config::use_queue_stats::value);
if (clang_workaround_unreachable_code)
{
- /* Only one serialization should be counted in total time */
- /* But two are contained in m_stat_mainloop */
- nperftime_t<true> overhead;
- nperftime_t<true> test;
+ // Only one serialization should be counted in total time
+ // But two are contained in m_stat_mainloop
+ plib::pperftime_t<true> overhead;
+ plib::pperftime_t<true> test;
{
auto overhead_guard(overhead.guard());
- for (int j=0; j<100000;j++)
+ for (int j = 0; j < 100000; j++)
{
auto test_guard(test.guard());
}
}
- nperftime_t<true>::type total_overhead = overhead()
- * static_cast<nperftime_t<true>::type>(total_count)
- / static_cast<nperftime_t<true>::type>(200000);
+ plib::pperftime_t<true>::type total_overhead
+ = overhead()
+ * gsl::narrow<plib::pperftime_t<true>::type>(total_count)
+ / gsl::narrow<plib::pperftime_t<true>::type>(200000);
- log().verbose("Queue Pushes {1:15}", m_queue.m_prof_call());
- log().verbose("Queue Moves {1:15}", m_queue.m_prof_sortmove());
- log().verbose("Queue Removes {1:15}", m_queue.m_prof_remove());
- log().verbose("Queue Retimes {1:15}", m_queue.m_prof_retime());
+ log().verbose("Queue Pushes {1:15}", si.m_queue.m_prof_call());
+ log().verbose("Queue Moves {1:15}",
+ si.m_queue.m_prof_sort_move());
+ log().verbose("Queue Removes {1:15}", si.m_queue.m_prof_remove());
log().verbose("");
- log().verbose("Take the next lines with a grain of salt. They depend on the measurement implementation.");
+ log().verbose(
+ "Take the next lines with a grain of salt. They depend on the measurement implementation.");
log().verbose("Total overhead {1:15}", total_overhead);
- nperftime_t<true>::type overhead_per_pop = (m_stat_mainloop()-2*total_overhead - (total_time - total_overhead))
- / static_cast<nperftime_t<true>::type>(m_queue.m_prof_call());
- log().verbose("Overhead per pop {1:11}", overhead_per_pop );
+ plib::pperftime_t<true>::type overhead_per_pop
+ = (si.m_stat_mainloop() - 2 * total_overhead
+ - (total_time - total_overhead))
+ / gsl::narrow<plib::pperftime_t<true>::type>(
+ si.m_queue.m_prof_call());
+ log().verbose("Overhead per pop {1:11}", overhead_per_pop);
log().verbose("");
}
auto trigger = total_count * 200 / 1000000; // 200 ppm
- for (auto &entry : m_state->m_devices)
+ for (const auto &entry : this->m_devices)
{
- auto ep = entry.second.get();
- auto stats = ep->m_stats.get();
- // Factor of 3 offers best performace increase
- if (stats->m_stat_inc_active() > 3 * stats->m_stat_total_time.count()
+ auto *ep = entry.second.get();
+ auto *stats = ep->stats();
+ // Factor of 3 offers best performance increase
+ if (stats->m_stat_inc_active()
+ > 3 * stats->m_stat_total_time.count()
&& stats->m_stat_inc_active() > trigger)
log().verbose("HINT({}, NO_DEACTIVATE) // {} {} {}", ep->name(),
- static_cast<double>(stats->m_stat_inc_active()) / static_cast<double>(stats->m_stat_total_time.count()),
- stats->m_stat_inc_active(), stats->m_stat_total_time.count());
+ gsl::narrow<nl_fptype>(stats->m_stat_inc_active())
+ / gsl::narrow<nl_fptype>(
+ stats->m_stat_total_time.count()),
+ stats->m_stat_inc_active(),
+ stats->m_stat_total_time.count());
}
+ log().verbose("");
}
-}
-core_device_t *netlist_state_t::get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const
-{
- core_device_t *ret = nullptr;
- for (auto &d : m_devices)
+ core_device_t *
+ netlist_state_t::get_single_device(const pstring &classname,
+ bool (*cc)(core_device_t *)) const
{
- if (cc(d.second.get()))
+ core_device_t *ret = nullptr;
+ for (const auto &d : m_devices)
{
- if (ret != nullptr)
- m_log.fatal(MF_MORE_THAN_ONE_1_DEVICE_FOUND(classname));
- else
+ if (cc(d.second.get()))
+ {
+ if (ret != nullptr)
+ {
+ m_log.fatal(MF_MORE_THAN_ONE_1_DEVICE_FOUND(classname));
+ throw nl_exception(
+ MF_MORE_THAN_ONE_1_DEVICE_FOUND(classname));
+ }
ret = d.second.get();
+ }
}
+ return ret;
}
- return ret;
-}
+ nlparse_t &netlist_state_t::parser() noexcept { return m_setup->parser(); }
+ const nlparse_t &netlist_state_t::parser() const noexcept
+ {
+ return m_setup->parser();
+ }
-// ----------------------------------------------------------------------------------------
-// core_device_t
-// ----------------------------------------------------------------------------------------
+ void netlist_state_t::remove_device(core_device_t *dev)
+ {
+ for (auto it = m_devices.begin(); it != m_devices.end(); it++)
+ if (it->second.get() == dev)
+ {
+ m_state.remove_save_items(dev);
+ m_devices.erase(it);
+ return;
+ }
+ }
-core_device_t::core_device_t(netlist_state_t &owner, const pstring &name)
- : object_t(name)
- , logic_family_t()
- , netlist_ref(owner)
- , m_hint_deactivate(false)
- , m_active_outputs(*this, "m_active_outputs", 1)
-{
- if (logic_family() == nullptr)
- set_logic_family(family_TTL());
- if (exec().stats_enabled())
- m_stats = plib::make_unique<stats_t>();
-}
-
-core_device_t::core_device_t(core_device_t &owner, const pstring &name)
- : object_t(owner.name() + "." + name)
- , logic_family_t()
- , netlist_ref(owner.state())
+ // -------------------------------------------------------------------------
+ // core_device_t
+ // -------------------------------------------------------------------------
+
+ core_device_t::core_device_t(core_device_param_t data)
+ : netlist_object_t(data.owner.exec(), data.name)
, m_hint_deactivate(false)
, m_active_outputs(*this, "m_active_outputs", 1)
-{
- set_logic_family(owner.logic_family());
- if (logic_family() == nullptr)
- set_logic_family(family_TTL());
- state().add_dev(this->name(), pool_owned_ptr<core_device_t>(this, false));
- if (exec().stats_enabled())
- m_stats = plib::make_unique<stats_t>();
-}
-
-void core_device_t::set_default_delegate(detail::core_terminal_t &term)
-{
- if (!term.m_delegate.is_set())
- term.m_delegate.set(&core_device_t::update, this);
-}
-
-log_type & core_device_t::log()
-{
- return state().log();
-}
-
-// ----------------------------------------------------------------------------------------
-// device_t
-// ----------------------------------------------------------------------------------------
-
-device_t::device_t(netlist_state_t &owner, const pstring &name)
-: core_device_t(owner, name)
-{
-}
+ {
+ if (exec().stats_enabled())
+ m_stats = state().make_pool_object<stats_t>();
+ }
-device_t::device_t(core_device_t &owner, const pstring &name)
-: core_device_t(owner, name)
-{
-}
+ log_type &core_device_t::log() { return state().log(); }
-setup_t &device_t::setup()
-{
- return state().setup();
-}
+ // -------------------------------------------------------------------------
+ // base_device_t
+ // -------------------------------------------------------------------------
-const setup_t &device_t::setup() const
-{
- return state().setup();
-}
+ base_device_t::base_device_t(base_device_param_t data)
+ : core_device_t(data)
+ {
+ }
-void device_t::register_subalias(const pstring &name, detail::core_terminal_t &term)
-{
- pstring alias = this->name() + "." + name;
+ void base_device_t::register_sub_alias(const pstring & name,
+ const detail::core_terminal_t &term)
+ {
+ pstring alias = this->name() + "." + name;
- // everything already fully qualified
- setup().register_alias_nofqn(alias, term.name());
-}
+ // everything already fully qualified
+ state().parser().register_fqn_alias(detail::alias_type::FUNCTIONAL,
+ alias, term.name());
+ }
-void device_t::register_subalias(const pstring &name, const pstring &aliased)
-{
- pstring alias = this->name() + "." + name;
- pstring aliased_fqn = this->name() + "." + aliased;
+ void base_device_t::register_sub_alias(const pstring &name,
+ const pstring &aliased)
+ {
+ pstring alias = this->name() + "." + name;
+ pstring aliased_fqn = this->name() + "." + aliased;
- // everything already fully qualified
- setup().register_alias_nofqn(alias, aliased_fqn);
-}
+ // everything already fully qualified
+ state().parser().register_fqn_alias(detail::alias_type::FUNCTIONAL,
+ alias, aliased_fqn);
+ }
-void device_t::connect(detail::core_terminal_t &t1, detail::core_terminal_t &t2)
-{
- setup().register_link_fqn(t1.name(), t2.name());
-}
+ void base_device_t::connect(const detail::core_terminal_t &t1,
+ const detail::core_terminal_t &t2)
+ {
+ state().parser().register_connection_fqn(t1.name(), t2.name());
+ }
-void device_t::connect(const pstring &t1, const pstring &t2)
-{
- setup().register_link_fqn(name() + "." + t1, name() + "." + t2);
-}
+ void base_device_t::connect(const pstring &t1, const pstring &t2)
+ {
+ state().parser().register_connection_fqn(name() + "." + t1,
+ name() + "." + t2);
+ }
-/* FIXME: this is only used by solver code since matrix solvers are started in
- * post_start.
- */
-void device_t::connect_post_start(detail::core_terminal_t &t1, detail::core_terminal_t &t2)
-{
- if (!setup().connect(t1, t2))
- log().fatal(MF_ERROR_CONNECTING_1_TO_2(t1.name(), t2.name()));
-}
+ // -------------------------------------------------------------------------
+ // device_t
+ // -------------------------------------------------------------------------
+ device_t::device_t(device_param_t data)
+ : base_device_t(data)
+ , m_model(*this, "MODEL", pstring(config::DEFAULT_LOGIC_FAMILY()))
+ {
+ set_logic_family(state().setup().family_from_model(m_model()));
+ if (logic_family() == nullptr)
+ throw nl_exception(MF_NULLPTR_FAMILY(this->name(), m_model()));
+ }
-// -----------------------------------------------------------------------------
-// family_setter_t
-// -----------------------------------------------------------------------------
+ device_t::device_t(device_param_t data, const pstring &model)
+ : base_device_t(data)
+ , m_model(*this, "MODEL", model)
+ {
+ set_logic_family(state().setup().family_from_model(m_model()));
+ if (logic_family() == nullptr)
+ throw nl_exception(MF_NULLPTR_FAMILY(this->name(), m_model()));
+ }
-// NOLINTNEXTLINE(modernize-use-equals-default)
-detail::family_setter_t::family_setter_t()
-{
-}
+ device_t::device_t(device_param_t data, const logic_family_desc_t *desc)
+ : base_device_t(data)
+ , m_model(*this, "MODEL", pstring(""))
+ {
+ set_logic_family(desc);
+ if (logic_family() == nullptr)
+ throw nl_exception(MF_NULLPTR_FAMILY(
+ this->name(), "<pointer provided by constructor>"));
+ }
-detail::family_setter_t::family_setter_t(core_device_t &dev, const pstring &desc)
-{
- dev.set_logic_family(dev.setup().family_from_model(desc));
-}
+ // -------------------------------------------------------------------------
+ // analog_t
+ // -------------------------------------------------------------------------
-detail::family_setter_t::family_setter_t(core_device_t &dev, const logic_family_desc_t *desc)
-{
- dev.set_logic_family(desc);
-}
+ analog_t::analog_t(core_device_t &dev, const pstring &aname,
+ const state_e state, nl_delegate delegate)
+ : core_terminal_t(dev, aname, state, delegate)
+ {
+ }
-// ----------------------------------------------------------------------------------------
-// net_t
-// ----------------------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
+ // net_t
+ // -------------------------------------------------------------------------
-detail::net_t::net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *mr)
- : object_t(aname)
- , netlist_ref(nl)
- , m_new_Q(*this, "m_new_Q", 0)
- , m_cur_Q (*this, "m_cur_Q", 0)
+ detail::net_t::net_t(netlist_state_t &nl, const pstring &aname,
+ core_terminal_t *rail_terminal)
+ : netlist_object_t(nl.exec(), aname)
+ , m_new_Q(*this, "m_new_Q", netlist_sig_t(0))
+ , m_cur_Q(*this, "m_cur_Q", netlist_sig_t(0))
, m_in_queue(*this, "m_in_queue", queue_status::DELIVERED)
- , m_next_scheduled_time(*this, "m_time", netlist_time::zero())
- , m_railterminal(mr)
-{
-}
-
-void detail::net_t::rebuild_list()
-{
- /* rebuild m_list */
+ , m_next_scheduled_time(*this, "m_time", netlist_time_ext::zero())
+ , m_rail_terminal(rail_terminal)
+ {
+ props::add(this, props::value_type());
+ }
- m_list_active.clear();
- for (auto & term : m_core_terms)
- if (term->terminal_state() != logic_t::STATE_INP_PASSIVE)
- {
- m_list_active.push_back(term);
- term->set_copied_input(m_cur_Q);
- }
-}
+ bool detail::net_t::is_logic() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const logic_net_t *>(this));
+ }
-template <bool KEEP_STATS, typename T>
-void detail::net_t::process(const T mask, netlist_sig_t sig)
-{
- m_cur_Q = sig;
+ bool detail::net_t::is_analog() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const analog_net_t *>(this));
+ }
- if (KEEP_STATS)
+ void detail::net_t::rebuild_list()
{
- for (auto & p : m_list_active)
- {
- p.set_copied_input(sig);
- auto *stats = p.device().m_stats.get();
- stats->m_stat_call_count.inc();
- if ((p.terminal_state() & mask))
+ // rebuild m_list
+
+ m_list_active.clear();
+ for (core_terminal_t *term : core_terms_ref())
+ if (term->terminal_state() != logic_t::STATE_INP_PASSIVE)
{
- auto g(stats->m_stat_total_time.guard());
- p.m_delegate();
+ m_list_active.push_back(term);
+ term->set_copied_input(m_cur_Q);
}
- }
}
- else
+
+ void detail::net_t::reset() noexcept
{
- for (auto & p : m_list_active)
+ m_next_scheduled_time = exec().time();
+ m_in_queue = queue_status::DELIVERED;
+
+ m_new_Q = 0;
+ m_cur_Q = 0;
+
+ if (auto p = plib::dynamic_downcast<analog_net_t *>(this))
+ (*p)->set_Q_Analog(nlconst::zero());
+
+ // rebuild m_list and reset terminals to active or analog out state
+
+ m_list_active.clear();
+ for (core_terminal_t *ct : core_terms_copy())
{
- p.set_copied_input(sig);
- if ((p.terminal_state() & mask))
- p.m_delegate();
+ ct->reset();
+ if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE)
+ m_list_active.push_back(ct);
+ ct->set_copied_input(m_cur_Q);
}
}
-}
-template <bool KEEP_STATS>
-void detail::net_t::update_devs() NL_NOEXCEPT
-{
- nl_assert(this->isRailNet());
+#if NL_USE_INPLACE_CORE_TERMS
+ void detail::net_t::remove_terminal(detail::core_terminal_t &term)
+ {
+ m_core_terms.remove(&term);
+ }
+
+ void detail::net_t::remove_all_terminals() { m_core_terms.clear(); }
- const unsigned int new_Q(m_new_Q);
+ void detail::net_t::add_terminal(detail::core_terminal_t &terminal)
+ {
+ for (detail::core_terminal_t *t : m_core_terms)
+ if (t == &terminal)
+ {
+ state().log().fatal(
+ MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name()));
+ throw nl_exception(
+ MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name()));
+ }
- const unsigned int mask((new_Q << core_terminal_t::INP_LH_SHIFT)
- | (m_cur_Q << core_terminal_t::INP_HL_SHIFT));
+ terminal.set_net(this);
+
+ m_core_terms.push_back(&terminal);
+ }
- m_in_queue = queue_status::DELIVERED; /* mark as taken ... */
- switch (mask)
+#else
+ void detail::net_t::remove_terminal(detail::core_terminal_t &term)
{
- case core_terminal_t::STATE_INP_HL:
- case core_terminal_t::STATE_INP_LH:
- process<KEEP_STATS>(mask | core_terminal_t::STATE_INP_ACTIVE, new_Q);
- break;
- default:
- /* do nothing */
- break;
+ // net.core_terms().remove(p);
+ for (auto pp = state().core_terms(*this).begin();
+ pp != state().core_terms(*this).end(); pp++)
+ if (*pp == &term)
+ {
+ state().core_terms(*this).erase(pp);
+ break;
+ }
}
-}
-void detail::net_t::reset()
-{
- m_next_scheduled_time = netlist_time::zero();
- m_in_queue = queue_status::DELIVERED;
+ void detail::net_t::remove_all_terminals()
+ {
+ state().core_terms(*this).clear();
+ }
- m_new_Q = 0;
- m_cur_Q = 0;
+ void detail::net_t::add_terminal(detail::core_terminal_t &terminal)
+ {
+ for (detail::core_terminal_t *t : core_terms_ref())
+ if (t == &terminal)
+ {
+ state().log().fatal(
+ MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name()));
+ throw nl_exception(
+ MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name()));
+ }
- auto *p = dynamic_cast<analog_net_t *>(this);
+ terminal.set_net(this);
- if (p != nullptr)
- p->m_cur_Analog = 0.0;
+ state().core_terms(*this).push_back(&terminal);
+ }
+#endif
- /* rebuild m_list and reset terminals to active or analog out state */
+ // -------------------------------------------------------------------------
+ // logic_net_t
+ // -------------------------------------------------------------------------
- m_list_active.clear();
- for (core_terminal_t *ct : m_core_terms)
+ logic_net_t::logic_net_t(netlist_state_t &nl, const pstring &aname,
+ detail::core_terminal_t *rail_terminal)
+ : net_t(nl, aname, rail_terminal)
{
- ct->reset();
- if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE)
- m_list_active.push_back(ct);
- ct->set_copied_input(m_cur_Q);
}
-}
-void detail::net_t::add_terminal(detail::core_terminal_t &terminal)
-{
- for (auto &t : m_core_terms)
- if (t == &terminal)
- state().log().fatal(MF_NET_1_DUPLICATE_TERMINAL_2(name(), t->name()));
+ // -------------------------------------------------------------------------
+ // analog_net_t
+ // -------------------------------------------------------------------------
- terminal.set_net(this);
+ analog_net_t::analog_net_t(netlist_state_t &nl, const pstring &aname,
+ detail::core_terminal_t *rail_terminal)
+ : net_t(nl, aname, rail_terminal)
+ , m_cur_Analog(*this, "m_cur_Analog", nlconst::zero())
+ , m_solver(nullptr)
+ {
+ }
- m_core_terms.push_back(&terminal);
-}
+ void analog_net_t::reset() noexcept
+ {
+ net_t::reset();
+ m_cur_Analog = nlconst::zero();
+ }
-void detail::net_t::remove_terminal(detail::core_terminal_t &terminal)
-{
- if (plib::container::contains(m_core_terms, &terminal))
+ // -------------------------------------------------------------------------
+ // core_terminal_t
+ // -------------------------------------------------------------------------
+
+ detail::core_terminal_t::core_terminal_t(core_device_t &dev,
+ const pstring &aname,
+ const state_e state,
+ nl_delegate delegate)
+ : device_object_t(&dev, dev.name() + "." + aname)
+ , m_Q_CIR(*this, "m_Q", 0)
+ , m_delegate(delegate)
+ , m_net(nullptr)
+ , m_state(*this, "m_state", state)
{
- terminal.set_net(nullptr);
- plib::container::remove(m_core_terms, &terminal);
}
- else
- state().log().fatal(MF_REMOVE_TERMINAL_1_FROM_NET_2(terminal.name(), this->name()));
-}
-void detail::net_t::move_connections(detail::net_t &dest_net)
-{
- for (auto &ct : m_core_terms)
- dest_net.add_terminal(*ct);
- m_core_terms.clear();
-}
+ bool detail::core_terminal_t::is_logic() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const logic_t *>(this));
+ }
-// ----------------------------------------------------------------------------------------
-// logic_net_t
-// ----------------------------------------------------------------------------------------
+ bool detail::core_terminal_t::is_logic_input() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const logic_input_t *>(this));
+ }
-logic_net_t::logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr)
- : net_t(nl, aname, mr)
-{
-}
+ bool detail::core_terminal_t::is_logic_output() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const logic_output_t *>(this));
+ }
-// ----------------------------------------------------------------------------------------
-// analog_net_t
-// ----------------------------------------------------------------------------------------
+ bool detail::core_terminal_t::is_tristate_output() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const tristate_output_t *>(this));
+ }
-analog_net_t::analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr)
- : net_t(nl, aname, mr)
- , m_cur_Analog(*this, "m_cur_Analog", 0.0)
- , m_solver(nullptr)
-{
-}
-
-// ----------------------------------------------------------------------------------------
-// core_terminal_t
-// ----------------------------------------------------------------------------------------
-
-detail::core_terminal_t::core_terminal_t(core_device_t &dev, const pstring &aname,
- const state_e state, nldelegate delegate)
-: device_object_t(dev, dev.name() + "." + aname)
-, plib::linkedlist_t<core_terminal_t>::element_t()
-, m_delegate(delegate)
-#if USE_COPY_INSTEAD_OF_REFERENCE
-, m_Q(*this, "m_Q", 0)
-#endif
-, m_net(nullptr)
-, m_state(*this, "m_state", state)
-{
-}
+ bool detail::core_terminal_t::is_analog() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const analog_t *>(this));
+ }
-analog_t::analog_t(core_device_t &dev, const pstring &aname, const state_e state,
- nldelegate delegate)
-: core_terminal_t(dev, aname, state, delegate)
-{
-}
+ bool detail::core_terminal_t::is_analog_input() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const analog_input_t *>(this));
+ }
-logic_t::logic_t(core_device_t &dev, const pstring &aname, const state_e state,
- nldelegate delegate)
- : core_terminal_t(dev, aname, state, delegate)
- , logic_family_t()
- , m_proxy(nullptr)
-{
-}
-
-// ----------------------------------------------------------------------------------------
-// terminal_t
-// ----------------------------------------------------------------------------------------
-
-terminal_t::terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm)
-: analog_t(dev, aname, STATE_BIDIR)
-, m_Idr1(nullptr)
-, m_go1(nullptr)
-, m_gt1(nullptr)
-, m_connected_terminal(otherterm)
-{
- state().setup().register_term(*this);
-}
+ bool detail::core_terminal_t::is_analog_output() const noexcept
+ {
+ return bool(plib::dynamic_downcast<const analog_output_t *>(this));
+ }
-void terminal_t::solve_now()
-{
- // Nets may belong to railnets which do not have a solver attached
- if (this->has_net())
- if (net().solver() != nullptr)
- net().solver()->update_forced();
-}
+ // -------------------------------------------------------------------------
+ // terminal_t
+ // -------------------------------------------------------------------------
-void terminal_t::schedule_solve_after(const netlist_time after)
-{
- // Nets may belong to railnets which do not have a solver attached
- if (this->has_net())
- if (net().solver() != nullptr)
- net().solver()->update_after(after);
-}
-
-// ----------------------------------------------------------------------------------------
-// net_input_t
-// ----------------------------------------------------------------------------------------
-
-// ----------------------------------------------------------------------------------------
-// net_output_t
-// ----------------------------------------------------------------------------------------
-
-// ----------------------------------------------------------------------------------------
-// logic_output_t
-// ----------------------------------------------------------------------------------------
-
-logic_output_t::logic_output_t(core_device_t &dev, const pstring &aname)
- : logic_t(dev, aname, STATE_OUT)
- , m_my_net(dev.state(), name() + ".net", this)
-{
- this->set_net(&m_my_net);
- state().register_net(pool_owned_ptr<logic_net_t>(&m_my_net, false));
- set_logic_family(dev.logic_family());
- state().setup().register_term(*this);
-}
+ terminal_t::terminal_t(core_device_t &dev, const pstring &aname,
+ terminal_t *other_terminal, nl_delegate delegate)
+ : terminal_t(dev, aname, other_terminal, {nullptr, nullptr}, delegate)
+ {
+ }
-void logic_output_t::initial(const netlist_sig_t val)
-{
- if (has_net())
- net().initial(val);
-}
+ terminal_t::terminal_t(core_device_t &dev, const pstring &aname,
+ terminal_t * other_terminal,
+ const std::array<terminal_t *, 2> &splitter_terms,
+ nl_delegate delegate)
+ : analog_t(dev, aname, STATE_BIDIR, delegate)
+ , m_Idr(nullptr)
+ , m_go(nullptr)
+ , m_gt(nullptr)
+ {
+ state().setup().register_term(*this, other_terminal, splitter_terms);
+ }
-// ----------------------------------------------------------------------------------------
-// analog_input_t
-// ----------------------------------------------------------------------------------------
+ void terminal_t::set_ptrs(nl_fptype *gt, nl_fptype *go,
+ nl_fptype *Idr) noexcept(false)
+ {
+ // NOLINTNEXTLINE(readability-implicit-bool-conversion)
+ if (!(gt && go && Idr) && (gt || go || Idr))
+ {
+ throw nl_exception(
+ "Either all pointers must be set or none for terminal {}",
+ name());
+ }
-analog_input_t::analog_input_t(core_device_t &dev, const pstring &aname,
- nldelegate delegate)
-: analog_t(dev, aname, STATE_INP_ACTIVE, delegate)
-{
- state().setup().register_term(*this);
-}
+ m_gt = gt;
+ m_go = go;
+ m_Idr = Idr;
+ }
-// ----------------------------------------------------------------------------------------
-// analog_output_t
-// ----------------------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
+ // logic_t
+ // -------------------------------------------------------------------------
-analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname)
- : analog_t(dev, aname, STATE_OUT)
- , m_my_net(dev.state(), name() + ".net", this)
-{
- state().register_net(pool_owned_ptr<analog_net_t>(&m_my_net, false));
- this->set_net(&m_my_net);
+ logic_t::logic_t(device_t &dev, const pstring &aname,
+ const state_e terminal_state, nl_delegate delegate)
+ : core_terminal_t(dev, aname, terminal_state, delegate)
+ , logic_family_t(dev.logic_family())
+ {
+ }
- //net().m_cur_Analog = NL_FCONST(0.0);
- state().setup().register_term(*this);
-}
+ // -------------------------------------------------------------------------
+ // logic_input_t
+ // -------------------------------------------------------------------------
-void analog_output_t::initial(const nl_double val)
-{
- net().set_Q_Analog(val);
-}
+ logic_input_t::logic_input_t(device_t &dev, const pstring &aname,
+ nl_delegate delegate)
+ : logic_t(dev, aname, STATE_INP_ACTIVE, delegate)
+ {
+ state().setup().register_term(*this);
+ }
-// -----------------------------------------------------------------------------
-// logic_input_t
-// -----------------------------------------------------------------------------
+ // -------------------------------------------------------------------------
+ // logic_output_t
+ // -------------------------------------------------------------------------
-logic_input_t::logic_input_t(core_device_t &dev, const pstring &aname,
- nldelegate delegate)
- : logic_t(dev, aname, STATE_INP_ACTIVE, delegate)
-{
- set_logic_family(dev.logic_family());
- state().setup().register_term(*this);
-}
+ logic_output_t::logic_output_t(device_t &dev, const pstring &aname,
+ [[maybe_unused]] bool dummy)
+ : logic_t(dev, aname, STATE_OUT, nl_delegate())
+ , m_my_net(dev.state(), name() + ".net", this)
+ {
+ this->set_net(&m_my_net);
+ state().register_net(
+ device_arena::owned_ptr<logic_net_t>(&m_my_net, false));
+ state().setup().register_term(*this);
+ }
-// ----------------------------------------------------------------------------------------
-// Parameters ...
-// ----------------------------------------------------------------------------------------
+ void logic_output_t::initial(const netlist_sig_t val) noexcept
+ {
+ if (has_net())
+ net().initial(val);
+ }
-param_t::param_t(device_t &device, const pstring &name)
- : device_object_t(device, device.name() + "." + name)
-{
- device.setup().register_param_t(this->name(), *this);
-}
+ // -------------------------------------------------------------------------
+ // tristate_output_t
+ // -------------------------------------------------------------------------
+
+ tristate_output_t::tristate_output_t(device_t &dev, const pstring &aname,
+ bool force_logic)
+ : logic_output_t(dev, aname)
+ , m_last_logic(dev, name() + "." + "m_last_logic", 1) // force change
+ , m_tristate(dev, name() + "." + "m_tristate",
+ force_logic ? 0 : 2) // force change
+ , m_force_logic(force_logic)
+ {
+ }
-param_t::param_type_t param_t::param_type() const
-{
- if (dynamic_cast<const param_str_t *>(this) != nullptr)
- return STRING;
- else if (dynamic_cast<const param_double_t *>(this) != nullptr)
- return DOUBLE;
- else if (dynamic_cast<const param_int_t *>(this) != nullptr)
- return INTEGER;
- else if (dynamic_cast<const param_logic_t *>(this) != nullptr)
- return LOGIC;
- else if (dynamic_cast<const param_ptr_t *>(this) != nullptr)
- return POINTER;
- else
+ // -------------------------------------------------------------------------
+ // analog_input_t
+ // -------------------------------------------------------------------------
+
+ analog_input_t::analog_input_t(core_device_t &dev, const pstring &aname,
+ nl_delegate delegate)
+ : analog_t(dev, aname, STATE_INP_ACTIVE, delegate)
{
- state().log().fatal(MF_UNKNOWN_PARAM_TYPE(name()));
- return POINTER; /* Please compiler */
+ state().setup().register_term(*this);
}
-}
+ // -------------------------------------------------------------------------
+ // analog_output_t
+ // -------------------------------------------------------------------------
-void param_t::update_param()
-{
- device().update_param();
-}
+ analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname)
+ : analog_t(dev, aname, STATE_OUT, nl_delegate())
+ , m_my_net(dev.state(), name() + ".net", this)
+ {
+ state().register_net(
+ device_arena::owned_ptr<analog_net_t>(&m_my_net, false));
+ this->set_net(&m_my_net);
-pstring param_t::get_initial(const device_t &dev, bool *found)
-{
- pstring res = dev.setup().get_initial_param_val(this->name(), "");
- *found = (res != "");
- return res;
-}
+ // net().m_cur_Analog = NL_FCONST(0.0);
+ state().setup().register_term(*this);
+ }
-const pstring param_model_t::type()
-{
- return state().setup().models().type(str());
-}
+ void analog_output_t::initial(nl_fptype val) noexcept
+ {
+ net().set_Q_Analog(val);
+ }
-param_str_t::param_str_t(device_t &device, const pstring &name, const pstring &val)
-: param_t(device, name)
-{
- m_param = device.setup().get_initial_param_val(this->name(),val);
-}
+ // -------------------------------------------------------------------------
+ // Parameters ...
+ // -------------------------------------------------------------------------
-void param_str_t::changed()
-{
-}
+ // device-less, it's the responsibility of the owner to register!
+ param_t::param_t(const pstring &name)
+ : device_object_t(nullptr, name)
+ {
+ }
-param_ptr_t::param_ptr_t(device_t &device, const pstring &name, uint8_t * val)
-: param_t(device, name)
-{
- m_param = val; //device.setup().get_initial_param_val(this->name(),val);
- //netlist().save(*this, m_param, "m_param");
-}
+ param_t::param_t(core_device_t &device, const pstring &name)
+ : device_object_t(&device, device.name() + "." + name)
+ {
+ device.state().setup().register_param_t(*this);
+ }
-void param_model_t::changed()
-{
- state().log().fatal(MF_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME(name()));
-}
+ // placed here to avoid weak vtable warnings
+ param_t::~param_t() noexcept = default;
-const pstring param_model_t::value_str(const pstring &entity)
-{
- return state().setup().models().value_str(str(), entity);
-}
+ param_t::param_type_t param_t::param_type() const noexcept(false)
+ {
+ if (plib::dynamic_downcast<const param_str_t *>(this))
+ return STRING;
+ if (plib::dynamic_downcast<const param_fp_t *>(this))
+ return DOUBLE;
+ if (plib::dynamic_downcast<const param_int_t *>(this))
+ return INTEGER;
+ if (plib::dynamic_downcast<const param_logic_t *>(this))
+ return LOGIC;
+ if (plib::dynamic_downcast<const param_ptr_t *>(this))
+ return POINTER;
-nl_double param_model_t::value(const pstring &entity)
-{
- return state().setup().models().value(str(), entity);
-}
+ state().log().fatal(MF_UNKNOWN_PARAM_TYPE(name()));
+ throw nl_exception(MF_UNKNOWN_PARAM_TYPE(name()));
+ }
+ pstring param_t::get_initial(const core_device_t *dev, bool *found) const
+ {
+ pstring res = dev->state().setup().get_initial_param_val(this->name(),
+ "");
+ *found = (!res.empty());
+ return res;
+ }
-plib::unique_ptr<std::istream> param_data_t::stream()
-{
- return device().setup().get_data_stream(str());
-}
+ param_str_t::param_str_t(core_device_t &device, const pstring &name,
+ const pstring &val)
+ : param_t(device, name)
+ {
+ m_param = plib::make_unique<pstring, host_arena>(val);
+ *m_param = device.state().setup().get_initial_param_val(this->name(),
+ val);
+ }
- bool detail::core_terminal_t::is_logic() const NL_NOEXCEPT
+ param_str_t::param_str_t(netlist_state_t &state, const pstring &name,
+ const pstring &val)
+ : param_t(name)
{
- return dynamic_cast<const logic_t *>(this) != nullptr;
+ // device-less parameter, no registration, owner is responsible
+ m_param = plib::make_unique<pstring, host_arena>(val);
+ *m_param = state.setup().get_initial_param_val(this->name(), val);
}
- bool detail::core_terminal_t::is_logic_input() const NL_NOEXCEPT
+ void param_str_t::changed() noexcept {}
+
+ param_ptr_t::param_ptr_t(core_device_t &device, const pstring &name,
+ uint8_t *val)
+ : param_t(device, name)
+ , m_param(val)
{
- return dynamic_cast<const logic_input_t *>(this) != nullptr;
}
- bool detail::core_terminal_t::is_logic_output() const NL_NOEXCEPT
+ void param_model_t::changed() noexcept {}
+
+ pstring param_model_t::type()
{
- return dynamic_cast<const logic_output_t *>(this) != nullptr;
+ auto mod = state().setup().models().get_model(str());
+ return mod.type();
}
- bool detail::core_terminal_t::is_analog() const NL_NOEXCEPT
+ pstring param_model_t::value_str(const pstring &entity)
{
- return dynamic_cast<const analog_t *>(this) != nullptr;
+ return state().setup().models().get_model(str()).value_str(entity);
}
- bool detail::core_terminal_t::is_analog_input() const NL_NOEXCEPT
+ nl_fptype param_model_t::value(const pstring &entity)
{
- return dynamic_cast<const analog_input_t *>(this) != nullptr;
+ return state().setup().models().get_model(str()).value(entity);
}
- bool detail::core_terminal_t::is_analog_output() const NL_NOEXCEPT
+ plib::istream_uptr param_data_t::stream()
{
- return dynamic_cast<const analog_output_t *>(this) != nullptr;
+ return device().state().parser().get_data_stream(str());
}
+ // -------------------------------------------------------------------------
+ // netlist_t
+ //
+ // Hot section
+ //
+ // Any changes below will impact performance.
+ // -------------------------------------------------------------------------
- bool detail::net_t::is_logic() const NL_NOEXCEPT
+ template <bool KEEP_STATS>
+ void netlist_t::process_queue_stats(const netlist_time_ext delta) noexcept
{
- return dynamic_cast<const logic_net_t *>(this) != nullptr;
+ netlist_time_ext stop(m_time + delta);
+
+ queue_push(stop, nullptr);
+
+ if (m_main_clock == nullptr)
+ {
+ m_time = m_queue.top().exec_time();
+ detail::net_t *obj(m_queue.top().object());
+ m_queue.pop();
+
+ while (obj != nullptr)
+ {
+ obj->template update_devs<KEEP_STATS>();
+ if (KEEP_STATS)
+ m_perf_out_processed.inc();
+ const detail::queue_t::entry_t *top = &m_queue.top();
+ m_time = top->exec_time();
+ obj = top->object();
+ m_queue.pop();
+ }
+ }
+ else
+ {
+ logic_net_t & mc_net(m_main_clock->m_Q.net());
+ const netlist_time inc(m_main_clock->m_inc);
+ netlist_time_ext mc_time(mc_net.next_scheduled_time());
+
+ do
+ {
+ const detail::queue_t::entry_t *top = &m_queue.top();
+ while (top->exec_time() > mc_time)
+ {
+ m_time = mc_time;
+ mc_net.toggle_new_Q();
+ mc_net.update_devs<KEEP_STATS>();
+ top = &m_queue.top();
+ mc_time += inc;
+ }
+
+ m_time = top->exec_time();
+ detail::net_t *const obj(top->object());
+ m_queue.pop();
+
+ if (!!(obj == nullptr))
+ break;
+
+ obj->template update_devs<KEEP_STATS>();
+
+ if (KEEP_STATS)
+ m_perf_out_processed.inc();
+ } while (true);
+
+ mc_net.set_next_scheduled_time(mc_time);
+ }
}
- bool detail::net_t::is_analog() const NL_NOEXCEPT
+ void netlist_t::process_queue(netlist_time_ext delta) noexcept
{
- return dynamic_cast<const analog_net_t *>(this) != nullptr;
+ if (!m_use_stats)
+ process_queue_stats<false>(delta);
+ else
+ {
+ auto sm_guard(m_stat_mainloop.guard());
+ process_queue_stats<true>(delta);
+ }
}
+ template struct state_var<std::uint8_t>;
+ template struct state_var<std::uint16_t>;
+ template struct state_var<std::uint32_t>;
+ template struct state_var<std::uint64_t>;
+ template struct state_var<std::int8_t>;
+ template struct state_var<std::int16_t>;
+ template struct state_var<std::int32_t>;
+ template struct state_var<std::int64_t>;
+ template struct state_var<bool>;
+
+ template class param_num_t<std::uint8_t>;
+ template class param_num_t<std::uint16_t>;
+ template class param_num_t<std::uint32_t>;
+ template class param_num_t<std::uint64_t>;
+ template class param_num_t<std::int8_t>;
+ template class param_num_t<std::int16_t>;
+ template class param_num_t<std::int32_t>;
+ template class param_num_t<std::int64_t>;
+ template class param_num_t<long double>;
+ template class param_num_t<double>;
+ template class param_num_t<float>;
+ template class param_num_t<bool>;
+
+ template class param_model_t::value_base_t<float>;
+ template class param_model_t::value_base_t<double>;
+ template class param_model_t::value_base_t<long double>;
+
+ template class object_array_t<logic_input_t, 1>;
+ template class object_array_t<logic_input_t, 2>;
+ template class object_array_t<logic_input_t, 3>;
+ template class object_array_t<logic_input_t, 4>;
+ template class object_array_t<logic_input_t, 5>;
+ template class object_array_t<logic_input_t, 6>;
+ template class object_array_t<logic_input_t, 7>;
+ template class object_array_t<logic_input_t, 8>;
+
+ template class object_array_t<logic_output_t, 1>;
+ template class object_array_t<logic_output_t, 2>;
+ template class object_array_t<logic_output_t, 3>;
+ template class object_array_t<logic_output_t, 4>;
+ template class object_array_t<logic_output_t, 5>;
+ template class object_array_t<logic_output_t, 6>;
+ template class object_array_t<logic_output_t, 7>;
+ template class object_array_t<logic_output_t, 8>;
} // namespace netlist