summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author couriersud <couriersud@gmx.org>2020-07-25 14:44:54 +0200
committer couriersud <couriersud@gmx.org>2020-07-25 14:47:22 +0200
commit2231bf8ae0ab6e752e394ad2c84d843d6a19d0f8 (patch)
tree252740e29ae17263d208cc896543ad3e5ce0f63f
parent016c636bb38824031082b100e667596508822cdd (diff)
netlist: Rewrote scheduler scheduling.
* All solver scheduling is now handled by nld_solver. * Previously, for dynamic timestepping the sub solvers would be responsible for their scheduling themselves. - This prevented any attemps to use parallel execution of solvers. * Now the route is free towards experiments to use parallel execution of solvers. * Uses ptimed_queue_linear in solver scheduling * Improved netlist queue implementation (template now) * Added const delegates. * Added subsolver stats * Removed dead code.
-rw-r--r--src/lib/netlist/analog/nld_mosfet.cpp11
-rw-r--r--src/lib/netlist/analog/nlid_fourterm.cpp17
-rw-r--r--src/lib/netlist/analog/nlid_twoterm.h4
-rw-r--r--src/lib/netlist/build/makefile2
-rw-r--r--src/lib/netlist/devices/nld_4316.cpp3
-rw-r--r--src/lib/netlist/devices/nlid_truthtable.cpp8
-rw-r--r--src/lib/netlist/nl_base.cpp79
-rw-r--r--src/lib/netlist/nl_base.h114
-rw-r--r--src/lib/netlist/nl_config.h4
-rw-r--r--src/lib/netlist/plib/pchrono.h6
-rwxr-xr-xsrc/lib/netlist/plib/plists.h114
-rw-r--r--src/lib/netlist/plib/ppmf.h25
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.cpp39
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.h47
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver_ext.h9
-rw-r--r--src/lib/netlist/solver/nld_solver.cpp129
-rw-r--r--src/lib/netlist/solver/nld_solver.h28
-rw-r--r--src/mame/audio/nl_kidniki.cpp2
18 files changed, 420 insertions, 221 deletions
diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp
index 0bc46adb002..acc7ad8359f 100644
--- a/src/lib/netlist/analog/nld_mosfet.cpp
+++ b/src/lib/netlist/analog/nld_mosfet.cpp
@@ -333,13 +333,12 @@ namespace analog
NETLIB_HANDLERI(termhandler)
{
- // FIXME: This should never be called
- if (!m_SG.P().net().is_rail_net())
- m_SG.P().solve_now(); // Basis
- else if (!m_SG.N().net().is_rail_net())
- m_SG.N().solve_now(); // Emitter
+ // only called if connected to a rail net ==> notify the solver to recalculate
+ auto *solv(m_SG.solver());
+ if (solv != nullptr)
+ solv->solve_now();
else
- m_DG.N().solve_now(); // Collector
+ m_DG.solver()->solve_now();
}
NETLIB_UPDATE_PARAMI();
NETLIB_UPDATE_TERMINALSI();
diff --git a/src/lib/netlist/analog/nlid_fourterm.cpp b/src/lib/netlist/analog/nlid_fourterm.cpp
index ed3ff1ca579..14276fcb66b 100644
--- a/src/lib/netlist/analog/nlid_fourterm.cpp
+++ b/src/lib/netlist/analog/nlid_fourterm.cpp
@@ -32,15 +32,16 @@ NETLIB_RESET(VCCS)
NETLIB_HANDLER(VCCS, termhandler)
{
+ solver::matrix_solver_t *solv = nullptr;
// only called if connected to a rail net ==> notify the solver to recalculate
- if (!m_IP.net().is_rail_net())
- m_IP.solve_now();
- else if (!m_IN.net().is_rail_net())
- m_IN.solve_now();
- else if (!m_OP.net().is_rail_net())
- m_OP.solve_now();
- else if (!m_ON.net().is_rail_net())
- m_ON.solve_now();
+ 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();
}
// ----------------------------------------------------------------------------------------
diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h
index 66b6d97ffe9..4e6dae91cb1 100644
--- a/src/lib/netlist/analog/nlid_twoterm.h
+++ b/src/lib/netlist/analog/nlid_twoterm.h
@@ -96,11 +96,11 @@ namespace analog
void solve_now() const;
template <typename F>
- void change_state(F f, netlist_time delay = netlist_time::quantum()) const
+ void change_state(F f) const
{
auto *solv(solver());
if (solv)
- solv->change_state(f, delay);
+ solv->change_state(f);
}
void set_G_V_I(nl_fptype G, nl_fptype V, nl_fptype I) const noexcept
diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile
index ce7060c4dea..e46e1ac4c26 100644
--- a/src/lib/netlist/build/makefile
+++ b/src/lib/netlist/build/makefile
@@ -320,7 +320,7 @@ clang-libc:
-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-return-std-move-in-c++11 -Wunreachable-code" \
+ -Wno-return-std-move-in-c++11 -Wno-unreachable-code" \
LDEXTRAFLAGS=-stdlib=libc++
clang-5:
diff --git a/src/lib/netlist/devices/nld_4316.cpp b/src/lib/netlist/devices/nld_4316.cpp
index b5b7fa80760..7c0159dbe91 100644
--- a/src/lib/netlist/devices/nld_4316.cpp
+++ b/src/lib/netlist/devices/nld_4316.cpp
@@ -37,8 +37,7 @@ namespace netlist { namespace devices {
m_R.set_R(m_base_r());
else
m_R.set_R(plib::reciprocal(exec().gmin()));
- }
- , NLTIME_FROM_NS(1));
+ });
}
private:
diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp
index 8614f949f77..947b2651acb 100644
--- a/src/lib/netlist/devices/nlid_truthtable.cpp
+++ b/src/lib/netlist/devices/nlid_truthtable.cpp
@@ -193,8 +193,8 @@ namespace devices
}
- plib::uninitialised_array_t<logic_input_t, m_NI> m_I;
- plib::uninitialised_array_t<logic_output_t, m_NO> m_Q;
+ plib::static_vector<logic_input_t, m_NI> m_I;
+ plib::static_vector<logic_output_t, m_NO> m_Q;
#if USE_TT_ALTERNATIVE
state_var<type_t> m_state;
@@ -389,7 +389,7 @@ namespace devices
for (std::size_t i=0; i < m_NI; i++)
{
inout[i] = plib::trim(inout[i]);
- m_I.emplace(i, *this, inout[i], nldelegate(&NETLIB_NAME(truthtable_t)<m_NI, m_NO> :: inputs, this));
+ m_I.emplace_back(*this, inout[i], nldelegate(&NETLIB_NAME(truthtable_t)<m_NI, m_NO> :: inputs, this));
}
#else
for (std::size_t i=0; i < m_NI; i++)
@@ -412,7 +412,7 @@ namespace devices
for (std::size_t i=0; i < m_NO; i++)
{
outputs[i] = plib::trim(outputs[i]);
- m_Q.emplace(i, *this, outputs[i]);
+ m_Q.emplace_back(*this, outputs[i]);
// Connect output "Q" to input "_Q" if this exists
// This enables timed state without having explicit state ....
pstring tmp = "_" + outputs[i];
diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp
index 078236da474..61265e9cb65 100644
--- a/src/lib/netlist/nl_base.cpp
+++ b/src/lib/netlist/nl_base.cpp
@@ -36,45 +36,6 @@ namespace netlist
// queue_t
// ----------------------------------------------------------------------------------------
- detail::queue_t::queue_t(netlist_t &nl, const pstring &name)
- : timed_queue<plib::pqentry_t<netlist_time_ext, net_t *>, false>(config::MAX_QUEUE_SIZE::value)
- , netlist_object_t(nl, name)
- , m_qsize(0)
- , m_times(config::MAX_QUEUE_SIZE::value)
- , m_net_ids(config::MAX_QUEUE_SIZE::value)
- {
- }
-
- 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());
- }
-
- 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++ )
- {
- m_times[i] = this->listptr()[i].exec_time().as_raw();
- m_net_ids[i] = state().find_net_id(this->listptr()[i].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++ )
- {
- detail::net_t *n = state().nets()[m_net_ids[i]].get();
- this->push<false>(queue_t::entry_t(netlist_time_ext::from_raw(m_times[i]),n));
- }
- }
-
// ----------------------------------------------------------------------------------------
// device_object_t
// ----------------------------------------------------------------------------------------
@@ -101,6 +62,30 @@ namespace netlist
//return terminal_type::TERMINAL; // please compiler
}
+ netlist_state_t &detail::device_object_t::state() noexcept
+ {
+ return m_device->state();
+ }
+
+ const netlist_state_t &detail::device_object_t::state() const noexcept
+ {
+ return m_device->state();
+ }
+
+ // ----------------------------------------------------------------------------------------
+ // netlist_object_t
+ // ----------------------------------------------------------------------------------------
+
+ netlist_state_t & detail::netlist_object_t::state() noexcept
+ {
+ return m_netlist.nlstate();
+ }
+
+ const netlist_state_t & detail::netlist_object_t::state() const noexcept
+ {
+ return m_netlist.nlstate();
+ }
+
// ----------------------------------------------------------------------------------------
// netlist_t
// ----------------------------------------------------------------------------------------
@@ -110,7 +95,9 @@ namespace netlist
, m_solver(nullptr)
, m_time(netlist_time_ext::zero())
, m_mainclock(nullptr)
- , m_queue(*this, aname + "." + "m_queue")
+ , m_queue(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))
, m_use_stats(false)
{
state.save(*this, static_cast<plib::state_manager_t::callback_t &>(m_queue), aname, "m_queue");
@@ -175,6 +162,10 @@ namespace netlist
return i;
return std::numeric_limits<std::size_t>::max();
}
+ detail::net_t *netlist_state_t::net_by_id(std::size_t id) const
+ {
+ return m_nets[id].get();
+ }
void netlist_state_t::rebuild_lists()
{
@@ -702,14 +693,6 @@ namespace netlist
state().setup().register_term(*this, *otherterm);
}
- void terminal_t::solve_now() const
- {
- const auto *solv(solver());
- // Nets may belong to railnets which do not have a solver attached
- if (solv != nullptr)
- solver()->solve_now();
- }
-
void terminal_t::set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false)
{
// NOLINTNEXTLINE(readability-implicit-bool-conversion)
diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h
index 7e113214820..66caae7519c 100644
--- a/src/lib/netlist/nl_base.h
+++ b/src/lib/netlist/nl_base.h
@@ -356,7 +356,12 @@ namespace netlist
//! Copy Constructor removed.
constexpr state_var(const state_var &rhs) = delete;
//! Assignment operator to assign value of a state var.
- constexpr state_var &operator=(const state_var &rhs) noexcept { m_value = rhs.m_value; return *this; } // OSX doesn't like noexcept
+ constexpr state_var &operator=(const state_var &rhs) noexcept
+ {
+ if (this != &rhs)
+ m_value = rhs.m_value;
+ 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; }
//! Assignment move operator to assign value of type T.
@@ -870,11 +875,6 @@ namespace netlist
}
}
- /// @brief Solve the system this terminal is connected to.
- ///
- /// \note deprecated - will be removed
- void solve_now() const; // FIXME: remove this
-
void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false);
private:
@@ -1498,35 +1498,73 @@ namespace netlist
// We don't need a thread-safe queue currently. Parallel processing of
// solvers will update inputs after parallel processing.
- class queue_t :
- //public timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>,
- public timed_queue<plib::pqentry_t<netlist_time_ext, net_t *>, false>,
- public netlist_object_t,
+ template <typename O, bool TS>
+ class queue_base :
+ public timed_queue<plib::pqentry_t<netlist_time_ext, O *>, false>,
public plib::state_manager_t::callback_t
{
public:
- using entry_t = plib::pqentry_t<netlist_time_ext, net_t *>;
+ using entry_t = plib::pqentry_t<netlist_time_ext, O *>;
using base_queue = timed_queue<entry_t, false>;
- explicit queue_t(netlist_t &nl, const pstring &name);
- ~queue_t() noexcept override = default;
+ using id_delegate = plib::pmfp<std::size_t, const O *>;
+ using obj_delegate = plib::pmfp<O *, std::size_t>;
+
+ explicit queue_base(std::size_t size, id_delegate get_id, obj_delegate get_obj)
+ : timed_queue<plib::pqentry_t<netlist_time_ext, O *>, false>(size)
+ , m_qsize(0)
+ , m_times(size)
+ , m_net_ids(size)
+ , m_get_id(get_id)
+ , m_obj_by_id(get_obj)
+ {
+ }
+
+ ~queue_base() noexcept override = default;
- queue_t(const queue_t &) = delete;
- queue_t(queue_t &&) = delete;
- queue_t &operator=(const queue_t &) = delete;
- queue_t &operator=(queue_t &&) = delete;
+ queue_base(const queue_base &) = delete;
+ queue_base(queue_base &&) = delete;
+ queue_base &operator=(const queue_base &) = delete;
+ queue_base &operator=(queue_base &&) = delete;
protected:
- void register_state(plib::state_manager_t &manager, const pstring &module) override;
- void on_pre_save(plib::state_manager_t &manager) override;
- void on_post_load(plib::state_manager_t &manager) override;
+ void register_state(plib::state_manager_t &manager, const pstring &module) override
+ {
+ manager.save_item(this, m_qsize, module + "." + "qsize");
+ manager.save_item(this, &m_times[0], module + "." + "times", m_times.size());
+ manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size());
+ }
+ void on_pre_save(plib::state_manager_t &manager) override
+ {
+ plib::unused_var(manager);
+ m_qsize = this->size();
+ for (std::size_t i = 0; i < m_qsize; i++ )
+ {
+ m_times[i] = this->listptr()[i].exec_time().as_raw();
+ m_net_ids[i] = m_get_id(this->listptr()[i].object());
+ }
+ }
+ void on_post_load(plib::state_manager_t &manager) override
+ {
+ plib::unused_var(manager);
+ this->clear();
+ for (std::size_t i = 0; i < m_qsize; 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));
+ }
+ }
private:
std::size_t m_qsize;
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;
};
+ using queue_t = queue_base<net_t, false>;
+
} // namespace detail
// -----------------------------------------------------------------------------
@@ -1620,6 +1658,7 @@ namespace netlist
// FIXME: only used by queue_t save state
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)); }
@@ -1883,6 +1922,7 @@ namespace netlist
const log_type &log() const noexcept { return m_state.log(); }
void print_stats() const;
+ bool use_stats() const { return m_use_stats; }
bool stats_enabled() const noexcept { return m_use_stats; }
void enable_stats(bool val) noexcept { m_use_stats = val; }
@@ -1914,7 +1954,7 @@ namespace netlist
// -----------------------------------------------------------------------------
template<class C, std::size_t N>
- class object_array_base_t : public plib::uninitialised_array_t<C, N>
+ class object_array_base_t : public plib::static_vector<C, N>
{
public:
template<class D, typename... Args>
@@ -1922,28 +1962,28 @@ namespace netlist
object_array_base_t(D &dev, std::array<const char *, N> &&names, Args&&... args)
{
for (std::size_t i = 0; i<N; i++)
- this->emplace(i, dev, pstring(names[i]), std::forward<Args>(args)...);
+ this->emplace_back(dev, pstring(names[i]), std::forward<Args>(args)...);
}
template<class D>
object_array_base_t(D &dev, const pstring &fmt)
{
for (std::size_t i = 0; i<N; i++)
- this->emplace(i, dev, formatted(fmt, i));
+ this->emplace_back(dev, formatted(fmt, i));
}
template<class D, typename... Args>
object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, Args&&... args)
{
for (std::size_t i = 0; i<N; i++)
- this->emplace(i, dev, formatted(fmt, i+offset), std::forward<Args>(args)...);
+ this->emplace_back(dev, formatted(fmt, i+offset), std::forward<Args>(args)...);
}
template<class D>
object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, nldelegate delegate)
{
for (std::size_t i = 0; i<N; i++)
- this->emplace(i, dev, formatted(fmt, i+offset), delegate);
+ this->emplace_back(dev, formatted(fmt, i+offset), delegate);
}
template<class D>
@@ -1988,7 +2028,7 @@ namespace netlist
object_array_t(D &dev, std::size_t offset, std::size_t qmask,
const pstring &fmt, std::array<nldelegate, ND> &&delegates)
{
- passert_always_msg(delegates.size() >= N, "initializer_list size mismatch");
+ static_assert(N <= ND, "initializer_list size mismatch");
std::size_t i = 0;
for (auto &e : delegates)
{
@@ -1997,7 +2037,7 @@ namespace netlist
pstring name(this->formatted(fmt, i+offset));
if ((qmask >> i) & 1)
name += "Q";
- this->emplace(i, dev, name, e);
+ this->emplace_back(dev, name, e);
}
i++;
}
@@ -2437,16 +2477,6 @@ namespace netlist
// inline implementations - cold
// -----------------------------------------------------------------------------
- inline netlist_state_t & detail::netlist_object_t::state() noexcept
- {
- return m_netlist.nlstate();
- }
-
- inline const netlist_state_t & detail::netlist_object_t::state() const noexcept
- {
- return m_netlist.nlstate();
- }
-
template<typename T, typename... Args>
inline device_arena::unique_ptr<T> detail::netlist_object_t::make_pool_object(Args&&... args)
{
@@ -2521,16 +2551,6 @@ namespace netlist
dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...);
}
- inline netlist_state_t &detail::device_object_t::state() noexcept
- {
- return m_device->state();
- }
-
- inline const netlist_state_t &detail::device_object_t::state() const noexcept
- {
- return m_device->state();
- }
-
inline solver::matrix_solver_t *analog_t::solver() const noexcept
{
return (this->has_net() ? net().solver() : nullptr);
diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h
index ed8953ba842..061c77b1c6c 100644
--- a/src/lib/netlist/nl_config.h
+++ b/src/lib/netlist/nl_config.h
@@ -225,6 +225,10 @@ namespace netlist
///
using MAX_QUEUE_SIZE = std::integral_constant<std::size_t, 512>; // NOLINT
+ /// \brief Maximum queue size for solvers
+ ///
+ using MAX_SOLVER_QUEUE_SIZE = std::integral_constant<std::size_t, 64>; // NOLINT
+
using use_float_matrix = std::integral_constant<bool, NL_USE_FLOAT_MATRIX>;
using use_long_double_matrix = std::integral_constant<bool, NL_USE_LONG_DOUBLE_MATRIX>;
using use_float128_matrix = std::integral_constant<bool, NL_USE_FLOAT128>;
diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h
index 4a5e77d9ca2..03edeeebe6f 100644
--- a/src/lib/netlist/plib/pchrono.h
+++ b/src/lib/netlist/plib/pchrono.h
@@ -217,6 +217,12 @@ namespace plib {
/ narrow_cast<S>(T::per_second()); }
guard_t guard() noexcept { return guard_t(*this); }
+
+ // pause must be followed by cont(inue)
+ void pause() noexcept { m_time += T::stop(); }
+ void cont() noexcept { m_time -= T::start(); }
+
+
private:
type m_time;
ctype m_count;
diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h
index 6929a10601b..328f0b1ad23 100755
--- a/src/lib/netlist/plib/plists.h
+++ b/src/lib/netlist/plib/plists.h
@@ -17,14 +17,13 @@
namespace plib {
- /// \brief fixed size array allowing to override constructor and initialize members by placement new.
+ /// \brief Array holding uninitialized elements
///
/// Use with care. This template is provided to improve locality of storage
/// in high frequency applications. It should not be used for anything else.
///
- ///
template <class C, std::size_t N>
- class uninitialised_array_t
+ class uninitialised_array
{
public:
@@ -41,18 +40,10 @@ namespace plib {
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
//uninitialised_array_t() noexcept = default;
- uninitialised_array_t() noexcept
- : m_initialized(0)
- {
- }
+ uninitialised_array() noexcept = default;
- PCOPYASSIGNMOVE(uninitialised_array_t, delete)
- ~uninitialised_array_t() noexcept
- {
- if (m_initialized>=N)
- for (size_type i=0; i<N; ++i)
- (*this)[i].~C();
- }
+ PCOPYASSIGNMOVE(uninitialised_array, delete)
+ ~uninitialised_array() noexcept = default;
constexpr size_t size() const noexcept { return N; }
@@ -70,34 +61,113 @@ namespace plib {
return reinterpret_cast<const_reference>(m_buf[index]);
}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); }
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + N); }
+
+ protected:
+
+ private:
+ std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf;
+ };
+
+ /// \brief fixed allocation vector
+ ///
+ /// Currently only emplace_back and clear are supported.
+ ///
+ /// Use with care. This template is provided to improve locality of storage
+ /// in high frequency applications. It should not be used for anything else.
+ ///
+ template <class C, std::size_t N>
+ class static_vector
+ {
+ public:
+
+ using value_type = C;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using iterator = value_type *;
+ using const_iterator = const value_type *;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ static_vector() noexcept
+ : m_pos(0)
+ {
+ }
+
+ PCOPYASSIGNMOVE(static_vector, delete)
+ ~static_vector() noexcept
+ {
+ clear();
+ }
+
+ constexpr size_t size() const noexcept { return m_pos; }
+
+ constexpr bool empty() const noexcept { return size() == 0; }
+
+ void clear()
+ {
+ for (size_type i=0; i<m_pos; ++i)
+ (*this)[i].~C();
+ m_pos = 0;
+ }
+
template<typename... Args>
- void emplace(size_type index, Args&&... args)
+ void emplace_back(Args&&... args)
+ {
+ // placement new on buffer
+ new (&m_buf[m_pos]) C(std::forward<Args>(args)...);
+ m_pos++;
+ }
+
+ reference operator[](size_type index) noexcept
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return reinterpret_cast<reference>(m_buf[index]);
+ }
+
+ constexpr const_reference operator[](size_type index) const noexcept
{
- m_initialized++;
- // allocate on buffer
- new (&m_buf[index]) C(std::forward<Args>(args)...);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ return reinterpret_cast<const_reference>(m_buf[index]);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); }
+ iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + m_pos); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); }
+ iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + m_pos); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); }
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + N); }
+ const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + m_pos); }
protected:
private:
std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf;
- unsigned m_initialized;
+ size_type m_pos;
};
/// \brief a simple linked list.
diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h
index 75e2e3b184d..6dd80758ad5 100644
--- a/src/lib/netlist/plib/ppmf.h
+++ b/src/lib/netlist/plib/ppmf.h
@@ -233,6 +233,9 @@ namespace plib {
template <class C>
using specific_member_function = R (C::*)(Targs...);
+ template <class C>
+ using const_specific_member_function = R (C::*)(Targs...) const;
+
using generic_member_function = specific_member_function<generic_class>;
template <class C>
@@ -320,6 +323,9 @@ namespace plib {
template <class C>
using specific_member_function = typename helper::template specific_member_function<C>;
+ template <class C>
+ using const_specific_member_function = typename helper::template const_specific_member_function<C>;
+
using generic_class = typename helper::generic_class;
using generic_member_function = typename helper::generic_member_function;
@@ -343,7 +349,17 @@ namespace plib {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved);
std::fill(s, s + sizeof(m_resolved), 0);
- bind(object, &mftp);
+ bind<specific_member_function<O>>(object, &mftp);
+ }
+
+ template<typename O>
+ pmfp_base(const_specific_member_function<O> mftp, O *object)
+ : m_obj(nullptr)
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ auto *s = reinterpret_cast<std::uint8_t *>(&m_resolved);
+ std::fill(s, s + sizeof(m_resolved), 0);
+ bind<const_specific_member_function<O>>(object, &mftp);
}
bool is_set() const noexcept { return m_resolved != nullptr; }
@@ -354,7 +370,7 @@ namespace plib {
template<typename O>
void set(specific_member_function<O> mftp, O *object)
{
- bind(object, &mftp);
+ bind<specific_member_function<O>>(object, &mftp);
}
inline R operator()(Targs... args) const noexcept(true)
@@ -363,11 +379,10 @@ namespace plib {
}
private:
- template<typename O, typename MF>
+ template<typename SPC, typename O, typename MF>
void bind(O * object, MF *fraw)
{
- //auto pFunc = *reinterpret_cast<specific_member_function<O> *>(fraw); // mftp;
- specific_member_function<O> pFunc;
+ SPC pFunc;
static_assert(sizeof(pFunc) >= sizeof(MF), "size error");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
*reinterpret_cast<MF *>(&pFunc) = *fraw;
diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp
index 0b08f198f57..871eff3dca3 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.cpp
+++ b/src/lib/netlist/solver/nld_matrix_solver.cpp
@@ -42,6 +42,7 @@ namespace solver
const net_list_t &nets,
const solver_parameters_t *params)
: device_t(static_cast<device_t &>(main_solver), name)
+ , m_next_exec(*this, "m_next_exec", netlist_time_ext::zero())
, m_params(*params)
, m_iterative_fail(*this, "m_iterative_fail", 0)
, m_iterative_total(*this, "m_iterative_total", 0)
@@ -51,16 +52,8 @@ namespace solver
, m_stat_newton_raphson_fail(*this, "m_stat_newton_raphson_fail", 0)
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
, m_last_step(*this, "m_last_step", netlist_time_ext::zero())
- , m_fb_sync(*this, "FB_sync", nldelegate(&matrix_solver_t::fb_sync, this))
- , m_Q_sync(*this, "Q_sync")
, m_ops(0)
{
- if (!this->state().setup().connect(m_fb_sync, m_Q_sync))
- {
- // FIXME: avoid clang warning for now
- m_main_solver.state().log().fatal(MF_ERROR_CONNECTING_1_TO_2(m_fb_sync.name(), m_Q_sync.name()));
- throw nl_exception(MF_ERROR_CONNECTING_1_TO_2(m_fb_sync.name(), m_Q_sync.name()));
- }
setup_base(this->state().setup(), nets);
// now setup the matrix
@@ -72,6 +65,11 @@ namespace solver
return &state().setup().get_connected_terminal(*term)->net();
}
+ void matrix_solver_t::reschedule(netlist_time ts)
+ {
+ m_main_solver.reschedule(this, ts);
+ }
+
void matrix_solver_t::setup_base(setup_t &setup, const net_list_t &nets)
{
log().debug("New solver setup\n");
@@ -495,18 +493,11 @@ namespace solver
if (m_stat_newton_raphson % 100 == 0)
log().warning(MW_NEWTON_LOOPS_EXCEEDED_INVOCATION_3(100, this->name(), exec().time().as_double() * 1e6));
- if (resched && !m_Q_sync.net().is_queued())
+ if (resched)
{
// reschedule ....
log().warning(MW_NEWTON_LOOPS_EXCEEDED_ON_NET_2(this->name(), exec().time().as_double() * 1e6));
- // FIXME: test and enable - this is working better, though not optimal yet
-#if 0
- // Don't store, the result can not be used
return netlist_time::from_fp(m_params.m_nr_recalc_delay());
-#else
- //restore(); // restore old voltages
- m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_nr_recalc_delay()));
-#endif
}
if (m_params.m_dynamic_ts)
return next_time_step;
@@ -514,16 +505,17 @@ namespace solver
return netlist_time::from_fp(m_params.m_max_timestep);
}
- netlist_time matrix_solver_t::solve(netlist_time_ext now)
+ netlist_time matrix_solver_t::solve(netlist_time_ext now, const char *source)
{
netlist_time_ext delta = now - m_last_step();
PFDEBUG(printf("solve %.10f\n", delta.as_double());)
+ plib::unused_var(source);
// We are already up to date. Avoid oscillations.
// FIXME: Make this a parameter!
if (delta < netlist_time_ext::quantum())
{
- PFDEBUG(printf("solve return\n");)
+ //printf("solve return %s at %f\n", source, now.as_double());
return netlist_time::zero();
}
@@ -549,9 +541,16 @@ namespace solver
}
if (m_params.m_dynamic_ts)
- return compute_next_timestep(delta.as_fp<nl_fptype>(), m_params.m_min_timestep, m_params.m_max_timestep);
+ {
+ if (timestep_device_count() > 0)
+ return compute_next_timestep(delta.as_fp<nl_fptype>(), m_params.m_min_timestep, m_params.m_max_timestep);
+ }
+
+ if (timestep_device_count() > 0)
+ return netlist_time::from_fp(m_params.m_max_timestep);
+
+ return netlist_time::zero();
- return netlist_time::from_fp(m_params.m_max_timestep);
}
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h
index fb63648673e..feb7d6bbd42 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.h
+++ b/src/lib/netlist/solver/nld_matrix_solver.h
@@ -197,7 +197,7 @@ namespace solver
// after every call to solve, update inputs must be called.
// this can be done as well as a batch to ease parallel processing.
- netlist_time solve(netlist_time_ext now);
+ netlist_time solve(netlist_time_ext now, const char *source);
void update_inputs();
/// \brief Checks if solver may alter a net
@@ -211,6 +211,12 @@ namespace solver
std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); }
std::size_t timestep_device_count() const noexcept { return m_step_funcs.size(); }
+ /// \brief reschedule solver execution
+ ///
+ /// Calls reschedule on main solver
+ ///
+ void reschedule(netlist_time ts);
+
/// \brief Immediately solve system at current time
///
/// This should only be called from update and update_param events.
@@ -221,47 +227,35 @@ namespace solver
// this should only occur outside of execution and thus
// using time should be safe.
- const netlist_time new_timestep = solve(exec().time());
+ const netlist_time new_timestep = solve(exec().time(), "solve_now");
plib::unused_var(new_timestep);
update_inputs();
if (m_params.m_dynamic_ts && (timestep_device_count() != 0))
{
- m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_min_timestep));
+ this->reschedule(netlist_time::from_fp(m_params.m_min_timestep));
}
}
template <typename F>
- void change_state(F f, netlist_time delay = netlist_time::quantum())
+ void change_state(F f)
{
// We only need to update the net first if this is a time stepping net
if (timestep_device_count() > 0)
{
- const netlist_time new_timestep = solve(exec().time());
+ const netlist_time new_timestep = solve(exec().time(), "change_state");
plib::unused_var(new_timestep);
update_inputs();
}
f();
- if ((delay == netlist_time::quantum()) && (timestep_device_count() > 0))
+ if (timestep_device_count() > 0)
{
PFDEBUG(printf("here2\n");)
- m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_min_ts_ts()));
+ this->reschedule(netlist_time::from_fp(m_params.m_min_ts_ts()));
}
else
- m_Q_sync.net().toggle_and_push_to_queue(delay);
- }
-
- NETLIB_HANDLERI(fb_sync)
- {
- PFDEBUG(printf("update\n");)
- const netlist_time new_timestep = solve(exec().time());
- update_inputs();
-
- if (m_params.m_dynamic_ts && (timestep_device_count() != 0) && new_timestep > netlist_time::zero())
- {
- m_Q_sync.net().toggle_and_push_to_queue(new_timestep);
- }
+ this->reschedule(netlist_time::quantum());
}
NETLIB_RESETI();
@@ -277,6 +271,8 @@ namespace solver
// return number of floating point operations for solve
constexpr std::size_t ops() const { return m_ops; }
+ state_var<netlist_time_ext> m_next_exec;
+ std::size_t id = 0; // FIXME - testing
protected:
matrix_solver_t(devices::nld_solver &main_solver, const pstring &name,
const net_list_t &nets,
@@ -289,6 +285,14 @@ namespace solver
virtual void backup() = 0;
virtual void restore() = 0;
+ std::size_t max_railstart() 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].railstart());
+ return max_rail;
+ }
+
plib::pmatrix2d_vrl<fptype, arena_type> m_gonn;
plib::pmatrix2d_vrl<fptype, arena_type> m_gtn;
plib::pmatrix2d_vrl<fptype, arena_type> m_Idrn;
@@ -339,9 +343,6 @@ namespace solver
plib::aligned_vector<nldelegate_dyn> m_dynamic_funcs;
plib::aligned_vector<device_arena::unique_ptr<proxied_analog_output_t>> m_inps;
- logic_input_t m_fb_sync;
- logic_output_t m_Q_sync;
-
std::size_t m_ops;
plib::aligned_vector<terms_for_net_t> m_rails_temp; // setup only
diff --git a/src/lib/netlist/solver/nld_matrix_solver_ext.h b/src/lib/netlist/solver/nld_matrix_solver_ext.h
index b89f7dde9ce..577abbb7fd6 100644
--- a/src/lib/netlist/solver/nld_matrix_solver_ext.h
+++ b/src/lib/netlist/solver/nld_matrix_solver_ext.h
@@ -56,15 +56,6 @@ namespace solver
//PALIGNAS_VECTOROPT() parrays define alignment already
plib::pmatrix2d<float_type *> m_mat_ptr;
- std::size_t max_railstart() 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].railstart());
- return max_rail;
- }
-
-
template <typename T, typename M>
void log_fill(const T &fill, M &mat)
{
diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp
index d756ecbd8f2..45f8a389b51 100644
--- a/src/lib/netlist/solver/nld_solver.cpp
+++ b/src/lib/netlist/solver/nld_solver.cpp
@@ -17,6 +17,7 @@
#include "nld_ms_w.h"
#include "nld_solver.h"
#include "plib/pomp.h"
+#include "plib/ptimed_queue.h"
#include <algorithm>
#include <type_traits>
@@ -32,8 +33,12 @@ namespace devices
NETLIB_RESET(solver)
{
+ if (exec().use_stats())
+ m_fb_step.set_delegate(NETLIB_DELEGATE(fb_step<true>));
for (auto &s : m_mat_solvers)
s->reset();
+ for (auto &s : m_mat_solvers)
+ m_queue.push<false>({netlist_time_ext::zero(), s.get()});
}
void NETLIB_NAME(solver)::stop()
@@ -42,6 +47,91 @@ namespace devices
s->log_stats();
}
+#if 1
+
+ template<bool KEEP_STATS>
+ 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_usec(100)));
+ plib::uninitialised_array<solver::matrix_solver_t *, config::MAX_SOLVER_QUEUE_SIZE::value> tmp;
+ plib::uninitialised_array<netlist_time, config::MAX_SOLVER_QUEUE_SIZE::value> nt;
+ std::size_t p=0;
+
+ while (m_queue.size() > 0)
+ {
+ auto t = m_queue.top().exec_time();
+ auto o = m_queue.top().object();
+ if (t != now)
+ if (t > sched)
+ break;
+ tmp[p++] = o;
+ m_queue.pop();
+ }
+
+ // FIXME: Disabled for now since parallel processing will decrease performance
+ // for tested applications. More testing required here
+ if (1 || nthreads < 2)
+ {
+ if (!KEEP_STATS)
+ {
+ for (std::size_t i = 0; i < p; i++)
+ nt[i] = tmp[i]->solve(now, "no-parallel");
+ }
+ else
+ {
+ stats()->m_stat_total_time.pause();
+ for (std::size_t i = 0; i < p; i++)
+ {
+ tmp[i]->stats()->m_stat_call_count.inc();
+ auto g(tmp[i]->stats()->m_stat_total_time.guard());
+ nt[i] = tmp[i]->solve(now, "no-parallel");
+ }
+ stats()->m_stat_total_time.cont();
+ }
+
+ for (std::size_t i = 0; i < p; i++)
+ {
+ if (nt[i] != netlist_time::zero())
+ m_queue.push<false>({now + nt[i], tmp[i]});
+ tmp[i]->update_inputs();
+ }
+ }
+ 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");
+ });
+ for (std::size_t i = 0; i < p; i++)
+ {
+ if (nt[i] != netlist_time::zero())
+ m_queue.push<false>({now + nt[i], tmp[i]});
+ tmp[i]->update_inputs();
+ }
+ }
+ if (m_queue.size() > 0)
+ m_Q_step.net().toggle_and_push_to_queue(m_queue.top().exec_time() - now);
+ }
+
+ 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);
+ m_queue.remove<false>(solv);
+ m_queue.push<false>({sched, solv});
+
+ if (m_Q_step.net().is_queued())
+ {
+ if (m_Q_step.net().next_scheduled_time() > sched)
+ m_Q_step.net().toggle_and_push_to_queue(ts);
+ }
+ else
+ m_Q_step.net().toggle_and_push_to_queue(ts);
+ }
+#else
NETLIB_HANDLER(solver, fb_step)
{
if (m_params.m_dynamic_ts)
@@ -54,26 +144,26 @@ namespace devices
std::size_t nthreads = std::min(static_cast<std::size_t>(m_params.m_parallel()), plib::omp::get_max_threads());
- std::vector<solver::matrix_solver_t *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_timestepping);
+ std::vector<solver_entry *> &solvers = (force_solve ? m_mat_solvers_all : m_mat_solvers_timestepping);
if (nthreads > 1 && solvers.size() > 1)
{
plib::omp::set_num_threads(nthreads);
plib::omp::for_static(static_cast<std::size_t>(0), solvers.size(), [&solvers, now](std::size_t i)
{
- const netlist_time ts = solvers[i]->solve(now);
+ const netlist_time ts = solvers[i]->ptr->solve(now);
plib::unused_var(ts);
});
}
else
for (auto & solver : solvers)
{
- const netlist_time ts = solver->solve(now);
+ const netlist_time ts = solver->ptr->solve(now);
plib::unused_var(ts);
}
for (auto & solver : solvers)
- solver->update_inputs();
+ solver->ptr->update_inputs();
// step circuit
if (!m_Q_step.net().is_queued())
@@ -81,8 +171,7 @@ namespace devices
m_Q_step.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_max_timestep));
}
}
-
- //using solver_ptr = host_arena::unique_ptr<solver::matrix_solver_t>;
+#endif
// FIXME: should be created in device space
template <class C>
@@ -90,8 +179,7 @@ namespace devices
NETLIB_NAME(solver)::net_list_t &nets,
solver::solver_parameters_t &params, std::size_t size)
{
- return plib::make_unique<C, host_arena>(main_solver, name, nets, &params, size);
- //return nl.make_pool_object<C>(nl, name, nets, &params, size);
+ return plib::make_unique<C, device_arena>(main_solver, name, nets, &params, size);
}
template <typename FT, int SIZE>
@@ -140,10 +228,10 @@ namespace devices
switch (net_count)
{
case 1:
- return plib::make_unique<solver::matrix_solver_direct1_t<FT>, host_arena>(*this, sname, nets, &m_params);
+ return plib::make_unique<solver::matrix_solver_direct1_t<FT>, device_arena>(*this, sname, nets, &m_params);
//return state().make_pool_object<solver::matrix_solver_direct1_t<FT>>(state(), sname, nets, &m_params);
case 2:
- return plib::make_unique<solver::matrix_solver_direct2_t<FT>, host_arena>(*this, sname, nets, &m_params);
+ return plib::make_unique<solver::matrix_solver_direct2_t<FT>, device_arena>(*this, sname, nets, &m_params);
//return state().make_pool_object<solver::matrix_solver_direct2_t<FT>>(state(), sname, nets, &m_params);
case 3:
return create_solver<FT, 3>(3, sname, nets);
@@ -338,12 +426,9 @@ namespace devices
}
}
- m_mat_solvers_all.push_back(ms.get());
- if (ms->timestep_device_count() != 0)
- m_mat_solvers_timestepping.push_back(ms.get());
-
- m_mat_solvers.emplace_back(std::move(ms));
+ m_mat_solvers.push_back(std::move(ms));
}
+
}
solver::static_compile_container NETLIB_NAME(solver)::create_solver_code(solver::static_compile_target target)
@@ -358,6 +443,20 @@ namespace devices
return mp;
}
+ 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++)
+ 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
+ {
+ return m_mat_solvers[id].get();
+ }
+
+
NETLIB_DEVICE_IMPL(solver, "SOLVER", "FREQ")
} // namespace devices
diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h
index 315c1e81d3b..269be1cd5ff 100644
--- a/src/lib/netlist/solver/nld_solver.h
+++ b/src/lib/netlist/solver/nld_solver.h
@@ -26,12 +26,19 @@ namespace devices
{
NETLIB_OBJECT(solver)
{
+ public:
+ using queue_type = detail::queue_base<solver::matrix_solver_t, false>;
+
NETLIB_CONSTRUCTOR(solver)
- , m_fb_step(*this, "FB_step", NETLIB_DELEGATE(fb_step))
+ , m_fb_step(*this, "FB_step", NETLIB_DELEGATE(fb_step<false>))
, m_Q_step(*this, "Q_step")
, m_params(*this)
+ , m_queue(config::MAX_SOLVER_QUEUE_SIZE::value,
+ queue_type::id_delegate(&NETLIB_NAME(solver) :: get_solver_id, this),
+ queue_type::obj_delegate(&NETLIB_NAME(solver) :: solver_by_id, this))
{
- // internal staff
+ // internal stuff
+ state().save(*this, static_cast<plib::state_manager_t::callback_t &>(m_queue), this->name(), "m_queue");
connect(m_fb_step, m_Q_step);
}
@@ -46,11 +53,14 @@ namespace devices
NETLIB_RESETI();
// NETLIB_UPDATE_PARAMI();
- //using solver_ptr = device_arena::unique_ptr<solver::matrix_solver_t>;
- using solver_ptr = host_arena::unique_ptr<solver::matrix_solver_t>;
+ using solver_ptr = device_arena::unique_ptr<solver::matrix_solver_t>;
+ //using solver_ptr = host_arena::unique_ptr<solver::matrix_solver_t>;
using net_list_t = solver::matrix_solver_t::net_list_t;
+ void reschedule(solver::matrix_solver_t *solv, netlist_time ts);
+
private:
+ template<bool KEEP_STATS>
NETLIB_HANDLERI(fb_step);
logic_input_t m_fb_step;
@@ -58,18 +68,20 @@ namespace devices
// FIXME: these should be created in device space
std::vector<solver_ptr> m_mat_solvers;
- std::vector<solver::matrix_solver_t *> m_mat_solvers_all;
- std::vector<solver::matrix_solver_t *> m_mat_solvers_timestepping;
solver::solver_parameters_t m_params;
+ queue_type m_queue;
template <typename FT, int SIZE>
solver_ptr create_solver(std::size_t size,
const pstring &solvername, net_list_t &nets);
template <typename FT>
- solver_ptr create_solvers(
- const pstring &sname, net_list_t &nets);
+ solver_ptr create_solvers(const pstring &sname, 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 devices
diff --git a/src/mame/audio/nl_kidniki.cpp b/src/mame/audio/nl_kidniki.cpp
index f30657a2086..21913be71f6 100644
--- a/src/mame/audio/nl_kidniki.cpp
+++ b/src/mame/audio/nl_kidniki.cpp
@@ -385,7 +385,7 @@ NETLIST_START(kidniki)
#endif
#if (USE_FRONTIERS)
- PARAM(Solver.PARALLEL, 2) // More does not help
+ PARAM(Solver.PARALLEL, 3) // More does not help
#else
PARAM(Solver.PARALLEL, 0)
#endif