netlist: Nice performance increase by removing logic terminals from net if they are inactive. Introduced a linked-list class to abstract linked-lists. Fixed deactivating devices. You have to enable this because it is not guaranteed to be timing-exact. [Couriersud]

This commit is contained in:
Couriersud 2014-03-23 16:52:07 +00:00
parent 72292ef70a
commit 61300bfcb8
10 changed files with 264 additions and 112 deletions

View File

@ -32,7 +32,7 @@ ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets, NETLI
(*pn)->m_solver = this;
for (netlist_core_terminal_t *p = (*pn)->m_head; p != NULL; p = p->m_update_list_next)
for (netlist_core_terminal_t *p = (*pn)->m_list.first(); p != NULL; p = (*pn)->m_list.next(p))
{
NL_VERBOSE_OUT(("%s %s %d\n", p->name().cstr(), (*pn)->name().cstr(), (int) (*pn)->isRailNet()));
switch (p->type())
@ -627,12 +627,12 @@ ATTR_COLD static bool already_processed(net_groups_t groups, int &cur_group, net
ATTR_COLD static void process_net(net_groups_t groups, int &cur_group, netlist_net_t *net)
{
if (net->m_head == NULL)
if (net->m_list.is_empty())
return;
/* add the net */
SOLVER_VERBOSE_OUT(("add %d - %s\n", cur_group, net->name().cstr()));
groups[cur_group].add(net);
for (netlist_core_terminal_t *p = net->m_head; p != NULL; p = p->m_update_list_next)
for (netlist_core_terminal_t *p = net->m_list.first(); p != NULL; p = net->m_list.next(p))
{
SOLVER_VERBOSE_OUT(("terminal %s\n", p->name().cstr()));
if (p->isType(netlist_terminal_t::TERMINAL))
@ -855,7 +855,7 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
{
SOLVER_VERBOSE_OUT(("Net %d: %s\n", j, groups[i][j]->name().cstr()));
netlist_net_t *n = groups[i][j];
for (netlist_core_terminal_t *p = n->m_head; p != NULL; p = p->m_update_list_next)
for (netlist_core_terminal_t *p = n->m_list.first(); p != NULL; p = n->m_list.next(p))
{
SOLVER_VERBOSE_OUT((" %s\n", p->name().cstr()));
}

View File

@ -7,6 +7,8 @@
NETLIB_START(9316)
{
register_sub(subABCD, "subABCD");
sub.m_ABCD = &subABCD;
register_sub(sub, "sub");
register_subalias("CLK", sub.m_CLK);
@ -16,10 +18,10 @@ NETLIB_START(9316)
register_input("CLRQ", m_CLRQ);
register_input("LOADQ", m_LOADQ);
register_subalias("A", sub.m_A);
register_subalias("B", sub.m_B);
register_subalias("C", sub.m_C);
register_subalias("D", sub.m_D);
register_subalias("A", subABCD.m_A);
register_subalias("B", subABCD.m_B);
register_subalias("C", subABCD.m_C);
register_subalias("D", subABCD.m_D);
register_subalias("QA", sub.m_QA);
register_subalias("QB", sub.m_QB);
@ -32,17 +34,45 @@ NETLIB_START(9316)
NETLIB_RESET(9316)
{
sub.do_reset();
subABCD.do_reset();
}
NETLIB_START(9316_subABCD)
{
register_input("A", m_A);
register_input("B", m_B);
register_input("C", m_C);
register_input("D", m_D);
}
NETLIB_RESET(9316_subABCD)
{
if (1 || !USE_ADD_REMOVE_LIST)
{
m_A.inactivate();
m_B.inactivate();
m_C.inactivate();
m_D.inactivate();
}
}
ATTR_HOT inline UINT8 NETLIB_NAME(9316_subABCD::read_ABCD)()
{
if (1 || !USE_ADD_REMOVE_LIST)
return (INPLOGIC_PASSIVE(m_D) << 3) | (INPLOGIC_PASSIVE(m_C) << 2) | (INPLOGIC_PASSIVE(m_B) << 1) | (INPLOGIC_PASSIVE(m_A) << 0);
else
return (INPLOGIC(m_D) << 3) | (INPLOGIC(m_C) << 2) | (INPLOGIC(m_B) << 1) | (INPLOGIC(m_A) << 0);
}
NETLIB_UPDATE(9316_subABCD)
{
}
NETLIB_START(9316_sub)
{
register_input("CLK", m_CLK);
register_input("A", m_A);
register_input("B", m_B);
register_input("C", m_C);
register_input("D", m_D);
register_output("QA", m_QA);
register_output("QB", m_QB);
register_output("QC", m_QC);
@ -57,11 +87,6 @@ NETLIB_START(9316_sub)
NETLIB_RESET(9316_sub)
{
m_CLK.set_state(netlist_input_t::STATE_INP_LH);
m_A.set_state(netlist_input_t::STATE_INP_PASSIVE);
m_B.set_state(netlist_input_t::STATE_INP_PASSIVE);
m_C.set_state(netlist_input_t::STATE_INP_PASSIVE);
m_D.set_state(netlist_input_t::STATE_INP_PASSIVE);
m_cnt = 0;
m_loadq = 1;
m_ent = 1;
@ -84,7 +109,7 @@ NETLIB_UPDATE(9316_sub)
}
else
{
cnt = (INPLOGIC_PASSIVE(m_D) << 3) | (INPLOGIC_PASSIVE(m_C) << 2) | (INPLOGIC_PASSIVE(m_B) << 1) | (INPLOGIC_PASSIVE(m_A) << 0);
cnt = m_ABCD->read_ABCD();
update_outputs_all(cnt);
OUTLOGIC(m_RC, m_ent & (cnt == 0x0f), NLTIME_FROM_NS(20));
}
@ -109,9 +134,9 @@ NETLIB_UPDATE(9316)
{
cnt = 0;
sub.update_outputs(cnt);
OUTLOGIC(sub.m_RC, 0, NLTIME_FROM_NS(20));
//OUTLOGIC(sub.m_RC, 0, NLTIME_FROM_NS(20));
sub.m_cnt = cnt;
return;
//return;
}
}
OUTLOGIC(sub.m_RC, sub.m_ent & (sub.m_cnt == 0x0f), NLTIME_FROM_NS(20));
@ -177,10 +202,10 @@ NETLIB_START(9316_dip)
register_subalias("1", m_CLRQ);
register_subalias("2", sub.m_CLK);
register_subalias("3", sub.m_A);
register_subalias("4", sub.m_B);
register_subalias("5", sub.m_C);
register_subalias("6", sub.m_D);
register_subalias("3", subABCD.m_A);
register_subalias("4", subABCD.m_B);
register_subalias("5", subABCD.m_C);
register_subalias("6", subABCD.m_D);
register_subalias("7", m_ENP);
// register_subalias("8", ); --> GND

View File

@ -66,18 +66,23 @@
#define TTL_9316_DIP(_name) \
NET_REGISTER_DEV(9316_dip, _name)
NETLIB_SUBDEVICE(9316_subABCD,
netlist_ttl_input_t m_A;
netlist_ttl_input_t m_B;
netlist_ttl_input_t m_C;
netlist_ttl_input_t m_D;
ATTR_HOT inline UINT8 read_ABCD();
);
NETLIB_SUBDEVICE(9316_sub,
ATTR_HOT void update_outputs_all(const UINT8 cnt);
ATTR_HOT void update_outputs(const UINT8 cnt);
netlist_ttl_input_t m_CLK;
netlist_ttl_input_t m_A;
netlist_ttl_input_t m_B;
netlist_ttl_input_t m_C;
netlist_ttl_input_t m_D;
UINT8 m_cnt;
NETLIB_NAME(9316_subABCD) *m_ABCD;
netlist_sig_t m_loadq;
netlist_sig_t m_ent;
@ -90,6 +95,7 @@ NETLIB_SUBDEVICE(9316_sub,
NETLIB_DEVICE(9316,
NETLIB_NAME(9316_sub) sub;
NETLIB_NAME(9316_subABCD) subABCD;
netlist_ttl_input_t m_ENP;
netlist_ttl_input_t m_ENT;
netlist_ttl_input_t m_CLRQ;

View File

@ -104,29 +104,33 @@ public:
m_active = 1;
}
#if (USE_DEACTIVE_DEVICE)
ATTR_HOT void inc_active()
{
if (++m_active == 1)
{
update();
}
}
#if (USE_DEACTIVE_DEVICE)
ATTR_HOT void inc_active()
{
if (++m_active == 1)
{
update();
}
}
ATTR_HOT void dec_active()
{
if (--m_active == 0)
{
for (int i = 0; i< _numdev; i++)
m_i[i].inactivate();
}
}
#endif
ATTR_HOT void dec_active()
{
if (--m_active == 0)
{
for (int i = 0; i< _numdev; i++)
m_i[i].inactivate();
}
}
#endif
virtual void update()
{
const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) };
// FIXME: this check is needed because update is called during startup as well
if (UNEXPECTED(USE_DEACTIVE_DEVICE && m_active == 0))
return;
for (int i = 0; i< _numdev; i++)
{
this->m_i[i].activate();
@ -174,29 +178,33 @@ public:
m_active = 1;
}
#if (USE_DEACTIVE_DEVICE)
ATTR_HOT virtual void inc_active()
{
if (++m_active == 1)
{
update();
}
}
#if (USE_DEACTIVE_DEVICE)
ATTR_HOT virtual void inc_active()
{
if (++m_active == 1)
{
update();
}
}
ATTR_HOT virtual void dec_active()
{
if (--m_active == 0)
{
m_i[0].inactivate();
m_i[1].inactivate();
}
}
#endif
ATTR_HOT virtual void dec_active()
{
if (--m_active == 0)
{
m_i[0].inactivate();
m_i[1].inactivate();
}
}
#endif
ATTR_HOT ATTR_ALIGN void update()
{
const netlist_time times[2] = { NLTIME_FROM_NS(15), NLTIME_FROM_NS(22)};
// FIXME: this check is needed because update is called during startup as well
if (UNEXPECTED(USE_DEACTIVE_DEVICE && m_active == 0))
return;
m_i[0].activate();
m_i[1].activate();
#if 0

View File

@ -465,7 +465,6 @@ ATTR_COLD netlist_net_t::netlist_net_t(const type_t atype, const family_t afamil
: netlist_object_t(atype, afamily)
, m_solver(NULL)
, m_railterminal(NULL)
, m_head(NULL)
, m_num_cons(0)
, m_time(netlist_time::zero)
, m_active(0)
@ -484,10 +483,16 @@ ATTR_COLD netlist_net_t::~netlist_net_t()
netlist().remove_save_items(this);
}
ATTR_HOT void netlist_net_t::inc_active()
ATTR_HOT void netlist_net_t::inc_active(netlist_core_terminal_t &term)
{
m_active++;
if (USE_ADD_REMOVE_LIST)
{
m_list.insert(term);
//m_list.add(term);
}
if (USE_DEACTIVE_DEVICE)
{
if (m_active == 1 && m_in_queue > 0)
@ -516,9 +521,15 @@ ATTR_HOT void netlist_net_t::inc_active()
}
}
ATTR_HOT void netlist_net_t::dec_active()
ATTR_HOT void netlist_net_t::dec_active(netlist_core_terminal_t &term)
{
m_active--;
if (USE_ADD_REMOVE_LIST)
{
m_list.remove(term);
}
if (USE_DEACTIVE_DEVICE)
{
if (m_active == 0)
@ -539,9 +550,12 @@ ATTR_COLD void netlist_net_t::reset()
m_active = 0;
m_in_queue = 2;
for (netlist_core_terminal_t *t = m_head; t != NULL; t = t->m_update_list_next)
for (netlist_core_terminal_t *t = m_list.first(); t != NULL; t = m_list.next(t))
{
t->do_reset();
}
for (netlist_core_terminal_t *t = m_list.first(); t != NULL; t = m_list.next(t))
{
if (t->state() != netlist_input_t::STATE_INP_PASSIVE)
m_active++;
}
@ -589,15 +603,15 @@ ATTR_COLD void netlist_net_t::merge_net(netlist_net_t *othernet)
}
else
{
netlist_core_terminal_t *p = othernet->m_head;
netlist_core_terminal_t *p = othernet->m_list.first();
while (p != NULL)
{
netlist_core_terminal_t *pn = p->m_update_list_next;
netlist_core_terminal_t *pn = othernet->m_list.next(p);
register_con(*p);
p = pn;
}
othernet->m_head = NULL; // FIXME: othernet needs to be free'd from memory
othernet->m_list.clear(); // FIXME: othernet needs to be free'd from memory
}
}
@ -605,8 +619,7 @@ ATTR_COLD void netlist_net_t::register_con(netlist_core_terminal_t &terminal)
{
terminal.set_net(*this);
terminal.m_update_list_next = m_head;
m_head = &terminal;
m_list.insert(terminal);
m_num_cons++;
if (terminal.state() != netlist_input_t::STATE_INP_PASSIVE)
@ -632,38 +645,52 @@ ATTR_HOT ATTR_ALIGN inline void netlist_net_t::update_devs()
const UINT32 masks[4] = { 1, 5, 3, 1 };
const UINT32 mask = masks[ (m_last_Q << 1) | m_new_Q ];
netlist_core_terminal_t *p = m_head;
netlist_core_terminal_t *p = m_list.first();
m_in_queue = 2; /* mark as taken ... */
m_cur_Q = m_new_Q;
m_cur_Analog = m_new_Analog;
#if 1
switch (m_num_cons)
if (USE_ADD_REMOVE_LIST)
{
case 2:
update_dev(p, mask);
p = p->m_update_list_next;
case 1:
update_dev(p, mask);
break;
default:
do
switch (m_active)
{
case 2:
update_dev(p, mask);
p = p->m_update_list_next;
} while (p != NULL);
break;
p = m_list.next(p);
if (p == NULL) break;
case 1:
update_dev(p, mask);
break;
default:
while (p != NULL)
{
update_dev(p, mask);
p = m_list.next(p);
}
break;
}
}
#else
do
else
{
update_dev(p, mask);
p = p->m_update_list_next;
} while (p != NULL);
#endif
switch (m_num_cons)
{
case 2:
update_dev(p, mask);
p = m_list.next(p);
case 1:
update_dev(p, mask);
break;
default:
do
{
update_dev(p, mask);
p = m_list.next(p);
} while (p != NULL);
break;
}
}
m_last_Q = m_cur_Q;
m_last_Analog = m_cur_Analog;
}
@ -680,8 +707,8 @@ ATTR_HOT void netlist_net_t::solve()
ATTR_COLD netlist_core_terminal_t::netlist_core_terminal_t(const type_t atype, const family_t afamily)
: netlist_owned_object_t(atype, afamily)
, plinked_list_element<netlist_core_terminal_t>()
, m_family_desc(NULL)
, m_update_list_next(NULL)
, m_net(NULL)
, m_state(STATE_NONEX)
{

View File

@ -364,7 +364,7 @@ private:
// netlist_core_terminal_t
// ----------------------------------------------------------------------------------------
class netlist_core_terminal_t : public netlist_owned_object_t
class netlist_core_terminal_t : public netlist_owned_object_t, public plinked_list_element<netlist_core_terminal_t>
{
NETLIST_PREVENT_COPYING(netlist_core_terminal_t)
public:
@ -403,8 +403,6 @@ public:
const netlist_logic_family_desc_t *m_family_desc;
netlist_core_terminal_t *m_update_list_next;
protected:
ATTR_COLD virtual void save_register()
{
@ -568,8 +566,8 @@ public:
ATTR_HOT inline const netlist_core_terminal_t & RESTRICT railterminal() const { return *m_railterminal; }
/* Everything below is used by the logic subsystem */
ATTR_HOT void inc_active();
ATTR_HOT void dec_active();
ATTR_HOT void inc_active(netlist_core_terminal_t &term);
ATTR_HOT void dec_active(netlist_core_terminal_t &term);
ATTR_HOT inline const netlist_sig_t Q() const
{
@ -627,7 +625,7 @@ public:
ATTR_HOT void solve();
netlist_core_terminal_t *m_head;
plinked_list<netlist_core_terminal_t> m_list;
protected: //FIXME: needed by current solver code
@ -1159,15 +1157,15 @@ ATTR_HOT inline void netlist_input_t::inactivate()
if (EXPECTED(!is_state(STATE_INP_PASSIVE)))
{
set_state(STATE_INP_PASSIVE);
net().dec_active();
net().dec_active(*this);
}
}
ATTR_HOT inline void netlist_input_t::activate()
{
if (EXPECTED(is_state(STATE_INP_PASSIVE)))
if (is_state(STATE_INP_PASSIVE))
{
net().inc_active();
net().inc_active(*this);
set_state(STATE_INP_ACTIVE);
}
}
@ -1176,7 +1174,7 @@ ATTR_HOT inline void netlist_input_t::activate_hl()
{
if (is_state(STATE_INP_PASSIVE))
{
net().inc_active();
net().inc_active(*this);
set_state(STATE_INP_HL);
}
}
@ -1185,7 +1183,7 @@ ATTR_HOT inline void netlist_input_t::activate_lh()
{
if (is_state(STATE_INP_PASSIVE))
{
net().inc_active();
net().inc_active(*this);
set_state(STATE_INP_LH);
}
}

View File

@ -23,11 +23,15 @@
*/
#define USE_PMFDELEGATES (0)
// This used to add 20% performance ... but is not guaranteed to be absolutely timing correct.
// Update 01.01.2014: Currently, enabling this has no observable impact on performance.
// This increases performance in circuits with a lot of gates
// but is not guaranteed to be absolutely timing correct.
#define USE_DEACTIVE_DEVICE (0)
// The following adds about 10% performance ...
#define USE_ADD_REMOVE_LIST (1)
#define USE_OPENMP (0)
// Use nano-second resolution - Sufficient for now

View File

@ -293,5 +293,82 @@ private:
netlist_list_t<_StackClass, _NumElem> m_list;
};
template <class _ListClass>
struct plinked_list_element
{
plinked_list_element() : m_next(NULL) {}
_ListClass * m_next;
};
template <class _ListClass>
class plinked_list
{
public:
plinked_list() : m_head(NULL) {}
ATTR_HOT inline void insert(const _ListClass &before, _ListClass &elem)
{
if (m_head == &before)
{
elem.m_next = m_head;
m_head = elem;
}
else
{
_ListClass *p = m_head;
while (p != NULL)
{
if (p->m_next == &before)
{
elem->m_next = &before;
p->m_next = &elem;
return;
}
p = p->m_next;
}
assert_always(false, "element not found");
}
}
ATTR_HOT inline void insert(_ListClass &elem)
{
elem.m_next = m_head;
m_head = &elem;
}
ATTR_HOT inline void add(_ListClass &elem)
{
_ListClass **p = &m_head;
while (*p != NULL)
{
p = &((*p)->m_next);
}
*p = &elem;
elem.m_next = NULL;
}
ATTR_HOT inline void remove(const _ListClass &elem)
{
_ListClass **p = &m_head;
while (*p != &elem)
{
assert(*p != NULL);
p = &((*p)->m_next);
}
(*p) = elem.m_next;
}
ATTR_HOT static inline _ListClass *next(const _ListClass &elem) { return elem.m_next; }
ATTR_HOT static inline _ListClass *next(const _ListClass *elem) { return elem->m_next; }
ATTR_HOT inline _ListClass *first() const { return m_head; }
ATTR_HOT inline void clear() { m_head = NULL; }
ATTR_HOT inline bool is_empty() const { return (m_head == NULL); }
private:
_ListClass *m_head;
};
#endif /* NLLISTS_H_ */

View File

@ -402,15 +402,15 @@ nld_base_d_to_a_proxy *netlist_setup_t::get_d_a_proxy(netlist_output_t &out)
#if 1
/* connect all existing terminals to new net */
netlist_core_terminal_t *p = out.net().m_head;
netlist_core_terminal_t *p = out.net().m_list.first();
while (p != NULL)
{
netlist_core_terminal_t *np = p->m_update_list_next;
netlist_core_terminal_t *np = out.net().m_list.next(p);
p->clear_net(); // de-link from all nets ...
connect(proxy->out(), *p);
p = np;
}
out.net().m_head = NULL; // clear the list
out.net().m_list.clear(); // clear the list
out.net().m_num_cons = 0;
#endif
out.net().register_con(proxy->m_I);
@ -620,7 +620,7 @@ void netlist_setup_t::resolve_inputs()
for (netlist_net_t *const *pn = netlist().m_nets.first(); pn != NULL; pn = netlist().m_nets.next(pn))
{
if ((*pn)->m_head == NULL)
if ((*pn)->m_list.is_empty())
{
todelete.add(*pn);
}

View File

@ -57,6 +57,13 @@ void free_file_line( void *memory, const char *file, int line )
osd_free( memory );
}
void CLIB_DECL logerror(const char *format, ...)
{
va_list arg;
va_start(arg, format);
vprintf(format, arg);
va_end(arg);
}
struct options_entry oplist[] =
{