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:
couriersud 2020-04-25 18:08:04 +02:00
parent 14f92c9786
commit d3ee7e21c6
16 changed files with 185 additions and 171 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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", "")

View File

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

View File

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

View File

@ -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")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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