mirror of
https://github.com/holub/mame
synced 2025-04-23 17:00:53 +03:00
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:
parent
b49a2e6e49
commit
6381ed11ed
@ -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))
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user