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.
This commit is contained in:
Couriersud 2014-05-30 16:04:08 +00:00
parent ac79d15878
commit f4f871ada4
9 changed files with 206 additions and 162 deletions

View File

@ -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<double>();
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);

View File

@ -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<m_N, _storage_N>::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<m_N, _storage_N>::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<m_N, _storage_N>::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 <int m_N, int _storage_N>
@ -415,26 +385,36 @@ ATTR_HOT void netlist_matrix_solver_direct_t<m_N, _storage_N>::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<m_N, _storage_N>::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<m_N, _storage_N>::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<int _N>
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<int _N>
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 <int m_N, int _storage_N>
ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::vsolve_non_dynamic()
{
@ -659,7 +654,7 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::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<m_N, _storage_N>::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<m_N, _storage_N>::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<m_N, _storage_N>::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<m_N, _storage_N>::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();

View File

@ -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<netlist_terminal_t *> m_term;
plinearlist_t<int> m_net_other;
plinearlist_t<double> m_gt;
plinearlist_t<double> m_go;
plinearlist_t<double> 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;

View File

@ -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);
}

View File

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

View File

@ -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();
}

View File

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

View File

@ -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);
}

View File

@ -35,10 +35,23 @@ enum pstate_data_type_e {
DT_BOOLEAN
};
template<typename _ItemType> struct nl_datatype { static const pstate_data_type_e type = pstate_data_type_e(NOT_SUPPORTED); };
template<typename _ItemType> struct nl_datatype
{
static const pstate_data_type_e type = pstate_data_type_e(NOT_SUPPORTED);
static const bool is_ptr = false;
};
template<typename _ItemType> struct nl_datatype<_ItemType *>
{
static const pstate_data_type_e type = pstate_data_type_e(NOT_SUPPORTED);
static const bool is_ptr = true;
};
//template<typename _ItemType> 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<TYPE>{ static const pstate_data_type_e type = pstate_data_type_e(TYPEDESC); }
#define NETLIST_SAVE_TYPE(TYPE, TYPEDESC) \
template<> struct nl_datatype<TYPE>{ static const pstate_data_type_e type = pstate_data_type_e(TYPEDESC); static const bool is_ptr = false;}; \
template<> struct nl_datatype<TYPE *>{ 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<pstate_entry_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<typename T>
T *resolved()
{
if (m_is_ptr)
return *static_cast<T **>(m_ptr);
else
return static_cast<T *>(m_ptr);
}
};
class pstate_manager_t
@ -96,17 +119,17 @@ public:
template<typename C> ATTR_COLD void save_item(C &state, const void *owner, const pstring &stname)
{
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(C), 1, &state);
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(C), 1, &state, nl_datatype<C>::is_ptr);
}
template<typename C, std::size_t N> ATTR_COLD void save_item(C (&state)[N], const void *owner, const pstring &stname)
{
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(state[0]), N, &(state[0]));
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(state[0]), N, &(state[0]), false);
}
template<typename C> ATTR_COLD void save_item(C *state, const void *owner, const pstring &stname, const int count)
{
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(C), count, state);
save_state_ptr(stname, nl_datatype<C>::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);
}