summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/nl_interface.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/nl_interface.h')
-rw-r--r--src/lib/netlist/nl_interface.h248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/lib/netlist/nl_interface.h b/src/lib/netlist/nl_interface.h
new file mode 100644
index 00000000000..eb187bad241
--- /dev/null
+++ b/src/lib/netlist/nl_interface.h
@@ -0,0 +1,248 @@
+// license:BSD-3-Clause
+// copyright-holders:Couriersud
+
+///
+/// \file nl_interface.h
+///
+/// This header contains objects for interfacing with the netlist core.
+///
+
+#ifndef NLINTERFACE_H_
+#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 <array>
+#include <memory>
+
+namespace netlist::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
+ {
+ 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)
+ {
+ }
+
+ 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);
+ }
+ }
+
+ 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)
+ {
+ }
+
+ NETLIB_HANDLERI(in)
+ {
+ 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() {}
+
+ NETLIB_HANDLERI(feedback)
+ {
+ 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
+ {
+ // 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++;
+
+ 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(""))
+ {
+ 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);
+ }
+ }
+
+ 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;
+ }
+
+ std::size_t id() const { return m_id; }
+
+ private:
+ using setter_t = plib::pmfp<void(nl_fptype)>;
+
+ template <typename S>
+ void setter(nl_fptype v)
+ {
+ static_cast<S *>(m_param)->set(v);
+ }
+
+ netlist_time m_sample_time;
+
+ logic_input_t m_feedback;
+ logic_output_t m_Q;
+
+ std::size_t m_pos;
+ std::size_t m_samples;
+
+ 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_