Netlist refactoring:

- Refactored netlist pmf code.
- Small optimization for diode calculations. 
- Minor refactoring across the board. (nw)
This commit is contained in:
couriersud 2017-01-23 21:20:09 +01:00
parent 093bda0193
commit 25152bd69a
10 changed files with 209 additions and 131 deletions

View File

@ -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
}
// ----------------------------------------------------------------------------------------

View File

@ -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<nl_double> m_Vd;
state_var<nl_double> m_Id;
state_var<nl_double> m_G;
state_var<double> m_Vd;
state_var<double> m_Id;
state_var<double> 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.

View File

@ -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<net_update_delegate>((this->*pFunc));
#elif (NL_PMF_TYPE == NL_PMF_TYPE_INTERNAL)
m_static_update = plib::mfp::get_mfp<net_update_delegate>(&core_device_t::update, this);
#if (!NL_USE_PMF_VIRTUAL)
m_static_update.set_base(&core_device_t::update, this);
#endif
}

View File

@ -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<void> m_static_update;
#endif
};
@ -1277,11 +1270,11 @@ namespace netlist
template<typename O, typename C> void save(O &owner, C &state, const pstring &stname)
{
this->state().save_item(static_cast<void *>(&owner), state, pstring::from_utf8(owner.name()) + pstring(".") + stname);
this->state().save_item(static_cast<void *>(&owner), state, from_utf8(owner.name()) + pstring(".") + stname);
}
template<typename O, typename C> void save(O &owner, C *state, const pstring &stname, const std::size_t count)
{
this->state().save_state_ptr(static_cast<void *>(&owner), pstring::from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f<C>::f(), count, state);
this->state().save_state_ptr(static_cast<void *>(&owner), from_utf8(owner.name()) + pstring(".") + stname, plib::state_manager_t::datatype_f<C>::f(), count, state);
}
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 */

View File

@ -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<false>;
#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

View File

@ -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<MemberFunctionType *>(this) = mftp;
}
// binding helper
template<typename FunctionType, typename ObjectType>
FunctionType update_after_bind(ObjectType *object)
{
return reinterpret_cast<FunctionType>(
convert_to_generic(reinterpret_cast<generic_class *>(object)));
}
template<typename FunctionType, typename MemberFunctionType, typename ObjectType>
static FunctionType get_mfp(MemberFunctionType mftp, ObjectType *object)
{
mfp mfpo(mftp);
return mfpo.update_after_bind<FunctionType>(object);
//return mfpo.update_after_bind<FunctionType>(object);
return reinterpret_cast<FunctionType>(
mfpo.convert_to_generic(reinterpret_cast<generic_class *>(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<typename R, typename... Targs>
class pmfp_base
{
public:
class generic_class;
using generic_function = R (generic_class::*)(Targs...);
pmfp_base() : m_func(nullptr) {}
template<typename MemberFunctionType, typename O>
void set_base(MemberFunctionType mftp, O *object)
{
using function_ptr = R (O::*)(Targs...);
function_ptr t = mftp;
m_func = reinterpret_cast<generic_function>(t);
}
template<typename O>
inline R call(O *obj, Targs... args) const
{
using function_ptr = R (O::*)(Targs...);
function_ptr t = reinterpret_cast<function_ptr>(m_func);
return (obj->*t)(std::forward<Targs>(args)...);
}
private:
generic_function m_func;
};
#elif ((PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV) || (PPMF_TYPE == PPMF_TYPE_INTERNAL))
template<typename R, typename... Targs>
class pmfp_base
{
public:
using generic_function = void (*)();
pmfp_base() : m_func(nullptr) {}
template<typename MemberFunctionType, typename O>
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<generic_function>(plib::mfp::get_mfp<function_ptr>(mftp, object));
#elif (PPMF_TYPE == PPMF_TYPE_GNUC_PMF_CONV)
R (O::* pFunc)(Targs...) = mftp;
m_func = reinterpret_cast<generic_function>((object->*pFunc));
#endif
}
template<typename O>
inline R call(O *obj, Targs... args) const
{
using function_ptr = MEMBER_ABI R (*)(O *obj, Targs... args);
return (*reinterpret_cast<function_ptr>(m_func))(obj, std::forward<Targs>(args)...);
}
private:
generic_function m_func;
};
#endif
template<typename R, typename... Targs>
class pmfp : public pmfp_base<R, Targs...>
{
public:
class generic_class;
pmfp() : pmfp_base<R, Targs...>(), m_obj(nullptr) {}
template<typename MemberFunctionType, typename O>
void set(MemberFunctionType mftp, O *object)
{
this->set_base(mftp, object);
m_obj = reinterpret_cast<generic_class *>(object);
}
inline R operator()(Targs... args) const
{
return this->call(m_obj, std::forward<Targs>(args)...);
}
private:
generic_class *m_obj;
};
}
#endif /* PCONFIG_H_ */

View File

@ -81,7 +81,7 @@ void pfunction::compile_postfix(const std::vector<pstring> &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;

View File

@ -371,7 +371,7 @@ void pstringbuffer::pcat(const pstring &s)
* This improves startup performance by 30%.
*/
#if 0
#if 1
static std::stack<pstr_t *> *stk = nullptr;

View File

@ -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:

View File

@ -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<void, int> atest;
plib::pmfp<int> 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);