diff --git a/src/lib/netlist/devices/nld_7448.cpp b/src/lib/netlist/devices/nld_7448.cpp index efc06d83cae..239d6b50921 100644 --- a/src/lib/netlist/devices/nld_7448.cpp +++ b/src/lib/netlist/devices/nld_7448.cpp @@ -188,11 +188,13 @@ namespace netlist NETLIB_RESET(7448) { m_state = 0; +#if 0 m_A.set_state(logic_t::STATE_INP_PASSIVE); m_B.set_state(logic_t::STATE_INP_PASSIVE); m_C.set_state(logic_t::STATE_INP_PASSIVE); m_D.set_state(logic_t::STATE_INP_PASSIVE); m_RBIQ.set_state(logic_t::STATE_INP_PASSIVE); +#endif } NETLIB_FUNC_VOID(7448, update_outputs, (unsigned v)) diff --git a/src/lib/netlist/devices/nld_9316.cpp b/src/lib/netlist/devices/nld_9316.cpp index 69dd1c1c6ca..d392250d8a5 100644 --- a/src/lib/netlist/devices/nld_9316.cpp +++ b/src/lib/netlist/devices/nld_9316.cpp @@ -21,7 +21,6 @@ namespace netlist , m_CLK(*this, "CLK", NETLIB_DELEGATE(9316, clk)) , m_ENT(*this, "ENT") , m_LOADQ(*this, "LOADQ") - , m_cnt(*this, "m_cnt", 0) , m_ENP(*this, "ENP") , m_CLRQ(*this, "CLRQ") , m_A(*this, "A", NETLIB_DELEGATE(9316, abcd)) @@ -30,7 +29,10 @@ namespace netlist , m_D(*this, "D", NETLIB_DELEGATE(9316, abcd)) , m_Q(*this, {{ "QA", "QB", "QC", "QD" }}) , m_RC(*this, "RC") + , m_cnt(*this, "m_cnt", 0) , m_abcd(*this, "m_abcd", 0) + , m_loadq(*this, "m_loadq", 0) + , m_ent(*this, "m_ent", 0) { } @@ -48,8 +50,6 @@ namespace netlist logic_input_t m_ENT; logic_input_t m_LOADQ; - state_var_u8 m_cnt; - logic_input_t m_ENP; logic_input_t m_CLRQ; @@ -60,7 +60,14 @@ namespace netlist object_array_t m_Q; logic_output_t m_RC; + + /* counter state */ + state_var_u8 m_cnt; + + /* cached pins */ state_var_u8 m_abcd; + state_var_sig m_loadq; + state_var_sig m_ent; private: void update_outputs_all(const unsigned &cnt, const netlist_time &out_delay) noexcept @@ -106,11 +113,10 @@ namespace netlist NETLIB_HANDLER(9316, clk) { auto cnt(m_cnt); - if (m_LOADQ()) + if (m_loadq) { ++cnt &= MAXCNT; //m_RC.push(m_ENT() && (cnt == MAXCNT), NLTIME_FROM_NS(27)); - if (cnt > 0 && cnt < MAXCNT) update_outputs_all(cnt, NLTIME_FROM_NS(20)); else if (cnt == 0) @@ -120,14 +126,14 @@ namespace netlist } else { - m_RC.push(m_ENT(), NLTIME_FROM_NS(27)); + m_RC.push(m_ent, NLTIME_FROM_NS(27)); update_outputs_all(MAXCNT, NLTIME_FROM_NS(20)); } } else { cnt = m_abcd; - m_RC.push(m_ENT() && (cnt == MAXCNT), NLTIME_FROM_NS(27)); + m_RC.push(m_ent && (cnt == MAXCNT), NLTIME_FROM_NS(27)); update_outputs_all(cnt, NLTIME_FROM_NS(22)); } m_cnt = cnt; @@ -136,9 +142,10 @@ namespace netlist NETLIB_UPDATE(9316) { const netlist_sig_t CLRQ(m_CLRQ()); - const netlist_sig_t ENT(m_ENT()); + m_ent = m_ENT(); + m_loadq = m_LOADQ(); - if (((m_LOADQ() ^ 1) || (ENT && m_ENP())) && CLRQ) + if (((m_loadq ^ 1) || (m_ent && m_ENP())) && CLRQ) { m_CLK.activate_lh(); } @@ -151,7 +158,7 @@ namespace netlist update_outputs_all(m_cnt, NLTIME_FROM_NS(36)); } } - m_RC.push(ENT && (m_cnt == MAXCNT), NLTIME_FROM_NS(27)); + m_RC.push(m_ent && (m_cnt == MAXCNT), NLTIME_FROM_NS(27)); } diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index cc057de25f8..24cb7cc8890 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -403,9 +403,17 @@ void netlist_state_t::reset() case 1: // brute force backward { log().verbose("Using brute force backward startup strategy"); + + for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1 + n->update_inputs(); + std::size_t i = m_devices.size(); while (i>0) m_devices[--i]->update(); + + for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1 + n->update_inputs(); + } break; case 2: // brute force forward @@ -694,7 +702,7 @@ detail::net_t::net_t(netlist_base_t &nl, const pstring &aname, core_terminal_t * , netlist_ref(nl) , m_new_Q(*this, "m_new_Q", 0) , m_cur_Q (*this, "m_cur_Q", 0) - , m_in_queue(*this, "m_in_queue", QS_DELIVERED) + , m_in_queue(*this, "m_in_queue", queue_status::DELIVERED) , m_next_scheduled_time(*this, "m_time", netlist_time::zero()) , m_railterminal(mr) { @@ -715,14 +723,18 @@ void detail::net_t::rebuild_list() if (term->terminal_state() != logic_t::STATE_INP_PASSIVE) { m_list_active.push_back(term); + term->set_copied_input(m_cur_Q); } } - template -void detail::net_t::process(const T mask) +void detail::net_t::process(const T mask, netlist_sig_t sig) { + m_cur_Q = sig; + for (auto & p : m_list_active) { + p.set_copied_input(sig); + p.device().m_stat_call_count.inc(); if ((p.terminal_state() & mask)) { @@ -743,13 +755,12 @@ void detail::net_t::update_devs() NL_NOEXCEPT const auto mask((new_Q << core_terminal_t::INP_LH_SHIFT) | (m_cur_Q << core_terminal_t::INP_HL_SHIFT)); - m_in_queue = QS_DELIVERED; /* mark as taken ... */ + m_in_queue = queue_status::DELIVERED; /* mark as taken ... */ switch (mask) { case core_terminal_t::STATE_INP_HL: case core_terminal_t::STATE_INP_LH: - m_cur_Q = new_Q; - process(mask | core_terminal_t::STATE_INP_ACTIVE); + process(mask | core_terminal_t::STATE_INP_ACTIVE, new_Q); break; default: /* do nothing */ @@ -760,7 +771,7 @@ void detail::net_t::update_devs() NL_NOEXCEPT void detail::net_t::reset() { m_next_scheduled_time = netlist_time::zero(); - m_in_queue = QS_DELIVERED; + m_in_queue = queue_status::DELIVERED; m_new_Q = 0; m_cur_Q = 0; @@ -778,6 +789,7 @@ void detail::net_t::reset() ct->reset(); if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE) m_list_active.push_back(ct); + ct->set_copied_input(m_cur_Q); } } @@ -849,6 +861,9 @@ detail::core_terminal_t::core_terminal_t(core_device_t &dev, const pstring &anam : device_object_t(dev, dev.name() + "." + aname) , plib::linkedlist_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) { diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 2d8f8154ed0..507eb42d367 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -524,7 +524,6 @@ namespace netlist void clear_net() noexcept { m_net = nullptr; } bool has_net() const noexcept { return (m_net != nullptr); } - const net_t & net() const noexcept { return *m_net;} net_t & net() noexcept { return *m_net;} @@ -538,6 +537,16 @@ namespace netlist void reset() noexcept { set_state(is_type(OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); } nldelegate m_delegate; +#if USE_COPY_INSTEAD_OF_REFERENCE + void set_copied_input(netlist_sig_t val) + { + m_Q = val; + } + + state_var_sig m_Q; +#else + void set_copied_input(netlist_sig_t val) const { plib::unused_var(val); } +#endif private: net_t * m_net; @@ -707,11 +716,11 @@ namespace netlist { public: - enum queue_status + enum class queue_status { - QS_DELAYED_DUE_TO_INACTIVE = 0, - QS_QUEUED, - QS_DELIVERED + DELAYED_DUE_TO_INACTIVE = 0, + QUEUED, + DELIVERED }; net_t(netlist_base_t &nl, const pstring &aname, core_terminal_t *mr = nullptr); @@ -728,7 +737,7 @@ namespace netlist } void push_to_queue(netlist_time delay) NL_NOEXCEPT; - bool is_queued() const noexcept { return m_in_queue == QS_QUEUED; } + bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; } void update_devs() NL_NOEXCEPT; @@ -755,7 +764,18 @@ namespace netlist void move_connections(net_t &dest_net); std::vector m_core_terms; // save post-start m_list ... - +#if USE_COPY_INSTEAD_OF_REFERENCE + void update_inputs() + { + for (auto & term : m_core_terms) + term->m_Q = m_cur_Q; + } +#else + void update_inputs() const + { + /* nothing needs to be done */ + } +#endif protected: state_var m_new_Q; state_var m_cur_Q; @@ -768,7 +788,7 @@ namespace netlist core_terminal_t * m_railterminal; template - void process(const T mask); + void process(const T mask, netlist_sig_t sig); }; class logic_net_t : public detail::net_t @@ -779,11 +799,15 @@ namespace netlist virtual ~logic_net_t(); netlist_sig_t Q() const noexcept { return m_cur_Q; } - void initial(const netlist_sig_t val) noexcept { m_cur_Q = m_new_Q = val; } + void initial(const netlist_sig_t val) noexcept + { + m_cur_Q = m_new_Q = val; + update_inputs(); + } void set_Q_and_push(const netlist_sig_t newQ, const netlist_time delay) NL_NOEXCEPT { - if (newQ != m_new_Q ) + if (newQ != m_new_Q) { m_new_Q = newQ; push_to_queue(delay); @@ -802,10 +826,11 @@ namespace netlist { if (newQ != m_new_Q) { - m_in_queue = QS_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; + update_inputs(); } /* internal state support @@ -1529,9 +1554,12 @@ namespace netlist if (is_queued()) q.remove(this); - m_in_queue = (!m_list_active.empty()) ? QS_QUEUED : QS_DELAYED_DUE_TO_INACTIVE; /* queued ? */ - if (m_in_queue == QS_QUEUED) + m_in_queue = (!m_list_active.empty()) ? + queue_status::QUEUED : queue_status::DELAYED_DUE_TO_INACTIVE; /* queued ? */ + if (m_in_queue == queue_status::QUEUED) q.push(queue_t::entry_t(nst, this)); + else + update_inputs(); m_next_scheduled_time = nst; } } @@ -1542,22 +1570,28 @@ namespace netlist { m_list_active.push_front(&term); railterminal().device().do_inc_active(); - if (m_in_queue == QS_DELAYED_DUE_TO_INACTIVE) + if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE) { if (m_next_scheduled_time > exec().time()) { - m_in_queue = QS_QUEUED; /* pending */ + m_in_queue = queue_status::QUEUED; /* pending */ exec().queue().push({m_next_scheduled_time, this}); } else { - m_in_queue = QS_DELIVERED; + m_in_queue = queue_status::DELIVERED; m_cur_Q = m_new_Q; } + update_inputs(); } + else + term.set_copied_input(m_cur_Q); } else + { + term.set_copied_input(m_cur_Q); m_list_active.push_front(&term); + } } inline void detail::net_t::remove_from_active_list(core_terminal_t &term) NL_NOEXCEPT @@ -1592,7 +1626,13 @@ namespace netlist inline netlist_sig_t logic_input_t::Q() const NL_NOEXCEPT { nl_assert(terminal_state() != STATE_INP_PASSIVE); + //if (net().Q() != m_Q) + // printf("term: %s, %d %d TS %d\n", this->name().c_str(), net().Q(), m_Q, terminal_state()); +#if USE_COPY_INSTEAD_OF_REFERENCE + return m_Q; +#else return net().Q(); +#endif } inline nl_double analog_input_t::Q_Analog() const NL_NOEXCEPT @@ -1624,7 +1664,6 @@ namespace netlist return m_device.exec(); } - inline const netlist_t &detail::device_object_t::exec() const NL_NOEXCEPT { return m_device.exec(); diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index dd94981d4ee..69b5fad945c 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -30,6 +30,18 @@ */ #define USE_MEMPOOL (0) +/*! Store input values in logic_terminal_t. + * + * Set to 1 to store values in logic_terminal_t instead of + * accessing them indirectly by pointer from logic_net_t. + * This approach is stricter and should identify bugs in + * the netlist core faster. + * By default it is disabled since it is not as fast as + * the default approach. + * + */ +#define USE_COPY_INSTEAD_OF_REFERENCE (0) + /* * FIXME: Using truthtable is a lot slower than the explicit device * in breakout. Performance drops by 20%. This can be fixed by diff --git a/src/lib/netlist/nl_time.h b/src/lib/netlist/nl_time.h index d5223db3140..b8ed1bb5a33 100644 --- a/src/lib/netlist/nl_time.h +++ b/src/lib/netlist/nl_time.h @@ -124,6 +124,7 @@ namespace netlist static constexpr ptime quantum() noexcept { return ptime(1, RES); } static constexpr ptime never() noexcept { return ptime(plib::numeric_limits::max(), RES); } static constexpr internal_type resolution() noexcept { return RES; } + private: static constexpr const double inv_res = 1.0 / static_cast(RES); internal_type m_time; @@ -133,6 +134,7 @@ namespace netlist using netlist_time = ptime; #else using netlist_time = ptime; + static_assert(noexcept(netlist_time::from_nsec(1)) == true, "Not evaluated as constexpr"); #endif }