mirror of
https://github.com/holub/mame
synced 2025-04-20 23:42:22 +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)
|
||||
{
|
||||
m_R.solve_now();
|
||||
if (!m_POS())
|
||||
m_R.change_state([this]()
|
||||
{
|
||||
m_R.set_R(R_OFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_R.set_R(R_ON);
|
||||
}
|
||||
m_R.solve_later();
|
||||
|
||||
m_R.set_R(m_POS() ? R_ON : R_OFF);
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -112,21 +105,19 @@ namespace netlist
|
||||
|
||||
NETLIB_UPDATE_PARAM(switch2)
|
||||
{
|
||||
// FIXME: We only need to update the net first if this is a time stepping net
|
||||
m_R1.solve_now();
|
||||
m_R2.solve_now();
|
||||
if (!m_POS())
|
||||
{
|
||||
m_R1.set_R(R_ON);
|
||||
m_R2.set_R(R_OFF);
|
||||
}
|
||||
// R1 and R2 are connected. However this net may be a rail net.
|
||||
// The code here thus is a bit more complex.
|
||||
|
||||
nl_fptype r1 = m_POS() ? R_OFF : R_ON;
|
||||
nl_fptype r2 = m_POS() ? R_ON : 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
|
||||
{
|
||||
m_R1.set_R(R_OFF);
|
||||
m_R2.set_R(R_ON);
|
||||
m_R1.change_state([this, &r1]() { m_R1.set_R(r1); });
|
||||
m_R2.change_state([this, &r2]() { m_R2.set_R(r2); });
|
||||
}
|
||||
m_R1.solve_later();
|
||||
m_R2.solve_later();
|
||||
}
|
||||
|
||||
} //namespace analog
|
||||
|
@ -15,24 +15,21 @@ namespace analog
|
||||
// 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
|
||||
if (m_P.has_net() && !m_P.net().is_rail_net())
|
||||
m_P.solve_now();
|
||||
else if (m_N.has_net() && !m_N.net().is_rail_net())
|
||||
m_N.solve_now();
|
||||
auto *solv(m_P.solver());
|
||||
if (solv)
|
||||
return solv;
|
||||
return m_N.solver();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -66,19 +63,22 @@ namespace analog
|
||||
|
||||
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();
|
||||
if (m_DialIsLog())
|
||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||
if (m_Reverse())
|
||||
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()));
|
||||
m_R1.solve_later();
|
||||
m_R2.solve_later();
|
||||
|
||||
nl_fptype r1(std::max(m_R() * v, exec().gmin()));
|
||||
nl_fptype r2(std::max(m_R() * (nlconst::one() - v), exec().gmin()));
|
||||
|
||||
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)
|
||||
{
|
||||
// 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();
|
||||
|
||||
if (m_DialIsLog())
|
||||
v = (plib::exp(v) - nlconst::one()) / (plib::exp(nlconst::one()) - nlconst::one());
|
||||
if (m_Reverse())
|
||||
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();
|
||||
|
||||
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
|
||||
{
|
||||
@ -168,9 +176,10 @@ namespace analog
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
// FIXME: We only need to update the net first if this is a time stepping net
|
||||
solve_now();
|
||||
set_R(std::max(m_R(), exec().gmin()));
|
||||
solve_later();
|
||||
change_state([this]()
|
||||
{
|
||||
set_R(std::max(m_R(), exec().gmin()));
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
@ -524,11 +533,12 @@ namespace analog
|
||||
{
|
||||
// FIXME: We only need to update the net first if this is a time stepping net
|
||||
//FIXME: works only for CS without function
|
||||
solve_now();
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -m_I(),
|
||||
zero, zero, m_I());
|
||||
solve_later();
|
||||
change_state([this]()
|
||||
{
|
||||
const auto zero(nlconst::zero());
|
||||
set_mat(zero, zero, -m_I(),
|
||||
zero, zero, m_I());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -69,9 +69,7 @@ namespace netlist
|
||||
if (R > nlconst::zero() && (m_last != new_state))
|
||||
{
|
||||
m_last = new_state;
|
||||
m_R.solve_now();
|
||||
m_R.set_R(R);
|
||||
m_R.solve_later();
|
||||
m_R.change_state([this, &R]() -> void { this->m_R.set_R(R);});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,12 +43,14 @@ namespace netlist { namespace devices {
|
||||
|
||||
NETLIB_UPDATE(CD4316_GATE)
|
||||
{
|
||||
m_R.solve_now();
|
||||
if (m_S() && !m_E())
|
||||
m_R.set_R(m_base_r());
|
||||
else
|
||||
m_R.set_R(plib::reciprocal(exec().gmin()));
|
||||
m_R.solve_later(NLTIME_FROM_NS(1));
|
||||
m_R.change_state([this]()
|
||||
{
|
||||
if (m_S() && !m_E())
|
||||
m_R.set_R(m_base_r());
|
||||
else
|
||||
m_R.set_R(plib::reciprocal(exec().gmin()));
|
||||
}
|
||||
, NLTIME_FROM_NS(1));
|
||||
}
|
||||
|
||||
NETLIB_DEVICE_IMPL(CD4316_GATE, "CD4316_GATE", "")
|
||||
|
@ -28,7 +28,6 @@ namespace netlist
|
||||
, m_Q(*this, "_Q")
|
||||
, m_inc(netlist_time::from_hz(24000 * 2))
|
||||
, m_shift(*this, "m_shift", 0)
|
||||
, m_is_timestep(false)
|
||||
{
|
||||
connect(m_feedback, m_Q);
|
||||
|
||||
@ -57,9 +56,6 @@ namespace netlist
|
||||
|
||||
/* state */
|
||||
state_var_u32 m_shift;
|
||||
|
||||
/* cache */
|
||||
bool m_is_timestep;
|
||||
};
|
||||
|
||||
NETLIB_RESET(MM5837_dip)
|
||||
@ -74,7 +70,6 @@ namespace netlist
|
||||
log().warning(MW_FREQUENCY_OUTSIDE_OF_SPECS_1(m_FREQ()));
|
||||
|
||||
m_shift = 0x1ffff;
|
||||
m_is_timestep = (m_RV.m_P.net().solver()->timestep_device_count() > 0);
|
||||
}
|
||||
|
||||
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 V = state ? m_VDD() : m_VSS();
|
||||
|
||||
// We only need to update the net first if this is a time stepping net
|
||||
if (m_is_timestep)
|
||||
m_RV.solve_now();
|
||||
m_RV.set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
|
||||
m_RV.solve_later(NLTIME_FROM_NS(1));
|
||||
m_RV.change_state([this, &R, &V]()
|
||||
{
|
||||
m_RV.set_G_V_I(plib::reciprocal(R), V, nlconst::zero());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,13 +39,13 @@ namespace netlist
|
||||
|
||||
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())
|
||||
* static_cast<nl_fptype>(m_val());
|
||||
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), V, nlconst::zero());
|
||||
solve_later();
|
||||
change_state([this, &V]()
|
||||
{
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), V, nlconst::zero());
|
||||
}
|
||||
);
|
||||
}
|
||||
} //namespace analog
|
||||
|
||||
|
@ -67,7 +67,6 @@ namespace netlist
|
||||
, m_RVO(*this, "RVO")
|
||||
, m_model(*this, "MODEL", "TTL_7414_GATE")
|
||||
, m_last_state(*this, "m_last_var", 1)
|
||||
, m_is_timestep(false)
|
||||
{
|
||||
register_subalias("Q", m_RVO.m_P);
|
||||
|
||||
@ -82,7 +81,6 @@ namespace netlist
|
||||
m_last_state = 1;
|
||||
m_RVI.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_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)
|
||||
{
|
||||
m_last_state = 0;
|
||||
if (m_is_timestep)
|
||||
m_RVO.solve_now();
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROH()), m_model.m_VOH, nlconst::zero());
|
||||
m_RVO.solve_later();
|
||||
m_RVO.change_state([this]()
|
||||
{
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROH()), m_model.m_VOH, nlconst::zero());
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -106,10 +104,10 @@ namespace netlist
|
||||
if (va > m_model.m_VTP)
|
||||
{
|
||||
m_last_state = 1;
|
||||
if (m_is_timestep)
|
||||
m_RVO.solve_now();
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
|
||||
m_RVO.solve_later();
|
||||
m_RVO.change_state([this]()
|
||||
{
|
||||
m_RVO.set_G_V_I(plib::reciprocal(m_model.m_ROL()), m_model.m_VOL, nlconst::zero());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,7 +119,6 @@ namespace netlist
|
||||
analog::NETLIB_SUB(twoterm) m_RVO;
|
||||
schmitt_trigger_model_t m_model;
|
||||
state_var<int> m_last_state;
|
||||
bool m_is_timestep;
|
||||
};
|
||||
|
||||
NETLIB_DEVICE_IMPL(schmitt_trigger, "SCHMITT_TRIGGER", "MODEL")
|
||||
|
@ -117,7 +117,6 @@ namespace netlist
|
||||
, m_RP(*this, "RP")
|
||||
, m_RN(*this, "RN")
|
||||
, m_last_state(*this, "m_last_var", -1)
|
||||
, m_is_timestep(false)
|
||||
{
|
||||
register_subalias("Q", m_RN.m_P);
|
||||
|
||||
@ -145,7 +144,6 @@ namespace netlist
|
||||
m_last_state = -1;
|
||||
m_RN.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()),
|
||||
logic_family()->low_offset_V(), nlconst::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
@ -158,28 +156,27 @@ namespace netlist
|
||||
const auto state = static_cast<int>(m_I());
|
||||
if (state != m_last_state)
|
||||
{
|
||||
// We only need to update the net first if this is a time stepping net
|
||||
if (m_is_timestep)
|
||||
// RN, RP are connected ...
|
||||
m_RN.change_state([this, &state]()
|
||||
{
|
||||
m_RN.solve_now(); // RN, RP are connected ...
|
||||
}
|
||||
if (state)
|
||||
{
|
||||
m_RN.set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
m_RP.set_G_V_I(plib::reciprocal(logic_family()->R_high()),
|
||||
logic_family()->high_offset_V(), nlconst::zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||
logic_family()->low_offset_V(), nlconst::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
}
|
||||
m_RN.solve_later(); // RN, RP are connected ...
|
||||
if (state)
|
||||
{
|
||||
|
||||
m_RN.set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
m_RP.set_G_V_I(plib::reciprocal(logic_family()->R_high()),
|
||||
logic_family()->high_offset_V(), nlconst::zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RN.set_G_V_I(plib::reciprocal(logic_family()->R_low()),
|
||||
logic_family()->low_offset_V(), nlconst::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
nlconst::zero(),
|
||||
nlconst::zero());
|
||||
}
|
||||
});
|
||||
m_last_state = state;
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,6 @@ namespace devices
|
||||
analog::NETLIB_NAME(twoterm) m_RP;
|
||||
analog::NETLIB_NAME(twoterm) m_RN;
|
||||
state_var<int> m_last_state;
|
||||
bool m_is_timestep;
|
||||
};
|
||||
|
||||
} // namespace devices
|
||||
|
@ -463,9 +463,10 @@ namespace devices
|
||||
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
|
||||
m_R.solve_now();
|
||||
m_R.set_R(R);
|
||||
m_R.solve_later();
|
||||
m_R.change_state([this, &R]()
|
||||
{
|
||||
m_R.set_R(R);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,18 +813,10 @@ namespace netlist
|
||||
|
||||
void terminal_t::solve_now()
|
||||
{
|
||||
const auto *solv(solver());
|
||||
// Nets may belong to railnets which do not have a solver attached
|
||||
if (this->has_net())
|
||||
if (net().solver() != nullptr)
|
||||
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);
|
||||
if (solv)
|
||||
solver()->solve_now();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
@ -798,6 +798,8 @@ namespace netlist
|
||||
|
||||
const analog_net_t & net() const noexcept;
|
||||
analog_net_t & net() noexcept;
|
||||
|
||||
solver::matrix_solver_t *solver() const noexcept;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -834,7 +836,6 @@ namespace netlist
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -945,6 +946,11 @@ namespace netlist
|
||||
solver::matrix_solver_t *solver() const noexcept { return m_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:
|
||||
state_var<nl_fptype> m_cur_Analog;
|
||||
solver::matrix_solver_t *m_solver;
|
||||
@ -1940,6 +1946,13 @@ namespace netlist
|
||||
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 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());
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// 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
|
||||
{
|
||||
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
|
||||
{
|
||||
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 -1;
|
||||
}
|
||||
|
@ -143,13 +143,11 @@ namespace solver
|
||||
|
||||
terminal_t **terms() noexcept { return m_terms.data(); }
|
||||
|
||||
template <typename FT, typename = std::enable_if<plib::is_floating_point<FT>::value, void>>
|
||||
FT getV() const noexcept { return static_cast<FT>(m_net->Q_Analog()); }
|
||||
nl_fptype getV() const noexcept { return m_net->Q_Analog(); }
|
||||
|
||||
template <typename FT, typename = std::enable_if<plib::is_floating_point<FT>::value, void>>
|
||||
void setV(FT v) noexcept { m_net->set_Q_Analog(static_cast<nl_fptype>(v)); }
|
||||
void setV(nl_fptype v) noexcept { m_net->set_Q_Analog(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; }
|
||||
|
||||
@ -191,6 +189,14 @@ namespace solver
|
||||
netlist_time solve(netlist_time_ext now);
|
||||
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 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.
|
||||
/// It's purpose is to bring voltage values to the current timestep.
|
||||
/// This will be called BEFORE updating object properties.
|
||||
void solve_now();
|
||||
|
||||
void update_after(netlist_time after) noexcept
|
||||
void solve_now()
|
||||
{
|
||||
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
|
||||
@ -413,7 +438,7 @@ namespace solver
|
||||
{
|
||||
const std::size_t iN = size();
|
||||
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
|
||||
// global tanh damping (4.197)
|
||||
@ -439,7 +464,7 @@ namespace solver
|
||||
const auto vntol(static_cast<float_type>(m_params.m_vntol));
|
||||
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 tol(vntol + reltol * std::max(plib::abs(vnew),plib::abs(vold)));
|
||||
if (plib::abs(vnew - vold) > tol)
|
||||
@ -455,7 +480,7 @@ namespace solver
|
||||
for (std::size_t k = 0; k < size(); 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
|
||||
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])));
|
||||
|
@ -183,30 +183,27 @@ namespace devices
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (net_count <= 64)
|
||||
if (net_count <= 64)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (net_count <= 256)
|
||||
if (net_count <= 256)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
return create_solver<FT, 0>(net_count, sname, nets);
|
||||
}
|
||||
return create_solver<FT, 0>(net_count, sname, nets);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user