summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/nl_base.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/nl_base.h')
-rw-r--r--src/lib/netlist/nl_base.h1307
1 files changed, 780 insertions, 527 deletions
diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h
index e56fde89f88..9d0eed869e0 100644
--- a/src/lib/netlist/nl_base.h
+++ b/src/lib/netlist/nl_base.h
@@ -9,27 +9,25 @@
#ifndef NLBASE_H_
#define NLBASE_H_
-#include "nl_lists.h"
-#include "nl_time.h"
+#ifdef NL_PROHIBIT_BASEH_INCLUDE
+#error "nl_base.h included. Please correct."
+#endif
+
#include "plib/palloc.h" // owned_ptr
#include "plib/pdynlib.h"
-#include "plib/pstate.h"
#include "plib/pfmtlog.h"
-#include "plib/pstream.h"
+#include "plib/pmempool.h"
#include "plib/ppmf.h"
+#include "plib/pstate.h"
+#include "plib/pstream.h"
-#include <unordered_map>
-
-#ifdef NL_PROHIBIT_BASEH_INCLUDE
-#error "nl_base.h included. Please correct."
-#endif
-
-// ----------------------------------------------------------------------------------------
-// Type definitions
-// ----------------------------------------------------------------------------------------
+#include "nl_errstr.h"
+#include "nl_lists.h"
+#include "nltypes.h"
+#include "plib/ptime.h"
-/*! netlist_sig_t is the type used for logic signals. */
-using netlist_sig_t = std::uint32_t;
+#include <unordered_map>
+#include <vector>
//============================================================
// MACROS / New Syntax
@@ -73,7 +71,7 @@ class NETLIB_NAME(name) : public device_t
/*! Used to define the destructor of a netlist device.
* The use of a destructor for netlist device should normally not be necessary.
*/
-#define NETLIB_DESTRUCTOR(name) public: virtual ~NETLIB_NAME(name)()
+#define NETLIB_DESTRUCTOR(name) public: virtual ~NETLIB_NAME(name)() noexcept
/*! Define an extended constructor and add further parameters to it.
* The macro allows to add further parameters to a device constructor. This is
@@ -85,14 +83,15 @@ class NETLIB_NAME(name) : public device_t
: device_t(owner, name)
/*! Add this to a device definition to mark the device as dynamic.
- * If NETLIB_IS_DYNAMIC(true) is added to the device definition the device
- * is treated as an analog dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI
- * is called on a each step of the Newton-Raphson step
- * of solving the linear equations.
- *
- * You may also use e.g. NETLIB_IS_DYNAMIC(m_func() != "") to only make the
- * device a dynamic device if parameter m_func is set.
- */
+ *
+ * If NETLIB_IS_DYNAMIC(true) is added to the device definition the device
+ * is treated as an analog dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI
+ * is called on a each step of the Newton-Raphson step
+ * of solving the linear equations.
+ *
+ * You may also use e.g. NETLIB_IS_DYNAMIC(m_func() != "") to only make the
+ * device a dynamic device if parameter m_func is set.
+ */
#define NETLIB_IS_DYNAMIC(expr) \
public: virtual bool is_dynamic() const override { return expr; }
@@ -127,36 +126,30 @@ class NETLIB_NAME(name) : public device_t
#define NETLIB_TIMESTEPI() \
public: virtual void timestep(const nl_double step) override
-#define NETLIB_UPDATE_AFTER_PARAM_CHANGE() \
- public: virtual bool needs_update_after_param_change() const override { return true; }
-
#define NETLIB_FAMILY(family) , m_famsetter(*this, family)
#define NETLIB_DELEGATE(chip, name) nldelegate(&NETLIB_NAME(chip) :: name, this)
-#define NETLIB_UPDATE_TERMINALSI() public: virtual void update_terminals() override
-#define NETLIB_HANDLERI(name) private: virtual void name() NL_NOEXCEPT
-#define NETLIB_UPDATEI() protected: virtual void update() NL_NOEXCEPT override
-#define NETLIB_UPDATE_PARAMI() public: virtual void update_param() override
-#define NETLIB_RESETI() protected: virtual void reset() override
+#define NETLIB_UPDATE_TERMINALSI() virtual void update_terminals() override
+#define NETLIB_HANDLERI(name) virtual void name() NL_NOEXCEPT
+#define NETLIB_UPDATEI() virtual void update() NL_NOEXCEPT override
+#define NETLIB_UPDATE_PARAMI() virtual void update_param() override
+#define NETLIB_RESETI() virtual void reset() override
#define NETLIB_TIMESTEP(chip) void NETLIB_NAME(chip) :: timestep(const nl_double step)
#define NETLIB_SUB(chip) nld_ ## chip
-#define NETLIB_SUBXX(ns, chip) std::unique_ptr< ns :: nld_ ## chip >
+#define NETLIB_SUBXX(ns, chip) pool_owned_ptr< ns :: nld_ ## chip >
-#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name(void) NL_NOEXCEPT
+#define NETLIB_HANDLER(chip, name) void NETLIB_NAME(chip) :: name() NL_NOEXCEPT
#define NETLIB_UPDATE(chip) NETLIB_HANDLER(chip, update)
-// FIXME: NETLIB_PARENT_UPDATE should disappear
-#define NETLIB_PARENT_UPDATE(chip) NETLIB_NAME(chip) :: update();
-
#define NETLIB_RESET(chip) void NETLIB_NAME(chip) :: reset(void)
-#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param(void)
+#define NETLIB_UPDATE_PARAM(chip) void NETLIB_NAME(chip) :: update_param()
#define NETLIB_FUNC_VOID(chip, name, params) void NETLIB_NAME(chip) :: name params
-#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals(void)
+#define NETLIB_UPDATE_TERMINALS(chip) void NETLIB_NAME(chip) :: update_terminals()
//============================================================
// Asserts
@@ -169,7 +162,7 @@ class NETLIB_NAME(name) : public device_t
#define nl_assert(x) do { if (0) if (!(x)) { /*throw nl_exception(plib::pfmt("assert: {1}:{2}: {3}")(__FILE__)(__LINE__)(#x) ); */} } while (0)
#define NL_NOEXCEPT noexcept
#endif
-#define nl_assert_always(x, msg) do { if (!(x)) throw nl_exception(plib::pfmt("Fatal error: {1}\nCaused by assert: {2}:{3}: {4}")(msg)(__FILE__)(__LINE__)(#x)); } while (0)
+#define nl_assert_always(x, msg) do { if (!(x)) throw nl_exception("Fatal error: {1}\nCaused by assert: {2}:{3}: {4}", msg, __FILE__, __LINE__, #x); } while (0)
//============================================================
// Namespace starts
@@ -177,6 +170,11 @@ class NETLIB_NAME(name) : public device_t
namespace netlist
{
+ /*! Delegate type for device notification.
+ *
+ */
+ using nldelegate = plib::pmfp<void>;
+
// -----------------------------------------------------------------------------
// forward definitions
// -----------------------------------------------------------------------------
@@ -191,27 +189,23 @@ namespace netlist
class NETLIB_NAME(base_proxy);
class NETLIB_NAME(base_d_to_a_proxy);
class NETLIB_NAME(base_a_to_d_proxy);
- }
+ } // namespace devices
namespace detail {
- class object_t;
- class device_object_t;
- struct netlist_ref;
- class core_terminal_t;
struct family_setter_t;
class queue_t;
- class net_t;
- }
+ } // namespace detail
class logic_output_t;
class logic_input_t;
class analog_net_t;
class logic_net_t;
- class net_t;
class setup_t;
class netlist_t;
+ class netlist_state_t;
class core_device_t;
class device_t;
+ class callbacks_t;
//============================================================
// Exceptions
@@ -229,9 +223,12 @@ namespace netlist
explicit nl_exception(const pstring &text //!< text to be passed
)
: plib::pexception(text) { }
- /*! Copy constructor. */
- nl_exception(const nl_exception &e) : plib::pexception(e) { }
- virtual ~nl_exception();
+
+ template<typename... Args>
+ explicit nl_exception(const pstring &fmt //!< format to be used
+ , Args&&... args //!< arguments to be passed
+ )
+ : plib::pexception(plib::pfmt(fmt)(std::forward<Args>(args)...)) { }
};
/*! Logic families descriptors are used to create proxy devices.
@@ -242,18 +239,21 @@ namespace netlist
{
public:
logic_family_desc_t();
- virtual ~logic_family_desc_t();
- virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, const pstring &name,
+ COPYASSIGNMOVE(logic_family_desc_t, delete)
+
+ virtual ~logic_family_desc_t() noexcept = default;
+
+ virtual pool_owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name,
logic_output_t *proxied) const = 0;
- virtual plib::owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_t &anetlist, const pstring &name,
+ virtual pool_owned_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name,
logic_input_t *proxied) const = 0;
double fixed_V() const { return m_fixed_V; }
double low_thresh_V(const double VN, const double VP) const { return VN + (VP - VN) * m_low_thresh_PCNT; }
double high_thresh_V(const double VN, const double VP) const { return VN + (VP - VN) * m_high_thresh_PCNT; }
- double low_V(const double VN, const double VP) const { return VN + m_low_VO; }
- double high_V(const double VN, const double VP) const { return VP - m_high_VO; }
+ double low_V(const double VN, const double VP) const { plib::unused_var(VP); return VN + m_low_VO; }
+ double high_V(const double VN, const double VP) const { plib::unused_var(VN); return VP - m_high_VO; }
double R_low() const { return m_R_low; }
double R_high() const { return m_R_high; }
@@ -282,12 +282,14 @@ namespace netlist
public:
logic_family_t() : m_logic_family(nullptr) {}
+ COPYASSIGNMOVE(logic_family_t, delete)
+
const logic_family_desc_t *logic_family() const { return m_logic_family; }
void set_logic_family(const logic_family_desc_t *fam) { m_logic_family = fam; }
protected:
- ~logic_family_t() { } // prohibit polymorphic destruction
+ ~logic_family_t() noexcept = default; // prohibit polymorphic destruction
const logic_family_desc_t *m_logic_family;
};
@@ -317,12 +319,15 @@ namespace netlist
const pstring &name, //!< identifier/name for this state variable
const T &value //!< Initial value after construction
);
+
+ //! Destructor.
+ ~state_var() noexcept = default;
//! Copy Constructor.
- constexpr state_var(const state_var &rhs) noexcept = default;
+ constexpr state_var(const state_var &rhs) = default;
//! Move Constructor.
constexpr state_var(state_var &&rhs) noexcept = default;
//! Assignment operator to assign value of a state var.
- C14CONSTEXPR state_var &operator=(const state_var &rhs) noexcept = default;
+ C14CONSTEXPR state_var &operator=(const state_var &rhs) = default;
//! Assignment move operator to assign value of a state var.
C14CONSTEXPR state_var &operator=(state_var &&rhs) noexcept = default;
//! Assignment operator to assign value of type T.
@@ -345,25 +350,29 @@ namespace netlist
* Please refer to \ref state_var.
*/
template <typename T, std::size_t N>
- struct state_var<T[N]>
+ struct state_array
{
public:
//! Constructor.
template <typename O>
- state_var(O &owner, //!< owner must have a netlist() method.
+ state_array(O &owner, //!< owner must have a netlist() method.
const pstring &name, //!< identifier/name for this state variable
const T &value //!< Initial value after construction
);
//! Copy Constructor.
- state_var(const state_var &rhs) NL_NOEXCEPT = default;
+ state_array(const state_array &rhs) noexcept = default;
+ //! Destructor.
+ ~state_array() noexcept = default;
//! Move Constructor.
- state_var(state_var &&rhs) NL_NOEXCEPT = default;
- state_var &operator=(const state_var &rhs) NL_NOEXCEPT = default;
- state_var &operator=(const T &rhs) NL_NOEXCEPT { m_value = rhs; return *this; }
- T & operator[](const std::size_t i) NL_NOEXCEPT { return m_value[i]; }
- constexpr T & operator[](const std::size_t i) const NL_NOEXCEPT { return m_value[i]; }
+ state_array(state_array &&rhs) noexcept = default;
+ state_array &operator=(const state_array &rhs) noexcept = default;
+ state_array &operator=(state_array &&rhs) noexcept = default;
+
+ state_array &operator=(const T &rhs) noexcept { m_value = rhs; return *this; }
+ T & operator[](const std::size_t i) noexcept { return m_value[i]; }
+ constexpr const T & operator[](const std::size_t i) const noexcept { return m_value[i]; }
private:
- T m_value[N];
+ std::array<T, N> m_value;
};
// -----------------------------------------------------------------------------
@@ -382,164 +391,324 @@ namespace netlist
/*! predefined state variable type for sig_t */
using state_var_sig = state_var<netlist_sig_t>;
- // -----------------------------------------------------------------------------
- // object_t
- // -----------------------------------------------------------------------------
+ namespace detail {
- /*! The base class for netlist devices, terminals and parameters.
- *
- * This class serves as the base class for all device, terminal and
- * objects. It provides new and delete operators to support e.g. pooled
- * memory allocation to enhance locality. Please refer to \ref USE_MEMPOOL as
- * well.
- */
- class detail::object_t
- {
- public:
+ // -----------------------------------------------------------------------------
+ // object_t
+ // -----------------------------------------------------------------------------
- /*! Constructor.
+ /*! The base class for netlist devices, terminals and parameters.
*
- * Every class derived from the object_t class must have a name.
+ * This class serves as the base class for all device, terminal and
+ * objects. It provides new and delete operators to support e.g. pooled
+ * memory allocation to enhance locality. Please refer to \ref USE_MEMPOOL as
+ * well.
*/
- explicit object_t(const pstring &aname /*!< string containing name of the object */);
+ class object_t
+ {
+ public:
- /*! return name of the object
- *
- * \returns name of the object.
- */
- const pstring &name() const;
+ /*! Constructor.
+ *
+ * Every class derived from the object_t class must have a name.
+ */
+ explicit object_t(const pstring &aname /*!< string containing name of the object */);
+
+ COPYASSIGNMOVE(object_t, delete)
+ /*! return name of the object
+ *
+ * \returns name of the object.
+ */
+ pstring name() const;
+
+ #if 0
+ void * operator new (size_t size, void *ptr) { plib::unused_var(size); return ptr; }
+ void operator delete (void *ptr, void *) { plib::unused_var(ptr); }
+ void * operator new (size_t size) = delete;
+ void operator delete (void * mem) = delete;
+ #endif
+ protected:
+ ~object_t() noexcept = default; // only childs should be destructible
- void * operator new (size_t size, void *ptr) { return ptr; }
- void operator delete (void *ptr, void *) { }
- void * operator new (size_t size);
- void operator delete (void * mem);
- protected:
- ~object_t(); // only childs should be destructible
+ private:
+ //pstring m_name;
+ static std::unordered_map<const object_t *, pstring> &name_hash()
+ {
+ static std::unordered_map<const object_t *, pstring> lhash;
+ return lhash;
+ }
+ };
- private:
- std::unique_ptr<pstring> m_name;
- };
+ struct netlist_ref
+ {
+ explicit netlist_ref(netlist_state_t &nl);
- struct detail::netlist_ref
- {
- explicit constexpr netlist_ref(netlist_t &nl) : m_netlist(nl) { }
+ COPYASSIGNMOVE(netlist_ref, delete)
- C14CONSTEXPR netlist_t & netlist() NL_NOEXCEPT { return m_netlist; }
- constexpr const netlist_t & netlist() const NL_NOEXCEPT { return m_netlist; }
+ netlist_state_t & state() noexcept;
+ const netlist_state_t & state() const noexcept;
- protected:
- ~netlist_ref() = default; // prohibit polymorphic destruction
+ setup_t & setup() noexcept;
+ const setup_t & setup() const noexcept;
- private:
- netlist_t & m_netlist;
+ netlist_t & exec() noexcept { return m_netlist; }
+ const netlist_t & exec() const noexcept { return m_netlist; }
- };
+ protected:
+ ~netlist_ref() noexcept = default; // prohibit polymorphic destruction
- // -----------------------------------------------------------------------------
- // device_object_t
- // -----------------------------------------------------------------------------
+ private:
+ netlist_t & m_netlist;
- /*! Base class for all objects being owned by a device.
- *
- * Serves as the base class of all objects being owned by a device.
- *
- */
- class detail::device_object_t : public detail::object_t
- {
- public:
- /*! Constructor.
+ };
+
+ // -----------------------------------------------------------------------------
+ // device_object_t
+ // -----------------------------------------------------------------------------
+
+ /*! Base class for all objects being owned by a device.
+ *
+ * Serves as the base class of all objects being owned by a device.
*
- * \param dev device owning the object.
- * \param name string holding the name of the device
*/
- device_object_t(core_device_t &dev, const pstring &name);
+ class device_object_t : public object_t
+ {
+ public:
+ /*! Constructor.
+ *
+ * \param dev device owning the object.
+ * \param name string holding the name of the device
+ */
+ device_object_t(core_device_t &dev, const pstring &name);
+
+ /*! returns reference to owning device.
+ * \returns reference to owning device.
+ */
+ core_device_t &device() noexcept { return m_device; }
+ const core_device_t &device() const noexcept { return m_device; }
+
+ /*! The netlist owning the owner of this object.
+ * \returns reference to netlist object.
+ */
+ netlist_state_t &state() NL_NOEXCEPT;
+ const netlist_state_t &state() const NL_NOEXCEPT;
+
+ netlist_t &exec() NL_NOEXCEPT;
+ const netlist_t &exec() const NL_NOEXCEPT;
- /*! returns reference to owning device.
- * \returns reference to owning device.
- */
- core_device_t &device() NL_NOEXCEPT { return m_device; }
- const core_device_t &device() const NL_NOEXCEPT { return m_device; }
+ private:
+ core_device_t & m_device;
+ };
- /*! The netlist owning the owner of this object.
- * \returns reference to netlist object.
+ // -----------------------------------------------------------------------------
+ // core_terminal_t
+ // -----------------------------------------------------------------------------
+
+ /*! Base class for all terminals.
+ *
+ * All terminals are derived from this class.
+ *
*/
- netlist_t &netlist() NL_NOEXCEPT;
- const netlist_t &netlist() const NL_NOEXCEPT;
- private:
- core_device_t & m_device;
-};
+ class net_t;
- /*! Delegate type for device notification.
- *
- */
- typedef plib::pmfp<void> nldelegate;
+ class core_terminal_t : public device_object_t,
+ public plib::linkedlist_t<core_terminal_t>::element_t
+ {
+ public:
- // -----------------------------------------------------------------------------
- // core_terminal_t
- // -----------------------------------------------------------------------------
+ using list_t = std::vector<core_terminal_t *>;
- /*! Base class for all terminals.
- *
- * All terminals are derived from this class.
- *
- */
- class detail::core_terminal_t : public device_object_t,
- public plib::linkedlist_t<core_terminal_t>::element_t
- {
- public:
+ static constexpr const auto INP_HL_SHIFT = 0;
+ static constexpr const auto INP_LH_SHIFT = 1;
+ static constexpr const auto INP_ACTIVE_SHIFT = 2;
+
+ enum state_e {
+ STATE_INP_PASSIVE = 0,
+ STATE_INP_HL = (1 << INP_HL_SHIFT),
+ STATE_INP_LH = (1 << INP_LH_SHIFT),
+ STATE_INP_ACTIVE = (1 << INP_ACTIVE_SHIFT),
+ STATE_OUT = 128,
+ STATE_BIDIR = 256
+ };
+
+ core_terminal_t(core_device_t &dev, const pstring &aname,
+ const state_e state, nldelegate delegate = nldelegate());
+ virtual ~core_terminal_t() noexcept = default;
+
+ COPYASSIGNMOVE(core_terminal_t, delete)
+
+ /*! The object type.
+ * \returns type of the object
+ */
+ terminal_type type() const;
+ /*! Checks if object is of specified type.
+ * \param atype type to check object against.
+ * \returns true if object is of specified type else false.
+ */
+ bool is_type(const terminal_type atype) const noexcept { return (type() == atype); }
+
+ void set_net(net_t *anet) noexcept { m_net = anet; }
+ void clear_net() noexcept { m_net = nullptr; }
+ bool has_net() const noexcept { return (m_net != nullptr); }
+
+ const net_t & net() const noexcept { return *m_net;}
+ net_t & net() noexcept { return *m_net;}
- using list_t = std::vector<core_terminal_t *>;
+ bool is_logic() const NL_NOEXCEPT;
+ bool is_analog() const NL_NOEXCEPT;
- static constexpr const unsigned INP_HL_SHIFT = 0;
- static constexpr const unsigned INP_LH_SHIFT = 1;
- static constexpr const unsigned INP_ACTIVE_SHIFT = 2;
+ bool is_state(state_e astate) const noexcept { return (m_state == astate); }
+ state_e terminal_state() const noexcept { return m_state; }
+ void set_state(state_e astate) noexcept { m_state = astate; }
- enum state_e {
- STATE_INP_PASSIVE = 0,
- STATE_INP_HL = (1 << INP_HL_SHIFT),
- STATE_INP_LH = (1 << INP_LH_SHIFT),
- STATE_INP_ACTIVE = (1 << INP_ACTIVE_SHIFT),
- STATE_OUT = 128,
- STATE_BIDIR = 256
+ void reset() noexcept { set_state(is_type(OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); }
+
+ nldelegate m_delegate;
+ #if USE_COPY_INSTEAD_OF_REFERENCE
+ void set_copied_input(netlist_sig_t val)
+ {
+ m_Q = val;
+ }
+
+ state_var_sig m_Q;
+ #else
+ void set_copied_input(netlist_sig_t val) const { plib::unused_var(val); }
+ #endif
+
+ private:
+ net_t * m_net;
+ state_var<state_e> m_state;
};
- core_terminal_t(core_device_t &dev, const pstring &aname,
- const state_e state, nldelegate delegate = nldelegate());
- virtual ~core_terminal_t();
+ // -----------------------------------------------------------------------------
+ // net_t
+ // -----------------------------------------------------------------------------
- /*! The object type.
- * \returns type of the object
- */
- terminal_type type() const;
- /*! Checks if object is of specified type.
- * \param atype type to check object against.
- * \returns true if object is of specified type else false.
- */
- bool is_type(const terminal_type atype) const { return (type() == atype); }
+ class net_t :
+ public object_t,
+ public netlist_ref
+ {
+ public:
- void set_net(net_t *anet);
- void clear_net();
- bool has_net() const NL_NOEXCEPT { return (m_net != nullptr); }
+ enum class queue_status
+ {
+ DELAYED_DUE_TO_INACTIVE = 0,
+ QUEUED,
+ DELIVERED
+ };
- const net_t & net() const NL_NOEXCEPT { return *m_net;}
- net_t & net() NL_NOEXCEPT { return *m_net;}
+ net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *mr = nullptr);
- bool is_logic() const NL_NOEXCEPT;
- bool is_analog() const NL_NOEXCEPT;
+ COPYASSIGNMOVE(net_t, delete)
- bool is_state(const state_e &astate) const NL_NOEXCEPT { return (m_state == astate); }
- const state_e &state() const NL_NOEXCEPT { return m_state; }
- void set_state(const state_e &astate) NL_NOEXCEPT { m_state = astate; }
+ virtual ~net_t() noexcept = default;
- void reset();
+ void reset();
- nldelegate m_delegate;
+ void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); }
- private:
- net_t * m_net;
- state_var<state_e> m_state;
- };
+ void toggle_and_push_to_queue(netlist_time delay) NL_NOEXCEPT
+ {
+ toggle_new_Q();
+ push_to_queue(delay);
+ }
+
+ void push_to_queue(netlist_time delay) NL_NOEXCEPT;
+ bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; }
+
+ void update_devs() NL_NOEXCEPT;
+
+ netlist_time next_scheduled_time() const noexcept { return m_next_scheduled_time; }
+ void set_next_scheduled_time(netlist_time ntime) noexcept { m_next_scheduled_time = ntime; }
+
+ bool isRailNet() const noexcept { return !(m_railterminal == nullptr); }
+ core_terminal_t & railterminal() const noexcept { return *m_railterminal; }
+
+ std::size_t num_cons() const noexcept { return m_core_terms.size(); }
+
+ void add_to_active_list(core_terminal_t &term) NL_NOEXCEPT;
+ void remove_from_active_list(core_terminal_t &term) NL_NOEXCEPT;
+
+ /* setup stuff */
+
+ void add_terminal(core_terminal_t &terminal);
+ void remove_terminal(core_terminal_t &terminal);
+
+ bool is_logic() const NL_NOEXCEPT;
+ bool is_analog() const NL_NOEXCEPT;
+
+ void rebuild_list(); /* rebuild m_list after a load */
+ void move_connections(net_t &dest_net);
+
+ std::vector<core_terminal_t *> &core_terms() { return m_core_terms; }
+ #if USE_COPY_INSTEAD_OF_REFERENCE
+ void update_inputs()
+ {
+ for (auto & term : m_core_terms)
+ term->m_Q = m_cur_Q;
+ }
+ #else
+ void update_inputs() const
+ {
+ /* nothing needs to be done */
+ }
+ #endif
+
+ protected:
+
+ /* only used for logic nets */
+ netlist_sig_t Q() const noexcept { return m_cur_Q; }
+
+ /* only used for logic nets */
+ void initial(const netlist_sig_t val) noexcept
+ {
+ m_cur_Q = m_new_Q = val;
+ update_inputs();
+ }
+
+ /* only used for logic nets */
+ void set_Q_and_push(const netlist_sig_t newQ, const netlist_time delay) NL_NOEXCEPT
+ {
+ if (newQ != m_new_Q)
+ {
+ m_new_Q = newQ;
+ push_to_queue(delay);
+ }
+ }
+
+ /* only used for logic nets */
+ void set_Q_time(const netlist_sig_t newQ, const netlist_time at) NL_NOEXCEPT
+ {
+ if (newQ != m_new_Q)
+ {
+ m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
+ m_next_scheduled_time = at;
+ }
+ m_cur_Q = m_new_Q = newQ;
+ update_inputs();
+ }
+
+ /* internal state support
+ * FIXME: get rid of this and implement export/import in MAME
+ */
+ /* only used for logic nets */
+ netlist_sig_t *Q_state_ptr() { return m_cur_Q.ptr(); }
+
+ private:
+ state_var<netlist_sig_t> m_new_Q;
+ state_var<netlist_sig_t> m_cur_Q;
+ state_var<queue_status> m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */
+ state_var<netlist_time> m_next_scheduled_time;
+
+ core_terminal_t * m_railterminal;
+ plib::linkedlist_t<core_terminal_t> m_list_active;
+ std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
+
+ template <typename T>
+ void process(const T mask, netlist_sig_t sig);
+ };
+ } // namespace detail
// -----------------------------------------------------------------------------
// analog_t
@@ -550,7 +719,6 @@ namespace netlist
public:
analog_t(core_device_t &dev, const pstring &aname, const state_e state);
- virtual ~analog_t();
const analog_net_t & net() const NL_NOEXCEPT;
analog_net_t & net() NL_NOEXCEPT;
@@ -564,53 +732,44 @@ namespace netlist
{
public:
- terminal_t(core_device_t &dev, const pstring &aname);
- virtual ~terminal_t();
+ terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm);
nl_double operator ()() const NL_NOEXCEPT;
- void set(const nl_double &G) NL_NOEXCEPT
+ void set_conductivity(const nl_double G) noexcept
{
- set(G,G, 0.0);
+ set_go_gt_I(-G, G, 0.0);
}
- void set(const nl_double &GO, const nl_double &GT) NL_NOEXCEPT
+ void set_go_gt(const nl_double GO, const nl_double GT) noexcept
{
- set(GO, GT, 0.0);
+ set_go_gt_I(GO, GT, 0.0);
}
- void set(const nl_double &GO, const nl_double &GT, const nl_double &I) NL_NOEXCEPT
+ void set_go_gt_I(const nl_double GO, const nl_double GT, const nl_double I) noexcept
{
- set_ptr(m_Idr1, I);
- set_ptr(m_go1, GO);
- set_ptr(m_gt1, GT);
+ if (m_go1 != nullptr)
+ {
+ if (*m_Idr1 != I) *m_Idr1 = I;
+ if (*m_go1 != GO) *m_go1 = GO;
+ if (*m_gt1 != GT) *m_gt1 = GT;
+ }
}
void solve_now();
- void schedule_solve_after(const netlist_time &after);
+ void schedule_solve_after(const netlist_time after);
- void set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) NL_NOEXCEPT
- {
- m_gt1 = gt;
- m_go1 = go;
- m_Idr1 = Idr;
- }
-
- terminal_t *m_otherterm;
+ void set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) noexcept;
+ terminal_t *connected_terminal() const noexcept { return m_connected_terminal; }
private:
- void set_ptr(nl_double *ptr, const nl_double &val) NL_NOEXCEPT
- {
- if (ptr != nullptr && *ptr != val)
- {
- *ptr = val;
- }
- }
nl_double *m_Idr1; // drive current
nl_double *m_go1; // conductance for Voltage from other term
nl_double *m_gt1; // conductance for total conductance
+ terminal_t *m_connected_terminal;
+
};
@@ -623,7 +782,6 @@ namespace netlist
public:
logic_t(core_device_t &dev, const pstring &aname,
const state_e state, nldelegate delegate = nldelegate());
- virtual ~logic_t();
bool has_proxy() const { return (m_proxy != nullptr); }
devices::nld_base_proxy *get_proxy() const { return m_proxy; }
@@ -647,7 +805,6 @@ namespace netlist
public:
logic_input_t(core_device_t &dev, const pstring &aname,
nldelegate delegate = nldelegate());
- virtual ~logic_input_t();
netlist_sig_t operator()() const NL_NOEXCEPT
{
@@ -679,9 +836,6 @@ namespace netlist
const pstring &aname /*!< name of terminal */
);
- /*! Destructor */
- virtual ~analog_input_t();
-
/*! returns voltage at terminal.
* \returns voltage at terminal.
*/
@@ -694,124 +848,18 @@ namespace netlist
};
- // -----------------------------------------------------------------------------
- // net_t
- // -----------------------------------------------------------------------------
-
- class detail::net_t :
- public detail::object_t,
- public detail::netlist_ref
- {
- public:
-
- enum queue_status
- {
- QS_DELAYED_DUE_TO_INACTIVE = 0,
- QS_QUEUED,
- QS_DELIVERED
- };
-
- net_t(netlist_t &nl, const pstring &aname, core_terminal_t *mr = nullptr);
- virtual ~net_t();
-
- void reset();
-
- void toggle_new_Q() NL_NOEXCEPT { m_new_Q = (m_cur_Q ^ 1); }
-
- void toggle_and_push_to_queue(const netlist_time &delay) NL_NOEXCEPT
- {
- toggle_new_Q();
- push_to_queue(delay);
- }
-
- void push_to_queue(const netlist_time &delay) NL_NOEXCEPT;
- bool is_queued() const NL_NOEXCEPT { return m_in_queue == QS_QUEUED; }
-
- void update_devs() NL_NOEXCEPT;
-
- const netlist_time &time() const NL_NOEXCEPT { return m_time; }
- void set_time(const netlist_time &ntime) NL_NOEXCEPT { m_time = ntime; }
-
- bool isRailNet() const NL_NOEXCEPT { return !(m_railterminal == nullptr); }
- core_terminal_t & railterminal() const NL_NOEXCEPT { return *m_railterminal; }
-
- std::size_t num_cons() const NL_NOEXCEPT { return m_core_terms.size(); }
-
- void inc_active(core_terminal_t &term) NL_NOEXCEPT;
- void dec_active(core_terminal_t &term) NL_NOEXCEPT;
-
- /* setup stuff */
-
- void add_terminal(core_terminal_t &terminal);
- void remove_terminal(core_terminal_t &terminal);
-
- bool is_logic() const NL_NOEXCEPT;
- bool is_analog() const NL_NOEXCEPT;
-
- void rebuild_list(); /* rebuild m_list after a load */
- void move_connections(net_t &dest_net);
-
- std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
-
- protected:
- state_var<netlist_sig_t> m_new_Q;
- state_var<netlist_sig_t> m_cur_Q;
- state_var<queue_status> m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */
- state_var_s32 m_active;
-
- state_var<netlist_time> m_time;
-
- private:
- plib::linkedlist_t<core_terminal_t> m_list_active;
- core_terminal_t * m_railterminal;
-
- void process(unsigned Mask);
- };
class logic_net_t : public detail::net_t
{
public:
- logic_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
- virtual ~logic_net_t();
-
- netlist_sig_t Q() const NL_NOEXCEPT { return m_cur_Q; }
- void initial(const netlist_sig_t val) NL_NOEXCEPT { m_cur_Q = m_new_Q = val; }
-
- void set_Q_and_push(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
- {
- if (newQ != m_new_Q )
- {
- m_new_Q = newQ;
- push_to_queue(delay);
- }
- }
- void set_Q_and_push_force(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
- {
- if (newQ != m_new_Q || is_queued())
- {
- m_new_Q = newQ;
- push_to_queue(delay);
- }
- }
-
- void set_Q_time(const netlist_sig_t newQ, const netlist_time &at) NL_NOEXCEPT
- {
- if (newQ != m_new_Q)
- {
- m_in_queue = QS_DELAYED_DUE_TO_INACTIVE;
- m_time = at;
- }
- m_cur_Q = m_new_Q = newQ;
- }
-
- /* internal state support
- * FIXME: get rid of this and implement export/import in MAME
- */
- netlist_sig_t *Q_state_ptr() { return m_cur_Q.ptr(); }
+ logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
- protected:
- private:
+ using detail::net_t::Q;
+ using detail::net_t::initial;
+ using detail::net_t::set_Q_and_push;
+ using detail::net_t::set_Q_time;
+ using detail::net_t::Q_state_ptr;
};
@@ -823,9 +871,7 @@ namespace netlist
friend class detail::net_t;
- analog_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
-
- virtual ~analog_net_t();
+ analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
nl_double Q_Analog() const NL_NOEXCEPT { return m_cur_Analog; }
void set_Q_Analog(const nl_double v) NL_NOEXCEPT { m_cur_Analog = v; }
@@ -849,21 +895,15 @@ namespace netlist
public:
logic_output_t(core_device_t &dev, const pstring &aname);
- virtual ~logic_output_t();
void initial(const netlist_sig_t val);
- void push(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
+ void push(const netlist_sig_t newQ, const netlist_time delay) NL_NOEXCEPT
{
m_my_net.set_Q_and_push(newQ, delay); // take the shortcut
}
- void push_force(const netlist_sig_t newQ, const netlist_time &delay) NL_NOEXCEPT
- {
- m_my_net.set_Q_and_push_force(newQ, delay); // take the shortcut
- }
-
- void set_Q_time(const netlist_sig_t newQ, const netlist_time &at) NL_NOEXCEPT
+ void set_Q_time(const netlist_sig_t newQ, const netlist_time at) NL_NOEXCEPT
{
m_my_net.set_Q_time(newQ, at); // take the shortcut
}
@@ -876,7 +916,6 @@ namespace netlist
{
public:
analog_output_t(core_device_t &dev, const pstring &aname);
- virtual ~analog_output_t();
void push(const nl_double val) NL_NOEXCEPT { set_Q(val); }
void initial(const nl_double val);
@@ -904,13 +943,17 @@ namespace netlist
param_t(device_t &device, const pstring &name);
+ COPYASSIGNMOVE(param_t, delete)
+
param_type_t param_type() const;
protected:
- virtual ~param_t(); /* not intended to be destroyed */
+ virtual ~param_t() noexcept = default; /* not intended to be destroyed */
void update_param();
+ pstring get_initial(const device_t &dev, bool *found);
+
template<typename C>
void set(C &p, const C v)
{
@@ -923,53 +966,51 @@ namespace netlist
};
- class param_ptr_t final: public param_t
- {
- public:
- param_ptr_t(device_t &device, const pstring &name, std::uint8_t* val);
- std::uint8_t * operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(std::uint8_t *param) { set(m_param, param); }
- private:
- std::uint8_t* m_param;
- };
+ // -----------------------------------------------------------------------------
+ // numeric parameter template
+ // -----------------------------------------------------------------------------
- class param_logic_t final: public param_t
+ template <typename T>
+ class param_num_t final: public param_t
{
public:
- param_logic_t(device_t &device, const pstring &name, const bool val);
- const bool &operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(const bool &param) { set(m_param, param); }
- private:
- bool m_param;
- };
+ param_num_t(device_t &device, const pstring &name, const T val);
- class param_int_t final: public param_t
- {
- public:
- param_int_t(device_t &device, const pstring &name, const int val);
- const int &operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(const int &param) { set(m_param, param); }
+ const T operator()() const NL_NOEXCEPT { return m_param; }
+ void setTo(const T &param) { set(m_param, param); }
private:
- int m_param;
+ T m_param;
};
- class param_double_t final: public param_t
+ /* FIXME: these should go as well */
+ using param_logic_t = param_num_t<bool>;
+ using param_int_t = param_num_t<int>;
+ using param_double_t = param_num_t<double>;
+
+ // -----------------------------------------------------------------------------
+ // pointer parameter
+ // -----------------------------------------------------------------------------
+
+ class param_ptr_t final: public param_t
{
public:
- param_double_t(device_t &device, const pstring &name, const double val);
- const double &operator()() const NL_NOEXCEPT { return m_param; }
- void setTo(const double &param) { set(m_param, param); }
+ param_ptr_t(device_t &device, const pstring &name, std::uint8_t* val);
+ std::uint8_t * operator()() const NL_NOEXCEPT { return m_param; }
+ void setTo(std::uint8_t *param) { set(m_param, param); }
private:
- double m_param;
+ std::uint8_t* m_param;
};
+ // -----------------------------------------------------------------------------
+ // string parameter
+ // -----------------------------------------------------------------------------
+
class param_str_t : public param_t
{
public:
param_str_t(device_t &device, const pstring &name, const pstring &val);
- virtual ~param_str_t();
- const pstring &operator()() const NL_NOEXCEPT { return Value(); }
+ const pstring &operator()() const NL_NOEXCEPT { return value(); }
void setTo(const pstring &param) NL_NOEXCEPT
{
if (m_param != param)
@@ -981,11 +1022,16 @@ namespace netlist
}
protected:
virtual void changed();
- const pstring &Value() const NL_NOEXCEPT { return m_param; }
+ const pstring &value() const NL_NOEXCEPT { return m_param; }
private:
+ PALIGNAS_CACHELINE()
pstring m_param;
};
+ // -----------------------------------------------------------------------------
+ // model parameter
+ // -----------------------------------------------------------------------------
+
class param_model_t : public param_str_t
{
public:
@@ -997,8 +1043,8 @@ namespace netlist
: m_value(param.model_value(name))
{
}
- const double &operator()() const NL_NOEXCEPT { return m_value; }
- operator const double&() const NL_NOEXCEPT { return m_value; }
+ double operator()() const noexcept { return m_value; }
+ operator double() const noexcept { return m_value; }
private:
const double m_value;
};
@@ -1010,24 +1056,29 @@ namespace netlist
const pstring model_value_str(const pstring &entity) /*const*/;
const pstring model_type() /*const*/;
+ /* hide this */
+ void setTo(const pstring &param) = delete;
protected:
- virtual void changed() override;
+ void changed() override;
nl_double model_value(const pstring &entity) /*const*/;
private:
- /* hide this */
- void setTo(const pstring &param) = delete;
- detail::model_map_t m_map;
};
+ // -----------------------------------------------------------------------------
+ // data parameter
+ // -----------------------------------------------------------------------------
class param_data_t : public param_str_t
{
public:
- param_data_t(device_t &device, const pstring &name);
+ param_data_t(device_t &device, const pstring &name)
+ : param_str_t(device, name, "")
+ {
+ }
- std::unique_ptr<plib::pistream> stream();
+ plib::unique_ptr<plib::pistream> stream();
protected:
- virtual void changed() override;
+ void changed() override { }
};
// -----------------------------------------------------------------------------
@@ -1041,15 +1092,15 @@ namespace netlist
param_rom_t(device_t &device, const pstring &name);
- const ST & operator[] (std::size_t n) NL_NOEXCEPT { return m_data[n]; }
+ ST operator[] (std::size_t n) const NL_NOEXCEPT { return m_data[n]; }
protected:
- virtual void changed() override
+ void changed() override
{
- stream()->read(&m_data[0],1<<AW);
+ stream()->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
}
private:
- ST m_data[1 << AW];
+ std::array<ST, 1 << AW> m_data;
};
// -----------------------------------------------------------------------------
@@ -1062,68 +1113,67 @@ namespace netlist
public detail::netlist_ref
{
public:
- core_device_t(netlist_t &owner, const pstring &name);
+ core_device_t(netlist_state_t &owner, const pstring &name);
core_device_t(core_device_t &owner, const pstring &name);
- virtual ~core_device_t();
+ COPYASSIGNMOVE(core_device_t, delete)
- void update_dev() NL_NOEXCEPT
- {
- do_update();
- }
+ virtual ~core_device_t() noexcept = default;
void do_inc_active() NL_NOEXCEPT
{
if (m_hint_deactivate)
{
- m_stat_inc_active.inc();
- inc_active();
+ if (++m_active_outputs == 1)
+ {
+ m_stat_inc_active.inc();
+ inc_active();
+ }
}
}
void do_dec_active() NL_NOEXCEPT
{
if (m_hint_deactivate)
- dec_active();
+ if (--m_active_outputs == 0)
+ {
+ dec_active();
+ }
}
- void do_reset() { reset(); }
void set_hint_deactivate(bool v) { m_hint_deactivate = v; }
bool get_hint_deactivate() { return m_hint_deactivate; }
+ /* Has to be set in device reset */
+ void set_active_outputs(int n) { m_active_outputs = n; }
void set_default_delegate(detail::core_terminal_t &term);
/* stats */
- nperftime_t m_stat_total_time;
- nperfcount_t m_stat_call_count;
- nperfcount_t m_stat_inc_active;
+ nperftime_t<NL_KEEP_STATISTICS> m_stat_total_time;
+ nperfcount_t<NL_KEEP_STATISTICS> m_stat_call_count;
+ nperfcount_t<NL_KEEP_STATISTICS> m_stat_inc_active;
+ virtual void update() NL_NOEXCEPT { }
+ virtual void reset() { }
protected:
- virtual void update() NL_NOEXCEPT { }
virtual void inc_active() NL_NOEXCEPT { }
virtual void dec_active() NL_NOEXCEPT { }
- virtual void reset() { }
- void do_update() NL_NOEXCEPT
- {
- update();
- }
-
- plib::plog_base<netlist_t, NL_DEBUG> &log();
+ log_type & log();
public:
- virtual void timestep(ATTR_UNUSED const nl_double st) { }
+ virtual void timestep(const nl_double st) { plib::unused_var(st); }
virtual void update_terminals() { }
virtual void update_param() {}
virtual bool is_dynamic() const { return false; }
virtual bool is_timestep() const { return false; }
- virtual bool needs_update_after_param_change() const { return false; }
private:
- bool m_hint_deactivate;
+ bool m_hint_deactivate;
+ state_var_s32 m_active_outputs;
};
// -----------------------------------------------------------------------------
@@ -1134,17 +1184,20 @@ namespace netlist
{
public:
- device_t(netlist_t &owner, const pstring &name);
+ device_t(netlist_state_t &owner, const pstring &name);
device_t(core_device_t &owner, const pstring &name);
- virtual ~device_t() override;
+ COPYASSIGNMOVE(device_t, delete)
+
+ ~device_t() noexcept override = default;
setup_t &setup();
+ const setup_t &setup() const;
template<class C, typename... Args>
- void register_sub(const pstring &name, std::unique_ptr<C> &dev, const Args&... args)
+ void create_and_register_subdevice(const pstring &name, pool_owned_ptr<C> &dev, Args&&... args)
{
- dev.reset(plib::palloc<C>(*this, name, args...));
+ dev = pool().make_poolptr<C>(*this, name, std::forward<Args>(args)...);
}
void register_subalias(const pstring &name, detail::core_terminal_t &term);
@@ -1167,13 +1220,18 @@ namespace netlist
struct detail::family_setter_t
{
- family_setter_t() { }
+ /* clang will complain about an unused private field if
+ * a defaulted constructor is used
+ */
+ // NOLINTNEXTLINE(modernize-use-equals-default)
+ family_setter_t();
family_setter_t(core_device_t &dev, const pstring &desc);
family_setter_t(core_device_t &dev, const logic_family_desc_t *desc);
};
// -----------------------------------------------------------------------------
// nld_base_dummy : basis for dummy devices
+ // FIXME: this is not the right place to define this
// -----------------------------------------------------------------------------
NETLIB_OBJECT(base_dummy)
@@ -1190,19 +1248,25 @@ namespace netlist
* solvers will update inputs after parallel processing.
*/
class detail::queue_t :
- public timed_queue<pqentry_t<net_t *, netlist_time>, false>,
+ public timed_queue<pqentry_t<net_t *, netlist_time>, false, NL_KEEP_STATISTICS>,
public detail::netlist_ref,
public plib::state_manager_t::callback_t
{
public:
- typedef pqentry_t<net_t *, netlist_time> entry_t;
- explicit queue_t(netlist_t &nl);
+ using entry_t = pqentry_t<net_t *, netlist_time>;
+ explicit queue_t(netlist_state_t &nl);
+ virtual ~queue_t() noexcept = default;
+
+ queue_t(const queue_t &) = delete;
+ queue_t(queue_t &&) = delete;
+ queue_t &operator=(const queue_t &) = delete;
+ queue_t &operator=(queue_t &&) = delete;
protected:
void register_state(plib::state_manager_t &manager, const pstring &module) override;
- void on_pre_save() override;
- void on_post_load() override;
+ void on_pre_save(plib::state_manager_t &manager) override;
+ void on_post_load(plib::state_manager_t &manager) override;
private:
std::size_t m_qsize;
@@ -1211,139 +1275,214 @@ namespace netlist
};
// -----------------------------------------------------------------------------
- // netlist_t
+ // netlist_state__t
// -----------------------------------------------------------------------------
-
- class netlist_t : private plib::nocopyassignmove
+ class netlist_state_t
{
public:
- explicit netlist_t(const pstring &aname);
- virtual ~netlist_t();
+ using nets_collection_type = std::vector<pool_owned_ptr<detail::net_t>>;
- /* run functions */
+ /* need to preserve order of device creation ... */
+ using devices_collection_type = std::vector<std::pair<pstring, pool_owned_ptr<core_device_t>>>;
+ netlist_state_t(const pstring &aname,
+ netlist_t & anetlist,
+ plib::unique_ptr<callbacks_t> &&callbacks);
- const netlist_time &time() const NL_NOEXCEPT { return m_time; }
- devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; }
+ COPYASSIGNMOVE(netlist_state_t, delete)
- /* never use this in constructors! */
- nl_double gmin() const NL_NOEXCEPT;
+ ~netlist_state_t() noexcept = default;
- void process_queue(const netlist_time &delta) NL_NOEXCEPT;
- void abort_current_queue_slice() NL_NOEXCEPT { m_queue.retime(detail::queue_t::entry_t(m_time, nullptr)); }
+ friend class netlist_t; // allow access to private members
- /* Control functions */
+ template<class C>
+ static bool check_class(core_device_t *p)
+ {
+ return dynamic_cast<C *>(p) != nullptr;
+ }
- void start();
- void stop();
- void reset();
+ template<class C>
+ C *get_single_device(const pstring &classname) const
+ {
+ return dynamic_cast<C *>(get_single_device(classname, check_class<C>));
+ }
- const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; }
- detail::queue_t &queue() NL_NOEXCEPT { return m_queue; }
+ /* logging and name */
- /* netlist build functions */
+ pstring name() const { return m_name; }
- setup_t &setup() NL_NOEXCEPT { return *m_setup; }
+ log_type & log() { return m_log; }
+ const log_type &log() const { return m_log; }
+
+ plib::dynlib &lib() { return *m_lib; }
+
+ netlist_t &exec() { return m_netlist; }
+ const netlist_t &exec() const { return m_netlist; }
- void register_dev(plib::owned_ptr<core_device_t> dev);
- void remove_dev(core_device_t *dev);
+ /* state handling */
+ plib::state_manager_t &run_state_manager() { return m_state; }
+
+ template<typename O, typename C>
+ void save(O &owner, C &state, const pstring &module, const pstring &stname)
+ {
+ this->run_state_manager().save_item(static_cast<void *>(&owner), state, module + pstring(".") + stname);
+ }
+ template<typename O, typename C>
+ void save(O &owner, C *state, const pstring &module, const pstring &stname, const std::size_t count)
+ {
+ this->run_state_manager().save_state_ptr(static_cast<void *>(&owner), module + pstring(".") + stname, plib::state_manager_t::dtype<C>(), count, state);
+ }
+
+ core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const;
detail::net_t *find_net(const pstring &name) const;
std::size_t find_net_id(const detail::net_t *net) const;
+ template <typename T>
+ void register_net(pool_owned_ptr<T> &&net) { m_nets.push_back(std::move(net)); }
+
template<class device_class>
- std::vector<device_class *> get_device_list() const
+ inline std::vector<device_class *> get_device_list()
{
std::vector<device_class *> tmp;
for (auto &d : m_devices)
{
- device_class *dev = dynamic_cast<device_class *>(d.get());
+ auto dev = dynamic_cast<device_class *>(d.second.get());
if (dev != nullptr)
tmp.push_back(dev);
}
return tmp;
}
- template<class C>
- static bool check_class(core_device_t *p)
+ template <typename T>
+ void add_dev(const pstring &name, pool_owned_ptr<T> &&dev)
{
- return dynamic_cast<C *>(p) != nullptr;
+ for (auto & d : m_devices)
+ if (d.first == name)
+ log().fatal(MF_1_DUPLICATE_NAME_DEVICE_LIST, d.first);
+ //m_devices.push_back(std::move(dev));
+ m_devices.insert(m_devices.end(), { name, std::move(dev) });
}
- template<class C>
- C *get_single_device(const pstring &classname) const
+ /**
+ * @brief Remove device
+ *
+ * Care needs to be applied if this is called to remove devices with
+ * sub-devices which may have registered state.
+ *
+ * @param dev Device to be removed
+ */
+ void remove_dev(core_device_t *dev)
{
- return dynamic_cast<C *>(get_single_device(classname, check_class<C>));
+ for (auto it = m_devices.begin(); it != m_devices.end(); it++)
+ if (it->second.get() == dev)
+ {
+ m_state.remove_save_items(dev);
+ m_devices.erase(it);
+ return;
+ }
}
- /* logging and name */
+ /* sole use is to manage lifetime of family objects */
+ std::vector<std::pair<pstring, plib::unique_ptr<logic_family_desc_t>>> m_family_cache;
- pstring name() const { return m_name; }
- plib::plog_base<netlist_t, NL_DEBUG> &log() { return m_log; }
- const plib::plog_base<netlist_t, NL_DEBUG> &log() const { return m_log; }
+ setup_t &setup() NL_NOEXCEPT { return *m_setup; }
+ const setup_t &setup() const NL_NOEXCEPT { return *m_setup; }
- /* state related */
+ nets_collection_type & nets() { return m_nets; }
+ devices_collection_type & devices() { return m_devices; }
- plib::state_manager_t &state() { return m_state; }
+ // FIXME: make a postload member and include code there
+ void rebuild_lists(); /* must be called after post_load ! */
- template<typename O, typename C> void save(O &owner, C &state, const pstring &stname)
- {
- this->state().save_item(static_cast<void *>(&owner), state, from_utf8(owner.name()) + pstring(".") + stname);
- }
- template<typename O, typename C> void save(O &owner, C *state, const pstring &stname, const std::size_t count)
- {
- this->state().save_state_ptr(static_cast<void *>(&owner), from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f<C>::f(), count, state);
- }
+ private:
- plib::dynlib &lib() { return *m_lib; }
+ void reset();
- // FIXME: find something better
+ pstring m_name;
+ netlist_t &m_netlist;
+ plib::unique_ptr<plib::dynlib> m_lib; // external lib needs to be loaded as long as netlist exists
+ plib::state_manager_t m_state;
+ plib::unique_ptr<callbacks_t> m_callbacks;
+ log_type m_log;
+ plib::unique_ptr<setup_t> m_setup;
+
+ nets_collection_type m_nets;
/* sole use is to manage lifetime of net objects */
- std::vector<plib::owned_ptr<detail::net_t>> m_nets;
- /* sole use is to manage lifetime of family objects */
- std::vector<std::pair<pstring, std::unique_ptr<logic_family_desc_t>>> m_family_cache;
+ devices_collection_type m_devices;
- // FIXME: sort rebuild_lists out
- void rebuild_lists(); /* must be called after post_load ! */
- /* logging callback */
- virtual void vlog(const plib::plog_level &l, const pstring &ls) const = 0;
- protected:
+ };
- void print_stats() const;
+ // -----------------------------------------------------------------------------
+ // netlist_t
+ // -----------------------------------------------------------------------------
- private:
+ class netlist_t
+ {
+ public:
- /* helper for save above */
- static pstring from_utf8(const char *c) { return pstring(c, pstring::UTF8); }
- static pstring from_utf8(const pstring &c) { return c; }
+ explicit netlist_t(const pstring &aname, plib::unique_ptr<callbacks_t> callbacks);
- core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const;
+ COPYASSIGNMOVE(netlist_t, delete)
- /* mostly rw */
- netlist_time m_time;
- detail::queue_t m_queue;
+ ~netlist_t() noexcept = default;
- /* mostly ro */
+ /* run functions */
- devices::NETLIB_NAME(mainclock) * m_mainclock;
- devices::NETLIB_NAME(solver) * m_solver;
- devices::NETLIB_NAME(netlistparams) *m_params;
+ netlist_time time() const NL_NOEXCEPT { return m_time; }
- pstring m_name;
- std::unique_ptr<setup_t> m_setup;
- plib::plog_base<netlist_t, NL_DEBUG> m_log;
- std::unique_ptr<plib::dynlib> m_lib; // external lib needs to be loaded as long as netlist exists
+ void process_queue(const netlist_time delta) NL_NOEXCEPT;
+ void abort_current_queue_slice() NL_NOEXCEPT { m_queue.retime(detail::queue_t::entry_t(m_time, nullptr)); }
- plib::state_manager_t m_state;
+ const detail::queue_t &queue() const NL_NOEXCEPT { return m_queue; }
+ detail::queue_t &queue() NL_NOEXCEPT { return m_queue; }
- // performance
- nperftime_t m_stat_mainloop;
- nperfcount_t m_perf_out_processed;
+ /* Control functions */
+
+ void stop();
+ void reset();
+
+ /* state handling */
+
+ plib::state_manager_t &run_state_manager() { return m_state->run_state_manager(); }
+
+ /* only used by nltool to create static c-code */
+ devices::NETLIB_NAME(solver) *solver() const NL_NOEXCEPT { return m_solver; }
+
+ /* force late type resolution */
+ template <typename X = devices::NETLIB_NAME(solver)>
+ nl_double gmin(X *solv = nullptr) const NL_NOEXCEPT
+ {
+ plib::unused_var(solv);
+ return static_cast<X *>(m_solver)->gmin();
+ }
+
+ netlist_state_t &nlstate() NL_NOEXCEPT { return *m_state; }
+ const netlist_state_t &nlstate() const { return *m_state; }
+
+ log_type & log() { return m_state->log(); }
+ const log_type &log() const { return m_state->log(); }
+
+ void print_stats() const;
+
+ private:
+ plib::unique_ptr<netlist_state_t> m_state;
+ devices::NETLIB_NAME(solver) * m_solver;
+
+ /* mostly rw */
+ PALIGNAS_CACHELINE()
+ netlist_time m_time;
+ devices::NETLIB_NAME(mainclock) * m_mainclock;
- std::vector<plib::owned_ptr<core_device_t>> m_devices;
+ PALIGNAS_CACHELINE()
+ detail::queue_t m_queue;
+
+ // performance
+ nperftime_t<NL_KEEP_STATISTICS> m_stat_mainloop;
+ nperfcount_t<NL_KEEP_STATISTICS> m_perf_out_processed;
};
// -----------------------------------------------------------------------------
@@ -1356,12 +1495,13 @@ namespace netlist
public:
struct init
{
- const char *p[N];
+ std::array<const char *, N> p;
};
- object_array_t(core_device_t &dev, init names)
+ template<typename... Args>
+ object_array_t(core_device_t &dev, init names, Args&&... args)
{
for (std::size_t i = 0; i<N; i++)
- this->emplace(i, dev, pstring(names.p[i], pstring::UTF8));
+ this->emplace(i, dev, pstring(names.p[i]), std::forward<Args>(args)...);
}
};
@@ -1369,15 +1509,56 @@ namespace netlist
// inline implementations
// -----------------------------------------------------------------------------
+ inline netlist_state_t & detail::netlist_ref::state() noexcept
+ {
+ return m_netlist.nlstate();
+ }
+
+ inline const netlist_state_t & detail::netlist_ref::state() const noexcept
+ {
+ return m_netlist.nlstate();
+ }
+
+ inline setup_t & detail::netlist_ref::setup() noexcept
+ {
+ return m_netlist.nlstate().setup();
+ }
+
+ inline const setup_t & detail::netlist_ref::setup() const noexcept
+ {
+ return m_netlist.nlstate().setup();
+ }
+
+ template <typename T>
+ param_num_t<T>::param_num_t(device_t &device, const pstring &name, const T val)
+ : param_t(device, name)
+ {
+ //m_param = device.setup().get_initial_param_val(this->name(),val);
+ bool found = false;
+ pstring p = this->get_initial(device, &found);
+ if (found)
+ {
+ bool err = false;
+ auto vald = plib::pstonum_ne<T>(p, err);
+ if (err)
+ device.state().log().fatal(MF_2_INVALID_NUMBER_CONVERSION_1_2, name, p);
+ m_param = vald;
+ }
+ else
+ m_param = val;
+
+ device.state().save(*this, m_param, this->name(), "m_param");
+ }
+
template <typename ST, std::size_t AW, std::size_t DW>
- inline param_rom_t<ST, AW, DW>::param_rom_t(device_t &device, const pstring &name)
+ param_rom_t<ST, AW, DW>::param_rom_t(device_t &device, const pstring &name)
: param_data_t(device, name)
{
auto f = stream();
if (f != nullptr)
- f->read(&m_data[0],1<<AW);
+ f->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
else
- device.netlist().log().warning("Rom {1} not found", Value());
+ device.state().log().warning("Rom {1} not found", value());
}
inline void logic_input_t::inactivate() NL_NOEXCEPT
@@ -1385,7 +1566,7 @@ namespace netlist
if (!is_state(STATE_INP_PASSIVE))
{
set_state(STATE_INP_PASSIVE);
- net().dec_active(*this);
+ net().remove_from_active_list(*this);
}
}
@@ -1393,7 +1574,7 @@ namespace netlist
{
if (is_state(STATE_INP_PASSIVE))
{
- net().inc_active(*this);
+ net().add_to_active_list(*this);
set_state(STATE_INP_ACTIVE);
}
}
@@ -1402,7 +1583,7 @@ namespace netlist
{
if (is_state(STATE_INP_PASSIVE))
{
- net().inc_active(*this);
+ net().add_to_active_list(*this);
set_state(STATE_INP_HL);
}
}
@@ -1411,24 +1592,68 @@ namespace netlist
{
if (is_state(STATE_INP_PASSIVE))
{
- net().inc_active(*this);
+ net().add_to_active_list(*this);
set_state(STATE_INP_LH);
}
}
- inline void detail::net_t::push_to_queue(const netlist_time &delay) NL_NOEXCEPT
+ inline void detail::net_t::push_to_queue(const netlist_time delay) NL_NOEXCEPT
{
if ((num_cons() != 0))
{
+ auto &lexec(exec());
+ auto &q(lexec.queue());
+ auto nst(lexec.time() + delay);
+
if (is_queued())
- netlist().queue().remove(this);
- m_time = netlist().time() + delay;
- m_in_queue = (m_active > 0) ? QS_QUEUED : QS_DELAYED_DUE_TO_INACTIVE; /* queued ? */
- if (m_in_queue == QS_QUEUED)
- netlist().queue().push(queue_t::entry_t(m_time, this));
+ q.remove(this);
+ m_in_queue = (!m_list_active.empty()) ?
+ queue_status::QUEUED : queue_status::DELAYED_DUE_TO_INACTIVE; /* queued ? */
+ if (m_in_queue == queue_status::QUEUED)
+ q.push(queue_t::entry_t(nst, this));
+ else
+ update_inputs();
+ m_next_scheduled_time = nst;
+ }
+ }
+
+ inline void detail::net_t::add_to_active_list(core_terminal_t &term) NL_NOEXCEPT
+ {
+ if (m_list_active.empty())
+ {
+ 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().queue().push({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);
+ }
+ else
+ {
+ term.set_copied_input(m_cur_Q);
+ m_list_active.push_front(&term);
}
}
+ inline void detail::net_t::remove_from_active_list(core_terminal_t &term) NL_NOEXCEPT
+ {
+ m_list_active.remove(&term);
+ if (m_list_active.empty())
+ railterminal().device().do_dec_active();
+ }
+
inline const analog_net_t & analog_t::net() const NL_NOEXCEPT
{
return static_cast<const analog_net_t &>(core_terminal_t::net());
@@ -1441,6 +1666,18 @@ namespace netlist
inline nl_double terminal_t::operator ()() const NL_NOEXCEPT { return net().Q_Analog(); }
+ inline void terminal_t::set_ptrs(nl_double *gt, nl_double *go, nl_double *Idr) noexcept
+ {
+ if (!(gt && go && Idr) && (gt || go || Idr))
+ state().log().fatal("Inconsistent nullptrs for terminal {}", name());
+ else
+ {
+ m_gt1 = gt;
+ m_go1 = go;
+ m_Idr1 = Idr;
+ }
+ }
+
inline logic_net_t & logic_t::net() NL_NOEXCEPT
{
return static_cast<logic_net_t &>(core_terminal_t::net());
@@ -1453,8 +1690,14 @@ namespace netlist
inline netlist_sig_t logic_input_t::Q() const NL_NOEXCEPT
{
- nl_assert(state() != STATE_INP_PASSIVE);
+ nl_assert(terminal_state() != STATE_INP_PASSIVE);
+ //if (net().Q() != m_Q)
+ // printf("term: %s, %d %d TS %d\n", this->name().c_str(), net().Q(), m_Q, terminal_state());
+#if USE_COPY_INSTEAD_OF_REFERENCE
+ return m_Q;
+#else
return net().Q();
+#endif
}
inline nl_double analog_input_t::Q_Analog() const NL_NOEXCEPT
@@ -1471,14 +1714,24 @@ namespace netlist
}
}
- inline netlist_t &detail::device_object_t::netlist() NL_NOEXCEPT
+ inline netlist_state_t &detail::device_object_t::state() NL_NOEXCEPT
+ {
+ return m_device.state();
+ }
+
+ inline const netlist_state_t &detail::device_object_t::state() const NL_NOEXCEPT
+ {
+ return m_device.state();
+ }
+
+ inline netlist_t &detail::device_object_t::exec() NL_NOEXCEPT
{
- return m_device.netlist();
+ return m_device.exec();
}
- inline const netlist_t &detail::device_object_t::netlist() const NL_NOEXCEPT
+ inline const netlist_t &detail::device_object_t::exec() const NL_NOEXCEPT
{
- return m_device.netlist();
+ return m_device.exec();
}
template <typename T>
@@ -1486,18 +1739,18 @@ namespace netlist
state_var<T>::state_var(O &owner, const pstring &name, const T &value)
: m_value(value)
{
- owner.netlist().save(owner, m_value, name);
+ owner.state().save(owner, m_value, owner.name(), name);
}
template <typename T, std::size_t N>
template <typename O>
- state_var<T[N]>::state_var(O &owner, const pstring &name, const T & value)
+ state_array<T,N>::state_array(O &owner, const pstring &name, const T & value)
{
- owner.netlist().save(owner, m_value, name);
+ owner.state().save(owner, m_value, owner.name(), name);
for (std::size_t i=0; i<N; i++)
m_value[i] = value;
}
-}
+} // namespace netlist
namespace plib
{
@@ -1505,7 +1758,7 @@ namespace plib
struct ptype_traits<netlist::state_var<X>> : ptype_traits<X>
{
};
-}
+} // namespace plib