diff options
Diffstat (limited to 'src/lib/netlist/nl_interface.h')
-rw-r--r-- | src/lib/netlist/nl_interface.h | 382 |
1 files changed, 194 insertions, 188 deletions
diff --git a/src/lib/netlist/nl_interface.h b/src/lib/netlist/nl_interface.h index a9acb0bd564..eb187bad241 100644 --- a/src/lib/netlist/nl_interface.h +++ b/src/lib/netlist/nl_interface.h @@ -11,232 +11,238 @@ #define NLINTERFACE_H_ #include "nl_setup.h" + #include "core/analog.h" #include "core/device.h" #include "core/device_macros.h" #include "core/logic.h" #include "core/setup.h" -#include <memory> #include <array> +#include <memory> -namespace netlist +namespace netlist::interface { - - namespace interface + /// \brief analog_callback device + /// + /// This device is used to call back into the application which + /// is controlling the execution of the netlist. + /// + /// The device will call the provided lambda with a reference to + /// itself and the current value of the net it is connected to. + /// + /// The following code is an example on how to add the device to + /// the netlist factory. + /// + /// ``` + /// const pstring pin(m_in); + /// pstring dname = pstring("OUT_") + pin; + /// + /// const auto lambda = [this](auto &in, netlist::nl_fptype val) + /// { + /// this->cpu()->update_icount(in.exec().time()); + /// this->m_delegate(val, this->cpu()->local_time()); + /// this->cpu()->check_mame_abort_slice(); + /// }; + /// + /// using lb_t = decltype(lambda); + /// using cb_t = + /// netlist::interface::NETLIB_NAME(analog_callback)<lb_t>; + /// + /// parser.factory().add<cb_t, netlist::nl_fptype, lb_t>(dname, + /// netlist::factory::properties("-", PSOURCELOC()), 1e-6, + /// std::forward<lb_t>(lambda)); + /// ``` + + template <typename FUNC> + class nld_analog_callback : public device_t { - /// \brief analog_callback device - /// - /// This device is used to call back into the application which - /// is controlling the execution of the netlist. - /// - /// The device will call the provided lambda with a reference to - /// itself and the current value of the net it is connected to. - /// - /// The following code is an example on how to add the device to - /// the netlist factory. - /// - /// ``` - /// const pstring pin(m_in); - /// pstring dname = pstring("OUT_") + pin; - /// - /// const auto lambda = [this](auto &in, netlist::nl_fptype val) - /// { - /// this->cpu()->update_icount(in.exec().time()); - /// this->m_delegate(val, this->cpu()->local_time()); - /// this->cpu()->check_mame_abort_slice(); - /// }; - /// - /// using lb_t = decltype(lambda); - /// using cb_t = netlist::interface::NETLIB_NAME(analog_callback)<lb_t>; - /// - /// parser.factory().add<cb_t, netlist::nl_fptype, lb_t>(dname, - /// netlist::factory::properties("-", PSOURCELOC()), 1e-6, std::forward<lb_t>(lambda)); - /// ``` - - template <typename FUNC> - NETLIB_OBJECT(analog_callback) + public: + nld_analog_callback(constructor_param_t data, nl_fptype threshold, + FUNC &&func) + : device_t(data) + , m_in(*this, "IN", NETLIB_DELEGATE(in)) + , m_threshold(threshold) + , m_last(*this, "m_last", 0) + , m_func(func) { - public: - NETLIB_CONSTRUCTOR_EX(analog_callback, nl_fptype threshold, FUNC &&func) - , m_in(*this, "IN", NETLIB_DELEGATE(in)) - , m_threshold(threshold) - , m_last(*this, "m_last", 0) - , m_func(func) - { - } + } - NETLIB_RESETI() - { - m_last = 0.0; - } - - NETLIB_HANDLERI(in) - { - const nl_fptype cur = m_in(); - if (plib::abs(cur - m_last) > m_threshold) - { - m_last = cur; - m_func(*this, cur); - } - } + NETLIB_RESETI() { m_last = 0.0; } - private: - analog_input_t m_in; - nl_fptype m_threshold; - state_var<nl_fptype> m_last; - FUNC m_func; - }; - - - /// \brief logic_callback device - /// - /// This device must be connected to a logic net. It has no power terminals - /// and conversion with proxies will not work. - /// - /// Background: This device may be inserted later into the driver and should - /// not modify the resulting analog representation of the netlist. - /// - /// If you get error messages on missing power terminals you have to use the - /// analog callback device instead. - - template <typename FUNC> - NETLIB_OBJECT(logic_callback) + NETLIB_HANDLERI(in) { - public: - NETLIB_CONSTRUCTOR_EX(logic_callback, FUNC &&func) - , m_in(*this, "IN", NETLIB_DELEGATE(in)) - , m_func(func) - { - } - - NETLIB_HANDLERI(in) + const nl_fptype cur = m_in(); + if (plib::abs(cur - m_last) > m_threshold) { - const netlist_sig_t cur = m_in(); + m_last = cur; m_func(*this, cur); } + } + + private: + analog_input_t m_in; + nl_fptype m_threshold; + state_var<nl_fptype> m_last; + FUNC m_func; + }; + + /// \brief logic_callback device + /// + /// This device must be connected to a logic net. It has no power + /// terminals and conversion with proxies will not work. + /// + /// Background: This device may be inserted later into the driver and + /// should not modify the resulting analog representation of the + /// netlist. + /// + /// If you get error messages on missing power terminals you have to use + /// the analog callback device instead. + + template <typename FUNC> + class nld_logic_callback : public device_t + { + public: + nld_logic_callback(constructor_param_t data, FUNC &&func) + : device_t(data) + , m_in(*this, "IN", NETLIB_DELEGATE(in)) + , m_func(func) + { + } - private: - logic_input_t m_in; - FUNC m_func; - }; - - /// \brief Set parameters to buffers contents at regular intervals - /// - /// This device will update a parameter from a buffers passed to the device. - /// It is the responsibility of the controlling application to ensure that - /// the buffer is filled at regular intervals. - /// - /// \tparam T The buffer type - /// \tparam N Maximum number of supported buffers - /// - template <typename T> - NETLIB_OBJECT(buffered_param_setter) + NETLIB_HANDLERI(in) { - public: - - NETLIB_CONSTRUCTOR(buffered_param_setter) - , m_sample_time(netlist_time::zero()) - , m_feedback(*this, "FB", NETLIB_DELEGATE(feedback)) // clock part - , m_Q(*this, "Q") - , m_pos(0) - , m_samples(0) - , m_param_name(*this, "CHAN", "") - , m_param_mult(*this, "MULT", 1.0) - , m_param_offset(*this, "OFFSET", 0.0) - , m_param(nullptr) - , m_id(*this, "ID", 0) - { - connect("FB", "Q"); - m_buffer = nullptr; - } + const netlist_sig_t cur = m_in(); + m_func(*this, cur); + } + + private: + logic_input_t m_in; + FUNC m_func; + }; + + /// \brief Set parameters to buffers contents at regular intervals + /// + /// This device will update a parameter from a buffer passed to the + /// device. It is the responsibility of the controlling application to + /// ensure that the buffer is filled at regular intervals. + /// + /// \tparam T The buffer type + /// \tparam N Maximum number of supported buffers + /// + template <typename T> + class nld_buffered_param_setter : public device_t + { + public: + nld_buffered_param_setter(constructor_param_t data) + : device_t(data) + , m_sample_time(netlist_time::zero()) + , m_feedback(*this, "FB", NETLIB_DELEGATE(feedback)) // clock part + , m_Q(*this, "Q") + , m_pos(0) + , m_samples(0) + , m_param_name(*this, "CHAN", "") + , m_param_mult(*this, "MULT", 1.0) + , m_param_offset(*this, "OFFSET", 0.0) + , m_param(nullptr) + , m_id(*this, "ID", 0) + { + connect("FB", "Q"); + m_buffer = nullptr; + } - protected: - NETLIB_RESETI() - { - } + protected: + NETLIB_RESETI() {} - NETLIB_HANDLERI(feedback) + NETLIB_HANDLERI(feedback) + { + if (m_pos < m_samples) { - if (m_pos < m_samples) - { - // check if called outside of stream_update - if (m_buffer != nullptr) - { - const nl_fptype v = (*m_buffer)[m_pos]; - m_param_setter(v * m_param_mult() + m_param_offset()); - } - } - else + // check if called outside of stream_update + if (m_buffer != nullptr) { - // FIXME: The logic has a rounding issue because time resolution divided - // by 48,000 is not a natural number. The fractional part - // adds up to one samples every 13 seconds for 100 ps resolution. - // Fixing this is possible but complicated and expensive. + const nl_fptype v = (*m_buffer)[m_pos]; + m_param_setter(v * m_param_mult() + m_param_offset()); } - m_pos++; - - m_Q.net().toggle_and_push_to_queue(m_sample_time); } - - public: - /// \brief resolve parameter names to pointers - /// - /// This function must be called after all device were constructed but - /// before reset is called. - void resolve_params(netlist_time sample_time) + else { - m_pos = 0; - m_sample_time = sample_time; - if (m_param_name() != pstring("")) - { - param_t *p = &state().setup().find_param(m_param_name()).param(); - m_param = p; - if (dynamic_cast<param_fp_t *>(p) != nullptr) - m_param_setter = setter_t(&NETLIB_NAME(buffered_param_setter)::setter<param_fp_t>, this); - else if (dynamic_cast<param_logic_t *>(p) != nullptr) - m_param_setter = setter_t(&NETLIB_NAME(buffered_param_setter)::setter<param_logic_t>, this); - } + // FIXME: The logic has a rounding issue because time + // resolution divided by 48,000 is not a natural + // number. The fractional part adds up to one samples + // every 13 seconds for 100 ps resolution. Fixing + // this is possible but complicated and expensive. } + m_pos++; - void buffer_reset(netlist_time sample_time, std::size_t num_samples, T *inputs) + m_Q.net().toggle_and_push_to_queue(m_sample_time); + } + + public: + /// \brief resolve parameter names to pointers + /// + /// This function must be called after all device were constructed + /// but before reset is called. + void resolve_params(netlist_time sample_time) + { + m_pos = 0; + m_sample_time = sample_time; + if (m_param_name() != pstring("")) { - m_samples = num_samples; - m_sample_time = sample_time; - m_pos = 0; - m_buffer = inputs; + param_t *p = &state() + .setup() + .find_param(m_param_name()) + .param(); + m_param = p; + if (plib::dynamic_downcast<param_fp_t *>(p)) + m_param_setter = setter_t( + &NETLIB_NAME(buffered_param_setter)::setter<param_fp_t>, + this); + else if (plib::dynamic_downcast<param_logic_t *>(p)) + m_param_setter = setter_t( + &NETLIB_NAME(buffered_param_setter)::setter< + param_logic_t>, + this); } + } - std::size_t id() const { return m_id; } - private: - using setter_t = plib::pmfp<void (nl_fptype)>; + void buffer_reset(netlist_time sample_time, std::size_t num_samples, + T *inputs) + { + m_samples = num_samples; + m_sample_time = sample_time; + m_pos = 0; + m_buffer = inputs; + } - template <typename S> - void setter(nl_fptype v) - { - static_cast<S *>(m_param)->set(v); - } + std::size_t id() const { return m_id; } - netlist_time m_sample_time; + private: + using setter_t = plib::pmfp<void(nl_fptype)>; - logic_input_t m_feedback; - logic_output_t m_Q; + template <typename S> + void setter(nl_fptype v) + { + static_cast<S *>(m_param)->set(v); + } - std::size_t m_pos; - std::size_t m_samples; + netlist_time m_sample_time; - param_str_t m_param_name; - param_fp_t m_param_mult; - param_fp_t m_param_offset; - param_t * m_param; - setter_t m_param_setter; - T * m_buffer; - param_num_t<std::size_t> m_id; - }; + logic_input_t m_feedback; + logic_output_t m_Q; - } // namespace interface + std::size_t m_pos; + std::size_t m_samples; -} // namespace netlist + param_str_t m_param_name; + param_fp_t m_param_mult; + param_fp_t m_param_offset; + param_t * m_param; + setter_t m_param_setter; + T * m_buffer; + param_num_t<std::size_t> m_id; + }; +} // namespace netlist::interface #endif // NLINTERFACE_H_ |