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)
{
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))

View File

@ -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<logic_output_t, 4> 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));
}

View File

@ -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 <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)
{
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<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)
{

View File

@ -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<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:
state_var<netlist_sig_t> m_new_Q;
state_var<netlist_sig_t> m_cur_Q;
@ -768,7 +788,7 @@ namespace netlist
core_terminal_t * m_railterminal;
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
@ -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();

View File

@ -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

View File

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