mirror of
https://github.com/holub/mame
synced 2025-06-01 10:31:48 +03:00
Netlist refactoring
- align timed_queue closer to std::priority_queue - use uint8_t in extended clock for better memory usage. - minor changes to nl_breakout.cpp (nw)
This commit is contained in:
parent
418a0ee67d
commit
1a2f928403
@ -119,7 +119,7 @@ namespace netlist
|
||||
, m_cnt(*this, "m_cnt", 0)
|
||||
, m_off(*this, "m_off", netlist_time::zero())
|
||||
{
|
||||
m_inc[0] = netlist_time::from_double(1.0 / (m_freq()*2.0));
|
||||
m_inc[0] = netlist_time::from_double(1.0 / (m_freq() * 2.0));
|
||||
|
||||
connect(m_feedback, m_Q);
|
||||
{
|
||||
@ -127,8 +127,8 @@ namespace netlist
|
||||
std::vector<pstring> pat(plib::psplit(m_pattern(),","));
|
||||
m_off = netlist_time::from_double(m_offset());
|
||||
|
||||
unsigned long pati[256];
|
||||
m_size = pat.size();
|
||||
unsigned long pati[32];
|
||||
m_size = static_cast<std::uint8_t>(pat.size());
|
||||
unsigned long total = 0;
|
||||
for (unsigned i=0; i<m_size; i++)
|
||||
{
|
||||
@ -155,10 +155,10 @@ namespace netlist
|
||||
|
||||
logic_input_t m_feedback;
|
||||
logic_output_t m_Q;
|
||||
netlist_time m_inc[32];
|
||||
state_var<unsigned> m_cnt;
|
||||
state_var<std::uint8_t> m_cnt;
|
||||
std::uint8_t m_size;
|
||||
state_var<netlist_time> m_off;
|
||||
std::size_t m_size;
|
||||
netlist_time m_inc[32];
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -147,7 +147,7 @@ const logic_family_desc_t *family_CD4XXX()
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
detail::queue_t::queue_t(netlist_t &nl)
|
||||
: timed_queue<net_t *, netlist_time>(512)
|
||||
: timed_queue<pqentry_t<net_t *, netlist_time>>(512)
|
||||
, netlist_ref(nl)
|
||||
, plib::state_manager_t::callback_t()
|
||||
, m_qsize(0)
|
||||
@ -537,13 +537,15 @@ void netlist_t::process_queue(const netlist_time &delta) NL_NOEXCEPT
|
||||
|
||||
if (m_mainclock == nullptr)
|
||||
{
|
||||
detail::queue_t::entry_t e(m_queue.pop());
|
||||
detail::queue_t::entry_t e(m_queue.top());
|
||||
m_queue.pop();
|
||||
m_time = e.m_exec_time;
|
||||
while (e.m_object != nullptr)
|
||||
{
|
||||
e.m_object->update_devs();
|
||||
m_perf_out_processed.inc();
|
||||
e = m_queue.pop();
|
||||
e = m_queue.top();
|
||||
m_queue.pop();
|
||||
m_time = e.m_exec_time;
|
||||
}
|
||||
}
|
||||
@ -565,7 +567,8 @@ void netlist_t::process_queue(const netlist_time &delta) NL_NOEXCEPT
|
||||
mc_time += inc;
|
||||
}
|
||||
|
||||
e = m_queue.pop();
|
||||
e = m_queue.top();
|
||||
m_queue.pop();
|
||||
m_time = e.m_exec_time;
|
||||
if (e.m_object != nullptr)
|
||||
{
|
||||
@ -780,9 +783,9 @@ detail::net_t::net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr)
|
||||
, 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_time(*this, "m_time", netlist_time::zero())
|
||||
, m_active(*this, "m_active", 0)
|
||||
, m_in_queue(*this, "m_in_queue", QS_DELIVERED)
|
||||
, m_cur_Analog(*this, "m_cur_Analog", 0.0)
|
||||
, m_railterminal(mr)
|
||||
{
|
||||
|
@ -320,11 +320,15 @@ namespace netlist
|
||||
//! Copy Constructor.
|
||||
state_var(const state_var &rhs) NL_NOEXCEPT = default;
|
||||
//! Move Constructor.
|
||||
state_var(state_var &&rhs) NL_NOEXCEPT = default;
|
||||
state_var(state_var &&rhs) NL_NOEXCEPT { std::swap(m_value, rhs.m_value); }
|
||||
//! Assignment operator to assign value of a state var.
|
||||
state_var &operator=(const state_var &rhs) NL_NOEXCEPT { m_value = rhs; return *this; }
|
||||
state_var &operator=(const state_var &rhs) NL_NOEXCEPT { m_value = rhs.m_value; return *this; }
|
||||
//! Assignment move operator to assign value of a state var.
|
||||
state_var &operator=(state_var &&rhs) NL_NOEXCEPT { std::swap(m_value, rhs.m_value); return *this; }
|
||||
//! Assignment operator to assign value of type T.
|
||||
state_var &operator=(const T &rhs) NL_NOEXCEPT { m_value = rhs; return *this; }
|
||||
//! Assignment move operator to assign value of type T.
|
||||
state_var &operator=(T &&rhs) NL_NOEXCEPT { std::swap(m_value, rhs); return *this; }
|
||||
//! Return value of state variable.
|
||||
operator T & () NL_NOEXCEPT { return m_value; }
|
||||
//! Return const value of state variable.
|
||||
@ -716,8 +720,8 @@ namespace netlist
|
||||
|
||||
void update_devs() NL_NOEXCEPT;
|
||||
|
||||
netlist_time time() const NL_NOEXCEPT { return m_time; }
|
||||
void set_time(const netlist_time ntime) NL_NOEXCEPT { m_time = ntime; }
|
||||
const netlist_time &time() const NL_NOEXCEPT { return m_time; }
|
||||
void set_time(const netlist_time &ntime) NL_NOEXCEPT { m_time = ntime; }
|
||||
|
||||
bool isRailNet() const { return !(m_railterminal == nullptr); }
|
||||
core_terminal_t & railterminal() const { return *m_railterminal; }
|
||||
@ -743,10 +747,10 @@ namespace netlist
|
||||
protected:
|
||||
state_var<netlist_sig_t> m_new_Q;
|
||||
state_var<netlist_sig_t> m_cur_Q;
|
||||
state_var<queue_status> m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */
|
||||
|
||||
state_var<netlist_time> m_time;
|
||||
state_var_s32 m_active;
|
||||
state_var<queue_status> m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */
|
||||
|
||||
state_var<nl_double> m_cur_Analog;
|
||||
|
||||
@ -1174,11 +1178,12 @@ namespace netlist
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class detail::queue_t :
|
||||
public timed_queue<net_t *, netlist_time>,
|
||||
public timed_queue<pqentry_t<net_t *, netlist_time>>,
|
||||
public detail::netlist_ref,
|
||||
public plib::state_manager_t::callback_t
|
||||
{
|
||||
public:
|
||||
typedef pqentry_t<net_t *, netlist_time> entry_t;
|
||||
explicit queue_t(netlist_t &nl);
|
||||
|
||||
protected:
|
||||
@ -1214,7 +1219,7 @@ namespace netlist
|
||||
nl_double gmin() const;
|
||||
|
||||
void process_queue(const netlist_time &delta) NL_NOEXCEPT;
|
||||
void abort_current_queue_slice() { m_queue.retime(nullptr, m_time); }
|
||||
void abort_current_queue_slice() { m_queue.retime(detail::queue_t::entry_t(m_time, nullptr)); }
|
||||
|
||||
/* Control functions */
|
||||
|
||||
|
@ -49,43 +49,64 @@ namespace netlist
|
||||
void unlock() const noexcept { }
|
||||
};
|
||||
|
||||
#if !USE_HEAP
|
||||
template <class Element, class Time>
|
||||
struct pqentry_t final
|
||||
{
|
||||
constexpr pqentry_t() noexcept : m_exec_time(), m_object(nullptr) { }
|
||||
constexpr pqentry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { }
|
||||
constexpr pqentry_t(const pqentry_t &e) noexcept : m_exec_time(e.m_exec_time), m_object(e.m_object) { }
|
||||
pqentry_t(pqentry_t &&e) noexcept { swap(e); }
|
||||
~pqentry_t() = default;
|
||||
|
||||
pqentry_t& operator=(pqentry_t && other) noexcept
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
pqentry_t& operator=(const pqentry_t &other) noexcept
|
||||
{
|
||||
pqentry_t t(other);
|
||||
swap(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(pqentry_t &other) noexcept
|
||||
{
|
||||
std::swap(m_exec_time, other.m_exec_time);
|
||||
std::swap(m_object, other.m_object);
|
||||
}
|
||||
|
||||
struct QueueOp
|
||||
{
|
||||
static constexpr bool less(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
|
||||
{
|
||||
return (lhs.m_exec_time < rhs.m_exec_time);
|
||||
}
|
||||
|
||||
static constexpr bool equal(const pqentry_t &lhs, const pqentry_t &rhs) noexcept
|
||||
{
|
||||
return lhs.m_object == rhs.m_object;
|
||||
}
|
||||
|
||||
static constexpr bool equal(const pqentry_t &lhs, const Element &rhs) noexcept
|
||||
{
|
||||
return lhs.m_object == rhs;
|
||||
}
|
||||
|
||||
static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); }
|
||||
};
|
||||
|
||||
Time m_exec_time;
|
||||
Element m_object;
|
||||
};
|
||||
|
||||
#if !USE_HEAP
|
||||
template <class T, class QueueOp = typename T::QueueOp>
|
||||
class timed_queue : plib::nocopyassignmove
|
||||
{
|
||||
public:
|
||||
|
||||
struct entry_t final
|
||||
{
|
||||
constexpr entry_t() noexcept : m_exec_time(), m_object(nullptr) { }
|
||||
constexpr entry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { }
|
||||
constexpr entry_t(const entry_t &e) noexcept : m_exec_time(e.m_exec_time), m_object(e.m_object) { }
|
||||
entry_t(entry_t &&e) noexcept { swap(e); }
|
||||
~entry_t() = default;
|
||||
|
||||
entry_t& operator=(entry_t && other) noexcept
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
entry_t& operator=(const entry_t &other) noexcept
|
||||
{
|
||||
entry_t t(other);
|
||||
swap(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(entry_t &other) noexcept
|
||||
{
|
||||
std::swap(m_exec_time, other.m_exec_time);
|
||||
std::swap(m_object, other.m_object);
|
||||
}
|
||||
|
||||
Time m_exec_time;
|
||||
Element m_object;
|
||||
};
|
||||
|
||||
timed_queue(const std::size_t list_size)
|
||||
: m_list(list_size)
|
||||
{
|
||||
@ -95,12 +116,12 @@ namespace netlist
|
||||
constexpr std::size_t capacity() const noexcept { return m_list.capacity() - 1; }
|
||||
constexpr bool empty() const noexcept { return (m_end == &m_list[1]); }
|
||||
|
||||
void push(entry_t &&e) noexcept
|
||||
void push(T &&e) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
tqlock lck(m_lock);
|
||||
entry_t * i = m_end;
|
||||
for (; e.m_exec_time > (i - 1)->m_exec_time; --i)
|
||||
T * i = m_end;
|
||||
for (; QueueOp::less(*(i - 1), e); --i)
|
||||
{
|
||||
*(i) = *(i-1);
|
||||
m_prof_sortmove.inc();
|
||||
@ -110,16 +131,17 @@ namespace netlist
|
||||
m_prof_call.inc();
|
||||
}
|
||||
|
||||
entry_t pop() noexcept { return *(--m_end); }
|
||||
const entry_t &top() const noexcept { return *(m_end-1); }
|
||||
void pop() noexcept { --m_end; }
|
||||
const T &top() const noexcept { return *(m_end-1); }
|
||||
|
||||
void remove(const Element &elem) noexcept
|
||||
template <class R>
|
||||
void remove(const R &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
tqlock lck(m_lock);
|
||||
for (entry_t * i = m_end - 1; i > &m_list[0]; i--)
|
||||
for (T * i = m_end - 1; i > &m_list[0]; i--)
|
||||
{
|
||||
if (i->m_object == elem)
|
||||
if (QueueOp::equal(*i, elem))
|
||||
{
|
||||
m_end--;
|
||||
for (;i < m_end; i++)
|
||||
@ -129,21 +151,21 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
void retime(const Element &elem, const Time t) noexcept
|
||||
void retime(const T &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
tqlock lck(m_lock);
|
||||
for (entry_t * i = m_end - 1; i > &m_list[0]; i--)
|
||||
for (T * i = m_end - 1; i > &m_list[0]; i--)
|
||||
{
|
||||
if (i->m_object == elem)
|
||||
if (QueueOp::equal(*i, elem)) // partial equal!
|
||||
{
|
||||
i->m_exec_time = t;
|
||||
while ((i-1)->m_exec_time < i->m_exec_time)
|
||||
*i = elem;
|
||||
while (QueueOp::less(*(i-1), *i))
|
||||
{
|
||||
std::swap(*(i-1), *i);
|
||||
i--;
|
||||
}
|
||||
while (i < m_end && (i+1)->m_exec_time > i->m_exec_time)
|
||||
while (i < m_end && QueueOp::less(*i, *(i+1)))
|
||||
{
|
||||
std::swap(*(i+1), *i);
|
||||
i++;
|
||||
@ -161,15 +183,15 @@ namespace netlist
|
||||
* the insert algo above will run into this element and doesn't
|
||||
* need a comparison with queue start.
|
||||
*/
|
||||
m_list[0] = { Time::never(), Element(0) };
|
||||
m_list[0] = QueueOp::never();
|
||||
m_end++;
|
||||
}
|
||||
|
||||
// save state support & mame disasm
|
||||
|
||||
constexpr const entry_t *listptr() const { return &m_list[1]; }
|
||||
constexpr const T *listptr() const { return &m_list[1]; }
|
||||
constexpr std::size_t size() const noexcept { return static_cast<std::size_t>(m_end - &m_list[1]); }
|
||||
constexpr const entry_t & operator[](const std::size_t index) const { return m_list[ 1 + index]; }
|
||||
constexpr const T & operator[](const std::size_t index) const { return m_list[ 1 + index]; }
|
||||
private:
|
||||
#if HAS_OPENMP && USE_OPENMP
|
||||
using tqmutex = pspin_mutex<true>;
|
||||
@ -179,8 +201,8 @@ namespace netlist
|
||||
using tqlock = std::lock_guard<tqmutex>;
|
||||
|
||||
tqmutex m_lock;
|
||||
entry_t * m_end;
|
||||
std::vector<entry_t> m_list;
|
||||
T * m_end;
|
||||
std::vector<T> m_list;
|
||||
|
||||
public:
|
||||
// profiling
|
||||
@ -188,45 +210,14 @@ namespace netlist
|
||||
nperfcount_t m_prof_call;
|
||||
};
|
||||
#else
|
||||
template <class Element, class Time>
|
||||
template <class T, class QueueOp = typename T::QueueOp>
|
||||
class timed_queue : plib::nocopyassignmove
|
||||
{
|
||||
public:
|
||||
|
||||
struct entry_t final
|
||||
{
|
||||
constexpr entry_t() noexcept : m_exec_time(), m_object(nullptr) { }
|
||||
constexpr entry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { }
|
||||
constexpr entry_t(const entry_t &e) noexcept : m_exec_time(e.m_exec_time), m_object(e.m_object) { }
|
||||
entry_t(entry_t &&e) noexcept { swap(e); }
|
||||
~entry_t() = default;
|
||||
|
||||
entry_t& operator=(entry_t && other) noexcept
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
entry_t& operator=(const entry_t &other) noexcept
|
||||
{
|
||||
entry_t t(other);
|
||||
swap(t);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(entry_t &other) noexcept
|
||||
{
|
||||
std::swap(m_exec_time, other.m_exec_time);
|
||||
std::swap(m_object, other.m_object);
|
||||
}
|
||||
|
||||
Time m_exec_time;
|
||||
Element m_object;
|
||||
};
|
||||
|
||||
struct compare
|
||||
{
|
||||
bool operator()(const entry_t &a, const entry_t &b) { return a.m_exec_time > b.m_exec_time; }
|
||||
bool operator()(const T &a, const T &b) { return QueueOp::less(b,a); }
|
||||
};
|
||||
|
||||
timed_queue(const std::size_t list_size)
|
||||
@ -238,7 +229,7 @@ namespace netlist
|
||||
constexpr std::size_t capacity() const noexcept { return m_list.capacity(); }
|
||||
constexpr bool empty() const noexcept { return &m_list[0] == m_end; }
|
||||
|
||||
void push(entry_t &&e) noexcept
|
||||
void push(T &&e) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
tqlock lck(m_lock);
|
||||
@ -247,23 +238,22 @@ namespace netlist
|
||||
m_prof_call.inc();
|
||||
}
|
||||
|
||||
entry_t pop() noexcept
|
||||
void pop() noexcept
|
||||
{
|
||||
entry_t t(m_list[0]);
|
||||
std::pop_heap(&m_list[0], m_end, compare());
|
||||
m_end--;
|
||||
return t;
|
||||
}
|
||||
|
||||
const entry_t &top() const noexcept { return m_list[0]; }
|
||||
const T &top() const noexcept { return m_list[0]; }
|
||||
|
||||
void remove(const Element &elem) noexcept
|
||||
template <class R>
|
||||
void remove(const R &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
tqlock lck(m_lock);
|
||||
for (entry_t * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
for (T * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
{
|
||||
if (i->m_object == elem)
|
||||
if (QueueOp::equal(*i, elem))
|
||||
{
|
||||
m_end--;
|
||||
for (;i < m_end; i++)
|
||||
@ -274,15 +264,15 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
void retime(const Element &elem, const Time t) noexcept
|
||||
void retime(const T &elem) noexcept
|
||||
{
|
||||
/* Lock */
|
||||
tqlock lck(m_lock);
|
||||
for (entry_t * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
for (T * i = m_end - 1; i >= &m_list[0]; i--)
|
||||
{
|
||||
if (i->m_object == elem)
|
||||
if (QueueOp::equal(*i, elem)) // partial equal!
|
||||
{
|
||||
i->m_exec_time = t;
|
||||
*i = elem;
|
||||
std::make_heap(&m_list[0], m_end, compare());
|
||||
return;
|
||||
}
|
||||
@ -298,9 +288,9 @@ namespace netlist
|
||||
|
||||
// save state support & mame disasm
|
||||
|
||||
constexpr const entry_t *listptr() const { return &m_list[0]; }
|
||||
constexpr const T *listptr() const { return &m_list[0]; }
|
||||
constexpr std::size_t size() const noexcept { return m_list.size(); }
|
||||
constexpr const entry_t & operator[](const std::size_t index) const { return m_list[ 0 + index]; }
|
||||
constexpr const T & operator[](const std::size_t index) const { return m_list[ 0 + index]; }
|
||||
private:
|
||||
#if HAS_OPENMP && USE_OPENMP
|
||||
using tqmutex = pspin_mutex<true>;
|
||||
@ -310,8 +300,8 @@ namespace netlist
|
||||
using tqlock = std::lock_guard<tqmutex>;
|
||||
|
||||
tqmutex m_lock;
|
||||
std::vector<entry_t> m_list;
|
||||
entry_t *m_end;
|
||||
std::vector<T> m_list;
|
||||
T *m_end;
|
||||
|
||||
public:
|
||||
// profiling
|
||||
|
@ -91,6 +91,7 @@ CIRCUIT_LAYOUT( breakout )
|
||||
#if (SLOW_BUT_ACCURATE)
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-8) // less accuracy and diode will not work
|
||||
PARAM(Solver.METHOD, "MAT_CR")
|
||||
#else
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-6)
|
||||
@ -128,7 +129,7 @@ CIRCUIT_LAYOUT( breakout )
|
||||
//----------------------------------------------------------------
|
||||
// Clock circuit
|
||||
//----------------------------------------------------------------
|
||||
#if 0 || (SLOW_BUT_ACCURATE)
|
||||
#if (SLOW_BUT_ACCURATE)
|
||||
MAINCLOCK(Y1, 14318000.0)
|
||||
CHIP("F1", 9316)
|
||||
NET_C(Y1.Q, F1.2)
|
||||
|
Loading…
Reference in New Issue
Block a user