mirror of
https://github.com/mamedev/mame.git
synced 2024-11-16 07:48:32 +01:00
Netlist:
- fixed a bug in which the fallback solver was called instead of gauss - seidel. - matrix solvers are now subdevices of the solver devices - matrix solvers can now be scheduled independently - Rename RESCHED_LOOPS to GS_LOOPS (Gauss Seidel) - Added paragmenter NR_LOOPS (Newton Raphson)
This commit is contained in:
parent
3c46c03671
commit
4b4b4542b2
8 changed files with 139 additions and 83 deletions
|
@ -14,7 +14,7 @@ NETLIST_START(msx)
|
|||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-5)
|
||||
//PARAM(Solver.CONVERG, 0.3)
|
||||
PARAM(Solver.RESCHED_LOOPS, 150)
|
||||
PARAM(Solver.GS_LOOPS, 50)
|
||||
|
||||
RES(RAY8910, 2345) // Max Voltage
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ NETLIST_START(main)
|
|||
SOLVER(Solver, 48000)
|
||||
//PARAM(Solver.ACCURACY, 1e-3)
|
||||
//PARAM(Solver.CONVERG, 1.0)
|
||||
//PARAM(Solver.RESCHED_LOOPS, 30)
|
||||
//PARAM(Solver.GS_LOOPS, 30)
|
||||
|
||||
/* Opamp wired as impedance changer */
|
||||
SUBMODEL(op, opamp)
|
||||
|
|
|
@ -89,12 +89,10 @@ static DipswitchDesc dipswitch1_desc("winning_score", "Winning Score", 0, "11",
|
|||
#endif
|
||||
|
||||
CIRCUIT_LAYOUT( pongdoubles )
|
||||
SOLVER(Solver)
|
||||
PARAM(Solver.FREQ, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-7) // works and is sufficient
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-7) // works and is sufficient
|
||||
//CHIP("CLOCK", CLOCK_14_318_MHZ)
|
||||
MAINCLOCK(CLOCK)
|
||||
PARAM(CLOCK.FREQ, 14318000.0)
|
||||
MAINCLOCK(CLOCK, 14318000.0)
|
||||
|
||||
ANALOG_INPUT(V5, 5)
|
||||
#define VCC "V5", Q
|
||||
|
|
|
@ -11,7 +11,7 @@ NETLIST_START(vccs)
|
|||
CLOCK(clk, 1000) // 1000 Hz
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-12)
|
||||
PARAM(Solver.RESCHED_LOOPS, 10000)
|
||||
PARAM(Solver.GS_LOOPS, 10000)
|
||||
|
||||
VCCS(VV)
|
||||
PARAM(VV.G, 100) // typical OP-AMP amplification
|
||||
|
|
|
@ -114,26 +114,35 @@ ATTR_HOT void netlist_matrix_solver_t::update_dynamic()
|
|||
|
||||
ATTR_HOT void netlist_matrix_solver_t::schedule()
|
||||
{
|
||||
// FIXME: Make this a parameter
|
||||
#if 0
|
||||
if (/*!m_scheduled &&*/ m_owner != NULL)
|
||||
{
|
||||
m_scheduled = true;
|
||||
this->m_owner->schedule();
|
||||
}
|
||||
if (!m_Q_sync.net().is_queued())
|
||||
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
|
||||
#else
|
||||
solve();
|
||||
update_inputs();
|
||||
|
||||
m_scheduled = false;
|
||||
if (solve())
|
||||
update_inputs();
|
||||
#endif
|
||||
}
|
||||
|
||||
ATTR_COLD void netlist_matrix_solver_t::start()
|
||||
{
|
||||
register_output("Q_sync", m_Q_sync);
|
||||
register_input("FB_sync", m_fb_sync);
|
||||
connect(m_fb_sync, m_Q_sync);
|
||||
}
|
||||
|
||||
ATTR_COLD void netlist_matrix_solver_t::reset()
|
||||
{
|
||||
m_last_step = netlist_time::zero;
|
||||
m_scheduled = true;
|
||||
}
|
||||
|
||||
ATTR_COLD void netlist_matrix_solver_t::update()
|
||||
{
|
||||
if (solve())
|
||||
update_inputs();
|
||||
}
|
||||
|
||||
|
||||
ATTR_HOT void netlist_matrix_solver_t::step(const netlist_time delta)
|
||||
{
|
||||
const double dd = delta.as_double();
|
||||
|
@ -141,7 +150,7 @@ ATTR_HOT void netlist_matrix_solver_t::step(const netlist_time delta)
|
|||
m_steps[k]->step_time(dd);
|
||||
}
|
||||
|
||||
ATTR_HOT void netlist_matrix_solver_t::solve()
|
||||
ATTR_HOT bool netlist_matrix_solver_t::solve()
|
||||
{
|
||||
|
||||
netlist_time now = owner().netlist().time();
|
||||
|
@ -159,18 +168,34 @@ ATTR_HOT void netlist_matrix_solver_t::solve()
|
|||
if (is_dynamic())
|
||||
{
|
||||
int this_resched;
|
||||
int newton_loops = 0;
|
||||
do
|
||||
{
|
||||
update_dynamic();
|
||||
while ((this_resched = solve_non_dynamic()) > m_params.m_resched_loops)
|
||||
while ((this_resched = solve_non_dynamic()) > m_params.m_gs_loops)
|
||||
owner().netlist().warning("Dynamic Solve iterations exceeded .. Consider increasing RESCHED_LOOPS");
|
||||
} while (this_resched > 1);
|
||||
newton_loops++;
|
||||
} while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
|
||||
|
||||
// reschedule ....
|
||||
if (this_resched > 1 && !m_Q_sync.net().is_queued())
|
||||
{
|
||||
#if 1
|
||||
owner().netlist().warning("NEWTON_LOOPS exceeded ... reschedule");
|
||||
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
|
||||
#else
|
||||
owner().netlist().warning("NEWTON_LOOPS exceeded ... reschedule all");
|
||||
m_owner->reschedule_all();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (solve_non_dynamic() > m_params.m_resched_loops)
|
||||
while (solve_non_dynamic() > m_params.m_gs_loops)
|
||||
owner().netlist().warning("Non-Dynamic Solve iterations exceeded .. Consider increasing RESCHED_LOOPS");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
@ -300,17 +325,25 @@ ATTR_HOT void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
|
|||
for (int i = 0; i < N(); i++) {
|
||||
#if 0
|
||||
/* Find the row with the largest first value */
|
||||
maxrow = i;
|
||||
for (j=i+1;j<n;j++) {
|
||||
if (ABS(a[i][j]) > ABS(a[i][maxrow]))
|
||||
double tmp;
|
||||
int maxrow = i;
|
||||
for (int j = i + 1; j < N(); j++)
|
||||
{
|
||||
if (fabs(A[j][i]) > fabs(A[maxrow][i]))
|
||||
maxrow = j;
|
||||
}
|
||||
|
||||
/* Swap the maxrow and ith row */
|
||||
for (k=i;k<n+1;k++) {
|
||||
tmp = a[k][i];
|
||||
a[k][i] = a[k][maxrow];
|
||||
a[k][maxrow] = tmp;
|
||||
if (maxrow != i)
|
||||
{
|
||||
/* Swap the maxrow and ith row */
|
||||
for (int k = i; k < N(); k++) {
|
||||
tmp = A[i][k];
|
||||
A[i][k] = A[maxrow][k];
|
||||
A[maxrow][k] = tmp;
|
||||
}
|
||||
tmp = RHS[i];
|
||||
RHS[i] = RHS[maxrow];
|
||||
RHS[maxrow] = tmp;
|
||||
}
|
||||
#endif
|
||||
/* Singular matrix? */
|
||||
|
@ -321,15 +354,14 @@ ATTR_HOT void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
|
|||
/* Eliminate column i from row j */
|
||||
for (int j = i + 1; j < N(); j++)
|
||||
{
|
||||
double f1 = A[j][i] * f;
|
||||
|
||||
if (f1 != 0.0)
|
||||
if (A[j][i] != 0.0)
|
||||
{
|
||||
for (int k = i; k < N(); k++)
|
||||
{
|
||||
const double f1 = A[j][i] * f;
|
||||
|
||||
for (int k = i; k < N(); k++)
|
||||
A[j][k] -= A[i][k] * f1;
|
||||
}
|
||||
RHS[j] -= RHS[i] * f1;
|
||||
|
||||
RHS[j] -= RHS[i] * f1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -559,11 +591,13 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::solve_non_dy
|
|||
else
|
||||
{
|
||||
w[k] = 1.0 / gtot_t;
|
||||
one_m_w[k] = 0.0;
|
||||
one_m_w[k] = 1.0 - 1.0;
|
||||
}
|
||||
|
||||
RHS[k] = RHS_t;
|
||||
}
|
||||
for (int k = 0; k < N(); k++)
|
||||
m_nets[k]->m_new_Analog = m_nets[k]->m_cur_Analog;
|
||||
|
||||
//NL_VERBOSE_OUT(("%f %d\n", w, m_nets.count());
|
||||
do {
|
||||
|
@ -580,27 +614,34 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::solve_non_dy
|
|||
|
||||
for (int i = 0; i < term_count; i++)
|
||||
{
|
||||
iIdr += terms[i]->m_go * terms[i]->m_otherterm->net().Q_Analog();
|
||||
iIdr += terms[i]->m_go * terms[i]->m_otherterm->net().m_new_Analog;
|
||||
//iIdr += terms[i]->m_go * terms[i]->m_otherterm->net().Q_Analog();
|
||||
}
|
||||
|
||||
//double new_val = (net->m_cur_Analog * gabs[k] + iIdr) / (gtot[k]);
|
||||
double new_val = net->m_cur_Analog * one_m_w[k] + iIdr * w[k];
|
||||
double new_val = net->m_new_Analog * one_m_w[k] + iIdr * w[k];
|
||||
|
||||
double e = (new_val - net->m_cur_Analog);
|
||||
double e = (new_val - net->m_new_Analog);
|
||||
cerr += e * e;
|
||||
|
||||
net->m_cur_Analog = net->m_new_Analog = new_val;
|
||||
net->m_new_Analog = new_val;
|
||||
}
|
||||
if (resched || cerr / m_nets.count() > m_params.m_accuracy * m_params.m_accuracy)
|
||||
if (cerr > m_params.m_accuracy * m_params.m_accuracy)
|
||||
{
|
||||
resched = true;
|
||||
//last_resched_net = net;
|
||||
}
|
||||
resched_cnt++;
|
||||
} while (resched && (resched_cnt < m_params.m_resched_loops / 3 ));
|
||||
} while (resched && (resched_cnt < m_params.m_gs_loops));
|
||||
|
||||
if (resched)
|
||||
return m_fallback.solve_non_dynamic();
|
||||
{
|
||||
//netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS");
|
||||
return m_fallback.solve_non_dynamic();
|
||||
}
|
||||
|
||||
for (int k = 0; k < N(); k++)
|
||||
m_nets[k]->m_cur_Analog = m_nets[k]->m_new_Analog;
|
||||
|
||||
return resched_cnt;
|
||||
}
|
||||
|
@ -648,29 +689,26 @@ ATTR_COLD static void process_net(net_groups_t groups, int &cur_group, netlist_n
|
|||
|
||||
NETLIB_START(solver)
|
||||
{
|
||||
register_output("Q_sync", m_Q_sync);
|
||||
register_output("Q_step", m_Q_step);
|
||||
//register_input("FB", m_feedback);
|
||||
|
||||
register_param("SYNC_DELAY", m_sync_delay, NLTIME_FROM_NS(5).as_double());
|
||||
register_param("SYNC_DELAY", m_sync_delay, NLTIME_FROM_NS(10).as_double());
|
||||
//register_param("SYNC_DELAY", m_sync_delay, NLTIME_FROM_US(10).as_double());
|
||||
m_nt_sync_delay = m_sync_delay.Value();
|
||||
|
||||
register_param("FREQ", m_freq, 48000.0);
|
||||
m_inc = netlist_time::from_hz(m_freq.Value());
|
||||
|
||||
register_param("ACCURACY", m_accuracy, 1e-7);
|
||||
register_param("CONVERG", m_convergence, 0.3);
|
||||
register_param("RESCHED_LOOPS", m_resched_loops, 35);
|
||||
register_param("GS_LOOPS", m_gs_loops, 7); // Gauss-Seidel loops
|
||||
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);
|
||||
|
||||
// internal staff
|
||||
|
||||
register_input("FB_sync", m_fb_sync);
|
||||
register_input("FB_step", m_fb_step);
|
||||
|
||||
connect(m_fb_sync, m_Q_sync);
|
||||
connect(m_fb_step, m_Q_step);
|
||||
|
||||
//save(NAME(m_last_step));
|
||||
|
@ -730,9 +768,16 @@ NETLIB_UPDATE(solver)
|
|||
for (int i = 0; i < t_cnt; i++)
|
||||
{
|
||||
if (m_mat_solvers[i]->is_timestep())
|
||||
m_mat_solvers[i]->solve();
|
||||
m_mat_solvers[i]->update_inputs();
|
||||
if (m_mat_solvers[i]->solve());
|
||||
m_mat_solvers[i]->update_inputs();
|
||||
}
|
||||
#if 0
|
||||
for (int i = 0; i < t_cnt; i++)
|
||||
{
|
||||
if (m_mat_solvers[i]->is_timestep())
|
||||
m_mat_solvers[i]->update_inputs();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* step circuit */
|
||||
|
@ -740,6 +785,13 @@ NETLIB_UPDATE(solver)
|
|||
m_Q_step.net().push_to_queue(m_inc);
|
||||
}
|
||||
|
||||
ATTR_COLD void NETLIB_NAME(solver)::reschedule_all()
|
||||
{
|
||||
for (int i = 0; i < m_mat_solvers.count(); i++)
|
||||
m_mat_solvers[i]->m_Q_sync.net().push_to_queue(m_mat_solvers[i]->m_params.m_nt_sync_delay);
|
||||
}
|
||||
|
||||
|
||||
ATTR_COLD void NETLIB_NAME(solver)::post_start()
|
||||
{
|
||||
netlist_net_t::list_t groups[100];
|
||||
|
@ -817,9 +869,16 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
|
|||
|
||||
ms->m_params.m_accuracy = m_accuracy.Value();
|
||||
ms->m_params.m_convergence_factor = m_convergence.Value();
|
||||
ms->m_params.m_resched_loops = m_resched_loops.Value();
|
||||
ms->setup(groups[i], *this);
|
||||
ms->m_params.m_gs_loops = m_gs_loops.Value();
|
||||
ms->m_params.m_nr_loops = m_nr_loops.Value();
|
||||
ms->m_params.m_nt_sync_delay = m_sync_delay.Value();
|
||||
|
||||
ms->setup(groups[i], *this);
|
||||
|
||||
register_sub(*ms, pstring::sprintf("Solver %d",m_mat_solvers.count()));
|
||||
|
||||
m_mat_solvers.add(ms);
|
||||
|
||||
SOLVER_VERBOSE_OUT(("%d ==> %d nets %s\n", i, groups[i].count(), (*groups[i].first())->m_head->name().cstr()));
|
||||
SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_dynamic() ? "dynamic" : "no dynamic"));
|
||||
SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_timestep() ? "timestep" : "no timestep"));
|
||||
|
|
|
@ -29,16 +29,18 @@ struct netlist_solver_parameters_t
|
|||
{
|
||||
double m_accuracy;
|
||||
double m_convergence_factor;
|
||||
int m_resched_loops;
|
||||
int m_gs_loops;
|
||||
int m_nr_loops;
|
||||
netlist_time m_nt_sync_delay;
|
||||
};
|
||||
|
||||
class netlist_matrix_solver_t
|
||||
class netlist_matrix_solver_t : public netlist_device_t
|
||||
{
|
||||
public:
|
||||
typedef netlist_list_t<netlist_matrix_solver_t *> list_t;
|
||||
typedef netlist_core_device_t::list_t dev_list_t;
|
||||
|
||||
netlist_matrix_solver_t() : m_scheduled(true), m_owner(NULL) {}
|
||||
netlist_matrix_solver_t() : m_owner(NULL) {}
|
||||
virtual ~netlist_matrix_solver_t() {}
|
||||
|
||||
ATTR_COLD virtual void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner);
|
||||
|
@ -47,7 +49,7 @@ public:
|
|||
ATTR_HOT virtual int solve_non_dynamic() = 0;
|
||||
ATTR_HOT virtual void step(const netlist_time delta);
|
||||
|
||||
ATTR_HOT void solve();
|
||||
ATTR_HOT bool solve();
|
||||
|
||||
ATTR_HOT void update_inputs();
|
||||
ATTR_HOT void update_dynamic();
|
||||
|
@ -58,14 +60,20 @@ public:
|
|||
ATTR_HOT inline bool is_timestep() { return m_steps.count() > 0; }
|
||||
|
||||
ATTR_HOT inline const NETLIB_NAME(solver) &owner() const;
|
||||
ATTR_COLD virtual void reset();
|
||||
|
||||
|
||||
ATTR_HOT void update();
|
||||
ATTR_COLD void start();
|
||||
ATTR_COLD virtual void reset();
|
||||
|
||||
netlist_solver_parameters_t m_params;
|
||||
|
||||
bool m_scheduled;
|
||||
netlist_ttl_output_t m_Q_sync;
|
||||
|
||||
protected:
|
||||
netlist_net_t::list_t m_nets;
|
||||
|
||||
netlist_ttl_input_t m_fb_sync;
|
||||
|
||||
netlist_net_t::list_t m_nets;
|
||||
dev_list_t m_dynamic;
|
||||
netlist_core_terminal_t::list_t m_inps;
|
||||
dev_list_t m_steps;
|
||||
|
@ -126,9 +134,10 @@ public:
|
|||
|
||||
ATTR_COLD virtual void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner)
|
||||
{
|
||||
/* FIXME: setup the fallback first, because setup sets m_solver on nets */
|
||||
m_fallback.setup(nets, owner);
|
||||
netlist_matrix_solver_t::setup(nets, owner);
|
||||
m_fallback.m_params = m_params;
|
||||
m_fallback.setup(nets, owner);
|
||||
}
|
||||
|
||||
ATTR_HOT int solve_non_dynamic();
|
||||
|
@ -162,43 +171,31 @@ private:
|
|||
NETLIB_DEVICE_WITH_PARAMS(solver,
|
||||
typedef netlist_core_device_t::list_t dev_list_t;
|
||||
|
||||
netlist_ttl_input_t m_fb_sync;
|
||||
netlist_ttl_output_t m_Q_sync;
|
||||
|
||||
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_convergence;
|
||||
netlist_param_double_t m_gmin;
|
||||
netlist_param_int_t m_resched_loops;
|
||||
netlist_param_int_t m_nr_loops;
|
||||
netlist_param_int_t m_gs_loops;
|
||||
netlist_param_int_t m_parallel;
|
||||
|
||||
netlist_time m_inc;
|
||||
netlist_time m_nt_sync_delay;
|
||||
|
||||
netlist_matrix_solver_t::list_t m_mat_solvers;
|
||||
public:
|
||||
|
||||
ATTR_COLD ~NETLIB_NAME(solver)();
|
||||
|
||||
ATTR_HOT inline void schedule();
|
||||
|
||||
ATTR_COLD void post_start();
|
||||
ATTR_COLD void reschedule_all();
|
||||
|
||||
ATTR_HOT inline double gmin() { return m_gmin.Value(); }
|
||||
);
|
||||
|
||||
ATTR_HOT inline void NETLIB_NAME(solver)::schedule()
|
||||
{
|
||||
if (!m_Q_sync.net().is_queued())
|
||||
{
|
||||
m_Q_sync.net().push_to_queue(m_nt_sync_delay);
|
||||
}
|
||||
}
|
||||
|
||||
ATTR_HOT inline const NETLIB_NAME(solver) &netlist_matrix_solver_t::owner() const
|
||||
{
|
||||
return *m_owner;
|
||||
|
|
|
@ -231,6 +231,7 @@ ATTR_COLD void netlist_base_t::reset()
|
|||
for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry))
|
||||
{
|
||||
netlist_device_t *dev = entry->object();
|
||||
//printf("step %s\n", dev->name().cstr());
|
||||
dev->update_dev();
|
||||
}
|
||||
|
||||
|
@ -487,7 +488,8 @@ ATTR_COLD netlist_net_t::netlist_net_t(const type_t atype, const family_t afamil
|
|||
|
||||
ATTR_COLD netlist_net_t::~netlist_net_t()
|
||||
{
|
||||
netlist().remove_save_items(this);
|
||||
if (isInitialized())
|
||||
netlist().remove_save_items(this);
|
||||
}
|
||||
|
||||
ATTR_HOT void netlist_net_t::inc_active(netlist_core_terminal_t &term)
|
||||
|
|
|
@ -310,7 +310,7 @@ public:
|
|||
virtual ~netlist_object_t();
|
||||
|
||||
ATTR_COLD void init_object(netlist_base_t &nl, const pstring &aname);
|
||||
ATTR_COLD bool isInitalized() { return (m_netlist != NULL); }
|
||||
ATTR_COLD bool isInitialized() { return (m_netlist != NULL); }
|
||||
|
||||
ATTR_COLD const pstring name() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue