mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
netlist: more header file separation
This commit is contained in:
parent
7df1f8de26
commit
923de88abb
@ -50,9 +50,15 @@ project "netlist"
|
||||
MAME_DIR .. "src/lib/netlist/nl_setup.cpp",
|
||||
MAME_DIR .. "src/lib/netlist/nl_setup.h",
|
||||
MAME_DIR .. "src/lib/netlist/nl_types.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/analog.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/base_objects.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/core_device.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/device.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/exec.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/logic_family.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/logic.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/nets.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/object_array.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/param.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/setup.h",
|
||||
MAME_DIR .. "src/lib/netlist/core/state_var.h",
|
||||
|
@ -156,6 +156,11 @@ namespace netlist
|
||||
analog_net_t m_my_net;
|
||||
};
|
||||
|
||||
inline solver::matrix_solver_t *analog_t::solver() const noexcept
|
||||
{
|
||||
return (this->has_net() ? net().solver() : nullptr);
|
||||
}
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
|
@ -181,9 +181,6 @@ namespace netlist
|
||||
netlist_state_t &state() noexcept;
|
||||
const netlist_state_t &state() const noexcept;
|
||||
|
||||
netlist_t &exec() noexcept;
|
||||
const netlist_t &exec() const noexcept;
|
||||
|
||||
private:
|
||||
core_device_t * m_device;
|
||||
};
|
||||
|
130
src/lib/netlist/core/core_device.h
Normal file
130
src/lib/netlist/core/core_device.h
Normal file
@ -0,0 +1,130 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
///
|
||||
/// \file device.h
|
||||
///
|
||||
|
||||
#ifndef NL_CORE_DEVICE_H_
|
||||
#define NL_CORE_DEVICE_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/pstring.h"
|
||||
#include "base_objects.h"
|
||||
#include "logic_family.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// core_device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// FIXME: belongs into detail namespace
|
||||
class core_device_t : public detail::netlist_object_t
|
||||
{
|
||||
public:
|
||||
core_device_t(netlist_state_t &owner, const pstring &name);
|
||||
core_device_t(core_device_t &owner, const pstring &name);
|
||||
|
||||
PCOPYASSIGNMOVE(core_device_t, delete)
|
||||
|
||||
virtual ~core_device_t() noexcept = default;
|
||||
|
||||
void do_inc_active() noexcept
|
||||
{
|
||||
if (m_hint_deactivate)
|
||||
{
|
||||
if (++m_active_outputs == 1)
|
||||
{
|
||||
if (m_stats)
|
||||
m_stats->m_stat_inc_active.inc();
|
||||
inc_active();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_dec_active() noexcept
|
||||
{
|
||||
if (m_hint_deactivate)
|
||||
if (--m_active_outputs == 0)
|
||||
{
|
||||
dec_active();
|
||||
}
|
||||
}
|
||||
|
||||
void set_hint_deactivate(bool v) noexcept { m_hint_deactivate = v; }
|
||||
bool get_hint_deactivate() const noexcept { return m_hint_deactivate; }
|
||||
// Has to be set in device reset
|
||||
void set_active_outputs(int n) noexcept { m_active_outputs = n; }
|
||||
|
||||
// stats
|
||||
struct stats_t
|
||||
{
|
||||
// NL_KEEP_STATISTICS
|
||||
plib::pperftime_t<true> m_stat_total_time;
|
||||
plib::pperfcount_t<true> m_stat_call_count;
|
||||
plib::pperfcount_t<true> m_stat_inc_active;
|
||||
};
|
||||
|
||||
stats_t * stats() const noexcept { return m_stats.get(); }
|
||||
#if 0
|
||||
virtual void update() noexcept { }
|
||||
#endif
|
||||
virtual void reset() { }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void inc_active() noexcept { }
|
||||
virtual void dec_active() noexcept { }
|
||||
|
||||
log_type & log();
|
||||
|
||||
public:
|
||||
virtual void timestep(timestep_type ts_type, nl_fptype st) noexcept { plib::unused_var(ts_type, st); }
|
||||
virtual void update_terminals() noexcept { }
|
||||
|
||||
virtual void update_param() noexcept {}
|
||||
virtual bool is_dynamic() const noexcept { return false; }
|
||||
virtual bool is_timestep() const noexcept { return false; }
|
||||
|
||||
private:
|
||||
bool m_hint_deactivate;
|
||||
state_var_s32 m_active_outputs;
|
||||
device_arena::unique_ptr<stats_t> m_stats;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// base_device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class base_device_t : public core_device_t
|
||||
{
|
||||
public:
|
||||
base_device_t(netlist_state_t &owner, const pstring &name);
|
||||
base_device_t(base_device_t &owner, const pstring &name);
|
||||
|
||||
PCOPYASSIGNMOVE(base_device_t, delete)
|
||||
|
||||
~base_device_t() noexcept override = default;
|
||||
|
||||
template<class O, class C, typename... Args>
|
||||
void create_and_register_subdevice(O& owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args)
|
||||
{
|
||||
dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void register_subalias(const pstring &name, const detail::core_terminal_t &term);
|
||||
void register_subalias(const pstring &name, const pstring &aliased);
|
||||
|
||||
void connect(const pstring &t1, const pstring &t2);
|
||||
void connect(const detail::core_terminal_t &t1, const detail::core_terminal_t &t2);
|
||||
protected:
|
||||
|
||||
//NETLIB_UPDATE_TERMINALSI() { }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_DEVICE_H_
|
@ -5,132 +5,20 @@
|
||||
/// \file device.h
|
||||
///
|
||||
|
||||
#ifndef NL_CORE_DEVICE_H_
|
||||
#define NL_CORE_DEVICE_H_
|
||||
#ifndef NL_DEVICE_H_
|
||||
#define NL_DEVICE_H_
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/pstring.h"
|
||||
#include "base_objects.h"
|
||||
#include "logic_family.h"
|
||||
#include "core_device.h"
|
||||
#include "param.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// core_device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
// FIXME: belongs into detail namespace
|
||||
class core_device_t : public detail::netlist_object_t
|
||||
{
|
||||
public:
|
||||
core_device_t(netlist_state_t &owner, const pstring &name);
|
||||
core_device_t(core_device_t &owner, const pstring &name);
|
||||
|
||||
PCOPYASSIGNMOVE(core_device_t, delete)
|
||||
|
||||
virtual ~core_device_t() noexcept = default;
|
||||
|
||||
void do_inc_active() noexcept
|
||||
{
|
||||
if (m_hint_deactivate)
|
||||
{
|
||||
if (++m_active_outputs == 1)
|
||||
{
|
||||
if (m_stats)
|
||||
m_stats->m_stat_inc_active.inc();
|
||||
inc_active();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_dec_active() noexcept
|
||||
{
|
||||
if (m_hint_deactivate)
|
||||
if (--m_active_outputs == 0)
|
||||
{
|
||||
dec_active();
|
||||
}
|
||||
}
|
||||
|
||||
void set_hint_deactivate(bool v) noexcept { m_hint_deactivate = v; }
|
||||
bool get_hint_deactivate() const noexcept { return m_hint_deactivate; }
|
||||
// Has to be set in device reset
|
||||
void set_active_outputs(int n) noexcept { m_active_outputs = n; }
|
||||
|
||||
// stats
|
||||
struct stats_t
|
||||
{
|
||||
// NL_KEEP_STATISTICS
|
||||
plib::pperftime_t<true> m_stat_total_time;
|
||||
plib::pperfcount_t<true> m_stat_call_count;
|
||||
plib::pperfcount_t<true> m_stat_inc_active;
|
||||
};
|
||||
|
||||
stats_t * stats() const noexcept { return m_stats.get(); }
|
||||
#if 0
|
||||
virtual void update() noexcept { }
|
||||
#endif
|
||||
virtual void reset() { }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void inc_active() noexcept { }
|
||||
virtual void dec_active() noexcept { }
|
||||
|
||||
log_type & log();
|
||||
|
||||
public:
|
||||
virtual void timestep(timestep_type ts_type, nl_fptype st) noexcept { plib::unused_var(ts_type, st); }
|
||||
virtual void update_terminals() noexcept { }
|
||||
|
||||
virtual void update_param() noexcept {}
|
||||
virtual bool is_dynamic() const noexcept { return false; }
|
||||
virtual bool is_timestep() const noexcept { return false; }
|
||||
|
||||
private:
|
||||
bool m_hint_deactivate;
|
||||
state_var_s32 m_active_outputs;
|
||||
device_arena::unique_ptr<stats_t> m_stats;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// base_device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class base_device_t : public core_device_t
|
||||
{
|
||||
public:
|
||||
base_device_t(netlist_state_t &owner, const pstring &name);
|
||||
base_device_t(base_device_t &owner, const pstring &name);
|
||||
|
||||
PCOPYASSIGNMOVE(base_device_t, delete)
|
||||
|
||||
~base_device_t() noexcept override = default;
|
||||
|
||||
template<class O, class C, typename... Args>
|
||||
void create_and_register_subdevice(O& owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args)
|
||||
{
|
||||
dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void register_subalias(const pstring &name, const detail::core_terminal_t &term);
|
||||
void register_subalias(const pstring &name, const pstring &aliased);
|
||||
|
||||
void connect(const pstring &t1, const pstring &t2);
|
||||
void connect(const detail::core_terminal_t &t1, const detail::core_terminal_t &t2);
|
||||
protected:
|
||||
|
||||
//NETLIB_UPDATE_TERMINALSI() { }
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// device_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class device_t : public base_device_t,
|
||||
public logic_family_t
|
||||
class device_t : public base_device_t,
|
||||
public logic_family_t
|
||||
{
|
||||
public:
|
||||
device_t(netlist_state_t &owner, const pstring &name);
|
||||
@ -160,4 +48,4 @@ namespace netlist
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_DEVICE_H_
|
||||
#endif // NL_DEVICE_H_
|
||||
|
120
src/lib/netlist/core/exec.h
Normal file
120
src/lib/netlist/core/exec.h
Normal file
@ -0,0 +1,120 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
///
|
||||
/// \file exec.h
|
||||
///
|
||||
|
||||
#ifndef NL_CORE_EXEC_H_
|
||||
#define NL_CORE_EXEC_H_
|
||||
|
||||
#include "base_objects.h"
|
||||
#include "state_var.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/plists.h"
|
||||
#include "../plib/pstring.h"
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
// netlist_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class netlist_t // NOLINT(clang-analyzer-optin.performance.Padding)
|
||||
{
|
||||
public:
|
||||
|
||||
explicit netlist_t(netlist_state_t &state, const pstring &aname);
|
||||
|
||||
PCOPYASSIGNMOVE(netlist_t, delete)
|
||||
|
||||
virtual ~netlist_t() noexcept = default;
|
||||
|
||||
// run functions
|
||||
|
||||
netlist_time_ext time() const noexcept { return m_time; }
|
||||
|
||||
void process_queue(netlist_time_ext delta) noexcept;
|
||||
void abort_current_queue_slice() noexcept
|
||||
{
|
||||
if (!NL_USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.retime<false>(detail::queue_t::entry_t(m_time, nullptr));
|
||||
else
|
||||
m_queue.retime<true>(detail::queue_t::entry_t(m_time, nullptr));
|
||||
}
|
||||
|
||||
const detail::queue_t &queue() const noexcept { return m_queue; }
|
||||
|
||||
template<typename... Args>
|
||||
void qpush(Args&&...args) noexcept
|
||||
{
|
||||
if (!NL_USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
|
||||
else
|
||||
m_queue.emplace<true>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
|
||||
}
|
||||
|
||||
template <class R>
|
||||
void qremove(const R &elem) noexcept
|
||||
{
|
||||
if (!NL_USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.remove<false>(elem);
|
||||
else
|
||||
m_queue.remove<true>(elem);
|
||||
}
|
||||
|
||||
// Control functions
|
||||
|
||||
void stop();
|
||||
void reset();
|
||||
|
||||
// only used by nltool to create static c-code
|
||||
devices::nld_solver *solver() const noexcept { return m_solver; }
|
||||
|
||||
// force late type resolution
|
||||
template <typename X = devices::nld_solver>
|
||||
nl_fptype gmin(X *solv = nullptr) const noexcept
|
||||
{
|
||||
plib::unused_var(solv);
|
||||
return static_cast<X *>(m_solver)->gmin();
|
||||
}
|
||||
|
||||
netlist_state_t &nlstate() noexcept { return m_state; }
|
||||
const netlist_state_t &nlstate() const noexcept { return m_state; }
|
||||
|
||||
log_type & log() noexcept { return m_state.log(); }
|
||||
const log_type &log() const noexcept { return m_state.log(); }
|
||||
|
||||
void print_stats() const;
|
||||
bool use_stats() const { return m_use_stats; }
|
||||
|
||||
bool stats_enabled() const noexcept { return m_use_stats; }
|
||||
void enable_stats(bool val) noexcept { m_use_stats = val; }
|
||||
|
||||
private:
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
void process_queue_stats(netlist_time_ext delta) noexcept;
|
||||
|
||||
netlist_state_t & m_state;
|
||||
devices::nld_solver * m_solver;
|
||||
|
||||
// mostly rw
|
||||
//PALIGNAS(16)
|
||||
netlist_time_ext m_time;
|
||||
devices::nld_mainclock * m_mainclock;
|
||||
|
||||
//PALIGNAS_CACHELINE()
|
||||
//PALIGNAS(16)
|
||||
detail::queue_t m_queue;
|
||||
bool m_use_stats;
|
||||
// performance
|
||||
plib::pperftime_t<true> m_stat_mainloop;
|
||||
plib::pperfcount_t<true> m_perf_out_processed;
|
||||
};
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
||||
#endif // NL_CORE_EXEC_H_
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "base_objects.h"
|
||||
#include "state_var.h"
|
||||
#include "core_device.h"
|
||||
#include "exec.h"
|
||||
|
||||
#include "../nltypes.h"
|
||||
#include "../plib/plists.h"
|
||||
@ -43,6 +45,12 @@ namespace netlist
|
||||
|
||||
virtual void reset() noexcept;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hot section
|
||||
//
|
||||
// Any changes below will impact performance.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); }
|
||||
|
||||
void toggle_and_push_to_queue(const netlist_time &delay) noexcept
|
||||
@ -51,11 +59,42 @@ namespace netlist
|
||||
push_to_queue(delay);
|
||||
}
|
||||
|
||||
void push_to_queue(const netlist_time &delay) noexcept;
|
||||
void push_to_queue(const netlist_time &delay) noexcept
|
||||
{
|
||||
if (has_connections())
|
||||
{
|
||||
if (!!is_queued())
|
||||
exec().qremove(this);
|
||||
|
||||
const auto nst(exec().time() + delay);
|
||||
m_next_scheduled_time = nst;
|
||||
|
||||
if (!m_list_active.empty())
|
||||
{
|
||||
m_in_queue = queue_status::QUEUED;
|
||||
exec().qpush(nst, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
|
||||
update_inputs();
|
||||
}
|
||||
}
|
||||
}
|
||||
NVCC_CONSTEXPR bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; }
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
inline void update_devs() noexcept;
|
||||
inline void update_devs() noexcept
|
||||
{
|
||||
nl_assert(this->is_rail_net());
|
||||
|
||||
m_in_queue = queue_status::DELIVERED; // mark as taken ...
|
||||
if (m_new_Q ^ m_cur_Q)
|
||||
{
|
||||
process<KEEP_STATS>((m_new_Q << core_terminal_t::INP_LH_SHIFT)
|
||||
| (m_cur_Q << core_terminal_t::INP_HL_SHIFT), m_new_Q);
|
||||
}
|
||||
}
|
||||
|
||||
netlist_time_ext next_scheduled_time() const noexcept { return m_next_scheduled_time; }
|
||||
void set_next_scheduled_time(netlist_time_ext ntime) noexcept { m_next_scheduled_time = ntime; }
|
||||
@ -65,10 +104,47 @@ namespace netlist
|
||||
|
||||
bool has_connections() const noexcept { return !m_core_terms.empty(); }
|
||||
|
||||
void add_to_active_list(core_terminal_t &term) noexcept;
|
||||
void remove_from_active_list(core_terminal_t &term) noexcept;
|
||||
void add_to_active_list(core_terminal_t &term) noexcept
|
||||
{
|
||||
if (!m_list_active.empty())
|
||||
{
|
||||
term.set_copied_input(m_cur_Q);
|
||||
m_list_active.push_front(&term);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_list_active.push_front(&term);
|
||||
railterminal().device().do_inc_active();
|
||||
if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
|
||||
{
|
||||
if (m_next_scheduled_time > exec().time())
|
||||
{
|
||||
m_in_queue = queue_status::QUEUED; // pending
|
||||
exec().qpush(m_next_scheduled_time, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_in_queue = queue_status::DELIVERED;
|
||||
m_cur_Q = m_new_Q;
|
||||
}
|
||||
update_inputs();
|
||||
}
|
||||
else
|
||||
term.set_copied_input(m_cur_Q);
|
||||
}
|
||||
}
|
||||
|
||||
// setup stuff
|
||||
void remove_from_active_list(core_terminal_t &term) noexcept
|
||||
{
|
||||
gsl_Expects(!m_list_active.empty());
|
||||
m_list_active.remove(&term);
|
||||
if (m_list_active.empty())
|
||||
railterminal().device().do_dec_active();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// setup stuff - cold
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool is_logic() const noexcept;
|
||||
bool is_analog() const noexcept;
|
||||
@ -135,8 +211,39 @@ namespace netlist
|
||||
plib::linkedlist_t<core_terminal_t> m_list_active;
|
||||
std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Very hot
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <bool KEEP_STATS, typename T, typename S>
|
||||
void process(T mask, const S &sig) noexcept;
|
||||
void process(T mask, const S &sig) noexcept
|
||||
{
|
||||
m_cur_Q = sig;
|
||||
|
||||
if (KEEP_STATS)
|
||||
{
|
||||
for (auto & p : m_list_active)
|
||||
{
|
||||
p.set_copied_input(sig);
|
||||
auto *stats(p.device().stats());
|
||||
stats->m_stat_call_count.inc();
|
||||
if ((p.terminal_state() & mask))
|
||||
{
|
||||
auto g(stats->m_stat_total_time.guard());
|
||||
p.run_delegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &p : m_list_active)
|
||||
{
|
||||
p.set_copied_input(sig);
|
||||
if ((p.terminal_state() & mask) != 0)
|
||||
p.run_delegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
@ -24,11 +24,14 @@
|
||||
#include "../nltypes.h"
|
||||
|
||||
#include "base_objects.h"
|
||||
#include "core_device.h"
|
||||
#include "setup.h"
|
||||
|
||||
#include "../plib/palloc.h"
|
||||
#include "../plib/pstream.h"
|
||||
#include "../plib/pstring.h"
|
||||
#include "../plib/putil.h" // psource_t
|
||||
#include "../plib/pfunction.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -63,8 +66,6 @@ namespace netlist
|
||||
|
||||
protected:
|
||||
|
||||
void update_param() noexcept;
|
||||
|
||||
pstring get_initial(const core_device_t *dev, bool *found) const;
|
||||
|
||||
template<typename C>
|
||||
@ -73,7 +74,7 @@ namespace netlist
|
||||
if (p != v)
|
||||
{
|
||||
p = v;
|
||||
update_param();
|
||||
device().update_param();
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,13 +171,14 @@ namespace netlist
|
||||
{
|
||||
*m_param = param;
|
||||
changed();
|
||||
update_param();
|
||||
device().update_param();
|
||||
}
|
||||
}
|
||||
pstring valstr() const override
|
||||
{
|
||||
return *m_param;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void changed() noexcept;
|
||||
pstring str() const noexcept { return *m_param; }
|
||||
@ -269,6 +271,63 @@ namespace netlist
|
||||
std::array<ST, 1 << AW> m_data;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
param_num_t<T>::param_num_t(core_device_t &device, const pstring &name, const T val)
|
||||
: param_t(device, name)
|
||||
, m_param(val)
|
||||
{
|
||||
bool found = false;
|
||||
pstring p = this->get_initial(&device, &found);
|
||||
if (found)
|
||||
{
|
||||
plib::pfunction<nl_fptype> func;
|
||||
func.compile_infix(p, {});
|
||||
auto valx = func.evaluate();
|
||||
if (plib::is_integral<T>::value)
|
||||
if (plib::abs(valx - plib::trunc(valx)) > nlconst::magic(1e-6))
|
||||
throw nl_exception(MF_INVALID_NUMBER_CONVERSION_1_2(device.name() + "." + name, p));
|
||||
m_param = plib::narrow_cast<T>(valx);
|
||||
}
|
||||
|
||||
device.state().save(*this, m_param, this->name(), "m_param");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
param_enum_t<T>::param_enum_t(core_device_t &device, const pstring &name, const T val)
|
||||
: param_t(device, name)
|
||||
, m_param(val)
|
||||
{
|
||||
bool found = false;
|
||||
pstring p = this->get_initial(&device, &found);
|
||||
if (found)
|
||||
{
|
||||
T temp(val);
|
||||
bool ok = temp.set_from_string(p);
|
||||
if (!ok)
|
||||
{
|
||||
device.state().log().fatal(MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
throw nl_exception(MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
}
|
||||
m_param = temp;
|
||||
}
|
||||
|
||||
device.state().save(*this, m_param, this->name(), "m_param");
|
||||
}
|
||||
|
||||
template <typename ST, std::size_t AW, std::size_t DW>
|
||||
param_rom_t<ST, AW, DW>::param_rom_t(core_device_t &device, const pstring &name)
|
||||
: param_data_t(device, name)
|
||||
{
|
||||
auto f = this->stream();
|
||||
if (!f.empty())
|
||||
{
|
||||
plib::istream_read(f.stream(), m_data.data(), 1<<AW);
|
||||
// FIXME: check for failbit if not in validation.
|
||||
}
|
||||
else
|
||||
device.state().log().warning(MW_ROM_NOT_FOUND(str()));
|
||||
}
|
||||
|
||||
|
||||
} // namespace netlist
|
||||
|
||||
|
@ -975,6 +975,83 @@ namespace netlist
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// netlist_t
|
||||
//
|
||||
// Hot section
|
||||
//
|
||||
// Any changes below will impact performance.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
void netlist_t::process_queue_stats(const netlist_time_ext delta) noexcept
|
||||
{
|
||||
netlist_time_ext stop(m_time + delta);
|
||||
|
||||
qpush(stop, nullptr);
|
||||
|
||||
if (m_mainclock == nullptr)
|
||||
{
|
||||
m_time = m_queue.top().exec_time();
|
||||
detail::net_t *obj(m_queue.top().object());
|
||||
m_queue.pop();
|
||||
|
||||
while (obj != nullptr)
|
||||
{
|
||||
obj->template update_devs<KEEP_STATS>();
|
||||
if (KEEP_STATS)
|
||||
m_perf_out_processed.inc();
|
||||
const detail::queue_t::entry_t *top = &m_queue.top();
|
||||
m_time = top->exec_time();
|
||||
obj = top->object();
|
||||
m_queue.pop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logic_net_t &mc_net(m_mainclock->m_Q.net());
|
||||
const netlist_time inc(m_mainclock->m_inc);
|
||||
netlist_time_ext mc_time(mc_net.next_scheduled_time());
|
||||
|
||||
do
|
||||
{
|
||||
const detail::queue_t::entry_t *top = &m_queue.top();
|
||||
while (top->exec_time() > mc_time)
|
||||
{
|
||||
m_time = mc_time;
|
||||
mc_net.toggle_new_Q();
|
||||
mc_net.update_devs<KEEP_STATS>();
|
||||
top = &m_queue.top();
|
||||
mc_time += inc;
|
||||
}
|
||||
|
||||
m_time = top->exec_time();
|
||||
auto *const obj(top->object());
|
||||
m_queue.pop();
|
||||
if (obj != nullptr)
|
||||
obj->template update_devs<KEEP_STATS>();
|
||||
else
|
||||
break;
|
||||
if (KEEP_STATS)
|
||||
m_perf_out_processed.inc();
|
||||
} while (true);
|
||||
|
||||
mc_net.set_next_scheduled_time(mc_time);
|
||||
}
|
||||
}
|
||||
|
||||
void netlist_t::process_queue(netlist_time_ext delta) noexcept
|
||||
{
|
||||
if (!m_use_stats)
|
||||
process_queue_stats<false>(delta);
|
||||
else
|
||||
{
|
||||
auto sm_guard(m_stat_mainloop.guard());
|
||||
process_queue_stats<true>(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template struct state_var<std::uint8_t>;
|
||||
template struct state_var<std::uint16_t>;
|
||||
template struct state_var<std::uint32_t>;
|
||||
|
@ -22,24 +22,7 @@
|
||||
#include "core/object_array.h"
|
||||
#include "core/param.h"
|
||||
#include "core/state_var.h"
|
||||
|
||||
#include "plib/palloc.h" // owned_ptr
|
||||
#include "plib/pfunction.h"
|
||||
#include "plib/plists.h"
|
||||
#include "plib/pmempool.h"
|
||||
#include "plib/ppmf.h"
|
||||
#include "plib/pstate.h"
|
||||
#include "plib/pstream.h"
|
||||
#include "plib/ptimed_queue.h"
|
||||
#include "plib/ptypes.h"
|
||||
|
||||
#include "nl_errstr.h"
|
||||
#include "nl_factory.h"
|
||||
#include "nltypes.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "core/exec.h"
|
||||
|
||||
//============================================================
|
||||
// MACROS / New Syntax
|
||||
@ -196,11 +179,6 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
|
||||
#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name() noexcept
|
||||
|
||||
#if 0
|
||||
#define NETLIB_UPDATEI() virtual void update() noexcept override
|
||||
#define NETLIB_UPDATE(chip) NETLIB_HANDLER(chip, update)
|
||||
#endif
|
||||
|
||||
#define NETLIB_RESET(chip) void NETLIB_NAME(chip) :: reset(void)
|
||||
|
||||
#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param() noexcept
|
||||
@ -214,9 +192,6 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t>
|
||||
namespace netlist
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
namespace devices
|
||||
{
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -247,107 +222,6 @@ namespace netlist
|
||||
};
|
||||
} // namespace devices
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// netlist_t
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class netlist_t // NOLINT(clang-analyzer-optin.performance.Padding)
|
||||
{
|
||||
public:
|
||||
|
||||
explicit netlist_t(netlist_state_t &state, const pstring &aname);
|
||||
|
||||
PCOPYASSIGNMOVE(netlist_t, delete)
|
||||
|
||||
virtual ~netlist_t() noexcept = default;
|
||||
|
||||
// run functions
|
||||
|
||||
netlist_time_ext time() const noexcept { return m_time; }
|
||||
|
||||
void process_queue(netlist_time_ext delta) noexcept;
|
||||
void abort_current_queue_slice() noexcept
|
||||
{
|
||||
if (!NL_USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.retime<false>(detail::queue_t::entry_t(m_time, nullptr));
|
||||
else
|
||||
m_queue.retime<true>(detail::queue_t::entry_t(m_time, nullptr));
|
||||
}
|
||||
|
||||
const detail::queue_t &queue() const noexcept { return m_queue; }
|
||||
|
||||
template<typename... Args>
|
||||
void qpush(Args&&...args) noexcept
|
||||
{
|
||||
if (!NL_USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
|
||||
else
|
||||
m_queue.emplace<true>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
|
||||
}
|
||||
|
||||
template <class R>
|
||||
void qremove(const R &elem) noexcept
|
||||
{
|
||||
if (!NL_USE_QUEUE_STATS || !m_use_stats)
|
||||
m_queue.remove<false>(elem);
|
||||
else
|
||||
m_queue.remove<true>(elem);
|
||||
}
|
||||
|
||||
// Control functions
|
||||
|
||||
void stop();
|
||||
void reset();
|
||||
|
||||
// only used by nltool to create static c-code
|
||||
devices::NETLIB_NAME(solver) *solver() const noexcept { return m_solver; }
|
||||
|
||||
// force late type resolution
|
||||
template <typename X = devices::NETLIB_NAME(solver)>
|
||||
nl_fptype gmin(X *solv = nullptr) const noexcept
|
||||
{
|
||||
plib::unused_var(solv);
|
||||
return static_cast<X *>(m_solver)->gmin();
|
||||
}
|
||||
|
||||
netlist_state_t &nlstate() noexcept { return m_state; }
|
||||
const netlist_state_t &nlstate() const noexcept { return m_state; }
|
||||
|
||||
log_type & log() noexcept { return m_state.log(); }
|
||||
const log_type &log() const noexcept { return m_state.log(); }
|
||||
|
||||
void print_stats() const;
|
||||
bool use_stats() const { return m_use_stats; }
|
||||
|
||||
bool stats_enabled() const noexcept { return m_use_stats; }
|
||||
void enable_stats(bool val) noexcept { m_use_stats = val; }
|
||||
|
||||
private:
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
void process_queue_stats(netlist_time_ext delta) noexcept;
|
||||
|
||||
netlist_state_t & m_state;
|
||||
devices::NETLIB_NAME(solver) * m_solver;
|
||||
|
||||
// mostly rw
|
||||
//PALIGNAS(16)
|
||||
netlist_time_ext m_time;
|
||||
devices::NETLIB_NAME(mainclock) * m_mainclock;
|
||||
|
||||
//PALIGNAS_CACHELINE()
|
||||
//PALIGNAS(16)
|
||||
detail::queue_t m_queue;
|
||||
bool m_use_stats;
|
||||
// performance
|
||||
plib::pperftime_t<true> m_stat_mainloop;
|
||||
plib::pperfcount_t<true> m_perf_out_processed;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Support classes for devices
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// power pins - not a device, but a helper
|
||||
@ -400,371 +274,6 @@ namespace netlist
|
||||
}
|
||||
} // namespace devices
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Hot section
|
||||
//
|
||||
// Any changes below will impact performance.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// logic_input_t
|
||||
// -----------------------------------------------------------------------------
|
||||
#if 0
|
||||
inline void logic_input_t::inactivate() noexcept
|
||||
{
|
||||
if (!is_state(STATE_INP_PASSIVE))
|
||||
{
|
||||
set_state(STATE_INP_PASSIVE);
|
||||
net().remove_from_active_list(*this);
|
||||
}
|
||||
}
|
||||
|
||||
inline void logic_input_t::activate() noexcept
|
||||
{
|
||||
if (is_state(STATE_INP_PASSIVE))
|
||||
{
|
||||
net().add_to_active_list(*this);
|
||||
set_state(STATE_INP_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
inline void logic_input_t::activate_hl() noexcept
|
||||
{
|
||||
if (is_state(STATE_INP_PASSIVE))
|
||||
{
|
||||
net().add_to_active_list(*this);
|
||||
set_state(STATE_INP_HL);
|
||||
}
|
||||
}
|
||||
|
||||
inline void logic_input_t::activate_lh() noexcept
|
||||
{
|
||||
if (is_state(STATE_INP_PASSIVE))
|
||||
{
|
||||
net().add_to_active_list(*this);
|
||||
set_state(STATE_INP_LH);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
inline void detail::net_t::push_to_queue(const netlist_time &delay) noexcept
|
||||
{
|
||||
if (has_connections())
|
||||
{
|
||||
if (!!is_queued())
|
||||
exec().qremove(this);
|
||||
|
||||
const auto nst(exec().time() + delay);
|
||||
m_next_scheduled_time = nst;
|
||||
|
||||
if (!m_list_active.empty())
|
||||
{
|
||||
m_in_queue = queue_status::QUEUED;
|
||||
exec().qpush(nst, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
|
||||
update_inputs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void detail::net_t::add_to_active_list(core_terminal_t &term) noexcept
|
||||
{
|
||||
if (!m_list_active.empty())
|
||||
{
|
||||
term.set_copied_input(m_cur_Q);
|
||||
m_list_active.push_front(&term);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_list_active.push_front(&term);
|
||||
railterminal().device().do_inc_active();
|
||||
if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
|
||||
{
|
||||
if (m_next_scheduled_time > exec().time())
|
||||
{
|
||||
m_in_queue = queue_status::QUEUED; // pending
|
||||
exec().qpush(m_next_scheduled_time, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_in_queue = queue_status::DELIVERED;
|
||||
m_cur_Q = m_new_Q;
|
||||
}
|
||||
update_inputs();
|
||||
}
|
||||
else
|
||||
term.set_copied_input(m_cur_Q);
|
||||
}
|
||||
}
|
||||
|
||||
inline void detail::net_t::remove_from_active_list(core_terminal_t &term) noexcept
|
||||
{
|
||||
gsl_Expects(!m_list_active.empty());
|
||||
m_list_active.remove(&term);
|
||||
if (m_list_active.empty())
|
||||
railterminal().device().do_dec_active();
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline nl_fptype terminal_t::operator ()() const noexcept
|
||||
{
|
||||
return net().Q_Analog();
|
||||
}
|
||||
|
||||
inline const analog_net_t & analog_t::net() const noexcept
|
||||
{
|
||||
return plib::downcast<const analog_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
|
||||
inline analog_net_t & analog_t::net() noexcept
|
||||
{
|
||||
return plib::downcast<analog_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
|
||||
|
||||
inline logic_net_t & logic_t::net() noexcept
|
||||
{
|
||||
return plib::downcast<logic_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
|
||||
inline const logic_net_t & logic_t::net() const noexcept
|
||||
{
|
||||
return plib::downcast<const logic_net_t &>(core_terminal_t::net());
|
||||
}
|
||||
inline netlist_sig_t logic_input_t::operator()() const noexcept
|
||||
{
|
||||
nl_assert(terminal_state() != STATE_INP_PASSIVE);
|
||||
#if NL_USE_COPY_INSTEAD_OF_REFERENCE
|
||||
return m_Q;
|
||||
#else
|
||||
return net().Q();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline nl_fptype analog_input_t::Q_Analog() const noexcept
|
||||
{
|
||||
return net().Q_Analog();
|
||||
}
|
||||
|
||||
inline void analog_output_t::push(nl_fptype val) noexcept
|
||||
{
|
||||
if (val != m_my_net.Q_Analog())
|
||||
{
|
||||
m_my_net.set_Q_Analog(val);
|
||||
m_my_net.toggle_and_push_to_queue(netlist_time::quantum());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline netlist_t &detail::device_object_t::exec() noexcept
|
||||
{
|
||||
return m_device->exec();
|
||||
}
|
||||
|
||||
inline const netlist_t &detail::device_object_t::exec() const noexcept
|
||||
{
|
||||
return m_device->exec();
|
||||
}
|
||||
|
||||
template <bool KEEP_STATS, typename T, typename S>
|
||||
inline void detail::net_t::process(T mask, const S &sig) noexcept
|
||||
{
|
||||
m_cur_Q = sig;
|
||||
|
||||
if (KEEP_STATS)
|
||||
{
|
||||
for (auto & p : m_list_active)
|
||||
{
|
||||
p.set_copied_input(sig);
|
||||
auto *stats(p.device().stats());
|
||||
stats->m_stat_call_count.inc();
|
||||
if ((p.terminal_state() & mask))
|
||||
{
|
||||
auto g(stats->m_stat_total_time.guard());
|
||||
p.run_delegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &p : m_list_active)
|
||||
{
|
||||
p.set_copied_input(sig);
|
||||
if ((p.terminal_state() & mask) != 0)
|
||||
p.run_delegate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
inline void detail::net_t::update_devs() noexcept
|
||||
{
|
||||
nl_assert(this->is_rail_net());
|
||||
|
||||
m_in_queue = queue_status::DELIVERED; // mark as taken ...
|
||||
if (m_new_Q ^ m_cur_Q)
|
||||
{
|
||||
process<KEEP_STATS>((m_new_Q << core_terminal_t::INP_LH_SHIFT)
|
||||
| (m_cur_Q << core_terminal_t::INP_HL_SHIFT), m_new_Q);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool KEEP_STATS>
|
||||
inline void netlist_t::process_queue_stats(const netlist_time_ext delta) noexcept
|
||||
{
|
||||
netlist_time_ext stop(m_time + delta);
|
||||
|
||||
qpush(stop, nullptr);
|
||||
|
||||
if (m_mainclock == nullptr)
|
||||
{
|
||||
m_time = m_queue.top().exec_time();
|
||||
detail::net_t *obj(m_queue.top().object());
|
||||
m_queue.pop();
|
||||
|
||||
while (obj != nullptr)
|
||||
{
|
||||
obj->template update_devs<KEEP_STATS>();
|
||||
if (KEEP_STATS)
|
||||
m_perf_out_processed.inc();
|
||||
const detail::queue_t::entry_t *top = &m_queue.top();
|
||||
m_time = top->exec_time();
|
||||
obj = top->object();
|
||||
m_queue.pop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logic_net_t &mc_net(m_mainclock->m_Q.net());
|
||||
const netlist_time inc(m_mainclock->m_inc);
|
||||
netlist_time_ext mc_time(mc_net.next_scheduled_time());
|
||||
|
||||
do
|
||||
{
|
||||
const detail::queue_t::entry_t *top = &m_queue.top();
|
||||
while (top->exec_time() > mc_time)
|
||||
{
|
||||
m_time = mc_time;
|
||||
mc_net.toggle_new_Q();
|
||||
mc_net.update_devs<KEEP_STATS>();
|
||||
top = &m_queue.top();
|
||||
mc_time += inc;
|
||||
}
|
||||
|
||||
m_time = top->exec_time();
|
||||
auto *const obj(top->object());
|
||||
m_queue.pop();
|
||||
if (obj != nullptr)
|
||||
obj->template update_devs<KEEP_STATS>();
|
||||
else
|
||||
break;
|
||||
if (KEEP_STATS)
|
||||
m_perf_out_processed.inc();
|
||||
} while (true);
|
||||
|
||||
mc_net.set_next_scheduled_time(mc_time);
|
||||
}
|
||||
}
|
||||
|
||||
inline void netlist_t::process_queue(netlist_time_ext delta) noexcept
|
||||
{
|
||||
if (!m_use_stats)
|
||||
process_queue_stats<false>(delta);
|
||||
else
|
||||
{
|
||||
auto sm_guard(m_stat_mainloop.guard());
|
||||
process_queue_stats<true>(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// inline implementations - cold
|
||||
// -----------------------------------------------------------------------------
|
||||
#if 0
|
||||
template<typename T, typename... Args>
|
||||
inline device_arena::unique_ptr<T> detail::netlist_object_t::make_pool_object(Args&&... args)
|
||||
{
|
||||
return state().make_pool_object<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
inline void param_t::update_param() noexcept
|
||||
{
|
||||
device().update_param();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
param_num_t<T>::param_num_t(core_device_t &device, const pstring &name, const T val)
|
||||
: param_t(device, name)
|
||||
, m_param(val)
|
||||
{
|
||||
bool found = false;
|
||||
pstring p = this->get_initial(&device, &found);
|
||||
if (found)
|
||||
{
|
||||
plib::pfunction<nl_fptype> func;
|
||||
func.compile_infix(p, {});
|
||||
auto valx = func.evaluate();
|
||||
if (plib::is_integral<T>::value)
|
||||
if (plib::abs(valx - plib::trunc(valx)) > nlconst::magic(1e-6))
|
||||
throw nl_exception(MF_INVALID_NUMBER_CONVERSION_1_2(device.name() + "." + name, p));
|
||||
m_param = plib::narrow_cast<T>(valx);
|
||||
}
|
||||
|
||||
device.state().save(*this, m_param, this->name(), "m_param");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
param_enum_t<T>::param_enum_t(core_device_t &device, const pstring &name, const T val)
|
||||
: param_t(device, name)
|
||||
, m_param(val)
|
||||
{
|
||||
bool found = false;
|
||||
pstring p = this->get_initial(&device, &found);
|
||||
if (found)
|
||||
{
|
||||
T temp(val);
|
||||
bool ok = temp.set_from_string(p);
|
||||
if (!ok)
|
||||
{
|
||||
device.state().log().fatal(MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
throw nl_exception(MF_INVALID_ENUM_CONVERSION_1_2(name, p));
|
||||
}
|
||||
m_param = temp;
|
||||
}
|
||||
|
||||
device.state().save(*this, m_param, this->name(), "m_param");
|
||||
}
|
||||
|
||||
template <typename ST, std::size_t AW, std::size_t DW>
|
||||
param_rom_t<ST, AW, DW>::param_rom_t(core_device_t &device, const pstring &name)
|
||||
: param_data_t(device, name)
|
||||
{
|
||||
auto f = this->stream();
|
||||
if (!f.empty())
|
||||
{
|
||||
plib::istream_read(f.stream(), m_data.data(), 1<<AW);
|
||||
// FIXME: check for failbit if not in validation.
|
||||
}
|
||||
else
|
||||
device.state().log().warning(MW_ROM_NOT_FOUND(str()));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<class O, class C, typename... Args>
|
||||
void base_device_t::create_and_register_subdevice(O &owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args)
|
||||
{
|
||||
dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
inline solver::matrix_solver_t *analog_t::solver() const noexcept
|
||||
{
|
||||
return (this->has_net() ? net().solver() : nullptr);
|
||||
}
|
||||
|
||||
|
||||
extern template struct state_var<std::uint8_t>;
|
||||
extern template struct state_var<std::uint16_t>;
|
||||
|
Loading…
Reference in New Issue
Block a user