Implemented an improved solving scheme into netlist. This improves performance for pong. However, it revealed issues around resetting netlist. "Reset(F3)" does not work properly now.

Also set pong frequency to NETLIST_CLOCK. This is necessary to avoid issues with time conversion into attotime and consequently rounding issues in fixfreq.
This commit is contained in:
Couriersud 2014-01-11 16:20:25 +00:00
parent f28670c9e0
commit 9a3fd8d1fd
15 changed files with 156 additions and 70 deletions

View File

@ -69,41 +69,42 @@ NETLIB_START(QBJT_switch)
m_state_on = 0;
{
double IS = m_model.model_value("IS", 1e-15);
double BF = m_model.model_value("BF", 100);
double NF = m_model.model_value("NF", 1);
//double VJE = m_model.dValue("VJE", 0.75);
set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
double alpha = BF / (1.0 + BF);
diode d(IS, NF);
// Assume 5mA Collector current for switch operation
m_V = d.V(0.005 / alpha);
/* Base current is 0.005 / beta
* as a rough estimate, we just scale the conductance down */
m_gB = d.gI(0.005 / alpha) / BF;
if (m_gB < NETLIST_GMIN)
m_gB = NETLIST_GMIN;
m_gC = BF * m_gB; // very rough estimate
//printf("%f %f \n", m_V, m_gB);
}
}
NETLIB_UPDATE(Q)
{
netlist().solver()->schedule();
netlist().solver()->schedule1();
}
NETLIB_UPDATE_PARAM(QBJT_switch)
{
double IS = m_model.model_value("IS", 1e-15);
double BF = m_model.model_value("BF", 100);
double NF = m_model.model_value("NF", 1);
//double VJE = m_model.dValue("VJE", 0.75);
set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
double alpha = BF / (1.0 + BF);
diode d(IS, NF);
// Assume 5mA Collector current for switch operation
m_V = d.V(0.005 / alpha);
/* Base current is 0.005 / beta
* as a rough estimate, we just scale the conductance down */
m_gB = d.gI(0.005 / alpha) / BF;
if (m_gB < NETLIST_GMIN)
m_gB = NETLIST_GMIN;
m_gC = BF * m_gB; // very rough estimate
//printf("%f %f \n", m_V, m_gB);
m_RB.set(NETLIST_GMIN, 0.0, 0.0);
m_RC.set(NETLIST_GMIN, 0.0, 0.0);
}
// ----------------------------------------------------------------------------------------
@ -136,25 +137,37 @@ NETLIB_START(QBJT_EB)
m_gD_BE.save("m_D_BE", *this);
m_gD_BC.save("m_D_BC", *this);
{
double IS = m_model.model_value("IS", 1e-15);
double BF = m_model.model_value("BF", 100);
double NF = m_model.model_value("NF", 1);
double BR = m_model.model_value("BR", 1);
double NR = m_model.model_value("NR", 1);
//double VJE = m_model.dValue("VJE", 0.75);
set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
m_alpha_f = BF / (1.0 + BF);
m_alpha_r = BR / (1.0 + BR);
m_gD_BE.set_param(IS / m_alpha_f, NF);
m_gD_BC.set_param(IS / m_alpha_r, NR);
}
}
NETLIB_UPDATE(QBJT_EB)
{
#if !(USE_ALTERNATE_SCHEDULING)
netlist().solver()->schedule1();
#else
m_D_BE.m_P.net().solve();
m_D_BE.m_N.net().solve();
m_D_BC.m_P.net().solve();
#endif
}
NETLIB_UPDATE_PARAM(QBJT_EB)
{
double IS = m_model.model_value("IS", 1e-15);
double BF = m_model.model_value("BF", 100);
double NF = m_model.model_value("NF", 1);
double BR = m_model.model_value("BR", 1);
double NR = m_model.model_value("NR", 1);
//double VJE = m_model.dValue("VJE", 0.75);
set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
m_alpha_f = BF / (1.0 + BF);
m_alpha_r = BR / (1.0 + BR);
m_gD_BE.set_param(IS / m_alpha_f, NF);
m_gD_BC.set_param(IS / m_alpha_r, NR);
}

View File

@ -169,6 +169,7 @@ protected:
ATTR_COLD virtual void start();
ATTR_HOT void update_param();
ATTR_HOT ATTR_ALIGN void virtual update();
netlist_generic_diode m_gD_BC;
netlist_generic_diode m_gD_BE;

View File

@ -55,7 +55,14 @@ NETLIB_UPDATE_PARAM(VCCS)
NETLIB_UPDATE(VCCS)
{
/* only called if connected to a rail net ==> notify the solver to recalculate */
netlist().solver()->schedule();
#if !(USE_ALTERNATE_SCHEDULING)
netlist().solver()->schedule1();
#else
m_IP.net().solve();
m_IN.net().solve();
m_OP.net().solve();
m_ON.net().solve();
#endif
}
// ----------------------------------------------------------------------------------------

View File

@ -186,6 +186,23 @@ ATTR_HOT inline bool netlist_matrix_solver_t::solve()
return m_resched;
}
ATTR_HOT void netlist_matrix_solver_t::schedule()
{
if (!solve())
{
// printf("update_inputs\n");
update_inputs();
}
else
{
//printf("resched\n");
if (m_owner != NULL) this->m_owner->schedule1();
}
//solve();
// update_inputs();
}
// ----------------------------------------------------------------------------------------
// solver
// ----------------------------------------------------------------------------------------
@ -275,6 +292,9 @@ NETLIB_UPDATE(solver)
{
netlist_time now = netlist().time();
netlist_time delta = now - m_last_step;
bool do_full = (USE_ALTERNATE_SCHEDULING ? false : true);
bool global_resched = false;
bool this_resched[100];
if (delta >= m_inc)
{
@ -285,9 +305,9 @@ NETLIB_UPDATE(solver)
{
(*e)->step(delta);
}
}
bool global_resched = false;
bool this_resched[100];
} else
do_full = true; // we have been called inbetween updates
#if HAS_OPENMP && USE_OPENMP
int t_cnt = m_mat_solvers.count();
@ -305,19 +325,24 @@ NETLIB_UPDATE(solver)
#else
for (int i = 0; i < m_mat_solvers.count(); i++)
{
this_resched[i] = m_mat_solvers[i]->solve();
if (do_full || (m_mat_solvers[i]->is_timestep()))
this_resched[i] = m_mat_solvers[i]->solve();
}
#endif
for (int i = 0; i < m_mat_solvers.count(); i++)
{
if (do_full || m_mat_solvers[i]->is_timestep())
{
global_resched = global_resched || this_resched[i];
if (!this_resched[i])
m_mat_solvers[i]->update_inputs();
}
}
if (global_resched)
{
schedule();
schedule1();
}
else
{

View File

@ -30,7 +30,7 @@ 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_resched(false) {}
netlist_matrix_solver_t() : m_resched(false), m_owner(NULL) {}
ATTR_COLD void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner);
@ -40,6 +40,8 @@ public:
ATTR_HOT void step(const netlist_time delta);
ATTR_HOT void update_inputs();
ATTR_HOT void schedule();
ATTR_HOT inline bool is_dynamic() { return m_dynamic.count() > 0; }
ATTR_HOT inline bool is_timestep() { return m_steps.count() > 0; }
@ -83,7 +85,7 @@ public:
ATTR_COLD ~NETLIB_NAME(solver)();
ATTR_HOT inline void schedule();
ATTR_HOT inline void schedule1();
ATTR_COLD void post_start();
ATTR_COLD void reset()
@ -92,7 +94,7 @@ public:
}
);
ATTR_HOT inline void NETLIB_NAME(solver)::schedule()
ATTR_HOT inline void NETLIB_NAME(solver)::schedule1()
{
if (!m_Q_sync.net().is_queued())
m_Q_sync.net().push_to_queue(m_nt_sync_delay);

View File

@ -44,6 +44,9 @@ NETLIB_UPDATE_PARAM(switch2)
m_R[0].set_R(R_OFF);
m_R[1].set_R(R_ON);
}
m_R[0].update_dev();
m_R[1].update_dev();
if (USE_ALTERNATE_SCHEDULING)
{
m_R[0].update_dev();
m_R[1].update_dev();
}
}

View File

@ -24,7 +24,13 @@ NETLIB_START(twoterm)
NETLIB_UPDATE(twoterm)
{
/* only called if connected to a rail net ==> notify the solver to recalculate */
netlist().solver()->schedule();
#if !(USE_ALTERNATE_SCHEDULING)
netlist().solver()->schedule1();
#else
/* we only need to call the non-rail terminal */
m_P.net().solve();
m_N.net().solve();
#endif
}
// ----------------------------------------------------------------------------------------
@ -57,6 +63,8 @@ NETLIB_UPDATE_PARAM(R)
{
//printf("updating %s to %f\n", name().cstr(), m_R.Value());
set_R(m_R.Value());
if (USE_ALTERNATE_SCHEDULING)
update_dev();
}
// ----------------------------------------------------------------------------------------
@ -93,7 +101,14 @@ NETLIB_UPDATE_PARAM(POT)
v = (exp(v) - 1.0) / (exp(1.0) - 1.0);
m_R1.set_R(MAX(m_R.Value() * v, NETLIST_GMIN));
m_R2.set_R(MAX(m_R.Value() * (1.0 - v), NETLIST_GMIN));
// force a schedule all
if (USE_ALTERNATE_SCHEDULING)
{
m_R1.update_dev();
m_R2.update_dev();
}
}
// ----------------------------------------------------------------------------------------
// nld_C
// ----------------------------------------------------------------------------------------
@ -104,12 +119,14 @@ NETLIB_START(C)
register_terminal("2", m_N);
register_param("C", m_C, 1e-6);
// set up the element
set(m_C.Value() / 1e-9, 0.0, 0.0);
}
NETLIB_UPDATE_PARAM(C)
{
// set to some very small step time for now
step_time(1e-9);
//step_time(1e-9);
}
NETLIB_UPDATE(C)

View File

@ -160,7 +160,10 @@ protected:
class netlist_generic_diode
{
public:
netlist_generic_diode() {}
netlist_generic_diode()
{
m_Vd = 0.7;
}
ATTR_HOT inline void update_diode(const double nVd)
{
@ -205,8 +208,6 @@ public:
m_Vcrit = m_Vt * log(m_Vt / m_Is / sqrt(2.0));
m_VtInv = 1.0 / m_Vt;
m_Vd = 0.7;
}
ATTR_HOT inline double I() { return m_Id; }

View File

@ -137,6 +137,8 @@ NETLIB_FUNC_VOID(nic7448_sub, update_outputs, (UINT8 v))
assert(v<16);
if (v != m_state)
{
// max transfer time is 100 NS */
OUTLOGIC(m_a, tab7448[v][0], NLTIME_FROM_NS(100));
OUTLOGIC(m_b, tab7448[v][1], NLTIME_FROM_NS(100));
OUTLOGIC(m_c, tab7448[v][2], NLTIME_FROM_NS(100));

View File

@ -18,11 +18,12 @@ NETLIB_START(ttl_const)
NETLIB_UPDATE(ttl_const)
{
OUTLOGIC(m_Q, m_const.Value(), NLTIME_IMMEDIATE);
}
NETLIB_UPDATE_PARAM(ttl_const)
{
OUTLOGIC(m_Q, m_const.Value(), NLTIME_IMMEDIATE);
OUTLOGIC(m_Q, m_const.Value(), NLTIME_IMMEDIATE);
}
NETLIB_START(analog_const)
@ -33,6 +34,7 @@ NETLIB_START(analog_const)
NETLIB_UPDATE(analog_const)
{
OUTANALOG(m_Q, m_const.Value(), NLTIME_IMMEDIATE);
}
NETLIB_UPDATE_PARAM(analog_const)
@ -79,6 +81,7 @@ NETLIB_START(logic_input)
NETLIB_UPDATE(logic_input)
{
OUTLOGIC(m_Q, m_OUT.Value() & 1, NLTIME_IMMEDIATE);
}
NETLIB_UPDATE_PARAM(logic_input)
@ -98,6 +101,7 @@ NETLIB_START(analog_input)
NETLIB_UPDATE(analog_input)
{
OUTANALOG(m_Q, m_OUT.Value(), NLTIME_IMMEDIATE);
}
NETLIB_UPDATE_PARAM(analog_input)

View File

@ -174,19 +174,19 @@ ATTR_COLD void netlist_base_t::reset()
if (m_solver != NULL)
m_solver->reset();
// FIXME: some const devices rely on this
/* make sure params are set now .. */
for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry))
{
entry->object()->update_param();
}
// Step all devices once !
for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry))
{
netlist_device_t *dev = entry->object();
dev->update_dev();
}
// FIXME: some const devices rely on this
/* make sure params are set now .. */
for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry))
{
entry->object()->update_param();
}
}
@ -535,6 +535,12 @@ ATTR_HOT inline void netlist_net_t::update_devs()
m_last = m_cur;
}
ATTR_HOT void netlist_net_t::solve()
{
if (m_solver != NULL)
m_solver->schedule();
}
// ----------------------------------------------------------------------------------------
// netlist_terminal_t
// ----------------------------------------------------------------------------------------

View File

@ -605,6 +605,8 @@ public:
terminal_list_t m_terms;
netlist_matrix_solver_t *m_solver;
ATTR_HOT void solve();
netlist_core_terminal_t *m_head;
/* use this to register state.... */

View File

@ -34,6 +34,8 @@
#define NETLIST_INTERNAL_RES (U64(1000000000))
//#define NETLIST_INTERNAL_RES (U64(1000000000000))
#define USE_ALTERNATE_SCHEDULING (1)
#define NETLIST_CLOCK (NETLIST_INTERNAL_RES)
#define NETLIST_GMIN (1e-9)
@ -119,7 +121,7 @@ typedef UINT8 netlist_sig_t;
//============================================================
#if (USE_OPENMP)
#if (!HAS_OPEN_MP)
#if (!(HAS_OPENMP))
#warning To use openmp compile and link with "-fopenmp"
#endif
#endif

View File

@ -16,7 +16,7 @@
#define NLTIME_FROM_NS(_t) netlist_time::from_nsec(_t)
#define NLTIME_FROM_US(_t) netlist_time::from_usec(_t)
#define NLTIME_FROM_MS(_t) netlist_time::from_msec(_t)
#define NLTIME_IMMEDIATE netlist_time::from_nsec(0)
#define NLTIME_IMMEDIATE netlist_time::from_nsec(1)
// ----------------------------------------------------------------------------------------
// net_list_time

View File

@ -758,7 +758,8 @@ INPUT_PORTS_END
static MACHINE_CONFIG_START( pong, pong_state )
/* basic machine hardware */
MCFG_NETLIST_ADD("maincpu", pong, MASTER_CLOCK * 2)
//MCFG_NETLIST_ADD("maincpu", pong, MASTER_CLOCK * 8)
MCFG_NETLIST_ADD("maincpu", pong, NETLIST_CLOCK)
MCFG_NETLIST_ANALOG_INPUT("maincpu", "vr0", "ic_b9_R.R")
MCFG_NETLIST_ANALOG_INPUT_MULT_OFFSET(1.0 / 100.0 * RES_K(50), RES_K(56) )
MCFG_NETLIST_ANALOG_INPUT("maincpu", "vr1", "ic_a9_R.R")