diff options
author | 2020-07-25 14:45:11 +0200 | |
---|---|---|
committer | 2020-07-25 14:47:22 +0200 | |
commit | 494690081bde2783eac0bc12507d03cd51c5eeb0 (patch) | |
tree | 11b6d089e1ede49df0a22c59c3483eb460e37e41 | |
parent | 2231bf8ae0ab6e752e394ad2c84d843d6a19d0f8 (diff) |
netlist: separate nl_base.h into separate header files.
* This clean-up exercise will hopefully make it easier to navigate the
core code. Another long term goal is to further straighten the object
model.
-rw-r--r-- | scripts/src/netlist.lua | 5 | ||||
-rw-r--r-- | src/lib/netlist/core/base_objects.h | 388 | ||||
-rw-r--r-- | src/lib/netlist/core/logic_family.h | 93 | ||||
-rw-r--r-- | src/lib/netlist/core/nets.h | 186 | ||||
-rw-r--r-- | src/lib/netlist/core/param.h | 275 | ||||
-rw-r--r-- | src/lib/netlist/core/state_var.h | 173 | ||||
-rw-r--r-- | src/lib/netlist/devices/nld_system.cpp | 7 | ||||
-rw-r--r-- | src/lib/netlist/nl_base.cpp | 2 | ||||
-rw-r--r-- | src/lib/netlist/nl_base.h | 997 | ||||
-rw-r--r-- | src/lib/netlist/nltypes.h | 20 | ||||
-rw-r--r-- | src/lib/netlist/plib/penum.h | 1 | ||||
-rw-r--r-- | src/lib/netlist/solver/nld_matrix_solver.cpp | 1 | ||||
-rw-r--r-- | src/lib/netlist/solver/nld_matrix_solver.h | 2 |
13 files changed, 1149 insertions, 1001 deletions
diff --git a/scripts/src/netlist.lua b/scripts/src/netlist.lua index 0a949221079..1fb67963c29 100644 --- a/scripts/src/netlist.lua +++ b/scripts/src/netlist.lua @@ -50,7 +50,12 @@ project "netlist" MAME_DIR .. "src/lib/netlist/nl_setup.cpp", MAME_DIR .. "src/lib/netlist/nl_setup.h", MAME_DIR .. "src/lib/netlist/nl_types.h", + MAME_DIR .. "src/lib/netlist/core/base_objects.h", + MAME_DIR .. "src/lib/netlist/core/logic_family.h", + MAME_DIR .. "src/lib/netlist/core/nets.h", + MAME_DIR .. "src/lib/netlist/core/param.h", MAME_DIR .. "src/lib/netlist/core/setup.h", + MAME_DIR .. "src/lib/netlist/core/state_var.h", MAME_DIR .. "src/lib/netlist/plib/pconfig.h", MAME_DIR .. "src/lib/netlist/plib/palloc.h", MAME_DIR .. "src/lib/netlist/plib/pchrono.h", diff --git a/src/lib/netlist/core/base_objects.h b/src/lib/netlist/core/base_objects.h new file mode 100644 index 00000000000..c697617e265 --- /dev/null +++ b/src/lib/netlist/core/base_objects.h @@ -0,0 +1,388 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file param.h +/// + +#ifndef NL_CORE_BASE_OBJECTS_H_ +#define NL_CORE_BASE_OBJECTS_H_ + +#include "state_var.h" + +#include "../nltypes.h" + +#include "../plib/palloc.h" +#include "../plib/pmempool.h" +#include "../plib/pchrono.h" +#include "../plib/pexception.h" +#include "../plib/plists.h" + +#include <unordered_map> + +namespace netlist +{ + + //============================================================ + // Exceptions + //============================================================ + + /// \brief Generic netlist exception. + /// The exception is used in all events which are considered fatal. + + class nl_exception : public plib::pexception + { + public: + /// \brief Constructor. + /// Allows a descriptive text to be passed to the exception + + explicit nl_exception(const pstring &text //!< text to be passed + ) + : plib::pexception(text) { } + + /// \brief Constructor. + /// Allows to use \ref plib::pfmt logic to be used in 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)...)) { } + }; + + namespace detail { + + template <typename C, typename T> + struct property_store_t + { + using value_type = T; + using key_type = const C *; + static void add(key_type obj, const value_type &aname) noexcept + { + store().insert({obj, aname}); + } + + static value_type *get(key_type obj) noexcept + { + try + { + auto ret(store().find(obj)); + if (ret == store().end()) + return nullptr; + return &ret->second; + } + catch (...) + { + plib::terminate("exception in property_store_t.get()"); + return static_cast<value_type *>(nullptr); + } + } + + static void remove(key_type obj) noexcept + { + store().erase(store().find(obj)); + } + + static std::unordered_map<key_type, value_type> &store() noexcept + { + static std::unordered_map<key_type, value_type> lstore; + return lstore; + } + + }; + + // ----------------------------------------------------------------------------- + // object_t + // ----------------------------------------------------------------------------- + + /// \brief The base class for netlist devices, terminals and parameters. + /// + /// This class serves as the base class for all device, terminal and + /// objects. + + class object_t + { + public: + + /// \brief Constructor. + /// Every class derived from the object_t class must have a name. + /// + /// \param aname string containing name of the object + + explicit object_t(const pstring &aname) + { + props::add(this, aname); + } + + PCOPYASSIGNMOVE(object_t, delete) + /// \brief return name of the object + /// + /// \returns name of the object. + + const pstring &name() const noexcept + { + return *props::get(this); + } + + protected: + + using props = property_store_t<object_t, pstring>; + + // only childs should be destructible + ~object_t() noexcept + { + props::remove(this); + } + + private: + }; + + /// \brief Base class for all objects bejng owned by a netlist + /// + /// The object provides adds \ref netlist_state_t and \ref netlist_t + /// accessors. + /// + class netlist_object_t : public object_t + { + public: + explicit netlist_object_t(netlist_t &nl, const pstring &name) + : object_t(name) + , m_netlist(nl) + { } + + ~netlist_object_t() = default; + + PCOPYASSIGNMOVE(netlist_object_t, delete) + + netlist_state_t & state() noexcept; + const netlist_state_t & state() const noexcept; + + netlist_t & exec() noexcept { return m_netlist; } + const netlist_t & exec() const noexcept { return m_netlist; } + + // to ease template design + template<typename T, typename... Args> + device_arena::unique_ptr<T> make_pool_object(Args&&... args); + + private: + netlist_t & m_netlist; + + }; + + // ----------------------------------------------------------------------------- + // device_object_t + // ----------------------------------------------------------------------------- + + /// \brief Base class for all objects being owned by a device. + /// + /// Serves as the base class of all objects being owned by a device. + /// + /// The class also supports device-less objects. In this case, + /// nullptr is passed in as the device object. + /// + + class device_object_t : public object_t + { + public: + /// \brief Constructor. + /// + /// \param dev pointer to device owning the object. + /// \param name string holding the name of the device + + device_object_t(core_device_t *dev, const pstring &name); + + /// \brief 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; } + + /// \brief The netlist owning the owner of this object. + /// \returns reference to netlist object. + + netlist_state_t &state() noexcept; + const netlist_state_t &state() const noexcept; + + netlist_t &exec() noexcept; + const netlist_t &exec() const noexcept; + + private: + core_device_t * m_device; + }; + + // ----------------------------------------------------------------------------- + // core_terminal_t + // ----------------------------------------------------------------------------- + + /// \brief Base class for all terminals. + /// + /// All terminals are derived from this class. + /// + class core_terminal_t : public device_object_t, + public plib::linkedlist_t<core_terminal_t>::element_t + { + public: + /// \brief Number of signal bits + /// + /// Going forward setting this to 8 will allow 8-bit signal + /// busses to be used in netlist, e.g. for more complex memory + /// arrangements. + /// Mimimum value is 2 here to support tristate output on proxies. + static constexpr const unsigned int INP_BITS = 2; + + static constexpr const unsigned int INP_MASK = (1 << INP_BITS) - 1; + static constexpr const unsigned int INP_HL_SHIFT = 0; + static constexpr const unsigned int INP_LH_SHIFT = INP_BITS; + + static constexpr netlist_sig_t OUT_TRISTATE() { return INP_MASK; } + + static_assert(INP_BITS * 2 <= sizeof(netlist_sig_t) * 8, "netlist_sig_t size not sufficient"); + + enum state_e { + STATE_INP_PASSIVE = 0, + STATE_INP_HL = (INP_MASK << INP_HL_SHIFT), + STATE_INP_LH = (INP_MASK << INP_LH_SHIFT), + STATE_INP_ACTIVE = STATE_INP_HL | STATE_INP_LH, + STATE_OUT = (1 << (2*INP_BITS)), + STATE_BIDIR = (1 << (2*INP_BITS + 1)) + }; + + core_terminal_t(core_device_t &dev, const pstring &aname, + state_e state, nldelegate delegate); + virtual ~core_terminal_t() noexcept = default; + + PCOPYASSIGNMOVE(core_terminal_t, delete) + + /// \brief The object type. + /// \returns type of the object + terminal_type type() const noexcept(false); + + /// \brief 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(false) { 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); } + + net_t & net() const noexcept { return *m_net;} + + bool is_logic() const noexcept; + bool is_logic_input() const noexcept; + bool is_logic_output() const noexcept; + bool is_tristate_output() const noexcept; + bool is_analog() const noexcept; + bool is_analog_input() const noexcept; + bool is_analog_output() const noexcept; + + 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; } + + void reset() noexcept { set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); } + + #if NL_USE_COPY_INSTEAD_OF_REFERENCE + void set_copied_input(netlist_sig_t val) noexcept + { + m_Q = val; + } + + state_var_sig m_Q; + #else + void set_copied_input(netlist_sig_t val) const noexcept { plib::unused_var(val); } // NOLINT: static means more message elsewhere + #endif + + void set_delegate(const nldelegate &delegate) noexcept { m_delegate = delegate; } + const nldelegate &delegate() const noexcept { return m_delegate; } + inline void run_delegate() noexcept { return m_delegate(); } + private: + nldelegate m_delegate; + net_t * m_net; + state_var<state_e> m_state; + }; + + + } // namespace detail + + // ----------------------------------------------------------------------------- + // core_device_t + // ----------------------------------------------------------------------------- + // FIXME: belongs into detail namespace + class core_device_t : public detail::netlist_object_t + { + public: + core_device_t(netlist_state_t &owner, const pstring &name); + core_device_t(core_device_t &owner, const pstring &name); + + PCOPYASSIGNMOVE(core_device_t, delete) + + virtual ~core_device_t() noexcept = default; + + void do_inc_active() noexcept + { + if (m_hint_deactivate) + { + if (++m_active_outputs == 1) + { + if (m_stats) + m_stats->m_stat_inc_active.inc(); + inc_active(); + } + } + } + + void do_dec_active() noexcept + { + if (m_hint_deactivate) + if (--m_active_outputs == 0) + { + dec_active(); + } + } + + void set_hint_deactivate(bool v) noexcept { m_hint_deactivate = v; } + bool get_hint_deactivate() const noexcept { return m_hint_deactivate; } + // Has to be set in device reset + void set_active_outputs(int n) noexcept { m_active_outputs = n; } + + // stats + struct stats_t + { + // NL_KEEP_STATISTICS + plib::pperftime_t<true> m_stat_total_time; + plib::pperfcount_t<true> m_stat_call_count; + plib::pperfcount_t<true> m_stat_inc_active; + }; + + stats_t * stats() const noexcept { return m_stats.get(); } +#if 0 + virtual void update() noexcept { } +#endif + virtual void reset() { } + + protected: + + virtual void inc_active() noexcept { } + virtual void dec_active() noexcept { } + + log_type & log(); + + public: + virtual void timestep(timestep_type ts_type, nl_fptype st) noexcept { plib::unused_var(ts_type, st); } + virtual void update_terminals() noexcept { } + + virtual void update_param() noexcept {} + virtual bool is_dynamic() const noexcept { return false; } + virtual bool is_timestep() const noexcept { return false; } + + private: + bool m_hint_deactivate; + state_var_s32 m_active_outputs; + device_arena::unique_ptr<stats_t> m_stats; + }; + +} // namespace netlist + + +#endif // NL_CORE_BASE_OBJECTS_H_ diff --git a/src/lib/netlist/core/logic_family.h b/src/lib/netlist/core/logic_family.h new file mode 100644 index 00000000000..e7e7c51081f --- /dev/null +++ b/src/lib/netlist/core/logic_family.h @@ -0,0 +1,93 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file logic_family.h +/// + +#ifndef NL_CORE_LOGIC_FAMILY_H_ +#define NL_CORE_LOGIC_FAMILY_H_ + +#include "../nltypes.h" +#include "../plib/pstring.h" + +namespace netlist +{ + /// \brief Logic families descriptors are used to create proxy devices. + /// The logic family describes the analog capabilities of logic devices, + /// inputs and outputs. + + class logic_family_desc_t + { + public: + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, modernize-use-equals-default) + logic_family_desc_t() + { + } + + PCOPYASSIGNMOVE(logic_family_desc_t, delete) + + virtual ~logic_family_desc_t() noexcept = default; + + virtual device_arena::unique_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, + const logic_output_t *proxied) const = 0; + virtual device_arena::unique_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, + const logic_input_t *proxied) const = 0; + + nl_fptype low_thresh_V(nl_fptype VN, nl_fptype VP) const noexcept{ return VN + (VP - VN) * m_low_thresh_PCNT; } + nl_fptype high_thresh_V(nl_fptype VN, nl_fptype VP) const noexcept{ return VN + (VP - VN) * m_high_thresh_PCNT; } + nl_fptype low_offset_V() const noexcept{ return m_low_VO; } + nl_fptype high_offset_V() const noexcept{ return m_high_VO; } + nl_fptype R_low() const noexcept{ return m_R_low; } + nl_fptype R_high() const noexcept{ return m_R_high; } + + bool is_above_high_thresh_V(nl_fptype V, nl_fptype VN, nl_fptype VP) const noexcept + { return V > high_thresh_V(VN, VP); } + + bool is_below_low_thresh_V(nl_fptype V, nl_fptype VN, nl_fptype VP) const noexcept + { return V < low_thresh_V(VN, VP); } + + pstring vcc_pin() const { return pstring(m_vcc); } + pstring gnd_pin() const { return pstring(m_gnd); } + + nl_fptype m_low_thresh_PCNT; //!< low input threshhold offset. If the input voltage is below this value times supply voltage, a "0" input is signalled + nl_fptype m_high_thresh_PCNT; //!< high input threshhold offset. If the input voltage is above the value times supply voltage, a "0" input is signalled + nl_fptype m_low_VO; //!< low output voltage offset. This voltage is output if the ouput is "0" + nl_fptype m_high_VO; //!< high output voltage offset. The supply voltage minus this offset is output if the ouput is "1" + nl_fptype m_R_low; //!< low output resistance. Value of series resistor used for low output + nl_fptype m_R_high; //!< high output resistance. Value of series resistor used for high output + const char *m_vcc; //!< default power pin name for positive supply + const char *m_gnd; //!< default power pin name for negative supply + }; + + /// \brief Base class for devices, terminals, outputs and inputs which support + /// logic families. + /// This class is a storage container to store the logic family for a + /// netlist object. You will not directly use it. Please refer to + /// \ref NETLIB_FAMILY to learn how to define a logic family for a device. + /// + /// All terminals inherit the family description from the device + /// The default is the ttl family, but any device can override the family. + /// For individual terminals, the family can be overwritten as well. + /// + + class logic_family_t + { + public: + logic_family_t() : m_logic_family(nullptr) {} + logic_family_t(const logic_family_desc_t *d) : m_logic_family(d) {} + PCOPYASSIGNMOVE(logic_family_t, delete) + + const logic_family_desc_t *logic_family() const noexcept { return m_logic_family; } + void set_logic_family(const logic_family_desc_t *fam) noexcept { m_logic_family = fam; } + + protected: + ~logic_family_t() noexcept = default; // prohibit polymorphic destruction + private: + const logic_family_desc_t *m_logic_family; + }; + +} // namespace netlist + + +#endif // NL_CORE_LOGIC_FAMILY_H_ diff --git a/src/lib/netlist/core/nets.h b/src/lib/netlist/core/nets.h new file mode 100644 index 00000000000..96ecdf1836f --- /dev/null +++ b/src/lib/netlist/core/nets.h @@ -0,0 +1,186 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file nets.h +/// + +#ifndef NL_CORE_NETS_H_ +#define NL_CORE_NETS_H_ + +#include "base_objects.h" +#include "state_var.h" + +#include "../nltypes.h" +#include "../plib/pstring.h" +#include "../plib/plists.h" + +namespace netlist +{ + + namespace detail { + + // ----------------------------------------------------------------------------- + // net_t + // ----------------------------------------------------------------------------- + + class net_t : public netlist_object_t + { + public: + + enum class queue_status + { + DELAYED_DUE_TO_INACTIVE = 0, + QUEUED, + DELIVERED + }; + + net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *railterminal = nullptr); + + PCOPYASSIGNMOVE(net_t, delete) + + virtual ~net_t() noexcept = default; + + virtual void reset() noexcept; + + void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); } + + void toggle_and_push_to_queue(const netlist_time &delay) noexcept + { + toggle_new_Q(); + push_to_queue(delay); + } + + void push_to_queue(const netlist_time &delay) noexcept; + NVCC_CONSTEXPR bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; } + + template <bool KEEP_STATS> + inline void update_devs() noexcept; + + netlist_time_ext next_scheduled_time() const noexcept { return m_next_scheduled_time; } + void set_next_scheduled_time(netlist_time_ext ntime) noexcept { m_next_scheduled_time = ntime; } + + NVCC_CONSTEXPR bool is_rail_net() const noexcept { return !(m_railterminal == nullptr); } + core_terminal_t & railterminal() const noexcept { return *m_railterminal; } + + bool has_connections() const noexcept { return !m_core_terms.empty(); } + + void add_to_active_list(core_terminal_t &term) noexcept; + void remove_from_active_list(core_terminal_t &term) noexcept; + + // setup stuff + + bool is_logic() const noexcept; + bool is_analog() const noexcept; + + void rebuild_list(); // rebuild m_list after a load + + std::vector<core_terminal_t *> &core_terms() noexcept { return m_core_terms; } + + void update_inputs() noexcept + { +#if NL_USE_COPY_INSTEAD_OF_REFERENCE + for (auto & term : m_core_terms) + term->m_Q = m_cur_Q; +#endif + // nothing needs to be done if define not set + } + + protected: + + // only used for logic nets + NVCC_CONSTEXPR netlist_sig_t Q() const noexcept { return m_cur_Q; } + + // only used for logic nets + void initial(netlist_sig_t val) noexcept + { + m_cur_Q = m_new_Q = val; + update_inputs(); + } + + // only used for logic nets + inline void set_Q_and_push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept + { + if (newQ != m_new_Q) + { + m_new_Q = newQ; + push_to_queue(delay); + } + } + + // only used for logic nets + inline void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) 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(); + } + else + { + m_cur_Q = newQ; + update_inputs(); + } + } + + private: + state_var<netlist_sig_t> m_new_Q; + state_var<netlist_sig_t> m_cur_Q; + state_var<queue_status> m_in_queue; + state_var<netlist_time_ext> 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 <bool KEEP_STATS, typename T, typename S> + void process(T mask, const S &sig) noexcept; + }; + } // namespace detail + + class analog_net_t : public detail::net_t + { + public: + + analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *railterminal = nullptr); + + void reset() noexcept override; + + nl_fptype Q_Analog() const noexcept { return m_cur_Analog; } + void set_Q_Analog(nl_fptype v) noexcept { m_cur_Analog = v; } + // used by solver code ... + nl_fptype *Q_Analog_state_ptr() noexcept { return &m_cur_Analog(); } + + //FIXME: needed by current solver code + solver::matrix_solver_t *solver() const noexcept { return m_solver; } + void set_solver(solver::matrix_solver_t *solver) noexcept { m_solver = solver; } + + friend constexpr bool operator==(const analog_net_t &lhs, const analog_net_t &rhs) noexcept + { + return &lhs == &rhs; + } + + private: + state_var<nl_fptype> m_cur_Analog; + solver::matrix_solver_t *m_solver; + }; + + class logic_net_t : public detail::net_t + { + public: + + logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *railterminal = nullptr); + + 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; + }; + + +} // namespace netlist + + +#endif // NL_CORE_NETS_H_ diff --git a/src/lib/netlist/core/param.h b/src/lib/netlist/core/param.h new file mode 100644 index 00000000000..80769f2d47e --- /dev/null +++ b/src/lib/netlist/core/param.h @@ -0,0 +1,275 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file param.h +/// + +#ifndef NL_CORE_PARAM_H_ +#define NL_CORE_PARAM_H_ + +#if 0 +#include "../nl_config.h" +#include "../nl_factory.h" +#include "../nl_setup.h" + +#include "../plib/ppreprocessor.h" + +#include <initializer_list> +#include <stack> +#include <unordered_map> +#include <vector> +#endif + +#include "../nltypes.h" + +#include "base_objects.h" + +#include "../plib/pstream.h" +#include "../plib/pstring.h" +#include "../plib/palloc.h" + +#include <memory> + +namespace netlist +{ + /// @brief Base class for all device parameters + /// + /// All device parameters classes derive from this object. + class param_t : public detail::device_object_t + { + public: + + enum param_type_t { + STRING, + DOUBLE, + INTEGER, + LOGIC, + POINTER // Special-case which is always initialized at MAME startup time + }; + + //deviceless, it's the responsibility of the owner to register! + param_t(const pstring &name); + + param_t(core_device_t &device, const pstring &name); + + PCOPYASSIGNMOVE(param_t, delete) + virtual ~param_t() noexcept; + + param_type_t param_type() const noexcept(false); + + virtual pstring valstr() const = 0; + + protected: + + void update_param() noexcept; + + pstring get_initial(const core_device_t *dev, bool *found) const; + + template<typename C> + void set_and_update_param(C &p, const C v) noexcept + { + if (p != v) + { + p = v; + update_param(); + } + } + + }; + + // ----------------------------------------------------------------------------- + // numeric parameter template + // ----------------------------------------------------------------------------- + + template <typename T> + class param_num_t final: public param_t + { + public: + using value_type = T; + + param_num_t(core_device_t &device, const pstring &name, T val) noexcept(false); + + T operator()() const noexcept { return m_param; } + operator T() const noexcept { return m_param; } + + void set(const T ¶m) noexcept { set_and_update_param(m_param, param); } + + pstring valstr() const override + { + return plib::pfmt("{}").e(gsl::narrow<nl_fptype>(m_param)); + } + + private: + T m_param; + }; + + template <typename T> + class param_enum_t final: public param_t + { + public: + using value_type = T; + + param_enum_t(core_device_t &device, const pstring &name, T val) noexcept(false); + + T operator()() const noexcept { return m_param; } + operator T() const noexcept { return m_param; } + void set(const T ¶m) noexcept { set_and_update_param(m_param, param); } + + pstring valstr() const override + { + // returns the numerical value + return plib::pfmt("{}")(static_cast<int>(m_param)); + } + private: + T m_param; + }; + + // FIXME: these should go as well + using param_logic_t = param_num_t<bool>; + using param_int_t = param_num_t<int>; + using param_fp_t = param_num_t<nl_fptype>; + + // ----------------------------------------------------------------------------- + // pointer parameter + // ----------------------------------------------------------------------------- + + // FIXME: not a core component -> legacy + class param_ptr_t final: public param_t + { + public: + param_ptr_t(core_device_t &device, const pstring &name, std::uint8_t* val); + std::uint8_t * operator()() const noexcept { return m_param; } + void set(std::uint8_t *param) noexcept { set_and_update_param(m_param, param); } + + pstring valstr() const override + { + // returns something which errors + return pstring("PTRERROR"); + } + + private: + std::uint8_t* m_param; + }; + + // ----------------------------------------------------------------------------- + // string parameter + // ----------------------------------------------------------------------------- + + class param_str_t : public param_t + { + public: + param_str_t(core_device_t &device, const pstring &name, const pstring &val); + param_str_t(netlist_state_t &state, const pstring &name, const pstring &val); + + pstring operator()() const noexcept { return str(); } + void set(const pstring ¶m) + { + if (*m_param != param) + { + *m_param = param; + changed(); + update_param(); + } + } + pstring valstr() const override + { + return *m_param; + } + protected: + virtual void changed() noexcept; + pstring str() const noexcept { return *m_param; } + private: + host_arena::unique_ptr<pstring> m_param; + }; + + // ----------------------------------------------------------------------------- + // model parameter + // ----------------------------------------------------------------------------- + + class param_model_t : public param_str_t + { + public: + + template <typename T> + class value_base_t + { + public: + template <typename P, typename Y=T, typename DUMMY = std::enable_if_t<plib::is_arithmetic<Y>::value>> + value_base_t(P ¶m, const pstring &name) + : m_value(gsl::narrow<T>(param.value(name))) + { + } + template <typename P, typename Y=T, std::enable_if_t<!plib::is_arithmetic<Y>::value, int> = 0> + value_base_t(P ¶m, const pstring &name) + : m_value(static_cast<T>(param.value_str(name))) + { + } + T operator()() const noexcept { return m_value; } + operator T() const noexcept { return m_value; } + private: + const T m_value; + }; + + using value_t = value_base_t<nl_fptype>; + using value_str_t = value_base_t<pstring>; + + param_model_t(core_device_t &device, const pstring &name, const pstring &val) + : param_str_t(device, name, val) + { + } + + pstring value_str(const pstring &entity); + nl_fptype value(const pstring &entity); + pstring type(); + // hide this + void set(const pstring ¶m) = delete; + protected: + void changed() noexcept override; + private: + }; + + // ----------------------------------------------------------------------------- + // data parameter + // ----------------------------------------------------------------------------- + + class param_data_t : public param_str_t + { + public: + param_data_t(core_device_t &device, const pstring &name) + : param_str_t(device, name, "") + { + } + + std::unique_ptr<std::istream> stream(); + protected: + void changed() noexcept override { } + }; + + // ----------------------------------------------------------------------------- + // rom parameter + // ----------------------------------------------------------------------------- + + template <typename ST, std::size_t AW, std::size_t DW> + class param_rom_t final: public param_data_t + { + public: + + param_rom_t(core_device_t &device, const pstring &name); + + const ST & operator[] (std::size_t n) const noexcept { return m_data[n]; } + protected: + void changed() noexcept override + { + plib::istream_read(*stream(), m_data.data(), 1<<AW); + } + + private: + std::array<ST, 1 << AW> m_data; + }; + + +} // namespace netlist + + +#endif // NL_CORE_PARAM_H_ diff --git a/src/lib/netlist/core/state_var.h b/src/lib/netlist/core/state_var.h new file mode 100644 index 00000000000..922789f584e --- /dev/null +++ b/src/lib/netlist/core/state_var.h @@ -0,0 +1,173 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file state_var.h +/// + +#ifndef NL_CORE_STATE_VAR_H_ +#define NL_CORE_STATE_VAR_H_ + +#include "../nltypes.h" +#include "../plib/pstring.h" + +namespace netlist +{ + /// \brief A persistent variable template. + /// Use the state_var template to define a variable whose value is saved. + /// Within a device definition use + /// + /// NETLIB_OBJECT(abc) + /// { + /// NETLIB_CONSTRUCTOR(abc) + /// , m_var(*this, "myvar", 0) + /// ... + /// state_var<unsigned> m_var; + /// } + template <typename T> + struct state_var + { + public: + + using value_type = T; + + template <typename O> + //! Constructor. + state_var(O &owner, //!< owner must have a netlist() method. + const pstring &name, //!< identifier/name for this state variable + const T &value //!< Initial value after construction + ); + + template <typename O> + //! Constructor. + state_var(O &owner, //!< owner must have a netlist() method. + const pstring &name //!< identifier/name for this state variable + ); + + PMOVEASSIGN(state_var, delete) + + //! Destructor. + ~state_var() noexcept = default; + + //! Copy Constructor removed. + constexpr state_var(const state_var &rhs) = delete; + //! Assignment operator to assign value of a state var. + constexpr state_var &operator=(const state_var &rhs) noexcept + { + if (this != &rhs) + m_value = rhs.m_value; + return *this; + } // OSX doesn't like noexcept + //! Assignment operator to assign value of type T. + constexpr state_var &operator=(const T &rhs) noexcept { m_value = rhs; return *this; } + //! Assignment move operator to assign value of type T. + constexpr state_var &operator=(T &&rhs) noexcept { std::swap(m_value, rhs); return *this; } + //! Return non-const value of state variable. + constexpr operator T & () noexcept { return m_value; } + //! Return const value of state variable. + constexpr operator const T & () const noexcept { return m_value; } + //! Return non-const value of state variable. + constexpr T & var() noexcept { return m_value; } + //! Return const value of state variable. + constexpr const T & var() const noexcept { return m_value; } + //! Return non-const value of state variable. + constexpr T & operator ()() noexcept { return m_value; } + //! Return const value of state variable. + constexpr const T & operator ()() const noexcept { return m_value; } + //! Access state variable by ->. + constexpr T * operator->() noexcept { return &m_value; } + //! Access state variable by const ->. + constexpr const T * operator->() const noexcept{ return &m_value; } + + private: + T m_value; + }; + + /// \brief A persistent array template. + /// Use this state_var template to define an array whose contents are saved. + /// Please refer to \ref state_var. + /// + /// \tparam C container class to use. + + template <typename C> + struct state_container : public C + { + public: + using value_type = typename C::value_type; + //! Constructor. + template <typename O> + state_container(O &owner, //!< owner must have a netlist() method. + const pstring &name, //!< identifier/name for this state variable + const value_type &value //!< Initial value after construction + ); + //! Constructor. + template <typename O> + state_container(O &owner, //!< owner must have a netlist() method. + const pstring &name, //!< identifier/name for this state variable + std::size_t n, //!< number of elements to allocate + const value_type &value //!< Initial value after construction + ); + //! Copy Constructor. + state_container(const state_container &rhs) noexcept = default; + //! Destructor. + ~state_container() noexcept = default; + //! Move Constructor. + state_container(state_container &&rhs) noexcept = default; + state_container &operator=(const state_container &rhs) noexcept = default; + state_container &operator=(state_container &&rhs) noexcept = default; + }; + + // ----------------------------------------------------------------------------- + // State variables - predefined and c++11 non-optional + // ----------------------------------------------------------------------------- + + /// \brief predefined state variable type for uint8_t + using state_var_u8 = state_var<std::uint8_t>; + /// \brief predefined state variable type for int8_t + using state_var_s8 = state_var<std::int8_t>; + + /// \brief predefined state variable type for uint32_t + using state_var_u32 = state_var<std::uint32_t>; + /// \brief predefined state variable type for int32_t + using state_var_s32 = state_var<std::int32_t>; + /// \brief predefined state variable type for sig_t + using state_var_sig = state_var<netlist_sig_t>; + + template <typename T> + template <typename O> + state_var<T>::state_var(O &owner, const pstring &name, const T &value) + : m_value(value) + { + owner.state().save(owner, m_value, owner.name(), name); + } + + template <typename T> + template <typename O> + state_var<T>::state_var(O &owner, const pstring &name) + { + owner.state().save(owner, m_value, owner.name(), name); + } + + template <typename C> + template <typename O> + state_container<C>::state_container(O &owner, const pstring &name, + const state_container<C>::value_type & value) + { + owner.state().save(owner, static_cast<C &>(*this), owner.name(), name); + for (std::size_t i=0; i < this->size(); i++) + (*this)[i] = value; + } + + template <typename C> + template <typename O> + state_container<C>::state_container(O &owner, const pstring &name, + std::size_t n, const state_container<C>::value_type & value) + : C(n, value) + { + owner.state().save(owner, static_cast<C &>(*this), owner.name(), name); + } + +} // namespace netlist + + +#endif // NL_CORE_STATE_VAR_H_ diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp index 78b5a3af923..a1477b6dce4 100644 --- a/src/lib/netlist/devices/nld_system.cpp +++ b/src/lib/netlist/devices/nld_system.cpp @@ -13,12 +13,10 @@ namespace netlist { namespace devices { - // ---------------------------------------------------------------------------------------- - // netlistparams - // ---------------------------------------------------------------------------------------- - + NETLIB_DEVICE_IMPL(netlistparams, "PARAMETER", "") NETLIB_DEVICE_IMPL(nc_pin, "NC_PIN", "") + NETLIB_DEVICE_IMPL(frontier, "FRONTIER_DEV", "+I,+G,+Q") NETLIB_DEVICE_IMPL(function, "AFUNC", "N,FUNC") NETLIB_DEVICE_IMPL(analog_input, "ANALOG_INPUT", "IN") @@ -39,7 +37,6 @@ namespace devices NETLIB_DEVICE_IMPL(mainclock, "MAINCLOCK", "FREQ") NETLIB_DEVICE_IMPL(gnd, "GNDA", "") - NETLIB_DEVICE_IMPL(netlistparams, "PARAMETER", "") using NETLIB_NAME(logic_input8) = NETLIB_NAME(logic_inputN)<8>; NETLIB_DEVICE_IMPL(logic_input8, "LOGIC_INPUT8", "IN,MODEL") diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 61265e9cb65..22baf636461 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -12,7 +12,7 @@ #include "core/setup.h" #include "devices/nlid_proxy.h" -#include "devices/nlid_system.h" +#include "devices/nlid_system.h" // netlist_params #include "macro/nlm_base.h" #include "nl_base.h" diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 66caae7519c..45b64c5e122 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -12,6 +12,12 @@ #error "nl_base.h included. Please correct." #endif +#include "core/base_objects.h" +#include "core/param.h" +#include "core/state_var.h" +#include "core/logic_family.h" +#include "core/nets.h" + #include "plib/palloc.h" // owned_ptr #include "plib/pfunction.h" #include "plib/plists.h" @@ -203,614 +209,7 @@ class NETLIB_NAME(name) : public delegator_t<base_device_t> namespace netlist { - enum class timestep_type - { - FORWARD, ///< forward time - RESTORE ///< restore state before last forward - }; - - /// \brief Delegate type for device notification. - /// - using nldelegate = plib::pmfp<void>; - using nldelegate_ts = plib::pmfp<void, timestep_type, nl_fptype>; - using nldelegate_dyn = plib::pmfp<void>; - - //============================================================ - // Exceptions - //============================================================ - - /// \brief Generic netlist exception. - /// The exception is used in all events which are considered fatal. - - class nl_exception : public plib::pexception - { - public: - /// \brief Constructor. - /// Allows a descriptive text to be passed to the exception - - explicit nl_exception(const pstring &text //!< text to be passed - ) - : plib::pexception(text) { } - - /// \brief Constructor. - /// Allows to use \ref plib::pfmt logic to be used in 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)...)) { } - }; - - /// \brief Logic families descriptors are used to create proxy devices. - /// The logic family describes the analog capabilities of logic devices, - /// inputs and outputs. - - class logic_family_desc_t - { - public: - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, modernize-use-equals-default) - logic_family_desc_t() - { - } - - - PCOPYASSIGNMOVE(logic_family_desc_t, delete) - - virtual ~logic_family_desc_t() noexcept = default; - - virtual device_arena::unique_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, - const logic_output_t *proxied) const = 0; - virtual device_arena::unique_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, - const logic_input_t *proxied) const = 0; - - nl_fptype low_thresh_V(nl_fptype VN, nl_fptype VP) const noexcept{ return VN + (VP - VN) * m_low_thresh_PCNT; } - nl_fptype high_thresh_V(nl_fptype VN, nl_fptype VP) const noexcept{ return VN + (VP - VN) * m_high_thresh_PCNT; } - nl_fptype low_offset_V() const noexcept{ return m_low_VO; } - nl_fptype high_offset_V() const noexcept{ return m_high_VO; } - nl_fptype R_low() const noexcept{ return m_R_low; } - nl_fptype R_high() const noexcept{ return m_R_high; } - - bool is_above_high_thresh_V(nl_fptype V, nl_fptype VN, nl_fptype VP) const noexcept - { return V > high_thresh_V(VN, VP); } - - bool is_below_low_thresh_V(nl_fptype V, nl_fptype VN, nl_fptype VP) const noexcept - { return V < low_thresh_V(VN, VP); } - - pstring vcc_pin() const { return pstring(m_vcc); } - pstring gnd_pin() const { return pstring(m_gnd); } - - nl_fptype m_low_thresh_PCNT; //!< low input threshhold offset. If the input voltage is below this value times supply voltage, a "0" input is signalled - nl_fptype m_high_thresh_PCNT; //!< high input threshhold offset. If the input voltage is above the value times supply voltage, a "0" input is signalled - nl_fptype m_low_VO; //!< low output voltage offset. This voltage is output if the ouput is "0" - nl_fptype m_high_VO; //!< high output voltage offset. The supply voltage minus this offset is output if the ouput is "1" - nl_fptype m_R_low; //!< low output resistance. Value of series resistor used for low output - nl_fptype m_R_high; //!< high output resistance. Value of series resistor used for high output - const char *m_vcc; //!< default power pin name for positive supply - const char *m_gnd; //!< default power pin name for negative supply - }; - - /// \brief Base class for devices, terminals, outputs and inputs which support - /// logic families. - /// This class is a storage container to store the logic family for a - /// netlist object. You will not directly use it. Please refer to - /// \ref NETLIB_FAMILY to learn how to define a logic family for a device. - /// - /// All terminals inherit the family description from the device - /// The default is the ttl family, but any device can override the family. - /// For individual terminals, the family can be overwritten as well. - /// - - class logic_family_t - { - public: - logic_family_t() : m_logic_family(nullptr) {} - logic_family_t(const logic_family_desc_t *d) : m_logic_family(d) {} - PCOPYASSIGNMOVE(logic_family_t, delete) - - const logic_family_desc_t *logic_family() const noexcept { return m_logic_family; } - void set_logic_family(const logic_family_desc_t *fam) noexcept { m_logic_family = fam; } - - protected: - ~logic_family_t() noexcept = default; // prohibit polymorphic destruction - private: - const logic_family_desc_t *m_logic_family; - }; - - /// \brief A persistent variable template. - /// Use the state_var template to define a variable whose value is saved. - /// Within a device definition use - /// - /// NETLIB_OBJECT(abc) - /// { - /// NETLIB_CONSTRUCTOR(abc) - /// , m_var(*this, "myvar", 0) - /// ... - /// state_var<unsigned> m_var; - /// } - template <typename T> - struct state_var - { - public: - - using value_type = T; - - template <typename O> - //! Constructor. - state_var(O &owner, //!< owner must have a netlist() method. - const pstring &name, //!< identifier/name for this state variable - const T &value //!< Initial value after construction - ); - - template <typename O> - //! Constructor. - state_var(O &owner, //!< owner must have a netlist() method. - const pstring &name //!< identifier/name for this state variable - ); - - PMOVEASSIGN(state_var, delete) - - //! Destructor. - ~state_var() noexcept = default; - - //! Copy Constructor removed. - constexpr state_var(const state_var &rhs) = delete; - //! Assignment operator to assign value of a state var. - constexpr state_var &operator=(const state_var &rhs) noexcept - { - if (this != &rhs) - m_value = rhs.m_value; - return *this; - } // OSX doesn't like noexcept - //! Assignment operator to assign value of type T. - constexpr state_var &operator=(const T &rhs) noexcept { m_value = rhs; return *this; } - //! Assignment move operator to assign value of type T. - constexpr state_var &operator=(T &&rhs) noexcept { std::swap(m_value, rhs); return *this; } - //! Return non-const value of state variable. - constexpr operator T & () noexcept { return m_value; } - //! Return const value of state variable. - constexpr operator const T & () const noexcept { return m_value; } - //! Return non-const value of state variable. - constexpr T & var() noexcept { return m_value; } - //! Return const value of state variable. - constexpr const T & var() const noexcept { return m_value; } - //! Return non-const value of state variable. - constexpr T & operator ()() noexcept { return m_value; } - //! Return const value of state variable. - constexpr const T & operator ()() const noexcept { return m_value; } - //! Access state variable by ->. - constexpr T * operator->() noexcept { return &m_value; } - //! Access state variable by const ->. - constexpr const T * operator->() const noexcept{ return &m_value; } - - private: - T m_value; - }; - - /// \brief A persistent array template. - /// Use this state_var template to define an array whose contents are saved. - /// Please refer to \ref state_var. - /// - /// \tparam C container class to use. - - template <typename C> - struct state_container : public C - { - public: - using value_type = typename C::value_type; - //! Constructor. - template <typename O> - state_container(O &owner, //!< owner must have a netlist() method. - const pstring &name, //!< identifier/name for this state variable - const value_type &value //!< Initial value after construction - ); - //! Constructor. - template <typename O> - state_container(O &owner, //!< owner must have a netlist() method. - const pstring &name, //!< identifier/name for this state variable - std::size_t n, //!< number of elements to allocate - const value_type &value //!< Initial value after construction - ); - //! Copy Constructor. - state_container(const state_container &rhs) noexcept = default; - //! Destructor. - ~state_container() noexcept = default; - //! Move Constructor. - state_container(state_container &&rhs) noexcept = default; - state_container &operator=(const state_container &rhs) noexcept = default; - state_container &operator=(state_container &&rhs) noexcept = default; - }; - - // ----------------------------------------------------------------------------- - // State variables - predefined and c++11 non-optional - // ----------------------------------------------------------------------------- - - /// \brief predefined state variable type for uint8_t - using state_var_u8 = state_var<std::uint8_t>; - /// \brief predefined state variable type for int8_t - using state_var_s8 = state_var<std::int8_t>; - - /// \brief predefined state variable type for uint32_t - using state_var_u32 = state_var<std::uint32_t>; - /// \brief predefined state variable type for int32_t - using state_var_s32 = state_var<std::int32_t>; - /// \brief predefined state variable type for sig_t - using state_var_sig = state_var<netlist_sig_t>; - - namespace detail { - - template <typename C, typename T> - struct property_store_t - { - using value_type = T; - using key_type = const C *; - static void add(key_type obj, const value_type &aname) noexcept - { - store().insert({obj, aname}); - } - - static value_type *get(key_type obj) noexcept - { - try - { - auto ret(store().find(obj)); - if (ret == store().end()) - return nullptr; - return &ret->second; - } - catch (...) - { - plib::terminate("exception in property_store_t.get()"); - return static_cast<value_type *>(nullptr); - } - } - - static void remove(key_type obj) noexcept - { - store().erase(store().find(obj)); - } - - static std::unordered_map<key_type, value_type> &store() noexcept - { - static std::unordered_map<key_type, value_type> lstore; - return lstore; - } - - }; - - // ----------------------------------------------------------------------------- - // object_t - // ----------------------------------------------------------------------------- - - /// \brief The base class for netlist devices, terminals and parameters. - /// - /// This class serves as the base class for all device, terminal and - /// objects. - - class object_t - { - public: - - /// \brief Constructor. - /// Every class derived from the object_t class must have a name. - /// - /// \param aname string containing name of the object - - explicit object_t(const pstring &aname) - { - props::add(this, aname); - } - - PCOPYASSIGNMOVE(object_t, delete) - /// \brief return name of the object - /// - /// \returns name of the object. - - const pstring &name() const noexcept - { - return *props::get(this); - } - - protected: - - using props = property_store_t<object_t, pstring>; - - // only childs should be destructible - ~object_t() noexcept - { - props::remove(this); - } - - private: - }; - - /// \brief Base class for all objects bejng owned by a netlist - /// - /// The object provides adds \ref netlist_state_t and \ref netlist_t - /// accessors. - /// - class netlist_object_t : public object_t - { - public: - explicit netlist_object_t(netlist_t &nl, const pstring &name) - : object_t(name) - , m_netlist(nl) - { } - - ~netlist_object_t() = default; - - PCOPYASSIGNMOVE(netlist_object_t, delete) - - netlist_state_t & state() noexcept; - const netlist_state_t & state() const noexcept; - - netlist_t & exec() noexcept { return m_netlist; } - const netlist_t & exec() const noexcept { return m_netlist; } - - // to ease template design - template<typename T, typename... Args> - device_arena::unique_ptr<T> make_pool_object(Args&&... args); - - private: - netlist_t & m_netlist; - - }; - - // ----------------------------------------------------------------------------- - // device_object_t - // ----------------------------------------------------------------------------- - - /// \brief Base class for all objects being owned by a device. - /// - /// Serves as the base class of all objects being owned by a device. - /// - /// The class also supports device-less objects. In this case, - /// nullptr is passed in as the device object. - /// - - class device_object_t : public object_t - { - public: - /// \brief Constructor. - /// - /// \param dev pointer to device owning the object. - /// \param name string holding the name of the device - - device_object_t(core_device_t *dev, const pstring &name); - - /// \brief 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; } - - /// \brief The netlist owning the owner of this object. - /// \returns reference to netlist object. - - netlist_state_t &state() noexcept; - const netlist_state_t &state() const noexcept; - - netlist_t &exec() noexcept; - const netlist_t &exec() const noexcept; - - private: - core_device_t * m_device; - }; - - // ----------------------------------------------------------------------------- - // core_terminal_t - // ----------------------------------------------------------------------------- - - /// \brief Base class for all terminals. - /// - /// All terminals are derived from this class. - /// - class core_terminal_t : public device_object_t, - public plib::linkedlist_t<core_terminal_t>::element_t - { - public: - /// \brief Number of signal bits - /// - /// Going forward setting this to 8 will allow 8-bit signal - /// busses to be used in netlist, e.g. for more complex memory - /// arrangements. - /// Mimimum value is 2 here to support tristate output on proxies. - static constexpr const unsigned int INP_BITS = 2; - - static constexpr const unsigned int INP_MASK = (1 << INP_BITS) - 1; - static constexpr const unsigned int INP_HL_SHIFT = 0; - static constexpr const unsigned int INP_LH_SHIFT = INP_BITS; - - static constexpr netlist_sig_t OUT_TRISTATE() { return INP_MASK; } - - static_assert(INP_BITS * 2 <= sizeof(netlist_sig_t) * 8, "netlist_sig_t size not sufficient"); - - enum state_e { - STATE_INP_PASSIVE = 0, - STATE_INP_HL = (INP_MASK << INP_HL_SHIFT), - STATE_INP_LH = (INP_MASK << INP_LH_SHIFT), - STATE_INP_ACTIVE = STATE_INP_HL | STATE_INP_LH, - STATE_OUT = (1 << (2*INP_BITS)), - STATE_BIDIR = (1 << (2*INP_BITS + 1)) - }; - - core_terminal_t(core_device_t &dev, const pstring &aname, - state_e state, nldelegate delegate); - virtual ~core_terminal_t() noexcept = default; - - PCOPYASSIGNMOVE(core_terminal_t, delete) - - /// \brief The object type. - /// \returns type of the object - terminal_type type() const noexcept(false); - - /// \brief 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(false) { 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); } - - net_t & net() const noexcept { return *m_net;} - - bool is_logic() const noexcept; - bool is_logic_input() const noexcept; - bool is_logic_output() const noexcept; - bool is_tristate_output() const noexcept; - bool is_analog() const noexcept; - bool is_analog_input() const noexcept; - bool is_analog_output() const noexcept; - - 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; } - - void reset() noexcept { set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); } - - #if NL_USE_COPY_INSTEAD_OF_REFERENCE - void set_copied_input(netlist_sig_t val) noexcept - { - m_Q = val; - } - - state_var_sig m_Q; - #else - void set_copied_input(netlist_sig_t val) const noexcept { plib::unused_var(val); } // NOLINT: static means more message elsewhere - #endif - - void set_delegate(const nldelegate &delegate) noexcept { m_delegate = delegate; } - const nldelegate &delegate() const noexcept { return m_delegate; } - inline void run_delegate() noexcept { return m_delegate(); } - private: - nldelegate m_delegate; - net_t * m_net; - state_var<state_e> m_state; - }; - - // ----------------------------------------------------------------------------- - // net_t - // ----------------------------------------------------------------------------- - - class net_t : public netlist_object_t - { - public: - - enum class queue_status - { - DELAYED_DUE_TO_INACTIVE = 0, - QUEUED, - DELIVERED - }; - - net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *railterminal = nullptr); - - PCOPYASSIGNMOVE(net_t, delete) - - virtual ~net_t() noexcept = default; - - virtual void reset() noexcept; - - void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); } - - void toggle_and_push_to_queue(const netlist_time &delay) noexcept - { - toggle_new_Q(); - push_to_queue(delay); - } - - void push_to_queue(const netlist_time &delay) noexcept; - NVCC_CONSTEXPR bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; } - - template <bool KEEP_STATS> - inline void update_devs() noexcept; - - netlist_time_ext next_scheduled_time() const noexcept { return m_next_scheduled_time; } - void set_next_scheduled_time(netlist_time_ext ntime) noexcept { m_next_scheduled_time = ntime; } - - NVCC_CONSTEXPR bool is_rail_net() const noexcept { return !(m_railterminal == nullptr); } - core_terminal_t & railterminal() const noexcept { return *m_railterminal; } - - bool has_connections() const noexcept { return !m_core_terms.empty(); } - - void add_to_active_list(core_terminal_t &term) noexcept; - void remove_from_active_list(core_terminal_t &term) noexcept; - - // setup stuff - - bool is_logic() const noexcept; - bool is_analog() const noexcept; - - void rebuild_list(); // rebuild m_list after a load - - std::vector<core_terminal_t *> &core_terms() noexcept { return m_core_terms; } - - void update_inputs() noexcept - { -#if NL_USE_COPY_INSTEAD_OF_REFERENCE - for (auto & term : m_core_terms) - term->m_Q = m_cur_Q; -#endif - // nothing needs to be done if define not set - } - - protected: - - // only used for logic nets - NVCC_CONSTEXPR netlist_sig_t Q() const noexcept { return m_cur_Q; } - - // only used for logic nets - void initial(netlist_sig_t val) noexcept - { - m_cur_Q = m_new_Q = val; - update_inputs(); - } - - // only used for logic nets - inline void set_Q_and_push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept - { - if (newQ != m_new_Q) - { - m_new_Q = newQ; - push_to_queue(delay); - } - } - - // only used for logic nets - inline void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) 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(); - } - else - { - m_cur_Q = newQ; - update_inputs(); - } - } - - // internal state support - // FIXME: get rid of this and implement export/import in MAME - private: - state_var<netlist_sig_t> m_new_Q; - state_var<netlist_sig_t> m_cur_Q; - state_var<queue_status> m_in_queue; - state_var<netlist_time_ext> 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 <bool KEEP_STATS, typename T, typename S> - void process(T mask, const S &sig) noexcept; - }; - } // namespace detail // ----------------------------------------------------------------------------- // analog_t @@ -944,45 +343,6 @@ namespace netlist nl_fptype Q_Analog() const noexcept; }; - class logic_net_t : public detail::net_t - { - public: - - logic_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *railterminal = nullptr); - - 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; - }; - - class analog_net_t : public detail::net_t - { - public: - - analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *railterminal = nullptr); - - void reset() noexcept override; - - nl_fptype Q_Analog() const noexcept { return m_cur_Analog; } - void set_Q_Analog(nl_fptype v) noexcept { m_cur_Analog = v; } - // used by solver code ... - nl_fptype *Q_Analog_state_ptr() noexcept { return &m_cur_Analog(); } - - //FIXME: needed by current solver code - solver::matrix_solver_t *solver() const noexcept { return m_solver; } - void set_solver(solver::matrix_solver_t *solver) noexcept { m_solver = solver; } - - friend constexpr bool operator==(const analog_net_t &lhs, const analog_net_t &rhs) noexcept - { - return &lhs == &rhs; - } - - private: - state_var<nl_fptype> m_cur_Analog; - solver::matrix_solver_t *m_solver; - }; - // ----------------------------------------------------------------------------- // logic_output_t // ----------------------------------------------------------------------------- @@ -1108,318 +468,6 @@ namespace netlist analog_net_t m_my_net; }; - /// @brief Base class for all device parameters - /// - /// All device parameters classes derive from this object. - class param_t : public detail::device_object_t - { - public: - - enum param_type_t { - STRING, - DOUBLE, - INTEGER, - LOGIC, - POINTER // Special-case which is always initialized at MAME startup time - }; - - //deviceless, it's the responsibility of the owner to register! - param_t(const pstring &name); - - param_t(core_device_t &device, const pstring &name); - - PCOPYASSIGNMOVE(param_t, delete) - virtual ~param_t() noexcept; - - param_type_t param_type() const noexcept(false); - - virtual pstring valstr() const = 0; - - protected: - - void update_param() noexcept; - - pstring get_initial(const core_device_t *dev, bool *found) const; - - template<typename C> - void set_and_update_param(C &p, const C v) noexcept - { - if (p != v) - { - p = v; - update_param(); - } - } - - }; - - // ----------------------------------------------------------------------------- - // numeric parameter template - // ----------------------------------------------------------------------------- - - template <typename T> - class param_num_t final: public param_t - { - public: - using value_type = T; - - param_num_t(core_device_t &device, const pstring &name, T val) noexcept(false); - - T operator()() const noexcept { return m_param; } - operator T() const noexcept { return m_param; } - - void set(const T ¶m) noexcept { set_and_update_param(m_param, param); } - - pstring valstr() const override - { - return plib::pfmt("{}").e(gsl::narrow<nl_fptype>(m_param)); - } - - private: - T m_param; - }; - - template <typename T> - class param_enum_t final: public param_t - { - public: - using value_type = T; - - param_enum_t(core_device_t &device, const pstring &name, T val) noexcept(false); - - T operator()() const noexcept { return T(m_param); } - operator T() const noexcept { return T(m_param); } - void set(const T ¶m) noexcept { set_and_update_param(m_param, static_cast<int>(param)); } - - pstring valstr() const override - { - // returns the numerical value - return plib::pfmt("{}")(m_param); - } - private: - int m_param; - }; - - // FIXME: these should go as well - using param_logic_t = param_num_t<bool>; - using param_int_t = param_num_t<int>; - using param_fp_t = param_num_t<nl_fptype>; - - // ----------------------------------------------------------------------------- - // pointer parameter - // ----------------------------------------------------------------------------- - - // FIXME: not a core component -> legacy - class param_ptr_t final: public param_t - { - public: - param_ptr_t(core_device_t &device, const pstring &name, std::uint8_t* val); - std::uint8_t * operator()() const noexcept { return m_param; } - void set(std::uint8_t *param) noexcept { set_and_update_param(m_param, param); } - - pstring valstr() const override - { - // returns something which errors - return pstring("PTRERROR"); - } - - private: - std::uint8_t* m_param; - }; - - // ----------------------------------------------------------------------------- - // string parameter - // ----------------------------------------------------------------------------- - - class param_str_t : public param_t - { - public: - param_str_t(core_device_t &device, const pstring &name, const pstring &val); - param_str_t(netlist_state_t &state, const pstring &name, const pstring &val); - - pstring operator()() const noexcept { return str(); } - void set(const pstring ¶m) - { - if (*m_param != param) - { - *m_param = param; - changed(); - update_param(); - } - } - pstring valstr() const override - { - return *m_param; - } - protected: - virtual void changed() noexcept; - pstring str() const noexcept { return *m_param; } - private: - host_arena::unique_ptr<pstring> m_param; - }; - - // ----------------------------------------------------------------------------- - // model parameter - // ----------------------------------------------------------------------------- - - class param_model_t : public param_str_t - { - public: - - template <typename T> - class value_base_t - { - public: - template <typename P, typename Y=T, typename DUMMY = std::enable_if_t<plib::is_arithmetic<Y>::value>> - value_base_t(P ¶m, const pstring &name) - : m_value(gsl::narrow<T>(param.value(name))) - { - } - template <typename P, typename Y=T, std::enable_if_t<!plib::is_arithmetic<Y>::value, int> = 0> - value_base_t(P ¶m, const pstring &name) - : m_value(static_cast<T>(param.value_str(name))) - { - } - T operator()() const noexcept { return m_value; } - operator T() const noexcept { return m_value; } - private: - const T m_value; - }; - - using value_t = value_base_t<nl_fptype>; - using value_str_t = value_base_t<pstring>; - - param_model_t(core_device_t &device, const pstring &name, const pstring &val) - : param_str_t(device, name, val) - { - } - - pstring value_str(const pstring &entity); - nl_fptype value(const pstring &entity); - pstring type(); - // hide this - void set(const pstring ¶m) = delete; - protected: - void changed() noexcept override; - private: - }; - - // ----------------------------------------------------------------------------- - // data parameter - // ----------------------------------------------------------------------------- - - class param_data_t : public param_str_t - { - public: - param_data_t(core_device_t &device, const pstring &name) - : param_str_t(device, name, "") - { - } - - std::unique_ptr<std::istream> stream(); - protected: - void changed() noexcept override { } - }; - - // ----------------------------------------------------------------------------- - // rom parameter - // ----------------------------------------------------------------------------- - - template <typename ST, std::size_t AW, std::size_t DW> - class param_rom_t final: public param_data_t - { - public: - - param_rom_t(core_device_t &device, const pstring &name); - - const ST & operator[] (std::size_t n) const noexcept { return m_data[n]; } - protected: - void changed() noexcept override - { - plib::istream_read(*stream(), m_data.data(), 1<<AW); - } - - private: - std::array<ST, 1 << AW> m_data; - }; - - - // ----------------------------------------------------------------------------- - // core_device_t - // ----------------------------------------------------------------------------- - - class core_device_t : public detail::netlist_object_t - { - public: - core_device_t(netlist_state_t &owner, const pstring &name); - core_device_t(core_device_t &owner, const pstring &name); - - PCOPYASSIGNMOVE(core_device_t, delete) - - virtual ~core_device_t() noexcept = default; - - void do_inc_active() noexcept - { - if (m_hint_deactivate) - { - if (++m_active_outputs == 1) - { - if (m_stats) - m_stats->m_stat_inc_active.inc(); - inc_active(); - } - } - } - - void do_dec_active() noexcept - { - if (m_hint_deactivate) - if (--m_active_outputs == 0) - { - dec_active(); - } - } - - void set_hint_deactivate(bool v) noexcept { m_hint_deactivate = v; } - bool get_hint_deactivate() const noexcept { return m_hint_deactivate; } - // Has to be set in device reset - void set_active_outputs(int n) noexcept { m_active_outputs = n; } - - // stats - struct stats_t - { - // NL_KEEP_STATISTICS - plib::pperftime_t<true> m_stat_total_time; - plib::pperfcount_t<true> m_stat_call_count; - plib::pperfcount_t<true> m_stat_inc_active; - }; - - stats_t * stats() const noexcept { return m_stats.get(); } -#if 0 - virtual void update() noexcept { } -#endif - virtual void reset() { } - - protected: - - virtual void inc_active() noexcept { } - virtual void dec_active() noexcept { } - - log_type & log(); - - public: - virtual void timestep(timestep_type ts_type, nl_fptype st) noexcept { plib::unused_var(ts_type, st); } - virtual void update_terminals() noexcept { } - - virtual void update_param() noexcept {} - virtual bool is_dynamic() const noexcept { return false; } - virtual bool is_timestep() const noexcept { return false; } - - private: - bool m_hint_deactivate; - state_var_s32 m_active_outputs; - device_arena::unique_ptr<stats_t> m_stats; - }; // ----------------------------------------------------------------------------- // base_device_t @@ -2556,39 +1604,6 @@ namespace netlist return (this->has_net() ? net().solver() : nullptr); } - template <typename T> - template <typename O> - state_var<T>::state_var(O &owner, const pstring &name, const T &value) - : m_value(value) - { - owner.state().save(owner, m_value, owner.name(), name); - } - - template <typename T> - template <typename O> - state_var<T>::state_var(O &owner, const pstring &name) - { - owner.state().save(owner, m_value, owner.name(), name); - } - - template <typename C> - template <typename O> - state_container<C>::state_container(O &owner, const pstring &name, - const state_container<C>::value_type & value) - { - owner.state().save(owner, static_cast<C &>(*this), owner.name(), name); - for (std::size_t i=0; i < this->size(); i++) - (*this)[i] = value; - } - - template <typename C> - template <typename O> - state_container<C>::state_container(O &owner, const pstring &name, - std::size_t n, const state_container<C>::value_type & value) - : C(n, value) - { - owner.state().save(owner, static_cast<C &>(*this), owner.name(), name); - } extern template struct state_var<std::uint8_t>; extern template struct state_var<std::uint16_t>; diff --git a/src/lib/netlist/nltypes.h b/src/lib/netlist/nltypes.h index 1ed6f66ca0d..be1de61aa44 100644 --- a/src/lib/netlist/nltypes.h +++ b/src/lib/netlist/nltypes.h @@ -14,10 +14,11 @@ #include "nl_config.h" -//#include "plib/pchrono.h" #include "plib/pstring.h" #include "plib/ptime.h" #include "plib/ptypes.h" +#include "plib/ppmf.h" +#include "plib/pmempool.h" #include <memory> @@ -80,6 +81,7 @@ namespace netlist struct abstract_t; class core_terminal_t; class net_t; + class device_object_t; } // namespace detail namespace factory @@ -196,6 +198,22 @@ namespace netlist // Types needed by various includes //============================================================ + /// \brief Timestep type. + /// + /// May be either FORWARD or RESTORE + /// + enum class timestep_type + { + FORWARD, ///< forward time + RESTORE ///< restore state before last forward + }; + + /// \brief Delegate type for device notification. + /// + using nldelegate = plib::pmfp<void>; + using nldelegate_ts = plib::pmfp<void, timestep_type, nl_fptype>; + using nldelegate_dyn = plib::pmfp<void>; + namespace detail { /// \brief Enum specifying the type of object diff --git a/src/lib/netlist/plib/penum.h b/src/lib/netlist/plib/penum.h index 55c0669afb5..8ea6f42a182 100644 --- a/src/lib/netlist/plib/penum.h +++ b/src/lib/netlist/plib/penum.h @@ -43,6 +43,7 @@ namespace plib pstring name() const { \ return nthstr(m_v, strings()); \ } \ + template <typename S> void save_state(S &saver) { saver.save_item(m_v, "m_v"); } \ private: E m_v; \ static pstring strings() {\ static const char * lstrings = # __VA_ARGS__; \ diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp index 871eff3dca3..1d25576a0d4 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.cpp +++ b/src/lib/netlist/solver/nld_matrix_solver.cpp @@ -42,7 +42,6 @@ namespace solver const net_list_t &nets, const solver_parameters_t *params) : device_t(static_cast<device_t &>(main_solver), name) - , m_next_exec(*this, "m_next_exec", netlist_time_ext::zero()) , m_params(*params) , m_iterative_fail(*this, "m_iterative_fail", 0) , m_iterative_total(*this, "m_iterative_total", 0) diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h index feb7d6bbd42..bfc105aa1cc 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.h +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -271,8 +271,6 @@ namespace solver // return number of floating point operations for solve constexpr std::size_t ops() const { return m_ops; } - state_var<netlist_time_ext> m_next_exec; - std::size_t id = 0; // FIXME - testing protected: matrix_solver_t(devices::nld_solver &main_solver, const pstring &name, const net_list_t &nets, |