mirror of
https://github.com/holub/mame
synced 2025-07-01 00:09:18 +03:00
netlist: unify solver calls. (nw)
Calls to the solver used different paths. These changes unify these calls and provide a common call for discontinuous state changes on analog components (change_state).
This commit is contained in:
parent
14f92c9786
commit
d3ee7e21c6
@ -49,17 +49,10 @@ namespace netlist
|
|||||||
|
|
||||||
NETLIB_UPDATE_PARAM(switch1)
|
NETLIB_UPDATE_PARAM(switch1)
|
||||||
{
|
{
|
||||||
m_R.solve_now();
|
m_R.change_state([this]()
|
||||||
if (!m_POS())
|
|
||||||
{
|
{
|
||||||
m_R.set_R(R_OFF);
|
m_R.set_R(m_POS() ? R_ON : R_OFF);
|
||||||
}
|
});
|
||||||
else
|
|
||||||
{
|
|
||||||
m_R.set_R(R_ON);
|
|
||||||
}
|
|
||||||
m_R.solve_later();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
@ -112,21 +105,19 @@ namespace netlist
|
|||||||
|
|
||||||
NETLIB_UPDATE_PARAM(switch2)
|
NETLIB_UPDATE_PARAM(switch2)
|
||||||
{
|
{
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
// R1 and R2 are connected. However this net may be a rail net.
|
||||||
m_R1.solve_now();
|
// The code here thus is a bit more complex.
|
||||||
m_R2.solve_now();
|
|
||||||
if (!m_POS())
|
nl_fptype r1 = m_POS() ? R_OFF : R_ON;
|
||||||
{
|
nl_fptype r2 = m_POS() ? R_ON : R_OFF;
|
||||||
m_R1.set_R(R_ON);
|
|
||||||
m_R2.set_R(R_OFF);
|
if (m_R1.solver() == m_R2.solver())
|
||||||
}
|
m_R1.change_state([this, &r1, &r2]() { m_R1.set_R(r1); m_R2.set_R(r2); });
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_R1.set_R(R_OFF);
|
m_R1.change_state([this, &r1]() { m_R1.set_R(r1); });
|
||||||
m_R2.set_R(R_ON);
|
m_R2.change_state([this, &r2]() { m_R2.set_R(r2); });
|
||||||
}
|
}
|
||||||
m_R1.solve_later();
|
|
||||||
m_R2.solve_later();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} //namespace analog
|
} //namespace analog
|
||||||
|
@ -15,24 +15,21 @@ namespace analog
|
|||||||
// nld_twoterm
|
// nld_twoterm
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void NETLIB_NAME(twoterm)::solve_now()
|
solver::matrix_solver_t * NETLIB_NAME(twoterm)::solver() const noexcept
|
||||||
{
|
{
|
||||||
// we only need to call the non-rail terminal
|
auto *solv(m_P.solver());
|
||||||
if (m_P.has_net() && !m_P.net().is_rail_net())
|
if (solv)
|
||||||
m_P.solve_now();
|
return solv;
|
||||||
else if (m_N.has_net() && !m_N.net().is_rail_net())
|
return m_N.solver();
|
||||||
m_N.solve_now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NETLIB_NAME(twoterm)::solve_later(netlist_time delay) noexcept
|
|
||||||
{
|
|
||||||
// we only need to call the non-rail terminal
|
|
||||||
if (m_P.has_net() && !m_P.net().is_rail_net())
|
|
||||||
m_P.schedule_solve_after(delay);
|
|
||||||
else if (m_N.has_net() && !m_N.net().is_rail_net())
|
|
||||||
m_N.schedule_solve_after(delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void NETLIB_NAME(twoterm)::solve_now() const
|
||||||
|
{
|
||||||
|
auto *solv(solver());
|
||||||
|
if (solv)
|
||||||
|
solv->solve_now();
|
||||||
|
}
|
||||||
|
|
||||||
NETLIB_UPDATE(twoterm)
|
NETLIB_UPDATE(twoterm)
|
||||||
{
|
{
|
||||||
@ -66,19 +63,22 @@ namespace analog
|
|||||||
|
|
||||||
NETLIB_UPDATE_PARAM(POT)
|
NETLIB_UPDATE_PARAM(POT)
|
||||||
{
|
{
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
|
||||||
m_R1.solve_now();
|
|
||||||
m_R2.solve_now();
|
|
||||||
|
|
||||||
nl_fptype v = m_Dial();
|
nl_fptype v = m_Dial();
|
||||||
if (m_DialIsLog())
|
if (m_DialIsLog())
|
||||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||||
if (m_Reverse())
|
if (m_Reverse())
|
||||||
v = nlconst::one() - v;
|
v = nlconst::one() - v;
|
||||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
|
||||||
m_R2.set_R(std::max(m_R() * (nlconst::one() - v), exec().gmin()));
|
nl_fptype r1(std::max(m_R() * v, exec().gmin()));
|
||||||
m_R1.solve_later();
|
nl_fptype r2(std::max(m_R() * (nlconst::one() - v), exec().gmin()));
|
||||||
m_R2.solve_later();
|
|
||||||
|
if (m_R1.solver() == m_R2.solver())
|
||||||
|
m_R1.change_state([this, &r1, &r2]() { m_R1.set_R(r1); m_R2.set_R(r2); });
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_R1.change_state([this, &r1]() { m_R1.set_R(r1); });
|
||||||
|
m_R2.change_state([this, &r2]() { m_R2.set_R(r2); });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,17 +100,17 @@ namespace analog
|
|||||||
|
|
||||||
NETLIB_UPDATE_PARAM(POT2)
|
NETLIB_UPDATE_PARAM(POT2)
|
||||||
{
|
{
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
|
||||||
m_R1.solve_now();
|
|
||||||
|
|
||||||
nl_fptype v = m_Dial();
|
nl_fptype v = m_Dial();
|
||||||
|
|
||||||
if (m_DialIsLog())
|
if (m_DialIsLog())
|
||||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||||
if (m_Reverse())
|
if (m_Reverse())
|
||||||
v = nlconst::one() - v;
|
v = nlconst::one() - v;
|
||||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
|
||||||
m_R1.solve_later();
|
m_R1.change_state([this, &v]()
|
||||||
|
{
|
||||||
|
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
@ -86,9 +86,17 @@ namespace analog
|
|||||||
|
|
||||||
NETLIB_UPDATEI();
|
NETLIB_UPDATEI();
|
||||||
|
|
||||||
void solve_now();
|
solver::matrix_solver_t *solver() const noexcept;
|
||||||
|
|
||||||
void solve_later(netlist_time delay = netlist_time::quantum()) noexcept;
|
void solve_now() const;
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void change_state(F f, netlist_time delay = netlist_time::quantum())
|
||||||
|
{
|
||||||
|
auto *solv(solver());
|
||||||
|
if (solv)
|
||||||
|
solv->change_state(f, delay);
|
||||||
|
}
|
||||||
|
|
||||||
void set_G_V_I(nl_fptype G, nl_fptype V, nl_fptype I) const noexcept
|
void set_G_V_I(nl_fptype G, nl_fptype V, nl_fptype I) const noexcept
|
||||||
{
|
{
|
||||||
@ -168,9 +176,10 @@ namespace analog
|
|||||||
NETLIB_UPDATE_PARAMI()
|
NETLIB_UPDATE_PARAMI()
|
||||||
{
|
{
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
// FIXME: We only need to update the net first if this is a time stepping net
|
||||||
solve_now();
|
change_state([this]()
|
||||||
set_R(std::max(m_R(), exec().gmin()));
|
{
|
||||||
solve_later();
|
set_R(std::max(m_R(), exec().gmin()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -524,11 +533,12 @@ namespace analog
|
|||||||
{
|
{
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
// FIXME: We only need to update the net first if this is a time stepping net
|
||||||
//FIXME: works only for CS without function
|
//FIXME: works only for CS without function
|
||||||
solve_now();
|
change_state([this]()
|
||||||
const auto zero(nlconst::zero());
|
{
|
||||||
set_mat(zero, zero, -m_I(),
|
const auto zero(nlconst::zero());
|
||||||
zero, zero, m_I());
|
set_mat(zero, zero, -m_I(),
|
||||||
solve_later();
|
zero, zero, m_I());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -69,9 +69,7 @@ namespace netlist
|
|||||||
if (R > nlconst::zero() && (m_last != new_state))
|
if (R > nlconst::zero() && (m_last != new_state))
|
||||||
{
|
{
|
||||||
m_last = new_state;
|
m_last = new_state;
|
||||||
m_R.solve_now();
|
m_R.change_state([this, &R]() -> void { this->m_R.set_R(R);});
|
||||||
m_R.set_R(R);
|
|
||||||
m_R.solve_later();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,12 +43,14 @@ namespace netlist { namespace devices {
|
|||||||
|
|
||||||
NETLIB_UPDATE(CD4316_GATE)
|
NETLIB_UPDATE(CD4316_GATE)
|
||||||
{
|
{
|
||||||
m_R.solve_now();
|
m_R.change_state([this]()
|
||||||
if (m_S() && !m_E())
|
{
|
||||||
m_R.set_R(m_base_r());
|
if (m_S() && !m_E())
|
||||||
else
|
m_R.set_R(m_base_r());
|
||||||
m_R.set_R(plib::reciprocal(exec().gmin()));
|
else
|
||||||
m_R.solve_later(NLTIME_FROM_NS(1));
|
m_R.set_R(plib::reciprocal(exec().gmin()));
|
||||||
|
}
|
||||||
|
, NLTIME_FROM_NS(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
NETLIB_DEVICE_IMPL(CD4316_GATE, "CD4316_GATE", "")
|
NETLIB_DEVICE_IMPL(CD4316_GATE, "CD4316_GATE", "")
|
||||||
|
@ -28,7 +28,6 @@ namespace netlist
|
|||||||
, m_Q(*this, "_Q")
|
, m_Q(*this, "_Q")
|
||||||
, m_inc(netlist_time::from_hz(24000 * 2))
|
, m_inc(netlist_time::from_hz(24000 * 2))
|
||||||
, m_shift(*this, "m_shift", 0)
|
, m_shift(*this, "m_shift", 0)
|
||||||
, m_is_timestep(false)
|
|
||||||
{
|
{
|
||||||
connect(m_feedback, m_Q);
|
connect(m_feedback, m_Q);
|
||||||
|
|
||||||
@ -57,9 +56,6 @@ namespace netlist
|
|||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
state_var_u32 m_shift;
|
state_var_u32 m_shift;
|
||||||
|
|
||||||
/* cache */
|
|
||||||
bool m_is_timestep;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NETLIB_RESET(MM5837_dip)
|
NETLIB_RESET(MM5837_dip)
|
||||||
@ -74,7 +70,6 @@ namespace netlist
|
|||||||
log().warning(MW_FREQUENCY_OUTSIDE_OF_SPECS_1(m_FREQ()));
|
log().warning(MW_FREQUENCY_OUTSIDE_OF_SPECS_1(m_FREQ()));
|
||||||
|
|
||||||
m_shift = 0x1ffff;
|
m_shift = 0x1ffff;
|
||||||
m_is_timestep = (m_RV.m_P.net().solver()->timestep_device_count() > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NETLIB_UPDATE_PARAM(MM5837_dip)
|
NETLIB_UPDATE_PARAM(MM5837_dip)
|
||||||
@ -104,11 +99,10 @@ namespace netlist
|
|||||||
const nl_fptype R = state ? m_R_HIGH : m_R_LOW;
|
const nl_fptype R = state ? m_R_HIGH : m_R_LOW;
|
||||||
const nl_fptype V = state ? m_VDD() : m_VSS();
|
const nl_fptype V = state ? m_VDD() : m_VSS();
|
||||||
|
|
||||||
// We only need to update the net first if this is a time stepping net
|
m_RV.change_state([this, &R, &V]()
|
||||||
if (m_is_timestep)
|
{
|
||||||
m_RV.solve_now();
|
m_RV.set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
|
||||||
m_RV.set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
|
});
|
||||||
m_RV.solve_later(NLTIME_FROM_NS(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,13 +39,13 @@ namespace netlist
|
|||||||
|
|
||||||
NETLIB_UPDATE_PARAM(r2r_dac)
|
NETLIB_UPDATE_PARAM(r2r_dac)
|
||||||
{
|
{
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
|
||||||
solve_now();
|
|
||||||
nl_fptype V = m_VIN() / static_cast<nl_fptype>(1 << m_num())
|
nl_fptype V = m_VIN() / static_cast<nl_fptype>(1 << m_num())
|
||||||
* static_cast<nl_fptype>(m_val());
|
* static_cast<nl_fptype>(m_val());
|
||||||
|
change_state([this, &V]()
|
||||||
this->set_G_V_I(plib::reciprocal(m_R()), V, nlconst::zero());
|
{
|
||||||
solve_later();
|
this->set_G_V_I(plib::reciprocal(m_R()), V, nlconst::zero());
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} //namespace analog
|
} //namespace analog
|
||||||
|
|
||||||
|
@ -67,7 +67,6 @@ namespace netlist
|
|||||||
, m_RVO(*this, "RVO")
|
, m_RVO(*this, "RVO")
|
||||||
, m_model(*this, "MODEL", "TTL_7414_GATE")
|
, m_model(*this, "MODEL", "TTL_7414_GATE")
|
||||||
, m_last_state(*this, "m_last_var", 1)
|
, m_last_state(*this, "m_last_var", 1)
|
||||||
, m_is_timestep(false)
|
|
||||||
{
|
{
|
||||||
register_subalias("Q", m_RVO.m_P);
|
register_subalias("Q", m_RVO.m_P);
|
||||||
|
|
||||||
@ -82,7 +81,6 @@ namespace netlist
|
|||||||
m_last_state = 1;
|
m_last_state = 1;
|
||||||
m_RVI.reset();
|
m_RVI.reset();
|
||||||
m_RVO.reset();
|
m_RVO.reset();
|
||||||
m_is_timestep = (m_RVO.m_P.net().solver()->timestep_device_count() > 0);
|
|
||||||
m_RVI.set_G_V_I(plib::reciprocal(m_model.m_RI()), m_model.m_VI, nlconst::zero());
|
m_RVI.set_G_V_I(plib::reciprocal(m_model.m_RI()), m_model.m_VI, nlconst::zero());
|
||||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
|
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
|
||||||
}
|
}
|
||||||
@ -95,10 +93,10 @@ namespace netlist
|
|||||||
if (va < m_model.m_VTM)
|
if (va < m_model.m_VTM)
|
||||||
{
|
{
|
||||||
m_last_state = 0;
|
m_last_state = 0;
|
||||||
if (m_is_timestep)
|
m_RVO.change_state([this]()
|
||||||
m_RVO.solve_now();
|
{
|
||||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROH()), m_model.m_VOH, nlconst::zero());
|
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROH()), m_model.m_VOH, nlconst::zero());
|
||||||
m_RVO.solve_later();
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -106,10 +104,10 @@ namespace netlist
|
|||||||
if (va > m_model.m_VTP)
|
if (va > m_model.m_VTP)
|
||||||
{
|
{
|
||||||
m_last_state = 1;
|
m_last_state = 1;
|
||||||
if (m_is_timestep)
|
m_RVO.change_state([this]()
|
||||||
m_RVO.solve_now();
|
{
|
||||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
|
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
|
||||||
m_RVO.solve_later();
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +119,6 @@ namespace netlist
|
|||||||
analog::NETLIB_SUB(twoterm) m_RVO;
|
analog::NETLIB_SUB(twoterm) m_RVO;
|
||||||
schmitt_trigger_model_t m_model;
|
schmitt_trigger_model_t m_model;
|
||||||
state_var<int> m_last_state;
|
state_var<int> m_last_state;
|
||||||
bool m_is_timestep;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NETLIB_DEVICE_IMPL(schmitt_trigger, "SCHMITT_TRIGGER", "MODEL")
|
NETLIB_DEVICE_IMPL(schmitt_trigger, "SCHMITT_TRIGGER", "MODEL")
|
||||||
|
@ -117,7 +117,6 @@ namespace netlist
|
|||||||
, m_RP(*this, "RP")
|
, m_RP(*this, "RP")
|
||||||
, m_RN(*this, "RN")
|
, m_RN(*this, "RN")
|
||||||
, m_last_state(*this, "m_last_var", -1)
|
, m_last_state(*this, "m_last_var", -1)
|
||||||
, m_is_timestep(false)
|
|
||||||
{
|
{
|
||||||
register_subalias("Q", m_RN.m_P);
|
register_subalias("Q", m_RN.m_P);
|
||||||
|
|
||||||
@ -145,7 +144,6 @@ namespace netlist
|
|||||||
m_last_state = -1;
|
m_last_state = -1;
|
||||||
m_RN.reset();
|
m_RN.reset();
|
||||||
m_RP.reset();
|
m_RP.reset();
|
||||||
m_is_timestep = (m_RN.m_P.net().solver()->timestep_device_count() > 0);
|
|
||||||
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||||
logic_family()->low_offset_V(), nlconst::zero());
|
logic_family()->low_offset_V(), nlconst::zero());
|
||||||
m_RP.set_G_V_I(G_OFF,
|
m_RP.set_G_V_I(G_OFF,
|
||||||
@ -158,28 +156,27 @@ namespace netlist
|
|||||||
const auto state = static_cast<int>(m_I());
|
const auto state = static_cast<int>(m_I());
|
||||||
if (state != m_last_state)
|
if (state != m_last_state)
|
||||||
{
|
{
|
||||||
// We only need to update the net first if this is a time stepping net
|
// RN, RP are connected ...
|
||||||
if (m_is_timestep)
|
m_RN.change_state([this, &state]()
|
||||||
{
|
{
|
||||||
m_RN.solve_now(); // RN, RP are connected ...
|
if (state)
|
||||||
}
|
{
|
||||||
if (state)
|
|
||||||
{
|
m_RN.set_G_V_I(G_OFF,
|
||||||
m_RN.set_G_V_I(G_OFF,
|
nlconst::zero(),
|
||||||
nlconst::zero(),
|
nlconst::zero());
|
||||||
nlconst::zero());
|
m_RP.set_G_V_I(plib::reciprocal(logic_family()->R_high()),
|
||||||
m_RP.set_G_V_I(plib::reciprocal(logic_family()->R_high()),
|
logic_family()->high_offset_V(), nlconst::zero());
|
||||||
logic_family()->high_offset_V(), nlconst::zero());
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||||
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
logic_family()->low_offset_V(), nlconst::zero());
|
||||||
logic_family()->low_offset_V(), nlconst::zero());
|
m_RP.set_G_V_I(G_OFF,
|
||||||
m_RP.set_G_V_I(G_OFF,
|
nlconst::zero(),
|
||||||
nlconst::zero(),
|
nlconst::zero());
|
||||||
nlconst::zero());
|
}
|
||||||
}
|
});
|
||||||
m_RN.solve_later(); // RN, RP are connected ...
|
|
||||||
m_last_state = state;
|
m_last_state = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,6 @@ namespace devices
|
|||||||
analog::NETLIB_NAME(twoterm) m_RP;
|
analog::NETLIB_NAME(twoterm) m_RP;
|
||||||
analog::NETLIB_NAME(twoterm) m_RN;
|
analog::NETLIB_NAME(twoterm) m_RN;
|
||||||
state_var<int> m_last_state;
|
state_var<int> m_last_state;
|
||||||
bool m_is_timestep;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace devices
|
} // namespace devices
|
||||||
|
@ -463,9 +463,10 @@ namespace devices
|
|||||||
const nl_fptype R = state ? m_RON() : m_ROFF();
|
const nl_fptype R = state ? m_RON() : m_ROFF();
|
||||||
|
|
||||||
// FIXME: We only need to update the net first if this is a time stepping net
|
// FIXME: We only need to update the net first if this is a time stepping net
|
||||||
m_R.solve_now();
|
m_R.change_state([this, &R]()
|
||||||
m_R.set_R(R);
|
{
|
||||||
m_R.solve_later();
|
m_R.set_R(R);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,18 +813,10 @@ namespace netlist
|
|||||||
|
|
||||||
void terminal_t::solve_now()
|
void terminal_t::solve_now()
|
||||||
{
|
{
|
||||||
|
const auto *solv(solver());
|
||||||
// Nets may belong to railnets which do not have a solver attached
|
// Nets may belong to railnets which do not have a solver attached
|
||||||
if (this->has_net())
|
if (solv)
|
||||||
if (net().solver() != nullptr)
|
solver()->solve_now();
|
||||||
net().solver()->solve_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminal_t::schedule_solve_after(netlist_time after) noexcept
|
|
||||||
{
|
|
||||||
// Nets may belong to railnets which do not have a solver attached
|
|
||||||
if (this->has_net())
|
|
||||||
if (net().solver() != nullptr)
|
|
||||||
net().solver()->update_after(after);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
@ -798,6 +798,8 @@ namespace netlist
|
|||||||
|
|
||||||
const analog_net_t & net() const noexcept;
|
const analog_net_t & net() const noexcept;
|
||||||
analog_net_t & net() noexcept;
|
analog_net_t & net() noexcept;
|
||||||
|
|
||||||
|
solver::matrix_solver_t *solver() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -834,7 +836,6 @@ namespace netlist
|
|||||||
}
|
}
|
||||||
|
|
||||||
void solve_now();
|
void solve_now();
|
||||||
void schedule_solve_after(netlist_time after) noexcept;
|
|
||||||
|
|
||||||
void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false);
|
void set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false);
|
||||||
|
|
||||||
@ -945,6 +946,11 @@ namespace netlist
|
|||||||
solver::matrix_solver_t *solver() const noexcept { return m_solver; }
|
solver::matrix_solver_t *solver() const noexcept { return m_solver; }
|
||||||
void set_solver(solver::matrix_solver_t *solver) noexcept { m_solver = solver; }
|
void set_solver(solver::matrix_solver_t *solver) noexcept { m_solver = solver; }
|
||||||
|
|
||||||
|
friend constexpr bool operator==(const analog_net_t &lhs, const analog_net_t &rhs) noexcept
|
||||||
|
{
|
||||||
|
return &lhs == &rhs;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
state_var<nl_fptype> m_cur_Analog;
|
state_var<nl_fptype> m_cur_Analog;
|
||||||
solver::matrix_solver_t *m_solver;
|
solver::matrix_solver_t *m_solver;
|
||||||
@ -1940,6 +1946,13 @@ namespace netlist
|
|||||||
return static_cast<analog_net_t &>(core_terminal_t::net());
|
return static_cast<analog_net_t &>(core_terminal_t::net());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline solver::matrix_solver_t *analog_t::solver() const noexcept
|
||||||
|
{
|
||||||
|
if (this->has_net())
|
||||||
|
return net().solver();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
inline nl_fptype terminal_t::operator ()() const noexcept { return net().Q_Analog(); }
|
inline nl_fptype terminal_t::operator ()() const noexcept { return net().Q_Analog(); }
|
||||||
|
|
||||||
inline void terminal_t::set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false)
|
inline void terminal_t::set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false)
|
||||||
|
@ -389,6 +389,20 @@ namespace solver
|
|||||||
inp->push(inp->proxied_net()->Q_Analog());
|
inp->push(inp->proxied_net()->Q_Analog());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool matrix_solver_t::updates_net(const analog_net_t *net) const noexcept
|
||||||
|
{
|
||||||
|
if (net != nullptr)
|
||||||
|
{
|
||||||
|
for (const auto &t : m_terms )
|
||||||
|
if (t.is_net(net))
|
||||||
|
return true;
|
||||||
|
for (const auto &inp : m_inps)
|
||||||
|
if (&inp->net() == net)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void matrix_solver_t::update_dynamic() noexcept
|
void matrix_solver_t::update_dynamic() noexcept
|
||||||
{
|
{
|
||||||
// update all non-linear devices
|
// update all non-linear devices
|
||||||
@ -412,22 +426,6 @@ namespace solver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void matrix_solver_t::solve_now()
|
|
||||||
{
|
|
||||||
// this should only occur outside of execution and thus
|
|
||||||
// using time should be safe.
|
|
||||||
|
|
||||||
const netlist_time new_timestep = solve(exec().time());
|
|
||||||
plib::unused_var(new_timestep);
|
|
||||||
|
|
||||||
update_inputs();
|
|
||||||
|
|
||||||
if (m_params.m_dynamic_ts && (timestep_device_count() != 0))
|
|
||||||
{
|
|
||||||
m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_min_timestep));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void matrix_solver_t::step(netlist_time delta) noexcept
|
void matrix_solver_t::step(netlist_time delta) noexcept
|
||||||
{
|
{
|
||||||
const auto dd(delta.as_fp<nl_fptype>());
|
const auto dd(delta.as_fp<nl_fptype>());
|
||||||
@ -495,7 +493,7 @@ namespace solver
|
|||||||
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
|
int matrix_solver_t::get_net_idx(const analog_net_t *net) const noexcept
|
||||||
{
|
{
|
||||||
for (std::size_t k = 0; k < m_terms.size(); k++)
|
for (std::size_t k = 0; k < m_terms.size(); k++)
|
||||||
if (m_terms[k].isNet(net))
|
if (m_terms[k].is_net(net))
|
||||||
return static_cast<int>(k);
|
return static_cast<int>(k);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -143,13 +143,11 @@ namespace solver
|
|||||||
|
|
||||||
terminal_t **terms() noexcept { return m_terms.data(); }
|
terminal_t **terms() noexcept { return m_terms.data(); }
|
||||||
|
|
||||||
template <typename FT, typename = std::enable_if<plib::is_floating_point<FT>::value, void>>
|
nl_fptype getV() const noexcept { return m_net->Q_Analog(); }
|
||||||
FT getV() const noexcept { return static_cast<FT>(m_net->Q_Analog()); }
|
|
||||||
|
|
||||||
template <typename FT, typename = std::enable_if<plib::is_floating_point<FT>::value, void>>
|
void setV(nl_fptype v) noexcept { m_net->set_Q_Analog(v); }
|
||||||
void setV(FT v) noexcept { m_net->set_Q_Analog(static_cast<nl_fptype>(v)); }
|
|
||||||
|
|
||||||
bool isNet(const analog_net_t * net) const noexcept { return net == m_net; }
|
bool is_net(const analog_net_t * net) const noexcept { return net == m_net; }
|
||||||
|
|
||||||
void set_railstart(std::size_t val) noexcept { m_railstart = val; }
|
void set_railstart(std::size_t val) noexcept { m_railstart = val; }
|
||||||
|
|
||||||
@ -191,6 +189,14 @@ namespace solver
|
|||||||
netlist_time solve(netlist_time_ext now);
|
netlist_time solve(netlist_time_ext now);
|
||||||
void update_inputs();
|
void update_inputs();
|
||||||
|
|
||||||
|
/// \brief Checks if solver may alter a net
|
||||||
|
///
|
||||||
|
/// This checks if a solver will alter a net. Returns true if the
|
||||||
|
/// net is either part of the voltage vector or if it belongs to
|
||||||
|
/// the analog input nets connected to the solver.
|
||||||
|
|
||||||
|
bool updates_net(const analog_net_t *net) const noexcept;
|
||||||
|
|
||||||
std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); }
|
std::size_t dynamic_device_count() const noexcept { return m_dynamic_funcs.size(); }
|
||||||
std::size_t timestep_device_count() const noexcept { return m_step_funcs.size(); }
|
std::size_t timestep_device_count() const noexcept { return m_step_funcs.size(); }
|
||||||
|
|
||||||
@ -199,11 +205,30 @@ namespace solver
|
|||||||
/// This should only be called from update and update_param events.
|
/// This should only be called from update and update_param events.
|
||||||
/// It's purpose is to bring voltage values to the current timestep.
|
/// It's purpose is to bring voltage values to the current timestep.
|
||||||
/// This will be called BEFORE updating object properties.
|
/// This will be called BEFORE updating object properties.
|
||||||
void solve_now();
|
void solve_now()
|
||||||
|
|
||||||
void update_after(netlist_time after) noexcept
|
|
||||||
{
|
{
|
||||||
m_Q_sync.net().toggle_and_push_to_queue(after);
|
// this should only occur outside of execution and thus
|
||||||
|
// using time should be safe.
|
||||||
|
|
||||||
|
const netlist_time new_timestep = solve(exec().time());
|
||||||
|
plib::unused_var(new_timestep);
|
||||||
|
|
||||||
|
update_inputs();
|
||||||
|
|
||||||
|
if (m_params.m_dynamic_ts && (timestep_device_count() != 0))
|
||||||
|
{
|
||||||
|
m_Q_sync.net().toggle_and_push_to_queue(netlist_time::from_fp(m_params.m_min_timestep));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void change_state(F f, netlist_time delay = netlist_time::quantum())
|
||||||
|
{
|
||||||
|
// We only need to update the net first if this is a time stepping net
|
||||||
|
if (timestep_device_count() > 0)
|
||||||
|
solve_now();
|
||||||
|
f();
|
||||||
|
m_Q_sync.net().toggle_and_push_to_queue(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
// netdevice functions
|
// netdevice functions
|
||||||
@ -413,7 +438,7 @@ namespace solver
|
|||||||
{
|
{
|
||||||
const std::size_t iN = size();
|
const std::size_t iN = size();
|
||||||
for (std::size_t i = 0; i < iN; i++)
|
for (std::size_t i = 0; i < iN; i++)
|
||||||
this->m_terms[i].setV(m_new_V[i]);
|
this->m_terms[i].setV(static_cast<nl_fptype>(m_new_V[i]));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// global tanh damping (4.197)
|
// global tanh damping (4.197)
|
||||||
@ -439,7 +464,7 @@ namespace solver
|
|||||||
const auto vntol(static_cast<float_type>(m_params.m_vntol));
|
const auto vntol(static_cast<float_type>(m_params.m_vntol));
|
||||||
for (std::size_t i = 0; i < iN; i++)
|
for (std::size_t i = 0; i < iN; i++)
|
||||||
{
|
{
|
||||||
const auto vold(this->m_terms[i].template getV<float_type>());
|
const auto vold(static_cast<float_type>(this->m_terms[i].getV()));
|
||||||
const auto vnew(m_new_V[i]);
|
const auto vnew(m_new_V[i]);
|
||||||
const auto tol(vntol + reltol * std::max(plib::abs(vnew),plib::abs(vold)));
|
const auto tol(vntol + reltol * std::max(plib::abs(vnew),plib::abs(vold)));
|
||||||
if (plib::abs(vnew - vold) > tol)
|
if (plib::abs(vnew - vold) > tol)
|
||||||
@ -455,7 +480,7 @@ namespace solver
|
|||||||
for (std::size_t k = 0; k < size(); k++)
|
for (std::size_t k = 0; k < size(); k++)
|
||||||
{
|
{
|
||||||
const auto &t = m_terms[k];
|
const auto &t = m_terms[k];
|
||||||
const auto v(t.template getV<nl_fptype>());
|
const auto v(static_cast<nl_fptype>(t.getV()));
|
||||||
// avoid floating point exceptions
|
// avoid floating point exceptions
|
||||||
const nl_fptype DD_n = std::max(-fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),
|
const nl_fptype DD_n = std::max(-fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),
|
||||||
std::min(+fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),(v - m_last_V[k])));
|
std::min(+fp_constants<nl_fptype>::TIMESTEP_MAXDIFF(),(v - m_last_V[k])));
|
||||||
|
@ -183,30 +183,27 @@ namespace devices
|
|||||||
{
|
{
|
||||||
return create_solver<FT, -16>(net_count, sname, nets);
|
return create_solver<FT, -16>(net_count, sname, nets);
|
||||||
}
|
}
|
||||||
else if (net_count <= 32)
|
if (net_count <= 32)
|
||||||
{
|
{
|
||||||
return create_solver<FT, -32>(net_count, sname, nets);
|
return create_solver<FT, -32>(net_count, sname, nets);
|
||||||
}
|
}
|
||||||
else if (net_count <= 64)
|
if (net_count <= 64)
|
||||||
{
|
{
|
||||||
return create_solver<FT, -64>(net_count, sname, nets);
|
return create_solver<FT, -64>(net_count, sname, nets);
|
||||||
}
|
}
|
||||||
else if (net_count <= 128)
|
if (net_count <= 128)
|
||||||
{
|
{
|
||||||
return create_solver<FT, -128>(net_count, sname, nets);
|
return create_solver<FT, -128>(net_count, sname, nets);
|
||||||
}
|
}
|
||||||
else if (net_count <= 256)
|
if (net_count <= 256)
|
||||||
{
|
{
|
||||||
return create_solver<FT, -256>(net_count, sname, nets);
|
return create_solver<FT, -256>(net_count, sname, nets);
|
||||||
}
|
}
|
||||||
else if (net_count <= 512)
|
if (net_count <= 512)
|
||||||
{
|
{
|
||||||
return create_solver<FT, -512>(net_count, sname, nets);
|
return create_solver<FT, -512>(net_count, sname, nets);
|
||||||
}
|
}
|
||||||
else
|
return create_solver<FT, 0>(net_count, sname, nets);
|
||||||
{
|
|
||||||
return create_solver<FT, 0>(net_count, sname, nets);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user