diff options
Diffstat (limited to 'src/lib/netlist/nl_base.h')
-rw-r--r-- | src/lib/netlist/nl_base.h | 1307 |
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 >) 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 >, 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 ¶m) { 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 ¶m) { set(m_param, param); } + const T operator()() const NL_NOEXCEPT { return m_param; } + void setTo(const T ¶m) { 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 ¶m) { 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 ¶m) 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 ¶m) = delete; protected: - virtual void changed() override; + void changed() override; nl_double model_value(const pstring &entity) /*const*/; private: - /* hide this */ - void setTo(const pstring ¶m) = 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 |