netlist: Optionally store input values instead of referencing them. (nw)

Useful for debugging purposes in the end - but not performance.

/*! 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)
This commit is contained in:
couriersud 2019-02-05 18:31:14 +01:00
parent b49a2e6e49
commit 6381ed11ed
6 changed files with 111 additions and 34 deletions

View File

@ -188,11 +188,13 @@ namespace netlist
NETLIB_RESET(7448) NETLIB_RESET(7448)
{ {
m_state = 0; m_state = 0;
#if 0
m_A.set_state(logic_t::STATE_INP_PASSIVE); m_A.set_state(logic_t::STATE_INP_PASSIVE);
m_B.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_C.set_state(logic_t::STATE_INP_PASSIVE);
m_D.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); m_RBIQ.set_state(logic_t::STATE_INP_PASSIVE);
#endif
} }
NETLIB_FUNC_VOID(7448, update_outputs, (unsigned v)) NETLIB_FUNC_VOID(7448, update_outputs, (unsigned v))

View File

@ -21,7 +21,6 @@ namespace netlist
, m_CLK(*this, "CLK", NETLIB_DELEGATE(9316, clk)) , m_CLK(*this, "CLK", NETLIB_DELEGATE(9316, clk))
, m_ENT(*this, "ENT") , m_ENT(*this, "ENT")
, m_LOADQ(*this, "LOADQ") , m_LOADQ(*this, "LOADQ")
, m_cnt(*this, "m_cnt", 0)
, m_ENP(*this, "ENP") , m_ENP(*this, "ENP")
, m_CLRQ(*this, "CLRQ") , m_CLRQ(*this, "CLRQ")
, m_A(*this, "A", NETLIB_DELEGATE(9316, abcd)) , m_A(*this, "A", NETLIB_DELEGATE(9316, abcd))
@ -30,7 +29,10 @@ namespace netlist
, m_D(*this, "D", NETLIB_DELEGATE(9316, abcd)) , m_D(*this, "D", NETLIB_DELEGATE(9316, abcd))
, m_Q(*this, {{ "QA", "QB", "QC", "QD" }}) , m_Q(*this, {{ "QA", "QB", "QC", "QD" }})
, m_RC(*this, "RC") , m_RC(*this, "RC")
, m_cnt(*this, "m_cnt", 0)
, m_abcd(*this, "m_abcd", 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_ENT;
logic_input_t m_LOADQ; logic_input_t m_LOADQ;
state_var_u8 m_cnt;
logic_input_t m_ENP; logic_input_t m_ENP;
logic_input_t m_CLRQ; logic_input_t m_CLRQ;
@ -60,7 +60,14 @@ namespace netlist
object_array_t<logic_output_t, 4> m_Q; object_array_t<logic_output_t, 4> m_Q;
logic_output_t m_RC; logic_output_t m_RC;
/* counter state */
state_var_u8 m_cnt;
/* cached pins */
state_var_u8 m_abcd; state_var_u8 m_abcd;
state_var_sig m_loadq;
state_var_sig m_ent;
private: private:
void update_outputs_all(const unsigned &cnt, const netlist_time &out_delay) noexcept void update_outputs_all(const unsigned &cnt, const netlist_time &out_delay) noexcept
@ -106,11 +113,10 @@ namespace netlist
NETLIB_HANDLER(9316, clk) NETLIB_HANDLER(9316, clk)
{ {
auto cnt(m_cnt); auto cnt(m_cnt);
if (m_LOADQ()) if (m_loadq)
{ {
++cnt &= MAXCNT; ++cnt &= MAXCNT;
//m_RC.push(m_ENT() && (cnt == MAXCNT), NLTIME_FROM_NS(27)); //m_RC.push(m_ENT() && (cnt == MAXCNT), NLTIME_FROM_NS(27));
if (cnt > 0 && cnt < MAXCNT) if (cnt > 0 && cnt < MAXCNT)
update_outputs_all(cnt, NLTIME_FROM_NS(20)); update_outputs_all(cnt, NLTIME_FROM_NS(20));
else if (cnt == 0) else if (cnt == 0)
@ -120,14 +126,14 @@ namespace netlist
} }
else 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)); update_outputs_all(MAXCNT, NLTIME_FROM_NS(20));
} }
} }
else else
{ {
cnt = m_abcd; 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)); update_outputs_all(cnt, NLTIME_FROM_NS(22));
} }
m_cnt = cnt; m_cnt = cnt;
@ -136,9 +142,10 @@ namespace netlist
NETLIB_UPDATE(9316) NETLIB_UPDATE(9316)
{ {
const netlist_sig_t CLRQ(m_CLRQ()); 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(); m_CLK.activate_lh();
} }
@ -151,7 +158,7 @@ namespace netlist
update_outputs_all(m_cnt, NLTIME_FROM_NS(36)); 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));
} }

View File

@ -403,9 +403,17 @@ void netlist_state_t::reset()
case 1: // brute force backward case 1: // brute force backward
{ {
log().verbose("Using brute force backward startup strategy"); 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(); std::size_t i = m_devices.size();
while (i>0) while (i>0)
m_devices[--i]->update(); m_devices[--i]->update();
for (auto &n : m_nets) // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
n->update_inputs();
} }
break; break;
case 2: // brute force forward 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) , netlist_ref(nl)
, m_new_Q(*this, "m_new_Q", 0) , m_new_Q(*this, "m_new_Q", 0)
, m_cur_Q (*this, "m_cur_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_next_scheduled_time(*this, "m_time", netlist_time::zero())
, m_railterminal(mr) , m_railterminal(mr)
{ {
@ -715,14 +723,18 @@ void detail::net_t::rebuild_list()
if (term->terminal_state() != logic_t::STATE_INP_PASSIVE) if (term->terminal_state() != logic_t::STATE_INP_PASSIVE)
{ {
m_list_active.push_back(term); m_list_active.push_back(term);
term->set_copied_input(m_cur_Q);
} }
} }
template <typename T> template <typename T>
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) for (auto & p : m_list_active)
{ {
p.set_copied_input(sig);
p.device().m_stat_call_count.inc(); p.device().m_stat_call_count.inc();
if ((p.terminal_state() & mask)) 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) const auto mask((new_Q << core_terminal_t::INP_LH_SHIFT)
| (m_cur_Q << core_terminal_t::INP_HL_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) switch (mask)
{ {
case core_terminal_t::STATE_INP_HL: case core_terminal_t::STATE_INP_HL:
case core_terminal_t::STATE_INP_LH: case core_terminal_t::STATE_INP_LH:
m_cur_Q = new_Q; process(mask | core_terminal_t::STATE_INP_ACTIVE, new_Q);
process(mask | core_terminal_t::STATE_INP_ACTIVE);
break; break;
default: default:
/* do nothing */ /* do nothing */
@ -760,7 +771,7 @@ void detail::net_t::update_devs() NL_NOEXCEPT
void detail::net_t::reset() void detail::net_t::reset()
{ {
m_next_scheduled_time = netlist_time::zero(); m_next_scheduled_time = netlist_time::zero();
m_in_queue = QS_DELIVERED; m_in_queue = queue_status::DELIVERED;
m_new_Q = 0; m_new_Q = 0;
m_cur_Q = 0; m_cur_Q = 0;
@ -778,6 +789,7 @@ void detail::net_t::reset()
ct->reset(); ct->reset();
if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE) if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE)
m_list_active.push_back(ct); 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) : device_object_t(dev, dev.name() + "." + aname)
, plib::linkedlist_t<core_terminal_t>::element_t() , plib::linkedlist_t<core_terminal_t>::element_t()
, m_delegate(delegate) , m_delegate(delegate)
#if USE_COPY_INSTEAD_OF_REFERENCE
, m_Q(*this, "m_Q", 0)
#endif
, m_net(nullptr) , m_net(nullptr)
, m_state(*this, "m_state", state) , m_state(*this, "m_state", state)
{ {

View File

@ -524,7 +524,6 @@ namespace netlist
void clear_net() noexcept { m_net = nullptr; } void clear_net() noexcept { m_net = nullptr; }
bool has_net() const noexcept { return (m_net != nullptr); } bool has_net() const noexcept { return (m_net != nullptr); }
const net_t & net() const noexcept { return *m_net;} const net_t & net() const noexcept { return *m_net;}
net_t & net() 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); } void reset() noexcept { set_state(is_type(OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); }
nldelegate m_delegate; 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: private:
net_t * m_net; net_t * m_net;
@ -707,11 +716,11 @@ namespace netlist
{ {
public: public:
enum queue_status enum class queue_status
{ {
QS_DELAYED_DUE_TO_INACTIVE = 0, DELAYED_DUE_TO_INACTIVE = 0,
QS_QUEUED, QUEUED,
QS_DELIVERED DELIVERED
}; };
net_t(netlist_base_t &nl, const pstring &aname, core_terminal_t *mr = nullptr); 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; 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; void update_devs() NL_NOEXCEPT;
@ -755,7 +764,18 @@ namespace netlist
void move_connections(net_t &dest_net); void move_connections(net_t &dest_net);
std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ... std::vector<core_terminal_t *> 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: protected:
state_var<netlist_sig_t> m_new_Q; state_var<netlist_sig_t> m_new_Q;
state_var<netlist_sig_t> m_cur_Q; state_var<netlist_sig_t> m_cur_Q;
@ -768,7 +788,7 @@ namespace netlist
core_terminal_t * m_railterminal; core_terminal_t * m_railterminal;
template <typename T> template <typename T>
void process(const T mask); void process(const T mask, netlist_sig_t sig);
}; };
class logic_net_t : public detail::net_t class logic_net_t : public detail::net_t
@ -779,11 +799,15 @@ namespace netlist
virtual ~logic_net_t(); virtual ~logic_net_t();
netlist_sig_t Q() const noexcept { return m_cur_Q; } 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 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; m_new_Q = newQ;
push_to_queue(delay); push_to_queue(delay);
@ -802,10 +826,11 @@ namespace netlist
{ {
if (newQ != m_new_Q) 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_next_scheduled_time = at;
} }
m_cur_Q = m_new_Q = newQ; m_cur_Q = m_new_Q = newQ;
update_inputs();
} }
/* internal state support /* internal state support
@ -1529,9 +1554,12 @@ namespace netlist
if (is_queued()) if (is_queued())
q.remove(this); q.remove(this);
m_in_queue = (!m_list_active.empty()) ? QS_QUEUED : QS_DELAYED_DUE_TO_INACTIVE; /* queued ? */ m_in_queue = (!m_list_active.empty()) ?
if (m_in_queue == QS_QUEUED) 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)); q.push(queue_t::entry_t(nst, this));
else
update_inputs();
m_next_scheduled_time = nst; m_next_scheduled_time = nst;
} }
} }
@ -1542,22 +1570,28 @@ namespace netlist
{ {
m_list_active.push_front(&term); m_list_active.push_front(&term);
railterminal().device().do_inc_active(); 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()) 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}); exec().queue().push({m_next_scheduled_time, this});
} }
else else
{ {
m_in_queue = QS_DELIVERED; m_in_queue = queue_status::DELIVERED;
m_cur_Q = m_new_Q; m_cur_Q = m_new_Q;
} }
update_inputs();
} }
else
term.set_copied_input(m_cur_Q);
} }
else else
{
term.set_copied_input(m_cur_Q);
m_list_active.push_front(&term); m_list_active.push_front(&term);
}
} }
inline void detail::net_t::remove_from_active_list(core_terminal_t &term) NL_NOEXCEPT 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 inline netlist_sig_t logic_input_t::Q() const NL_NOEXCEPT
{ {
nl_assert(terminal_state() != STATE_INP_PASSIVE); 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(); return net().Q();
#endif
} }
inline nl_double analog_input_t::Q_Analog() const NL_NOEXCEPT inline nl_double analog_input_t::Q_Analog() const NL_NOEXCEPT
@ -1624,7 +1664,6 @@ namespace netlist
return m_device.exec(); return m_device.exec();
} }
inline const netlist_t &detail::device_object_t::exec() const NL_NOEXCEPT inline const netlist_t &detail::device_object_t::exec() const NL_NOEXCEPT
{ {
return m_device.exec(); return m_device.exec();

View File

@ -30,6 +30,18 @@
*/ */
#define USE_MEMPOOL (0) #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 * FIXME: Using truthtable is a lot slower than the explicit device
* in breakout. Performance drops by 20%. This can be fixed by * in breakout. Performance drops by 20%. This can be fixed by

View File

@ -124,6 +124,7 @@ namespace netlist
static constexpr ptime quantum() noexcept { return ptime(1, RES); } static constexpr ptime quantum() noexcept { return ptime(1, RES); }
static constexpr ptime never() noexcept { return ptime(plib::numeric_limits<internal_type>::max(), RES); } static constexpr ptime never() noexcept { return ptime(plib::numeric_limits<internal_type>::max(), RES); }
static constexpr internal_type resolution() noexcept { return RES; } static constexpr internal_type resolution() noexcept { return RES; }
private: private:
static constexpr const double inv_res = 1.0 / static_cast<double>(RES); static constexpr const double inv_res = 1.0 / static_cast<double>(RES);
internal_type m_time; internal_type m_time;
@ -133,6 +134,7 @@ namespace netlist
using netlist_time = ptime<UINT128, NETLIST_INTERNAL_RES>; using netlist_time = ptime<UINT128, NETLIST_INTERNAL_RES>;
#else #else
using netlist_time = ptime<std::uint64_t, NETLIST_INTERNAL_RES>; using netlist_time = ptime<std::uint64_t, NETLIST_INTERNAL_RES>;
static_assert(noexcept(netlist_time::from_nsec(1)) == true, "Not evaluated as constexpr");
#endif #endif
} }