diff options
27 files changed, 1278 insertions, 1008 deletions
diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile index e46e1ac4c26..0763c938b8a 100644 --- a/src/lib/netlist/build/makefile +++ b/src/lib/netlist/build/makefile @@ -53,7 +53,7 @@ TIDY_SOURCES = $(SOURCES) #TIDY_SOURCES = $(SRC)/devices/nld_7442.cpp $(SRC)/devices/nld_7492.cpp -#TIDY_FLAGS = -p $(OBJ) -checks=llvm-include-order,llvm-namespace-comment,modernize-use-override,modernize-use-using -fix +TIDY_FLAGS = -p $(OBJ) -checks=llvm-include-order,llvm-namespace-comment,modernize-use-override,modernize-use-using -fix #TIDY_FLAGS = -checks=llvm-include-order -fix #TIDY_FLAGS = -checks=llvm-namespace-comment -fix #TIDY_FLAGS = -checks=modernize-use-override -fix diff --git a/src/lib/netlist/core/analog.h b/src/lib/netlist/core/analog.h new file mode 100644 index 00000000000..a868443b8d2 --- /dev/null +++ b/src/lib/netlist/core/analog.h @@ -0,0 +1,162 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file param.h +/// + +#ifndef NL_CORE_ANALOG_H_ +#define NL_CORE_ANALOG_H_ + +#include "../nltypes.h" +#include "base_objects.h" +#include "nets.h" + +#include "../plib/plists.h" +#include "../plib/pstring.h" + +#include <array> +#include <utility> + +namespace netlist +{ + // ----------------------------------------------------------------------------- + // analog_t + // ----------------------------------------------------------------------------- + + class analog_t : public detail::core_terminal_t + { + public: + + analog_t(core_device_t &dev, const pstring &aname, state_e state, + nldelegate delegate); + + const analog_net_t & net() const noexcept + { + return plib::downcast<const analog_net_t &>(core_terminal_t::net()); + } + + analog_net_t & net() noexcept + { + return plib::downcast<analog_net_t &>(core_terminal_t::net()); + } + + solver::matrix_solver_t *solver() const noexcept; + }; + + /// \brief Base class for terminals. + /// + /// Each \ref nld_twoterm object consists of two terminals. Terminals + /// are at the core of analog netlists and are connected to \ref net_t + /// objects. + /// + class terminal_t : public analog_t + { + public: + + /// \brief constructor + /// + /// @param dev core_devict_t object owning the terminal + /// @param aname name of this terminal + /// @param otherterm pointer to the sibling terminal + terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm, nldelegate delegate); + + /// \brief Returns voltage of connected net + /// + /// @return voltage of net this terminal is connected to + nl_fptype operator ()() const noexcept + { + return net().Q_Analog(); + } + + /// @brief sets conductivity value of this terminal + /// + /// @param G Conductivity + void set_conductivity(nl_fptype G) const noexcept + { + set_go_gt_I(-G, G, nlconst::zero()); + } + + void set_go_gt(nl_fptype GO, nl_fptype GT) const noexcept + { + set_go_gt_I(GO, GT, nlconst::zero()); + } + + void set_go_gt_I(nl_fptype GO, nl_fptype GT, nl_fptype I) const noexcept + { + // Check for rail nets ... + if (m_go != nullptr) + { + *m_Idr = I; + *m_go = GO; + *m_gt = GT; + } + } + + void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false); + + private: + nl_fptype *m_Idr; ///< drive current + nl_fptype *m_go; ///< conductance for Voltage from other term + nl_fptype *m_gt; ///< conductance for total conductance + + }; + + // ----------------------------------------------------------------------------- + // analog_input_t + // ----------------------------------------------------------------------------- + + /// \brief terminal providing analog input voltage. + /// + /// This terminal class provides a voltage measurement. The conductance against + /// ground is infinite. + + class analog_input_t : public analog_t + { + public: + /// \brief Constructor + analog_input_t(core_device_t &dev, ///< owning device + const pstring &aname, ///< name of terminal + nldelegate delegate ///< delegate + ); + + /// \brief returns voltage at terminal. + /// \returns voltage at terminal. + nl_fptype operator()() const noexcept { return Q_Analog(); } + + /// \brief returns voltage at terminal. + /// \returns voltage at terminal. + nl_fptype Q_Analog() const noexcept + { + return net().Q_Analog(); + } + }; + + // ----------------------------------------------------------------------------- + // analog_output_t + // ----------------------------------------------------------------------------- + + class analog_output_t : public analog_t + { + public: + analog_output_t(core_device_t &dev, const pstring &aname); + + void push(nl_fptype val) noexcept + { + if (val != m_my_net.Q_Analog()) + { + m_my_net.set_Q_Analog(val); + m_my_net.toggle_and_push_to_queue(netlist_time::quantum()); + } + } + + void initial(nl_fptype val) noexcept; + + private: + analog_net_t m_my_net; + }; + +} // namespace netlist + + +#endif // NL_CORE_ANALOG_H_ diff --git a/src/lib/netlist/core/base_objects.h b/src/lib/netlist/core/base_objects.h index c697617e265..656898b21d0 100644 --- a/src/lib/netlist/core/base_objects.h +++ b/src/lib/netlist/core/base_objects.h @@ -8,48 +8,22 @@ #ifndef NL_CORE_BASE_OBJECTS_H_ #define NL_CORE_BASE_OBJECTS_H_ +#include "netlist_state.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 "../plib/pmempool.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> @@ -142,6 +116,7 @@ namespace netlist /// The object provides adds \ref netlist_state_t and \ref netlist_t /// accessors. /// + class netlist_object_t : public object_t { public: @@ -162,7 +137,10 @@ namespace netlist // to ease template design template<typename T, typename... Args> - device_arena::unique_ptr<T> make_pool_object(Args&&... args); + device_arena::unique_ptr<T> make_pool_object(Args&&... args) + { + return state().make_pool_object<T>(std::forward<Args>(args)...); + } private: netlist_t & m_netlist; @@ -305,83 +283,6 @@ namespace netlist } // 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 diff --git a/src/lib/netlist/core/device.h b/src/lib/netlist/core/device.h new file mode 100644 index 00000000000..99a5a1884ec --- /dev/null +++ b/src/lib/netlist/core/device.h @@ -0,0 +1,163 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file device.h +/// + +#ifndef NL_CORE_DEVICE_H_ +#define NL_CORE_DEVICE_H_ + +#include "../nltypes.h" +#include "../plib/pstring.h" +#include "base_objects.h" +#include "logic_family.h" +#include "param.h" + +namespace netlist +{ + // ----------------------------------------------------------------------------- + // 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; + }; + + // ----------------------------------------------------------------------------- + // base_device_t + // ----------------------------------------------------------------------------- + + class base_device_t : public core_device_t + { + public: + base_device_t(netlist_state_t &owner, const pstring &name); + base_device_t(base_device_t &owner, const pstring &name); + + PCOPYASSIGNMOVE(base_device_t, delete) + + ~base_device_t() noexcept override = default; + + template<class O, class C, typename... Args> + void create_and_register_subdevice(O& owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args) + { + dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...); + } + + void register_subalias(const pstring &name, const detail::core_terminal_t &term); + void register_subalias(const pstring &name, const pstring &aliased); + + void connect(const pstring &t1, const pstring &t2); + void connect(const detail::core_terminal_t &t1, const detail::core_terminal_t &t2); + protected: + + //NETLIB_UPDATE_TERMINALSI() { } + + private: + }; + + // ----------------------------------------------------------------------------- + // device_t + // ----------------------------------------------------------------------------- + + class device_t : public base_device_t, + public logic_family_t + { + public: + device_t(netlist_state_t &owner, const pstring &name); + device_t(netlist_state_t &owner, const pstring &name, + const pstring &model); + // only needed by proxies + device_t(netlist_state_t &owner, const pstring &name, + const logic_family_desc_t *desc); + + device_t(device_t &owner, const pstring &name); + // pass in a default model - this may be overwritten by PARAM(DEVICE.MODEL, "XYZ(...)") + device_t(device_t &owner, const pstring &name, + const pstring &model); + + PCOPYASSIGNMOVE(device_t, delete) + + ~device_t() noexcept override = default; + + protected: + + //NETLIB_UPDATE_TERMINALSI() { } + + private: + param_model_t m_model; + }; + +} // namespace netlist + + +#endif // NL_CORE_DEVICE_H_ diff --git a/src/lib/netlist/core/logic.h b/src/lib/netlist/core/logic.h new file mode 100644 index 00000000000..c8ff979cc65 --- /dev/null +++ b/src/lib/netlist/core/logic.h @@ -0,0 +1,208 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file param.h +/// + +#ifndef NL_CORE_LOGIC_H_ +#define NL_CORE_LOGIC_H_ + +#include "../nltypes.h" +#include "base_objects.h" +#include "logic_family.h" +#include "nets.h" +#include "state_var.h" + +#include "../plib/plists.h" +#include "../plib/pstring.h" + +#include <array> +#include <utility> + +namespace netlist +{ + // ----------------------------------------------------------------------------- + // logic_t + // ----------------------------------------------------------------------------- + + class logic_t : public detail::core_terminal_t, public logic_family_t + { + public: + logic_t(device_t &dev, const pstring &aname, + state_e terminal_state, nldelegate delegate); + + logic_net_t & net() noexcept + { + return plib::downcast<logic_net_t &>(core_terminal_t::net()); + } + const logic_net_t & net() const noexcept + { + return plib::downcast<const logic_net_t &>(core_terminal_t::net()); + } + }; + + // ----------------------------------------------------------------------------- + // logic_input_t + // ----------------------------------------------------------------------------- + + class logic_input_t : public logic_t + { + public: + logic_input_t(device_t &dev, const pstring &aname, + nldelegate delegate); + + inline netlist_sig_t operator()() const noexcept + { + nl_assert(terminal_state() != STATE_INP_PASSIVE); + #if NL_USE_COPY_INSTEAD_OF_REFERENCE + return m_Q; + #else + return net().Q(); + #endif + } + + void inactivate() noexcept + { + if (!is_state(STATE_INP_PASSIVE)) + { + set_state(STATE_INP_PASSIVE); + net().remove_from_active_list(*this); + } + } + + void activate() noexcept + { + if (is_state(STATE_INP_PASSIVE)) + { + net().add_to_active_list(*this); + set_state(STATE_INP_ACTIVE); + } + } + + void activate_hl() noexcept + { + if (is_state(STATE_INP_PASSIVE)) + { + net().add_to_active_list(*this); + set_state(STATE_INP_HL); + } + } + + void activate_lh() noexcept + { + if (is_state(STATE_INP_PASSIVE)) + { + net().add_to_active_list(*this); + set_state(STATE_INP_LH); + } + } + }; + + // ----------------------------------------------------------------------------- + // logic_output_t + // ----------------------------------------------------------------------------- + + class logic_output_t : public logic_t + { + public: + + /// \brief logic output constructor + /// + /// The third parameter does nothing. It is provided only for + /// compatibility with tristate_output_t in templatized device models + /// + /// \param dev Device owning this output + /// \param aname The name of this output + /// \param dummy Dummy parameter to allow construction like tristate output + /// + logic_output_t(device_t &dev, const pstring &aname, bool dummy = false); + + void initial(netlist_sig_t val) noexcept; + + inline void push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept + { + m_my_net.set_Q_and_push(newQ, delay); // take the shortcut + } + + inline void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept + { + m_my_net.set_Q_time(newQ, at); // take the shortcut + } + + /// \brief Dummy implementation for templatized generic devices + /// + /// This function shall never be called. It is defined here so that + /// templatized generic device models do not have to do tons of + /// template magic. + /// + /// This function terminates if actually called. + /// + [[noreturn]] static void set_tristate(netlist_sig_t v, + netlist_time ts_off_on, netlist_time ts_on_off) + { + plib::unused_var(v, ts_off_on, ts_on_off); + plib::terminate("set_tristate on logic_output should never be called!"); + } + private: + logic_net_t m_my_net; + }; + + // ----------------------------------------------------------------------------- + // tristate_output_t + // ----------------------------------------------------------------------------- + + /// \brief Tristate output + /// + /// In a lot of applications tristate enable inputs are just connected to + /// VCC/GND to permanently enable the outputs. In this case a pure + /// implementation using analog outputs would not perform well. + /// + /// For this object during creation it can be decided if a logic output or + /// a tristate output is used. Generally the owning device uses parameter + /// FORCE_TRISTATE_LOGIC to determine this. + /// + /// This is the preferred way to implement tristate outputs. + /// + + class tristate_output_t : public logic_output_t + { + public: + + tristate_output_t(device_t &dev, const pstring &aname, bool force_logic); + + void push(netlist_sig_t newQ, netlist_time delay) noexcept + { + if (!m_tristate) + logic_output_t::push(newQ, delay); + m_last_logic = newQ; + } + + void set_tristate(netlist_sig_t v, + netlist_time ts_off_on, netlist_time ts_on_off) noexcept + { + if (!m_force_logic) + if (v != m_tristate) + { + logic_output_t::push((v != 0) ? OUT_TRISTATE() : m_last_logic, v ? ts_off_on : ts_on_off); + m_tristate = v; + } + } + + bool is_force_logic() const noexcept + { + return m_force_logic; + } + + private: + using logic_output_t::initial; + using logic_output_t::set_Q_time; + state_var<netlist_sig_t> m_last_logic; + state_var<netlist_sig_t> m_tristate; + bool m_force_logic; + }; + +} // namespace netlist + + +#endif // NL_CORE_LOGIC_H_ diff --git a/src/lib/netlist/core/netlist_state.h b/src/lib/netlist/core/netlist_state.h new file mode 100644 index 00000000000..318eaae6b2d --- /dev/null +++ b/src/lib/netlist/core/netlist_state.h @@ -0,0 +1,275 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file netlist_state.h +/// + +#ifndef NL_CORE_NETLIST_STATE_H_ +#define NL_CORE_NETLIST_STATE_H_ + +#include "queue.h" + +#include "../nltypes.h" + +#include "../plib/plists.h" +#include "../plib/pstate.h" +#include "../plib/pstring.h" + +#include <array> +#include <unordered_map> +#include <utility> +#include <vector> + +namespace netlist +{ + // ----------------------------------------------------------------------------- + // netlist_state__t + // ----------------------------------------------------------------------------- + + class netlist_state_t + { + public: + + using nets_collection_type = std::vector<device_arena::owned_ptr<detail::net_t>>; + using family_collection_type = std::unordered_map<pstring, host_arena::unique_ptr<logic_family_desc_t>>; + + // need to preserve order of device creation ... + using devices_collection_type = std::vector<std::pair<pstring, device_arena::owned_ptr<core_device_t>>>; + netlist_state_t(const pstring &name, host_arena::unique_ptr<callbacks_t> &&callbacks); + + PCOPYASSIGNMOVE(netlist_state_t, delete) + + /// \brief Destructor + /// + /// The destructor is virtual to allow implementation specific devices + /// to connect to the outside world. For examples see MAME netlist.cpp. + /// + virtual ~netlist_state_t() noexcept = default; + + template<class C> + static bool check_class(core_device_t *p) noexcept + { + return dynamic_cast<C *>(p) != nullptr; + } + + core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const noexcept(false); + + /// \brief Get single device filtered by class and name + /// + /// \tparam C Device class for which devices will be returned + /// \param name Name of the device + /// + /// \return pointers to device + + template<class C> + C *get_single_device(const pstring &name) const + { + return dynamic_cast<C *>(get_single_device(name, check_class<C>)); + } + + /// \brief Get vector of devices + /// + /// \tparam C Device class for which devices will be returned + /// + /// \return vector with pointers to devices + + template<class C> + inline std::vector<C *> get_device_list() const + { + std::vector<C *> tmp; + for (const auto &d : m_devices) + { + auto * const dev = dynamic_cast<C *>(d.second.get()); + if (dev != nullptr) + tmp.push_back(dev); + } + return tmp; + } + + // logging + + log_type & log() noexcept { return m_log; } + const log_type &log() const noexcept { return m_log; } + + plib::dynlib_base &lib() const noexcept { return *m_lib; } + + netlist_t &exec() noexcept { return *m_netlist; } + const netlist_t &exec() const noexcept { return *m_netlist; } + + // state handling + plib::state_manager_t &run_state_manager() noexcept { 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 + "." + 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 + "." + stname, plib::state_manager_t::dtype<C>(), count, state); + } + + // FIXME: only used by queue_t save state + std::size_t find_net_id(const detail::net_t *net) const; + detail::net_t *net_by_id(std::size_t id) const; + + template <typename T> + void register_net(device_arena::owned_ptr<T> &&net) { m_nets.push_back(std::move(net)); } + + /// \brief Get device pointer by name + /// + /// + /// \param name Name of the device + /// + /// \return core_device_t pointer if device exists, else nullptr + + core_device_t *find_device(const pstring &name) const + { + for (const auto & d : m_devices) + if (d.first == name) + return d.second.get(); + return nullptr; + } + + /// \brief Register device using owned_ptr + /// + /// Used to register owned devices. These are devices declared as objects + /// in another devices. + /// + /// \param name Name of the device + /// \param dev Device to be registered + + template <typename T> + void register_device(const pstring &name, device_arena::owned_ptr<T> &&dev) noexcept(false) + { + for (auto & d : m_devices) + if (d.first == name) + { + dev.release(); + log().fatal(MF_DUPLICATE_NAME_DEVICE_LIST(name)); + throw nl_exception(MF_DUPLICATE_NAME_DEVICE_LIST(name)); + } + //m_devices.push_back(std::move(dev)); + m_devices.insert(m_devices.end(), { name, std::move(dev) }); + } + + /// \brief Register device using unique_ptr + /// + /// Used to register devices. + /// + /// \param name Name of the device + /// \param dev Device to be registered + + template <typename T> + void register_device(const pstring &name, device_arena::unique_ptr<T> &&dev) + { + register_device(name, device_arena::owned_ptr<T>(dev.release(), true, dev.get_deleter())); + } + + /// \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_device(core_device_t *dev); + + setup_t &setup() noexcept { return *m_setup; } + const setup_t &setup() const noexcept { return *m_setup; } + + nlparse_t &parser(); + const nlparse_t &parser() const; + + // FIXME: make a postload member and include code there + void rebuild_lists(); // must be called after post_load ! + + static void compile_defines(std::vector<std::pair<pstring, pstring>> &defs); + static pstring version(); + static pstring version_patchlevel(); + + nets_collection_type & nets() noexcept { return m_nets; } + const nets_collection_type & nets() const noexcept { return m_nets; } + + devices_collection_type & devices() noexcept { return m_devices; } + const devices_collection_type & devices() const noexcept { return m_devices; } + + family_collection_type &family_cache() { return m_family_cache; } + + template<typename T, typename... Args> + device_arena::unique_ptr<T> make_pool_object(Args&&... args) + { + return plib::make_unique<T>(m_pool, std::forward<Args>(args)...); + } + // memory pool - still needed in some places + device_arena &pool() noexcept { return m_pool; } + const device_arena &pool() const noexcept { return m_pool; } + + /// \brief set extended validation mode. + /// + /// The extended validation mode is not intended for running. + /// The intention is to identify power pins which are not properly + /// connected. The downside is that this mode creates a netlist which + /// is different (and not able to run). + /// + /// Extended validation is supported by nltool validate option. + /// + /// \param val Boolean value enabling/disabling extended validation mode + void set_extended_validation(bool val) { m_extended_validation = val; } + + /// \brief State of extended validation mode. + /// + /// \returns boolean value indicating if extended validation mode is + /// turned on. + bool is_extended_validation() const { return m_extended_validation; } + + struct stats_info + { + const detail::queue_t &m_queue;// performance + const plib::pperftime_t<true> &m_stat_mainloop; + const plib::pperfcount_t<true> &m_perf_out_processed; + }; + + /// \brief print statistics gathered during run + /// + void print_stats(stats_info &si) const; + + /// \brief call reset on all netlist components + /// + void reset(); + + /// \brief prior to running free no longer needed resources + /// + void free_setup_resources(); + + private: + + device_arena m_pool; // must be deleted last! + + device_arena::unique_ptr<netlist_t> m_netlist; + std::unique_ptr<plib::dynlib_base> m_lib; + plib::state_manager_t m_state; + host_arena::unique_ptr<callbacks_t> m_callbacks; + log_type m_log; + + // FIXME: should only be available during device construcion + host_arena::unique_ptr<setup_t> m_setup; + + nets_collection_type m_nets; + // sole use is to manage lifetime of net objects + devices_collection_type m_devices; + // sole use is to manage lifetime of family objects + family_collection_type m_family_cache; + bool m_extended_validation; + + // dummy version + int m_dummy_version; + }; + +} // namespace netlist + + +#endif // NL_CORE_NETLIST_STATE_H_ diff --git a/src/lib/netlist/core/nets.h b/src/lib/netlist/core/nets.h index 96ecdf1836f..5eced2379e4 100644 --- a/src/lib/netlist/core/nets.h +++ b/src/lib/netlist/core/nets.h @@ -12,8 +12,8 @@ #include "state_var.h" #include "../nltypes.h" -#include "../plib/pstring.h" #include "../plib/plists.h" +#include "../plib/pstring.h" namespace netlist { diff --git a/src/lib/netlist/core/object_array.h b/src/lib/netlist/core/object_array.h new file mode 100644 index 00000000000..0079d819c3e --- /dev/null +++ b/src/lib/netlist/core/object_array.h @@ -0,0 +1,225 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file param.h +/// + +#ifndef NL_CORE_OBJECT_ARRAY_H_ +#define NL_CORE_OBJECT_ARRAY_H_ + +#include "../nltypes.h" + +#include "../plib/plists.h" +#include "../plib/pstring.h" + +#include <array> +#include <utility> + +namespace netlist +{ + template<class C, std::size_t N> + class object_array_base_t : public plib::static_vector<C, N> + { + public: + template<class D, typename... Args> + //object_array_base_t(D &dev, const std::initializer_list<const char *> &names, Args&&... args) + object_array_base_t(D &dev, std::array<const char *, N> &&names, Args&&... args) + { + for (std::size_t i = 0; i<N; i++) + this->emplace_back(dev, pstring(names[i]), std::forward<Args>(args)...); + } + + template<class D> + object_array_base_t(D &dev, const pstring &fmt) + { + for (std::size_t i = 0; i<N; i++) + this->emplace_back(dev, formatted(fmt, i)); + } + + template<class D, typename... Args> + object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, Args&&... args) + { + for (std::size_t i = 0; i<N; i++) + this->emplace_back(dev, formatted(fmt, i+offset), std::forward<Args>(args)...); + } + + template<class D> + object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, nldelegate delegate) + { + for (std::size_t i = 0; i<N; i++) + this->emplace_back(dev, formatted(fmt, i+offset), delegate); + } + + template<class D> + object_array_base_t(D &dev, std::size_t offset, std::size_t qmask, const pstring &fmt) + { + for (std::size_t i = 0; i<N; i++) + { + pstring name(formatted(fmt, i+offset)); + if ((qmask >> i) & 1) + name += "Q"; + this->emplace(i, dev, name); + } + } + protected: + object_array_base_t() = default; + + static pstring formatted(const pstring &fmt, std::size_t n) + { + if (N != 1) + return plib::pfmt(fmt)(n); + return plib::pfmt(fmt)(""); + } + }; + + + template<class C, std::size_t N> + class object_array_t : public object_array_base_t<C, N> + { + public: + using base_type = object_array_base_t<C, N>; + using base_type::base_type; + }; + + template<std::size_t N> + class object_array_t<logic_input_t,N> : public object_array_base_t<logic_input_t, N> + { + public: + using base_type = object_array_base_t<logic_input_t, N>; + using base_type::base_type; + + template<class D, std::size_t ND> + object_array_t(D &dev, std::size_t offset, std::size_t qmask, + const pstring &fmt, std::array<nldelegate, ND> &&delegates) + { + static_assert(N <= ND, "initializer_list size mismatch"); + std::size_t i = 0; + for (auto &e : delegates) + { + if (i < N) + { + pstring name(this->formatted(fmt, i+offset)); + if ((qmask >> i) & 1) + name += "Q"; + this->emplace_back(dev, name, e); + } + i++; + } + } + + //using value_type = typename plib::fast_type_for_bits<N>::type; + using value_type = std::uint32_t; + value_type operator ()() + { + if (N == 1) return e<0>() ; + if (N == 2) return e<0>() | (e<1>() << 1); + if (N == 3) return e<0>() | (e<1>() << 1) | (e<2>() << 2); + if (N == 4) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3); + if (N == 5) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4); + if (N == 6) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4) | (e<5>() << 5); + if (N == 7) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4) | (e<5>() << 5) | (e<6>() << 6); + if (N == 8) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4) | (e<5>() << 5) | (e<6>() << 6) | (e<7>() << 7); + + value_type r(0); + for (std::size_t i = 0; i < N; i++) + r = static_cast<value_type>((*this)[i]() << (N-1)) | (r >> 1); + return r; + } + + private: + template <std::size_t P> + inline constexpr value_type e() const { return (*this)[P](); } + }; + + template<std::size_t N> + class object_array_t<logic_output_t,N> : public object_array_base_t<logic_output_t, N> + { + public: + using base_type = object_array_base_t<logic_output_t, N>; + using base_type::base_type; + + template <typename T> + inline void push(const T &v, const netlist_time &t) + { + if (N >= 1) (*this)[0].push((v >> 0) & 1, t); + if (N >= 2) (*this)[1].push((v >> 1) & 1, t); + if (N >= 3) (*this)[2].push((v >> 2) & 1, t); + if (N >= 4) (*this)[3].push((v >> 3) & 1, t); + if (N >= 5) (*this)[4].push((v >> 4) & 1, t); + if (N >= 6) (*this)[5].push((v >> 5) & 1, t); + if (N >= 7) (*this)[6].push((v >> 6) & 1, t); + if (N >= 8) (*this)[7].push((v >> 7) & 1, t); + for (std::size_t i = 8; i < N; i++) + (*this)[i].push((v >> i) & 1, t); + } + + template<typename T> + void push(const T &v, const netlist_time * t) + { + if (N >= 1) (*this)[0].push((v >> 0) & 1, t[0]); + if (N >= 2) (*this)[1].push((v >> 1) & 1, t[1]); + if (N >= 3) (*this)[2].push((v >> 2) & 1, t[2]); + if (N >= 4) (*this)[3].push((v >> 3) & 1, t[3]); + if (N >= 5) (*this)[4].push((v >> 4) & 1, t[4]); + if (N >= 6) (*this)[5].push((v >> 5) & 1, t[5]); + if (N >= 7) (*this)[6].push((v >> 6) & 1, t[6]); + if (N >= 8) (*this)[7].push((v >> 7) & 1, t[7]); + for (std::size_t i = 8; i < N; i++) + (*this)[i].push((v >> i) & 1, t[i]); + } + + template<typename T, std::size_t NT> + void push(const T &v, const std::array<netlist_time, NT> &t) + { + static_assert(NT >= N, "Not enough timing entries provided"); + + push(v, t.data()); + } + + void set_tristate(netlist_sig_t v, + netlist_time ts_off_on, netlist_time ts_on_off) noexcept + { + for (std::size_t i = 0; i < N; i++) + (*this)[i].set_tristate(v, ts_off_on, ts_on_off); + } + }; + + template<std::size_t N> + class object_array_t<tristate_output_t, N> : public object_array_base_t<tristate_output_t, N> + { + public: + using base_type = object_array_base_t<tristate_output_t, N>; + using base_type::base_type; + + template <typename T> + inline void push(const T &v, const netlist_time &t) + { + if (N >= 1) (*this)[0].push((v >> 0) & 1, t); + if (N >= 2) (*this)[1].push((v >> 1) & 1, t); + if (N >= 3) (*this)[2].push((v >> 2) & 1, t); + if (N >= 4) (*this)[3].push((v >> 3) & 1, t); + if (N >= 5) (*this)[4].push((v >> 4) & 1, t); + if (N >= 6) (*this)[5].push((v >> 5) & 1, t); + if (N >= 7) (*this)[6].push((v >> 6) & 1, t); + if (N >= 8) (*this)[7].push((v >> 7) & 1, t); + for (std::size_t i = 8; i < N; i++) + (*this)[i].push((v >> i) & 1, t); + } + + void set_tristate(netlist_sig_t v, + netlist_time ts_off_on, netlist_time ts_on_off) noexcept + { + for (std::size_t i = 0; i < N; i++) + (*this)[i].set_tristate(v, ts_off_on, ts_on_off); + } + }; + +} // namespace netlist + + +#endif // NL_CORE_OBJECT_ARRAY_H_ diff --git a/src/lib/netlist/core/param.h b/src/lib/netlist/core/param.h index 80769f2d47e..87741765815 100644 --- a/src/lib/netlist/core/param.h +++ b/src/lib/netlist/core/param.h @@ -25,9 +25,9 @@ #include "base_objects.h" +#include "../plib/palloc.h" #include "../plib/pstream.h" #include "../plib/pstring.h" -#include "../plib/palloc.h" #include <memory> diff --git a/src/lib/netlist/core/queue.h b/src/lib/netlist/core/queue.h new file mode 100644 index 00000000000..7e38c3f0ef9 --- /dev/null +++ b/src/lib/netlist/core/queue.h @@ -0,0 +1,114 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud + +/// +/// \file queue.h +/// + +#ifndef NL_CORE_QUEUE_H_ +#define NL_CORE_QUEUE_H_ + +#include "queue.h" + +#include "../nl_errstr.h" +#include "../nltypes.h" + +#include "../plib/pstate.h" +#include "../plib/pstring.h" +#include "../plib/ptimed_queue.h" + +#include <array> +#include <unordered_map> +#include <utility> +#include <vector> + +namespace netlist +{ + namespace detail { + // Use timed_queue_heap to use stdc++ heap functions instead of linear processing. + // This slows down processing by about 25% on a Kaby Lake. + // template <class T, bool TS> + // using timed_queue = plib::timed_queue_heap<T, TS>; + + template <class T, bool TS> + using timed_queue = plib::timed_queue_linear<T, TS>; + + // ----------------------------------------------------------------------------- + // queue_t + // ----------------------------------------------------------------------------- + + // We don't need a thread-safe queue currently. Parallel processing of + // solvers will update inputs after parallel processing. + + template <typename O, bool TS> + class queue_base : + public timed_queue<plib::pqentry_t<netlist_time_ext, O *>, false>, + public plib::state_manager_t::callback_t + { + public: + using entry_t = plib::pqentry_t<netlist_time_ext, O *>; + using base_queue = timed_queue<entry_t, false>; + using id_delegate = plib::pmfp<std::size_t, const O *>; + using obj_delegate = plib::pmfp<O *, std::size_t>; + + explicit queue_base(std::size_t size, id_delegate get_id, obj_delegate get_obj) + : timed_queue<plib::pqentry_t<netlist_time_ext, O *>, false>(size) + , m_qsize(0) + , m_times(size) + , m_net_ids(size) + , m_get_id(get_id) + , m_obj_by_id(get_obj) + { + } + + ~queue_base() noexcept override = default; + + queue_base(const queue_base &) = delete; + queue_base(queue_base &&) = delete; + queue_base &operator=(const queue_base &) = delete; + queue_base &operator=(queue_base &&) = delete; + + protected: + + void register_state(plib::state_manager_t &manager, const pstring &module) override + { + manager.save_item(this, m_qsize, module + "." + "qsize"); + manager.save_item(this, &m_times[0], module + "." + "times", m_times.size()); + manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size()); + } + void on_pre_save(plib::state_manager_t &manager) override + { + plib::unused_var(manager); + m_qsize = this->size(); + for (std::size_t i = 0; i < m_qsize; i++ ) + { + m_times[i] = this->listptr()[i].exec_time().as_raw(); + m_net_ids[i] = m_get_id(this->listptr()[i].object()); + } + } + void on_post_load(plib::state_manager_t &manager) override + { + plib::unused_var(manager); + this->clear(); + for (std::size_t i = 0; i < m_qsize; i++ ) + { + O *n = m_obj_by_id(m_net_ids[i]); + this->template push<false>(entry_t(netlist_time_ext::from_raw(m_times[i]),n)); + } + } + + private: + std::size_t m_qsize; + std::vector<netlist_time_ext::internal_type> m_times; + std::vector<std::size_t> m_net_ids; + id_delegate m_get_id; + obj_delegate m_obj_by_id; + }; + + using queue_t = queue_base<net_t, false>; + + } // namespace detail +} // namespace netlist + + +#endif // NL_CORE_QUEUE_H_ diff --git a/src/lib/netlist/core/setup.h b/src/lib/netlist/core/setup.h index d21b948f4ee..0f1f12b0e29 100644 --- a/src/lib/netlist/core/setup.h +++ b/src/lib/netlist/core/setup.h @@ -9,9 +9,9 @@ #define NL_CORE_SETUP_H_ #include "../nl_config.h" -#include "../nltypes.h" #include "../nl_factory.h" #include "../nl_setup.h" +#include "../nltypes.h" #include "../plib/ppreprocessor.h" #include "../plib/pstream.h" diff --git a/src/lib/netlist/devices/nld_devinc.h b/src/lib/netlist/devices/nld_devinc.h index 46afe121fdb..dce8d60f103 100644 --- a/src/lib/netlist/devices/nld_devinc.h +++ b/src/lib/netlist/devices/nld_devinc.h @@ -148,7 +148,7 @@ #define CLOCK(...) \ NET_REGISTER_DEVEXT(CLOCK, __VA_ARGS__) -// usage : VARCLOCK(name, pFUNC) +// usage : VARCLOCK(name, pN, pFUNC) #define VARCLOCK(...) \ NET_REGISTER_DEVEXT(VARCLOCK, __VA_ARGS__) @@ -441,14 +441,14 @@ // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_74123.cpp // --------------------------------------------------------------------- +// usage : TTL_74121(name) +#define TTL_74121(...) \ + NET_REGISTER_DEVEXT(TTL_74121, __VA_ARGS__) + // usage : TTL_74123(name) #define TTL_74123(...) \ NET_REGISTER_DEVEXT(TTL_74123, __VA_ARGS__) -// usage : TTL_74123_DIP(name) -#define TTL_74123_DIP(...) \ - NET_REGISTER_DEVEXT(TTL_74123_DIP, __VA_ARGS__) - // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_74125.cpp // --------------------------------------------------------------------- @@ -475,17 +475,22 @@ // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_74161.cpp // --------------------------------------------------------------------- -// usage : TTL_74161(name, pA, pB, pC, pD, pCLRQ, pLOADQ, pCLK, pENABLEP, pENABLET) +// usage : TTL_74161(name, pCLK, pENP, pENT, pCLRQ, pLOADQ, pA, pB, pC, pD) // auto connect: VCC, GND #define TTL_74161(...) \ NET_REGISTER_DEVEXT(TTL_74161, __VA_ARGS__) +// usage : TTL_74161_FIXME(name, pA, pB, pC, pD, pCLRQ, pLOADQ, pCLK, pENP, pENT) +// auto connect: VCC, GND +#define TTL_74161_FIXME(...) \ + NET_REGISTER_DEVEXT(TTL_74161_FIXME, __VA_ARGS__) + // usage : TTL_74161_DIP(name) #define TTL_74161_DIP(...) \ NET_REGISTER_DEVEXT(TTL_74161_DIP, __VA_ARGS__) // --------------------------------------------------------------------- -// Source: src/lib/netlist/devices/nld_9316.cpp +// Source: src/lib/netlist/devices/nld_74163.cpp // --------------------------------------------------------------------- // usage : TTL_74163(name, pCLK, pENP, pENT, pCLRQ, pLOADQ, pA, pB, pC, pD) // auto connect: VCC, GND @@ -727,9 +732,9 @@ // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_74123.cpp // --------------------------------------------------------------------- -// usage : CD4538_DIP(name) -#define CD4538_DIP(...) \ - NET_REGISTER_DEVEXT(CD4538_DIP, __VA_ARGS__) +// usage : CD4538(name) +#define CD4538(...) \ + NET_REGISTER_DEVEXT(CD4538, __VA_ARGS__) // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_schmitt.cpp @@ -846,9 +851,9 @@ // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_74123.cpp // --------------------------------------------------------------------- -// usage : TTL_9602_DIP(name) -#define TTL_9602_DIP(...) \ - NET_REGISTER_DEVEXT(TTL_9602_DIP, __VA_ARGS__) +// usage : TTL_9602(name) +#define TTL_9602(...) \ + NET_REGISTER_DEVEXT(TTL_9602, __VA_ARGS__) // --------------------------------------------------------------------- // Source: src/lib/netlist/devices/nld_9310.cpp @@ -986,7 +991,7 @@ // usage : TTL_7421_AND(name, pA, pB, pC, pD) // auto connect: VCC, GND -#define TTL_7421_AND(...) \ +#define TTL_7421_AND(...) \ NET_REGISTER_DEVEXT(TTL_7421_AND, __VA_ARGS__) // usage : TTL_7425_GATE(name) @@ -1164,6 +1169,18 @@ #define TTL_7486_DIP(...) \ NET_REGISTER_DEVEXT(TTL_7486_DIP, __VA_ARGS__) +// usage : TTL_74121_DIP(name) +#define TTL_74121_DIP(...) \ + NET_REGISTER_DEVEXT(TTL_74121_DIP, __VA_ARGS__) + +// usage : TTL_74123_DIP(name) +#define TTL_74123_DIP(...) \ + NET_REGISTER_DEVEXT(TTL_74123_DIP, __VA_ARGS__) + +// usage : TTL_9602_DIP(name) +#define TTL_9602_DIP(...) \ + NET_REGISTER_DEVEXT(TTL_9602_DIP, __VA_ARGS__) + // usage : TTL_74125_DIP(name) #define TTL_74125_DIP(...) \ NET_REGISTER_DEVEXT(TTL_74125_DIP, __VA_ARGS__) @@ -1251,6 +1268,10 @@ #define CD4316_DIP(...) \ NET_REGISTER_DEVEXT(CD4316_DIP, __VA_ARGS__) +// usage : CD4538_DIP(name) +#define CD4538_DIP(...) \ + NET_REGISTER_DEVEXT(CD4538_DIP, __VA_ARGS__) + // --------------------------------------------------------------------- // Source: src/lib/netlist/macro/nlm_opamp.cpp // --------------------------------------------------------------------- diff --git a/src/lib/netlist/devices/nld_log.cpp b/src/lib/netlist/devices/nld_log.cpp index b00dc62ff0d..5c0c550e11c 100644 --- a/src/lib/netlist/devices/nld_log.cpp +++ b/src/lib/netlist/devices/nld_log.cpp @@ -8,8 +8,8 @@ #include "netlist/nl_base.h" #include "nld_log.h" #include "plib/pfmtlog.h" -#include "plib/pstream.h" #include "plib/pmulti_threading.h" +#include "plib/pstream.h" //#include "sound/wavwrite.h" #include <array> diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h index b3bc9c6434e..a8ba6937164 100644 --- a/src/lib/netlist/devices/nlid_system.h +++ b/src/lib/netlist/devices/nlid_system.h @@ -102,7 +102,7 @@ namespace devices for (int i=0; i < m_N(); i++) { pstring inpname = plib::pfmt("A{1}")(i); - m_I.push_back(state().make_pool_object<analog_input_t>(*this, inpname, NETLIB_DELEGATE(fb))); + m_I.push_back(owner.template make_pool_object<analog_input_t>(*this, inpname, NETLIB_DELEGATE(fb))); inps.push_back(inpname); m_vals.push_back(nlconst::zero()); } @@ -460,7 +460,7 @@ namespace devices for (int i=0; i < m_N(); i++) { pstring inpname = plib::pfmt("A{1}")(i); - m_I.push_back(state().make_pool_object<analog_input_t>(*this, inpname, NETLIB_DELEGATE(inputs))); + m_I.push_back(owner.template make_pool_object<analog_input_t>(*this, inpname, NETLIB_DELEGATE(inputs))); inps.push_back(inpname); m_vals.push_back(nlconst::zero()); } diff --git a/src/lib/netlist/macro/nlm_base.cpp b/src/lib/netlist/macro/nlm_base.cpp index b399a2c360c..1185f482e73 100644 --- a/src/lib/netlist/macro/nlm_base.cpp +++ b/src/lib/netlist/macro/nlm_base.cpp @@ -1,6 +1,5 @@ // license:GPL-2.0+ // copyright-holders:Couriersud -#include "netlist/nl_setup.h" #include "netlist/devices/net_lib.h" #include "nlm_base.h" diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 22baf636461..3b07912a8d4 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -759,6 +759,16 @@ namespace netlist net().initial(val); } + // ----------------------------------------------------------------------------- + // tristate_output_t + // ----------------------------------------------------------------------------- + tristate_output_t::tristate_output_t(device_t &dev, const pstring &aname, bool force_logic) + : logic_output_t(dev, aname) + , m_last_logic(dev, name() + "." + "m_last_logic", 1) // force change + , m_tristate(dev, name() + "." + "m_tristate", force_logic ? 0 : 2) // force change + , m_force_logic(force_logic) + {} + // ---------------------------------------------------------------------------------------- // analog_input_t // ---------------------------------------------------------------------------------------- @@ -939,6 +949,17 @@ namespace netlist nlparse_t &netlist_state_t::parser() { return m_setup->parser(); } const nlparse_t &netlist_state_t::parser() const { return m_setup->parser(); } + void netlist_state_t::remove_device(core_device_t *dev) + { + 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; + } + } + template struct state_var<std::uint8_t>; template struct state_var<std::uint16_t>; template struct state_var<std::uint32_t>; diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 45b64c5e122..cf2acfd9d54 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -12,11 +12,16 @@ #error "nl_base.h included. Please correct." #endif +#include "core/analog.h" #include "core/base_objects.h" -#include "core/param.h" -#include "core/state_var.h" +#include "core/device.h" +#include "core/logic.h" #include "core/logic_family.h" +#include "core/netlist_state.h" #include "core/nets.h" +#include "core/object_array.h" +#include "core/param.h" +#include "core/state_var.h" #include "plib/palloc.h" // owned_ptr #include "plib/pfunction.h" @@ -211,664 +216,6 @@ namespace netlist - // ----------------------------------------------------------------------------- - // analog_t - // ----------------------------------------------------------------------------- - - class analog_t : public detail::core_terminal_t - { - public: - - analog_t(core_device_t &dev, const pstring &aname, state_e state, - nldelegate delegate); - - const analog_net_t & net() const noexcept; - analog_net_t & net() noexcept; - - solver::matrix_solver_t *solver() const noexcept; - }; - - /// \brief Base clase for terminals. - /// - /// Each \ref nld_twoterm object consists of two terminals. Terminals - /// are at the core of analog netlists and provide. \ref net_t objects - /// connect terminals. - /// - class terminal_t : public analog_t - { - public: - - /// \brief constructor - /// - /// @param dev core_devict_t object owning the terminal - /// @param aname name of this terminal - /// @param otherterm pointer to the sibling terminal - terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm, nldelegate delegate); - - /// \brief Returns voltage of connected net - /// - /// @return voltage of net this terminal is connected to - nl_fptype operator ()() const noexcept; - - /// @brief sets conductivity value of this terminal - /// - /// @param G Conductivity - void set_conductivity(nl_fptype G) const noexcept - { - set_go_gt_I(-G, G, nlconst::zero()); - } - - void set_go_gt(nl_fptype GO, nl_fptype GT) const noexcept - { - set_go_gt_I(GO, GT, nlconst::zero()); - } - - void set_go_gt_I(nl_fptype GO, nl_fptype GT, nl_fptype I) const noexcept - { - // Check for rail nets ... - if (m_go != nullptr) - { - *m_Idr = I; - *m_go = GO; - *m_gt = GT; - } - } - - void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false); - - private: - nl_fptype *m_Idr; ///< drive current - nl_fptype *m_go; ///< conductance for Voltage from other term - nl_fptype *m_gt; ///< conductance for total conductance - - }; - - - // ----------------------------------------------------------------------------- - // logic_t - // ----------------------------------------------------------------------------- - - class logic_t : public detail::core_terminal_t, public logic_family_t - { - public: - logic_t(device_t &dev, const pstring &aname, - state_e terminal_state, nldelegate delegate); - - logic_net_t & net() noexcept; - const logic_net_t & net() const noexcept; - }; - - // ----------------------------------------------------------------------------- - // logic_input_t - // ----------------------------------------------------------------------------- - - class logic_input_t : public logic_t - { - public: - logic_input_t(device_t &dev, const pstring &aname, - nldelegate delegate); - - inline netlist_sig_t operator()() const noexcept; - - void inactivate() noexcept; - void activate() noexcept; - void activate_hl() noexcept; - void activate_lh() noexcept; - }; - - // ----------------------------------------------------------------------------- - // analog_input_t - // ----------------------------------------------------------------------------- - - /// \brief terminal providing analog input voltage. - /// - /// This terminal class provides a voltage measurement. The conductance against - /// ground is infinite. - - class analog_input_t : public analog_t - { - public: - /// \brief Constructor - analog_input_t(core_device_t &dev, ///< owning device - const pstring &aname, ///< name of terminal - nldelegate delegate ///< delegate - ); - - /// \brief returns voltage at terminal. - /// \returns voltage at terminal. - nl_fptype operator()() const noexcept { return Q_Analog(); } - - /// \brief returns voltage at terminal. - /// \returns voltage at terminal. - nl_fptype Q_Analog() const noexcept; - }; - - // ----------------------------------------------------------------------------- - // logic_output_t - // ----------------------------------------------------------------------------- - - class logic_output_t : public logic_t - { - public: - - /// \brief logic output constructor - /// - /// The third parameter does nothing. It is provided only for - /// compatibility with tristate_output_t in templatized device models - /// - /// \param dev Device owning this output - /// \param aname The name of this output - /// \param dummy Dummy parameter to allow construction like tristate output - /// - logic_output_t(device_t &dev, const pstring &aname, bool dummy = false); - - void initial(netlist_sig_t val) noexcept; - - inline void push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept - { - m_my_net.set_Q_and_push(newQ, delay); // take the shortcut - } - - inline void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept - { - m_my_net.set_Q_time(newQ, at); // take the shortcut - } - - /// \brief Dummy implementation for templatized generic devices - /// - /// This function shall never be called. It is defined here so that - /// templatized generic device models do not have to do tons of - /// template magic. - /// - /// This function terminates if actually called. - /// - [[noreturn]] static void set_tristate(netlist_sig_t v, - netlist_time ts_off_on, netlist_time ts_on_off) - { - plib::unused_var(v, ts_off_on, ts_on_off); - plib::terminate("set_tristate on logic_output should never be called!"); - } - private: - logic_net_t m_my_net; - }; - - // ----------------------------------------------------------------------------- - // tristate_output_t - // ----------------------------------------------------------------------------- - - /// \brief Tristate output - /// - /// In a lot of applications tristate enable inputs are just connected to - /// VCC/GND to permanently enable the outputs. In this case a pure - /// implementation using analog outputs would not perform well. - /// - /// For this object during creation it can be decided if a logic output or - /// a tristate output is used. Generally the owning device uses parameter - /// FORCE_TRISTATE_LOGIC to determine this. - /// - /// This is the preferred way to implement tristate outputs. - /// - - class tristate_output_t : public logic_output_t - { - public: - - tristate_output_t(device_t &dev, const pstring &aname, bool force_logic) - : logic_output_t(dev, aname) - , m_last_logic(dev, name() + "." + "m_last_logic", 1) // force change - , m_tristate(dev, name() + "." + "m_tristate", force_logic ? 0 : 2) // force change - , m_force_logic(force_logic) - {} - - void push(netlist_sig_t newQ, netlist_time delay) noexcept - { - if (!m_tristate) - logic_output_t::push(newQ, delay); - m_last_logic = newQ; - } - - void set_tristate(netlist_sig_t v, - netlist_time ts_off_on, netlist_time ts_on_off) noexcept - { - if (!m_force_logic) - if (v != m_tristate) - { - logic_output_t::push((v != 0) ? OUT_TRISTATE() : m_last_logic, v ? ts_off_on : ts_on_off); - m_tristate = v; - } - } - - bool is_force_logic() const noexcept - { - return m_force_logic; - } - - private: - using logic_output_t::initial; - using logic_output_t::set_Q_time; - state_var<netlist_sig_t> m_last_logic; - state_var<netlist_sig_t> m_tristate; - bool m_force_logic; - }; - - - // ----------------------------------------------------------------------------- - // analog_output_t - // ----------------------------------------------------------------------------- - - class analog_output_t : public analog_t - { - public: - analog_output_t(core_device_t &dev, const pstring &aname); - - void push(nl_fptype val) noexcept; - void initial(nl_fptype val) noexcept; - - private: - analog_net_t m_my_net; - }; - - - // ----------------------------------------------------------------------------- - // base_device_t - // ----------------------------------------------------------------------------- - - class base_device_t : public core_device_t - { - public: - base_device_t(netlist_state_t &owner, const pstring &name); - base_device_t(base_device_t &owner, const pstring &name); - - PCOPYASSIGNMOVE(base_device_t, delete) - - ~base_device_t() noexcept override = default; - - template<class O, class C, typename... Args> - void create_and_register_subdevice(O& owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args); - - void register_subalias(const pstring &name, const detail::core_terminal_t &term); - void register_subalias(const pstring &name, const pstring &aliased); - - void connect(const pstring &t1, const pstring &t2); - void connect(const detail::core_terminal_t &t1, const detail::core_terminal_t &t2); - protected: - - //NETLIB_UPDATE_TERMINALSI() { } - - private: - }; - - // ----------------------------------------------------------------------------- - // device_t - // ----------------------------------------------------------------------------- - - class device_t : public base_device_t, - public logic_family_t - { - public: - device_t(netlist_state_t &owner, const pstring &name); - device_t(netlist_state_t &owner, const pstring &name, - const pstring &model); - // only needed by proxies - device_t(netlist_state_t &owner, const pstring &name, - const logic_family_desc_t *desc); - - device_t(device_t &owner, const pstring &name); - // pass in a default model - this may be overwritten by PARAM(DEVICE.MODEL, "XYZ(...)") - device_t(device_t &owner, const pstring &name, - const pstring &model); - - PCOPYASSIGNMOVE(device_t, delete) - - ~device_t() noexcept override = default; - - protected: - - //NETLIB_UPDATE_TERMINALSI() { } - - private: - param_model_t m_model; - }; - - namespace detail { - // Use timed_queue_heap to use stdc++ heap functions instead of linear processing. - // This slows down processing by about 25% on a Kaby Lake. - // template <class T, bool TS> - // using timed_queue = plib::timed_queue_heap<T, TS>; - - template <class T, bool TS> - using timed_queue = plib::timed_queue_linear<T, TS>; - - // ----------------------------------------------------------------------------- - // queue_t - // ----------------------------------------------------------------------------- - - // We don't need a thread-safe queue currently. Parallel processing of - // solvers will update inputs after parallel processing. - - template <typename O, bool TS> - class queue_base : - public timed_queue<plib::pqentry_t<netlist_time_ext, O *>, false>, - public plib::state_manager_t::callback_t - { - public: - using entry_t = plib::pqentry_t<netlist_time_ext, O *>; - using base_queue = timed_queue<entry_t, false>; - using id_delegate = plib::pmfp<std::size_t, const O *>; - using obj_delegate = plib::pmfp<O *, std::size_t>; - - explicit queue_base(std::size_t size, id_delegate get_id, obj_delegate get_obj) - : timed_queue<plib::pqentry_t<netlist_time_ext, O *>, false>(size) - , m_qsize(0) - , m_times(size) - , m_net_ids(size) - , m_get_id(get_id) - , m_obj_by_id(get_obj) - { - } - - ~queue_base() noexcept override = default; - - queue_base(const queue_base &) = delete; - queue_base(queue_base &&) = delete; - queue_base &operator=(const queue_base &) = delete; - queue_base &operator=(queue_base &&) = delete; - - protected: - - void register_state(plib::state_manager_t &manager, const pstring &module) override - { - manager.save_item(this, m_qsize, module + "." + "qsize"); - manager.save_item(this, &m_times[0], module + "." + "times", m_times.size()); - manager.save_item(this, &m_net_ids[0], module + "." + "names", m_net_ids.size()); - } - void on_pre_save(plib::state_manager_t &manager) override - { - plib::unused_var(manager); - m_qsize = this->size(); - for (std::size_t i = 0; i < m_qsize; i++ ) - { - m_times[i] = this->listptr()[i].exec_time().as_raw(); - m_net_ids[i] = m_get_id(this->listptr()[i].object()); - } - } - void on_post_load(plib::state_manager_t &manager) override - { - plib::unused_var(manager); - this->clear(); - for (std::size_t i = 0; i < m_qsize; i++ ) - { - O *n = m_obj_by_id(m_net_ids[i]); - this->template push<false>(entry_t(netlist_time_ext::from_raw(m_times[i]),n)); - } - } - - private: - std::size_t m_qsize; - std::vector<netlist_time_ext::internal_type> m_times; - std::vector<std::size_t> m_net_ids; - id_delegate m_get_id; - obj_delegate m_obj_by_id; - }; - - using queue_t = queue_base<net_t, false>; - - } // namespace detail - - // ----------------------------------------------------------------------------- - // netlist_state__t - // ----------------------------------------------------------------------------- - - class netlist_state_t - { - public: - - using nets_collection_type = std::vector<device_arena::owned_ptr<detail::net_t>>; - using family_collection_type = std::unordered_map<pstring, host_arena::unique_ptr<logic_family_desc_t>>; - - // need to preserve order of device creation ... - using devices_collection_type = std::vector<std::pair<pstring, device_arena::owned_ptr<core_device_t>>>; - netlist_state_t(const pstring &name, host_arena::unique_ptr<callbacks_t> &&callbacks); - - PCOPYASSIGNMOVE(netlist_state_t, delete) - - /// \brief Destructor - /// - /// The destructor is virtual to allow implementation specific devices - /// to connect to the outside world. For examples see MAME netlist.cpp. - /// - virtual ~netlist_state_t() noexcept = default; - - template<class C> - static bool check_class(core_device_t *p) noexcept - { - return dynamic_cast<C *>(p) != nullptr; - } - - core_device_t *get_single_device(const pstring &classname, bool (*cc)(core_device_t *)) const noexcept(false); - - /// \brief Get single device filtered by class and name - /// - /// \tparam C Device class for which devices will be returned - /// \param name Name of the device - /// - /// \return pointers to device - - template<class C> - C *get_single_device(const pstring &name) const - { - return dynamic_cast<C *>(get_single_device(name, check_class<C>)); - } - - /// \brief Get vector of devices - /// - /// \tparam C Device class for which devices will be returned - /// - /// \return vector with pointers to devices - - template<class C> - inline std::vector<C *> get_device_list() const - { - std::vector<C *> tmp; - for (const auto &d : m_devices) - { - auto * const dev = dynamic_cast<C *>(d.second.get()); - if (dev != nullptr) - tmp.push_back(dev); - } - return tmp; - } - - // logging - - log_type & log() noexcept { return m_log; } - const log_type &log() const noexcept { return m_log; } - - plib::dynlib_base &lib() const noexcept { return *m_lib; } - - netlist_t &exec() noexcept { return *m_netlist; } - const netlist_t &exec() const noexcept { return *m_netlist; } - - // state handling - plib::state_manager_t &run_state_manager() noexcept { 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 + "." + 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 + "." + stname, plib::state_manager_t::dtype<C>(), count, state); - } - - // FIXME: only used by queue_t save state - std::size_t find_net_id(const detail::net_t *net) const; - detail::net_t *net_by_id(std::size_t id) const; - - template <typename T> - void register_net(device_arena::owned_ptr<T> &&net) { m_nets.push_back(std::move(net)); } - - /// \brief Get device pointer by name - /// - /// - /// \param name Name of the device - /// - /// \return core_device_t pointer if device exists, else nullptr - - core_device_t *find_device(const pstring &name) const - { - for (const auto & d : m_devices) - if (d.first == name) - return d.second.get(); - return nullptr; - } - - /// \brief Register device using owned_ptr - /// - /// Used to register owned devices. These are devices declared as objects - /// in another devices. - /// - /// \param name Name of the device - /// \param dev Device to be registered - - template <typename T> - void register_device(const pstring &name, device_arena::owned_ptr<T> &&dev) noexcept(false) - { - for (auto & d : m_devices) - if (d.first == name) - { - dev.release(); - log().fatal(MF_DUPLICATE_NAME_DEVICE_LIST(name)); - throw nl_exception(MF_DUPLICATE_NAME_DEVICE_LIST(name)); - } - //m_devices.push_back(std::move(dev)); - m_devices.insert(m_devices.end(), { name, std::move(dev) }); - } - - /// \brief Register device using unique_ptr - /// - /// Used to register devices. - /// - /// \param name Name of the device - /// \param dev Device to be registered - - template <typename T> - void register_device(const pstring &name, device_arena::unique_ptr<T> &&dev) - { - register_device(name, device_arena::owned_ptr<T>(dev.release(), true, dev.get_deleter())); - } - - /// \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_device(core_device_t *dev) - { - 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; - } - } - - setup_t &setup() noexcept { return *m_setup; } - const setup_t &setup() const noexcept { return *m_setup; } - - nlparse_t &parser(); - const nlparse_t &parser() const; - - // FIXME: make a postload member and include code there - void rebuild_lists(); // must be called after post_load ! - - static void compile_defines(std::vector<std::pair<pstring, pstring>> &defs); - static pstring version(); - static pstring version_patchlevel(); - - nets_collection_type & nets() noexcept { return m_nets; } - const nets_collection_type & nets() const noexcept { return m_nets; } - - devices_collection_type & devices() noexcept { return m_devices; } - const devices_collection_type & devices() const noexcept { return m_devices; } - - family_collection_type &family_cache() { return m_family_cache; } - - template<typename T, typename... Args> - device_arena::unique_ptr<T> make_pool_object(Args&&... args) - { - return plib::make_unique<T>(m_pool, std::forward<Args>(args)...); - } - // memory pool - still needed in some places - device_arena &pool() noexcept { return m_pool; } - const device_arena &pool() const noexcept { return m_pool; } - - /// \brief set extended validation mode. - /// - /// The extended validation mode is not intended for running. - /// The intention is to identify power pins which are not properly - /// connected. The downside is that this mode creates a netlist which - /// is different (and not able to run). - /// - /// Extended validation is supported by nltool validate option. - /// - /// \param val Boolean value enabling/disabling extended validation mode - void set_extended_validation(bool val) { m_extended_validation = val; } - - /// \brief State of extended validation mode. - /// - /// \returns boolean value indicating if extended validation mode is - /// turned on. - bool is_extended_validation() const { return m_extended_validation; } - - struct stats_info - { - const detail::queue_t &m_queue;// performance - const plib::pperftime_t<true> &m_stat_mainloop; - const plib::pperfcount_t<true> &m_perf_out_processed; - }; - - /// \brief print statistics gathered during run - /// - void print_stats(stats_info &si) const; - - /// \brief call reset on all netlist components - /// - void reset(); - - /// \brief prior to running free no longer needed resources - /// - void free_setup_resources(); - - private: - - device_arena m_pool; // must be deleted last! - - device_arena::unique_ptr<netlist_t> m_netlist; - std::unique_ptr<plib::dynlib_base> m_lib; - plib::state_manager_t m_state; - host_arena::unique_ptr<callbacks_t> m_callbacks; - log_type m_log; - - // FIXME: should only be available during device construcion - host_arena::unique_ptr<setup_t> m_setup; - - nets_collection_type m_nets; - // sole use is to manage lifetime of net objects - devices_collection_type m_devices; - // sole use is to manage lifetime of family objects - family_collection_type m_family_cache; - bool m_extended_validation; - - // dummy version - int m_dummy_version; - }; namespace devices { @@ -1001,206 +348,6 @@ namespace netlist // Support classes for devices // ----------------------------------------------------------------------------- - template<class C, std::size_t N> - class object_array_base_t : public plib::static_vector<C, N> - { - public: - template<class D, typename... Args> - //object_array_base_t(D &dev, const std::initializer_list<const char *> &names, Args&&... args) - object_array_base_t(D &dev, std::array<const char *, N> &&names, Args&&... args) - { - for (std::size_t i = 0; i<N; i++) - this->emplace_back(dev, pstring(names[i]), std::forward<Args>(args)...); - } - - template<class D> - object_array_base_t(D &dev, const pstring &fmt) - { - for (std::size_t i = 0; i<N; i++) - this->emplace_back(dev, formatted(fmt, i)); - } - - template<class D, typename... Args> - object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, Args&&... args) - { - for (std::size_t i = 0; i<N; i++) - this->emplace_back(dev, formatted(fmt, i+offset), std::forward<Args>(args)...); - } - - template<class D> - object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, nldelegate delegate) - { - for (std::size_t i = 0; i<N; i++) - this->emplace_back(dev, formatted(fmt, i+offset), delegate); - } - - template<class D> - object_array_base_t(D &dev, std::size_t offset, std::size_t qmask, const pstring &fmt) - { - for (std::size_t i = 0; i<N; i++) - { - pstring name(formatted(fmt, i+offset)); - if ((qmask >> i) & 1) - name += "Q"; - this->emplace(i, dev, name); - } - } - protected: - object_array_base_t() = default; - - static pstring formatted(const pstring &fmt, std::size_t n) - { - if (N != 1) - return plib::pfmt(fmt)(n); - return plib::pfmt(fmt)(""); - } - }; - - - template<class C, std::size_t N> - class object_array_t : public object_array_base_t<C, N> - { - public: - using base_type = object_array_base_t<C, N>; - using base_type::base_type; - }; - - template<std::size_t N> - class object_array_t<logic_input_t,N> : public object_array_base_t<logic_input_t, N> - { - public: - using base_type = object_array_base_t<logic_input_t, N>; - using base_type::base_type; - - template<class D, std::size_t ND> - object_array_t(D &dev, std::size_t offset, std::size_t qmask, - const pstring &fmt, std::array<nldelegate, ND> &&delegates) - { - static_assert(N <= ND, "initializer_list size mismatch"); - std::size_t i = 0; - for (auto &e : delegates) - { - if (i < N) - { - pstring name(this->formatted(fmt, i+offset)); - if ((qmask >> i) & 1) - name += "Q"; - this->emplace_back(dev, name, e); - } - i++; - } - } - - //using value_type = typename plib::fast_type_for_bits<N>::type; - using value_type = std::uint32_t; - value_type operator ()() - { - if (N == 1) return e<0>() ; - if (N == 2) return e<0>() | (e<1>() << 1); - if (N == 3) return e<0>() | (e<1>() << 1) | (e<2>() << 2); - if (N == 4) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3); - if (N == 5) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) - | (e<4>() << 4); - if (N == 6) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) - | (e<4>() << 4) | (e<5>() << 5); - if (N == 7) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) - | (e<4>() << 4) | (e<5>() << 5) | (e<6>() << 6); - if (N == 8) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) - | (e<4>() << 4) | (e<5>() << 5) | (e<6>() << 6) | (e<7>() << 7); - - value_type r(0); - for (std::size_t i = 0; i < N; i++) - r = static_cast<value_type>((*this)[i]() << (N-1)) | (r >> 1); - return r; - } - - private: - template <std::size_t P> - inline constexpr value_type e() const { return (*this)[P](); } - }; - - template<std::size_t N> - class object_array_t<logic_output_t,N> : public object_array_base_t<logic_output_t, N> - { - public: - using base_type = object_array_base_t<logic_output_t, N>; - using base_type::base_type; - - template <typename T> - inline void push(const T &v, const netlist_time &t) - { - if (N >= 1) (*this)[0].push((v >> 0) & 1, t); - if (N >= 2) (*this)[1].push((v >> 1) & 1, t); - if (N >= 3) (*this)[2].push((v >> 2) & 1, t); - if (N >= 4) (*this)[3].push((v >> 3) & 1, t); - if (N >= 5) (*this)[4].push((v >> 4) & 1, t); - if (N >= 6) (*this)[5].push((v >> 5) & 1, t); - if (N >= 7) (*this)[6].push((v >> 6) & 1, t); - if (N >= 8) (*this)[7].push((v >> 7) & 1, t); - for (std::size_t i = 8; i < N; i++) - (*this)[i].push((v >> i) & 1, t); - } - - template<typename T> - void push(const T &v, const netlist_time * t) - { - if (N >= 1) (*this)[0].push((v >> 0) & 1, t[0]); - if (N >= 2) (*this)[1].push((v >> 1) & 1, t[1]); - if (N >= 3) (*this)[2].push((v >> 2) & 1, t[2]); - if (N >= 4) (*this)[3].push((v >> 3) & 1, t[3]); - if (N >= 5) (*this)[4].push((v >> 4) & 1, t[4]); - if (N >= 6) (*this)[5].push((v >> 5) & 1, t[5]); - if (N >= 7) (*this)[6].push((v >> 6) & 1, t[6]); - if (N >= 8) (*this)[7].push((v >> 7) & 1, t[7]); - for (std::size_t i = 8; i < N; i++) - (*this)[i].push((v >> i) & 1, t[i]); - } - - template<typename T, std::size_t NT> - void push(const T &v, const std::array<netlist_time, NT> &t) - { - static_assert(NT >= N, "Not enough timing entries provided"); - - push(v, t.data()); - } - - void set_tristate(netlist_sig_t v, - netlist_time ts_off_on, netlist_time ts_on_off) noexcept - { - for (std::size_t i = 0; i < N; i++) - (*this)[i].set_tristate(v, ts_off_on, ts_on_off); - } - }; - - template<std::size_t N> - class object_array_t<tristate_output_t,N> : public object_array_base_t<tristate_output_t, N> - { - public: - using base_type = object_array_base_t<tristate_output_t, N>; - using base_type::base_type; - - template <typename T> - inline void push(const T &v, const netlist_time &t) - { - if (N >= 1) (*this)[0].push((v >> 0) & 1, t); - if (N >= 2) (*this)[1].push((v >> 1) & 1, t); - if (N >= 3) (*this)[2].push((v >> 2) & 1, t); - if (N >= 4) (*this)[3].push((v >> 3) & 1, t); - if (N >= 5) (*this)[4].push((v >> 4) & 1, t); - if (N >= 6) (*this)[5].push((v >> 5) & 1, t); - if (N >= 7) (*this)[6].push((v >> 6) & 1, t); - if (N >= 8) (*this)[7].push((v >> 7) & 1, t); - for (std::size_t i = 8; i < N; i++) - (*this)[i].push((v >> i) & 1, t); - } - - void set_tristate(netlist_sig_t v, - netlist_time ts_off_on, netlist_time ts_on_off) noexcept - { - for (std::size_t i = 0; i < N; i++) - (*this)[i].set_tristate(v, ts_off_on, ts_on_off); - } - }; // ----------------------------------------------------------------------------- // power pins - not a device, but a helper @@ -1254,7 +401,7 @@ namespace netlist // ----------------------------------------------------------------------------- // logic_input_t // ----------------------------------------------------------------------------- - +#if 0 inline void logic_input_t::inactivate() noexcept { if (!is_state(STATE_INP_PASSIVE)) @@ -1290,7 +437,7 @@ namespace netlist set_state(STATE_INP_LH); } } - +#endif inline void detail::net_t::push_to_queue(const netlist_time &delay) noexcept { if (has_connections()) @@ -1352,6 +499,12 @@ namespace netlist railterminal().device().do_dec_active(); } +#if 0 + inline nl_fptype terminal_t::operator ()() const noexcept + { + return net().Q_Analog(); + } + inline const analog_net_t & analog_t::net() const noexcept { return plib::downcast<const analog_net_t &>(core_terminal_t::net()); @@ -1362,7 +515,6 @@ namespace netlist return plib::downcast<analog_net_t &>(core_terminal_t::net()); } - inline nl_fptype terminal_t::operator ()() const noexcept { return net().Q_Analog(); } inline logic_net_t & logic_t::net() noexcept { @@ -1373,7 +525,6 @@ namespace netlist { return plib::downcast<const logic_net_t &>(core_terminal_t::net()); } - inline netlist_sig_t logic_input_t::operator()() const noexcept { nl_assert(terminal_state() != STATE_INP_PASSIVE); @@ -1397,6 +548,7 @@ namespace netlist m_my_net.toggle_and_push_to_queue(netlist_time::quantum()); } } +#endif inline netlist_t &detail::device_object_t::exec() noexcept { @@ -1524,13 +676,13 @@ namespace netlist // ----------------------------------------------------------------------------- // inline implementations - cold // ----------------------------------------------------------------------------- - +#if 0 template<typename T, typename... Args> inline device_arena::unique_ptr<T> detail::netlist_object_t::make_pool_object(Args&&... args) { return state().make_pool_object<T>(std::forward<Args>(args)...); } - +#endif inline void param_t::update_param() noexcept { device().update_param(); @@ -1593,12 +745,13 @@ namespace netlist device.state().log().warning(MW_ROM_NOT_FOUND(str())); } +#if 0 template<class O, class C, typename... Args> void base_device_t::create_and_register_subdevice(O &owner, const pstring &name, device_arena::unique_ptr<C> &dev, Args&&... args) { dev = state().make_pool_object<C>(owner, name, std::forward<Args>(args)...); } - +#endif inline solver::matrix_solver_t *analog_t::solver() const noexcept { return (this->has_net() ? net().solver() : nullptr); diff --git a/src/lib/netlist/nl_factory.h b/src/lib/netlist/nl_factory.h index 25c957e5a07..ad26a505453 100644 --- a/src/lib/netlist/nl_factory.h +++ b/src/lib/netlist/nl_factory.h @@ -129,6 +129,7 @@ namespace factory { const pstring &name, std::tuple<Args...>& args, std::index_sequence<Is...>) { return plib::make_unique<C>(pool, anetlist, name, std::forward<Args>(std::get<Is>(args))...); + //return anetlist.make_pool_object<C>(anetlist, name, std::forward<Args>(std::get<Is>(args))...); } dev_uptr make_device(device_arena &pool, diff --git a/src/lib/netlist/nltypes.h b/src/lib/netlist/nltypes.h index be1de61aa44..1dcb1f943c9 100644 --- a/src/lib/netlist/nltypes.h +++ b/src/lib/netlist/nltypes.h @@ -14,11 +14,11 @@ #include "nl_config.h" +#include "plib/pmempool.h" +#include "plib/ppmf.h" #include "plib/pstring.h" #include "plib/ptime.h" #include "plib/ptypes.h" -#include "plib/ppmf.h" -#include "plib/pmempool.h" #include <memory> @@ -45,6 +45,7 @@ namespace netlist // ----------------------------------------------------------------------------- class logic_output_t; + class tristate_output_t; class logic_input_t; class analog_net_t; class logic_net_t; @@ -294,6 +295,32 @@ namespace netlist using desc_const_t = std::integral_constant<const T, V>; }; + //============================================================ + // 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 netlist diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h index 230b05f03c4..b0e21924dd7 100644 --- a/src/lib/netlist/plib/palloc.h +++ b/src/lib/netlist/plib/palloc.h @@ -10,9 +10,9 @@ #include "pconfig.h" #include "pgsl.h" +#include "pgsl.h" #include "pmath.h" // FIXME: only uses lcm ... move to ptypes. #include "ptypes.h" -#include "pgsl.h" #include <algorithm> #include <cstddef> // for std::max_align_t (usually long long) diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index 1fc2615ed42..526243d4e90 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -11,10 +11,10 @@ #include <array> #include <map> +#include <map> #include <stack> #include <type_traits> #include <utility> -#include <map> namespace plib { diff --git a/src/lib/netlist/plib/pmulti_threading.h b/src/lib/netlist/plib/pmulti_threading.h index b359af084e6..9f470054e2d 100644 --- a/src/lib/netlist/plib/pmulti_threading.h +++ b/src/lib/netlist/plib/pmulti_threading.h @@ -12,10 +12,10 @@ #include <algorithm> #include <atomic> +#include <condition_variable> #include <mutex> #include <type_traits> #include <utility> -#include <condition_variable> namespace plib { diff --git a/src/lib/netlist/plib/ptests.h b/src/lib/netlist/plib/ptests.h index 9755d49c240..e0faaf99bbb 100644 --- a/src/lib/netlist/plib/ptests.h +++ b/src/lib/netlist/plib/ptests.h @@ -10,11 +10,11 @@ /// google tests compatible (hopefully) test macros. This is work in progress! /// +#include <exception> +#include <functional> +#include <iostream> #include <string> #include <vector> -#include <iostream> -#include <functional> -#include <exception> #if defined(__clang__) #pragma clang diagnostic ignored "-Wglobal-constructors" @@ -115,7 +115,7 @@ namespace testing { using reg_entry_base::reg_entry_base; - virtual Test *create() const override { return new T(); } + Test *create() const override { return new T(); } }; template <typename C, typename T1, typename T2> diff --git a/src/lib/netlist/plib/ptimed_queue.h b/src/lib/netlist/plib/ptimed_queue.h index 5e62d5b82aa..fe60fadb75f 100644 --- a/src/lib/netlist/plib/ptimed_queue.h +++ b/src/lib/netlist/plib/ptimed_queue.h @@ -8,10 +8,10 @@ /// \file ptimed_queue.h /// +#include "palloc.h" // FIXME: for aligned_vector #include "pchrono.h" #include "pmulti_threading.h" #include "ptypes.h" -#include "palloc.h" // FIXME: for aligned_vector #include <algorithm> #include <mutex> diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp index b518e92918d..4076de4bd12 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.cpp +++ b/src/lib/netlist/solver/nld_matrix_solver.cpp @@ -2,9 +2,9 @@ // copyright-holders:Couriersud #include "nld_solver.h" -#include "nld_matrix_solver.h" #include "core/setup.h" #include "nl_setup.h" +#include "nld_matrix_solver.h" #include "plib/putil.h" namespace netlist diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h index 3d1a025d289..a5bda6a070e 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.h +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -80,7 +80,7 @@ namespace solver constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); } constexpr bool m_pivot() { return false; } constexpr nl_fptype m_nr_recalc_delay(){ return netlist_time::quantum().as_fp<nl_fptype>(); } - constexpr std::size_t m_parallel() { return 0; } + constexpr int m_parallel() { return 0; } constexpr nl_fptype m_min_ts_ts() { return nlconst::magic(1e-9); } // automatic time step diff --git a/src/lib/netlist/tests/test_pfunction.cpp b/src/lib/netlist/tests/test_pfunction.cpp index cb0cad8e188..60e6753b7ac 100644 --- a/src/lib/netlist/tests/test_pfunction.cpp +++ b/src/lib/netlist/tests/test_pfunction.cpp @@ -9,8 +9,8 @@ #include "plib/ptests.h" -#include "plib/pfunction.h" #include "plib/pexception.h" +#include "plib/pfunction.h" #define PFUNCEXPECT(formula, val) \ PEXPECT_EQ(val, plib::pfunction<double>(formula)()) |