diff options
author | 2022-06-10 16:11:21 +0200 | |
---|---|---|
committer | 2022-06-10 16:11:21 +0200 | |
commit | 1f3f5e0d574e256bc106ee4bc9ee701858585ca3 (patch) | |
tree | e471112c27fccd862215cf2c460d5471d546de86 /src | |
parent | 63e595ae364a6f9e6b3692af673d1a0c48523f2d (diff) |
netlist: fix bugs and more cpp instead of macros (#9897)
* netlist: fix bugs and more cpp instead of macros
- C-style comments converted to c++
- Fix crash in state saving code when an abort queue processing event
is pending.
- Fix a bug where a net could be twice in the queue.
- Convert more macros to c++
- fixed SUBTARGET=nl build
- fixed potential bugs which would allow a terminal to belong to more
than one net. This is not possible even for a short time.
- moved some member function definitions out-of-class.
- moved code out-of-class
- added constexpr where appropriate
- fixed mamenl build
- Cleanup and indentation
Diffstat (limited to 'src')
58 files changed, 2691 insertions, 2427 deletions
diff --git a/src/lib/netlist/analog/nld_mosfet.cpp b/src/lib/netlist/analog/nld_mosfet.cpp index b8d4454d206..46dead610ca 100644 --- a/src/lib/netlist/analog/nld_mosfet.cpp +++ b/src/lib/netlist/analog/nld_mosfet.cpp @@ -543,8 +543,8 @@ namespace analog const nl_fptype gbs = nlconst::zero(); #endif // exchange controlling nodes if necessary - const nl_fptype gsource = is_forward ? (gm + gmb) : nlconst::zero(); - const nl_fptype gdrain = is_forward ? nlconst::zero() : (gm + gmb); + const nl_fptype gate_source = is_forward ? (gm + gmb) : nlconst::zero(); + const nl_fptype gate_drain = is_forward ? nlconst::zero() : (gm + gmb); const nl_fptype IeqDS = (is_forward) ? Ids - gm * Vgs - gmb * Vbs - gds * Vds @@ -562,13 +562,13 @@ namespace analog nl_fptype gGB = nlconst::zero(); nl_fptype gDG = gm; - nl_fptype gDD = gds + gbd - gdrain; - const nl_fptype gDS = -gds - gsource; + nl_fptype gDD = gds + gbd - gate_drain; + const nl_fptype gDS = -gds - gate_source; const nl_fptype gDB = gmb - gbd; nl_fptype gSG = -gm; - const nl_fptype gSD = -gds + gdrain; - nl_fptype gSS = gbs + gds + gsource; + const nl_fptype gSD = -gds + gate_drain; + nl_fptype gSS = gbs + gds + gate_source; const nl_fptype gSB = -gbs - gmb; nl_fptype gBG = nlconst::zero(); diff --git a/src/lib/netlist/build/cspell.json b/src/lib/netlist/build/cspell.json index 43e72035b64..f242083ac82 100644 --- a/src/lib/netlist/build/cspell.json +++ b/src/lib/netlist/build/cspell.json @@ -31,8 +31,30 @@ "nmos", "opamp", "opamps", - "pmos", "picosecond", + "pmos", + // Physics + "atto", + "centi", + "deca", + "femto", + "giga", + "hecto", + "peta", + "tera", + "yocto", + "yotta", + "zepto", + "zetta", + // Software + "kicad", + // C library functions / definitions + "feenableexcept", + "fedisableexcept", + // asm + "rdtsc", + "rdtscp", + "cpuid", // Specific project terms "MAME", "Couriersud", @@ -43,6 +65,7 @@ "nvcc", "lfsr", "gmres", + "nlmod_", // FIXME: Remove everything below here again // Excluded for now ... Still over 1000 in the log "plib", // namespace diff --git a/src/lib/netlist/build/makefile b/src/lib/netlist/build/makefile index d0b13693686..91ae7140acf 100644 --- a/src/lib/netlist/build/makefile +++ b/src/lib/netlist/build/makefile @@ -49,6 +49,7 @@ TIDY_FLAGSX += -readability-implicit-bool-conversion, TIDY_FLAGSX += -readability-named-parameter,-readability-function-size, TIDY_FLAGSX += -llvmlibc-restrict-system-libc-headers,-llvmlibc-implementation-in-namespace,-llvmlibc-callee-namespace, TIDY_FLAGSX += -modernize-use-nodiscard, +TIDY_FLAGSX += -modernize-use-auto, #TIDY_FLAGSX += -cppcoreguidelines-pro-bounds-array-to-pointer-decay, #TIDY_FLAGSX += -cppcoreguidelines-prefer-member-initializer, #TIDY_FLAGSX += -modernize-use-transparent-functors, @@ -103,6 +104,7 @@ MD = @mkdir RM = @rm endif +CSPELL=cspell PYTHON=@python TIDY_DB = $(OBJ)/compile_commands.json @@ -289,10 +291,6 @@ native: gcc9: $(MAKE) CC=g++-9 LD=g++-9 CEXTRAFLAGS="-march=native -Wall -pedantic -Wpedantic -fext-numeric-literals -Wsign-compare -Wextra" EXTRALIBS="-lquadmath" OBJ=obj/gcc9 -emsdk: - emmake $(MAKE) CC=emcc LD=emcc CEXTRAFLAGS="-fexceptions -msimd128" LDEXTRAFLAGS="-s ALLOW_MEMORY_GROWTH=0 -s TOTAL_MEMORY=268435456 -fexceptions -msimd128 --emrun --embed-file ../../../mame/machine/nl_pong.cpp@nl_pong.cpp --embed-file ../../../mame/audio/nl_kidniki.cpp@nl_kidniki.cpp" OBJ=obj/emsdk EXESUFFIX=.html - # LDFLAGS -s ASSERTIONS=1 - clang: #$(MAKE) CC=clang++-11 LD=clang++-11 OBJ=obj/clang CEXTRAFLAGS="-march=native -msse4.2 -Weverything -Wall -pedantic -Wpedantic -Wunused-private-field -Wno-padded -Wno-unused-template -Wno-missing-variable-declarations -Wno-float-equal -Wconversion -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-format-nonliteral -Wno-exit-time-destructors" $(MAKE) CC=clang++-13 LD=clang++-13 OBJ=obj/clang CEXTRAFLAGS="-march=native \ @@ -343,6 +341,14 @@ mingw-cross: LDEXTRAFLAGS="-Wl,--subsystem,console -municode" OBJ=obj/mingw-cross \ EXESUFFIX=.exe LIBS= +# +# run with emrun --browser chrome nltool.html -c run -t 10 -n kidniki nl_kidniki.cpp +# +emsdk: + emmake $(MAKE) CC=emcc LD=emcc CEXTRAFLAGS="-fexceptions -msimd128" LDEXTRAFLAGS="-s ALLOW_MEMORY_GROWTH=0 -s TOTAL_MEMORY=268435456 -fexceptions -msimd128 --emrun --embed-file ../../../mame/machine/nl_pongf.cpp@nl_pongf.cpp --embed-file ../../../mame/audio/nl_kidniki.cpp@nl_kidniki.cpp" OBJ=obj/emsdk EXESUFFIX=.html + # LDFLAGS -s ASSERTIONS=1 + + #------------------------------------------------- # regression tests #------------------------------------------------- @@ -365,8 +371,8 @@ doc: $(DOXYGEN) doxygen.conf cspell: - cd .. && cspell -c build/cspell.json --no-color --locale en-GB --relative $(patsubst $(SRC)/%, %, $(ALLHEADERS) ) | sed -e "s/ - Unknown/: error: Unknown/g" - #cd .. && cspell -c build/cspell.json --no-color --locale en-GB --relative $(patsubst $(SRC)/%, %, $(ALLHEADERS) $(ALLSOURCES)) | sed -e "s/ - Unknown/: error: Unknown/g" + #cd .. && cspell -c build/cspell.json --no-color --locale en-GB --relative $(patsubst $(SRC)/%, %, $(ALLHEADERS) ) | sed -e "s/ - Unknown/: error: Unknown/g" + cd .. && $(CSPELL) -c build/cspell.json --no-color --locale en-GB --relative $(patsubst $(SRC)/%, %, $(ALLHEADERS) $(ALLSOURCES)) | sed -e "s/ - Unknown/: error: Unknown/g" #------------------------------------------------- # depends @@ -420,7 +426,7 @@ fix_permissions: srcclean: $(ALLSOURCES) $(ALLHEADERS) @../../../../srcclean -u $(ALLSOURCES) $(ALLHEADERS) -precommit: fix_permissions srcclean +precommit: fix_permissions srcclean all runtests #------------------------------------------------- # clang tidy diff --git a/src/lib/netlist/core/base_objects.h b/src/lib/netlist/core/base_objects.h index 20fce1c91ca..782d94cf572 100644 --- a/src/lib/netlist/core/base_objects.h +++ b/src/lib/netlist/core/base_objects.h @@ -58,8 +58,8 @@ namespace netlist::detail { static store_type &store() noexcept { - static store_type lstore; - return lstore; + static store_type static_store; + return static_store; } }; @@ -131,8 +131,8 @@ namespace netlist::detail { 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; } + constexpr netlist_t & exec() noexcept { return m_netlist; } + constexpr const netlist_t & exec() const noexcept { return m_netlist; } // to ease template design template <typename T, typename... Args> @@ -192,14 +192,17 @@ namespace netlist::detail { /// /// All terminals are derived from this class. /// - class core_terminal_t : public device_object_t, - public plib::linked_list_t<core_terminal_t>::element_t + class core_terminal_t : public device_object_t + , public plib::linked_list_t<core_terminal_t, 0>::element_t +#if NL_USE_INPLACE_CORE_TERMS + , public plib::linked_list_t<core_terminal_t, 1>::element_t +#endif { 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 + /// buses to be used in netlist, e.g. for more complex memory /// arrangements. /// Minimum value is 2 here to support tristate output on proxies. static constexpr const unsigned int INP_BITS = 2; @@ -240,7 +243,7 @@ namespace netlist::detail { void clear_net() noexcept { m_net = nullptr; } constexpr bool has_net() const noexcept { return (m_net != nullptr); } - net_t & net() const noexcept { return *m_net;} + constexpr net_t & net() const noexcept { return *m_net;} bool is_logic() const noexcept; bool is_logic_input() const noexcept; @@ -250,25 +253,26 @@ namespace netlist::detail { bool is_analog_input() const noexcept; bool is_analog_output() const noexcept; - constexpr bool is_state(state_e astate) const noexcept { return (m_state == astate); } - constexpr const state_e &terminal_state() const noexcept { return m_state; } - void set_state(state_e astate) noexcept { m_state = astate; } + constexpr bool is_state(state_e state) const noexcept { return (m_state == state); } + constexpr state_e terminal_state() const noexcept { return m_state; } + constexpr void set_state(state_e state) noexcept { m_state = state; } 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 + constexpr void set_copied_input([[maybe_unused]] netlist_sig_t val) noexcept { - m_Q = val; + if constexpr (config::use_copy_instead_of_reference::value) + { + m_Q_CIR = val; + } } - state_var_sig m_Q; -#else - void set_copied_input([[maybe_unused]] const netlist_sig_t &val) const noexcept { } // NOLINT: static means more message elsewhere -#endif void set_delegate(const nl_delegate &delegate) noexcept { m_delegate = delegate; } const nl_delegate &delegate() const noexcept { return m_delegate; } void run_delegate() const noexcept { return m_delegate(); } + protected: + //std::conditional_t<config::use_copy_instead_of_reference::value, state_var_sig, void *> m_Q; + state_var_sig m_Q_CIR; private: nl_delegate m_delegate; net_t * m_net; diff --git a/src/lib/netlist/core/core_device.h b/src/lib/netlist/core/core_device.h index f7f05427f54..b81835b716e 100644 --- a/src/lib/netlist/core/core_device.h +++ b/src/lib/netlist/core/core_device.h @@ -25,35 +25,16 @@ namespace netlist 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) + core_device_t(const core_device_t &) = delete; + core_device_t &operator=(const core_device_t &) = delete; + core_device_t(core_device_t &&) noexcept = delete; + core_device_t &operator=(core_device_t &&) noexcept = delete; virtual ~core_device_t() noexcept = default; - void do_inc_active() noexcept - { - gsl_Expects(m_active_outputs >= 0); - - if (!m_activate.isnull() && m_hint_deactivate) - { - if (++m_active_outputs == 1) - { - if (m_stats) - m_stats->m_stat_inc_active.inc(); - m_activate(true);//inc_active(); - } - } - } + void do_inc_active() noexcept; - void do_dec_active() noexcept - { - gsl_Expects(m_active_outputs >= 1); - - if (!m_activate.isnull() && m_hint_deactivate) - if (--m_active_outputs == 0) - { - m_activate(false); //dec_active(); - } - } + void do_dec_active() noexcept; void set_hint_deactivate(bool v) noexcept { m_hint_deactivate = v; } bool get_hint_deactivate() const noexcept { return m_hint_deactivate; } @@ -94,11 +75,39 @@ namespace netlist virtual bool is_time_step() const noexcept { return false; } private: + // FIXME: should this be a state_var? bool m_hint_deactivate; state_var_s32 m_active_outputs; device_arena::unique_ptr<stats_t> m_stats; }; + inline void core_device_t::do_inc_active() noexcept + { + gsl_Expects(m_active_outputs >= 0); + + if (!m_activate.isnull() && m_hint_deactivate) + { + if (++m_active_outputs == 1) + { + if (m_stats) + m_stats->m_stat_inc_active.inc(); + m_activate(true);//inc_active(); + } + } + } + + inline void core_device_t::do_dec_active() noexcept + { + gsl_Expects(m_active_outputs >= 1); + + if (!m_activate.isnull() && m_hint_deactivate) + if (--m_active_outputs == 0) + { + m_activate(false); //dec_active(); + } + } + + // ----------------------------------------------------------------------------- // base_device_t // ----------------------------------------------------------------------------- diff --git a/src/lib/netlist/core/device.h b/src/lib/netlist/core/device.h index 74486a2dc80..33a1bdaac35 100644 --- a/src/lib/netlist/core/device.h +++ b/src/lib/netlist/core/device.h @@ -33,11 +33,30 @@ namespace netlist device_t(device_t &owner, const pstring &name, const pstring &model); - PCOPYASSIGNMOVE(device_t, delete) + device_t(const device_t &) = delete; + device_t &operator=(const device_t &) = delete; + device_t(device_t &&) noexcept = delete; + device_t &operator=(device_t &&) noexcept = delete; ~device_t() noexcept override = default; protected: + template <typename T1, typename T2> + void push_two(T1 &term1, netlist_sig_t newQ1, const netlist_time &delay1, + T2 &term2, netlist_sig_t newQ2, const netlist_time &delay2) noexcept + { + if (delay2 < delay1) + { + term1.push(newQ1, delay1); + term2.push(newQ2, delay2); + } + else + { + term2.push(newQ2, delay2); + term1.push(newQ1, delay1); + } + } + //NETLIB_UPDATE_TERMINALSI() { } private: diff --git a/src/lib/netlist/core/devices.h b/src/lib/netlist/core/devices.h index 52e33b7d96c..07c82be20da 100644 --- a/src/lib/netlist/core/devices.h +++ b/src/lib/netlist/core/devices.h @@ -136,6 +136,9 @@ namespace netlist::devices // ----------------------------------------------------------------------------- // nld_nc_pin + // + // FIXME: This needs to optimized + // The input can be in de-activated state. // ----------------------------------------------------------------------------- NETLIB_OBJECT(nc_pin) diff --git a/src/lib/netlist/core/exec.h b/src/lib/netlist/core/exec.h index 83a41239d91..70786d420e6 100644 --- a/src/lib/netlist/core/exec.h +++ b/src/lib/netlist/core/exec.h @@ -27,39 +27,42 @@ namespace netlist explicit netlist_t(netlist_state_t &state, const pstring &aname); - PCOPYASSIGNMOVE(netlist_t, delete) + netlist_t(const netlist_t &) = delete; + netlist_t &operator=(const netlist_t &) = delete; + netlist_t(netlist_t &&) noexcept = delete; + netlist_t &operator=(netlist_t &&) noexcept = delete; virtual ~netlist_t() noexcept = default; // run functions - const netlist_time_ext &time() const noexcept { return m_time; } + constexpr const netlist_time_ext &time() const noexcept { return m_time; } void process_queue(netlist_time_ext delta) noexcept; void abort_current_queue_slice() noexcept { - qremove(nullptr); - qpush(m_time, nullptr); + queue_remove(nullptr); + queue_push(m_time, nullptr); } - const detail::queue_t &queue() const noexcept { return m_queue; } + constexpr const detail::queue_t &queue() const noexcept { return m_queue; } template <typename... Args> - void qpush(Args&&...args) noexcept + void queue_push(Args&&...args) noexcept { if (config::use_queue_stats::value && m_use_stats) - m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg) - else m_queue.emplace<true>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg) + else + m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg) } template <class R> - void qremove(const R &elem) noexcept + void queue_remove(R &&elem) noexcept { if (config::use_queue_stats::value && m_use_stats) - m_queue.remove<true>(elem); + m_queue.remove<true>(std::forward<R>(elem)); else - m_queue.remove<false>(elem); + m_queue.remove<false>(std::forward<R>(elem)); } // Control functions diff --git a/src/lib/netlist/core/logic.h b/src/lib/netlist/core/logic.h index fef1f848052..2efa92d8f6d 100644 --- a/src/lib/netlist/core/logic.h +++ b/src/lib/netlist/core/logic.h @@ -36,7 +36,7 @@ namespace netlist { return plib::downcast<logic_net_t &>(core_terminal_t::net()); } - const logic_net_t & net() const noexcept + constexpr const logic_net_t & net() const noexcept { return plib::downcast<const logic_net_t &>(core_terminal_t::net()); } @@ -52,14 +52,14 @@ namespace netlist logic_input_t(device_t &dev, const pstring &aname, nl_delegate delegate); - const netlist_sig_t &operator()() const noexcept + //const netlist_sig_t &operator()() const noexcept + constexpr netlist_sig_t operator()() const noexcept { gsl_Expects(terminal_state() != STATE_INP_PASSIVE); - #if NL_USE_COPY_INSTEAD_OF_REFERENCE - return m_Q; - #else - return net().Q(); - #endif + if constexpr (config::use_copy_instead_of_reference::value) + return m_Q_CIR; + else + return net().Q(); } void inactivate() noexcept @@ -97,6 +97,7 @@ namespace netlist set_state(STATE_INP_LH); } } + }; // ----------------------------------------------------------------------------- @@ -120,14 +121,14 @@ namespace netlist void initial(netlist_sig_t val) noexcept; - void push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept + void push(netlist_sig_t newQ, const netlist_time &delay) noexcept { gsl_Expects(delay >= netlist_time::zero()); m_my_net.set_Q_and_push(newQ, delay); // take the shortcut } - void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept + void set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept { m_my_net.set_Q_time(newQ, at); // take the shortcut } diff --git a/src/lib/netlist/core/logic_family.h b/src/lib/netlist/core/logic_family.h index 5a225a11c3e..7264987b466 100644 --- a/src/lib/netlist/core/logic_family.h +++ b/src/lib/netlist/core/logic_family.h @@ -25,7 +25,12 @@ namespace netlist { } - PCOPYASSIGNMOVE(logic_family_desc_t, delete) + logic_family_desc_t(const logic_family_desc_t &) = delete; + logic_family_desc_t &operator=(const logic_family_desc_t &) = delete; + + // FOXME: Should be move constructible + logic_family_desc_t(logic_family_desc_t &&) noexcept = delete; + logic_family_desc_t &operator=(logic_family_desc_t &&) noexcept = delete; virtual ~logic_family_desc_t() noexcept = default; @@ -76,7 +81,13 @@ namespace netlist 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) + + logic_family_t(const logic_family_t &) = delete; + logic_family_t &operator=(const logic_family_t &) = delete; + + // FIXME: logic family can be move constructible. + logic_family_t(logic_family_t &&) noexcept = delete; + logic_family_t &operator=(logic_family_t &&) noexcept = 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; } diff --git a/src/lib/netlist/core/netlist_state.h b/src/lib/netlist/core/netlist_state.h index 5e8ae4567ec..0f0b62f8bee 100644 --- a/src/lib/netlist/core/netlist_state.h +++ b/src/lib/netlist/core/netlist_state.h @@ -235,12 +235,12 @@ namespace netlist /// \brief prior to running free no longer needed resources /// void free_setup_resources(); - - std::vector<detail::core_terminal_t *> &core_terms(const detail::net_t &net) noexcept +#if !(NL_USE_INPLACE_CORE_TERMS) + std::vector<detail::core_terminal_t *> &core_terms(const detail::net_t &net) { return m_core_terms[&net]; } - +#endif private: device_arena m_pool; // must be deleted last! @@ -258,8 +258,10 @@ namespace netlist devices_collection_type m_devices; // sole use is to manage lifetime of family objects family_collection_type m_family_cache; +#if !(NL_USE_INPLACE_CORE_TERMS) // all terms for a net std::unordered_map<const detail::net_t *, std::vector<detail::core_terminal_t *>> m_core_terms; +#endif // dummy version int m_dummy_version; }; diff --git a/src/lib/netlist/core/nets.h b/src/lib/netlist/core/nets.h index a121f261a50..280cda2013e 100644 --- a/src/lib/netlist/core/nets.h +++ b/src/lib/netlist/core/nets.h @@ -17,13 +17,10 @@ #include "../plib/plists.h" #include "../plib/pstring.h" -#ifndef AVOID_NOOP_QUEUE_PUSHES -#error AVOID_NOOP_QUEUE_PUSHES not defined -#endif +#include <algorithm> namespace netlist { - namespace detail { // ----------------------------------------------------------------------------- @@ -43,7 +40,10 @@ namespace netlist net_t(netlist_state_t &nl, const pstring &aname, core_terminal_t *rail_terminal = nullptr); - PCOPYASSIGNMOVE(net_t, delete) + net_t(const net_t &) = delete; + net_t &operator=(const net_t &) = delete; + net_t(net_t &&) noexcept = delete; + net_t &operator=(net_t &&) noexcept = delete; virtual ~net_t() noexcept = default; @@ -55,7 +55,10 @@ namespace netlist // Any changes below will impact performance. // ----------------------------------------------------------------------------- - void toggle_new_Q() noexcept { m_new_Q = (m_cur_Q ^ 1); } + constexpr void toggle_new_Q() noexcept + { + m_new_Q = (m_cur_Q ^ 1); + } void toggle_and_push_to_queue(const netlist_time &delay) noexcept { @@ -63,133 +66,28 @@ namespace netlist push_to_queue(delay); } - void push_to_queue(const netlist_time &delay) noexcept - { - if (!!is_queued()) - exec().qremove(this); + void push_to_queue(const netlist_time &delay) noexcept; - m_next_scheduled_time = exec().time() + delay; -#if (AVOID_NOOP_QUEUE_PUSHES) - m_in_queue = (m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE - : (m_new_Q != m_cur_Q ? queue_status::QUEUED : queue_status::DELIVERED)); - if (m_in_queue == queue_status::QUEUED) - exec().qpush(m_next_scheduled_time, this); - else - update_inputs(); -#else - m_in_queue = m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE : queue_status::QUEUED; - if (m_in_queue == queue_status::QUEUED) - exec().qpush(m_next_scheduled_time, this); - else - update_inputs(); -#endif + constexpr bool is_queued() const noexcept + { + return m_in_queue == queue_status::QUEUED; } - constexpr bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; } // ----------------------------------------------------------------------------- // Very hot // ----------------------------------------------------------------------------- template <bool KEEP_STATS> - void update_devs() noexcept - { - gsl_Expects(this->is_rail_net()); - - m_in_queue = queue_status::DELIVERED; // mark as taken ... - - const netlist_sig_t new_Q(m_new_Q); - const netlist_sig_t cur_Q(m_cur_Q); -#if (!AVOID_NOOP_QUEUE_PUSHES) - if (new_Q ^ cur_Q) -#endif - { - const auto mask = (new_Q << core_terminal_t::INP_LH_SHIFT) - | (cur_Q << core_terminal_t::INP_HL_SHIFT); - m_cur_Q = new_Q; - - if (!KEEP_STATS) - { - for (auto &p : m_list_active) - { - p.set_copied_input(new_Q); - if ((p.terminal_state() & mask) != 0) - p.run_delegate(); - } - } - else - { - for (auto & p : m_list_active) - { - p.set_copied_input(new_Q); - auto *stats(p.device().stats()); - stats->m_stat_call_count.inc(); - if ((p.terminal_state() & mask)) - { - auto g(stats->m_stat_total_time.guard()); - p.run_delegate(); - } - } - } - } - } + void update_devs() noexcept; constexpr const netlist_time_ext &next_scheduled_time() const noexcept { return m_next_scheduled_time; } - void set_next_scheduled_time(netlist_time_ext next_time) noexcept { m_next_scheduled_time = next_time; } + void set_next_scheduled_time(const netlist_time_ext &next_time) noexcept { m_next_scheduled_time = next_time; } bool is_rail_net() const noexcept { return !(m_rail_terminal == nullptr); } core_terminal_t & rail_terminal() const noexcept { return *m_rail_terminal; } - void add_to_active_list(core_terminal_t &term) noexcept - { - if (!m_list_active.empty()) - { - term.set_copied_input(m_cur_Q); - m_list_active.push_front(&term); - } - else - { - m_list_active.push_front(&term); - rail_terminal().device().do_inc_active(); - if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE) - { -#if (AVOID_NOOP_QUEUE_PUSHES) - if (m_next_scheduled_time > exec().time() - && (m_cur_Q != m_new_Q)) -#else - if (m_next_scheduled_time > exec().time()) -#endif - { - m_in_queue = queue_status::QUEUED; // pending - exec().qpush(m_next_scheduled_time, this); - } - else - { - m_in_queue = queue_status::DELIVERED; - m_cur_Q = m_new_Q; - } - update_inputs(); - } - else - term.set_copied_input(m_cur_Q); - } - } - - void remove_from_active_list(core_terminal_t &term) noexcept - { - gsl_Expects(!m_list_active.empty()); - m_list_active.remove(&term); - if (m_list_active.empty()) - { -#if (AVOID_NOOP_QUEUE_PUSHES) - if (!!is_queued()) - { - exec().qremove(this); - m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE; - } -#endif - rail_terminal().device().do_dec_active(); - } - } + void add_to_active_list(core_terminal_t &term) noexcept; + void remove_from_active_list(core_terminal_t &term) noexcept; // ----------------------------------------------------------------------------- // setup stuff - cold @@ -200,17 +98,31 @@ namespace netlist void rebuild_list(); // rebuild m_list after a load - //std::vector<core_terminal_t *> &core_terms() noexcept { return state().m_core_terms[this]; } - 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 + if constexpr (config::use_copy_instead_of_reference::value) + { + for (auto *term : core_terms_ref()) + term->set_copied_input(m_cur_Q); + } + } + + // ----------------------------------------------------------------------------- + // net management + // ----------------------------------------------------------------------------- + + const std::vector<detail::core_terminal_t *> core_terms_copy() + { + std::vector<detail::core_terminal_t *> ret(core_terms_ref().size()); + std::copy(core_terms_ref().begin(), core_terms_ref().end(), ret.begin()); + return ret; } + void remove_terminal(detail::core_terminal_t &term); + void remove_all_terminals(); + void add_terminal(detail::core_terminal_t &terminal); + + bool core_terms_empty() noexcept { return core_terms_ref().empty(); } protected: // only used for logic nets @@ -224,49 +136,188 @@ namespace netlist } // only used for logic nets - void set_Q_and_push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept + void set_Q_and_push(netlist_sig_t newQ, const netlist_time &delay) noexcept; + + // only used for logic nets + void set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept; + + + private: +#if NL_USE_INPLACE_CORE_TERMS + const plib::linked_list_t<core_terminal_t, 1> &core_terms_ref() const noexcept { - gsl_Expects(delay >= netlist_time::zero()); + return m_core_terms; + } +#else + std::vector<detail::core_terminal_t *> &core_terms_ref() + { + return state().core_terms(*this); + } +#endif + state_var<netlist_sig_t> m_new_Q; + state_var<netlist_sig_t> m_cur_Q; + state_var<queue_status> m_in_queue; + // FIXME: this needs to be saved as well + plib::linked_list_t<core_terminal_t, 0> m_list_active; + state_var<netlist_time_ext> m_next_scheduled_time; + + core_terminal_t * m_rail_terminal; +#if NL_USE_INPLACE_CORE_TERMS + plib::linked_list_t<core_terminal_t, 1> m_core_terms; +#endif + }; + + inline void net_t::push_to_queue(const netlist_time &delay) noexcept + { + if (is_queued()) + exec().queue_remove(this); + + m_next_scheduled_time = exec().time() + delay; + if constexpr (config::avoid_noop_queue_pushes::value) + m_in_queue = (m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE + : (m_new_Q != m_cur_Q ? queue_status::QUEUED : queue_status::DELIVERED)); + else + m_in_queue = m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE : queue_status::QUEUED; + + if (m_in_queue == queue_status::QUEUED) + exec().queue_push(m_next_scheduled_time, this); + else + update_inputs(); + } + + template <bool KEEP_STATS> + void net_t::update_devs() noexcept + { + gsl_Expects(this->is_rail_net()); - if (newQ != m_new_Q) + m_in_queue = queue_status::DELIVERED; // mark as taken ... + + const netlist_sig_t new_Q(m_new_Q); + const netlist_sig_t cur_Q(m_cur_Q); + if (config::avoid_noop_queue_pushes::value || ((new_Q ^ cur_Q) != 0)) + { + m_cur_Q = new_Q; + const auto mask = (new_Q << core_terminal_t::INP_LH_SHIFT) + | (cur_Q << core_terminal_t::INP_HL_SHIFT); + + if (!KEEP_STATS) { - m_new_Q = newQ; - push_to_queue(delay); + for (core_terminal_t * p: m_list_active) + { + p->set_copied_input(new_Q); + if ((p->terminal_state() & mask) != 0) + p->run_delegate(); + } + } + else + { + for (core_terminal_t * p : m_list_active) + { + p->set_copied_input(new_Q); + auto *stats(p->device().stats()); + stats->m_stat_call_count.inc(); + if ((p->terminal_state() & mask)) + { + auto g(stats->m_stat_total_time.guard()); + p->run_delegate(); + } + } } } + } - // only used for logic nets - void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept + inline void net_t::add_to_active_list(core_terminal_t &term) noexcept + { + if (!m_list_active.empty()) { - gsl_Expects(at >= netlist_time_ext::zero()); - - if (newQ != m_new_Q) + term.set_copied_input(m_cur_Q); + m_list_active.push_front(&term); + } + else + { + m_list_active.push_front(&term); + rail_terminal().device().do_inc_active(); + if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE) { - m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE; - m_next_scheduled_time = at; - m_cur_Q = m_new_Q = newQ; + // if we avoid queue pushes we must test if m_cur_Q and m_new_Q are equal + if ((!config::avoid_noop_queue_pushes::value || (m_cur_Q != m_new_Q)) + && (m_next_scheduled_time > exec().time())) + { + m_in_queue = queue_status::QUEUED; // pending + exec().queue_push(m_next_scheduled_time, this); + } + else + { + m_in_queue = queue_status::DELIVERED; + m_cur_Q = m_new_Q; + } update_inputs(); } else + term.set_copied_input(m_cur_Q); + } + } + + inline void net_t::remove_from_active_list(core_terminal_t &term) noexcept + { + gsl_Expects(!m_list_active.empty()); + m_list_active.remove(&term); + if (m_list_active.empty()) + { + if constexpr (true || config::avoid_noop_queue_pushes::value) { - m_cur_Q = newQ; - update_inputs(); + // All our connected outputs have signalled they no longer + // will act on input. We thus remove any potentially queued + // events and mark them. + // FIXME: May cause regression test to fail - revisit in this case + // + // This code is definitively needed for the + // AVOID_NOOP_QUEUE_PUSHES code path - therefore I left + // the if statement in and enabled it for all code paths + if (is_queued()) + { + exec().queue_remove(this); + m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE; + } } + rail_terminal().device().do_dec_active(); } + } - private: - state_var<netlist_sig_t> m_new_Q; - state_var<netlist_sig_t> m_cur_Q; - state_var<queue_status> m_in_queue; - plib::linked_list_t<core_terminal_t> m_list_active; - state_var<netlist_time_ext> m_next_scheduled_time; + // only used for logic nets + inline void net_t::set_Q_and_push(netlist_sig_t newQ, const netlist_time &delay) noexcept + { + gsl_Expects(delay >= netlist_time::zero()); - core_terminal_t * m_rail_terminal; - //std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ... + if (newQ != m_new_Q) + { + m_new_Q = newQ; + push_to_queue(delay); + } + } + + // only used for logic nets + inline void net_t::set_Q_time(netlist_sig_t newQ, const netlist_time_ext &at) noexcept + { + gsl_Expects(at >= netlist_time_ext::zero()); + + 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(); + } + } - }; } // namespace detail + class analog_net_t : public detail::net_t { public: diff --git a/src/lib/netlist/core/object_array.h b/src/lib/netlist/core/object_array.h index 69528796303..08b66a64990 100644 --- a/src/lib/netlist/core/object_array.h +++ b/src/lib/netlist/core/object_array.h @@ -133,7 +133,7 @@ namespace netlist private: template <std::size_t P> - constexpr const value_type &e() const { return (*this)[P](); } + constexpr value_type e() const { return (*this)[P](); } }; template<std::size_t N> @@ -174,7 +174,7 @@ namespace netlist } template<typename T, std::size_t NT> - void push(const T &v, const std::array<netlist_time, NT> &t) + void push(const T &v, const std::array<const netlist_time, NT> &t) { static_assert(NT >= N, "Not enough timing entries provided"); diff --git a/src/lib/netlist/core/param.h b/src/lib/netlist/core/param.h index 52f086cf6f0..388ccebc1ba 100644 --- a/src/lib/netlist/core/param.h +++ b/src/lib/netlist/core/param.h @@ -101,8 +101,8 @@ namespace netlist 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; } + constexpr T operator()() const noexcept { return m_param; } + constexpr operator T() const noexcept { return m_param; } void set(const T ¶m) noexcept { set_and_update_param(m_param, param); } pstring value_string() const override diff --git a/src/lib/netlist/core/queue.h b/src/lib/netlist/core/queue.h index d8b95ac86e7..19600f0198c 100644 --- a/src/lib/netlist/core/queue.h +++ b/src/lib/netlist/core/queue.h @@ -25,14 +25,6 @@ namespace netlist::detail { - // Use timed_queue_heap to use stdc++ heap functions instead of linear processing. - // This slows down processing by about 35% on a Kaby Lake. - // template <class A, class T, bool TS> - // using timed_queue = plib::timed_queue_heap<A, T, TS>; - - template <typename A, typename T, bool TS> - using timed_queue = plib::timed_queue_linear<A, T, TS>; - // ----------------------------------------------------------------------------- // queue_t // ----------------------------------------------------------------------------- @@ -40,19 +32,19 @@ namespace netlist::detail // We don't need a thread-safe queue currently. Parallel processing of // solvers will update inputs after parallel processing. - template <typename A, typename O, bool TS> + template <typename A, typename O> class queue_base : - public timed_queue<A, plib::queue_entry_t<netlist_time_ext, O *>, false>, + public config::timed_queue<A, plib::queue_entry_t<netlist_time_ext, O *>>, public plib::state_manager_t::callback_t { public: using entry_t = plib::queue_entry_t<netlist_time_ext, O *>; - using base_queue = timed_queue<A, entry_t, false>; + using base_queue = config::timed_queue<A, entry_t>; using id_delegate = plib::pmfp<std::size_t (const O *)>; using obj_delegate = plib::pmfp<O * (std::size_t)>; explicit queue_base(A &arena, std::size_t size, id_delegate get_id, obj_delegate get_obj) - : timed_queue<A, plib::queue_entry_t<netlist_time_ext, O *>, false>(arena, size) + : base_queue(arena, size) , m_size(0) , m_times(size) , m_net_ids(size) @@ -72,7 +64,7 @@ namespace netlist::detail void register_state(plib::state_manager_t &manager, const pstring &module) override { - manager.save_item(this, m_size, module + "." + "qsize"); + manager.save_item(this, m_size, module + "." + "size"); 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()); } @@ -103,7 +95,7 @@ namespace netlist::detail obj_delegate m_obj_by_id; }; - using queue_t = queue_base<device_arena, net_t, false>; + using queue_t = queue_base<device_arena, net_t>; } // namespace netlist::detail diff --git a/src/lib/netlist/core/setup.h b/src/lib/netlist/core/setup.h index 5171d1428e8..ddf1aa14889 100644 --- a/src/lib/netlist/core/setup.h +++ b/src/lib/netlist/core/setup.h @@ -95,7 +95,7 @@ namespace netlist // need to preserve order of device creation ... std::vector<std::pair<pstring, factory::element_t *>> m_device_factory; // lifetime control only - can be cleared before run - std::vector<std::pair<pstring, pstring>> m_defparams; + std::vector<std::pair<pstring, pstring>> m_default_params; std::unordered_map<pstring, bool> m_hints; factory::list_t m_factory; }; @@ -188,9 +188,6 @@ namespace netlist log_type &log() noexcept; const log_type &log() const noexcept; - // FIXME: needed from matrix_solver_t - void add_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false); - private: void resolve_inputs(); @@ -215,7 +212,7 @@ namespace netlist // net manipulations - void remove_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false); + //void remove_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false); void move_connections(detail::net_t &net, detail::net_t &dest_net); void delete_empty_nets(); diff --git a/src/lib/netlist/core/state_var.h b/src/lib/netlist/core/state_var.h index 7791a8604d6..88f9a072a1f 100644 --- a/src/lib/netlist/core/state_var.h +++ b/src/lib/netlist/core/state_var.h @@ -47,7 +47,8 @@ namespace netlist const pstring &name //!< identifier/name for this state variable ); - PMOVEASSIGN(state_var, delete) + state_var(state_var &&) noexcept = delete; + state_var &operator=(state_var &&) noexcept = delete; //! Destructor. ~state_var() noexcept = default; @@ -195,7 +196,7 @@ namespace netlist namespace plib { template <typename X> - struct ptype_traits<netlist::state_var<X>> : ptype_traits<X> + struct format_traits<netlist::state_var<X>> : format_traits<X> { }; } // namespace plib diff --git a/src/lib/netlist/devices/nld_74107.cpp b/src/lib/netlist/devices/nld_74107.cpp index 4433ba6b98b..1501be4763e 100644 --- a/src/lib/netlist/devices/nld_74107.cpp +++ b/src/lib/netlist/devices/nld_74107.cpp @@ -100,6 +100,8 @@ namespace netlist::devices { NETLIB_HANDLERI(clk) { + const netlist_sig_t J(m_J()); + const netlist_sig_t K(m_K()); const netlist_sig_t t(m_Q.net().Q()); /* * J K Q1 Q2 F t Q @@ -112,12 +114,12 @@ namespace netlist::devices { * 1 0 0 0 1 1 1 * 1 1 1 0 0 1 0 */ - if ((m_J() & m_K()) ^ 1) + if ((J & K) ^ 1) m_clk.inactivate(); - newstate(((t ^ 1) & m_J()) | (t & (m_K() ^ 1))); + newstate(((t ^ 1) & J) | (t & (K ^ 1))); } - void newstate(const netlist_sig_t state) + void newstate(const netlist_sig_t state) noexcept { m_Q.push(state, D::delay::value(state)); m_QQ.push(state ^ 1, D::delay::value(state ^ 1)); diff --git a/src/lib/netlist/devices/nld_7474.cpp b/src/lib/netlist/devices/nld_7474.cpp index e1f5027599e..f79d38c5e0f 100644 --- a/src/lib/netlist/devices/nld_7474.cpp +++ b/src/lib/netlist/devices/nld_7474.cpp @@ -103,7 +103,7 @@ namespace netlist::devices { nld_power_pins m_power_pins; - void newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ) + void newstate(const netlist_sig_t stateQ, const netlist_sig_t stateQQ) noexcept { // 0: High-to-low 40 ns, 1: Low-to-high 25 ns static constexpr const std::array<netlist_time, 2> delay = { NLTIME_FROM_NS(40), NLTIME_FROM_NS(25) }; diff --git a/src/lib/netlist/devices/nld_7490.cpp b/src/lib/netlist/devices/nld_7490.cpp index 1415fc95b13..7bcf1f7b214 100644 --- a/src/lib/netlist/devices/nld_7490.cpp +++ b/src/lib/netlist/devices/nld_7490.cpp @@ -56,7 +56,7 @@ namespace netlist::devices { - static constexpr const std::array<netlist_time, 4> delay = + static constexpr const std::array<const netlist_time, 4> delay = { NLTIME_FROM_NS(18), NLTIME_FROM_NS(36) - NLTIME_FROM_NS(18), diff --git a/src/lib/netlist/devices/nld_7492.cpp b/src/lib/netlist/devices/nld_7492.cpp index 7d14591b88d..1689ff0dd9d 100644 --- a/src/lib/netlist/devices/nld_7492.cpp +++ b/src/lib/netlist/devices/nld_7492.cpp @@ -54,7 +54,7 @@ namespace netlist::devices { - static constexpr const std::array<netlist_time, 4> delay = + static constexpr const std::array<const netlist_time, 4> delay = { NLTIME_FROM_NS(18), NLTIME_FROM_NS(36) - NLTIME_FROM_NS(18), diff --git a/src/lib/netlist/devices/nld_7493.cpp b/src/lib/netlist/devices/nld_7493.cpp index 2b1a01389a4..a6d80fd551b 100644 --- a/src/lib/netlist/devices/nld_7493.cpp +++ b/src/lib/netlist/devices/nld_7493.cpp @@ -59,7 +59,7 @@ namespace netlist::devices { - static constexpr std::array<netlist_time, 3> out_delay { NLTIME_FROM_NS(18), NLTIME_FROM_NS(36), NLTIME_FROM_NS(54) }; + static constexpr const std::array<const netlist_time, 3> out_delay { NLTIME_FROM_NS(18), NLTIME_FROM_NS(36), NLTIME_FROM_NS(54) }; NETLIB_OBJECT(7493) { @@ -67,7 +67,7 @@ namespace netlist::devices { , m_CLKA(*this, "CLKA", NETLIB_DELEGATE(updA)) , m_CLKB(*this, "CLKB", NETLIB_DELEGATE(updB)) , m_QA(*this, "QA") - , m_QB(*this, {"QB", "QC", "QD"}) + , m_QBCD(*this, {"QB", "QC", "QD"}) , m_a(*this, "m_a", 0) , m_bcd(*this, "m_b", 0) , m_R1(*this, "R1", NETLIB_DELEGATE(inputs)) @@ -96,7 +96,7 @@ namespace netlist::devices { m_CLKA.inactivate(); m_CLKB.inactivate(); m_QA.push(0, NLTIME_FROM_NS(40)); - m_QB.push(0, NLTIME_FROM_NS(40)); + m_QBCD.push(0, NLTIME_FROM_NS(40)); m_a = m_bcd = 0; } } @@ -110,14 +110,14 @@ namespace netlist::devices { NETLIB_HANDLERI(updB) { const auto cnt(++m_bcd &= 0x07); - m_QB.push(cnt, out_delay); + m_QBCD.push(cnt, out_delay); } logic_input_t m_CLKA; logic_input_t m_CLKB; logic_output_t m_QA; - object_array_t<logic_output_t, 3> m_QB; + object_array_t<logic_output_t, 3> m_QBCD; state_var<unsigned> m_a; state_var<unsigned> m_bcd; diff --git a/src/lib/netlist/devices/nld_ne555.cpp b/src/lib/netlist/devices/nld_ne555.cpp index 5367ed0648e..b6b444fe04d 100644 --- a/src/lib/netlist/devices/nld_ne555.cpp +++ b/src/lib/netlist/devices/nld_ne555.cpp @@ -29,7 +29,7 @@ namespace netlist::devices { , m_last_reset(*this, "m_last_reset", false) , m_overshoot(*this, "m_overshoot", 0.0) , m_undershoot(*this, "m_undershoot", 0.0) - , m_ovlimit(0.0) + , m_overshoot_limit(0.0) { register_sub_alias("GND", "R3.2"); // Pin 1 register_sub_alias("CONT", "R1.2"); // Pin 5 @@ -56,7 +56,7 @@ namespace netlist::devices { // Check for astable setup, usually TRIG AND THRES connected. Enable // overshoot compensation in this case. if (m_TRIG.net() == m_THRES.net()) - m_ovlimit = nlconst::magic(0.5); + m_overshoot_limit = nlconst::magic(0.5); } private: @@ -66,12 +66,12 @@ namespace netlist::devices { const auto reset = m_RESET(); - const nl_fptype vthresh = clamp_hl(m_R2.P()(), nlconst::magic(0.7), nlconst::magic(1.4)); - const nl_fptype vtrig = clamp_hl(m_R2.N()(), nlconst::magic(0.7), nlconst::magic(1.4)); + const nl_fptype v_threshold = clamp_hl(m_R2.P()(), nlconst::magic(0.7), nlconst::magic(1.4)); + const nl_fptype v_trigger = clamp_hl(m_R2.N()(), nlconst::magic(0.7), nlconst::magic(1.4)); // avoid artificial oscillation due to overshoot compensation when // the control input is used. - const auto ovlimit = std::min(m_ovlimit, std::max(0.0, (vthresh - vtrig) / 3.0)); + const auto overshoot_limit = std::min(m_overshoot_limit, std::max(0.0, (v_threshold - v_trigger) / 3.0)); if (!reset && m_last_reset) { @@ -80,15 +80,15 @@ namespace netlist::devices { else { #if (NL_USE_BACKWARD_EULER) - const bool bthresh = (m_THRES() + m_overshoot > vthresh); - const bool btrig = (m_TRIG() - m_overshoot > vtrig); + const bool threshold_exceeded = (m_THRES() + m_overshoot > v_threshold); + const bool trigger_exceeded = (m_TRIG() - m_overshoot > v_trigger); #else - const bool bthresh = (m_THRES() + m_overshoot > vthresh); - const bool btrig = (m_TRIG() - m_undershoot > vtrig); + const bool threshold_exceeded = (m_THRES() + m_overshoot > v_threshold); + const bool trigger_exceeded = (m_TRIG() - m_undershoot > v_trigger); #endif - if (!btrig) + if (!trigger_exceeded) m_ff = true; - else if (bthresh) + else if (threshold_exceeded) { m_ff = false; } @@ -99,11 +99,11 @@ namespace netlist::devices { if (m_last_out && !out) { #if (NL_USE_BACKWARD_EULER) - m_overshoot += ((m_THRES() - vthresh)) * 2.0; + m_overshoot += ((m_THRES() - v_threshold)) * 2.0; #else - m_overshoot += ((m_THRES() - vthresh)); + m_overshoot += ((m_THRES() - v_threshold)); #endif - m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), ovlimit); + m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), overshoot_limit); //if (this->name() == "IC6_2") // printf("%f %s %f %f %f\n", exec().time().as_double(), this->name().c_str(), m_overshoot(), m_R2.P()(), m_THRES()); m_RDIS.change_state([this]() @@ -115,11 +115,11 @@ namespace netlist::devices { else if (!m_last_out && out) { #if (NL_USE_BACKWARD_EULER) - m_overshoot += (vtrig - m_TRIG()) * 2.0; - m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), ovlimit); + m_overshoot += (v_trigger - m_TRIG()) * 2.0; + m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), overshoot_limit); #else - m_undershoot += (vtrig - m_TRIG()); - m_undershoot = plib::clamp(m_undershoot(), nlconst::zero(), ovlimit); + m_undershoot += (v_trigger - m_TRIG()); + m_undershoot = plib::clamp(m_undershoot(), nlconst::zero(), overshoot_limit); #endif m_RDIS.change_state([this]() { @@ -147,7 +147,7 @@ namespace netlist::devices { state_var<bool> m_last_reset; state_var<nl_fptype> m_overshoot; state_var<nl_fptype> m_undershoot; - nl_fptype m_ovlimit; + nl_fptype m_overshoot_limit; nl_fptype clamp_hl(const nl_fptype v, const nl_fptype a, const nl_fptype b) noexcept { diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp index 8192222c236..0f68517cb1f 100644 --- a/src/lib/netlist/devices/nlid_truthtable.cpp +++ b/src/lib/netlist/devices/nlid_truthtable.cpp @@ -41,7 +41,7 @@ namespace netlist::devices { const pstring &model, truth_table_t &ttp, const std::vector<pstring> &desc) : device_t(owner, name, model) -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE , m_state(*this, "m_state", 0) #endif , m_ign(*this, "m_ign", 0) @@ -61,25 +61,26 @@ namespace netlist::devices { { int active_outputs = 0; m_ign = 0; -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE m_state = 0; #endif for (std::size_t i = 0; i < m_NI; ++i) { m_I[i].activate(); -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE m_state |= (m_I[i]() << i); #endif } for (auto &q : m_Q) - if (q.has_net() && !exec().nl_state().core_terms(q.net()).empty()) - active_outputs++; + if (q.has_net()) + if (!q.net().core_terms_empty()) + active_outputs++; set_active_outputs(active_outputs); } NETLIB_HANDLERI(inputs) { -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE m_state = 0; for (std::size_t i = 0; i < m_NI; ++i) { @@ -89,7 +90,7 @@ namespace netlist::devices { process<true>(); } -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE template <std::size_t N> void update_N() noexcept { @@ -122,7 +123,7 @@ namespace netlist::devices { if (doOUT) { -#if !USE_TT_ALTERNATIVE +#if !NL_USE_TT_ALTERNATIVE for (auto I = m_I.begin(); ign != 0; ign >>= 1, ++I) if (ign & 1) I->activate(); @@ -150,7 +151,7 @@ namespace netlist::devices { } const type_t output_state(m_ttp.m_out_state[new_state]); - type_t out(output_state & m_outmask); + const type_t out(output_state & m_outmask); m_ign = output_state >> m_NO; @@ -171,7 +172,7 @@ namespace netlist::devices { for (auto I = m_I.begin(); ign != 0; ign >>= 1, ++I) if (ign & 1) I->inactivate(); -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE m_state = new_state; #endif } @@ -195,7 +196,7 @@ namespace netlist::devices { plib::static_vector<logic_input_t, m_NI> m_I; plib::static_vector<logic_output_t, m_NO> m_Q; -#if USE_TT_ALTERNATIVE +#if NL_USE_TT_ALTERNATIVE state_var<type_t> m_state; #endif state_var<type_t> m_ign; @@ -214,18 +215,18 @@ namespace netlist::devices { { using type = T; - pbitset() noexcept : m_bs(0) { } - pbitset(T v) noexcept : m_bs(v) { } + constexpr pbitset() noexcept : m_bs(0) { } + constexpr pbitset(T v) noexcept : m_bs(v) { } - pbitset &set() noexcept { *this = all_bits(); return *this; } - pbitset &set(std::size_t bit) noexcept { m_bs |= (static_cast<T>(1) << bit); return *this; } - pbitset &reset() noexcept { *this = no_bits(); return *this; } - pbitset &reset(std::size_t bit) noexcept { m_bs &= ~(static_cast<T>(1) << bit); return *this; } + constexpr pbitset &set() noexcept { *this = all_bits(); return *this; } + constexpr pbitset &set(std::size_t bit) noexcept { m_bs |= (static_cast<T>(1) << bit); return *this; } + constexpr pbitset &reset() noexcept { *this = no_bits(); return *this; } + constexpr pbitset &reset(std::size_t bit) noexcept { m_bs &= ~(static_cast<T>(1) << bit); return *this; } - pbitset flip() const noexcept { return pbitset(~m_bs); } - pbitset flip(std::size_t bit) const noexcept { return pbitset(m_bs ^ (static_cast<T>(1) << bit)); } + constexpr pbitset flip() const noexcept { return pbitset(~m_bs); } + constexpr pbitset flip(std::size_t bit) const noexcept { return pbitset(m_bs ^ (static_cast<T>(1) << bit)); } - std::size_t count() const noexcept + constexpr std::size_t count() const noexcept { std::size_t ret(0); for (T v = m_bs; v != 0; v = v >> 1) @@ -236,8 +237,8 @@ namespace netlist::devices { } constexpr bool test(const std::size_t bit) const { return ((m_bs >> bit) & 1) == 1; } - operator T&() noexcept { return m_bs; } - operator const T&() const noexcept { return m_bs; } + constexpr operator T&() noexcept { return m_bs; } + constexpr operator const T&() const noexcept { return m_bs; } constexpr T as_uint() const noexcept { return m_bs; } constexpr bool all() const noexcept { return *this == all_bits(); } @@ -254,7 +255,7 @@ namespace netlist::devices { /// /// \returns pbitset /// - pbitset expand_and(pbitset b) const noexcept + constexpr pbitset expand_and(pbitset b) const noexcept { pbitset ret; T v( m_bs); @@ -271,8 +272,8 @@ namespace netlist::devices { return ret; } - static constexpr pbitset all_bits() noexcept { return pbitset(~static_cast<T>(0)); } - static constexpr pbitset no_bits() noexcept{ return pbitset(static_cast<T>(0)); } + static constexpr const pbitset all_bits() noexcept { return pbitset(~static_cast<T>(0)); } + static constexpr const pbitset no_bits() noexcept{ return pbitset(static_cast<T>(0)); } private: T m_bs; }; @@ -285,12 +286,12 @@ namespace netlist::devices { struct packed_int { - packed_int(void *data, std::size_t bits) noexcept + constexpr packed_int(void *data, std::size_t bits) noexcept : m_data(data) , m_size(bits) {} - void set(size_t pos, std::uint_least64_t val) noexcept + constexpr void set(size_t pos, std::uint_least64_t val) noexcept { switch (m_size) { @@ -302,7 +303,7 @@ namespace netlist::devices { } } - std::uint_least64_t operator[] (size_t pos) const noexcept + constexpr std::uint_least64_t operator[] (size_t pos) const noexcept { switch (m_size) { @@ -315,7 +316,7 @@ namespace netlist::devices { } } - std::uint_least64_t mask() const noexcept + constexpr std::uint_least64_t mask() const noexcept { switch (m_size) { @@ -346,7 +347,7 @@ namespace netlist::devices { { } - void parse(const std::vector<pstring> &truthtable); + void parse(const std::vector<pstring> &truth_table); private: void parse_line(unsigned cur, std::vector<pstring> list, @@ -382,7 +383,7 @@ namespace netlist::devices { std::vector<pstring> outputs(plib::psplit(io[1], ',')); nl_assert_always(outputs.size() == m_NO, "output count wrong"); -#if !USE_TT_ALTERNATIVE +#if !NL_USE_TT_ALTERNATIVE for (std::size_t i=0; i < m_NI; i++) { inout[i] = plib::trim(inout[i]); @@ -393,18 +394,18 @@ namespace netlist::devices { { inout[i] = plib::trim(inout[i]); } - if (0 < m_NI) m_I.emplace(0, *this, inout[0]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<0>, this)); - if (1 < m_NI) m_I.emplace(1, *this, inout[1]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<1>, this)); - if (2 < m_NI) m_I.emplace(2, *this, inout[2]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<2>, this)); - if (3 < m_NI) m_I.emplace(3, *this, inout[3]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<3>, this)); - if (4 < m_NI) m_I.emplace(4, *this, inout[4]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<4>, this)); - if (5 < m_NI) m_I.emplace(5, *this, inout[5]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<5>, this)); - if (6 < m_NI) m_I.emplace(6, *this, inout[6]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<6>, this)); - if (7 < m_NI) m_I.emplace(7, *this, inout[7]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<7>, this)); - if (8 < m_NI) m_I.emplace(8, *this, inout[8]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<8>, this)); - if (9 < m_NI) m_I.emplace(9, *this, inout[9]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<9>, this)); - if (10 < m_NI) m_I.emplace(10, *this, inout[10]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<10>, this)); - if (11 < m_NI) m_I.emplace(11, *this, inout[11]); //# nldelegate(&nld_truthtable_t<m_NI, m_NO>::update_N<11>, this)); + if (0 < m_NI) m_I.emplace_back(*this, inout[0], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<0>, this)); + if (1 < m_NI) m_I.emplace_back(*this, inout[1], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<1>, this)); + if (2 < m_NI) m_I.emplace_back(*this, inout[2], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<2>, this)); + if (3 < m_NI) m_I.emplace_back(*this, inout[3], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<3>, this)); + if (4 < m_NI) m_I.emplace_back(*this, inout[4], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<4>, this)); + if (5 < m_NI) m_I.emplace_back(*this, inout[5], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<5>, this)); + if (6 < m_NI) m_I.emplace_back(*this, inout[6], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<6>, this)); + if (7 < m_NI) m_I.emplace_back(*this, inout[7], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<7>, this)); + if (8 < m_NI) m_I.emplace_back(*this, inout[8], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<8>, this)); + if (9 < m_NI) m_I.emplace_back(*this, inout[9], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<9>, this)); + if (10 < m_NI) m_I.emplace_back(*this, inout[10], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<10>, this)); + if (11 < m_NI) m_I.emplace_back(*this, inout[11], nl_delegate(&nld_truth_table_t<m_NI, m_NO>::update_N<11>, this)); #endif for (std::size_t i=0; i < m_NO; i++) { @@ -437,20 +438,20 @@ namespace netlist::devices { { using tt_type = nld_truth_table_t<m_NI, m_NO>; - if (!m_ttbl) + if (!m_table) { - m_ttbl = plib::make_unique<typename nld_truth_table_t<m_NI, m_NO>::truth_table_t>(pool); + m_table = plib::make_unique<typename nld_truth_table_t<m_NI, m_NO>::truth_table_t>(pool); truth_table_parser desc_s(m_NO, m_NI, - packed_int(m_ttbl->m_out_state.data(), sizeof(m_ttbl->m_out_state[0]) * 8), - m_ttbl->m_timing_index.data(), m_ttbl->m_timing_nt.data()); + packed_int(m_table->m_out_state.data(), sizeof(m_table->m_out_state[0]) * 8), + m_table->m_timing_index.data(), m_table->m_timing_nt.data()); desc_s.parse(m_desc); } - return plib::make_unique<tt_type>(pool, anetlist, name, m_family_name, *m_ttbl, m_desc); + return plib::make_unique<tt_type>(pool, anetlist, name, m_family_name, *m_table, m_desc); } private: - device_arena::unique_ptr<typename nld_truth_table_t<m_NI, m_NO>::truth_table_t> m_ttbl; + device_arena::unique_ptr<typename nld_truth_table_t<m_NI, m_NO>::truth_table_t> m_table; }; tt_bitset truth_table_parser::calculate_ignored_inputs(tt_bitset state) const @@ -562,13 +563,13 @@ namespace netlist::devices { } } - void truth_table_parser::parse(const std::vector<pstring> &truthtable) + void truth_table_parser::parse(const std::vector<pstring> &truth_table) { unsigned line = 0; - pstring ttline(truthtable[line]); + pstring tt_line(truth_table[line]); line++; - ttline = truthtable[line]; + tt_line = truth_table[line]; line++; for (unsigned j=0; j < m_size; j++) @@ -577,9 +578,9 @@ namespace netlist::devices { for (int j=0; j < 16; j++) m_timing_nt[j] = netlist_time::zero(); - while (!ttline.empty()) + while (!tt_line.empty()) { - std::vector<pstring> io(plib::psplit(ttline,'|')); + std::vector<pstring> io(plib::psplit(tt_line,'|')); // checks nl_assert_always(io.size() == 3, "io.count mismatch"); std::vector<pstring> inout(plib::psplit(io[0], ',')); @@ -590,7 +591,7 @@ namespace netlist::devices { nl_assert_always(times.size() == m_NO, "timing count not matching"); tt_bitset val = 0; - std::vector<uint_least8_t> tindex; + std::vector<uint_least8_t> indexes; // // FIXME: evaluation of outputs should be done in parse_line to @@ -610,14 +611,14 @@ namespace netlist::devices { while (m_timing_nt[k] != netlist_time::zero() && m_timing_nt[k] != t) k++; m_timing_nt[k] = t; - tindex.push_back(k); //[j] = k; + indexes.push_back(k); //[j] = k; } - parse_line(0, inout, 0 , val, tindex); - if (line < truthtable.size()) - ttline = truthtable[line]; + parse_line(0, inout, 0 , val, indexes); + if (line < truth_table.size()) + tt_line = truth_table[line]; else - ttline = ""; + tt_line = ""; line++; } @@ -666,9 +667,9 @@ namespace netlist::factory { } #define ENTRYY(n, m, s) case (n * 100 + m): \ - { using xtype = devices::netlist_factory_truth_table_t<n, m>; \ + { using dev_type = devices::netlist_factory_truth_table_t<n, m>; \ auto cs=s; \ - ret = plib::make_unique<xtype, host_arena>(desc.name, std::move(cs)); } \ + ret = plib::make_unique<dev_type, host_arena>(desc.name, std::move(cs)); } \ break #define ENTRY(n, s) ENTRYY(n, 1, s); ENTRYY(n, 2, s); ENTRYY(n, 3, s); \ diff --git a/src/lib/netlist/devices/nlid_truthtable.h b/src/lib/netlist/devices/nlid_truthtable.h index a7e4d7a327d..83f9679e70b 100644 --- a/src/lib/netlist/devices/nlid_truthtable.h +++ b/src/lib/netlist/devices/nlid_truthtable.h @@ -12,8 +12,6 @@ #include "../nl_setup.h" #include "nl_factory.h" -#define USE_TT_ALTERNATIVE (0) - namespace netlist::factory { class truth_table_base_element_t : public factory::element_t diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 6441b91c287..c60162efb0c 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -25,23 +25,9 @@ namespace netlist { // ---------------------------------------------------------------------------------------- - // callbacks_t + // detail::core_terminal_t // ---------------------------------------------------------------------------------------- - // ---------------------------------------------------------------------------------------- - // queue_t - // ---------------------------------------------------------------------------------------- - - // ---------------------------------------------------------------------------------------- - // device_object_t - // ---------------------------------------------------------------------------------------- - - detail::device_object_t::device_object_t(core_device_t *dev, const pstring &aname) - : object_t(aname) - , m_device(dev) - { - } - detail::terminal_type detail::core_terminal_t::type() const noexcept(false) { if (dynamic_cast<const terminal_t *>(this) != nullptr) @@ -58,6 +44,16 @@ namespace netlist //return terminal_type::TERMINAL; // please compiler } + // ---------------------------------------------------------------------------------------- + // detail::device_object_t + // ---------------------------------------------------------------------------------------- + + detail::device_object_t::device_object_t(core_device_t *dev, const pstring &aname) + : object_t(aname) + , m_device(dev) + { + } + netlist_state_t &detail::device_object_t::state() noexcept { return m_device->state(); @@ -69,7 +65,7 @@ namespace netlist } // ---------------------------------------------------------------------------------------- - // netlist_object_t + // detail::netlist_object_t // ---------------------------------------------------------------------------------------- netlist_state_t & detail::netlist_object_t::state() noexcept @@ -100,8 +96,47 @@ namespace netlist state.save(*this, m_time, aname, "m_time"); } + void netlist_t::reset() + { + log().debug("Searching for main clock\n"); + m_main_clock = m_state.get_single_device<devices::NETLIB_NAME(mainclock)>("mainclock"); + + log().debug("Searching for solver\n"); + m_solver = m_state.get_single_device<devices::NETLIB_NAME(solver)>("solver"); + + // Don't reset time + //m_time = netlist_time_ext::zero(); + m_queue.clear(); + if (m_main_clock != nullptr) + m_main_clock->m_Q.net().set_next_scheduled_time(m_time); + //if (m_solver != nullptr) + // m_solver->reset(); + + m_state.reset(); + } + + void netlist_t::stop() + { + log().debug("Printing statistics ...\n"); + print_stats(); + log().debug("Stopping solver device ...\n"); + if (m_solver != nullptr) + m_solver->stop(); + } + + void netlist_t::print_stats() const + { + if (m_use_stats) + { + netlist_state_t::stats_info si{m_queue, m_stat_mainloop, m_perf_out_processed}; + m_state.print_stats(si); + } + log().verbose("Current pool memory allocated: {1:12} kB", nl_state().pool().cur_alloc() >> 10); + log().verbose("Maximum pool memory allocated: {1:12} kB", nl_state().pool().max_alloc() >> 10); + } + // ---------------------------------------------------------------------------------------- - // netlist_t + // netlist_state_t // ---------------------------------------------------------------------------------------- netlist_state_t::netlist_state_t(const pstring &name, @@ -137,8 +172,8 @@ namespace netlist m_setup->parser().add_include<plib::psource_str_t>("devices/net_lib.h", content); #if 1 NETLIST_NAME(base_lib)(m_setup->parser()); - //m_setup->parser().register_source<source_pattern_t>("../macro/modules/nlmod_{1}.cpp"); - //m_setup->parser().register_source<source_pattern_t>("../macro/nlm_{1}.cpp"); + //#m_setup->parser().register_source<source_pattern_t>("../macro/modules/nlmod_{1}.cpp"); + //#m_setup->parser().register_source<source_pattern_t>("../macro/nlm_{1}.cpp"); #else #if 1 pstring dir = "src/lib/netlist/"; @@ -166,25 +201,25 @@ namespace netlist m_lib = std::move(lib); } - - void netlist_t::stop() - { - log().debug("Printing statistics ...\n"); - print_stats(); - log().debug("Stopping solver device ...\n"); - if (m_solver != nullptr) - m_solver->stop(); - } - std::size_t netlist_state_t::find_net_id(const detail::net_t *net) const { + // special case for queue end processing items + if (net == nullptr) + return std::numeric_limits<std::size_t>::max() - 1; + for (std::size_t i = 0; i < m_nets.size(); i++) if (m_nets[i].get() == net) return i; + return std::numeric_limits<std::size_t>::max(); } + detail::net_t *netlist_state_t::net_by_id(std::size_t id) const { + // special case for queue end processing items + if (id == std::numeric_limits<std::size_t>::max() - 1) + return nullptr; + return m_nets[id].get(); } @@ -274,25 +309,6 @@ namespace netlist return plib::pfmt("{1}.{2}.{3}")(NL_VERSION_MAJOR, NL_VERSION_MINOR, NL_VERSION_PATCHLEVEL); } - void netlist_t::reset() - { - log().debug("Searching for main clock\n"); - m_main_clock = m_state.get_single_device<devices::NETLIB_NAME(mainclock)>("mainclock"); - - log().debug("Searching for solver\n"); - m_solver = m_state.get_single_device<devices::NETLIB_NAME(solver)>("solver"); - - // Don't reset time - //m_time = netlist_time_ext::zero(); - m_queue.clear(); - if (m_main_clock != nullptr) - m_main_clock->m_Q.net().set_next_scheduled_time(m_time); - //if (m_solver != nullptr) - // m_solver->reset(); - - m_state.reset(); - } - void netlist_state_t::free_setup_resources() { m_setup = nullptr; @@ -339,7 +355,7 @@ namespace netlist for (auto &n : m_nets) { n->update_inputs(); // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1 - for (auto & term : core_terms(*n)) + for (detail::core_terminal_t * term : n->core_terms_copy()) { if (!plib::container::contains(t, &term->delegate())) { @@ -370,17 +386,6 @@ namespace netlist } - void netlist_t::print_stats() const - { - if (m_use_stats) - { - netlist_state_t::stats_info si{m_queue, m_stat_mainloop, m_perf_out_processed}; - m_state.print_stats(si); - } - log().verbose("Current pool memory allocated: {1:12} kB", nl_state().pool().cur_alloc() >> 10); - log().verbose("Maximum pool memory allocated: {1:12} kB", nl_state().pool().max_alloc() >> 10); - } - void netlist_state_t::print_stats(stats_info &si) const { std::vector<size_t> index; @@ -431,7 +436,7 @@ namespace netlist / gsl::narrow<plib::pperftime_t<true>::type>(200000); log().verbose("Queue Pushes {1:15}", si.m_queue.m_prof_call()); - log().verbose("Queue Moves {1:15}", si.m_queue.m_prof_sortmove()); + log().verbose("Queue Moves {1:15}", si.m_queue.m_prof_sort_move()); log().verbose("Queue Removes {1:15}", si.m_queue.m_prof_remove()); log().verbose(""); @@ -476,6 +481,19 @@ namespace netlist return ret; } + 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; + } + } // ---------------------------------------------------------------------------------------- // core_device_t @@ -525,7 +543,7 @@ namespace netlist pstring alias = this->name() + "." + name; // everything already fully qualified - state().parser().register_alias_nofqn(alias, term.name()); + state().parser().register_alias_no_fqn(alias, term.name()); } void base_device_t::register_sub_alias(const pstring &name, const pstring &aliased) @@ -534,7 +552,7 @@ namespace netlist pstring aliased_fqn = this->name() + "." + aliased; // everything already fully qualified - state().parser().register_alias_nofqn(alias, aliased_fqn); + state().parser().register_alias_no_fqn(alias, aliased_fqn); } void base_device_t::connect(const detail::core_terminal_t &t1, const detail::core_terminal_t &t2) @@ -600,6 +618,16 @@ namespace netlist } // ---------------------------------------------------------------------------------------- + // analog_t + // ---------------------------------------------------------------------------------------- + + analog_t::analog_t(core_device_t &dev, const pstring &aname, const state_e state, + nl_delegate delegate) + : core_terminal_t(dev, aname, state, delegate) + { + } + + // ---------------------------------------------------------------------------------------- // net_t // ---------------------------------------------------------------------------------------- @@ -614,12 +642,22 @@ namespace netlist props::add(this, props::value_type()); } + bool detail::net_t::is_logic() const noexcept + { + return dynamic_cast<const logic_net_t *>(this) != nullptr; + } + + bool detail::net_t::is_analog() const noexcept + { + return dynamic_cast<const analog_net_t *>(this) != nullptr; + } + void detail::net_t::rebuild_list() { // rebuild m_list m_list_active.clear(); - for (auto & term : exec().nl_state().core_terms(*this)) + for (core_terminal_t * term : core_terms_ref()) if (term->terminal_state() != logic_t::STATE_INP_PASSIVE) { m_list_active.push_back(term); @@ -627,7 +665,6 @@ namespace netlist } } - void detail::net_t::reset() noexcept { m_next_scheduled_time = exec().time(); @@ -644,7 +681,7 @@ namespace netlist // rebuild m_list and reset terminals to active or analog out state m_list_active.clear(); - for (core_terminal_t *ct : exec().nl_state().core_terms(*this)) + for (core_terminal_t * ct : core_terms_copy()) { ct->reset(); if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE) @@ -653,6 +690,63 @@ namespace netlist } } +#if NL_USE_INPLACE_CORE_TERMS + void detail::net_t::remove_terminal(detail::core_terminal_t &term) + { + m_core_terms.remove(&term); + } + + void detail::net_t::remove_all_terminals() + { + m_core_terms.clear(); + } + + void detail::net_t::add_terminal(detail::core_terminal_t &terminal) + { + for (detail::core_terminal_t * t : m_core_terms) + if (t == &terminal) + { + state().log().fatal(MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name())); + throw nl_exception(MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name())); + } + + terminal.set_net(this); + + m_core_terms.push_back(&terminal); + } + +#else + void detail::net_t::remove_terminal(detail::core_terminal_t &term) + { + //net.core_terms().remove(p); + for (auto pp = state().core_terms(*this).begin(); pp != state().core_terms(*this).end(); pp++) + if (*pp == &term) + { + state().core_terms(*this).erase(pp); + break; + } + } + + void detail::net_t::remove_all_terminals() + { + state().core_terms(*this).clear(); + } + + void detail::net_t::add_terminal(detail::core_terminal_t &terminal) + { + for (detail::core_terminal_t * t : state().core_terms(*this)) + if (t == &terminal) + { + state().log().fatal(MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name())); + throw nl_exception(MF_NET_1_DUPLICATE_TERMINAL_2(this->name(), t->name())); + } + + terminal.set_net(this); + + state().core_terms(*this).push_back(&terminal); + } +#endif + // ---------------------------------------------------------------------------------------- // logic_net_t // ---------------------------------------------------------------------------------------- @@ -678,6 +772,7 @@ namespace netlist net_t::reset(); m_cur_Analog = nlconst::zero(); } + // ---------------------------------------------------------------------------------------- // core_terminal_t // ---------------------------------------------------------------------------------------- @@ -685,19 +780,46 @@ namespace netlist detail::core_terminal_t::core_terminal_t(core_device_t &dev, const pstring &aname, const state_e state, nl_delegate delegate) : device_object_t(&dev, dev.name() + "." + aname) - #if NL_USE_COPY_INSTEAD_OF_REFERENCE - , m_Q(*this, "m_Q", 0) - #endif + , m_Q_CIR(*this, "m_Q", 0) , m_delegate(delegate) , m_net(nullptr) , m_state(*this, "m_state", state) { } - analog_t::analog_t(core_device_t &dev, const pstring &aname, const state_e state, - nl_delegate delegate) - : core_terminal_t(dev, aname, state, delegate) + bool detail::core_terminal_t::is_logic() const noexcept + { + return dynamic_cast<const logic_t *>(this) != nullptr; + } + + bool detail::core_terminal_t::is_logic_input() const noexcept + { + return dynamic_cast<const logic_input_t *>(this) != nullptr; + } + + bool detail::core_terminal_t::is_logic_output() const noexcept + { + return dynamic_cast<const logic_output_t *>(this) != nullptr; + } + + bool detail::core_terminal_t::is_tristate_output() const noexcept { + return dynamic_cast<const tristate_output_t *>(this) != nullptr; + } + + bool detail::core_terminal_t::is_analog() const noexcept + { + return dynamic_cast<const analog_t *>(this) != nullptr; + } + + bool detail::core_terminal_t::is_analog_input() const noexcept + { + return dynamic_cast<const analog_input_t *>(this) != nullptr; + } + + bool detail::core_terminal_t::is_analog_output() const noexcept + { + return dynamic_cast<const analog_output_t *>(this) != nullptr; } // ---------------------------------------------------------------------------------------- @@ -764,7 +886,6 @@ namespace netlist state().setup().register_term(*this); } - // ---------------------------------------------------------------------------------------- // logic_output_t // ---------------------------------------------------------------------------------------- @@ -787,6 +908,7 @@ namespace netlist // ----------------------------------------------------------------------------- // 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 @@ -862,7 +984,6 @@ namespace netlist } - pstring param_t::get_initial(const core_device_t *dev, bool *found) const { pstring res = dev->state().setup().get_initial_param_val(this->name(), ""); @@ -915,76 +1036,11 @@ namespace netlist return state().setup().models().get_model(str()).value(entity); } - plib::istream_uptr param_data_t::stream() { return device().state().parser().get_data_stream(str()); } - bool detail::core_terminal_t::is_logic() const noexcept - { - return dynamic_cast<const logic_t *>(this) != nullptr; - } - - bool detail::core_terminal_t::is_logic_input() const noexcept - { - return dynamic_cast<const logic_input_t *>(this) != nullptr; - } - - bool detail::core_terminal_t::is_logic_output() const noexcept - { - return dynamic_cast<const logic_output_t *>(this) != nullptr; - } - - bool detail::core_terminal_t::is_tristate_output() const noexcept - { - return dynamic_cast<const tristate_output_t *>(this) != nullptr; - } - - bool detail::core_terminal_t::is_analog() const noexcept - { - return dynamic_cast<const analog_t *>(this) != nullptr; - } - - bool detail::core_terminal_t::is_analog_input() const noexcept - { - return dynamic_cast<const analog_input_t *>(this) != nullptr; - } - - bool detail::core_terminal_t::is_analog_output() const noexcept - { - return dynamic_cast<const analog_output_t *>(this) != nullptr; - } - - - bool detail::net_t::is_logic() const noexcept - { - return dynamic_cast<const logic_net_t *>(this) != nullptr; - } - - bool detail::net_t::is_analog() const noexcept - { - return dynamic_cast<const analog_net_t *>(this) != nullptr; - } - - // ---------------------------------------------------------------------------------------- - // netlist_state_t - // ---------------------------------------------------------------------------------------- - - 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; - } - } - // ---------------------------------------------------------------------------------------- // netlist_t // @@ -998,7 +1054,7 @@ namespace netlist { netlist_time_ext stop(m_time + delta); - qpush(stop, nullptr); + queue_push(stop, nullptr); if (m_main_clock == nullptr) { diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index 1559589606d..c19fe296aa7 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -51,19 +51,6 @@ #define NL_USE_ACADEMIC_SOLVERS (1) #endif -/// \brief Store input values in logic_terminal_t. -/// -/// Set to 1 to store values in logic_terminal_t instead of -/// accessing them indirectly by pointer from logic_net_t. -/// This approach is stricter and should identify bugs in -/// the netlist core faster. -/// By default it is disabled since it is not as fast as -/// the default approach. It is up to 20% slower. -/// -#ifndef NL_USE_COPY_INSTEAD_OF_REFERENCE -#define NL_USE_COPY_INSTEAD_OF_REFERENCE (0) // FIXME: Move to config struct later -#endif - /// \brief Use backward Euler integration /// /// This will use backward Euler instead of trapezoidal integration. @@ -77,6 +64,35 @@ #define NL_USE_BACKWARD_EULER (1) // FIXME: Move to config struct later #endif +/// \brief Compile with core terminals owned by net_t +/// +/// Set to 1 to enable that net_t owns core terminal collection. +/// In addition, this approach will use plib::list_t so that the doubled linked +/// list pointers are part of the core_terminal_t. +/// +/// This approach requires that terminals at each point in time are only owned +/// by one net. The approach helped to identify bugs. Since the approach +/// involves that containers are located in different locations, it needs a +/// pre-processor define. +/// +/// By default the setting is currently disabled. +/// +#ifndef NL_USE_INPLACE_CORE_TERMS +#define NL_USE_INPLACE_CORE_TERMS (0) +#endif + +/// \brief Use alternative truth table execution approach +/// +/// Enabling this will define a separate truth table execution approach which +/// will use a separate delegate for each input. This approach needs more +/// refinement yet. It works, but is not as fast as the standard approach. +/// +/// Unfortunately this has to be macro since it needs another member variable. +/// +#ifndef NL_USE_TT_ALTERNATIVE +#define NL_USE_TT_ALTERNATIVE (0) +#endif + /// \brief Compile matrix solvers using the __float128 type. /// /// Defaults to \ref PUSE_FLOAT128 @@ -84,15 +100,6 @@ #define NL_USE_FLOAT128 PUSE_FLOAT128 #endif -/// \brief Avoid unnecessary queue pushes -/// -/// Enable the setting below to avoid queue pushes were at execution -/// no action will be taken. This is academically cleaner, but slower than -/// allowing this to happen and filter it during during "process". -/// This is used in core/nets.h -#ifndef AVOID_NOOP_QUEUE_PUSHES -#define AVOID_NOOP_QUEUE_PUSHES (0) // FIXME: Move to config struct later -#endif //============================================================ // DEBUGGING @@ -216,6 +223,42 @@ namespace netlist /// FIXME: More work needed. Review magic numbers. /// using fptype = double; + + /// \brief Store input values in logic_terminal_t. + /// + /// Set to 1 to store values in logic_terminal_t instead of + /// accessing them indirectly by pointer from logic_net_t. + /// This approach is stricter and should identify bugs in + /// the netlist core faster. The approach needs + /// NL_USE_INPLACE_CORE_TERMS enabled to achieve some performance. + /// + /// By default it is disabled since it is not as fast as + /// the default approach. It is ~20% slower. + /// + using use_copy_instead_of_reference = std::integral_constant<bool, false>; + + /// \brief Avoid unnecessary queue pushes + /// + /// Enable the setting below to avoid queue pushes were at execution + /// no action will be taken. This is academically cleaner, but + /// ~6% slower than allowing this to happen and filter it during + /// during "process". + /// + using avoid_noop_queue_pushes = std::integral_constant<bool, false>; + + /// \brief Which sorted queue to use + /// + /// Use timed_queue_heap to use stdc++ heap functions instead of the + /// linear processing queue. This slows down execution by about 35% + /// on a Kaby Lake. + /// + /// The default is the linear queue. + + // template <class A, class T> + // using timed_queue = plib::timed_queue_heap<A, T>; + + template <typename A, typename T> + using timed_queue = plib::timed_queue_linear<A, T>; }; /// \brief Netlist configuration. @@ -225,6 +268,9 @@ namespace netlist /// struct config : public config_default { + //using mempool_align = std::integral_constant<std::size_t, 32>; + //using avoid_noop_queue_pushes = std::integral_constant<bool, true>; + //using use_copy_instead_of_reference = std::integral_constant<bool, true>; }; using nl_fptype = config::fptype; diff --git a/src/lib/netlist/nl_parser.cpp b/src/lib/netlist/nl_parser.cpp index 507ecea0aa7..02c7d11f2b2 100644 --- a/src/lib/netlist/nl_parser.cpp +++ b/src/lib/netlist/nl_parser.cpp @@ -8,577 +8,575 @@ namespace netlist { -// ---------------------------------------------------------------------------------------- -// A netlist parser -// ---------------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------------- + // A netlist parser + // ---------------------------------------------------------------------------------------- -void parser_t::verror(const pstring &msg) -{ - m_setup.log().fatal("{1}", msg); - throw nl_exception(plib::pfmt("{1}")(msg)); -} + void parser_t::verror(const pstring &msg) + { + m_setup.log().fatal("{1}", msg); + throw nl_exception(plib::pfmt("{1}")(msg)); + } -parser_t::parser_t(nlparse_t &setup) - : m_setup(setup) - , m_cur_local(nullptr) -{ - m_tokenizer.identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-$@") - .number_chars(".0123456789", "0123456789eE-.") //FIXME: processing of numbers - .whitespace(pstring("") + ' ' + static_cast<char>(9) + static_cast<char>(10) + static_cast<char>(13)) - .comment("/*", "*/", "//"); - m_tok_paren_left = m_tokenizer.register_token("("); - m_tok_paren_right = m_tokenizer.register_token(")"); - m_tok_comma = m_tokenizer.register_token(","); - - m_tok_static = m_tokenizer.register_token("static"); - m_tok_ALIAS = m_tokenizer.register_token("ALIAS"); - m_tok_DIPPINS = m_tokenizer.register_token("DIPPINS"); - m_tok_NET_C = m_tokenizer.register_token("NET_C"); - m_tok_FRONTIER = m_tokenizer.register_token("OPTIMIZE_FRONTIER"); - m_tok_PARAM = m_tokenizer.register_token("PARAM"); - m_tok_DEFPARAM = m_tokenizer.register_token("DEFPARAM"); - m_tok_HINT = m_tokenizer.register_token("HINT"); - m_tok_NET_MODEL = m_tokenizer.register_token("NET_MODEL"); - m_tok_NET_REGISTER_DEV = m_tokenizer.register_token("NET_REGISTER_DEV"); - m_tok_INCLUDE = m_tokenizer.register_token("INCLUDE"); - m_tok_LOCAL_SOURCE = m_tokenizer.register_token("LOCAL_SOURCE"); - m_tok_LOCAL_LIB_ENTRY = m_tokenizer.register_token("LOCAL_LIB_ENTRY"); - m_tok_EXTERNAL_LIB_ENTRY = m_tokenizer.register_token("EXTERNAL_LIB_ENTRY"); - m_tok_SUBMODEL = m_tokenizer.register_token("SUBMODEL"); - m_tok_NETLIST_START = m_tokenizer.register_token("NETLIST_START"); - m_tok_NETLIST_END = m_tokenizer.register_token("NETLIST_END"); - m_tok_NETLIST_EXTERNAL = m_tokenizer.register_token("NETLIST_EXTERNAL"); - m_tok_EXTERNAL_SOURCE = m_tokenizer.register_token("EXTERNAL_SOURCE"); - m_tok_TRUTHTABLE_START = m_tokenizer.register_token("TRUTHTABLE_START"); - m_tok_TRUTHTABLE_END = m_tokenizer.register_token("TRUTHTABLE_END"); - m_tok_TRUTHTABLE_ENTRY = m_tokenizer.register_token("TRUTHTABLE_ENTRY"); - m_tok_TT_HEAD = m_tokenizer.register_token("TT_HEAD"); - m_tok_TT_LINE = m_tokenizer.register_token("TT_LINE"); - m_tok_TT_FAMILY = m_tokenizer.register_token("TT_FAMILY"); - - m_tokenizer.register_token("RES_R"); - m_tokenizer.register_token("RES_K"); - m_tokenizer.register_token("RES_M"); - m_tokenizer.register_token("CAP_U"); - m_tokenizer.register_token("CAP_N"); - m_tokenizer.register_token("CAP_P"); - -} - -bool parser_t::parse(plib::istream_uptr &&strm, const pstring &nlname) -{ - token_store_t tokstor; - parse_tokens(std::move(strm), tokstor); - return parse(tokstor, nlname); -} + parser_t::parser_t(nlparse_t &setup) + : m_setup(setup) + , m_cur_local(nullptr) + { + m_tokenizer.identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-$@") + .number_chars(".0123456789", "0123456789eE-.") //FIXME: processing of numbers + .whitespace(pstring("") + ' ' + static_cast<char>(9) + static_cast<char>(10) + static_cast<char>(13)) + .comment("/*", "*/", "//"); + m_tok_paren_left = m_tokenizer.register_token("("); + m_tok_paren_right = m_tokenizer.register_token(")"); + m_tok_comma = m_tokenizer.register_token(","); + + m_tok_static = m_tokenizer.register_token("static"); + m_tok_ALIAS = m_tokenizer.register_token("ALIAS"); + m_tok_DIPPINS = m_tokenizer.register_token("DIPPINS"); + m_tok_NET_C = m_tokenizer.register_token("NET_C"); + m_tok_FRONTIER = m_tokenizer.register_token("OPTIMIZE_FRONTIER"); + m_tok_PARAM = m_tokenizer.register_token("PARAM"); + m_tok_DEFPARAM = m_tokenizer.register_token("DEFPARAM"); + m_tok_HINT = m_tokenizer.register_token("HINT"); + m_tok_NET_MODEL = m_tokenizer.register_token("NET_MODEL"); + m_tok_NET_REGISTER_DEV = m_tokenizer.register_token("NET_REGISTER_DEV"); + m_tok_INCLUDE = m_tokenizer.register_token("INCLUDE"); + m_tok_LOCAL_SOURCE = m_tokenizer.register_token("LOCAL_SOURCE"); + m_tok_LOCAL_LIB_ENTRY = m_tokenizer.register_token("LOCAL_LIB_ENTRY"); + m_tok_EXTERNAL_LIB_ENTRY = m_tokenizer.register_token("EXTERNAL_LIB_ENTRY"); + m_tok_SUBMODEL = m_tokenizer.register_token("SUBMODEL"); + m_tok_NETLIST_START = m_tokenizer.register_token("NETLIST_START"); + m_tok_NETLIST_END = m_tokenizer.register_token("NETLIST_END"); + m_tok_NETLIST_EXTERNAL = m_tokenizer.register_token("NETLIST_EXTERNAL"); + m_tok_EXTERNAL_SOURCE = m_tokenizer.register_token("EXTERNAL_SOURCE"); + m_tok_TRUTHTABLE_START = m_tokenizer.register_token("TRUTHTABLE_START"); + m_tok_TRUTHTABLE_END = m_tokenizer.register_token("TRUTHTABLE_END"); + m_tok_TRUTHTABLE_ENTRY = m_tokenizer.register_token("TRUTHTABLE_ENTRY"); + m_tok_TT_HEAD = m_tokenizer.register_token("TT_HEAD"); + m_tok_TT_LINE = m_tokenizer.register_token("TT_LINE"); + m_tok_TT_FAMILY = m_tokenizer.register_token("TT_FAMILY"); + + m_tokenizer.register_token("RES_R"); + m_tokenizer.register_token("RES_K"); + m_tokenizer.register_token("RES_M"); + m_tokenizer.register_token("CAP_U"); + m_tokenizer.register_token("CAP_N"); + m_tokenizer.register_token("CAP_P"); -void parser_t::parse_tokens(plib::istream_uptr &&strm, token_store_t &tokstor) -{ - plib::putf8_reader u8reader(strm.release_stream()); - m_tokenizer.append_to_store(&u8reader, tokstor); -} + } -bool parser_t::parse(const token_store_t &tokstor, const pstring &nlname) -{ - set_token_source(&tokstor); + bool parser_t::parse(plib::istream_uptr &&strm, const pstring &nlname) + { + token_store_t tokstor; + parse_tokens(std::move(strm), tokstor); + return parse(tokstor, nlname); + } - bool in_nl = false; + void parser_t::parse_tokens(plib::istream_uptr &&strm, token_store_t &tokstor) + { + plib::putf8_reader u8reader(strm.release_stream()); + m_tokenizer.append_to_store(&u8reader, tokstor); + } - while (true) + bool parser_t::parse(const token_store_t &tokstor, const pstring &nlname) { - // FIXME: line numbers in cached local netlists are wrong - // need to process raw tokens here. - token_t token = get_token_raw(); - if (token.is_type(token_type::ENDOFFILE)) - { - return false; - } + set_token_source(&tokstor); + + bool in_nl = false; - if (token.is(m_tok_NETLIST_END) || token.is(m_tok_TRUTHTABLE_END)) + while (true) { - if (!in_nl) - error (MF_PARSER_UNEXPECTED_1(token.str())); - else + // FIXME: line numbers in cached local netlists are wrong + // need to process raw tokens here. + token_t token = get_token_raw(); + if (token.is_type(token_type::ENDOFFILE)) { - in_nl = false; + return false; } - require_token(m_tok_paren_left); - require_token(m_tok_paren_right); - m_cur_local->push_back(token); - m_cur_local->push_back(token_t(m_tok_paren_left)); - m_cur_local->push_back(token_t(m_tok_paren_right)); + if (token.is(m_tok_NETLIST_END) || token.is(m_tok_TRUTHTABLE_END)) + { + if (!in_nl) + error (MF_PARSER_UNEXPECTED_1(token.str())); + else + { + in_nl = false; + } + require_token(m_tok_paren_left); + require_token(m_tok_paren_right); + + m_cur_local->push_back(token); + m_cur_local->push_back(token_t(m_tok_paren_left)); + m_cur_local->push_back(token_t(m_tok_paren_right)); - } - else if (token.is(m_tok_NETLIST_START) || token.is(m_tok_TRUTHTABLE_START)) - { - if (in_nl) - error (MF_PARSER_UNEXPECTED_1(token.str())); - require_token(m_tok_paren_left); - token_t name = get_token(); - if (token.is(m_tok_NETLIST_START) && (name.str() == nlname || nlname.empty())) + } + else if (token.is(m_tok_NETLIST_START) || token.is(m_tok_TRUTHTABLE_START)) + { + if (in_nl) + error (MF_PARSER_UNEXPECTED_1(token.str())); + require_token(m_tok_paren_left); + token_t name = get_token(); + if (token.is(m_tok_NETLIST_START) && (name.str() == nlname || nlname.empty())) + { + require_token(m_tok_paren_right); + parse_netlist(); + return true; + } + if (token.is(m_tok_TRUTHTABLE_START) && name.str() == nlname) + { + net_truth_table_start(nlname); + return true; + } + + // create a new cached local store + m_local.emplace(name.str(), token_store_t()); + m_cur_local = &m_local[name.str()]; + auto sl = location(); + auto li = plib::pfmt("# {1} \"{2}\"")(sl.line(), sl.file_name()); + + m_cur_local->push_back(token_t(token_type::LINEMARKER, li)); + m_cur_local->push_back(token); + m_cur_local->push_back(token_t(m_tok_paren_left)); + m_cur_local->push_back(name); + //m_cur_local->push_back(token_t(m_tok_paren_right)); + in_nl = true; + } + // FIXME: do we really need this going forward ? there should be no need + // for NETLIST_EXTERNAL in netlist files + else if (token.is(m_tok_NETLIST_EXTERNAL)) { + if (in_nl) + error (MF_UNEXPECTED_NETLIST_EXTERNAL()); + require_token(m_tok_paren_left); + token_t name = get_token(); require_token(m_tok_paren_right); - parse_netlist(); - return true; } - if (token.is(m_tok_TRUTHTABLE_START) && name.str() == nlname) + else if (!in_nl) { - net_truth_table_start(nlname); - return true; + if (!token.is(m_tok_static) && !token.is_type(token_type::SOURCELINE) + && !token.is_type(token_type::LINEMARKER)) + error(MF_EXPECTED_NETLIST_START_1(token.str())); + } + else + { + m_cur_local->push_back(token); } - - // create a new cached local store - m_local.emplace(name.str(), token_store_t()); - m_cur_local = &m_local[name.str()]; - auto sl = location(); - auto li = plib::pfmt("# {1} \"{2}\"")(sl.line(), sl.file_name()); - - m_cur_local->push_back(token_t(token_type::LINEMARKER, li)); - m_cur_local->push_back(token); - m_cur_local->push_back(token_t(m_tok_paren_left)); - m_cur_local->push_back(name); - //m_cur_local->push_back(token_t(m_tok_paren_right)); - in_nl = true; - } - // FIXME: do we really need this going forward ? there should be no need - // for NETLIST_EXTERNAL in netlist files - else if (token.is(m_tok_NETLIST_EXTERNAL)) - { - if (in_nl) - error (MF_UNEXPECTED_NETLIST_EXTERNAL()); - require_token(m_tok_paren_left); - token_t name = get_token(); - require_token(m_tok_paren_right); - } - else if (!in_nl) - { - if (!token.is(m_tok_static) && !token.is_type(token_type::SOURCELINE) - && !token.is_type(token_type::LINEMARKER)) - error(MF_EXPECTED_NETLIST_START_1(token.str())); - } - else - { - m_cur_local->push_back(token); } } -} -void parser_t::parse_netlist() -{ - while (true) + void parser_t::parse_netlist() { - token_t token = get_token(); - - if (token.is_type(token_type::ENDOFFILE)) - error (MF_UNEXPECTED_END_OF_FILE()); - - m_setup.log().debug("Parser: Device: {1}\n", token.str()); - - if (token.is(m_tok_ALIAS)) - net_alias(); - else if (token.is(m_tok_DIPPINS)) - dip_pins(); - else if (token.is(m_tok_NET_C)) - net_c(); - else if (token.is(m_tok_FRONTIER)) - frontier(); - else if (token.is(m_tok_PARAM)) - netdev_param(); - else if (token.is(m_tok_DEFPARAM)) - netdev_default_param(); - else if (token.is(m_tok_HINT)) - netdev_hint(); - else if (token.is(m_tok_NET_MODEL)) - net_model(); - else if (token.is(m_tok_SUBMODEL)) - net_sub_model(); - else if (token.is(m_tok_INCLUDE)) - net_include(); - else if (token.is(m_tok_LOCAL_SOURCE)) - net_local_source(); - else if (token.is(m_tok_EXTERNAL_SOURCE)) - net_external_source(); - else if (token.is(m_tok_LOCAL_LIB_ENTRY)) - net_lib_entry(true); - else if (token.is(m_tok_EXTERNAL_LIB_ENTRY)) - net_lib_entry(false); - else if (token.is(m_tok_TRUTHTABLE_ENTRY)) - { - require_token(m_tok_paren_left); - pstring name(get_identifier()); - register_local_as_source(name); - m_setup.include(name); - require_token(m_tok_paren_right); - } - else if (token.is(m_tok_NET_REGISTER_DEV)) - { - net_register_dev(); - } - else if (token.is(m_tok_NETLIST_END)) + while (true) { - netdev_netlist_end(); - return; + token_t token = get_token(); + + if (token.is_type(token_type::ENDOFFILE)) + error (MF_UNEXPECTED_END_OF_FILE()); + + m_setup.log().debug("Parser: Device: {1}\n", token.str()); + + if (token.is(m_tok_ALIAS)) + net_alias(); + else if (token.is(m_tok_DIPPINS)) + dip_pins(); + else if (token.is(m_tok_NET_C)) + net_c(); + else if (token.is(m_tok_FRONTIER)) + frontier(); + else if (token.is(m_tok_PARAM)) + netdev_param(); + else if (token.is(m_tok_DEFPARAM)) + netdev_default_param(); + else if (token.is(m_tok_HINT)) + netdev_hint(); + else if (token.is(m_tok_NET_MODEL)) + net_model(); + else if (token.is(m_tok_SUBMODEL)) + net_sub_model(); + else if (token.is(m_tok_INCLUDE)) + net_include(); + else if (token.is(m_tok_LOCAL_SOURCE)) + net_local_source(); + else if (token.is(m_tok_EXTERNAL_SOURCE)) + net_external_source(); + else if (token.is(m_tok_LOCAL_LIB_ENTRY)) + net_lib_entry(true); + else if (token.is(m_tok_EXTERNAL_LIB_ENTRY)) + net_lib_entry(false); + else if (token.is(m_tok_TRUTHTABLE_ENTRY)) + { + require_token(m_tok_paren_left); + pstring name(get_identifier()); + register_local_as_source(name); + m_setup.include(name); + require_token(m_tok_paren_right); + } + else if (token.is(m_tok_NET_REGISTER_DEV)) + { + net_register_dev(); + } + else if (token.is(m_tok_NETLIST_END)) + { + netdev_netlist_end(); + return; + } + else if (!token.is_type(token_type::IDENTIFIER)) + error(MF_EXPECTED_IDENTIFIER_GOT_1(token.str())); + else + device(token.str()); } - else if (!token.is_type(token_type::IDENTIFIER)) - error(MF_EXPECTED_IDENTIFIER_GOT_1(token.str())); - else - device(token.str()); } -} -void parser_t::net_lib_entry(bool is_local) -{ - require_token(m_tok_paren_left); - pstring name(get_identifier()); + void parser_t::net_lib_entry(bool is_local) + { + require_token(m_tok_paren_left); + pstring name(get_identifier()); - if (is_local) - register_local_as_source(name); - else if (m_local.find(name) != m_local.end()) - error(MF_EXTERNAL_SOURCE_IS_LOCAL_1(name)); + if (is_local) + register_local_as_source(name); + else if (m_local.find(name) != m_local.end()) + error(MF_EXTERNAL_SOURCE_IS_LOCAL_1(name)); - // FIXME: Need to pass in parameter definition FIXME: get line number right - m_setup.register_lib_entry(name, "", location()); - require_token(m_tok_paren_right); -} + // FIXME: Need to pass in parameter definition FIXME: get line number right + m_setup.register_lib_entry(name, "", location()); + require_token(m_tok_paren_right); + } -void parser_t::net_truth_table_start(const pstring &nlname) -{ - bool head_found(false); - - // parse remaining parameters - require_token(m_tok_comma); - long ni = get_number_long(); - require_token(m_tok_comma); - long no = get_number_long(); - require_token(m_tok_comma); - pstring def_param = get_string(); - require_token(m_tok_paren_right); - - netlist::tt_desc desc; - desc.name = nlname; - desc.ni = gsl::narrow<unsigned long>(ni); - desc.no = gsl::narrow<unsigned long>(no); - desc.family = ""; - - while (true) + void parser_t::net_truth_table_start(const pstring &nlname) { - token_t token = get_token(); + bool head_found(false); + + // parse remaining parameters + require_token(m_tok_comma); + long ni = get_number_long(); + require_token(m_tok_comma); + long no = get_number_long(); + require_token(m_tok_comma); + pstring def_param = get_string(); + require_token(m_tok_paren_right); - if (token.is(m_tok_TT_HEAD)) - { - require_token(m_tok_paren_left); - desc.desc.push_back(get_string()); - require_token(m_tok_paren_right); - head_found = true; - } - else if (token.is(m_tok_TT_LINE)) - { - if (!head_found) - error(MF_TT_LINE_WITHOUT_HEAD()); - require_token(m_tok_paren_left); - desc.desc.push_back(get_string()); - require_token(m_tok_paren_right); - } - else if (token.is(m_tok_TT_FAMILY)) - { - require_token(m_tok_paren_left); - desc.family = get_string(); - require_token(m_tok_paren_right); - } - else + netlist::tt_desc desc; + desc.name = nlname; + desc.ni = gsl::narrow<unsigned long>(ni); + desc.no = gsl::narrow<unsigned long>(no); + desc.family = ""; + + while (true) { - require_token(token, m_tok_TRUTHTABLE_END); - require_token(m_tok_paren_left); - require_token(m_tok_paren_right); - // FIXME: proper location - m_setup.truth_table_create(desc, def_param, location()); - return; + token_t token = get_token(); + + if (token.is(m_tok_TT_HEAD)) + { + require_token(m_tok_paren_left); + desc.desc.push_back(get_string()); + require_token(m_tok_paren_right); + head_found = true; + } + else if (token.is(m_tok_TT_LINE)) + { + if (!head_found) + error(MF_TT_LINE_WITHOUT_HEAD()); + require_token(m_tok_paren_left); + desc.desc.push_back(get_string()); + require_token(m_tok_paren_right); + } + else if (token.is(m_tok_TT_FAMILY)) + { + require_token(m_tok_paren_left); + desc.family = get_string(); + require_token(m_tok_paren_right); + } + else + { + require_token(token, m_tok_TRUTHTABLE_END); + require_token(m_tok_paren_left); + require_token(m_tok_paren_right); + // FIXME: proper location + m_setup.truth_table_create(desc, def_param, location()); + return; + } } } -} -void parser_t::netdev_netlist_end() -{ - // don't do much - require_token(m_tok_paren_left); - require_token(m_tok_paren_right); -} - -void parser_t::net_model() -{ - require_token(m_tok_paren_left); - pstring model = get_string(); - m_setup.register_model(model); - require_token(m_tok_paren_right); -} + void parser_t::netdev_netlist_end() + { + // don't do much + require_token(m_tok_paren_left); + require_token(m_tok_paren_right); + } -void parser_t::net_sub_model() -{ - require_token(m_tok_paren_left); - pstring model(get_identifier()); - require_token(m_tok_comma); - pstring name = get_identifier(); - require_token(m_tok_paren_right); - - m_setup.namespace_push(name); - m_setup.include(model); - m_setup.namespace_pop(); -} - -void parser_t::frontier() -{ - require_token(m_tok_paren_left); - // don't do much - pstring attachat = get_identifier(); - require_token(m_tok_comma); - auto tok = get_token(); - auto r_IN = stringify_expression(tok); - require_token(tok, m_tok_comma); - tok = get_token(); - auto r_OUT = stringify_expression(tok); - require_token(tok, m_tok_paren_right); - - m_setup.register_frontier(attachat, r_IN, r_OUT); -} - -void parser_t::net_include() -{ - require_token(m_tok_paren_left); - pstring name(get_identifier()); - require_token(m_tok_paren_right); + void parser_t::net_model() + { + require_token(m_tok_paren_left); + pstring model = get_string(); + m_setup.register_model(model); + require_token(m_tok_paren_right); + } - m_setup.include(name); -} + void parser_t::net_sub_model() + { + require_token(m_tok_paren_left); + pstring model(get_identifier()); + require_token(m_tok_comma); + pstring name = get_identifier(); + require_token(m_tok_paren_right); -void parser_t::net_local_source() -{ - // This directive is only for hardcoded netlists. Ignore it here. - require_token(m_tok_paren_left); - pstring name(get_identifier()); - require_token(m_tok_paren_right); + m_setup.namespace_push(name); + m_setup.include(model); + m_setup.namespace_pop(); + } - register_local_as_source(name); -} + void parser_t::frontier() + { + require_token(m_tok_paren_left); + // don't do much + pstring attach_at = get_identifier(); + require_token(m_tok_comma); + auto tok = get_token(); + auto r_IN = stringify_expression(tok); + require_token(tok, m_tok_comma); + tok = get_token(); + auto r_OUT = stringify_expression(tok); + require_token(tok, m_tok_paren_right); -void parser_t::register_local_as_source(const pstring &name) -{ - auto p = m_local.find(name); - if (p != m_local.end()) - m_setup.register_source<source_token_t>(name, p->second); - else - error(MF_LOCAL_SOURCE_NOT_FOUND_1(name)); -} - -void parser_t::net_external_source() -{ - // This directive is only for hardcoded netlists. Ignore it here. - require_token(m_tok_paren_left); - pstring name(get_identifier()); - require_token(m_tok_paren_right); + m_setup.register_frontier(attach_at, r_IN, r_OUT); + } -} + void parser_t::net_include() + { + require_token(m_tok_paren_left); + pstring name(get_identifier()); + require_token(m_tok_paren_right); -void parser_t::net_alias() -{ - require_token(m_tok_paren_left); - pstring alias = get_identifier_or_number(); + m_setup.include(name); + } - require_token(m_tok_comma); + void parser_t::net_local_source() + { + // This directive is only for hardcoded netlists. Ignore it here. + require_token(m_tok_paren_left); + pstring name(get_identifier()); + require_token(m_tok_paren_right); - pstring out = get_identifier(); + register_local_as_source(name); + } - require_token(m_tok_paren_right); + void parser_t::register_local_as_source(const pstring &name) + { + auto p = m_local.find(name); + if (p != m_local.end()) + m_setup.register_source<source_token_t>(name, p->second); + else + error(MF_LOCAL_SOURCE_NOT_FOUND_1(name)); + } - m_setup.log().debug("Parser: Alias: {1} {2}\n", alias, out); - m_setup.register_alias(alias, out); -} + void parser_t::net_external_source() + { + // This directive is only for hardcoded netlists. Ignore it here. + require_token(m_tok_paren_left); + pstring name(get_identifier()); + require_token(m_tok_paren_right); -void parser_t::net_c() -{ - require_token(m_tok_paren_left); - pstring first = get_identifier(); - require_token(m_tok_comma); + } - while (true) + void parser_t::net_alias() { - pstring t1 = get_identifier(); - m_setup.register_link(first , t1); - m_setup.log().debug("Parser: Connect: {1} {2}\n", first, t1); - token_t n = get_token(); - if (n.is(m_tok_paren_right)) - break; - if (!n.is(m_tok_comma)) - error(MF_EXPECTED_COMMA_OR_RP_1(n.str())); - } + require_token(m_tok_paren_left); + pstring alias = get_identifier_or_number(); -} + require_token(m_tok_comma); -void parser_t::dip_pins() -{ - std::vector<pstring> pins; + pstring out = get_identifier(); - require_token(m_tok_paren_left); - pins.push_back(get_identifier()); - require_token(m_tok_comma); + require_token(m_tok_paren_right); - while (true) + m_setup.log().debug("Parser: Alias: {1} {2}\n", alias, out); + m_setup.register_alias(alias, out); + } + + void parser_t::net_c() { - pstring t1 = get_identifier(); - pins.push_back(t1); - token_t n = get_token(); - if (n.is(m_tok_paren_right)) - break; - if (!n.is(m_tok_comma)) - error(MF_EXPECTED_COMMA_OR_RP_1(n.str())); + require_token(m_tok_paren_left); + pstring first = get_identifier(); + require_token(m_tok_comma); + + while (true) + { + pstring t1 = get_identifier(); + m_setup.register_link(first , t1); + m_setup.log().debug("Parser: Connect: {1} {2}\n", first, t1); + token_t n = get_token(); + if (n.is(m_tok_paren_right)) + break; + if (!n.is(m_tok_comma)) + error(MF_EXPECTED_COMMA_OR_RP_1(n.str())); + } + } - if ((pins.size() % 2) == 1) - error(MF_DIPPINS_EQUAL_NUMBER_1(pins[0])); - std::size_t n = pins.size(); - for (std::size_t i = 0; i < n / 2; i++) + + void parser_t::dip_pins() { - m_setup.register_alias(plib::pfmt("{1}")(i+1), pins[i*2]); - m_setup.register_alias(plib::pfmt("{1}")(n-i), pins[i*2 + 1]); + std::vector<pstring> pins; + + require_token(m_tok_paren_left); + pins.push_back(get_identifier()); + require_token(m_tok_comma); + + while (true) + { + pstring t1 = get_identifier(); + pins.push_back(t1); + token_t n = get_token(); + if (n.is(m_tok_paren_right)) + break; + if (!n.is(m_tok_comma)) + error(MF_EXPECTED_COMMA_OR_RP_1(n.str())); + } + if ((pins.size() % 2) == 1) + error(MF_DIPPINS_EQUAL_NUMBER_1(pins[0])); + std::size_t n = pins.size(); + for (std::size_t i = 0; i < n / 2; i++) + { + m_setup.register_alias(plib::pfmt("{1}")(i+1), pins[i*2]); + m_setup.register_alias(plib::pfmt("{1}")(n-i), pins[i*2 + 1]); + } } -} -void parser_t::netdev_param() -{ - require_token(m_tok_paren_left); - pstring param(get_identifier()); - require_token(m_tok_comma); - token_t tok = get_token(); - if (tok.is_type(token_type::STRING)) + void parser_t::netdev_param() { - m_setup.log().debug("Parser: Param: {1} {2}\n", param, tok.str()); - m_setup.register_param(param, tok.str()); - require_token(m_tok_paren_right); + require_token(m_tok_paren_left); + pstring param(get_identifier()); + require_token(m_tok_comma); + token_t tok = get_token(); + if (tok.is_type(token_type::STRING)) + { + m_setup.log().debug("Parser: Param: {1} {2}\n", param, tok.str()); + m_setup.register_param(param, tok.str()); + require_token(m_tok_paren_right); + } + else + { + auto val = stringify_expression(tok); + m_setup.log().debug("Parser: Param: {1} {2}\n", param, val); + m_setup.register_param(param, val); + require_token(tok, m_tok_paren_right); + } } - else + + void parser_t::netdev_default_param() { - auto val = stringify_expression(tok); - m_setup.log().debug("Parser: Param: {1} {2}\n", param, val); - m_setup.register_param(param, val); - require_token(tok, m_tok_paren_right); + require_token(m_tok_paren_left); + pstring param(get_identifier()); + require_token(m_tok_comma); + token_t tok = get_token(); + if (tok.is_type(token_type::STRING)) + { + m_setup.log().debug("Parser: DefParam: {1} {2}\n", param, tok.str()); + m_setup.register_default_param(param, tok.str()); + require_token(m_tok_paren_right); + } + else + { + auto val = stringify_expression(tok); + m_setup.log().debug("Parser: Param: {1} {2}\n", param, val); + m_setup.register_default_param(param, val); + require_token(tok, m_tok_paren_right); + } } -} -void parser_t::netdev_default_param() -{ - require_token(m_tok_paren_left); - pstring param(get_identifier()); - require_token(m_tok_comma); - token_t tok = get_token(); - if (tok.is_type(token_type::STRING)) + void parser_t::netdev_hint() { - m_setup.log().debug("Parser: DefParam: {1} {2}\n", param, tok.str()); - m_setup.register_defparam(param, tok.str()); + require_token(m_tok_paren_left); + pstring id(get_identifier()); + require_token(m_tok_comma); + pstring hint(get_identifier()); + m_setup.register_hint(id, ".HINT_" + hint); require_token(m_tok_paren_right); } - else + + void parser_t::net_register_dev() { - auto val = stringify_expression(tok); - m_setup.log().debug("Parser: Param: {1} {2}\n", param, val); - m_setup.register_defparam(param, val); - require_token(tok, m_tok_paren_right); + require_token(m_tok_paren_left); + pstring type(get_identifier()); + require_token(m_tok_comma); + pstring name(get_identifier()); + require_token(m_tok_paren_right); + + m_setup.register_dev(type, name); } -} -void parser_t::netdev_hint() -{ - require_token(m_tok_paren_left); - pstring id(get_identifier()); - require_token(m_tok_comma); - pstring hint(get_identifier()); - m_setup.register_hint(id, ".HINT_" + hint); - require_token(m_tok_paren_right); -} - -void parser_t::net_register_dev() -{ - require_token(m_tok_paren_left); - pstring type(get_identifier()); - require_token(m_tok_comma); - pstring name(get_identifier()); - require_token(m_tok_paren_right); + void parser_t::device(const pstring &dev_type) + { + std::vector<pstring> params; - m_setup.register_dev(type, name); -} + require_token(m_tok_paren_left); + pstring devname(get_identifier()); -void parser_t::device(const pstring &dev_type) -{ - std::vector<pstring> params; + m_setup.log().debug("Parser: IC: {1}\n", devname); - require_token(m_tok_paren_left); - pstring devname(get_identifier()); + auto tok(get_token()); - m_setup.log().debug("Parser: IC: {1}\n", devname); + while (tok.is(m_tok_comma)) + { + tok = get_token(); + if (tok.is_type(token_type::STRING)) + { + params.push_back(tok.str()); + tok = get_token(); + } + else + { + auto value = stringify_expression(tok); + params.push_back(value); + } + } + + require_token(tok, m_tok_paren_right); + m_setup.register_dev(dev_type, devname, params); + } - auto tok(get_token()); + // ---------------------------------------------------------------------------------------- + // private + // ---------------------------------------------------------------------------------------- - while (tok.is(m_tok_comma)) + pstring parser_t::stringify_expression(token_t &tok) { - tok = get_token(); - if (/*tok.is_type(token_type::IDENTIFIER) ||*/ tok.is_type(token_type::STRING)) + int pc(0); + pstring ret; + while (!tok.is(m_tok_comma)) { - params.push_back(tok.str()); + if (tok.is(m_tok_paren_left)) + pc++; + else if (tok.is(m_tok_paren_right)) + { + if (pc<=0) + break; + pc--; + } + ret += tok.str(); tok = get_token(); } - else - { - auto value = stringify_expression(tok); - params.push_back(value); - } + return ret; } - require_token(tok, m_tok_paren_right); - m_setup.register_dev(dev_type, devname, params); -} - + // ---------------------------------------------------------------------------------------- + // source_token_t + // ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// private -// ---------------------------------------------------------------------------------------- - -pstring parser_t::stringify_expression(token_t &tok) -{ - int pc(0); - pstring ret; - while (!tok.is(m_tok_comma)) + bool source_token_t::parse(nlparse_t &setup, const pstring &name) { - if (tok.is(m_tok_paren_left)) - pc++; - else if (tok.is(m_tok_paren_right)) + if (name == m_name) { - if (pc<=0) - break; - pc--; + auto ret = setup.parse_tokens(m_store, name); + return ret; } - ret += tok.str(); - tok = get_token(); - } - return ret; -} -// ---------------------------------------------------------------------------------------- -// source_token_t -// ---------------------------------------------------------------------------------------- + return false; + } -bool source_token_t::parse(nlparse_t &setup, const pstring &name) -{ - if (name == m_name) + plib::istream_uptr source_token_t::stream([[maybe_unused]] const pstring &name) { - auto ret = setup.parse_tokens(m_store, name); - return ret; + return plib::istream_uptr(); } - return false; -} - -plib::istream_uptr source_token_t::stream([[maybe_unused]] const pstring &name) -{ - return plib::istream_uptr(); -} - - } // namespace netlist diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp index b98ed123a7b..d8040258568 100644 --- a/src/lib/netlist/nl_setup.cpp +++ b/src/lib/netlist/nl_setup.cpp @@ -35,7 +35,7 @@ namespace netlist { pstring alias_fqn = build_fqn(alias); pstring out_fqn = build_fqn(out); - register_alias_nofqn(alias_fqn, out_fqn); + register_alias_no_fqn(alias_fqn, out_fqn); } void nlparse_t::register_dip_alias_arr(const pstring &terms) @@ -70,7 +70,7 @@ namespace netlist void nlparse_t::register_dev(const pstring &classname, const pstring &name, const std::vector<pstring> ¶ms_and_connections, - factory::element_t **felem) + factory::element_t **factory_element) { auto *f = factory().factory_by_name(classname); @@ -98,25 +98,25 @@ namespace netlist if (!params_and_connections.empty()) { - auto ptok(params_and_connections.begin()); - auto ptok_end(params_and_connections.end()); + auto token_ptr(params_and_connections.begin()); + auto token_end(params_and_connections.end()); for (const pstring &tp : parameter_list) { if (plib::startsWith(tp, "+")) { - if (ptok == ptok_end) + if (token_ptr == token_end) { auto err = MF_PARAM_COUNT_MISMATCH_2(name, params_and_connections.size()); log().fatal(err); throw nl_exception(err); //break; } - pstring output_name = *ptok; + pstring output_name = *token_ptr; log().debug("Link: {1} {2}", tp, output_name); register_link(name + "." + tp.substr(1), output_name); - ++ptok; + ++token_ptr; } else if (plib::startsWith(tp, "@")) { @@ -127,30 +127,30 @@ namespace netlist } else { - if (ptok == params_and_connections.end()) + if (token_ptr == token_end) { auto err = MF_PARAM_COUNT_MISMATCH_2(name, params_and_connections.size()); log().fatal(err); throw nl_exception(err); } - pstring paramfq = name + "." + tp; + pstring fully_qualified_name = name + "." + tp; - log().debug("Default parameter: {1}\n", paramfq); + log().debug("Default parameter: {1}\n", fully_qualified_name); - register_param(paramfq, *ptok); + register_param(fully_qualified_name, *token_ptr); - ++ptok; + ++token_ptr; } } - if (ptok != params_and_connections.end()) + if (token_ptr != params_and_connections.end()) { MF_PARAM_COUNT_EXCEEDED_2 err(name, params_and_connections.size()); log().fatal(err); throw nl_exception(err); } } - if (felem != nullptr) - *felem = f; + if (factory_element != nullptr) + *factory_element = f; } void nlparse_t::register_hint(const pstring &object_name, const pstring &hint_name) @@ -240,7 +240,7 @@ namespace netlist { if (idx->second.find("$(") == pstring::npos) { - //* There may be reason ... so make it an INFO + // There may be reason ... so make it an INFO log().info(MI_OVERWRITING_PARAM_1_OLD_2_NEW_3(fqn, idx->second, val)); } @@ -248,7 +248,7 @@ namespace netlist } } - void nlparse_t::register_defparam(const pstring &name, const pstring &def) + void nlparse_t::register_default_param(const pstring &name, const pstring &def) { // strip " from stringified strings pstring val(def); @@ -256,7 +256,7 @@ namespace netlist val = def.substr(1, def.length() - 2); // Replace "@." with the current namespace val = plib::replace_all(val, "@.", namespace_prefix()); - m_abstract.m_defparams.emplace_back(namespace_prefix() + name, val); + m_abstract.m_default_params.emplace_back(namespace_prefix() + name, val); } factory::list_t &nlparse_t::factory() noexcept @@ -284,17 +284,17 @@ namespace netlist register_param(frontier_name + ".RIN", r_IN); register_param(frontier_name + ".ROUT", r_OUT); register_link(frontier_name + ".G", "GND"); - pstring attfn = build_fqn(attach); + pstring attach_fully_qualified_name = build_fqn(attach); pstring front_fqn = build_fqn(frontier_name); bool found = false; for (auto & link : m_abstract.m_links) { - if (link.first == attfn) + if (link.first == attach_fully_qualified_name) { link.first = front_fqn + ".I"; found = true; } - else if (link.second == attfn) + else if (link.second == attach_fully_qualified_name) { link.second = front_fqn + ".I"; found = true; @@ -329,7 +329,7 @@ namespace netlist return namespace_prefix() + obj_name; } - void nlparse_t::register_alias_nofqn(const pstring &alias, const pstring &out) + void nlparse_t::register_alias_no_fqn(const pstring &alias, const pstring &out) { if (!m_abstract.m_alias.insert({alias, out}).second) { @@ -414,12 +414,12 @@ namespace netlist void nlparse_t::remove_connections(const pstring &pin) { // FIXME: check use_cases - remove_connections may be dead - pstring pinfn = build_fqn(pin); + pstring pin_fully_qualified_name = build_fqn(pin); bool found = false; for (auto link = m_abstract.m_links.begin(); link != m_abstract.m_links.end(); ) { - if ((link->first == pinfn) || (link->second == pinfn)) + if ((link->first == pin_fully_qualified_name) || (link->second == pin_fully_qualified_name)) { log().verbose("removing connection: {1} <==> {2}\n", link->first, link->second); link = m_abstract.m_links.erase(link); @@ -451,7 +451,6 @@ namespace netlist } } - // ---------------------------------------------------------------------------------------- // Sources // ---------------------------------------------------------------------------------------- @@ -469,1294 +468,1268 @@ namespace netlist // setup_t // ---------------------------------------------------------------------------------------- + setup_t::setup_t(netlist_state_t &nlstate) + : m_abstract(nlstate.log()) + , m_parser(nlstate.log(), m_abstract) + , m_nlstate(nlstate) + , m_models(m_abstract.m_models) // FIXME : parse abstract_t only + , m_netlist_params(nullptr) + , m_proxy_cnt(0) + { + } -setup_t::setup_t(netlist_state_t &nlstate) - : m_abstract(nlstate.log()) - , m_parser(nlstate.log(), m_abstract) - , m_nlstate(nlstate) - , m_models(m_abstract.m_models) // FIXME : parse abstract_t only - , m_netlist_params(nullptr) - , m_proxy_cnt(0) -{ -} - -pstring setup_t::termtype_as_str(detail::core_terminal_t &in) -{ - switch (in.type()) + pstring setup_t::termtype_as_str(detail::core_terminal_t &in) { - case detail::terminal_type::TERMINAL: - return "TERMINAL"; - case detail::terminal_type::INPUT: - return "INPUT"; - case detail::terminal_type::OUTPUT: - return "OUTPUT"; + switch (in.type()) + { + case detail::terminal_type::TERMINAL: + return "TERMINAL"; + case detail::terminal_type::INPUT: + return "INPUT"; + case detail::terminal_type::OUTPUT: + return "OUTPUT"; + } + return "Error"; // Tease gcc } - return "Error"; // Tease gcc -} -pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def) const -{ - // When `get_intial_param_val` is called the parameter `<name>` is already registered - // and the value `(value_string())` is set to the default value, e.g. "74XX" - // If thus `$(IC5E.A.MODEL)` is given for `name=="IC5E.A.MODEL"` `value_string()` below - // will return the default. - // FIXME: It may be more explicit and stable to test if pattern==name and return - // `def` in this case. - - auto i = m_abstract.m_param_values.find(name); - auto found_pat(false); - pstring v = (i == m_abstract.m_param_values.end()) ? def : i->second; - - do - { - found_pat = false; - auto sp(plib::psplit(v, std::vector<pstring>({"$(", ")"}))); - std::size_t p(0); - v = ""; - while (p < sp.size()) - { - if (sp[p] == "$(") + pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def) const + { + // When `get_intial_param_val` is called the parameter `<name>` is already registered + // and the value `(value_string())` is set to the default value, e.g. "74XX" + // If thus `$(IC5E.A.MODEL)` is given for `name=="IC5E.A.MODEL"` `value_string()` below + // will return the default. + // FIXME: It may be more explicit and stable to test if pattern==name and return + // `def` in this case. + + auto i = m_abstract.m_param_values.find(name); + auto found_pat(false); + pstring v = (i == m_abstract.m_param_values.end()) ? def : i->second; + + do + { + found_pat = false; + auto sp(plib::psplit(v, std::vector<pstring>({"$(", ")"}))); + std::size_t p(0); + v = ""; + while (p < sp.size()) { - p++; - pstring r; - while (p < sp.size() && sp[p] != ")") - r += sp[p++]; - p++; - auto k = m_params.find(r); - if (k != m_params.end()) + if (sp[p] == "$(") { - v = v + k->second.param().value_string(); - found_pat = true; + p++; + pstring r; + while (p < sp.size() && sp[p] != ")") + r += sp[p++]; + p++; + auto k = m_params.find(r); + if (k != m_params.end()) + { + v = v + k->second.param().value_string(); + found_pat = true; + } + else + { + // pass - on + v = v + "$(" + r + ")"; + } } else - { - // pass - on - v = v + "$(" + r + ")"; - } + v += sp[p++]; } - else - v += sp[p++]; - } - } while (found_pat); + } while (found_pat); - return v; -} + return v; + } -void setup_t::register_term(detail::core_terminal_t &term) -{ - log().debug("{1} {2}\n", termtype_as_str(term), term.name()); - if (!m_terminals.insert({term.name(), &term}).second) + void setup_t::register_term(detail::core_terminal_t &term) { - log().fatal(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name())); - throw nl_exception(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name())); + log().debug("{1} {2}\n", termtype_as_str(term), term.name()); + if (!m_terminals.insert({term.name(), &term}).second) + { + log().fatal(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name())); + throw nl_exception(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name())); + } } -} -void setup_t::register_term(terminal_t &term, terminal_t *other_term, const std::array<terminal_t *, 2> &splitter_terms) -{ - this->register_term(term); - m_connected_terminals.insert({&term, {other_term, splitter_terms[0], splitter_terms[1], nullptr}}); -} + void setup_t::register_term(terminal_t &term, terminal_t *other_term, const std::array<terminal_t *, 2> &splitter_terms) + { + this->register_term(term); + m_connected_terminals.insert({&term, {other_term, splitter_terms[0], splitter_terms[1], nullptr}}); + } -void setup_t::register_param_t(param_t ¶m) -{ - if (!m_params.insert({param.name(), param_ref_t(param.device(), param)}).second) + void setup_t::register_param_t(param_t ¶m) { - log().fatal(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name())); - throw nl_exception(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name())); + if (!m_params.insert({param.name(), param_ref_t(param.device(), param)}).second) + { + log().fatal(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name())); + throw nl_exception(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name())); + } } -} -pstring setup_t::resolve_alias(const pstring &name) const -{ - pstring temp = name; - pstring ret; + pstring setup_t::resolve_alias(const pstring &name) const + { + pstring temp = name; + pstring ret; - // FIXME: Detect endless loop - do { - ret = temp; - auto p = m_abstract.m_alias.find(ret); - temp = (p != m_abstract.m_alias.end() ? p->second : ""); - } while (!temp.empty() && temp != ret); + // FIXME: Detect endless loop + do { + ret = temp; + auto p = m_abstract.m_alias.find(ret); + temp = (p != m_abstract.m_alias.end() ? p->second : ""); + } while (!temp.empty() && temp != ret); - log().debug("{1}==>{2}\n", name, ret); - return ret; -} + log().debug("{1}==>{2}\n", name, ret); + return ret; + } -pstring setup_t::de_alias(const pstring &alias) const -{ - pstring temp = alias; - pstring ret; + pstring setup_t::de_alias(const pstring &alias) const + { + pstring temp = alias; + pstring ret; - // FIXME: Detect endless loop - do { - ret = temp; - temp = ""; - for (const auto &e : m_abstract.m_alias) - { - // FIXME: this will resolve first one found - if (e.second == ret) + // FIXME: Detect endless loop + do { + ret = temp; + temp = ""; + for (const auto &e : m_abstract.m_alias) { - temp = e.first; - break; + // FIXME: this will resolve first one found + if (e.second == ret) + { + temp = e.first; + break; + } } - } - } while (!temp.empty() && temp != ret); + } while (!temp.empty() && temp != ret); - log().debug("{1}==>{2}\n", alias, ret); - return ret; -} + log().debug("{1}==>{2}\n", alias, ret); + return ret; + } -std::vector<pstring> setup_t::get_terminals_for_device_name(const pstring &devname) const -{ - std::vector<pstring> terms; - for (const auto & t : m_terminals) + std::vector<pstring> setup_t::get_terminals_for_device_name(const pstring &devname) const { - if (plib::startsWith(t.second->name(), devname)) + std::vector<pstring> terms; + for (const auto & t : m_terminals) { - pstring tn(t.second->name().substr(devname.length()+1)); - if (tn.find('.') == pstring::npos) - terms.push_back(tn); + if (plib::startsWith(t.second->name(), devname)) + { + pstring tn(t.second->name().substr(devname.length()+1)); + if (tn.find('.') == pstring::npos) + terms.push_back(tn); + } } - } - for (const auto & t : m_abstract.m_alias) - { - if (plib::startsWith(t.first, devname)) + for (const auto & t : m_abstract.m_alias) { - pstring tn(t.first.substr(devname.length()+1)); - if (tn.find('.') == pstring::npos) + if (plib::startsWith(t.first, devname)) { - terms.push_back(tn); - pstring resolved = resolve_alias(t.first); - if (resolved != t.first) + pstring tn(t.first.substr(devname.length()+1)); + if (tn.find('.') == pstring::npos) { - auto found = std::find(terms.begin(), terms.end(), resolved.substr(devname.length()+1)); - if (found!=terms.end()) - terms.erase(found); + terms.push_back(tn); + pstring resolved = resolve_alias(t.first); + if (resolved != t.first) + { + auto found = std::find(terms.begin(), terms.end(), resolved.substr(devname.length()+1)); + if (found!=terms.end()) + terms.erase(found); + } } } } + return terms; } - return terms; -} -detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, bool required) const -{ - const pstring &tname = resolve_alias(terminal_in); - auto ret = m_terminals.find(tname); - // look for default - if (ret == m_terminals.end()) + detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, bool required) const { - // look for ".Q" std output - ret = m_terminals.find(tname + ".Q"); - } - - detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second); + const pstring &tname = resolve_alias(terminal_in); + auto ret = m_terminals.find(tname); + // look for default + if (ret == m_terminals.end()) + { + // look for ".Q" std output + ret = m_terminals.find(tname + ".Q"); + } - if (term == nullptr && required) - { - log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); - throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); - } - if (term != nullptr) - { - log().debug("Found input {1}\n", tname); - } + detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second); - return term; -} + if (term == nullptr && required) + { + log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); + throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); + } + if (term != nullptr) + { + log().debug("Found input {1}\n", tname); + } -detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, - detail::terminal_type atype, bool required) const -{ - const pstring &tname = resolve_alias(terminal_in); - auto ret = m_terminals.find(tname); - // look for default - if (ret == m_terminals.end() && atype == detail::terminal_type::OUTPUT) - { - // look for ".Q" std output - ret = m_terminals.find(tname + ".Q"); + return term; } - if (ret == m_terminals.end() && required) - { - log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); - throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); - } - detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second); - if (term != nullptr && term->type() != atype) + detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, + detail::terminal_type atype, bool required) const { - if (required) + const pstring &tname = resolve_alias(terminal_in); + auto ret = m_terminals.find(tname); + // look for default + if (ret == m_terminals.end() && atype == detail::terminal_type::OUTPUT) + { + // look for ".Q" std output + ret = m_terminals.find(tname + ".Q"); + } + if (ret == m_terminals.end() && required) { - log().fatal(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname)); - throw nl_exception(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname)); + log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); + throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname)); } + detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second); - term = nullptr; - } - if (term != nullptr) - log().debug("Found input {1}\n", tname); + if (term != nullptr && term->type() != atype) + { + if (required) + { + log().fatal(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname)); + throw nl_exception(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname)); + } - return term; -} + term = nullptr; + } + if (term != nullptr) + log().debug("Found input {1}\n", tname); -param_ref_t setup_t::find_param(const pstring ¶m_in) const -{ - const pstring resolved_param_name(resolve_alias(param_in)); - auto ret(m_params.find(resolved_param_name)); - if (ret == m_params.end()) + return term; + } + + param_ref_t setup_t::find_param(const pstring ¶m_in) const { - log().fatal(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name)); - throw nl_exception(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name)); + const pstring resolved_param_name(resolve_alias(param_in)); + auto ret(m_params.find(resolved_param_name)); + if (ret == m_params.end()) + { + log().fatal(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name)); + throw nl_exception(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name)); + } + return ret->second; } - return ret->second; -} + //NOLINTNEXTLINE(misc-no-recursion) + devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &out) + { + gsl_Expects(out.is_logic()); -//NOLINTNEXTLINE(misc-no-recursion) -devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &out) -{ - gsl_Expects(out.is_logic()); + const auto &out_cast = dynamic_cast<const logic_output_t &>(out); + auto iter_proxy(m_proxies.find(&out)); - const auto &out_cast = dynamic_cast<const logic_output_t &>(out); - auto iter_proxy(m_proxies.find(&out)); + if (iter_proxy != m_proxies.end()) + return iter_proxy->second; - if (iter_proxy != m_proxies.end()) - return iter_proxy->second; + // create a new one ... + pstring x = plib::pfmt("proxy_da_{1}_{2}")(out.name())(m_proxy_cnt); + auto new_proxy = + out_cast.logic_family()->create_d_a_proxy(m_nlstate, x, &out_cast); + m_proxy_cnt++; + // connect all existing terminals to new net - // create a new one ... - pstring x = plib::pfmt("proxy_da_{1}_{2}")(out.name())(m_proxy_cnt); - auto new_proxy = - out_cast.logic_family()->create_d_a_proxy(m_nlstate, x, &out_cast); - m_proxy_cnt++; - // connect all existing terminals to new net + // Get a copy first + auto temp_terminals(out.net().core_terms_copy()); + // remove all terminals from out.net() + out.net().remove_all_terminals(); - for (auto & p : nlstate().core_terms(out.net())) - { - p->clear_net(); // de-link from all nets ... - if (!connect(new_proxy->proxy_term(), *p)) + for (detail::core_terminal_t * p : temp_terminals) { - log().fatal(MF_CONNECTING_1_TO_2( - new_proxy->proxy_term().name(), (*p).name())); - throw nl_exception(MF_CONNECTING_1_TO_2( - new_proxy->proxy_term().name(), (*p).name())); + p->clear_net(); // de-link from all nets ... + if (!connect(new_proxy->proxy_term(), *p)) + { + log().fatal(MF_CONNECTING_1_TO_2( + new_proxy->proxy_term().name(), (*p).name())); + throw nl_exception(MF_CONNECTING_1_TO_2( + new_proxy->proxy_term().name(), (*p).name())); + } } - } - nlstate().core_terms(out.net()).clear(); - add_terminal(out.net(), new_proxy->in()); + out.net().add_terminal(new_proxy->in()); - auto *proxy(new_proxy.get()); - if (!m_proxies.insert({&out, proxy}).second) - throw nl_exception(MF_DUPLICATE_PROXY_1(out.name())); + auto *proxy(new_proxy.get()); + if (!m_proxies.insert({&out, proxy}).second) + throw nl_exception(MF_DUPLICATE_PROXY_1(out.name())); - m_nlstate.register_device(new_proxy->name(), std::move(new_proxy)); - return proxy; - -} + m_nlstate.register_device(new_proxy->name(), std::move(new_proxy)); + return proxy; + } -//NOLINTNEXTLINE(misc-no-recursion) -devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp) -{ - gsl_Expects(inp.is_logic()); + //NOLINTNEXTLINE(misc-no-recursion) + devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp) + { + gsl_Expects(inp.is_logic()); - const auto &incast = dynamic_cast<const logic_input_t &>(inp); + const auto &logic_input_terminal = dynamic_cast<const logic_input_t &>(inp); - auto iter_proxy(m_proxies.find(&inp)); + auto iter_proxy(m_proxies.find(&inp)); - if (iter_proxy != m_proxies.end()) - return iter_proxy->second; + if (iter_proxy != m_proxies.end()) + return iter_proxy->second; - log().debug("connect_terminal_input: connecting proxy\n"); - auto new_proxy = incast.logic_family()->create_a_d_proxy(m_nlstate, - plib::pfmt("proxy_ad_{1}_{2}")(inp.name())(m_proxy_cnt), &incast); + log().debug("connect_terminal_input: connecting proxy\n"); + auto new_proxy = + logic_input_terminal.logic_family()->create_a_d_proxy(m_nlstate, + plib::pfmt("proxy_ad_{1}_{2}")(inp.name())(m_proxy_cnt), + &logic_input_terminal); - auto *ret(new_proxy.get()); + auto *ret(new_proxy.get()); - if (!m_proxies.insert({&inp, ret}).second) - throw nl_exception(MF_DUPLICATE_PROXY_1(inp.name())); + if (!m_proxies.insert({&inp, ret}).second) + throw nl_exception(MF_DUPLICATE_PROXY_1(inp.name())); - m_proxy_cnt++; + m_proxy_cnt++; - // connect all existing terminals to new net + // connect all existing terminals to new net - if (inp.has_net()) - { - for (detail::core_terminal_t * p : nlstate().core_terms(inp.net())) + if (inp.has_net()) { - // inp may already belongs to the logic net. Thus skip it here. - // It will be removed by the clear further down. - if (p != &inp) + auto temp_terminals(inp.net().core_terms_copy()); + + inp.net().remove_all_terminals(); + + for (detail::core_terminal_t * p : temp_terminals) { - p->clear_net(); // de-link from all nets ... - if (!connect(ret->proxy_term(), *p)) + // inp may already belongs to the logic net. Thus skip it here. + // It will be removed by the clear further down. + if (p != &inp) { - log().fatal(MF_CONNECTING_1_TO_2( - ret->proxy_term().name(), (*p).name())); - throw nl_exception(MF_CONNECTING_1_TO_2( - ret->proxy_term().name(), (*p).name())); + p->clear_net(); // de-link from all nets ... + if (!connect(ret->proxy_term(), *p)) + { + log().fatal(MF_CONNECTING_1_TO_2( + ret->proxy_term().name(), (*p).name())); + throw nl_exception(MF_CONNECTING_1_TO_2( + ret->proxy_term().name(), (*p).name())); + } } } } - nlstate().core_terms(inp.net()).clear(); // clear the list + inp.clear_net(); + ret->out().net().add_terminal(inp); + m_nlstate.register_device(new_proxy->name(), std::move(new_proxy)); + return ret; } - inp.clear_net(); - add_terminal(ret->out().net(), inp); - m_nlstate.register_device(new_proxy->name(), std::move(new_proxy)); - return ret; -} -detail::core_terminal_t &setup_t::resolve_proxy(detail::core_terminal_t &term) -{ - if (term.is_logic()) + detail::core_terminal_t &setup_t::resolve_proxy(detail::core_terminal_t &term) { - const auto &out = dynamic_cast<const logic_t &>(term); - auto iter_proxy(m_proxies.find(&out)); - if (iter_proxy != m_proxies.end()) - return iter_proxy->second->proxy_term(); + if (term.is_logic()) + { + const auto &out = dynamic_cast<const logic_t &>(term); + auto iter_proxy(m_proxies.find(&out)); + if (iter_proxy != m_proxies.end()) + return iter_proxy->second->proxy_term(); + } + return term; } - return term; -} - -//NOLINTNEXTLINE(misc-no-recursion) -void setup_t::merge_nets(detail::net_t &this_net, detail::net_t &other_net) -{ - log().debug("merging nets ...\n"); - if (&other_net == &this_net) + //NOLINTNEXTLINE(misc-no-recursion) + void setup_t::merge_nets(detail::net_t &this_net, detail::net_t &other_net) { - log().warning(MW_CONNECTING_1_TO_ITSELF(this_net.name())); - return; // Nothing to do - } + log().debug("merging nets ...\n"); + if (&other_net == &this_net) + { + log().warning(MW_CONNECTING_1_TO_ITSELF(this_net.name())); + return; // Nothing to do + } - if (this_net.is_rail_net() && other_net.is_rail_net()) - { - log().fatal(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name())); - throw nl_exception(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name())); - } + if (this_net.is_rail_net() && other_net.is_rail_net()) + { + log().fatal(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name())); + throw nl_exception(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name())); + } - if (other_net.is_rail_net()) - { - log().debug("other net is a rail net\n"); - merge_nets(other_net, this_net); - } - else - { - move_connections(other_net, this_net); + if (other_net.is_rail_net()) + { + log().debug("other net is a rail net\n"); + merge_nets(other_net, this_net); + } + else + { + move_connections(other_net, this_net); + } } -} - -//NOLINTNEXTLINE(misc-no-recursion) -void setup_t::connect_input_output(detail::core_terminal_t &in, detail::core_terminal_t &out) -{ - if (out.is_analog() && in.is_logic()) + //NOLINTNEXTLINE(misc-no-recursion) + void setup_t::connect_input_output(detail::core_terminal_t &in, detail::core_terminal_t &out) { - auto *proxy = get_a_d_proxy(in); + if (out.is_analog() && in.is_logic()) + { + auto *proxy = get_a_d_proxy(in); - add_terminal(out.net(), proxy->proxy_term()); - } - else if (out.is_logic() && in.is_analog()) - { - devices::nld_base_proxy *proxy = get_d_a_proxy(out); + out.net().add_terminal(proxy->proxy_term()); + } + else if (out.is_logic() && in.is_analog()) + { + devices::nld_base_proxy *proxy = get_d_a_proxy(out); - connect_terminals(proxy->proxy_term(), in); - //proxy->out().net().register_con(in); - } - else - { - if (in.has_net()) - merge_nets(out.net(), in.net()); + connect_terminals(proxy->proxy_term(), in); + //proxy->out().net().register_con(in); + } else - add_terminal(out.net(), in); + { + if (in.has_net()) + merge_nets(out.net(), in.net()); + else + out.net().add_terminal(in); + } } -} - -//NOLINTNEXTLINE(misc-no-recursion) -void setup_t::connect_terminal_input(terminal_t &term, detail::core_terminal_t &inp) -{ - if (inp.is_analog()) + //NOLINTNEXTLINE(misc-no-recursion) + void setup_t::connect_terminal_input(terminal_t &term, detail::core_terminal_t &inp) { - connect_terminals(inp, term); - } - else if (inp.is_logic()) - { - log().verbose("connect terminal {1} (in, {2}) to {3}\n", inp.name(), - inp.is_analog() ? "analog" : inp.is_logic() ? "logic" : "?", term.name()); - auto *proxy = get_a_d_proxy(inp); + if (inp.is_analog()) + { + connect_terminals(inp, term); + } + else if (inp.is_logic()) + { + log().verbose("connect terminal {1} (in, {2}) to {3}\n", inp.name(), + inp.is_analog() ? "analog" : inp.is_logic() ? "logic" : "?", term.name()); + auto *proxy = get_a_d_proxy(inp); - //out.net().register_con(proxy->proxy_term()); - connect_terminals(term, proxy->proxy_term()); + //out.net().register_con(proxy->proxy_term()); + connect_terminals(term, proxy->proxy_term()); + } + else + { + log().fatal(MF_OBJECT_INPUT_TYPE_1(inp.name())); + throw nl_exception(MF_OBJECT_INPUT_TYPE_1(inp.name())); + } } - else - { - log().fatal(MF_OBJECT_INPUT_TYPE_1(inp.name())); - throw nl_exception(MF_OBJECT_INPUT_TYPE_1(inp.name())); - } -} - -//NOLINTNEXTLINE(misc-no-recursion) -void setup_t::connect_terminal_output(terminal_t &in, detail::core_terminal_t &out) -{ - if (out.is_analog()) + //NOLINTNEXTLINE(misc-no-recursion) + void setup_t::connect_terminal_output(terminal_t &in, detail::core_terminal_t &out) { - log().debug("connect_terminal_output: {1} {2}\n", in.name(), out.name()); - // no proxy needed, just merge existing terminal net - if (in.has_net()) + if (out.is_analog()) { - if (&out.net() != &in.net()) - merge_nets(out.net(), in.net()); + log().debug("connect_terminal_output: {1} {2}\n", in.name(), out.name()); + // no proxy needed, just merge existing terminal net + if (in.has_net()) + { + if (&out.net() != &in.net()) + merge_nets(out.net(), in.net()); + else + // Only an info - some ICs (CD4538) connect pins internally to GND + // and the schematics again externally. This will cause this warning. + // FIXME: Add a hint to suppress the warning. + log().info(MI_CONNECTING_1_TO_2_SAME_NET(in.name(), out.name(), in.net().name())); + } else - // Only an info - some ICs (CD4538) connect pins internally to GND - // and the schematics again externally. This will cause this warning. - // FIXME: Add a hint to suppress the warning. - log().info(MI_CONNECTING_1_TO_2_SAME_NET(in.name(), out.name(), in.net().name())); + out.net().add_terminal(in); } - else - add_terminal(out.net(), in); - } - else if (out.is_logic()) - { - log().debug("connect_terminal_output: connecting proxy\n"); - devices::nld_base_proxy *proxy = get_d_a_proxy(out); + else if (out.is_logic()) + { + log().debug("connect_terminal_output: connecting proxy\n"); + devices::nld_base_proxy *proxy = get_d_a_proxy(out); - connect_terminals(proxy->proxy_term(), in); - } - else - { - log().fatal(MF_OBJECT_OUTPUT_TYPE_1(out.name())); - throw nl_exception(MF_OBJECT_OUTPUT_TYPE_1(out.name())); + connect_terminals(proxy->proxy_term(), in); + } + else + { + log().fatal(MF_OBJECT_OUTPUT_TYPE_1(out.name())); + throw nl_exception(MF_OBJECT_OUTPUT_TYPE_1(out.name())); + } } -} -void setup_t::connect_terminals(detail::core_terminal_t &t1,detail::core_terminal_t &t2) -{ - if (t1.has_net() && t2.has_net()) - { - log().debug("T2 and T1 have net\n"); - merge_nets(t1.net(), t2.net()); - } - else if (t2.has_net()) - { - log().debug("T2 has net\n"); - add_terminal(t2.net(), t1); - } - else if (t1.has_net()) + void setup_t::connect_terminals(detail::core_terminal_t &t1,detail::core_terminal_t &t2) { - log().debug("T1 has net\n"); - add_terminal(t1.net(), t2); - } - else - { - log().debug("adding analog net ...\n"); - // FIXME: Nets should have a unique name - auto anet = plib::make_owned<analog_net_t>(nlstate().pool(), m_nlstate,"net." + t1.name()); - auto *anetp = anet.get(); - m_nlstate.register_net(std::move(anet)); - t1.set_net(anetp); - add_terminal(*anetp, t2); - add_terminal(*anetp, t1); + if (t1.has_net() && t2.has_net()) + { + log().debug("T2 and T1 have net\n"); + merge_nets(t1.net(), t2.net()); + } + else if (t2.has_net()) + { + log().debug("T2 has net\n"); + t2.net().add_terminal(t1); + } + else if (t1.has_net()) + { + log().debug("T1 has net\n"); + t1.net().add_terminal(t2); + } + else + { + log().debug("adding analog net ...\n"); + // FIXME: Nets should have a unique name + auto new_net_uptr = plib::make_owned<analog_net_t>(nlstate().pool(), m_nlstate,"net." + t1.name()); + auto *new_net_ptr = new_net_uptr.get(); + m_nlstate.register_net(std::move(new_net_uptr)); + t1.set_net(new_net_ptr); + new_net_ptr->add_terminal(t2); + new_net_ptr->add_terminal(t1); + } } -} -//NOLINTNEXTLINE(misc-no-recursion) -bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_terminal_t &t2) -{ - bool ret = false; - if (t1.has_net()) + //NOLINTNEXTLINE(misc-no-recursion) + bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_terminal_t &t2) { - if (t1.net().is_rail_net()) - ret = connect(t2, t1.net().rail_terminal()); - if (!ret) + bool ret = false; + if (t1.has_net()) { - for (auto & t : nlstate().core_terms(t1.net())) + if (t1.net().is_rail_net()) + ret = connect(t2, t1.net().rail_terminal()); + if (!ret) { - if (t->is_type(detail::terminal_type::TERMINAL)) - ret = connect(t2, *t); - if (ret) - break; + for (detail::core_terminal_t * t : t1.net().core_terms_copy()) + { + if (t->is_type(detail::terminal_type::TERMINAL)) + ret = connect(t2, *t); + if (ret) + break; + } } } - } - if (!ret && t2.has_net()) - { - if (t2.net().is_rail_net()) - ret = connect(t1, t2.net().rail_terminal()); - if (!ret) + if (!ret && t2.has_net()) { - for (auto & t : nlstate().core_terms(t2.net())) + if (t2.net().is_rail_net()) + ret = connect(t1, t2.net().rail_terminal()); + if (!ret) { - if (t->is_type(detail::terminal_type::TERMINAL)) - ret = connect(t1, *t); - if (ret) - break; + for (detail::core_terminal_t * t : t2.net().core_terms_copy()) + { + if (t->is_type(detail::terminal_type::TERMINAL)) + ret = connect(t1, *t); + if (ret) + break; + } } } + return ret; } - return ret; -} - -//NOLINTNEXTLINE(misc-no-recursion) -bool setup_t::connect(detail::core_terminal_t &t1_in, detail::core_terminal_t &t2_in) -{ - log().debug("Connecting {1} to {2}\n", t1_in.name(), t2_in.name()); - detail::core_terminal_t &t1 = resolve_proxy(t1_in); - detail::core_terminal_t &t2 = resolve_proxy(t2_in); - bool ret = true; - - if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::INPUT)) + //NOLINTNEXTLINE(misc-no-recursion) + bool setup_t::connect(detail::core_terminal_t &t1_in, detail::core_terminal_t &t2_in) { - if (t2.has_net() && t2.net().is_rail_net()) + log().debug("Connecting {1} to {2}\n", t1_in.name(), t2_in.name()); + detail::core_terminal_t &t1 = resolve_proxy(t1_in); + detail::core_terminal_t &t2 = resolve_proxy(t2_in); + bool ret = true; + + if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::INPUT)) { - log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t2.name())); - throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t2.name())); + if (t2.has_net() && t2.net().is_rail_net()) + { + log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t2.name())); + throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t2.name())); + } + connect_input_output(t2, t1); } - connect_input_output(t2, t1); - } - else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::OUTPUT)) - { - if (t1.has_net() && t1.net().is_rail_net()) + else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::OUTPUT)) { - log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t1.name())); - throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t1.name())); + if (t1.has_net() && t1.net().is_rail_net()) + { + log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t1.name())); + throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t1.name())); + } + connect_input_output(t1, t2); } - connect_input_output(t1, t2); - } - else if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::TERMINAL)) - { - connect_terminal_output(dynamic_cast<terminal_t &>(t2), t1); - } - else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::OUTPUT)) - { - connect_terminal_output(dynamic_cast<terminal_t &>(t1), t2); - } - else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::TERMINAL)) - { - connect_terminal_input(dynamic_cast<terminal_t &>(t2), t1); - } - else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::INPUT)) - { - connect_terminal_input(dynamic_cast<terminal_t &>(t1), t2); - } - else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::TERMINAL)) - { - connect_terminals(dynamic_cast<terminal_t &>(t1), dynamic_cast<terminal_t &>(t2)); - } - else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::INPUT)) - { - ret = connect_input_input(t1, t2); - } - else - { - ret = false; - } - return ret; -} - -void setup_t::resolve_inputs() -{ - log().verbose("Resolving inputs ..."); - - // Netlist can directly connect input to input. - // We therefore first park connecting inputs and retry - // after all other terminals were connected. - - unsigned tries = m_netlist_params->m_max_link_loops(); -#if 0 - // This code fails for some netlists when the element at position 0 - // is deleted. It will fail somewhere deep in std::pair releasing - // std::string called from erase. - // - // One example is the this netlist: - // - // #include "netlist/devices/net_lib.h" - // NETLIST_START(charge_discharge) - // SOLVER(solver, 48000) // Fixed frequency solver - // CLOCK(I, 200) // 200 Hz clock as input, TTL logic output - // RES(R, RES_K(1)) - // CAP(C, CAP_U(1)) - // - // NET_C(I.Q, R.1) - // NET_C(R.2, C.1) - // NET_C(C.2, GND) - // - // ALIAS(O, R.2) // Output O == C.1 == R.2 - // // NETLIST_END() - // - // Just save the net list as /tmp/test1.cpp, run - // ./nltool --cmd=run -t 0.05 -l O -l I /tmp/test1.cpp - // and see it crash with this code enabled. - // - // g++-7 (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0 - // - while (!m_links.empty() && tries > 0) - { - auto li = m_links.begin(); - while (li != m_links.end()) + else if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::TERMINAL)) { - const pstring t1s = li->first; - const pstring t2s = li->second; - detail::core_terminal_t *t1 = find_terminal(t1s); - detail::core_terminal_t *t2 = find_terminal(t2s); - - if (connect(*t1, *t2)) - li = m_links.erase(li); - else - li++; + connect_terminal_output(dynamic_cast<terminal_t &>(t2), t1); } - tries--; - } -#else - while (!m_abstract.m_links.empty() && tries > 0) - { - for (std::size_t i = 0; i < m_abstract.m_links.size(); ) + else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::OUTPUT)) { - const pstring t1s(m_abstract.m_links[i].first); - const pstring t2s(m_abstract.m_links[i].second); - detail::core_terminal_t *t1 = find_terminal(t1s); - detail::core_terminal_t *t2 = find_terminal(t2s); - if (connect(*t1, *t2)) - m_abstract.m_links.erase(m_abstract.m_links.begin() + plib::narrow_cast<std::ptrdiff_t>(i)); - else - i++; + connect_terminal_output(dynamic_cast<terminal_t &>(t1), t2); } - tries--; - } -#endif - if (tries == 0) - { - for (auto & link : m_abstract.m_links) - log().warning(MF_CONNECTING_1_TO_2(de_alias(link.first), de_alias(link.second))); - - log().fatal(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops())); - throw nl_exception(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops())); - } - - log().verbose("deleting empty nets ..."); - - // delete empty nets - - delete_empty_nets(); - - bool err(false); - - log().verbose("looking for terminals not connected ..."); - for (auto & i : m_terminals) - { - detail::core_terminal_t *term = i.second; - const pstring name_da = de_alias(term->name()); - bool is_nc_pin(dynamic_cast< devices::NETLIB_NAME(nc_pin) *>(&term->device()) != nullptr); - bool is_nc_flagged(false); - - auto hnc = m_abstract.m_hints.find(name_da + sHINT_NC); - if (hnc != m_abstract.m_hints.end()) + else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::TERMINAL)) { - hnc->second = true; // mark as used - is_nc_flagged = true; + connect_terminal_input(dynamic_cast<terminal_t &>(t2), t1); } - - if (term->has_net() && is_nc_pin) + else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::INPUT)) { - log().error(ME_NC_PIN_1_WITH_CONNECTIONS(name_da)); - err = true; + connect_terminal_input(dynamic_cast<terminal_t &>(t1), t2); } - else if (is_nc_pin) + else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::TERMINAL)) { - /* ignore */ + connect_terminals(dynamic_cast<terminal_t &>(t1), dynamic_cast<terminal_t &>(t2)); } - else if (!term->has_net()) + else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::INPUT)) { - log().error(ME_TERMINAL_1_WITHOUT_NET(name_da)); - err = true; + ret = connect_input_input(t1, t2); } - else if (nlstate().core_terms(term->net()).empty()) + else { - if (term->is_logic_input()) - log().warning(MW_LOGIC_INPUT_1_WITHOUT_CONNECTIONS(name_da)); - else if (term->is_logic_output()) + ret = false; + } + return ret; + } + + void setup_t::resolve_inputs() + { + log().verbose("Resolving inputs ..."); + + // Netlist can directly connect input to input. + // We therefore first park connecting inputs and retry + // after all other terminals were connected. + + unsigned tries = m_netlist_params->m_max_link_loops(); + #if 0 + // This code fails for some netlists when the element at position 0 + // is deleted. It will fail somewhere deep in std::pair releasing + // std::string called from erase. + // + // One example is the this netlist: + // + // #include "netlist/devices/net_lib.h" + // NETLIST_START(charge_discharge) + // SOLVER(solver, 48000) // Fixed frequency solver + // CLOCK(I, 200) // 200 Hz clock as input, TTL logic output + // RES(R, RES_K(1)) + // CAP(C, CAP_U(1)) + // + // NET_C(I.Q, R.1) + // NET_C(R.2, C.1) + // NET_C(C.2, GND) + // + // ALIAS(O, R.2) // Output O == C.1 == R.2 + // // NETLIST_END() + // + // Just save the net list as /tmp/test1.cpp, run + // ./nltool --cmd=run -t 0.05 -l O -l I /tmp/test1.cpp + // and see it crash with this code enabled. + // + // g++-7 (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0 + // + while (!m_links.empty() && tries > 0) + { + auto li = m_links.begin(); + while (li != m_links.end()) { - if (!is_nc_flagged) - log().info(MI_LOGIC_OUTPUT_1_WITHOUT_CONNECTIONS(name_da)); + const pstring t1s = li->first; + const pstring t2s = li->second; + detail::core_terminal_t *t1 = find_terminal(t1s); + detail::core_terminal_t *t2 = find_terminal(t2s); + + if (connect(*t1, *t2)) + li = m_links.erase(li); + else + li++; } - else if (term->is_analog_output()) + tries--; + } + #else + while (!m_abstract.m_links.empty() && tries > 0) + { + for (std::size_t i = 0; i < m_abstract.m_links.size(); ) { - if (!is_nc_flagged) - log().info(MI_ANALOG_OUTPUT_1_WITHOUT_CONNECTIONS(name_da)); + const pstring t1s(m_abstract.m_links[i].first); + const pstring t2s(m_abstract.m_links[i].second); + detail::core_terminal_t *t1 = find_terminal(t1s); + detail::core_terminal_t *t2 = find_terminal(t2s); + if (connect(*t1, *t2)) + m_abstract.m_links.erase(m_abstract.m_links.begin() + plib::narrow_cast<std::ptrdiff_t>(i)); + else + i++; } - else - log().warning(MW_TERMINAL_1_WITHOUT_CONNECTIONS(name_da)); + tries--; } - } + #endif + if (tries == 0) + { + for (auto & link : m_abstract.m_links) + log().warning(MF_CONNECTING_1_TO_2(de_alias(link.first), de_alias(link.second))); - log().verbose("checking tristate consistency ..."); - for (auto & i : m_terminals) - { - detail::core_terminal_t *term = i.second; - if (term->is_tristate_output()) + log().fatal(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops())); + throw nl_exception(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops())); + } + + log().verbose("deleting empty nets ..."); + + // delete empty nets + + delete_empty_nets(); + + bool err(false); + + log().verbose("looking for terminals not connected ..."); + for (auto & i : m_terminals) { - const auto &tri(dynamic_cast<tristate_output_t &>(*term)); - // check if we are connected to a proxy - const auto iter_proxy(m_proxies.find(&tri)); + detail::core_terminal_t *term = i.second; + const pstring name_da = de_alias(term->name()); + bool is_nc_pin(dynamic_cast< devices::NETLIB_NAME(nc_pin) *>(&term->device()) != nullptr); + bool is_nc_flagged(false); + + auto hnc = m_abstract.m_hints.find(name_da + sHINT_NC); + if (hnc != m_abstract.m_hints.end()) + { + hnc->second = true; // mark as used + is_nc_flagged = true; + } - if (iter_proxy == m_proxies.end() && !tri.is_force_logic()) + if (term->has_net() && is_nc_pin) { - log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name())); + log().error(ME_NC_PIN_1_WITH_CONNECTIONS(name_da)); err = true; } - else if (iter_proxy != m_proxies.end() && tri.is_force_logic()) + else if (is_nc_pin) + { + // ignore + } + else if (!term->has_net()) { - log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name())); + log().error(ME_TERMINAL_1_WITHOUT_NET(name_da)); err = true; } + else if (term->net().core_terms_empty()) + { + if (term->is_logic_input()) + log().warning(MW_LOGIC_INPUT_1_WITHOUT_CONNECTIONS(name_da)); + else if (term->is_logic_output()) + { + if (!is_nc_flagged) + log().info(MI_LOGIC_OUTPUT_1_WITHOUT_CONNECTIONS(name_da)); + } + else if (term->is_analog_output()) + { + if (!is_nc_flagged) + log().info(MI_ANALOG_OUTPUT_1_WITHOUT_CONNECTIONS(name_da)); + } + else + log().warning(MW_TERMINAL_1_WITHOUT_CONNECTIONS(name_da)); + } } - } - if (err) - { - log().fatal(MF_TERMINALS_WITHOUT_NET()); - throw nl_exception(MF_TERMINALS_WITHOUT_NET()); - } -} + log().verbose("checking tristate consistency ..."); + for (auto & i : m_terminals) + { + detail::core_terminal_t *term = i.second; + if (term->is_tristate_output()) + { + const auto &tri(dynamic_cast<tristate_output_t &>(*term)); + // check if we are connected to a proxy + const auto iter_proxy(m_proxies.find(&tri)); -void setup_t::add_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false) -{ - for (auto &t : nlstate().core_terms(net)) - if (t == &terminal) + if (iter_proxy == m_proxies.end() && !tri.is_force_logic()) + { + log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name())); + err = true; + } + else if (iter_proxy != m_proxies.end() && tri.is_force_logic()) + { + log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name())); + err = true; + } + } + } + if (err) { - log().fatal(MF_NET_1_DUPLICATE_TERMINAL_2(net.name(), t->name())); - throw nl_exception(MF_NET_1_DUPLICATE_TERMINAL_2(net.name(), t->name())); + log().fatal(MF_TERMINALS_WITHOUT_NET()); + throw nl_exception(MF_TERMINALS_WITHOUT_NET()); } - terminal.set_net(&net); - - nlstate().core_terms(net).push_back(&terminal); -} - -void setup_t::remove_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false) -{ - if (plib::container::contains(nlstate().core_terms(net), &terminal)) - { - terminal.set_net(nullptr); - plib::container::remove(nlstate().core_terms(net), &terminal); } - else + + void setup_t::move_connections(detail::net_t &net, detail::net_t &dest_net) { - log().fatal(MF_REMOVE_TERMINAL_1_FROM_NET_2(terminal.name(), net.name())); - throw nl_exception(MF_REMOVE_TERMINAL_1_FROM_NET_2(terminal.name(), net.name())); - } -} + auto temp(net.core_terms_copy()); -void setup_t::move_connections(detail::net_t &net, detail::net_t &dest_net) -{ - for (auto &ct : nlstate().core_terms(net)) - add_terminal(dest_net, *ct); - nlstate().core_terms(net).clear(); -} + net.remove_all_terminals(); + for (detail::core_terminal_t * ct : temp) + { + dest_net.add_terminal(*ct); + } + } + log_type &setup_t::log() noexcept { return m_nlstate.log(); } + const log_type &setup_t::log() const noexcept { return m_nlstate.log(); } -log_type &setup_t::log() noexcept { return m_nlstate.log(); } -const log_type &setup_t::log() const noexcept { return m_nlstate.log(); } + // ---------------------------------------------------------------------------------------- + // Models + // ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// Models -// ---------------------------------------------------------------------------------------- + //NOLINTNEXTLINE(misc-no-recursion) + void models_t::model_parse(const pstring &model_in, map_t &map) + { + pstring model = model_in; + std::size_t pos = 0; + pstring key; + while (true) + { + pos = model.find('('); + if (pos != pstring::npos) break; -//NOLINTNEXTLINE(misc-no-recursion) -void models_t::model_parse(const pstring &model_in, map_t &map) -{ - pstring model = model_in; - std::size_t pos = 0; - pstring key; + key = plib::ucase(model); + auto i = m_models.find(key); + if (i == m_models.end()) + { + throw nl_exception(MF_MODEL_NOT_FOUND(pstring("xx") + model)); + } - while (true) - { - pos = model.find('('); - if (pos != pstring::npos) break; + model = i->second; + } + pstring base_model = plib::left(model, pos); - key = plib::ucase(model); - auto i = m_models.find(key); - if (i == m_models.end()) + if (base_model == "_") + map["COREMODEL"] = key; + else { - throw nl_exception(MF_MODEL_NOT_FOUND(pstring("xx") + model)); + auto i = m_models.find(base_model); + if (i != m_models.end()) + model_parse(base_model, map); + else + throw nl_exception(MF_MODEL_NOT_FOUND(model_in)); } - model = i->second; - } - pstring xmodel = plib::left(model, pos); + pstring remainder = plib::trim(model.substr(pos + 1)); + if (!plib::endsWith(remainder, ")")) + throw nl_exception(MF_MODEL_ERROR_1(model)); + // FIMXE: Not optimal + remainder = plib::left(remainder, remainder.length() - 1); - if (xmodel == "_") - map["COREMODEL"] = key; - else - { - auto i = m_models.find(xmodel); - if (i != m_models.end()) - model_parse(xmodel, map); - else - throw nl_exception(MF_MODEL_NOT_FOUND(model_in)); + const auto pairs(plib::psplit(remainder,' ', true)); + for (const pstring &pe : pairs) + { + auto pose = pe.find('='); + if (pose == pstring::npos) + throw nl_exception(MF_MODEL_ERROR_ON_PAIR_1(model)); + map[plib::ucase(plib::left(pe, pose))] = pe.substr(pose + 1); + } } - pstring remainder = plib::trim(model.substr(pos + 1)); - if (!plib::endsWith(remainder, ")")) - throw nl_exception(MF_MODEL_ERROR_1(model)); - // FIMXE: Not optimal - remainder = plib::left(remainder, remainder.length() - 1); - - const auto pairs(plib::psplit(remainder,' ', true)); - for (const pstring &pe : pairs) + pstring models_t::model_t::model_string(const map_t &map) { - auto pose = pe.find('='); - if (pose == pstring::npos) - throw nl_exception(MF_MODEL_ERROR_ON_PAIR_1(model)); - map[plib::ucase(plib::left(pe, pose))] = pe.substr(pose + 1); - } -} + // operator [] has no const implementation + pstring ret = map.at("COREMODEL") + "("; + for (const auto & i : map) + ret += (i.first + '=' + i.second + ' '); -pstring models_t::model_t::model_string(const map_t &map) -{ - // operator [] has no const implementation - pstring ret = map.at("COREMODEL") + "("; - for (const auto & i : map) - ret += (i.first + '=' + i.second + ' '); - - return ret + ")"; -} - -models_t::model_t models_t::get_model(const pstring &model) -{ - map_t &map = m_cache[model]; - - if (map.empty()) - model_parse(model , map); + return ret + ")"; + } - return { model, map }; -} + models_t::model_t models_t::get_model(const pstring &model) + { + map_t &map = m_cache[model]; -pstring models_t::model_t::value_str(const pstring &entity) const -{ - if (entity != plib::ucase(entity)) - throw nl_exception(MF_MODEL_PARAMETERS_NOT_UPPERCASE_1_2(entity, model_string(m_map))); - const auto it(m_map.find(entity)); - if ( it == m_map.end()) - throw nl_exception(MF_ENTITY_1_NOT_FOUND_IN_MODEL_2(entity, model_string(m_map))); + if (map.empty()) + model_parse(model , map); - return it->second; -} + return { model, map }; + } -nl_fptype models_t::model_t::value(const pstring &entity) const -{ - pstring tmp = value_str(entity); - - nl_fptype factor = nlconst::one(); - auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.length() - 1)); - switch (*p) - { - case 'M': factor = nlconst::magic(1e6); break; // NOLINT - case 'k': - case 'K': factor = nlconst::magic(1e3); break; // NOLINT - case 'm': factor = nlconst::magic(1e-3); break; // NOLINT - case 'u': factor = nlconst::magic(1e-6); break; // NOLINT - case 'n': factor = nlconst::magic(1e-9); break; // NOLINT - case 'p': factor = nlconst::magic(1e-12); break; // NOLINT - case 'f': factor = nlconst::magic(1e-15); break; // NOLINT - case 'a': factor = nlconst::magic(1e-18); break; // NOLINT - default: - if (*p < '0' || *p > '9') - throw nl_exception(MF_UNKNOWN_NUMBER_FACTOR_IN_2(m_model, entity)); - } - if (factor != nlconst::one()) - tmp = plib::left(tmp, tmp.length() - 1); - // FIXME: check for errors - bool err(false); - auto val = plib::pstonum_ne<nl_fptype>(tmp, err); - if (err) - throw nl_exception(MF_MODEL_NUMBER_CONVERSION_ERROR(entity, tmp, "double", m_model)); - return val * factor; -} - - -// FIXME: all this belongs elsewhere - -PENUM(family_type, - CUSTOM, - TTL, - MOS, - CMOS, - NMOS, - PMOS) - -class logic_family_std_proxy_t : public logic_family_desc_t -{ -public: - logic_family_std_proxy_t(family_type ft) - : m_family_type(ft) + pstring models_t::model_t::value_str(const pstring &entity) const { + if (entity != plib::ucase(entity)) + throw nl_exception(MF_MODEL_PARAMETERS_NOT_UPPERCASE_1_2(entity, model_string(m_map))); + const auto it(m_map.find(entity)); + if ( it == m_map.end()) + throw nl_exception(MF_ENTITY_1_NOT_FOUND_IN_MODEL_2(entity, model_string(m_map))); + + return it->second; } - // FIXME: create proxies based on family type (far future) - 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 override + nl_fptype models_t::model_t::value(const pstring &entity) const { - switch(m_family_type) + pstring tmp = value_str(entity); + + nl_fptype factor = nlconst::one(); + auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.length() - 1)); + switch (*p) { - case family_type::CUSTOM: - case family_type::TTL: - case family_type::MOS: - case family_type::CMOS: - case family_type::NMOS: - case family_type::PMOS: - return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + case 'M': factor = nlconst::magic(1e6); break; // NOLINT + case 'k': + case 'K': factor = nlconst::magic(1e3); break; // NOLINT + case 'm': factor = nlconst::magic(1e-3); break; // NOLINT + case 'u': factor = nlconst::magic(1e-6); break; // NOLINT + case 'n': factor = nlconst::magic(1e-9); break; // NOLINT + case 'p': factor = nlconst::magic(1e-12); break; // NOLINT + case 'f': factor = nlconst::magic(1e-15); break; // NOLINT + case 'a': factor = nlconst::magic(1e-18); break; // NOLINT + default: + if (*p < '0' || *p > '9') + throw nl_exception(MF_UNKNOWN_NUMBER_FACTOR_IN_2(m_model, entity)); } - return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + if (factor != nlconst::one()) + tmp = plib::left(tmp, tmp.length() - 1); + // FIXME: check for errors + bool err(false); + auto val = plib::pstonum_ne<nl_fptype>(tmp, err); + if (err) + throw nl_exception(MF_MODEL_NUMBER_CONVERSION_ERROR(entity, tmp, "double", m_model)); + return val * factor; } - 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 override - { - switch(m_family_type) + // ---------------------------------------------------------------------------------------- + // logic_family_std_proxy_t + // + // FIXME: all this belongs elsewhere + // ---------------------------------------------------------------------------------------- + PENUM(family_type, + CUSTOM, + TTL, + MOS, + CMOS, + NMOS, + PMOS) + + class logic_family_std_proxy_t : public logic_family_desc_t + { + public: + logic_family_std_proxy_t(family_type ft) + : m_family_type(ft) + { + } + + // FIXME: create proxies based on family type (far future) + 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 override + { + switch(m_family_type) + { + case family_type::CUSTOM: + case family_type::TTL: + case family_type::MOS: + case family_type::CMOS: + case family_type::NMOS: + case family_type::PMOS: + return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + } + return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied); + } + + 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 override + { + switch(m_family_type) + { + case family_type::CUSTOM: + case family_type::TTL: + case family_type::MOS: + case family_type::CMOS: + case family_type::NMOS: + case family_type::PMOS: + return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied); + } + return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied); + } + private: + family_type m_family_type; + }; + + /// \brief Class representing the logic families. + /// + /// This is the model representation of the logic families. This is a + /// netlist specific model. Examples give values for TTL family + /// + // + /// |NL? |name |parameter |units| TTL | + /// |:--:|:-----|:----------------------------------------------------------|:----|------:| + /// | Y |IVL |Input voltage low threshold relative to supply voltage | |1.0e-14| + /// | Y |IVH |Input voltage high threshold relative to supply voltage | | 0| + /// | Y |OVL |Output voltage minimum voltage relative to supply voltage | |1.0e-14| + /// | Y |OVL |Output voltage maximum voltage relative to supply voltage | |1.0e-14| + /// | Y |ORL |Output output resistance for logic 0 | | 0| + /// | Y |ORH |Output output resistance for logic 1 | | 0| + /// + class family_model_t + { + public: + template <typename P> + family_model_t(P &model) + : m_TYPE(model, "TYPE") + , m_IVL(model, "IVL") + , m_IVH(model, "IVH") + , m_OVL(model, "OVL") + , m_OVH(model, "OVH") + , m_ORL(model, "ORL") + , m_ORH(model, "ORH") + {} + + param_model_t::value_str_t m_TYPE; //!< Family type (TTL, CMOS, ...) + param_model_t::value_t m_IVL; //!< Input voltage low threshold relative to supply voltage + param_model_t::value_t m_IVH; //!< Input voltage high threshold relative to supply voltage + param_model_t::value_t m_OVL; //!< Output voltage minimum voltage relative to supply voltage + param_model_t::value_t m_OVH; //!< Output voltage maximum voltage relative to supply voltage + param_model_t::value_t m_ORL; //!< Output output resistance for logic 0 + param_model_t::value_t m_ORH; //!< Output output resistance for logic 1 + }; + + const logic_family_desc_t *setup_t::family_from_model(const pstring &model) + { + family_type ft(family_type::CUSTOM); + + auto mod(m_models.get_model(model)); + family_model_t modv(mod); + + if (!ft.set_from_string(modv.m_TYPE())) + throw nl_exception(MF_UNKNOWN_FAMILY_TYPE_1(modv.m_TYPE(), model)); + + auto it = m_nlstate.family_cache().find(model); + if (it != m_nlstate.family_cache().end()) + return it->second.get(); + + auto ret = plib::make_unique<logic_family_std_proxy_t, host_arena>(ft); + + ret->m_low_threshold_PCNT = modv.m_IVL(); + ret->m_high_threshold_PCNT = modv.m_IVH(); + ret->m_low_VO = modv.m_OVL(); + ret->m_high_VO = modv.m_OVH(); + ret->m_R_low = modv.m_ORL(); + ret->m_R_high = modv.m_ORH(); + + switch (ft) { case family_type::CUSTOM: case family_type::TTL: + case family_type::NMOS: + ret->m_vcc = "VCC"; + ret->m_gnd = "GND"; + break; case family_type::MOS: case family_type::CMOS: - case family_type::NMOS: case family_type::PMOS: - return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied); - } - return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied); - } -private: - family_type m_family_type; -}; - - -/// \brief Class representing the logic families. -/// -/// This is the model representation of the logic families. This is a -/// netlist specific model. Examples give values for TTL family -/// -// -/// |NL? |name |parameter |units| TTL | -/// |:--:|:-----|:----------------------------------------------------------|:----|------:| -/// | Y |IVL |Input voltage low threshold relative to supply voltage | |1.0e-14| -/// | Y |IVH |Input voltage high threshold relative to supply voltage | | 0| -/// | Y |OVL |Output voltage minimum voltage relative to supply voltage | |1.0e-14| -/// | Y |OVL |Output voltage maximum voltage relative to supply voltage | |1.0e-14| -/// | Y |ORL |Output output resistance for logic 0 | | 0| -/// | Y |ORH |Output output resistance for logic 1 | | 0| -/// -class family_model_t -{ -public: - template <typename P> - family_model_t(P &model) - : m_TYPE(model, "TYPE") - , m_IVL(model, "IVL") - , m_IVH(model, "IVH") - , m_OVL(model, "OVL") - , m_OVH(model, "OVH") - , m_ORL(model, "ORL") - , m_ORH(model, "ORH") - {} - - param_model_t::value_str_t m_TYPE; //!< Family type (TTL, CMOS, ...) - param_model_t::value_t m_IVL; //!< Input voltage low threshold relative to supply voltage - param_model_t::value_t m_IVH; //!< Input voltage high threshold relative to supply voltage - param_model_t::value_t m_OVL; //!< Output voltage minimum voltage relative to supply voltage - param_model_t::value_t m_OVH; //!< Output voltage maximum voltage relative to supply voltage - param_model_t::value_t m_ORL; //!< Output output resistance for logic 0 - param_model_t::value_t m_ORH; //!< Output output resistance for logic 1 -}; - - -const logic_family_desc_t *setup_t::family_from_model(const pstring &model) -{ - family_type ft(family_type::CUSTOM); - - auto mod(m_models.get_model(model)); - family_model_t modv(mod); + ret->m_vcc = "VDD"; + ret->m_gnd = "VSS"; + break; + } - if (!ft.set_from_string(modv.m_TYPE())) - throw nl_exception(MF_UNKNOWN_FAMILY_TYPE_1(modv.m_TYPE(), model)); + auto *retp = ret.get(); - auto it = m_nlstate.family_cache().find(model); - if (it != m_nlstate.family_cache().end()) - return it->second.get(); + m_nlstate.family_cache().emplace(model, std::move(ret)); - auto ret = plib::make_unique<logic_family_std_proxy_t, host_arena>(ft); + return retp; + } - ret->m_low_threshold_PCNT = modv.m_IVL(); - ret->m_high_threshold_PCNT = modv.m_IVH(); - ret->m_low_VO = modv.m_OVL(); - ret->m_high_VO = modv.m_OVH(); - ret->m_R_low = modv.m_ORL(); - ret->m_R_high = modv.m_ORH(); + // ---------------------------------------------------------------------------------------- + // Device handling + // ---------------------------------------------------------------------------------------- - switch (ft) + void setup_t::delete_empty_nets() { - case family_type::CUSTOM: - case family_type::TTL: - case family_type::NMOS: - ret->m_vcc = "VCC"; - ret->m_gnd = "GND"; - break; - case family_type::MOS: - case family_type::CMOS: - case family_type::PMOS: - ret->m_vcc = "VDD"; - ret->m_gnd = "VSS"; - break; + m_nlstate.nets().erase( + std::remove_if(m_nlstate.nets().begin(), m_nlstate.nets().end(), + [](device_arena::owned_ptr<detail::net_t> &net) + { + if (net->core_terms_empty()) + { + // FIXME: need to remove from state->m_core_terms as well. + net->state().log().verbose("Deleting net {1} ...", net->name()); + net->state().run_state_manager().remove_save_items(net.get()); + return true; + } + return false; + }), m_nlstate.nets().end()); } - auto *retp = ret.get(); + // ---------------------------------------------------------------------------------------- + // Run preparation + // ---------------------------------------------------------------------------------------- - m_nlstate.family_cache().emplace(model, std::move(ret)); + void setup_t::prepare_to_run() + { + pstring env_log_setting = plib::util::environment("NL_LOGS", ""); - return retp; -} + if (!env_log_setting.empty()) + { + const auto list_of_logs(plib::psplit(env_log_setting, ':')); + m_parser.register_dynamic_log_devices(list_of_logs); + } -// ---------------------------------------------------------------------------------------- -// Device handling -// ---------------------------------------------------------------------------------------- + // create default parameters first! -void setup_t::delete_empty_nets() -{ - m_nlstate.nets().erase( - std::remove_if(m_nlstate.nets().begin(), m_nlstate.nets().end(), - [](device_arena::owned_ptr<detail::net_t> &net) - { - if (net->state().core_terms(*net).empty()) - { - // FIXME: need to remove from state->m_core_terms as well. - net->state().log().verbose("Deleting net {1} ...", net->name()); - net->state().run_state_manager().remove_save_items(net.get()); - return true; - } - return false; - }), m_nlstate.nets().end()); -} + for (auto & e : m_abstract.m_default_params) + { + auto param(plib::make_unique<param_str_t, host_arena>(nlstate(), e.first, e.second)); + register_param_t(*param); + m_defparam_lifetime.push_back(std::move(param)); + } -// ---------------------------------------------------------------------------------------- -// Run preparation -// ---------------------------------------------------------------------------------------- + // make sure the solver and parameters are started first! -void setup_t::prepare_to_run() -{ - pstring env_log_setting = plib::util::environment("NL_LOGS", ""); + for (auto & e : m_abstract.m_device_factory) + { + if ( m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second) + || m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second)) + { + m_nlstate.register_device(e.first, e.second->make_device(nlstate().pool(), m_nlstate, e.first)); + } + } - if (!env_log_setting.empty()) - { - const auto loglist(plib::psplit(env_log_setting, ':')); - m_parser.register_dynamic_log_devices(loglist); - } + log().debug("Searching for solver and parameters ...\n"); - // create defparams first! + auto *solver = m_nlstate.get_single_device<devices::NETLIB_NAME(solver)>("solver"); + m_netlist_params = m_nlstate.get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter"); - for (auto & e : m_abstract.m_defparams) - { - auto param(plib::make_unique<param_str_t, host_arena>(nlstate(), e.first, e.second)); - register_param_t(*param); - m_defparam_lifetime.push_back(std::move(param)); - } + // set default model parameters - // make sure the solver and parameters are started first! + // FIXME: this is not optimal + m_parser.register_model(plib::pfmt("NMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model())); + m_parser.register_model(plib::pfmt("PMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model())); - for (auto & e : m_abstract.m_device_factory) - { - if ( m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second) - || m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second)) + // create devices + + log().debug("Creating devices ...\n"); + for (auto & e : m_abstract.m_device_factory) { - m_nlstate.register_device(e.first, e.second->make_device(nlstate().pool(), m_nlstate, e.first)); + if ( !m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second) + && !m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second)) + { + auto dev = e.second->make_device(m_nlstate.pool(), m_nlstate, e.first); + m_nlstate.register_device(dev->name(), std::move(dev)); + } } - } - log().debug("Searching for solver and parameters ...\n"); + int error_count(0); - auto *solver = m_nlstate.get_single_device<devices::NETLIB_NAME(solver)>("solver"); - m_netlist_params = m_nlstate.get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter"); + const bool use_deactivate = m_netlist_params->m_use_deactivate(); - // set default model parameters + for (auto &d : m_nlstate.devices()) + { + auto p = m_abstract.m_hints.find(d.second->name() + sHINT_NO_DEACTIVATE); + if (p != m_abstract.m_hints.end()) + { + p->second = true; // mark as used + d.second->set_hint_deactivate(false); + } + else + d.second->set_hint_deactivate(use_deactivate); + } - // FIXME: this is not optimal - m_parser.register_model(plib::pfmt("NMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model())); - m_parser.register_model(plib::pfmt("PMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model())); + if (error_count > 0) + { + log().fatal(MF_ERRORS_FOUND(error_count)); + throw nl_exception(MF_ERRORS_FOUND(error_count)); + } - // create devices + // resolve inputs + resolve_inputs(); - log().debug("Creating devices ...\n"); - for (auto & e : m_abstract.m_device_factory) - { - if ( !m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second) - && !m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second)) + log().verbose("looking for two terms connected to rail nets ..."); + for (auto & t : m_nlstate.get_device_list<analog::NETLIB_NAME(two_terminal)>()) { - auto dev = e.second->make_device(m_nlstate.pool(), m_nlstate, e.first); - m_nlstate.register_device(dev->name(), std::move(dev)); + if (t->N().net().is_rail_net() && t->P().net().is_rail_net()) + { + log().info(MI_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3( + t->name(), t->N().net().name(), t->P().net().name())); + // The following would remove internal devices in e.g. MOSFETs as well. + #if 0 + remove_terminal(t->setup_N().net(), t->setup_N()); + remove_terminal(t->setup_P().net(), t->setup_P()); + m_nlstate.remove_device(t); + #endif + } } - } - int error_count(0); + log().verbose("looking for unused hints ..."); + for (auto &h : m_abstract.m_hints) + { + if (!h.second) + { + log().fatal(MF_UNUSED_HINT_1(h.first)); + throw nl_exception(MF_UNUSED_HINT_1(h.first)); + } + } - const bool use_deactivate = m_netlist_params->m_use_deactivate(); + log().verbose("initialize solver ...\n"); - for (auto &d : m_nlstate.devices()) - { - auto p = m_abstract.m_hints.find(d.second->name() + sHINT_NO_DEACTIVATE); - if (p != m_abstract.m_hints.end()) + if (solver == nullptr) { - p->second = true; // mark as used - d.second->set_hint_deactivate(false); + for (auto &p : m_nlstate.nets()) + if (p->is_analog()) + { + log().fatal(MF_NO_SOLVER()); + throw nl_exception(MF_NO_SOLVER()); + } } else - d.second->set_hint_deactivate(use_deactivate); - } - - if (error_count > 0) - { - log().fatal(MF_ERRORS_FOUND(error_count)); - throw nl_exception(MF_ERRORS_FOUND(error_count)); - } - - // resolve inputs - resolve_inputs(); + solver->post_start(); - log().verbose("looking for two terms connected to rail nets ..."); - for (auto & t : m_nlstate.get_device_list<analog::NETLIB_NAME(two_terminal)>()) - { - if (t->N().net().is_rail_net() && t->P().net().is_rail_net()) + error_count = 0; + log().debug("Looking for unknown parameters ...\n"); + for (auto &p : m_abstract.m_param_values) { - log().info(MI_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3( - t->name(), t->N().net().name(), t->P().net().name())); - // The following would remove internal devices in e.g. MOSFETs as well. -#if 0 - remove_terminal(t->setup_N().net(), t->setup_N()); - remove_terminal(t->setup_P().net(), t->setup_P()); - m_nlstate.remove_device(t); -#endif + auto f = m_params.find(p.first); + if (f == m_params.end()) + { + log().error(ME_UNKNOWN_PARAMETER(p.first)); + error_count++; + } + } + if (error_count > 0) + { + log().fatal(MF_ERRORS_FOUND(error_count)); + throw nl_exception(MF_ERRORS_FOUND(error_count)); } - } - log().verbose("looking for unused hints ..."); - for (auto &h : m_abstract.m_hints) - { - if (!h.second) + for (auto &n : m_nlstate.nets()) { - log().fatal(MF_UNUSED_HINT_1(h.first)); - throw nl_exception(MF_UNUSED_HINT_1(h.first)); + for (detail::core_terminal_t * term : n->core_terms_copy()) + if (term->delegate().isnull()) + { + log().fatal(MF_DELEGATE_NOT_SET_1(term->name())); + throw nl_exception(MF_DELEGATE_NOT_SET_1(term->name())); + } + n->rebuild_list(); } } - log().verbose("initialize solver ...\n"); + // ---------------------------------------------------------------------------------------- + // base sources + // ---------------------------------------------------------------------------------------- - if (solver == nullptr) + bool source_netlist_t::parse(nlparse_t &setup, const pstring &name) { - for (auto &p : m_nlstate.nets()) - if (p->is_analog()) - { - log().fatal(MF_NO_SOLVER()); - throw nl_exception(MF_NO_SOLVER()); - } + auto strm(stream(name)); + return (!strm.empty()) ? setup.parse_stream(std::move(strm), name) : false; } - else - solver->post_start(); - error_count = 0; - log().debug("Looking for unknown parameters ...\n"); - for (auto &p : m_abstract.m_param_values) + plib::istream_uptr source_string_t::stream([[maybe_unused]] const pstring &name) { - auto f = m_params.find(p.first); - if (f == m_params.end()) - { - log().error(ME_UNKNOWN_PARAMETER(p.first)); - error_count++; - } - } - if (error_count > 0) - { - log().fatal(MF_ERRORS_FOUND(error_count)); - throw nl_exception(MF_ERRORS_FOUND(error_count)); + plib::istream_uptr ret(std::make_unique<std::istringstream>(putf8string(m_str)), name); + ret->imbue(std::locale::classic()); + return ret; } - for (auto &n : m_nlstate.nets()) + plib::istream_uptr source_mem_t::stream([[maybe_unused]] const pstring &name) { - for (auto & term : m_nlstate.core_terms(*n)) - if (term->delegate().isnull()) - { - log().fatal(MF_DELEGATE_NOT_SET_1(term->name())); - throw nl_exception(MF_DELEGATE_NOT_SET_1(term->name())); - } - n->rebuild_list(); + plib::istream_uptr ret(std::make_unique<std::istringstream>(m_str, std::ios_base::binary), name); + ret->imbue(std::locale::classic()); + return ret; } -} -// ---------------------------------------------------------------------------------------- -// base sources -// ---------------------------------------------------------------------------------------- - -bool source_netlist_t::parse(nlparse_t &setup, const pstring &name) -{ - auto strm(stream(name)); - return (!strm.empty()) ? setup.parse_stream(std::move(strm), name) : false; -} - -plib::istream_uptr source_string_t::stream([[maybe_unused]] const pstring &name) -{ - plib::istream_uptr ret(std::make_unique<std::istringstream>(putf8string(m_str)), name); - ret->imbue(std::locale::classic()); - return ret; -} - -plib::istream_uptr source_mem_t::stream([[maybe_unused]] const pstring &name) -{ - plib::istream_uptr ret(std::make_unique<std::istringstream>(m_str, std::ios_base::binary), name); - ret->imbue(std::locale::classic()); - return ret; -} - -plib::istream_uptr source_file_t::stream([[maybe_unused]] const pstring &name) -{ - auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(m_filename)); - if (f->is_open()) + plib::istream_uptr source_file_t::stream([[maybe_unused]] const pstring &name) { - return { std::move(f), m_filename }; - } + auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(m_filename)); + if (f->is_open()) + { + return { std::move(f), m_filename }; + } - return plib::istream_uptr(); -} + return plib::istream_uptr(); + } -plib::istream_uptr source_pattern_t::stream([[maybe_unused]] const pstring &name) -{ - pstring filename = plib::pfmt(m_pattern)(m_force_lowercase ? plib::lcase(name) : name); - auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(filename)); - if (f->is_open()) + plib::istream_uptr source_pattern_t::stream([[maybe_unused]] const pstring &name) { - return { std::move(f), filename }; + pstring filename = plib::pfmt(m_pattern)(m_force_lowercase ? plib::lcase(name) : name); + auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(filename)); + if (f->is_open()) + { + return { std::move(f), filename }; + } + + return plib::istream_uptr(); } - return plib::istream_uptr(); -} + bool source_proc_t::parse(nlparse_t &setup, const pstring &name) + { + if (name == m_setup_func_name) + { + m_setup_func(setup); + return true; + } + return false; + } -bool source_proc_t::parse(nlparse_t &setup, const pstring &name) -{ - if (name == m_setup_func_name) + plib::istream_uptr source_proc_t::stream([[maybe_unused]] const pstring &name) { - m_setup_func(setup); - return true; + return plib::istream_uptr(); } - return false; -} - -plib::istream_uptr source_proc_t::stream([[maybe_unused]] const pstring &name) -{ - return plib::istream_uptr(); -} - } // namespace netlist diff --git a/src/lib/netlist/nl_setup.h b/src/lib/netlist/nl_setup.h index 14eaf90d95e..d22b78c3703 100644 --- a/src/lib/netlist/nl_setup.h +++ b/src/lib/netlist/nl_setup.h @@ -55,7 +55,7 @@ setup.register_param(NET_STR(name), NET_STR(val)); #define DEFPARAM(name, val) \ - setup.register_defparam(NET_STR(name), NET_STR(val)); + setup.register_default_param(NET_STR(name), NET_STR(val)); #define HINT(name, val) \ setup.register_hint(# name , ".HINT_" # val); @@ -168,7 +168,7 @@ namespace netlist void register_model(const pstring &model_in); void register_alias(const pstring &alias, const pstring &out); - void register_alias_nofqn(const pstring &alias, const pstring &out); + void register_alias_no_fqn(const pstring &alias, const pstring &out); void register_dip_alias_arr(const pstring &terms); // last argument only needed by nltool @@ -181,7 +181,7 @@ namespace netlist register_dev(classname, name, std::vector<pstring>()); } - void register_hint(const pstring &objname, const pstring &hint_name); + void register_hint(const pstring &object_name, const pstring &hint_name); void register_link(const pstring &sin, const pstring &sout); void register_link_arr(const pstring &terms); @@ -191,7 +191,7 @@ namespace netlist void register_param(const pstring ¶m, const pstring &value); // DEFPARAM support - void register_defparam(const pstring &name, const pstring &def); + void register_default_param(const pstring &name, const pstring &def); template <typename T> std::enable_if_t<plib::is_arithmetic<T>::value> diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h index b07a533a22d..94bb424998c 100644 --- a/src/lib/netlist/plib/parray.h +++ b/src/lib/netlist/plib/parray.h @@ -123,13 +123,13 @@ namespace plib { ~parray() noexcept = default; - base_type &as_base() noexcept { return m_a; } + constexpr base_type &as_base() noexcept { return m_a; } constexpr size_type size() const noexcept { return SIZE <= 0 ? m_size : SIZEABS(); } constexpr size_type max_size() const noexcept { return base_type::max_size(); } - bool empty() const noexcept { return size() == 0; } + constexpr bool empty() const noexcept { return size() == 0; } constexpr reference operator[](size_type i) noexcept { @@ -140,8 +140,8 @@ namespace plib { return m_a[i]; } - pointer data() noexcept { return m_a.data(); } - const_pointer data() const noexcept { return m_a.data(); } + constexpr pointer data() noexcept { return m_a.data(); } + constexpr const_pointer data() const noexcept { return m_a.data(); } private: PALIGNAS_VECTOROPT() diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h index e245e955665..1c2e4b13057 100644 --- a/src/lib/netlist/plib/pchrono.h +++ b/src/lib/netlist/plib/pchrono.h @@ -37,8 +37,8 @@ namespace plib { using ret_type = R; static ret_type per_second() noexcept { - static ret_type persec = 0; - if (persec == 0) + static ret_type per_second = 0; + if (per_second == 0) { ret_type x = 0; system_ticks::type t = system_ticks::start(); @@ -48,9 +48,9 @@ namespace plib { e = system_ticks::stop(); } while (e - t < system_ticks::per_second() / 100 ); x += T :: stop(); - persec = (ret_type)(double)((double) x * (double) system_ticks::per_second() / double (e - t)); + per_second = (ret_type)(double)((double) x * (double) system_ticks::per_second() / double (e - t)); } - return persec; + return per_second; } }; @@ -163,11 +163,11 @@ namespace plib { template<bool enabled_> struct counter { - counter() : m_count(0) { } + constexpr counter() : m_count(0) { } using type = uint_least64_t; - type operator()() const noexcept { return m_count; } - void inc() noexcept { ++m_count; } - void reset() noexcept { m_count = 0; } + constexpr type operator()() const noexcept { return m_count; } + constexpr void inc() noexcept { ++m_count; } + constexpr void reset() noexcept { m_count = 0; } constexpr static bool enabled = enabled_; private: type m_count; @@ -178,8 +178,8 @@ namespace plib { { using type = uint_least64_t; constexpr type operator()() const noexcept { return 0; } - void inc() const noexcept { } - void reset() const noexcept { } + constexpr void inc() const noexcept { } + constexpr void reset() const noexcept { } constexpr static bool enabled = false; }; @@ -189,7 +189,7 @@ namespace plib { { using type = typename T::type; using ctype = uint_least64_t; - constexpr static bool enabled = enabled_; + constexpr static const bool enabled = enabled_; struct guard_t { @@ -210,7 +210,7 @@ namespace plib { constexpr type operator()() const { return m_time; } - void reset() noexcept { m_time = 0; m_count = 0; } + constexpr void reset() noexcept { m_time = 0; m_count = 0; } constexpr type average() const noexcept { return (m_count == 0) ? 0 : m_time / m_count; } constexpr type total() const noexcept { return m_time; } constexpr ctype count() const noexcept { return m_count; } @@ -221,7 +221,6 @@ namespace plib { constexpr guard_t guard() noexcept { return guard_t(*this); } - // pause must be followed by cont(inue) void stop() noexcept { m_time += T::stop(); } void start() noexcept { m_time -= T::start(); } diff --git a/src/lib/netlist/plib/penum.h b/src/lib/netlist/plib/penum.h index 2e9bf322072..5a1db765ba0 100644 --- a/src/lib/netlist/plib/penum.h +++ b/src/lib/netlist/plib/penum.h @@ -32,7 +32,7 @@ namespace plib struct ename : public plib::penum_base { \ enum E { __VA_ARGS__ }; \ constexpr ename (const E &v) : m_v(v) { } \ - template <typename T> explicit constexpr ename(const T &val) { m_v = static_cast<E>(val); } \ + template <typename T> explicit constexpr ename(const T &val) : m_v(static_cast<E>(val)) { } \ bool set_from_string (const pstring &s) { \ int f = from_string_int(strings(), s); \ if (f>=0) { m_v = static_cast<E>(f); return true; } \ diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp index 61cb9480301..260fa908bf0 100644 --- a/src/lib/netlist/plib/pexception.cpp +++ b/src/lib/netlist/plib/pexception.cpp @@ -28,7 +28,7 @@ namespace plib { } catch (...) { - /* ignore */ + // ignore } std::terminate(); } @@ -45,7 +45,7 @@ namespace plib { } catch (...) { - /* ignore */ + // ignore } std::terminate(); } @@ -106,17 +106,17 @@ namespace plib { //FIXME: mingw needs to be compiled with `-fnon-call-exceptions` - fp_signal_enabler::fp_signal_enabler(unsigned fpexceptions) + fp_signal_enabler::fp_signal_enabler(unsigned fp_exceptions) { #if HAS_FEENABLE_EXCEPT if (m_enable) { int b = 0; - if (fpexceptions & plib::FP_INEXACT) b = b | FE_INEXACT; - if (fpexceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO; - if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW; - if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW; - if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID; + if (fp_exceptions & plib::FP_INEXACT) b = b | FE_INEXACT; + if (fp_exceptions & plib::FP_DIVBYZERO) b = b | FE_DIVBYZERO; + if (fp_exceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW; + if (fp_exceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW; + if (fp_exceptions & plib::FP_INVALID) b = b | FE_INVALID; if ((b & m_last_enabled) != b) m_last_enabled = feenableexcept(b); } @@ -124,11 +124,11 @@ namespace plib { if (m_enable) { int b = _EM_DENORMAL | _EM_INEXACT | _EM_ZERODIVIDE | _EM_UNDERFLOW | _EM_OVERFLOW | _EM_INVALID; - if (fpexceptions & plib::FP_INEXACT) b &= ~_EM_INEXACT; - if (fpexceptions & plib::FP_DIVBYZERO) b &= ~_EM_ZERODIVIDE; - if (fpexceptions & plib::FP_UNDERFLOW) b &= ~_EM_UNDERFLOW; - if (fpexceptions & plib::FP_OVERFLOW) b &= ~_EM_OVERFLOW; - if (fpexceptions & plib::FP_INVALID) b &= ~_EM_INVALID; + if (fp_exceptions & plib::FP_INEXACT) b &= ~_EM_INEXACT; + if (fp_exceptions & plib::FP_DIVBYZERO) b &= ~_EM_ZERODIVIDE; + if (fp_exceptions & plib::FP_UNDERFLOW) b &= ~_EM_UNDERFLOW; + if (fp_exceptions & plib::FP_OVERFLOW) b &= ~_EM_OVERFLOW; + if (fp_exceptions & plib::FP_INVALID) b &= ~_EM_INVALID; m_last_enabled = _controlfp(0, 0); _controlfp(b, _MCW_EM ); } diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp index 61c48e0051f..64a9d8791ae 100644 --- a/src/lib/netlist/plib/pfmtlog.cpp +++ b/src/lib/netlist/plib/pfmtlog.cpp @@ -39,7 +39,7 @@ private: }; #endif -pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec) +pfmt::rtype pfmt::set_format(std::stringstream &strm, char32_t cfmt_spec) { pstring fmt; pstring search("{"); diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h index 468c04c8ba3..1586deacf3c 100644 --- a/src/lib/netlist/plib/pfmtlog.h +++ b/src/lib/netlist/plib/pfmtlog.h @@ -18,12 +18,12 @@ #include <locale> #include <sstream> -#define PERRMSGV(name, narg, str) \ +#define PERRMSGV(name, argument_count, str) \ struct name : public plib::perrmsg \ { \ template<typename... Args> explicit name(Args&&... args) \ : plib::perrmsg(str, std::forward<Args>(args)...) \ - { static_assert((narg) == sizeof...(args), "Argument count mismatch"); } \ + { static_assert((argument_count) == sizeof...(args), "Argument count mismatch"); } \ }; namespace plib { @@ -37,7 +37,7 @@ namespace plib { FATAL) template <typename T> - struct ptype_traits_base + struct format_traits_base { static constexpr const bool is_signed = std::numeric_limits<T>::is_signed; static char32_t fmt_spec() { return 'u'; } @@ -49,7 +49,7 @@ namespace plib { #if (PUSE_FLOAT128) template <> - struct ptype_traits_base<FLOAT128> + struct format_traits_base<FLOAT128> { // FIXME: need native support at some time static constexpr const bool is_signed = true; @@ -62,10 +62,10 @@ namespace plib { #endif template <typename T> - struct ptype_traits; + struct format_traits; template<> - struct ptype_traits<compile_info::int128_type> + struct format_traits<compile_info::int128_type> { // FIXME: need native support at some time static constexpr const bool is_signed = true; @@ -78,97 +78,97 @@ namespace plib { }; template<> - struct ptype_traits<bool> : ptype_traits_base<bool> + struct format_traits<bool> : format_traits_base<bool> { }; template<> - struct ptype_traits<char> : ptype_traits_base<char> + struct format_traits<char> : format_traits_base<char> { static char32_t fmt_spec() { return is_signed ? 'd' : 'u'; } }; template<> - struct ptype_traits<short> : ptype_traits_base<short> + struct format_traits<short> : format_traits_base<short> { static char32_t fmt_spec() { return 'd'; } }; template<> - struct ptype_traits<int> : ptype_traits_base<int> + struct format_traits<int> : format_traits_base<int> { static char32_t fmt_spec() { return 'd'; } }; template<> - struct ptype_traits<long> : ptype_traits_base<long> + struct format_traits<long> : format_traits_base<long> { static char32_t fmt_spec() { return 'd'; } }; template<> - struct ptype_traits<long long> : ptype_traits_base<long long> + struct format_traits<long long> : format_traits_base<long long> { static char32_t fmt_spec() { return 'd'; } }; template<> - struct ptype_traits<signed char> : ptype_traits_base<signed char> + struct format_traits<signed char> : format_traits_base<signed char> { static char32_t fmt_spec() { return 'd'; } }; template<> - struct ptype_traits<unsigned char> : ptype_traits_base<unsigned char> + struct format_traits<unsigned char> : format_traits_base<unsigned char> { static char32_t fmt_spec() { return 'u'; } }; template<> - struct ptype_traits<unsigned short> : ptype_traits_base<unsigned short> + struct format_traits<unsigned short> : format_traits_base<unsigned short> { static char32_t fmt_spec() { return 'u'; } }; template<> - struct ptype_traits<unsigned int> : ptype_traits_base<unsigned int> + struct format_traits<unsigned int> : format_traits_base<unsigned int> { static char32_t fmt_spec() { return 'u'; } }; template<> - struct ptype_traits<unsigned long> : ptype_traits_base<unsigned long> + struct format_traits<unsigned long> : format_traits_base<unsigned long> { static char32_t fmt_spec() { return 'u'; } }; template<> - struct ptype_traits<unsigned long long> : ptype_traits_base<unsigned long long> + struct format_traits<unsigned long long> : format_traits_base<unsigned long long> { static char32_t fmt_spec() { return 'u'; } }; template<> - struct ptype_traits<float> : ptype_traits_base<float> + struct format_traits<float> : format_traits_base<float> { static char32_t fmt_spec() { return 'f'; } }; template<> - struct ptype_traits<double> : ptype_traits_base<double> + struct format_traits<double> : format_traits_base<double> { static char32_t fmt_spec() { return 'f'; } }; template<> - struct ptype_traits<long double> : ptype_traits_base<long double> + struct format_traits<long double> : format_traits_base<long double> { static char32_t fmt_spec() { return 'f'; } }; #if (PUSE_FLOAT128) template<> - struct ptype_traits<FLOAT128> : ptype_traits_base<FLOAT128> + struct format_traits<FLOAT128> : format_traits_base<FLOAT128> { static char32_t fmt_spec() { return 'f'; } }; @@ -176,19 +176,19 @@ namespace plib { template<> - struct ptype_traits<char *> : ptype_traits_base<char *> + struct format_traits<char *> : format_traits_base<char *> { static char32_t fmt_spec() { return 's'; } }; template<> - struct ptype_traits<const char *> : ptype_traits_base<const char *> + struct format_traits<const char *> : format_traits_base<const char *> { static char32_t fmt_spec() { return 's'; } }; template<> - struct ptype_traits<const char16_t *> : ptype_traits_base<const char16_t *> + struct format_traits<const char16_t *> : format_traits_base<const char16_t *> { static char32_t fmt_spec() { return 's'; } static void streamify(std::ostream &s, const char16_t *v) @@ -199,7 +199,7 @@ namespace plib { }; template<> - struct ptype_traits<const char32_t *> : ptype_traits_base<const char32_t *> + struct format_traits<const char32_t *> : format_traits_base<const char32_t *> { static char32_t fmt_spec() { return 's'; } static void streamify(std::ostream &s, const char32_t *v) @@ -210,19 +210,19 @@ namespace plib { }; template<> - struct ptype_traits<std::string> : ptype_traits_base<std::string> + struct format_traits<std::string> : format_traits_base<std::string> { static char32_t fmt_spec() { return 's'; } }; template<> - struct ptype_traits<putf8string> : ptype_traits_base<putf8string> + struct format_traits<putf8string> : format_traits_base<putf8string> { static char32_t fmt_spec() { return 's'; } }; template<> - struct ptype_traits<putf16string> : ptype_traits_base<putf16string> + struct format_traits<putf16string> : format_traits_base<putf16string> { static char32_t fmt_spec() { return 's'; } static void streamify(std::ostream &s, const putf16string &v) @@ -232,7 +232,7 @@ namespace plib { }; template<> - struct ptype_traits<const void *> : ptype_traits_base<const void *> + struct format_traits<const void *> : format_traits_base<const void *> { static char32_t fmt_spec() { return 'p'; } }; @@ -307,10 +307,10 @@ namespace plib { return format_element('o', x); } - friend std::ostream& operator<<(std::ostream &ostrm, const pfmt &fmt) + friend std::ostream& operator<<(std::ostream &out_stream, const pfmt &fmt) { - ostrm << putf8string(fmt.m_str); - return ostrm; + out_stream << putf8string(fmt.m_str); + return out_stream; } protected: @@ -322,16 +322,16 @@ namespace plib { pstring::size_type p; pstring::size_type sl; }; - rtype setfmt(std::stringstream &strm, char32_t cfmt_spec); + rtype set_format(std::stringstream &strm, char32_t char_format); template <typename T> pfmt &format_element(T &&v) { - return format_element(ptype_traits<typename std::decay<T>::type>::fmt_spec(), std::forward<T>(v)); + return format_element(format_traits<typename std::decay<T>::type>::fmt_spec(), std::forward<T>(v)); } template <typename T> - pfmt &format_element(const char32_t cfmt_spec, T &&v) + pfmt &format_element(const char32_t char_format, T &&v) { rtype ret; @@ -340,10 +340,10 @@ namespace plib { do { std::stringstream strm; strm.imbue(m_locale); - ret = setfmt(strm, cfmt_spec); + ret = set_format(strm, char_format); if (ret.ret>=0) { - ptype_traits<typename std::decay<T>::type>::streamify(strm, std::forward<T>(v)); + format_traits<typename std::decay<T>::type>::streamify(strm, std::forward<T>(v)); const pstring ps(putf8string(strm.str())); m_str = m_str.substr(0, ret.p) + ps + m_str.substr(ret.p + ret.sl); } @@ -375,7 +375,7 @@ namespace plib { if (build_enabled && enabled && m_enabled) { pfmt pf(fmt); - dynamic_cast<T &>(*this).upstream_write(xlog(pf, std::forward<Args>(args)...)); + dynamic_cast<T &>(*this).upstream_write(log_translate(pf, std::forward<Args>(args)...)); } } @@ -385,7 +385,7 @@ namespace plib { if (build_enabled && m_enabled) { pfmt pf(fmt); - static_cast<const T &>(*this).upstream_write(xlog(pf, std::forward<Args>(args)...)); + static_cast<const T &>(*this).upstream_write(log_translate(pf, std::forward<Args>(args)...)); } } @@ -400,12 +400,12 @@ namespace plib { ~pfmt_writer_t() noexcept = default; private: - pfmt &xlog(pfmt &fmt) const { return fmt; } + pfmt &log_translate(pfmt &fmt) const { return fmt; } template<typename X, typename... Args> - pfmt &xlog(pfmt &fmt, X&& x, Args&&... args) const + pfmt &log_translate(pfmt &fmt, X&& x, Args&&... args) const { - return xlog(fmt(std::forward<X>(x)), std::forward<Args>(args)...); + return log_translate(fmt(std::forward<X>(x)), std::forward<Args>(args)...); } bool m_enabled; diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index 6d295f48a73..ed906a40385 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -78,18 +78,18 @@ namespace plib { { "G", narrow_cast<F>( 1e9) }, // NOLINT: Giga { "M", narrow_cast<F>( 1e6) }, // NOLINT: Mega { "k", narrow_cast<F>( 1e3) }, // NOLINT: Kilo - { "h", narrow_cast<F>( 1e2) }, // NOLINT: Hekto - //{ "da", narrow_cast<F>(1e1) }, // NOLINT: Deka - { "d", narrow_cast<F>(1e-1) }, // NOLINT: Dezi - { "c", narrow_cast<F>(1e-2) }, // NOLINT: Zenti + { "h", narrow_cast<F>( 1e2) }, // NOLINT: Hecto + //{ "da", narrow_cast<F>(1e1) }, // NOLINT: Deca + { "d", narrow_cast<F>(1e-1) }, // NOLINT: Deci + { "c", narrow_cast<F>(1e-2) }, // NOLINT: Centi { "m", narrow_cast<F>(1e-3) }, // NOLINT: Milli - { "μ", narrow_cast<F>(1e-6) }, // NOLINT: Mikro + { "μ", narrow_cast<F>(1e-6) }, // NOLINT: Micro { "n", narrow_cast<F>(1e-9) }, // NOLINT: Nano - { "p", narrow_cast<F>(1e-12) }, // NOLINT: Piko + { "p", narrow_cast<F>(1e-12) }, // NOLINT: Pico { "f", narrow_cast<F>(1e-15) }, // NOLINT: Femto { "a", narrow_cast<F>(1e-18) }, // NOLINT: Atto { "z", narrow_cast<F>(1e-21) }, // NOLINT: Zepto - { "y", narrow_cast<F>(1e-24) }, // NOLINT: Yokto + { "y", narrow_cast<F>(1e-24) }, // NOLINT: Yocto }; return units_si_stat; } diff --git a/src/lib/netlist/plib/pgsl.h b/src/lib/netlist/plib/pgsl.h index efda84e546c..3125df5cc00 100644 --- a/src/lib/netlist/plib/pgsl.h +++ b/src/lib/netlist/plib/pgsl.h @@ -29,7 +29,8 @@ #define gsl_Expects(e) ((e) ? static_cast<void>(0) : static_cast<void>(0)) #endif #elif defined(__GNUC__) && !(defined( __CUDACC__ ) && defined( __CUDA_ARCH__ )) - #define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable()) + //#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable()) + #define gsl_Expects(e) (__builtin_expect(!!(e), 1) ? static_cast<void>(0) : __builtin_unreachable()) #elif defined(_MSC_VER) #define gsl_Expects(e) __assume(e) #else diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h index 4148eeb82fd..6bb7db69792 100644 --- a/src/lib/netlist/plib/plists.h +++ b/src/lib/netlist/plib/plists.h @@ -39,12 +39,12 @@ namespace plib { using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; - uninitialised_array() noexcept = default; + constexpr uninitialised_array() noexcept = default; - uninitialised_array(const uninitialised_array &) = default; - uninitialised_array &operator=(const uninitialised_array &) = default; - uninitialised_array(uninitialised_array &&) noexcept = default; - uninitialised_array &operator=(uninitialised_array &&) noexcept = default; + constexpr uninitialised_array(const uninitialised_array &) = default; + constexpr uninitialised_array &operator=(const uninitialised_array &) = default; + constexpr uninitialised_array(uninitialised_array &&) noexcept = default; + constexpr uninitialised_array &operator=(uninitialised_array &&) noexcept = default; ~uninitialised_array() noexcept = default; @@ -52,7 +52,7 @@ namespace plib { constexpr bool empty() const noexcept { return size() == 0; } - reference operator[](size_type index) noexcept + constexpr reference operator[](size_type index) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast<reference>(m_buf[index]); @@ -65,21 +65,19 @@ namespace plib { } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } + constexpr iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); } + constexpr iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } + constexpr iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); } + constexpr iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + N); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); } + constexpr const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + N); } - - protected: + constexpr const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + N); } private: std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf; @@ -109,15 +107,15 @@ namespace plib { using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; - static_vector() noexcept + constexpr static_vector() noexcept : m_pos(0) { } - static_vector(const static_vector &) = default; - static_vector &operator=(const static_vector &) = default; - static_vector(static_vector &&) noexcept = default; - static_vector &operator=(static_vector &&) noexcept = default; + constexpr static_vector(const static_vector &) = default; + constexpr static_vector &operator=(const static_vector &) = default; + constexpr static_vector(static_vector &&) noexcept = default; + constexpr static_vector &operator=(static_vector &&) noexcept = default; ~static_vector() noexcept { @@ -128,7 +126,7 @@ namespace plib { constexpr bool empty() const noexcept { return size() == 0; } - void clear() + constexpr void clear() { for (size_type i=0; i<m_pos; ++i) (*this)[i].~C(); @@ -136,14 +134,14 @@ namespace plib { } template<typename... Args> - void emplace_back(Args&&... args) + constexpr void emplace_back(Args&&... args) { // placement new on buffer new (&m_buf[m_pos]) C(std::forward<Args>(args)...); m_pos++; } - reference operator[](size_type index) noexcept + constexpr reference operator[](size_type index) noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast<reference>(m_buf[index]); @@ -156,21 +154,19 @@ namespace plib { } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } + constexpr iterator begin() const noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + m_pos); } + constexpr iterator end() const noexcept { return reinterpret_cast<iterator>(&m_buf[0] + m_pos); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } + constexpr iterator begin() noexcept { return reinterpret_cast<iterator>(&m_buf[0]); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + m_pos); } + constexpr iterator end() noexcept { return reinterpret_cast<iterator>(&m_buf[0] + m_pos); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); } + constexpr const_iterator cbegin() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0]); } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + m_pos); } - - protected: + constexpr const_iterator cend() const noexcept { return reinterpret_cast<const_iterator>(&m_buf[0] + m_pos); } private: std::array<typename std::aligned_storage<sizeof(C), alignof(C)>::type, N> m_buf; @@ -181,55 +177,67 @@ namespace plib { /// /// The list allows insertions and deletions whilst being processed. /// - template <class LC> + template <class LC, int TAG> class linked_list_t { public: + using ttag = std::integral_constant<int, TAG>; struct element_t { public: - friend class linked_list_t<LC>; + using tag = std::integral_constant<int, TAG>; + + friend class linked_list_t<LC, TAG>; - constexpr element_t() : m_next(nullptr), m_prev(nullptr) {} + constexpr element_t() noexcept : m_next(nullptr), m_prev(nullptr) {} ~element_t() noexcept = default; - element_t(const element_t &) = default; \ - element_t &operator=(const element_t &) = default; - element_t(element_t &&) noexcept = default; - element_t &operator=(element_t &&) noexcept = default; + constexpr element_t(const element_t &) noexcept = default; + constexpr element_t &operator=(const element_t &) noexcept = default; + constexpr element_t(element_t &&) noexcept = default; + constexpr element_t &operator=(element_t &&) noexcept = default; - constexpr LC * &next() noexcept { return m_next; } - constexpr LC * &prev() noexcept { return m_prev; } private: - LC * m_next; - LC * m_prev; + element_t * m_next; + element_t * m_prev; }; struct iter_t final : public std::iterator<std::forward_iterator_tag, LC> { private: - LC* p; + element_t * p; public: - explicit constexpr iter_t(LC* x) noexcept : p(x) { } + using tag = std::integral_constant<int, TAG>; + + explicit constexpr iter_t(element_t * x) noexcept : p(x) { } + constexpr iter_t(const iter_t &rhs) noexcept = default; - iter_t(iter_t &&rhs) noexcept = default; + constexpr iter_t(iter_t &&rhs) noexcept = default; + constexpr iter_t& operator=(const iter_t &rhs) noexcept = default; + constexpr iter_t& operator=(iter_t &&rhs) noexcept = default; - iter_t& operator=(const iter_t &rhs) noexcept = default; - iter_t& operator=(iter_t &&rhs) noexcept = default; ~iter_t() noexcept = default; - iter_t& operator++() noexcept { p = p->next(); return *this; } + iter_t& operator++() noexcept { p = p->m_next; return *this; } // NOLINTNEXTLINE(cert-dcl21-cpp) iter_t operator++(int) & noexcept { const iter_t tmp(*this); operator++(); return tmp; } constexpr bool operator==(const iter_t& rhs) const noexcept { return p == rhs.p; } constexpr bool operator!=(const iter_t& rhs) const noexcept { return p != rhs.p; } - constexpr LC& operator*() noexcept { return *p; } - constexpr LC* operator->() noexcept { return p; } - - constexpr LC& operator*() const noexcept { return *p; } - constexpr LC* operator->() const noexcept { return p; } +#if 0 + constexpr LC& operator*() noexcept { return *static_cast<LC *>(p); } + constexpr LC* operator->() noexcept { return static_cast<LC *>(p); } + + constexpr LC& operator*() const noexcept { return *static_cast<LC *>(p); } + constexpr LC* operator->() const noexcept { return static_cast<LC *>(p); } +#else + constexpr LC* operator*() noexcept { return static_cast<LC *>(p); } + constexpr LC* operator->() noexcept { return static_cast<LC *>(p); } + + constexpr LC* operator*() const noexcept { return static_cast<LC *>(p); } + constexpr LC* operator->() const noexcept { return static_cast<LC *>(p); } +#endif }; constexpr linked_list_t() noexcept : m_head(nullptr) {} @@ -237,7 +245,7 @@ namespace plib { constexpr iter_t begin() const noexcept { return iter_t(m_head); } constexpr iter_t end() const noexcept { return iter_t(nullptr); } - void push_front(LC *elem) noexcept + constexpr void push_front(element_t *elem) noexcept { elem->m_next = m_head; elem->m_prev = nullptr; @@ -246,10 +254,10 @@ namespace plib { m_head = elem; } - void push_back(LC *elem) noexcept + constexpr void push_back(element_t *elem) noexcept { - LC ** p(&m_head); - LC * prev(nullptr); + element_t ** p(&m_head); + element_t * prev(nullptr); while (*p != nullptr) { prev = *p; @@ -260,7 +268,7 @@ namespace plib { elem->m_next = nullptr; } - void remove(const LC *elem) noexcept + constexpr void remove(const element_t *elem) noexcept { if (elem->m_prev) elem->m_prev->m_next = elem->m_next; @@ -276,12 +284,24 @@ namespace plib { constexpr LC *front() const noexcept { return m_head; } constexpr bool empty() const noexcept { return (m_head == nullptr); } - void clear() noexcept + constexpr std::size_t size() const noexcept + { + std::size_t ret = 0; + element_t *p = m_head; + while (p != nullptr) + { + ret++; + p = p->m_next; + } + return ret; + } + + constexpr void clear() noexcept { - LC *p(m_head); + element_t *p(m_head); while (p != nullptr) { - LC *n(p->m_next); + element_t *n(p->m_next); p->m_next = nullptr; p->m_prev = nullptr; p = n; @@ -290,7 +310,7 @@ namespace plib { } private: - LC *m_head; + element_t *m_head; }; } // namespace plib diff --git a/src/lib/netlist/plib/pmain.h b/src/lib/netlist/plib/pmain.h index 632a4f638de..3213719d0d2 100644 --- a/src/lib/netlist/plib/pmain.h +++ b/src/lib/netlist/plib/pmain.h @@ -42,7 +42,7 @@ namespace plib { virtual pstring usage() = 0; - /* short version of usage, defaults to usage */ + // short version of usage, defaults to usage virtual pstring usage_short() { return usage(); } virtual int execute() = 0; diff --git a/src/lib/netlist/plib/pmatrix_cr.h b/src/lib/netlist/plib/pmatrix_cr.h index 3462cefde67..ec1729dae72 100644 --- a/src/lib/netlist/plib/pmatrix_cr.h +++ b/src/lib/netlist/plib/pmatrix_cr.h @@ -79,27 +79,27 @@ namespace plib constexpr std::size_t size() const noexcept { return (N>0) ? narrow_cast<std::size_t>(N) : m_size; } - void clear() noexcept + constexpr void clear() noexcept { nz_num = 0; for (std::size_t i=0; i < size() + 1; i++) row_idx[i] = 0; } - void set_scalar(T scalar) noexcept + constexpr void set_scalar(T scalar) noexcept { for (std::size_t i=0, e=nz_num; i<e; i++) A[i] = scalar; } - void set_row_scalar(C r, T val) noexcept + constexpr void set_row_scalar(C r, T val) noexcept { C ri = row_idx[r]; while (ri < row_idx[r+1]) A[ri++] = val; } - void set(C r, C c, T val) noexcept + constexpr void set(C r, C c, T val) noexcept { C ri = row_idx[r]; while (ri < row_idx[r+1] && col_idx[ri] < c) @@ -233,8 +233,8 @@ namespace plib A[k] = src.A[k]; } - index_type * nzbd(std::size_t row) { return m_nzbd[row]; } - std::size_t nzbd_count(std::size_t row) { return m_nzbd.col_count(row) - 1; } + constexpr index_type * nzbd(std::size_t row) noexcept { return m_nzbd[row]; } + constexpr std::size_t nzbd_count(std::size_t row) noexcept { return m_nzbd.col_count(row) - 1; } protected: // FIXME: this should be private // NOLINTNEXTLINE @@ -265,7 +265,7 @@ namespace plib ~pGEmatrix_cr() = default; template <typename M> - std::pair<std::size_t, std::size_t> gaussian_extend_fill_mat(M &fill) + std::pair<std::size_t, std::size_t> gaussian_extend_fill_mat(M &fill) noexcept { std::size_t ops = 0; std::size_t fill_max = 0; @@ -298,7 +298,7 @@ namespace plib } template <typename V> - void gaussian_elimination(V & RHS) + void gaussian_elimination(V & RHS) noexcept { const std::size_t iN = base_type::size(); @@ -338,7 +338,7 @@ namespace plib } } - int get_parallel_level(std::size_t k) const + int get_parallel_level(std::size_t k) const noexcept { for (std::size_t i = 0; i < m_ge_par.size(); i++) if (plib::container::contains( m_ge_par[i], k)) @@ -347,7 +347,7 @@ namespace plib } template <typename V> - void gaussian_elimination_parallel(V & RHS) + void gaussian_elimination_parallel(V & RHS) noexcept { //printf("omp: %ld %d %d\n", m_ge_par.size(), nz_num, (int)m_ge_par[m_ge_par.size()-2].size()); for (auto l = 0UL; l < m_ge_par.size(); l++) @@ -388,7 +388,7 @@ namespace plib } template <typename V1, typename V2> - void gaussian_back_substitution(V1 &V, const V2 &RHS) + void gaussian_back_substitution(V1 &V, const V2 &RHS) noexcept { const std::size_t iN = base_type::size(); // row n-1 @@ -406,7 +406,7 @@ namespace plib } template <typename V1> - void gaussian_back_substitution(V1 &V) + void gaussian_back_substitution(V1 &V) noexcept { const std::size_t iN = base_type::size(); // row n-1 @@ -425,7 +425,7 @@ namespace plib private: template <typename M> - void build_parallel_gaussian_execution_scheme(const M &fill) + void build_parallel_gaussian_execution_scheme(const M &fill) noexcept { // calculate parallel scheme for gaussian elimination std::vector<std::vector<std::size_t>> rt(base_type::size()); @@ -505,7 +505,7 @@ namespace plib ~pLUmatrix_cr() = default; template <typename M> - void build(M &fill, std::size_t ilup) + void build(M &fill, std::size_t ilup) noexcept { std::size_t p(0); // build ilu_rows @@ -552,7 +552,7 @@ namespace plib /// k=k+1 /// i=i+1 /// - void incomplete_LU_factorization(const base_type &mat) + void incomplete_LU_factorization(const base_type &mat) noexcept { if (m_ILUp < 1) this->raw_copy_from(mat); @@ -615,7 +615,7 @@ namespace plib /// This can be solved for x using backwards elimination in U. /// template <typename R> - void solveLU (R &r) + void solveLU (R &r) noexcept { for (std::size_t i = 1; i < base_type::size(); ++i ) { diff --git a/src/lib/netlist/plib/pmulti_threading.h b/src/lib/netlist/plib/pmulti_threading.h index 4645351f854..f7b89079bc0 100644 --- a/src/lib/netlist/plib/pmulti_threading.h +++ b/src/lib/netlist/plib/pmulti_threading.h @@ -36,8 +36,8 @@ namespace plib { { public: inline pspin_mutex() noexcept = default; - static inline void lock() /*const*/ noexcept { } - static inline void unlock() /*const*/ noexcept { } + static inline void lock() noexcept { } + static inline void unlock() noexcept { } }; class psemaphore diff --git a/src/lib/netlist/plib/prandom.h b/src/lib/netlist/plib/prandom.h index 062e0507705..c087e6acbda 100644 --- a/src/lib/netlist/plib/prandom.h +++ b/src/lib/netlist/plib/prandom.h @@ -147,7 +147,7 @@ namespace plib template <typename ST> void save_state([[maybe_unused]] ST &st) { - /* no state to save */ + // no state to save } private: diff --git a/src/lib/netlist/plib/pstate.h b/src/lib/netlist/plib/pstate.h index 164937dbbcf..72473590b9b 100644 --- a/src/lib/netlist/plib/pstate.h +++ b/src/lib/netlist/plib/pstate.h @@ -105,9 +105,9 @@ public: { } template <typename XS> - void save_item(XS &xstate, const pstring &item_name) + void save_item(XS &some_state, const pstring &item_name) { - m_sm.save_item(m_owner, xstate, m_member_name + "." + item_name); + m_sm.save_item(m_owner, some_state, m_member_name + "." + item_name); } state_manager_t &m_sm; diff --git a/src/lib/netlist/plib/pstream.h b/src/lib/netlist/plib/pstream.h index 281bca65be3..72a2f242106 100644 --- a/src/lib/netlist/plib/pstream.h +++ b/src/lib/netlist/plib/pstream.h @@ -69,7 +69,7 @@ namespace plib { , m_filename(std::move(rhs.m_filename)) { } - istream_uptr &operator=(istream_uptr &&) /*noexcept*/ = delete; + istream_uptr &operator=(istream_uptr &&) = delete; ~istream_uptr() = default; diff --git a/src/lib/netlist/plib/ptime.h b/src/lib/netlist/plib/ptime.h index 6ccafe640ba..0881f337371 100644 --- a/src/lib/netlist/plib/ptime.h +++ b/src/lib/netlist/plib/ptime.h @@ -172,8 +172,8 @@ namespace plib } constexpr double as_double() const noexcept { return as_fp<double>(); } - constexpr double as_float() const noexcept { return as_fp<float>(); } - constexpr double as_long_double() const noexcept { return as_fp<long double>(); } + constexpr float as_float() const noexcept { return as_fp<float>(); } + constexpr long double as_long_double() const noexcept { return as_fp<long double>(); } constexpr ptime shl(unsigned shift) const noexcept { return ptime(m_time << shift); } diff --git a/src/lib/netlist/plib/ptimed_queue.h b/src/lib/netlist/plib/ptimed_queue.h index 49ff09a69a8..35f9f9a6b54 100644 --- a/src/lib/netlist/plib/ptimed_queue.h +++ b/src/lib/netlist/plib/ptimed_queue.h @@ -28,6 +28,8 @@ namespace plib { template <typename Time, typename Element> struct queue_entry_t final { + using element_type = Element; + constexpr queue_entry_t() noexcept : m_exec_time(), m_object(nullptr) { } constexpr queue_entry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { } @@ -67,8 +69,7 @@ namespace plib { Element m_object; }; - // Use TS = true for a threadsafe queue - template <class A, class T, bool TS> + template <class A, class T> class timed_queue_linear { public: @@ -80,94 +81,34 @@ namespace plib { } ~timed_queue_linear() = default; - PCOPYASSIGNMOVE(timed_queue_linear, delete) + timed_queue_linear(const timed_queue_linear &) = delete; + timed_queue_linear &operator=(const timed_queue_linear &) = delete; + timed_queue_linear(timed_queue_linear &&) noexcept = delete; + timed_queue_linear &operator=(timed_queue_linear &&) noexcept = delete; - std::size_t capacity() const noexcept { return m_list.capacity() - 1; } - bool empty() const noexcept { return (m_end == &m_list[1]); } + constexpr std::size_t capacity() const noexcept { return m_list.capacity() - 1; } + constexpr bool empty() const noexcept { return (m_end == &m_list[1]); } template<bool KEEPSTAT, typename... Args> - void emplace(Args&&... args) noexcept - { - // Lock - lock_guard_type lck(m_lock); - T * i(m_end++); - *i = T(std::forward<Args>(args)...); - - if (!KEEPSTAT) - { - for (; *(i-1) < *i; --i) - { - std::swap(*(i-1), *(i)); - } - } - else - { - for (; *(i-1) < *i; --i) - { - std::swap(*(i-1), *(i)); - m_prof_sortmove.inc(); - } - m_prof_call.inc(); - } - } + constexpr void emplace (Args&&... args) noexcept; template<bool KEEPSTAT> - void push(T && e) noexcept - { -#if 0 - // Lock - lock_guard_type lck(m_lock); - T * i(m_end-1); - for (; *i < e; --i) - { - *(i+1) = *(i); - if (KEEPSTAT) - m_prof_sortmove.inc(); - } - *(i+1) = std::move(e); - ++m_end; -#else - // Lock - lock_guard_type lck(m_lock); - T * i(m_end++); - *i = std::move(e); - for (; *(i-1) < *i; --i) - { - std::swap(*(i-1), *(i)); - if (KEEPSTAT) - m_prof_sortmove.inc(); - } -#endif - if (KEEPSTAT) - m_prof_call.inc(); - } + constexpr void push(T && e) noexcept; - void pop() noexcept { --m_end; } + constexpr void pop() noexcept { --m_end; } - const T &top() const noexcept { return *(m_end-1); } + constexpr const T &top() const noexcept { return *(m_end-1); } - template <bool KEEPSTAT, class R> - void remove(const R &elem) noexcept - { - // Lock - lock_guard_type lck(m_lock); - if (KEEPSTAT) - m_prof_remove.inc(); - for (T * i = m_end - 1; i > &m_list[0]; --i) - { - // == operator ignores time! - if (*i == elem) - { - std::copy(i+1, m_end--, i); - return; - } - } - //printf("Element not found in delete %s\n", elem->name().c_str()); - } + constexpr bool exists(const typename T::element_type &elem) const noexcept; + + template <bool KEEPSTAT> + constexpr void remove(const T &elem) noexcept; + + template <bool KEEPSTAT> + constexpr void remove(const typename T::element_type &elem) noexcept; - void clear() noexcept + constexpr void clear() noexcept { - lock_guard_type lck(m_lock); m_end = &m_list[0]; // put an empty element with maximum time into the queue. // the insert algo above will run into this element and doesn't @@ -179,26 +120,135 @@ namespace plib { // save state support & mame disassembler - const T *list_pointer() const noexcept { return &m_list[1]; } - std::size_t size() const noexcept { return narrow_cast<std::size_t>(m_end - &m_list[1]); } - const T & operator[](std::size_t index) const noexcept { return m_list[ 1 + index]; } - private: - using mutex_type = pspin_mutex<TS>; - using lock_guard_type = std::lock_guard<mutex_type>; + constexpr const T *list_pointer() const noexcept { return &m_list[1]; } + constexpr std::size_t size() const noexcept { return narrow_cast<std::size_t>(m_end - &m_list[1]); } + constexpr const T & operator[](std::size_t index) const noexcept { return m_list[ 1 + index]; } - mutex_type m_lock; + private: + PALIGNAS(PALIGN_CACHELINE) T * m_end; - plib::arena_vector<A, T> m_list; + plib::arena_vector<A, T, PALIGN_CACHELINE> m_list; public: // profiling // FIXME: Make those private - pperfcount_t<true> m_prof_sortmove; // NOLINT + pperfcount_t<true> m_prof_sort_move; // NOLINT pperfcount_t<true> m_prof_call; // NOLINT pperfcount_t<true> m_prof_remove; // NOLINT }; - template <class A, class T, bool TS> + template <class A, class T> + template<bool KEEPSTAT, typename... Args> + inline constexpr void timed_queue_linear<A, T>::emplace (Args&&... args) noexcept + { + T * i(m_end); + *i = T(std::forward<Args>(args)...); + //if (i->object() != nullptr && exists(i->object())) + // printf("Object exists %s\n", i->object()->name().c_str()); + m_end++; + if constexpr (!KEEPSTAT) + { + for (; *(i-1) < *i; --i) + { + std::swap(*(i-1), *(i)); + } + } + else + { + for (; *(i-1) < *i; --i) + { + std::swap(*(i-1), *(i)); + m_prof_sort_move.inc(); + } + m_prof_call.inc(); + } + } + + template <class A, class T> + template<bool KEEPSTAT> + inline constexpr void timed_queue_linear<A, T>::push(T && e) noexcept + { +#if 0 + // The code is not as fast as the code path which is enabled. + // It is left here in case on a platform different to x64 it may + // be faster. + T * i(m_end-1); + for (; *i < e; --i) + { + *(i+1) = *(i); + if (KEEPSTAT) + m_prof_sort_move.inc(); + } + *(i+1) = std::move(e); + ++m_end; +#else + //if (e.object() != nullptr && exists(e.object())) + // printf("Object exists %s\n", e.object()->name().c_str()); + T * i(m_end++); + *i = std::move(e); + for (; *(i-1) < *i; --i) + { + std::swap(*(i-1), *(i)); + if constexpr (KEEPSTAT) + m_prof_sort_move.inc(); + } +#endif + if constexpr (KEEPSTAT) + m_prof_call.inc(); + } + + template <class A, class T> + template <bool KEEPSTAT> + inline constexpr void timed_queue_linear<A, T>::remove(const T &elem) noexcept + { + if constexpr (KEEPSTAT) + m_prof_remove.inc(); + for (T * i = m_end - 1; i > &m_list[0]; --i) + { + // == operator ignores time! + if (*i == elem) + { + std::copy(i+1, m_end--, i); + return; + } + } + //printf("Element not found in delete %s\n", elem->name().c_str()); + } + + template <class A, class T> + template <bool KEEPSTAT> + inline constexpr void timed_queue_linear<A, T>::remove(const typename T::element_type &elem) noexcept + { + if constexpr (KEEPSTAT) + m_prof_remove.inc(); + for (T * i = m_end - 1; i > &m_list[0]; --i) + { + // == operator ignores time! + if (*i == elem) + { + std::copy(i+1, m_end--, i); + return; + } + } + //printf("Element not found in delete %s\n", elem->name().c_str()); + } + + template <class A, class T> + inline constexpr bool timed_queue_linear<A, T>::exists(const typename T::element_type &elem) const noexcept + { + for (T * i = &m_list[1]; i < m_end; ++i) + { + if (*i == elem) + { + return true; + } + } + return false; + } + + + + template <class A, class T> class timed_queue_heap { public: @@ -223,8 +273,6 @@ namespace plib { template<bool KEEPSTAT, typename... Args> void emplace(Args&&... args) noexcept { - // Lock - lock_guard_type lck(m_lock); *m_end++ = T(std::forward<Args>(args)...); std::push_heap(&m_list[0], m_end, compare()); if (KEEPSTAT) @@ -234,8 +282,6 @@ namespace plib { template <bool KEEPSTAT> void push(T &&e) noexcept { - // Lock - lock_guard_type lck(m_lock); *m_end++ = e; std::push_heap(&m_list[0], m_end, compare()); if (KEEPSTAT) @@ -250,11 +296,26 @@ namespace plib { const T &top() const noexcept { return m_list[0]; } - template <bool KEEPSTAT, class R> - void remove(const R &elem) noexcept + template <bool KEEPSTAT> + void remove(const T &elem) noexcept + { + if (KEEPSTAT) + m_prof_remove.inc(); + for (T * i = m_end - 1; i >= &m_list[0]; i--) + { + if (*i == elem) + { + m_end--; + *i = *m_end; + std::make_heap(&m_list[0], m_end, compare()); + return; + } + } + } + + template <bool KEEPSTAT> + void remove(const typename T::element_type &elem) noexcept { - // Lock - lock_guard_type lck(m_lock); if (KEEPSTAT) m_prof_remove.inc(); for (T * i = m_end - 1; i >= &m_list[0]; i--) @@ -271,7 +332,6 @@ namespace plib { void clear() { - lock_guard_type lck(m_lock); m_list.clear(); m_end = &m_list[0]; } @@ -282,16 +342,12 @@ namespace plib { constexpr std::size_t size() const noexcept { return m_list.size(); } constexpr const T & operator[](const std::size_t index) const { return m_list[ 0 + index]; } private: - using mutex_type = pspin_mutex<TS>; - using lock_guard_type = std::lock_guard<mutex_type>; - - mutex_type m_lock; T * m_end; plib::arena_vector<A, T> m_list; public: // profiling - pperfcount_t<true> m_prof_sortmove; // NOLINT + pperfcount_t<true> m_prof_sort_move; // NOLINT pperfcount_t<true> m_prof_call; // NOLINT pperfcount_t<true> m_prof_remove; // NOLINT }; diff --git a/src/lib/netlist/plib/ptokenizer.cpp b/src/lib/netlist/plib/ptokenizer.cpp index 67fd506dc39..98be18b6419 100644 --- a/src/lib/netlist/plib/ptokenizer.cpp +++ b/src/lib/netlist/plib/ptokenizer.cpp @@ -83,11 +83,11 @@ namespace plib { m_token_queue = nullptr; } - void token_reader_t::require_token(const token_id_t &token_num) { require_token(get_token(), token_num); } + void token_reader_t::require_token(const token_t &tok, const token_id_t &token_num) { if (!tok.is(token_num)) diff --git a/src/lib/netlist/plib/ptypes.h b/src/lib/netlist/plib/ptypes.h index cf0476beb4c..1ae9b1edeb1 100644 --- a/src/lib/netlist/plib/ptypes.h +++ b/src/lib/netlist/plib/ptypes.h @@ -57,6 +57,12 @@ namespace plib struct plog_level; + template <typename A, typename T> + class timed_queue_linear; + + template <typename A, typename T> + class timed_queue_heap; + namespace detail { class token_store_t; diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp index cd2e8eacc7e..b741259c49e 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.cpp +++ b/src/lib/netlist/solver/nld_matrix_solver.cpp @@ -86,7 +86,7 @@ namespace netlist::solver m_main_solver.reschedule(this, ts); } - void matrix_solver_t::setup_base(setup_t &setup, const net_list_t &nets) + void matrix_solver_t::setup_base([[maybe_unused]] setup_t &setup, const net_list_t &nets) { log().debug("New solver setup\n"); std::vector<core_device_t *> step_devices; @@ -102,14 +102,19 @@ namespace netlist::solver for (std::size_t k = 0; k < nets.size(); k++) { + std::vector<detail::core_terminal_t *> temp; + analog_net_t &net = *nets[k]; - log().debug("adding net with {1} populated connections\n", setup.nlstate().core_terms(net).size()); + // FIXME: add size() to list + // log().debug("adding net with {1} populated connections\n", net.core_terms().size()); net.set_solver(this); - for (auto &p : setup.nlstate().core_terms(net)) + for (detail::core_terminal_t * p : net.core_terms_copy()) { + nl_assert_always(&p->net() == &net, "Net integrity violated"); + log().debug("{1} {2} {3}\n", p->name(), net.name(), net.is_rail_net()); switch (p->type()) { @@ -122,6 +127,7 @@ namespace netlist::solver dynamic_devices.push_back(&p->device()); { auto *pterm = dynamic_cast<terminal_t *>(p); + nl_assert(pterm != nullptr); add_term(k, pterm); } log().debug("Added terminal {1}\n", p->name()); @@ -139,12 +145,13 @@ namespace netlist::solver if (net_proxy_output == nullptr) { pstring new_name(this->name() + "." + pstring(plib::pfmt("m{1}")(m_inputs.size()))); - nl_assert(p->net().is_analog()); + nl_assert_always(net.is_analog(), "Net is not an analog net"); auto net_proxy_output_u = state().make_pool_object<proxied_analog_output_t>(*this, new_name, &dynamic_cast<analog_net_t &>(p->net())); net_proxy_output = net_proxy_output_u.get(); m_inputs.emplace_back(std::move(net_proxy_output_u)); } - setup.add_terminal(net_proxy_output->net(), *p); + net.remove_terminal(*p); + net_proxy_output->net().add_terminal(*p); // FIXME: repeated calling - kind of brute force net_proxy_output->net().rebuild_list(); log().debug("Added input {1}", net_proxy_output->name()); @@ -155,6 +162,7 @@ namespace netlist::solver throw nl_exception(MF_UNHANDLED_ELEMENT_1_FOUND(p->name())); } } + net.rebuild_list(); } for (auto &d : step_devices) m_step_funcs.emplace_back(nl_delegate_ts(&core_device_t::time_step, d)); @@ -167,7 +175,7 @@ namespace netlist::solver /// @param sort Sort algorithm to use. /// /// Sort in descending order by number of connected matrix voltages. - ///The idea is, that for Gauss-Seidel algorithm the first voltage computed + /// The idea is, that for Gauss-Seidel algorithm the first voltage computed /// depends on the greatest number of previous voltages thus taking into /// account the maximum amount of information. /// @@ -427,20 +435,6 @@ namespace netlist::solver inp->push(inp->proxied_net()->Q_Analog()); } - bool matrix_solver_t::updates_net(const analog_net_t *net) const noexcept - { - if (net != nullptr) - { - for (const auto &t : m_terms ) - if (t.is_net(net)) - return true; - for (const auto &inp : m_inputs) - if (&inp->net() == net) - return true; - } - return false; - } - void matrix_solver_t::update_dynamic() noexcept { // update all non-linear devices diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h index 6bf4efcb733..6b53fe81ed2 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.h +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -245,14 +245,6 @@ namespace netlist::solver netlist_time solve(netlist_time_ext now, const char *source); void update_inputs(); - /// \brief Checks if solver may alter a net - /// - /// This checks if a solver will alter a net. Returns true if the - /// net is either part of the voltage vector or if it belongs to - /// the analog input nets connected to the solver. - - bool updates_net(const analog_net_t *net) const noexcept; - std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); } std::size_t time_step_device_count() const noexcept { return m_step_funcs.size(); } @@ -307,7 +299,7 @@ namespace netlist::solver virtual std::pair<pstring, pstring> create_solver_code([[maybe_unused]] solver::static_compile_target target) { - return { "", plib::pfmt("/* solver doesn't support static compile */\n\n") }; + return { "", plib::pfmt("// solver doesn't support static compile\n\n") }; } // return number of floating point operations for solve diff --git a/src/lib/netlist/solver/nld_ms_direct_lu.h b/src/lib/netlist/solver/nld_ms_direct_lu.h index d95019ded1f..c51ccac4da5 100644 --- a/src/lib/netlist/solver/nld_ms_direct_lu.h +++ b/src/lib/netlist/solver/nld_ms_direct_lu.h @@ -137,10 +137,10 @@ protected: nl_double delta(const nl_double * RESTRICT V); void store(const nl_double * RESTRICT V); - /* bring the whole system to the current time - * Don't schedule a new calculation time. The recalculation has to be - * triggered by the caller after the netlist element was changed. - */ + // bring the whole system to the current time + // Don't schedule a new calculation time. The recalculation has to be + // triggered by the caller after the netlist element was changed. + nl_double compute_next_time_step(); template <typename T1, typename T2> @@ -175,10 +175,9 @@ nl_double matrix_solver_direct_t<m_N, storage_N>::compute_next_time_step() if (m_params.m_dynamic_ts) { - /* - * FIXME: We should extend the logic to use either all nets or - * only output nets. - */ + // + // FIXME: We should extend the logic to use either all nets or + // only output nets. for (unsigned k = 0, iN=N(); k < iN; k++) { analog_net_t *n = m_nets[k]; @@ -223,7 +222,7 @@ void matrix_solver_direct_t<m_N, storage_N>::add_term(int k, terminal_t *term) { m_terms[k]->add(term, ot, true); } - /* Should this be allowed ? */ + // Should this be allowed ? else // if (ot<0) { m_rails_temp[k].add(term, ot, true); @@ -259,25 +258,25 @@ void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) #if 1 - /* Sort in descending order by number of connected matrix voltages. - * The idea is, that for Gauss-Seidel algo the first voltage computed - * depends on the greatest number of previous voltages thus taking into - * account the maximum amount of information. - * - * This actually improves performance on popeye slightly. Average - * GS computations reduce from 2.509 to 2.370 - * - * Smallest to largest : 2.613 - * Unsorted : 2.509 - * Largest to smallest : 2.370 - * - * Sorting as a general matrix pre-conditioning is mentioned in - * literature but I have found no articles about Gauss Seidel. - * - * For Gaussian Elimination however increasing order is better suited. - * FIXME: Even better would be to sort on elements right of the matrix diagonal. - * - */ + // Sort in descending order by number of connected matrix voltages. + // The idea is, that for Gauss-Seidel algo the first voltage computed + // depends on the greatest number of previous voltages thus taking into + // account the maximum amount of information. + // + // This actually improves performance on popeye slightly. Average + // GS computations reduce from 2.509 to 2.370 + // + // Smallest to largest : 2.613 + // Unsorted : 2.509 + // Largest to smallest : 2.370 + // + // Sorting as a general matrix pre-conditioning is mentioned in + // literature but I have found no articles about Gauss Seidel. + // + // For Gaussian Elimination however increasing order is better suited. + // FIXME: Even better would be to sort on elements right of the matrix diagonal. + // + // int sort_order = (type() == GAUSS_SEIDEL ? 1 : -1); @@ -301,14 +300,13 @@ void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) #endif - /* create a list of non zero elements right of the diagonal - * These list anticipate the population of array elements by - * Gaussian elimination. - */ + // create a list of non zero elements right of the diagonal + // These list anticipate the population of array elements by + // Gaussian elimination. + for (unsigned k = 0; k < N(); k++) { terms_for_net_t * t = m_terms[k]; - /* pretty brutal */ int *other = t->connected_net_idx(); t->m_nz.clear(); @@ -354,9 +352,10 @@ void matrix_solver_direct_t<m_N, storage_N>::vsetup(analog_net_t::list_t &nets) log("\n"); } - /* - * save states - */ + // + // save states + // + save(NLNAME(m_RHS)); save(NLNAME(m_last_V)); @@ -494,7 +493,6 @@ void matrix_solver_direct_t<m_N, storage_N>::LE_solve() m_A[imax][k]=m_A[j][k]; m_A[j][k]=dum; } - //*d = -(*d); vv[imax]=vv[j]; } indx[j]=imax; @@ -514,7 +512,7 @@ void matrix_solver_direct_t<m_N, storage_N>::LE_back_subst( { const unsigned kN = N(); - /* back substitution */ + // back substitution // int ip; // ii=-1 @@ -546,10 +544,9 @@ template <unsigned m_N, unsigned storage_N> nl_double matrix_solver_direct_t<m_N, storage_N>::delta( const nl_double * RESTRICT V) { - /* FIXME: Ideally we should also include currents (RHS) here. This would - * need a revaluation of the right hand side after voltages have been updated - * and thus belong into a different calculation. This applies to all solvers. - */ + // FIXME: Ideally we should also include currents (RHS) here. This would + // need a revaluation of the right hand side after voltages have been updated + // and thus belong into a different calculation. This applies to all solvers. const unsigned iN = this->N(); nl_double cerr = 0; @@ -626,5 +623,5 @@ matrix_solver_direct_t<m_N, storage_N>::matrix_solver_direct_t(const eSolverType } //namespace devices } // namespace netlist -#endif /* NLD_MS_DIRECT_H_ */ +#endif // NLD_MS_DIRECT_H_ #endif diff --git a/src/lib/netlist/solver/nld_ms_gcr.h b/src/lib/netlist/solver/nld_ms_gcr.h index 48a78c81533..61bedfa8d06 100644 --- a/src/lib/netlist/solver/nld_ms_gcr.h +++ b/src/lib/netlist/solver/nld_ms_gcr.h @@ -161,7 +161,7 @@ namespace netlist::solver //# auto gtot_t = std::accumulate(gt, gt + term_count, plib::constants<FT>::zero()); //# *tcr_r[railstart] = static_cast<FT>(gtot_t); //mat.A[mat.diag[k]] += gtot_t; - auto pd = this->m_mat_ptr[k][net.rail_start()] - &this->mat.A[0]; + std::size_t pd = std::size_t(this->m_mat_ptr[k][net.rail_start()] - &this->mat.A[0]); #if COMPRESSED //pstring terms = plib::pfmt("m_A{1} = gt[{2}]")(pd, this->m_gtn.didx(k,0)); @@ -184,7 +184,7 @@ namespace netlist::solver #else for (std::size_t i=0; i < net.count(); i++) strm("\tm_A{1} += gt[{2}];\n", pd, this->m_gtn.didx(k,i)); - //for (std::size_t i = 0; i < railstart; i++) + //for (std::size_t i = 0; i < rail_start; i++) // *tcr_r[i] += static_cast<FT>(go[i]); for (std::size_t i = 0; i < net.rail_start(); i++) { @@ -207,9 +207,9 @@ namespace netlist::solver for (std::size_t k = 0; k < iN; k++) { auto &net = this->m_terms[k]; - for (std::size_t i = 0; i < net.railstart(); i++) + for (std::size_t i = 0; i < net.rail_start(); i++) { - auto p = this->m_mat_ptr[k][i] - &this->mat.A[0]; + std::size_t p = std::size_t(this->m_mat_ptr[k][i] - &this->mat.A[0]); if (!A[p].empty()) A[p] += " + "; A[p] += plib::pfmt("go[{1}]")(this->m_gonn.didx(k,i)); diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp index 59cc7a4ac31..445608a2c27 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -281,7 +281,7 @@ namespace netlist::devices for (auto & net : nl_state.nets()) { nl_state.log().verbose("processing {1}", net->name()); - if (!net->is_rail_net() && !nl_state.core_terms(*net).empty()) + if (!net->is_rail_net() && !net->core_terms_empty()) { nl_state.log().verbose(" ==> not a rail net"); // Must be an analog net @@ -346,12 +346,14 @@ namespace netlist::devices { // ignore empty nets. FIXME: print a warning message nl_state.log().verbose("Net {}", n.name()); - if (!nl_state.core_terms(n).empty()) + auto terminals(n.core_terms_copy()); + + if (!terminals.empty()) { // add the net groupspre.back().push_back(&n); // process all terminals connected to this net - for (auto &term : nl_state.core_terms(n)) + for (detail::core_terminal_t * term : terminals) { nl_state.log().verbose("Term {} {}", term->name(), static_cast<int>(term->type())); // only process analog terminals @@ -406,7 +408,7 @@ namespace netlist::devices state().log().error(ME_SOLVER_CONSISTENCY_RAIL_NET(n->name())); num_errors++; } - for (const auto &t : state().core_terms(*n)) + for (detail::core_terminal_t * t : n->core_terms_copy()) { if (!t->has_net()) { @@ -471,7 +473,7 @@ namespace netlist::devices for (auto &n : grp) { log().verbose("Net {1}", n->name()); - for (const auto &t : state().core_terms(*n)) + for (const detail::core_terminal_t *t : n->core_terms_copy()) { log().verbose(" {1}", t->name()); } diff --git a/src/lib/netlist/solver/nld_solver.h b/src/lib/netlist/solver/nld_solver.h index 0cc8b339448..898dac7403f 100644 --- a/src/lib/netlist/solver/nld_solver.h +++ b/src/lib/netlist/solver/nld_solver.h @@ -29,7 +29,7 @@ namespace netlist::devices { public: using solver_arena = device_arena; - using queue_type = detail::queue_base<solver_arena, solver::matrix_solver_t, false>; + using queue_type = detail::queue_base<solver_arena, solver::matrix_solver_t>; NETLIB_CONSTRUCTOR(solver) , m_fb_step(*this, "FB_step", NETLIB_DELEGATE(fb_step<false>)) diff --git a/src/lib/netlist/tests/test_penum.cpp b/src/lib/netlist/tests/test_penum.cpp index 715cbeedbcc..0fafafa97b4 100644 --- a/src/lib/netlist/tests/test_penum.cpp +++ b/src/lib/netlist/tests/test_penum.cpp @@ -181,15 +181,15 @@ PTEST(penum, conversion) { plibx::teste x = plib::functor<plibx::teste>("A"); - PEXPECT_EQ(x, plibx::teste::B); - PEXPECT_EQ(plib::functor<plibx::teste>("A"), plibx::teste::B); - PEXPECT_EQ(plib::functor<testf>("A"), testf::B); + PEXPECT_NE(x, plibx::teste::B); + PEXPECT_NE(plib::functor<plibx::teste>("A"), plibx::teste::B); + PEXPECT_NE(plib::functor<testf>("A"), testf::B); //PEXPECT_EQ(plib::functor("A"), testf::B); - PEXPECT_EQ(testf::B, "A"); - PEXPECT_EQ("A", testf::B); - PEXPECT_EQ(plib::functor(testf::A), "B"); + PEXPECT_EQ(testf::B, "B"); + PEXPECT_EQ("A", testf::A); + PEXPECT_NE(plib::functor(testf::A), "B"); PEXPECT_FALSE(plib::functor<pure>::is_defined::value); PEXPECT_EQ(plib::penum_to_string(testf::B), "B"); - PEXPECT_EQ(plib::string_to_penum<testf>("B"), testf::A); + PEXPECT_NE(plib::string_to_penum<testf>("B"), testf::A); //PEXPECT_EQ(pure::X, pure::Y); } diff --git a/src/lib/netlist/tests/test_precommit.cpp b/src/lib/netlist/tests/test_precommit.cpp index 7f710dfb668..55f9b596a8c 100644 --- a/src/lib/netlist/tests/test_precommit.cpp +++ b/src/lib/netlist/tests/test_precommit.cpp @@ -18,9 +18,10 @@ PTEST(test_precommit, precommit) PEXPECT_EQ(PPMF_EXPERIMENTAL, 0); PEXPECT_EQ(PPMF_USE_MAME_DELEGATES, 0); - PEXPECT_EQ(NL_USE_COPY_INSTEAD_OF_REFERENCE, 0); + PEXPECT_EQ(netlist::config::use_copy_instead_of_reference::value, false); PEXPECT_EQ(NL_USE_BACKWARD_EULER, 1); PEXPECT_EQ(PUSE_FLOAT128, 0); PEXPECT_EQ(NL_USE_FLOAT128, PUSE_FLOAT128); - PEXPECT_EQ(AVOID_NOOP_QUEUE_PUSHES, 0); + PEXPECT_EQ(NL_USE_INPLACE_CORE_TERMS, 0); + PEXPECT_EQ(netlist::config::avoid_noop_queue_pushes::value, false); } diff --git a/src/lib/netlist/tools/nl_convert.cpp b/src/lib/netlist/tools/nl_convert.cpp index 5a98910abb5..78ed6f12d77 100644 --- a/src/lib/netlist/tools/nl_convert.cpp +++ b/src/lib/netlist/tools/nl_convert.cpp @@ -417,7 +417,7 @@ static pstring rem(const std::vector<pstring> &vps, std::size_t start) return r; } -static int npoly(const pstring &s) +static int get_poly_count(const pstring &s) { // Brute force if (s=="POLY(1)") @@ -531,7 +531,7 @@ void nl_convert_spice_t::process_line(const pstring &line) break; case 'E': { - auto n=npoly(tt[3]); + auto n=get_poly_count(tt[3]); if (n<0) { add_device("VCVS", tt[0], get_sp_val(tt[5])); @@ -550,26 +550,26 @@ void nl_convert_spice_t::process_line(const pstring &line) out("// IGNORED {}: {}\n", tt[0], line); break; } - pstring lastnet = tt[1]; + pstring last_net = tt[1]; for (std::size_t i=0; i < static_cast<std::size_t>(n); i++) { pstring devname = plib::pfmt("{}{}")(tt[0], i); - pstring nextnet = (i<static_cast<std::size_t>(n)-1) ? plib::pfmt("{}a{}")(tt[1], i) : tt[2]; + pstring next_net = (i<static_cast<std::size_t>(n)-1) ? plib::pfmt("{}a{}")(tt[1], i) : tt[2]; auto net2 = plib::psplit(plib::replace_all(plib::replace_all(tt[sce+i],")",""),"(",""),','); add_device("VCVS", devname, get_sp_val(tt[scoeff+i])); - add_term(lastnet, devname, 0); - add_term(nextnet, devname, 1); + add_term(last_net, devname, 0); + add_term(next_net, devname, 1); add_term(net2[0], devname, 2); add_term(net2[1], devname, 3); //# add_device_extra(devname, "PARAM({}, {})", devname + ".G", tt[scoeff+i]); - lastnet = nextnet; + last_net = next_net; } } } break; case 'F': { - auto n=npoly(tt[3]); + auto n=get_poly_count(tt[3]); unsigned sce(4); unsigned scoeff(5 + static_cast<unsigned>(n)); if (n<0) |