diff options
-rw-r--r-- | scripts/src/netlist.lua | 6 | ||||
-rw-r--r-- | src/lib/netlist/core/analog.h | 5 | ||||
-rw-r--r-- | src/lib/netlist/core/base_objects.h | 3 | ||||
-rw-r--r-- | src/lib/netlist/core/core_device.h | 130 | ||||
-rw-r--r-- | src/lib/netlist/core/device.h | 124 | ||||
-rw-r--r-- | src/lib/netlist/core/exec.h | 120 | ||||
-rw-r--r-- | src/lib/netlist/core/nets.h | 119 | ||||
-rw-r--r-- | src/lib/netlist/core/param.h | 67 | ||||
-rw-r--r-- | src/lib/netlist/nl_base.cpp | 77 | ||||
-rw-r--r-- | src/lib/netlist/nl_base.h | 493 |
10 files changed, 521 insertions, 623 deletions
diff --git a/scripts/src/netlist.lua b/scripts/src/netlist.lua index 0d55049d7b3..b46dfec4d3a 100644 --- a/scripts/src/netlist.lua +++ b/scripts/src/netlist.lua @@ -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", diff --git a/src/lib/netlist/core/analog.h b/src/lib/netlist/core/analog.h index a868443b8d2..4bc986f48fc 100644 --- a/src/lib/netlist/core/analog.h +++ b/src/lib/netlist/core/analog.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 diff --git a/src/lib/netlist/core/base_objects.h b/src/lib/netlist/core/base_objects.h index 656898b21d0..140fde1149e 100644 --- a/src/lib/netlist/core/base_objects.h +++ b/src/lib/netlist/core/base_objects.h @@ -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; }; diff --git a/src/lib/netlist/core/core_device.h b/src/lib/netlist/core/core_device.h new file mode 100644 index 00000000000..e1df57deb50 --- /dev/null +++ b/src/lib/netlist/core/core_device.h @@ -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_ diff --git a/src/lib/netlist/core/device.h b/src/lib/netlist/core/device.h index 99a5a1884ec..c087686b0dc 100644 --- a/src/lib/netlist/core/device.h +++ b/src/lib/netlist/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_ diff --git a/src/lib/netlist/core/exec.h b/src/lib/netlist/core/exec.h new file mode 100644 index 00000000000..307baa6b0f2 --- /dev/null +++ b/src/lib/netlist/core/exec.h @@ -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_ diff --git a/src/lib/netlist/core/nets.h b/src/lib/netlist/core/nets.h index 5eced2379e4..7b872250d56 100644 --- a/src/lib/netlist/core/nets.h +++ b/src/lib/netlist/core/nets.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 diff --git a/src/lib/netlist/core/param.h b/src/lib/netlist/core/param.h index 9b353d0bdef..609c89d1cf3 100644 --- a/src/lib/netlist/core/param.h +++ b/src/lib/netlist/core/param.h @@ -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 diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index d53606e52b8..1ea7817dc72 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -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>; diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index b6f5da80461..32cc1f0eacc 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -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>; |