From 25152bd69a070aa7ba84248b368b0803e407272a Mon Sep 17 00:00:00 2001 From: couriersud Date: Mon, 23 Jan 2017 21:20:09 +0100 Subject: [PATCH] Netlist refactoring: - Refactored netlist pmf code. - Small optimization for diode calculations. - Minor refactoring across the board. (nw) --- src/lib/netlist/analog/nld_twoterm.cpp | 31 ++---- src/lib/netlist/analog/nld_twoterm.h | 31 +++--- src/lib/netlist/nl_base.cpp | 14 +-- src/lib/netlist/nl_base.h | 25 ++--- src/lib/netlist/nl_config.h | 67 +++--------- src/lib/netlist/plib/pconfig.h | 141 +++++++++++++++++++++++-- src/lib/netlist/plib/pfunction.cpp | 2 +- src/lib/netlist/plib/pstring.cpp | 2 +- src/lib/netlist/plib/pstring.h | 9 +- src/lib/netlist/prg/nltool.cpp | 18 ++++ 10 files changed, 209 insertions(+), 131 deletions(-) diff --git a/src/lib/netlist/analog/nld_twoterm.cpp b/src/lib/netlist/analog/nld_twoterm.cpp index 0e53d77f1f5..d7b0c06392e 100644 --- a/src/lib/netlist/analog/nld_twoterm.cpp +++ b/src/lib/netlist/analog/nld_twoterm.cpp @@ -23,6 +23,7 @@ generic_diode::generic_diode(device_t &dev, pstring name) , m_Id(dev, name + ".m_Id", 0.0) , m_G(dev, name + ".m_G", 1e-15) , m_Vt(0.0) + , m_Vmin(0.0) , m_Is(0.0) , m_n(0.0) , m_gmin(1e-15) @@ -40,6 +41,7 @@ void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double g m_gmin = gmin; m_Vt = 0.0258 * m_n; + m_Vmin = -5.0 * m_Vt; m_Vcrit = m_Vt * std::log(m_Vt / m_Is / csqrt2); m_VtInv = 1.0 / m_Vt; @@ -47,8 +49,7 @@ void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double g void generic_diode::update_diode(const nl_double nVd) { -#if 1 - if (nVd < NL_FCONST(-5.0) * m_Vt) + if (nVd < m_Vmin) { m_Vd = nVd; m_G = m_gmin; @@ -58,29 +59,19 @@ void generic_diode::update_diode(const nl_double nVd) { m_Vd = nVd; //m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - m_G = m_Is * m_VtInv * eVDVt + m_gmin; + //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv); + const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv); + m_Id = IseVDVt - m_Is; + m_G = IseVDVt * m_VtInv + m_gmin; } else { -#if 1 - const nl_double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(-0.99)); + const double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(-0.99)); m_Vd = m_Vd + std::log1p(a) * m_Vt; -#else - m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); -#endif - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - - m_G = m_Is * m_VtInv * eVDVt + m_gmin; + const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv); + m_Id = IseVDVt - m_Is; + m_G = IseVDVt * m_VtInv + m_gmin; } -#else - m_Vd = m_Vd + 20.0 * m_Vt * std::tanh((nVd - m_Vd) / 20.0 / m_Vt); - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - m_G = m_Is * m_VtInv * eVDVt + m_gmin; -#endif } // ---------------------------------------------------------------------------------------- diff --git a/src/lib/netlist/analog/nld_twoterm.h b/src/lib/netlist/analog/nld_twoterm.h index 9494ad26520..44b3d29c16e 100644 --- a/src/lib/netlist/analog/nld_twoterm.h +++ b/src/lib/netlist/analog/nld_twoterm.h @@ -338,29 +338,30 @@ class generic_diode public: generic_diode(device_t &dev, pstring name); - void update_diode(const nl_double nVd); + void update_diode(const double nVd); - void set_param(const nl_double Is, const nl_double n, nl_double gmin); + void set_param(const double Is, const double n, double gmin); - inline nl_double I() const { return m_Id; } - inline nl_double G() const { return m_G; } - inline nl_double Ieq() const { return (m_Id - m_Vd * m_G); } - inline nl_double Vd() const { return m_Vd; } + inline double I() const { return m_Id; } + inline double G() const { return m_G; } + inline double Ieq() const { return (m_Id - m_Vd * m_G); } + inline double Vd() const { return m_Vd; } /* owning object must save those ... */ private: - state_var m_Vd; - state_var m_Id; - state_var m_G; + state_var m_Vd; + state_var m_Id; + state_var m_G; - nl_double m_Vt; - nl_double m_Is; - nl_double m_n; - nl_double m_gmin; + double m_Vt; + double m_Vmin; + double m_Is; + double m_n; + double m_gmin; - nl_double m_VtInv; - nl_double m_Vcrit; + double m_VtInv; + double m_Vcrit; }; /*! Class representing the diode model paramers. diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 6128200fe9a..50ef51827d8 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -578,7 +578,7 @@ core_device_t::core_device_t(netlist_t &owner, const pstring &name) , logic_family_t() , netlist_ref(owner) , m_hint_deactivate(false) -#if (NL_PMF_TYPE > NL_PMF_TYPE_VIRTUAL) +#if (!NL_USE_PMF_VIRTUAL) , m_static_update() #endif { @@ -591,7 +591,7 @@ core_device_t::core_device_t(core_device_t &owner, const pstring &name) , logic_family_t() , netlist_ref(owner.netlist()) , m_hint_deactivate(false) -#if (NL_PMF_TYPE > NL_PMF_TYPE_VIRTUAL) +#if (!NL_USE_PMF_VIRTUAL) , m_static_update() #endif { @@ -607,14 +607,8 @@ core_device_t::~core_device_t() void core_device_t::set_delegate_pointer() { -#if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF) - void (core_device_t::* pFunc)() = &core_device_t::update; - m_static_update = pFunc; -#elif (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) - void (core_device_t::* pFunc)() = &core_device_t::update; - m_static_update = reinterpret_cast((this->*pFunc)); -#elif (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL) - m_static_update = plib::mfp::get_mfp(&core_device_t::update, this); +#if (!NL_USE_PMF_VIRTUAL) + m_static_update.set_base(&core_device_t::update, this); #endif } diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 57d1e197378..e1bb98e3651 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -1082,12 +1082,10 @@ namespace netlist void do_update() NL_NOEXCEPT { - #if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF) - (this->*m_static_update)(); - #elif ((NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) || (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL)) - m_static_update(this); + #if (NL_USE_PMF_VIRTUAL) + update(); #else - update(); + m_static_update.call(this); #endif } @@ -1104,14 +1102,9 @@ namespace netlist private: bool m_hint_deactivate; - #if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF) - typedef void (core_device_t::*net_update_delegate)(); - #elif ((NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) || (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL)) - using net_update_delegate = MEMBER_ABI void (*)(core_device_t *); - #endif - #if (NL_PMF_TYPE > NL_PMF_TYPE_VIRTUAL) - net_update_delegate m_static_update; + #if (!NL_USE_PMF_VIRTUAL) + plib::pmfp_base m_static_update; #endif }; @@ -1277,11 +1270,11 @@ namespace netlist template void save(O &owner, C &state, const pstring &stname) { - this->state().save_item(static_cast(&owner), state, pstring::from_utf8(owner.name()) + pstring(".") + stname); + this->state().save_item(static_cast(&owner), state, from_utf8(owner.name()) + pstring(".") + stname); } template void save(O &owner, C *state, const pstring &stname, const std::size_t count) { - this->state().save_state_ptr(static_cast(&owner), pstring::from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f::f(), count, state); + this->state().save_state_ptr(static_cast(&owner), from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f::f(), count, state); } void rebuild_lists(); /* must be called after post_load ! */ @@ -1299,6 +1292,10 @@ namespace netlist private: + /* helper for save above */ + static pstring from_utf8(const char *c) { return pstring(c, pstring::UTF8); } + static pstring from_utf8(const pstring &c) { return c; } + core_device_t *pget_single_device(const pstring classname, bool (*cc)(core_device_t *)); /* mostly rw */ diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h index 88f240394be..174549410d6 100644 --- a/src/lib/netlist/nl_config.h +++ b/src/lib/netlist/nl_config.h @@ -18,59 +18,6 @@ // SETUP //============================================================ -/* - * The following options determine how object::update is called. - * NL_PMF_TYPE_VIRTUAL - * Use stock virtual call - * - * NL_PMF_TYPE_GNUC_PMF - * Use standard pointer to member function syntax - * - * NL_PMF_TYPE_GNUC_PMF_CONV - * Use gnu extension and convert the pmf to a function pointer. - * This is not standard compliant and needs - * -Wno-pmf-conversions to compile. - * - * NL_PMF_TYPE_INTERNAL - * Use the same approach as MAME for deriving the function pointer. - * This is compiler-dependant as well - * - * Benchmarks for ./nltool -c run -f src/mame/drivers/nl_pong.c -t 10 -n pong_fast - * - * NL_PMF_TYPE_INTERNAL: 215% - * NL_PMF_TYPE_GNUC_PMF: 163% - * NL_PMF_TYPE_GNUC_PMF_CONV: 215% - * NL_PMF_TYPE_VIRTUAL: 213% - * - * The whole exercise was done to avoid virtual calls. In prior versions of - * netlist, the INTERNAL and GNUC_PMF_CONV approach provided significant improvement. - * Since than, was removed from functions declared as virtual. - * This may explain that the recent benchmarks show no difference at all. - * - * Disappointing is the GNUC_PMF performance. - */ - -// This will be autodetected -// #define NL_PMF_TYPE 0 - -#define NL_PMF_TYPE_VIRTUAL 0 -#define NL_PMF_TYPE_GNUC_PMF 1 -#define NL_PMF_TYPE_GNUC_PMF_CONV 2 -#define NL_PMF_TYPE_INTERNAL 3 - -#ifndef NL_PMF_TYPE - #if PHAS_PMF_INTERNAL - #define NL_PMF_TYPE NL_PMF_TYPE_INTERNAL - #else - #define NL_PMF_TYPE NL_PMF_TYPE_VIRTUAL - #endif -#endif - -#if (NL_PMF_TYPE == NL_PMF_TYPE_GNUC_PMF_CONV) -#pragma GCC diagnostic ignored "-Wpmf-conversions" -#endif - - //============================================================ // GENERAL @@ -156,6 +103,20 @@ using nperfcount_t = plib::chrono::counter; #define NL_FCONST(x) x using nl_double = double; +/* The following option determines how object::update is called. + * If set to 1, a virtual call is used. If it is left undefined, the best + * approach will be automatically selected. + */ + +//#define NL_USE_PMF_VIRTUAL 1 + +#ifndef NL_USE_PMF_VIRTUAL + #if PPMF_TYPE == PPMF_TYPE_PMF + #define NL_USE_PMF_VIRTUAL 1 + #else + #define NL_USE_PMF_VIRTUAL 0 + #endif +#endif //============================================================ // WARNINGS diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h index 9cd917ceb28..198da5a4cc5 100644 --- a/src/lib/netlist/plib/pconfig.h +++ b/src/lib/netlist/plib/pconfig.h @@ -63,6 +63,42 @@ typedef __int128_t INT128; // cut down delegate implementation //============================================================ +/* + * + * NL_PMF_TYPE_GNUC_PMF + * Use standard pointer to member function syntax C++11 + * + * NL_PMF_TYPE_GNUC_PMF_CONV + * Use gnu extension and convert the pmf to a function pointer. + * This is not standard compliant and needs + * -Wno-pmf-conversions to compile. + * + * NL_PMF_TYPE_INTERNAL + * Use the same approach as MAME for deriving the function pointer. + * This is compiler-dependent as well + * + * Benchmarks for ./nltool -c run -f src/mame/machine/nl_pong.cpp -t 10 -n pong_fast + * + * NL_PMF_TYPE_INTERNAL: 215% 215% + * NL_PMF_TYPE_GNUC_PMF: 163% 196% + * NL_PMF_TYPE_GNUC_PMF_CONV: 215% 215% + * NL_PMF_TYPE_VIRTUAL: 213% 209% + * + * The whole exercise was done to avoid virtual calls. In prior versions of + * netlist, the INTERNAL and GNUC_PMF_CONV approach provided significant improvement. + * Since than, "hot" was removed from functions declared as virtual. + * This may explain that the recent benchmarks show no difference at all. + * + */ + +// This will be autodetected +// #define PPMF_TYPE 1 + +#define PPMF_TYPE_PMF 0 +#define PPMF_TYPE_GNUC_PMF_CONV 1 +#define PPMF_TYPE_INTERNAL 2 + + #if defined(__GNUC__) /* does not work in versions over 4.7.x of 32bit MINGW */ #if defined(__MINGW32__) && !defined(__x86_64) && defined(__i386__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))) @@ -87,6 +123,18 @@ typedef __int128_t INT128; #define MEMBER_ABI #endif +#ifndef PPMF_TYPE + #if PHAS_PMF_INTERNAL + #define PPMF_TYPE PPMF_TYPE_INTERNAL + #else + #define PPMF_TYPE PPMF_TYPE_PMF + #endif +#endif + +#if (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) +#pragma GCC diagnostic ignored "-Wpmf-conversions" +#endif + namespace plib { /* * The following class was derived from the MAME delegate.h code. @@ -108,18 +156,13 @@ namespace plib { *reinterpret_cast(this) = mftp; } - // binding helper - template - FunctionType update_after_bind(ObjectType *object) - { - return reinterpret_cast( - convert_to_generic(reinterpret_cast(object))); - } template static FunctionType get_mfp(MemberFunctionType mftp, ObjectType *object) { mfp mfpo(mftp); - return mfpo.update_after_bind(object); + //return mfpo.update_after_bind(object); + return reinterpret_cast( + mfpo.convert_to_generic(reinterpret_cast(object))); } private: @@ -144,9 +187,89 @@ namespace plib { // if odd, it's the byte offset into the vtable int m_this_delta; // delta to apply to the 'this' pointer }; - #endif +#if (PPMF_TYPE == PPMF_TYPE_PMF) + template + class pmfp_base + { + public: + class generic_class; + using generic_function = R (generic_class::*)(Targs...); + pmfp_base() : m_func(nullptr) {} + + template + void set_base(MemberFunctionType mftp, O *object) + { + using function_ptr = R (O::*)(Targs...); + function_ptr t = mftp; + m_func = reinterpret_cast(t); + } + template + inline R call(O *obj, Targs... args) const + { + using function_ptr = R (O::*)(Targs...); + function_ptr t = reinterpret_cast(m_func); + return (obj->*t)(std::forward(args)...); + } + private: + generic_function m_func; + }; + +#elif ((PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) || (PPMF_TYPE == PPMF_TYPE_INTERNAL)) + template + class pmfp_base + { + public: + using generic_function = void (*)(); + + pmfp_base() : m_func(nullptr) {} + + template + void set_base(MemberFunctionType mftp, O *object) + { + #if (PPMF_TYPE == PPMF_TYPE_INTERNAL) + using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args); + m_func = reinterpret_cast(plib::mfp::get_mfp(mftp, object)); + #elif (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) + R (O::* pFunc)(Targs...) = mftp; + m_func = reinterpret_cast((object->*pFunc)); + #endif + } + template + inline R call(O *obj, Targs... args) const + { + using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args); + return (*reinterpret_cast(m_func))(obj, std::forward(args)...); + } + private: + generic_function m_func; + }; +#endif + + template + class pmfp : public pmfp_base + { + public: + class generic_class; + pmfp() : pmfp_base(), m_obj(nullptr) {} + + template + void set(MemberFunctionType mftp, O *object) + { + this->set_base(mftp, object); + m_obj = reinterpret_cast(object); + } + + inline R operator()(Targs... args) const + { + return this->call(m_obj, std::forward(args)...); + } + private: + generic_class *m_obj; + }; + + } #endif /* PCONFIG_H_ */ diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index 004d0f3be86..9c797800650 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -81,7 +81,7 @@ void pfunction::compile_postfix(const std::vector &inputs, throw plib::pexception(plib::pfmt("nld_function: stack count different to one on <{2}>")(expr)); } -int get_prio(pstring v) +static int get_prio(pstring v) { if (v == "(" or v == ")") return 1; diff --git a/src/lib/netlist/plib/pstring.cpp b/src/lib/netlist/plib/pstring.cpp index 1a65bb152ff..3fc8ffa6dba 100644 --- a/src/lib/netlist/plib/pstring.cpp +++ b/src/lib/netlist/plib/pstring.cpp @@ -371,7 +371,7 @@ void pstringbuffer::pcat(const pstring &s) * This improves startup performance by 30%. */ -#if 0 +#if 1 static std::stack *stk = nullptr; diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h index 059df4b6376..e3dd475175e 100644 --- a/src/lib/netlist/plib/pstring.h +++ b/src/lib/netlist/plib/pstring.h @@ -23,7 +23,7 @@ struct pstr_t { - pstr_t(const int alen) { init(alen); } + pstr_t(const std::size_t alen) { init(alen); } void init(const std::size_t alen) { m_ref_count = 1; @@ -169,13 +169,6 @@ public: const pstring_t ucase() const; - // FIXME: do something with encoding - // FIXME: belongs into derived class - // This is only used in state saving to support "owners" whose name() function - // returns char*. - static pstring_t from_utf8(const mem_t *c) { return pstring_t(c, UTF8); } - static pstring_t from_utf8(const pstring_t &c) { return c; } - static void resetmem(); protected: diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp index 910f9078561..14b7409b95e 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -502,12 +502,30 @@ static const pstring pmf_verbose[] = }; #endif +struct tt +{ + void test(int a) {printf ("test :%d\n", a);} + int test1() { return 1;} +}; + +plib::pmfp atest; +plib::pmfp atest1; int main(int argc, char *argv[]) { tool_options_t opts; int ret; + tt x; + + atest.set(&tt::test, &x); + atest1.set(&tt::test1, &x); + + atest(1); + int a = atest1(); + + printf("%d\n", a); + //return 1 ; /* make SIGFPE actually deliver signals on supoorted platforms */ plib::fpsignalenabler::global_enable(true); plib::fpsignalenabler sigen(plib::FP_ALL & ~plib::FP_INEXACT & ~plib::FP_UNDERFLOW);