From f4f871ada4f0f228fe520b881ca6e311f378299a Mon Sep 17 00:00:00 2001 From: Couriersud Date: Fri, 30 May 2014 16:04:08 +0000 Subject: [PATCH] Netlist changes: - Reworked the analog storage model to better support the compiler. This will most likely only pay off on larger matrices than currently used. Investment for future platforms with larger vectors - Added parameter "GS_THRESHOLD" to select the minimum matrix size for Gauss-Seidel solver - pstate: pointer will be resolved late, i.e. after all initialization is finished. State is registered during start, but some pointers are only set during post_load in the solver. --- src/emu/machine/netlist.c | 5 +- src/emu/netlist/analog/nld_solver.c | 197 +++++++++++++-------------- src/emu/netlist/analog/nld_solver.h | 49 +++++-- src/emu/netlist/analog/nld_twoterm.c | 6 +- src/emu/netlist/analog/nld_twoterm.h | 17 +-- src/emu/netlist/nl_base.c | 18 +-- src/emu/netlist/nl_base.h | 29 ++-- src/emu/netlist/pstate.c | 4 +- src/emu/netlist/pstate.h | 43 ++++-- 9 files changed, 206 insertions(+), 162 deletions(-) diff --git a/src/emu/machine/netlist.c b/src/emu/machine/netlist.c index 3365144af68..55ef624f35e 100644 --- a/src/emu/machine/netlist.c +++ b/src/emu/machine/netlist.c @@ -439,7 +439,10 @@ ATTR_COLD void netlist_mame_device_t::save_state() switch (s->m_dt) { case DT_DOUBLE: - save_pointer((double *) s->m_ptr, s->m_name, s->m_count); + { + double *td = s->resolved(); + if (td != NULL) save_pointer(td, s->m_name, s->m_count); + } break; case DT_INT64: save_pointer((INT64 *) s->m_ptr, s->m_name, s->m_count); diff --git a/src/emu/netlist/analog/nld_solver.c b/src/emu/netlist/analog/nld_solver.c index 4711ea2eb7a..db7aab7c52c 100644 --- a/src/emu/netlist/analog/nld_solver.c +++ b/src/emu/netlist/analog/nld_solver.c @@ -18,6 +18,12 @@ #define SOLVER_VERBOSE_OUT(x) do {} while (0) //#define SOLVER_VERBOSE_OUT(x) printf x +/* Commented out for now. Relatively low number of terminals / net makes + * the vectorizations this enables pretty expensive + */ + +//#pragma GCC optimize "-ffast-math" + // ---------------------------------------------------------------------------------------- // netlist_matrix_solver // ---------------------------------------------------------------------------------------- @@ -122,9 +128,8 @@ ATTR_HOT double netlist_matrix_solver_direct_t::compute_next_ti if (m_params.m_dynamic) { /* - * FIXME: this is a reduced LTE focusing on the nets which drive other nets - * The academically correct version using all nets is the one commented out - * This causes really bad performance due to rounding errors. + * FIXME: We should extend the logic to use either all nets or + * only output nets. */ #if 0 for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p)) @@ -140,7 +145,7 @@ ATTR_HOT double netlist_matrix_solver_direct_t::compute_next_ti if (fabs(DD_n) < 2.0 * m_params.m_accuracy) DD_n = 0.0; else - DD_n = DD_n / hn; + DD_n = copysign(fabs(DD_n) - 2.0 * m_params.m_accuracy, DD_n) / hn; double h_n_m_1 = n->m_h_n_m_1; // limit last timestep in equation. @@ -361,47 +366,12 @@ ATTR_COLD void netlist_matrix_solver_direct_t::vsetup(netlist_a netlist_matrix_solver_t::setup(nets); -#if 0 - for (int k = 0; k < N(); k++) - { - const netlist_terminal_t::list_t &terms = m_nets[k].m_terms; - for (int i = 0; i < terms.count(); i++) - { - int ot = get_net_idx(&terms[i]->m_otherterm->net()); - if (ot>=0) - { - m_terms[k].add(terms_t(terms[i], ot)); - SOLVER_VERBOSE_OUT(("Net %d Term %s %f %f\n", k, terms[i]->name().cstr(), terms[i]->m_gt, terms[i]->m_go)); - } - } - } - - /* Should this be allowed ? */ - for (int k = 0; k < N(); k++) - { - const netlist_terminal_t::list_t &terms = m_nets[k].m_terms; - for (int i = 0; i < terms.count(); i++) - { - int ot = get_net_idx(&terms[i]->m_otherterm->net()); - if (ot<0) - { - m_rails[k].add(terms_t(terms[i], ot)); - netlist().warning("found term with missing othernet %s\n", terms[i]->name().cstr()); - } - } + for (int k = 0; k < N(); k++) + { + m_terms[k].set_pointers(); + m_rails[k].set_pointers(); } - - for (int k = 0; k < N(); k++) - { - const netlist_terminal_t::list_t &rails = m_nets[k].m_rails; - for (int i = 0; i < rails.count(); i++) - { - m_rails[k].add(terms_t(rails[i], -1)); - SOLVER_VERBOSE_OUT(("Net %d Rail %s %f %f\n", k, rails[i]->name().cstr(), rails[i]->m_gt, rails[i]->m_go)); - } - } -#endif } template @@ -415,26 +385,36 @@ ATTR_HOT void netlist_matrix_solver_direct_t::build_LE() { double rhsk = 0.0; double akk = 0.0; - const int terms_count = m_terms[k].count(); - const netlist_terminal_t * const *terms = m_terms[k].terms(); - const int *net_other = m_terms[k].net_other(); - - for (int i = 0; i < terms_count; i++) - { - //printf("A %d %d %s %f %f\n",t.net_this, t.net_other, t.term->name().cstr(), t.term->m_gt, t.term->m_go); - - rhsk = rhsk + terms[i]->m_Idr; - akk = akk + terms[i]->m_gt; - m_A[k][net_other[i]] += -terms[i]->m_go; - } - - const int rails_count = m_rails[k].count(); - const netlist_terminal_t * const *rails = m_rails[k].terms(); - - for (int i = 0; i < rails_count; i++) { - rhsk = rhsk + rails[i]->m_Idr + rails[i]->m_go * rails[i]->m_otherterm->net().as_analog().Q_Analog(); - akk = akk + rails[i]->m_gt; + const int terms_count = m_terms[k].count(); + //const netlist_terminal_t * const *terms = m_terms[k].terms(); + const int *net_other = m_terms[k].net_other(); + const double *gt = m_terms[k].gt(); + const double *go = m_terms[k].go(); + const double *Idr = m_terms[k].Idr(); + + for (int i = 0; i < terms_count; i++) + { + //printf("A %d %d %s %f %f\n",t.net_this, t.net_other, t.term->name().cstr(), t.term->m_gt, t.term->m_go); + + rhsk = rhsk + Idr[i]; + akk = akk + gt[i]; + m_A[k][net_other[i]] += -go[i]; + } + } + { + const int rails_count = m_rails[k].count(); + const netlist_terminal_t * const *rails = m_rails[k].terms(); + const double *gt = m_rails[k].gt(); + const double *go = m_rails[k].go(); + const double *Idr = m_rails[k].Idr(); + + for (int i = 0; i < rails_count; i++) + { + rhsk = rhsk + Idr[i]; + akk = akk + gt[i]; + rhsk = rhsk + go[i] * rails[i]->m_otherterm->net().as_analog().Q_Analog(); + } } m_RHS[k] = rhsk; m_A[k][k] += akk; @@ -479,20 +459,17 @@ ATTR_HOT void netlist_matrix_solver_direct_t::gauss_LE( } } - /* Singular matrix? */ - double f = m_A[i][i]; - //if (fabs(f) < 1e-20) printf("Singular!"); - f = 1.0 / f; + /* FIXME: Singular matrix? */ + const double f = 1.0 / m_A[i][i]; /* Eliminate column i from row j */ for (int j = i + 1; j < kN; j++) { - //__builtin_prefetch(&A[j+1][i], 1); const double f1 = m_A[j][i] * f; if (f1 != 0.0) { - for (int k = i; k < kN; k++) + for (int k = i + 1; k < kN; k++) m_A[j][k] -= m_A[i][k] * f1; m_RHS[j] -= m_RHS[i] * f1; } @@ -501,7 +478,7 @@ ATTR_HOT void netlist_matrix_solver_direct_t::gauss_LE( /* back substitution */ for (int j = kN - 1; j >= 0; j--) { - //__builtin_prefetch(&A[j-1][j], 0); + //__builtin_prefetch(&m_A[j-1][j], 0); double tmp = 0; for (int k = j + 1; k < kN; k++) tmp += m_A[j][k] * x[k]; @@ -650,6 +627,24 @@ ATTR_HOT int netlist_matrix_solver_direct2_t::vsolve_non_dynamic() // netlist_matrix_solver - Gauss - Seidel // ---------------------------------------------------------------------------------------- +template +static inline const double sum(const double *v) +{ + double tmp = 0.0; + for (int i=0; i < _N; i++) + tmp += v[i]; + return tmp; +} + +template +static inline const double sumabs(const double *v) +{ + double tmp = 0.0; + for (int i=0; i < _N; i++) + tmp += fabs(v[i]); + return tmp; +} + template ATTR_HOT int netlist_matrix_solver_gauss_seidel_t::vsolve_non_dynamic() { @@ -659,7 +654,7 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t::vsolve_non_d */ #if 0 - double new_v[_storage_N] = { 0.0 }; + ATTR_ALIGN double new_v[_storage_N] = { 0.0 }; const int iN = this->N(); bool resched = false; @@ -680,7 +675,7 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t::vsolve_non_d { double Idrive = 0; - // loop auto-vectorized + // Reduction loops need -ffast-math for (int i = 0; i < iN; i++) Idrive -= this->m_A[k][i] * new_v[i]; @@ -726,10 +721,10 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t::vsolve_non_d //const double w = 1.0; //2.0 / (1.0 + sin(3.14159 / (m_nets.count()+1))); //const double w1 = 1.0 - w; - double w[_storage_N]; - double one_m_w[_storage_N]; - double RHS[_storage_N]; - double new_V[_storage_N]; + ATTR_ALIGN double w[_storage_N]; + ATTR_ALIGN double one_m_w[_storage_N]; + ATTR_ALIGN double RHS[_storage_N]; + ATTR_ALIGN double new_V[_storage_N]; for (int k = 0; k < iN; k++) { @@ -746,27 +741,30 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t::vsolve_non_d const netlist_terminal_t * const * rails = this->m_rails[k].terms(); //const int * othernet = this->m_rails[k].m_othernet; const int rail_count = this->m_rails[k].count(); + const double *gt = this->m_rails[k].gt(); + const double *go = this->m_rails[k].go(); + const double *Idr = this->m_rails[k].Idr(); - for (int i = 0; i < rail_count; i++) - { - const netlist_terminal_t *rail = rails[i]; - gtot_t += rail->m_gt; - gabs_t += fabs(rail->m_go); - RHS_t += rail->m_Idr; - // this may point to a rail net ... - RHS_t += rail->m_go * rail->m_otherterm->net().as_analog().Q_Analog(); - } + for (int i = 0; i < rail_count; i++) + { + RHS_t += go[i] * rails[i]->m_otherterm->net().as_analog().Q_Analog(); + gtot_t += gt[i]; + gabs_t += fabs(go[i]); + RHS_t += Idr[i]; + // this may point to a rail net ... + } } { - const netlist_terminal_t * const * terms = this->m_terms[k].terms(); const int term_count = this->m_terms[k].count(); + const double *gt = this->m_terms[k].gt(); + const double *go = this->m_terms[k].go(); + const double *Idr = this->m_terms[k].Idr(); for (int i = 0; i < term_count; i++) { - const netlist_terminal_t *term = terms[i]; - gtot_t += term->m_gt; - gabs_t += fabs(term->m_go); - RHS_t += term->m_Idr; + gtot_t += gt[i]; + gabs_t += fabs(go[i]); + RHS_t += Idr[i]; } } gabs_t *= 1.0; @@ -791,15 +789,15 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t::vsolve_non_d for (int k = 0; k < iN; k++) { - //netlist_analog_net_t & RESTRICT net = *this->m_nets[k]; - const netlist_terminal_t * const * terms = this->m_terms[k].terms(); const int * net_other = this->m_terms[k].net_other(); const int term_count = this->m_terms[k].count(); + const double *go = this->m_terms[k].go(); + // -msse2 -msse3 -msse4.1 -msse4.2 -mfpmath=sse -ftree-vectorizer-verbose=3 -fprefetch-loop-arrays -ffast-math double Idrive = 0; for (int i = 0; i < term_count; i++) - Idrive += terms[i]->m_go * new_V[net_other[i]]; + Idrive = Idrive + go[i] * new_V[net_other[i]]; //double new_val = (net->m_cur_Analog * gabs[k] + iIdr) / (gtot[k]); const double new_val = new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k]; @@ -856,14 +854,15 @@ NETLIB_START(solver) register_param("FREQ", m_freq, 48000.0); - register_param("ACCURACY", m_accuracy, 1e-4); - register_param("GS_LOOPS", m_gs_loops, 5); // Gauss-Seidel loops + register_param("ACCURACY", m_accuracy, 1e-7); + register_param("GS_LOOPS", m_gs_loops, 9); // Gauss-Seidel loops + register_param("GS_THRESHOLD", m_gs_threshold, 5); // below this value, gaussian elimination is used register_param("NR_LOOPS", m_nr_loops, 25); // Newton-Raphson loops register_param("PARALLEL", m_parallel, 0); register_param("GMIN", m_gmin, NETLIST_GMIN_DEFAULT); register_param("DYNAMIC_TS", m_dynamic, 0); - register_param("LTE", m_lte, 1e-2); // 100mV diff/timestep - register_param("MIN_TIMESTEP", m_min_timestep, 2e-9); // double timestep resolution + register_param("LTE", m_lte, 5e-5); // diff/timestep + register_param("MIN_TIMESTEP", m_min_timestep, 1e-6); // double timestep resolution // internal staff @@ -927,12 +926,11 @@ NETLIB_UPDATE(solver) this_resched[i] = m_mat_solvers[i]->solve(); } #else - // FIXME: parameter for (int i = 0; i < t_cnt; i++) { if (m_mat_solvers[i]->is_timestep()) { - // Ignore return value + // Ignore return value ATTR_UNUSED const double ts = m_mat_solvers[i]->solve(); } } @@ -965,8 +963,7 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start() { netlist_analog_net_t::list_t groups[100]; int cur_group = -1; - // FIXME: Turn into parameters ... - const int gs_threshold = 5; + const int gs_threshold = m_gs_threshold.Value(); const bool use_specific = true; m_params.m_accuracy = m_accuracy.Value(); diff --git a/src/emu/netlist/analog/nld_solver.h b/src/emu/netlist/analog/nld_solver.h index b7327fcdced..28f067431f1 100644 --- a/src/emu/netlist/analog/nld_solver.h +++ b/src/emu/netlist/analog/nld_solver.h @@ -79,22 +79,42 @@ protected: { m_term.clear(); m_net_other.clear(); + m_gt.clear(); } void add(netlist_terminal_t *term, int net_other) { m_term.add(term); m_net_other.add(net_other); + m_gt.add(0.0); + m_go.add(0.0); + m_Idr.add(0.0); } inline int count() { return m_term.count(); } inline netlist_terminal_t **terms() { return m_term; } inline int *net_other() { return m_net_other; } + inline double *gt() { return m_gt; } + inline double *go() { return m_go; } + inline double *Idr() { return m_Idr; } + + void set_pointers() + { + for (int i = 0; i < count(); i++) + { + m_term[i]->m_gt1 = &m_gt[i]; + m_term[i]->m_go1 = &m_go[i]; + m_term[i]->m_Idr1 = &m_Idr[i]; + } + } private: plinearlist_t m_term; plinearlist_t m_net_other; + plinearlist_t m_gt; + plinearlist_t m_go; + plinearlist_t m_Idr; }; @@ -230,24 +250,23 @@ protected: ATTR_HOT void reset(); ATTR_HOT void update_param(); - //typedef netlist_core_device_t::list_t dev_list_t; + netlist_ttl_input_t m_fb_step; + netlist_ttl_output_t m_Q_step; - netlist_ttl_input_t m_fb_step; - netlist_ttl_output_t m_Q_step; + netlist_param_double_t m_freq; + netlist_param_double_t m_sync_delay; + netlist_param_double_t m_accuracy; + netlist_param_double_t m_gmin; + netlist_param_double_t m_lte; + netlist_param_logic_t m_dynamic; + netlist_param_double_t m_min_timestep; - netlist_param_double_t m_freq; - netlist_param_double_t m_sync_delay; - netlist_param_double_t m_accuracy; - netlist_param_double_t m_gmin; - netlist_param_double_t m_lte; - netlist_param_logic_t m_dynamic; - netlist_param_double_t m_min_timestep; + netlist_param_int_t m_nr_loops; + netlist_param_int_t m_gs_loops; + netlist_param_int_t m_gs_threshold; + netlist_param_int_t m_parallel; - netlist_param_int_t m_nr_loops; - netlist_param_int_t m_gs_loops; - netlist_param_int_t m_parallel; - - netlist_matrix_solver_t::list_t m_mat_solvers; + netlist_matrix_solver_t::list_t m_mat_solvers; private: netlist_solver_parameters_t m_params; diff --git a/src/emu/netlist/analog/nld_twoterm.c b/src/emu/netlist/analog/nld_twoterm.c index 02ea0ca7424..4b3652fce0b 100644 --- a/src/emu/netlist/analog/nld_twoterm.c +++ b/src/emu/netlist/analog/nld_twoterm.c @@ -39,8 +39,8 @@ ATTR_COLD void netlist_generic_diode::save(pstring name, netlist_object_t &paren // nld_twoterm // ---------------------------------------------------------------------------------------- -ATTR_COLD NETLIB_NAME(twoterm)::NETLIB_NAME(twoterm)(const family_t afamily) : - netlist_device_t(afamily) +ATTR_COLD NETLIB_NAME(twoterm)::NETLIB_NAME(twoterm)(const family_t afamily) + : netlist_device_t(afamily) { m_P.m_otherterm = &m_N; m_N.m_otherterm = &m_P; @@ -177,7 +177,7 @@ NETLIB_START(C) register_param("C", m_C, 1e-6); // set up the element - set(netlist().gmin(), 0.0, -5.0 / netlist().gmin()); + //set(netlist().gmin(), 0.0, -5.0 / netlist().gmin()); //set(1.0/NETLIST_GMIN, 0.0, -5.0 * NETLIST_GMIN); } diff --git a/src/emu/netlist/analog/nld_twoterm.h b/src/emu/netlist/analog/nld_twoterm.h index 48000bfa84e..1454d41b0bb 100644 --- a/src/emu/netlist/analog/nld_twoterm.h +++ b/src/emu/netlist/analog/nld_twoterm.h @@ -98,9 +98,9 @@ public: ATTR_HOT inline void set(const double G, const double V, const double I) { - m_P.m_go = m_N.m_go = m_P.m_gt = m_N.m_gt = G; - m_N.m_Idr = ( -V) * G + I; - m_P.m_Idr = ( V) * G - I; + /* GO, GT, I */ + m_P.set( G, G, ( V) * G - I); + m_N.set( G, G, ( -V) * G + I); } ATTR_HOT inline double deltaV() @@ -110,14 +110,9 @@ public: ATTR_HOT void set_mat(double a11, double a12, double a21, double a22, double r1, double r2) { - m_P.m_gt = a11; - m_P.m_go = -a12; - m_N.m_gt = a22; - m_N.m_go = -a21; - - m_P.m_Idr = -r1; - m_N.m_Idr = -r2; - + /* GO, GT, I */ + m_P.set(-a12, a11, -r1); + m_N.set(-a21, a22, -r2); } protected: diff --git a/src/emu/netlist/nl_base.c b/src/emu/netlist/nl_base.c index e3e3e2b46a0..537c3207ffd 100644 --- a/src/emu/netlist/nl_base.c +++ b/src/emu/netlist/nl_base.c @@ -767,9 +767,9 @@ ATTR_COLD netlist_core_terminal_t::netlist_core_terminal_t(const type_t atype, c ATTR_COLD netlist_terminal_t::netlist_terminal_t() : netlist_core_terminal_t(TERMINAL, ANALOG) -, m_Idr(0.0) -, m_go(NETLIST_GMIN_DEFAULT) -, m_gt(NETLIST_GMIN_DEFAULT) +, m_Idr1(NULL) +, m_go1(NULL) +, m_gt1(NULL) , m_otherterm(NULL) { } @@ -779,16 +779,16 @@ ATTR_COLD void netlist_terminal_t::reset() { //netlist_terminal_core_terminal_t::reset(); set_state(STATE_INP_ACTIVE); - m_Idr = 0.0; - m_go = netlist().gmin(); - m_gt = netlist().gmin(); + set_ptr(m_Idr1, 0.0); + set_ptr(m_go1, netlist().gmin()); + set_ptr(m_gt1, netlist().gmin()); } ATTR_COLD void netlist_terminal_t::save_register() { - save(NAME(m_Idr)); - save(NAME(m_go)); - save(NAME(m_gt)); + save(NAME(m_Idr1)); + save(NAME(m_go1)); + save(NAME(m_gt1)); netlist_core_terminal_t::save_register(); } diff --git a/src/emu/netlist/nl_base.h b/src/emu/netlist/nl_base.h index f74b38efb3e..e328189cbb8 100644 --- a/src/emu/netlist/nl_base.h +++ b/src/emu/netlist/nl_base.h @@ -433,28 +433,29 @@ public: ATTR_COLD netlist_terminal_t(); - double m_Idr; // drive current - double m_go; // conductance for Voltage from other term - double m_gt; // conductance for total conductance + double *m_Idr1; // drive current + double *m_go1; // conductance for Voltage from other term + double *m_gt1; // conductance for total conductance ATTR_HOT inline void set(const double G) { - m_Idr = 0; - m_go = m_gt = G; + set_ptr(m_Idr1, 0); + set_ptr(m_go1, G); + set_ptr(m_gt1, G); } ATTR_HOT inline void set(const double GO, const double GT) { - m_Idr = 0; - m_go = GO; - m_gt = GT; + set_ptr(m_Idr1, 0); + set_ptr(m_go1, GO); + set_ptr(m_gt1, GT); } ATTR_HOT inline void set(const double GO, const double GT, const double I) { - m_Idr = I; - m_go = GO; - m_gt = GT; + set_ptr(m_Idr1, I); + set_ptr(m_go1, GO); + set_ptr(m_gt1, GT); } @@ -464,6 +465,12 @@ protected: ATTR_COLD virtual void save_register(); ATTR_COLD virtual void reset(); +private: + inline void set_ptr(double *ptr, const double val) + { + if (ptr != NULL) + *ptr = val; + } }; diff --git a/src/emu/netlist/pstate.c b/src/emu/netlist/pstate.c index 5b07692e460..6dfa6c62527 100644 --- a/src/emu/netlist/pstate.c +++ b/src/emu/netlist/pstate.c @@ -12,7 +12,7 @@ ATTR_COLD pstate_manager_t::~pstate_manager_t() -ATTR_COLD void pstate_manager_t::save_state_ptr(const pstring &stname, const pstate_data_type_e dt, const void *owner, const int size, const int count, void *ptr) +ATTR_COLD void pstate_manager_t::save_state_ptr(const pstring &stname, const pstate_data_type_e dt, const void *owner, const int size, const int count, void *ptr, bool is_ptr) { pstring fullname = stname; ATTR_UNUSED pstring ts[] = { @@ -27,7 +27,7 @@ ATTR_COLD void pstate_manager_t::save_state_ptr(const pstring &stname, const pst }; NL_VERBOSE_OUT(("SAVE: <%s> %s(%d) %p\n", fullname.cstr(), ts[dt].cstr(), size, ptr)); - pstate_entry_t *p = new pstate_entry_t(stname, dt, owner, size, count, ptr); + pstate_entry_t *p = new pstate_entry_t(stname, dt, owner, size, count, ptr, is_ptr); m_save.add(p); } diff --git a/src/emu/netlist/pstate.h b/src/emu/netlist/pstate.h index 78fd0395022..e959e98e1d2 100644 --- a/src/emu/netlist/pstate.h +++ b/src/emu/netlist/pstate.h @@ -35,10 +35,23 @@ enum pstate_data_type_e { DT_BOOLEAN }; -template struct nl_datatype { static const pstate_data_type_e type = pstate_data_type_e(NOT_SUPPORTED); }; +template struct nl_datatype +{ + static const pstate_data_type_e type = pstate_data_type_e(NOT_SUPPORTED); + static const bool is_ptr = false; +}; + +template struct nl_datatype<_ItemType *> +{ + static const pstate_data_type_e type = pstate_data_type_e(NOT_SUPPORTED); + static const bool is_ptr = true; +}; + //template struct type_checker<_ItemType*> { static const bool is_atom = false; static const bool is_pointer = true; }; -#define NETLIST_SAVE_TYPE(TYPE, TYPEDESC) template<> struct nl_datatype{ static const pstate_data_type_e type = pstate_data_type_e(TYPEDESC); } +#define NETLIST_SAVE_TYPE(TYPE, TYPEDESC) \ + template<> struct nl_datatype{ static const pstate_data_type_e type = pstate_data_type_e(TYPEDESC); static const bool is_ptr = false;}; \ + template<> struct nl_datatype{ static const pstate_data_type_e type = pstate_data_type_e(TYPEDESC); static const bool is_ptr = true;}; NETLIST_SAVE_TYPE(char, DT_INT8); NETLIST_SAVE_TYPE(double, DT_DOUBLE); @@ -73,11 +86,11 @@ struct pstate_entry_t typedef plinearlist_t list_t; pstate_entry_t(const pstring &stname, const pstate_data_type_e dt, const void *owner, - const int size, const int count, void *ptr) - : m_name(stname), m_dt(dt), m_owner(owner), m_callback(NULL), m_size(size), m_count(count), m_ptr(ptr) { } + const int size, const int count, void *ptr, bool is_ptr) + : m_name(stname), m_dt(dt), m_owner(owner), m_callback(NULL), m_size(size), m_count(count), m_ptr(ptr), m_is_ptr(is_ptr) { } pstate_entry_t(const pstring &stname, const void *owner, pstate_callback_t *callback) - : m_name(stname), m_dt(DT_CUSTOM), m_owner(owner), m_callback(callback), m_size(0), m_count(0), m_ptr(NULL) { } + : m_name(stname), m_dt(DT_CUSTOM), m_owner(owner), m_callback(callback), m_size(0), m_count(0), m_ptr(NULL), m_is_ptr(false) { } pstring m_name; const pstate_data_type_e m_dt; @@ -86,6 +99,16 @@ struct pstate_entry_t const int m_size; const int m_count; void *m_ptr; + bool m_is_ptr; + + template + T *resolved() + { + if (m_is_ptr) + return *static_cast(m_ptr); + else + return static_cast(m_ptr); + } }; class pstate_manager_t @@ -96,17 +119,17 @@ public: template ATTR_COLD void save_item(C &state, const void *owner, const pstring &stname) { - save_state_ptr(stname, nl_datatype::type, owner, sizeof(C), 1, &state); + save_state_ptr(stname, nl_datatype::type, owner, sizeof(C), 1, &state, nl_datatype::is_ptr); } template ATTR_COLD void save_item(C (&state)[N], const void *owner, const pstring &stname) { - save_state_ptr(stname, nl_datatype::type, owner, sizeof(state[0]), N, &(state[0])); + save_state_ptr(stname, nl_datatype::type, owner, sizeof(state[0]), N, &(state[0]), false); } template ATTR_COLD void save_item(C *state, const void *owner, const pstring &stname, const int count) { - save_state_ptr(stname, nl_datatype::type, owner, sizeof(C), count, state); + save_state_ptr(stname, nl_datatype::type, owner, sizeof(C), count, state, false); } ATTR_COLD void pre_save(); @@ -116,7 +139,7 @@ public: inline const pstate_entry_t::list_t &save_list() const { return m_save; } protected: - ATTR_COLD void save_state_ptr(const pstring &stname, const pstate_data_type_e, const void *owner, const int size, const int count, void *ptr); + ATTR_COLD void save_state_ptr(const pstring &stname, const pstate_data_type_e, const void *owner, const int size, const int count, void *ptr, bool is_ptr); private: pstate_entry_t::list_t m_save; @@ -132,7 +155,7 @@ template<> ATTR_COLD inline void pstate_manager_t::save_item(pstate_callback_t & template<> ATTR_COLD inline void pstate_manager_t::save_item(netlist_time &nlt, const void *owner, const pstring &stname) { - save_state_ptr(stname, DT_INT64, owner, sizeof(netlist_time::INTERNALTYPE), 1, nlt.get_internaltype_ptr()); + save_state_ptr(stname, DT_INT64, owner, sizeof(netlist_time::INTERNALTYPE), 1, nlt.get_internaltype_ptr(), false); }