summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/core/nets.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/core/nets.h')
-rw-r--r--src/lib/netlist/core/nets.h351
1 files changed, 201 insertions, 150 deletions
diff --git a/src/lib/netlist/core/nets.h b/src/lib/netlist/core/nets.h
index a121f261a50..280cda2013e 100644
--- a/src/lib/netlist/core/nets.h
+++ b/src/lib/netlist/core/nets.h
@@ -17,13 +17,10 @@
#include "../plib/plists.h"
#include "../plib/pstring.h"
-#ifndef AVOID_NOOP_QUEUE_PUSHES
-#error AVOID_NOOP_QUEUE_PUSHES not defined
-#endif
+#include <algorithm>
namespace netlist
{
-
namespace detail {
// -----------------------------------------------------------------------------
@@ -43,7 +40,10 @@ namespace netlist
net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *rail_terminal = nullptr);
- PCOPYASSIGNMOVE(net_t, delete)
+ net_t(const net_t &) = delete;
+ net_t &operator=(const net_t &) = delete;
+ net_t(net_t &&) noexcept = delete;
+ net_t &operator=(net_t &&) noexcept = delete;
virtual ~net_t() noexcept = default;
@@ -55,7 +55,10 @@ namespace netlist
// Any changes below will impact performance.
// -----------------------------------------------------------------------------
- void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); }
+ constexpr void toggle_new_Q() noexcept
+ {
+ m_new_Q = (m_cur_Q ^ 1);
+ }
void toggle_and_push_to_queue(const netlist_time &delay) noexcept
{
@@ -63,133 +66,28 @@ namespace netlist
push_to_queue(delay);
}
- void push_to_queue(const netlist_time &delay) noexcept
- {
- if (!!is_queued())
- exec().qremove(this);
+ void push_to_queue(const netlist_time &delay) noexcept;
- m_next_scheduled_time = exec().time() + delay;
-#if (AVOID_NOOP_QUEUE_PUSHES)
- m_in_queue = (m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE
- : (m_new_Q != m_cur_Q ? queue_status::QUEUED : queue_status::DELIVERED));
- if (m_in_queue == queue_status::QUEUED)
- exec().qpush(m_next_scheduled_time, this);
- else
- update_inputs();
-#else
- m_in_queue = m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE : queue_status::QUEUED;
- if (m_in_queue == queue_status::QUEUED)
- exec().qpush(m_next_scheduled_time, this);
- else
- update_inputs();
-#endif
+ constexpr bool is_queued() const noexcept
+ {
+ return m_in_queue == queue_status::QUEUED;
}
- constexpr bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; }
// -----------------------------------------------------------------------------
// Very hot
// -----------------------------------------------------------------------------
template <bool KEEP_STATS>
- void update_devs() noexcept
- {
- gsl_Expects(this->is_rail_net());
-
- m_in_queue = queue_status::DELIVERED; // mark as taken ...
-
- const netlist_sig_t new_Q(m_new_Q);
- const netlist_sig_t cur_Q(m_cur_Q);
-#if (!AVOID_NOOP_QUEUE_PUSHES)
- if (new_Q ^ cur_Q)
-#endif
- {
- const auto mask = (new_Q << core_terminal_t::INP_LH_SHIFT)
- | (cur_Q << core_terminal_t::INP_HL_SHIFT);
- m_cur_Q = new_Q;
-
- if (!KEEP_STATS)
- {
- for (auto &p : m_list_active)
- {
- p.set_copied_input(new_Q);
- if ((p.terminal_state() & mask) != 0)
- p.run_delegate();
- }
- }
- else
- {
- for (auto & p : m_list_active)
- {
- p.set_copied_input(new_Q);
- auto *stats(p.device().stats());
- stats->m_stat_call_count.inc();
- if ((p.terminal_state() & mask))
- {
- auto g(stats->m_stat_total_time.guard());
- p.run_delegate();
- }
- }
- }
- }
- }
+ void update_devs() noexcept;
constexpr const netlist_time_ext &next_scheduled_time() const noexcept { return m_next_scheduled_time; }
- void set_next_scheduled_time(netlist_time_ext next_time) noexcept { m_next_scheduled_time = next_time; }
+ void set_next_scheduled_time(const netlist_time_ext &next_time) noexcept { m_next_scheduled_time = next_time; }
bool is_rail_net() const noexcept { return !(m_rail_terminal == nullptr); }
core_terminal_t & rail_terminal() const noexcept { return *m_rail_terminal; }
- void add_to_active_list(core_terminal_t &term) noexcept
- {
- if (!m_list_active.empty())
- {
- term.set_copied_input(m_cur_Q);
- m_list_active.push_front(&term);
- }
- else
- {
- m_list_active.push_front(&term);
- rail_terminal().device().do_inc_active();
- if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
- {
-#if (AVOID_NOOP_QUEUE_PUSHES)
- if (m_next_scheduled_time > exec().time()
- && (m_cur_Q != m_new_Q))
-#else
- if (m_next_scheduled_time > exec().time())
-#endif
- {
- m_in_queue = queue_status::QUEUED; // pending
- exec().qpush(m_next_scheduled_time, this);
- }
- else
- {
- m_in_queue = queue_status::DELIVERED;
- m_cur_Q = m_new_Q;
- }
- update_inputs();
- }
- else
- term.set_copied_input(m_cur_Q);
- }
- }
-
- void remove_from_active_list(core_terminal_t &term) noexcept
- {
- gsl_Expects(!m_list_active.empty());
- m_list_active.remove(&term);
- if (m_list_active.empty())
- {
-#if (AVOID_NOOP_QUEUE_PUSHES)
- if (!!is_queued())
- {
- exec().qremove(this);
- m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
- }
-#endif
- rail_terminal().device().do_dec_active();
- }
- }
+ void add_to_active_list(core_terminal_t &term) noexcept;
+ void remove_from_active_list(core_terminal_t &term) noexcept;
// -----------------------------------------------------------------------------
// setup stuff - cold
@@ -200,17 +98,31 @@ namespace netlist
void rebuild_list(); // rebuild m_list after a load
- //std::vector<core_terminal_t *> &core_terms() noexcept { return state().m_core_terms[this]; }
-
void update_inputs() noexcept
{
-#if NL_USE_COPY_INSTEAD_OF_REFERENCE
- for (auto & term : m_core_terms)
- term->m_Q = m_cur_Q;
-#endif
- // nothing needs to be done if define not set
+ if constexpr (config::use_copy_instead_of_reference::value)
+ {
+ for (auto *term : core_terms_ref())
+ term->set_copied_input(m_cur_Q);
+ }
+ }
+
+ // -----------------------------------------------------------------------------
+ // net management
+ // -----------------------------------------------------------------------------
+
+ const std::vector<detail::core_terminal_t *> core_terms_copy()
+ {
+ std::vector<detail::core_terminal_t *> ret(core_terms_ref().size());
+ std::copy(core_terms_ref().begin(), core_terms_ref().end(), ret.begin());
+ return ret;
}
+ void remove_terminal(detail::core_terminal_t &term);
+ void remove_all_terminals();
+ void add_terminal(detail::core_terminal_t &terminal);
+
+ bool core_terms_empty() noexcept { return core_terms_ref().empty(); }
protected:
// only used for logic nets
@@ -224,49 +136,188 @@ namespace netlist
}
// only used for logic nets
- void set_Q_and_push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept
+ void set_Q_and_push(netlist_sig_t newQ, const netlist_time &delay) noexcept;
+
+ // only used for logic nets
+ void set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept;
+
+
+ private:
+#if NL_USE_INPLACE_CORE_TERMS
+ const plib::linked_list_t<core_terminal_t, 1> &core_terms_ref() const noexcept
{
- gsl_Expects(delay >= netlist_time::zero());
+ return m_core_terms;
+ }
+#else
+ std::vector<detail::core_terminal_t *> &core_terms_ref()
+ {
+ return state().core_terms(*this);
+ }
+#endif
+ state_var<netlist_sig_t> m_new_Q;
+ state_var<netlist_sig_t> m_cur_Q;
+ state_var<queue_status> m_in_queue;
+ // FIXME: this needs to be saved as well
+ plib::linked_list_t<core_terminal_t, 0> m_list_active;
+ state_var<netlist_time_ext> m_next_scheduled_time;
+
+ core_terminal_t * m_rail_terminal;
+#if NL_USE_INPLACE_CORE_TERMS
+ plib::linked_list_t<core_terminal_t, 1> m_core_terms;
+#endif
+ };
+
+ inline void net_t::push_to_queue(const netlist_time &delay) noexcept
+ {
+ if (is_queued())
+ exec().queue_remove(this);
+
+ m_next_scheduled_time = exec().time() + delay;
+ if constexpr (config::avoid_noop_queue_pushes::value)
+ m_in_queue = (m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE
+ : (m_new_Q != m_cur_Q ? queue_status::QUEUED : queue_status::DELIVERED));
+ else
+ m_in_queue = m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE : queue_status::QUEUED;
+
+ if (m_in_queue == queue_status::QUEUED)
+ exec().queue_push(m_next_scheduled_time, this);
+ else
+ update_inputs();
+ }
+
+ template <bool KEEP_STATS>
+ void net_t::update_devs() noexcept
+ {
+ gsl_Expects(this->is_rail_net());
- if (newQ != m_new_Q)
+ m_in_queue = queue_status::DELIVERED; // mark as taken ...
+
+ const netlist_sig_t new_Q(m_new_Q);
+ const netlist_sig_t cur_Q(m_cur_Q);
+ if (config::avoid_noop_queue_pushes::value || ((new_Q ^ cur_Q) != 0))
+ {
+ m_cur_Q = new_Q;
+ const auto mask = (new_Q << core_terminal_t::INP_LH_SHIFT)
+ | (cur_Q << core_terminal_t::INP_HL_SHIFT);
+
+ if (!KEEP_STATS)
{
- m_new_Q = newQ;
- push_to_queue(delay);
+ for (core_terminal_t * p: m_list_active)
+ {
+ p->set_copied_input(new_Q);
+ if ((p->terminal_state() & mask) != 0)
+ p->run_delegate();
+ }
+ }
+ else
+ {
+ for (core_terminal_t * p : m_list_active)
+ {
+ p->set_copied_input(new_Q);
+ auto *stats(p->device().stats());
+ stats->m_stat_call_count.inc();
+ if ((p->terminal_state() & mask))
+ {
+ auto g(stats->m_stat_total_time.guard());
+ p->run_delegate();
+ }
+ }
}
}
+ }
- // only used for logic nets
- void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept
+ inline void net_t::add_to_active_list(core_terminal_t &term) noexcept
+ {
+ if (!m_list_active.empty())
{
- gsl_Expects(at >= netlist_time_ext::zero());
-
- if (newQ != m_new_Q)
+ term.set_copied_input(m_cur_Q);
+ m_list_active.push_front(&term);
+ }
+ else
+ {
+ m_list_active.push_front(&term);
+ rail_terminal().device().do_inc_active();
+ if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
{
- m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
- m_next_scheduled_time = at;
- m_cur_Q = m_new_Q = newQ;
+ // if we avoid queue pushes we must test if m_cur_Q and m_new_Q are equal
+ if ((!config::avoid_noop_queue_pushes::value || (m_cur_Q != m_new_Q))
+ && (m_next_scheduled_time > exec().time()))
+ {
+ m_in_queue = queue_status::QUEUED; // pending
+ exec().queue_push(m_next_scheduled_time, this);
+ }
+ else
+ {
+ m_in_queue = queue_status::DELIVERED;
+ m_cur_Q = m_new_Q;
+ }
update_inputs();
}
else
+ term.set_copied_input(m_cur_Q);
+ }
+ }
+
+ inline void net_t::remove_from_active_list(core_terminal_t &term) noexcept
+ {
+ gsl_Expects(!m_list_active.empty());
+ m_list_active.remove(&term);
+ if (m_list_active.empty())
+ {
+ if constexpr (true || config::avoid_noop_queue_pushes::value)
{
- m_cur_Q = newQ;
- update_inputs();
+ // All our connected outputs have signalled they no longer
+ // will act on input. We thus remove any potentially queued
+ // events and mark them.
+ // FIXME: May cause regression test to fail - revisit in this case
+ //
+ // This code is definitively needed for the
+ // AVOID_NOOP_QUEUE_PUSHES code path - therefore I left
+ // the if statement in and enabled it for all code paths
+ if (is_queued())
+ {
+ exec().queue_remove(this);
+ m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
+ }
}
+ rail_terminal().device().do_dec_active();
}
+ }
- private:
- state_var<netlist_sig_t> m_new_Q;
- state_var<netlist_sig_t> m_cur_Q;
- state_var<queue_status> m_in_queue;
- plib::linked_list_t<core_terminal_t> m_list_active;
- state_var<netlist_time_ext> m_next_scheduled_time;
+ // only used for logic nets
+ inline void net_t::set_Q_and_push(netlist_sig_t newQ, const netlist_time &delay) noexcept
+ {
+ gsl_Expects(delay >= netlist_time::zero());
- core_terminal_t * m_rail_terminal;
- //std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
+ if (newQ != m_new_Q)
+ {
+ m_new_Q = newQ;
+ push_to_queue(delay);
+ }
+ }
+
+ // only used for logic nets
+ inline void net_t::set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept
+ {
+ gsl_Expects(at >= netlist_time_ext::zero());
+
+ if (newQ != m_new_Q)
+ {
+ m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
+ m_next_scheduled_time = at;
+ m_cur_Q = m_new_Q = newQ;
+ update_inputs();
+ }
+ else
+ {
+ m_cur_Q = newQ;
+ update_inputs();
+ }
+ }
- };
} // namespace detail
+
class analog_net_t : public detail::net_t
{
public: