netlist: MAJOR bug fix. Expect other bugs to surface. [Couriersud]

This commit fixes an issue with parsing netlists. To cut a long story
short: The separation of nets into independant groups of nets failed
under some circumstances for four terminal devices (controlled
voltage/current devices). Everything worked as long as an external
feedback loop existed. Without external feedback loop, the separation
would either fail or create "false" separated nets.
This fix also highlighted an issue with cmos switches (4066/4016).

There is a slight chance that other bugs may surface due to this change.
This commit is contained in:
couriersud 2020-01-26 21:22:13 +01:00
parent 3b55bb501f
commit 636894b02f
3 changed files with 41 additions and 11 deletions

View File

@ -23,6 +23,7 @@ namespace netlist
, m_R(*this, "R")
, m_control(*this, "CTL")
, m_base_r(*this, "BASER", nlconst::magic(270.0))
, m_last(*this, "m_last", false)
{
}
@ -34,7 +35,8 @@ namespace netlist
analog::NETLIB_SUB(R_base) m_R;
analog_input_t m_control;
param_fp_t m_base_r;
param_fp_t m_base_r;
state_var<bool> m_last;
};
NETLIB_RESET(CD4066_GATE)
@ -53,6 +55,7 @@ namespace netlist
nl_fptype in = m_control() - m_supply.GND().Q_Analog();
nl_fptype rON = m_base_r() * nlconst::magic(5.0) / sup;
nl_fptype R = -nlconst::one();
bool new_state(false);
if (in < low)
{
@ -61,10 +64,12 @@ namespace netlist
else if (in > high)
{
R = rON;
new_state = true;
}
//printf("%s %f %f %g\n", name().c_str(), sup, in, R);
if (R > nlconst::zero())
if (R > nlconst::zero() && (m_last != new_state))
{
m_last = new_state;
m_R.update();
m_R.set_R(R);
m_R.solve_later();

View File

@ -17,7 +17,7 @@
///
/// \brief Version - Minor.
///
#define NL_VERSION_MINOR 9
#define NL_VERSION_MINOR 10
/// \brief Version - Patch level.
///
#define NL_VERSION_PATCHLEVEL 0

View File

@ -253,28 +253,45 @@ namespace devices
struct net_splitter
{
bool already_processed(const analog_net_t &n) const
bool already_processed(const analog_net_t &n)
{
// no need to process rail nets - these are known variables
if (n.isRailNet())
return true;
// First check if it is in a previous group.
// In this case we need to merge this group into the current group
if (groupspre.size() > 1)
{
for (std::size_t i = 0; i<groupspre.size() - 1; i++)
if (plib::container::contains(groupspre[i], &n))
{
// copy all nets
for (auto & cn : groupspre[i])
if (!plib::container::contains(groupspre.back(), cn))
groupspre.back().push_back(cn);
// clear
groupspre[i].clear();
return true;
}
}
// if it's already processed - no need to continue
for (auto & grp : groups)
if (plib::container::contains(grp, &n))
return true;
if (!groupspre.empty() && plib::container::contains(groupspre.back(), &n))
return true;
return false;
}
void process_net(netlist_state_t &netlist, analog_net_t &n)
{
// ignore empty nets. FIXME: print a warning message
netlist.log().verbose("Net {}", n.name());
if (n.num_cons() == 0)
return;
// add the net
groups.back().push_back(&n);
groupspre.back().push_back(&n);
// process all terminals connected to this net
for (auto &term : n.core_terms())
{
netlist.log().verbose("Term {} {}", term->name(), (int) term->type());
// only process analog terminals
if (term->is_type(detail::terminal_type::TERMINAL))
{
@ -282,6 +299,7 @@ namespace devices
// check the connected terminal
// analog_net_t &connected_net = pt->connected_terminal()->net();
analog_net_t &connected_net = netlist.setup().get_connected_terminal(*pt)->net();
netlist.log().verbose(" Connected net {}", connected_net.name());
if (!already_processed(connected_net))
process_net(netlist, connected_net);
}
@ -292,22 +310,29 @@ namespace devices
{
for (auto & net : netlist.nets())
{
netlist.log().debug("processing {1}\n", net->name());
netlist.log().debug("processing {1}", net->name());
netlist.log().verbose("processing {1}", net->name());
if (!net->isRailNet() && net->num_cons() > 0)
{
netlist.log().debug(" ==> not a rail net\n");
netlist.log().debug(" ==> not a rail net");
netlist.log().verbose(" ==> not a rail net");
// Must be an analog net
auto &n = *static_cast<analog_net_t *>(net.get());
if (!already_processed(n))
{
groups.emplace_back(analog_net_t::list_t());
groupspre.emplace_back(analog_net_t::list_t());
process_net(netlist, n);
}
}
}
for (auto &g : groupspre)
if (!g.empty())
groups.push_back(g);
}
std::vector<analog_net_t::list_t> groups;
private:
std::vector<analog_net_t::list_t> groupspre;
};
void NETLIB_NAME(solver)::post_start()