summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/nl_setup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/nl_setup.cpp')
-rw-r--r--src/lib/netlist/nl_setup.cpp2079
1 files changed, 1026 insertions, 1053 deletions
diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp
index b98ed123a7b..d8040258568 100644
--- a/src/lib/netlist/nl_setup.cpp
+++ b/src/lib/netlist/nl_setup.cpp
@@ -35,7 +35,7 @@ namespace netlist
{
pstring alias_fqn = build_fqn(alias);
pstring out_fqn = build_fqn(out);
- register_alias_nofqn(alias_fqn, out_fqn);
+ register_alias_no_fqn(alias_fqn, out_fqn);
}
void nlparse_t::register_dip_alias_arr(const pstring &terms)
@@ -70,7 +70,7 @@ namespace netlist
void nlparse_t::register_dev(const pstring &classname, const pstring &name,
const std::vector<pstring> &params_and_connections,
- factory::element_t **felem)
+ factory::element_t **factory_element)
{
auto *f = factory().factory_by_name(classname);
@@ -98,25 +98,25 @@ namespace netlist
if (!params_and_connections.empty())
{
- auto ptok(params_and_connections.begin());
- auto ptok_end(params_and_connections.end());
+ auto token_ptr(params_and_connections.begin());
+ auto token_end(params_and_connections.end());
for (const pstring &tp : parameter_list)
{
if (plib::startsWith(tp, "+"))
{
- if (ptok == ptok_end)
+ if (token_ptr == token_end)
{
auto err = MF_PARAM_COUNT_MISMATCH_2(name, params_and_connections.size());
log().fatal(err);
throw nl_exception(err);
//break;
}
- pstring output_name = *ptok;
+ pstring output_name = *token_ptr;
log().debug("Link: {1} {2}", tp, output_name);
register_link(name + "." + tp.substr(1), output_name);
- ++ptok;
+ ++token_ptr;
}
else if (plib::startsWith(tp, "@"))
{
@@ -127,30 +127,30 @@ namespace netlist
}
else
{
- if (ptok == params_and_connections.end())
+ if (token_ptr == token_end)
{
auto err = MF_PARAM_COUNT_MISMATCH_2(name, params_and_connections.size());
log().fatal(err);
throw nl_exception(err);
}
- pstring paramfq = name + "." + tp;
+ pstring fully_qualified_name = name + "." + tp;
- log().debug("Default parameter: {1}\n", paramfq);
+ log().debug("Default parameter: {1}\n", fully_qualified_name);
- register_param(paramfq, *ptok);
+ register_param(fully_qualified_name, *token_ptr);
- ++ptok;
+ ++token_ptr;
}
}
- if (ptok != params_and_connections.end())
+ if (token_ptr != params_and_connections.end())
{
MF_PARAM_COUNT_EXCEEDED_2 err(name, params_and_connections.size());
log().fatal(err);
throw nl_exception(err);
}
}
- if (felem != nullptr)
- *felem = f;
+ if (factory_element != nullptr)
+ *factory_element = f;
}
void nlparse_t::register_hint(const pstring &object_name, const pstring &hint_name)
@@ -240,7 +240,7 @@ namespace netlist
{
if (idx->second.find("$(") == pstring::npos)
{
- //* There may be reason ... so make it an INFO
+ // There may be reason ... so make it an INFO
log().info(MI_OVERWRITING_PARAM_1_OLD_2_NEW_3(fqn,
idx->second, val));
}
@@ -248,7 +248,7 @@ namespace netlist
}
}
- void nlparse_t::register_defparam(const pstring &name, const pstring &def)
+ void nlparse_t::register_default_param(const pstring &name, const pstring &def)
{
// strip " from stringified strings
pstring val(def);
@@ -256,7 +256,7 @@ namespace netlist
val = def.substr(1, def.length() - 2);
// Replace "@." with the current namespace
val = plib::replace_all(val, "@.", namespace_prefix());
- m_abstract.m_defparams.emplace_back(namespace_prefix() + name, val);
+ m_abstract.m_default_params.emplace_back(namespace_prefix() + name, val);
}
factory::list_t &nlparse_t::factory() noexcept
@@ -284,17 +284,17 @@ namespace netlist
register_param(frontier_name + ".RIN", r_IN);
register_param(frontier_name + ".ROUT", r_OUT);
register_link(frontier_name + ".G", "GND");
- pstring attfn = build_fqn(attach);
+ pstring attach_fully_qualified_name = build_fqn(attach);
pstring front_fqn = build_fqn(frontier_name);
bool found = false;
for (auto & link : m_abstract.m_links)
{
- if (link.first == attfn)
+ if (link.first == attach_fully_qualified_name)
{
link.first = front_fqn + ".I";
found = true;
}
- else if (link.second == attfn)
+ else if (link.second == attach_fully_qualified_name)
{
link.second = front_fqn + ".I";
found = true;
@@ -329,7 +329,7 @@ namespace netlist
return namespace_prefix() + obj_name;
}
- void nlparse_t::register_alias_nofqn(const pstring &alias, const pstring &out)
+ void nlparse_t::register_alias_no_fqn(const pstring &alias, const pstring &out)
{
if (!m_abstract.m_alias.insert({alias, out}).second)
{
@@ -414,12 +414,12 @@ namespace netlist
void nlparse_t::remove_connections(const pstring &pin)
{
// FIXME: check use_cases - remove_connections may be dead
- pstring pinfn = build_fqn(pin);
+ pstring pin_fully_qualified_name = build_fqn(pin);
bool found = false;
for (auto link = m_abstract.m_links.begin(); link != m_abstract.m_links.end(); )
{
- if ((link->first == pinfn) || (link->second == pinfn))
+ if ((link->first == pin_fully_qualified_name) || (link->second == pin_fully_qualified_name))
{
log().verbose("removing connection: {1} <==> {2}\n", link->first, link->second);
link = m_abstract.m_links.erase(link);
@@ -451,7 +451,6 @@ namespace netlist
}
}
-
// ----------------------------------------------------------------------------------------
// Sources
// ----------------------------------------------------------------------------------------
@@ -469,1294 +468,1268 @@ namespace netlist
// setup_t
// ----------------------------------------------------------------------------------------
+ setup_t::setup_t(netlist_state_t &nlstate)
+ : m_abstract(nlstate.log())
+ , m_parser(nlstate.log(), m_abstract)
+ , m_nlstate(nlstate)
+ , m_models(m_abstract.m_models) // FIXME : parse abstract_t only
+ , m_netlist_params(nullptr)
+ , m_proxy_cnt(0)
+ {
+ }
-setup_t::setup_t(netlist_state_t &nlstate)
- : m_abstract(nlstate.log())
- , m_parser(nlstate.log(), m_abstract)
- , m_nlstate(nlstate)
- , m_models(m_abstract.m_models) // FIXME : parse abstract_t only
- , m_netlist_params(nullptr)
- , m_proxy_cnt(0)
-{
-}
-
-pstring setup_t::termtype_as_str(detail::core_terminal_t &in)
-{
- switch (in.type())
+ pstring setup_t::termtype_as_str(detail::core_terminal_t &in)
{
- case detail::terminal_type::TERMINAL:
- return "TERMINAL";
- case detail::terminal_type::INPUT:
- return "INPUT";
- case detail::terminal_type::OUTPUT:
- return "OUTPUT";
+ switch (in.type())
+ {
+ case detail::terminal_type::TERMINAL:
+ return "TERMINAL";
+ case detail::terminal_type::INPUT:
+ return "INPUT";
+ case detail::terminal_type::OUTPUT:
+ return "OUTPUT";
+ }
+ return "Error"; // Tease gcc
}
- return "Error"; // Tease gcc
-}
-pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def) const
-{
- // When `get_intial_param_val` is called the parameter `<name>` is already registered
- // and the value `(value_string())` is set to the default value, e.g. "74XX"
- // If thus `$(IC5E.A.MODEL)` is given for `name=="IC5E.A.MODEL"` `value_string()` below
- // will return the default.
- // FIXME: It may be more explicit and stable to test if pattern==name and return
- // `def` in this case.
-
- auto i = m_abstract.m_param_values.find(name);
- auto found_pat(false);
- pstring v = (i == m_abstract.m_param_values.end()) ? def : i->second;
-
- do
- {
- found_pat = false;
- auto sp(plib::psplit(v, std::vector<pstring>({"$(", ")"})));
- std::size_t p(0);
- v = "";
- while (p < sp.size())
- {
- if (sp[p] == "$(")
+ pstring setup_t::get_initial_param_val(const pstring &name, const pstring &def) const
+ {
+ // When `get_intial_param_val` is called the parameter `<name>` is already registered
+ // and the value `(value_string())` is set to the default value, e.g. "74XX"
+ // If thus `$(IC5E.A.MODEL)` is given for `name=="IC5E.A.MODEL"` `value_string()` below
+ // will return the default.
+ // FIXME: It may be more explicit and stable to test if pattern==name and return
+ // `def` in this case.
+
+ auto i = m_abstract.m_param_values.find(name);
+ auto found_pat(false);
+ pstring v = (i == m_abstract.m_param_values.end()) ? def : i->second;
+
+ do
+ {
+ found_pat = false;
+ auto sp(plib::psplit(v, std::vector<pstring>({"$(", ")"})));
+ std::size_t p(0);
+ v = "";
+ while (p < sp.size())
{
- p++;
- pstring r;
- while (p < sp.size() && sp[p] != ")")
- r += sp[p++];
- p++;
- auto k = m_params.find(r);
- if (k != m_params.end())
+ if (sp[p] == "$(")
{
- v = v + k->second.param().value_string();
- found_pat = true;
+ p++;
+ pstring r;
+ while (p < sp.size() && sp[p] != ")")
+ r += sp[p++];
+ p++;
+ auto k = m_params.find(r);
+ if (k != m_params.end())
+ {
+ v = v + k->second.param().value_string();
+ found_pat = true;
+ }
+ else
+ {
+ // pass - on
+ v = v + "$(" + r + ")";
+ }
}
else
- {
- // pass - on
- v = v + "$(" + r + ")";
- }
+ v += sp[p++];
}
- else
- v += sp[p++];
- }
- } while (found_pat);
+ } while (found_pat);
- return v;
-}
+ return v;
+ }
-void setup_t::register_term(detail::core_terminal_t &term)
-{
- log().debug("{1} {2}\n", termtype_as_str(term), term.name());
- if (!m_terminals.insert({term.name(), &term}).second)
+ void setup_t::register_term(detail::core_terminal_t &term)
{
- log().fatal(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name()));
- throw nl_exception(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name()));
+ log().debug("{1} {2}\n", termtype_as_str(term), term.name());
+ if (!m_terminals.insert({term.name(), &term}).second)
+ {
+ log().fatal(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name()));
+ throw nl_exception(MF_ADDING_1_2_TO_TERMINAL_LIST(termtype_as_str(term), term.name()));
+ }
}
-}
-void setup_t::register_term(terminal_t &term, terminal_t *other_term, const std::array<terminal_t *, 2> &splitter_terms)
-{
- this->register_term(term);
- m_connected_terminals.insert({&term, {other_term, splitter_terms[0], splitter_terms[1], nullptr}});
-}
+ void setup_t::register_term(terminal_t &term, terminal_t *other_term, const std::array<terminal_t *, 2> &splitter_terms)
+ {
+ this->register_term(term);
+ m_connected_terminals.insert({&term, {other_term, splitter_terms[0], splitter_terms[1], nullptr}});
+ }
-void setup_t::register_param_t(param_t &param)
-{
- if (!m_params.insert({param.name(), param_ref_t(param.device(), param)}).second)
+ void setup_t::register_param_t(param_t &param)
{
- log().fatal(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name()));
- throw nl_exception(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name()));
+ if (!m_params.insert({param.name(), param_ref_t(param.device(), param)}).second)
+ {
+ log().fatal(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name()));
+ throw nl_exception(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param.name()));
+ }
}
-}
-pstring setup_t::resolve_alias(const pstring &name) const
-{
- pstring temp = name;
- pstring ret;
+ pstring setup_t::resolve_alias(const pstring &name) const
+ {
+ pstring temp = name;
+ pstring ret;
- // FIXME: Detect endless loop
- do {
- ret = temp;
- auto p = m_abstract.m_alias.find(ret);
- temp = (p != m_abstract.m_alias.end() ? p->second : "");
- } while (!temp.empty() && temp != ret);
+ // FIXME: Detect endless loop
+ do {
+ ret = temp;
+ auto p = m_abstract.m_alias.find(ret);
+ temp = (p != m_abstract.m_alias.end() ? p->second : "");
+ } while (!temp.empty() && temp != ret);
- log().debug("{1}==>{2}\n", name, ret);
- return ret;
-}
+ log().debug("{1}==>{2}\n", name, ret);
+ return ret;
+ }
-pstring setup_t::de_alias(const pstring &alias) const
-{
- pstring temp = alias;
- pstring ret;
+ pstring setup_t::de_alias(const pstring &alias) const
+ {
+ pstring temp = alias;
+ pstring ret;
- // FIXME: Detect endless loop
- do {
- ret = temp;
- temp = "";
- for (const auto &e : m_abstract.m_alias)
- {
- // FIXME: this will resolve first one found
- if (e.second == ret)
+ // FIXME: Detect endless loop
+ do {
+ ret = temp;
+ temp = "";
+ for (const auto &e : m_abstract.m_alias)
{
- temp = e.first;
- break;
+ // FIXME: this will resolve first one found
+ if (e.second == ret)
+ {
+ temp = e.first;
+ break;
+ }
}
- }
- } while (!temp.empty() && temp != ret);
+ } while (!temp.empty() && temp != ret);
- log().debug("{1}==>{2}\n", alias, ret);
- return ret;
-}
+ log().debug("{1}==>{2}\n", alias, ret);
+ return ret;
+ }
-std::vector<pstring> setup_t::get_terminals_for_device_name(const pstring &devname) const
-{
- std::vector<pstring> terms;
- for (const auto & t : m_terminals)
+ std::vector<pstring> setup_t::get_terminals_for_device_name(const pstring &devname) const
{
- if (plib::startsWith(t.second->name(), devname))
+ std::vector<pstring> terms;
+ for (const auto & t : m_terminals)
{
- pstring tn(t.second->name().substr(devname.length()+1));
- if (tn.find('.') == pstring::npos)
- terms.push_back(tn);
+ if (plib::startsWith(t.second->name(), devname))
+ {
+ pstring tn(t.second->name().substr(devname.length()+1));
+ if (tn.find('.') == pstring::npos)
+ terms.push_back(tn);
+ }
}
- }
- for (const auto & t : m_abstract.m_alias)
- {
- if (plib::startsWith(t.first, devname))
+ for (const auto & t : m_abstract.m_alias)
{
- pstring tn(t.first.substr(devname.length()+1));
- if (tn.find('.') == pstring::npos)
+ if (plib::startsWith(t.first, devname))
{
- terms.push_back(tn);
- pstring resolved = resolve_alias(t.first);
- if (resolved != t.first)
+ pstring tn(t.first.substr(devname.length()+1));
+ if (tn.find('.') == pstring::npos)
{
- auto found = std::find(terms.begin(), terms.end(), resolved.substr(devname.length()+1));
- if (found!=terms.end())
- terms.erase(found);
+ terms.push_back(tn);
+ pstring resolved = resolve_alias(t.first);
+ if (resolved != t.first)
+ {
+ auto found = std::find(terms.begin(), terms.end(), resolved.substr(devname.length()+1));
+ if (found!=terms.end())
+ terms.erase(found);
+ }
}
}
}
+ return terms;
}
- return terms;
-}
-detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, bool required) const
-{
- const pstring &tname = resolve_alias(terminal_in);
- auto ret = m_terminals.find(tname);
- // look for default
- if (ret == m_terminals.end())
+ detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in, bool required) const
{
- // look for ".Q" std output
- ret = m_terminals.find(tname + ".Q");
- }
-
- detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second);
+ const pstring &tname = resolve_alias(terminal_in);
+ auto ret = m_terminals.find(tname);
+ // look for default
+ if (ret == m_terminals.end())
+ {
+ // look for ".Q" std output
+ ret = m_terminals.find(tname + ".Q");
+ }
- if (term == nullptr && required)
- {
- log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
- throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
- }
- if (term != nullptr)
- {
- log().debug("Found input {1}\n", tname);
- }
+ detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second);
- return term;
-}
+ if (term == nullptr && required)
+ {
+ log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
+ throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
+ }
+ if (term != nullptr)
+ {
+ log().debug("Found input {1}\n", tname);
+ }
-detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in,
- detail::terminal_type atype, bool required) const
-{
- const pstring &tname = resolve_alias(terminal_in);
- auto ret = m_terminals.find(tname);
- // look for default
- if (ret == m_terminals.end() && atype == detail::terminal_type::OUTPUT)
- {
- // look for ".Q" std output
- ret = m_terminals.find(tname + ".Q");
+ return term;
}
- if (ret == m_terminals.end() && required)
- {
- log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
- throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
- }
- detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second);
- if (term != nullptr && term->type() != atype)
+ detail::core_terminal_t *setup_t::find_terminal(const pstring &terminal_in,
+ detail::terminal_type atype, bool required) const
{
- if (required)
+ const pstring &tname = resolve_alias(terminal_in);
+ auto ret = m_terminals.find(tname);
+ // look for default
+ if (ret == m_terminals.end() && atype == detail::terminal_type::OUTPUT)
+ {
+ // look for ".Q" std output
+ ret = m_terminals.find(tname + ".Q");
+ }
+ if (ret == m_terminals.end() && required)
{
- log().fatal(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname));
- throw nl_exception(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname));
+ log().fatal(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
+ throw nl_exception(MF_TERMINAL_1_2_NOT_FOUND(terminal_in, tname));
}
+ detail::core_terminal_t *term = (ret == m_terminals.end() ? nullptr : ret->second);
- term = nullptr;
- }
- if (term != nullptr)
- log().debug("Found input {1}\n", tname);
+ if (term != nullptr && term->type() != atype)
+ {
+ if (required)
+ {
+ log().fatal(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname));
+ throw nl_exception(MF_OBJECT_1_2_WRONG_TYPE(terminal_in, tname));
+ }
- return term;
-}
+ term = nullptr;
+ }
+ if (term != nullptr)
+ log().debug("Found input {1}\n", tname);
-param_ref_t setup_t::find_param(const pstring &param_in) const
-{
- const pstring resolved_param_name(resolve_alias(param_in));
- auto ret(m_params.find(resolved_param_name));
- if (ret == m_params.end())
+ return term;
+ }
+
+ param_ref_t setup_t::find_param(const pstring &param_in) const
{
- log().fatal(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name));
- throw nl_exception(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name));
+ const pstring resolved_param_name(resolve_alias(param_in));
+ auto ret(m_params.find(resolved_param_name));
+ if (ret == m_params.end())
+ {
+ log().fatal(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name));
+ throw nl_exception(MF_PARAMETER_1_2_NOT_FOUND(param_in, resolved_param_name));
+ }
+ return ret->second;
}
- return ret->second;
-}
+ //NOLINTNEXTLINE(misc-no-recursion)
+ devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &out)
+ {
+ gsl_Expects(out.is_logic());
-//NOLINTNEXTLINE(misc-no-recursion)
-devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &out)
-{
- gsl_Expects(out.is_logic());
+ const auto &out_cast = dynamic_cast<const logic_output_t &>(out);
+ auto iter_proxy(m_proxies.find(&out));
- const auto &out_cast = dynamic_cast<const logic_output_t &>(out);
- auto iter_proxy(m_proxies.find(&out));
+ if (iter_proxy != m_proxies.end())
+ return iter_proxy->second;
- if (iter_proxy != m_proxies.end())
- return iter_proxy->second;
+ // create a new one ...
+ pstring x = plib::pfmt("proxy_da_{1}_{2}")(out.name())(m_proxy_cnt);
+ auto new_proxy =
+ out_cast.logic_family()->create_d_a_proxy(m_nlstate, x, &out_cast);
+ m_proxy_cnt++;
+ // connect all existing terminals to new net
- // create a new one ...
- pstring x = plib::pfmt("proxy_da_{1}_{2}")(out.name())(m_proxy_cnt);
- auto new_proxy =
- out_cast.logic_family()->create_d_a_proxy(m_nlstate, x, &out_cast);
- m_proxy_cnt++;
- // connect all existing terminals to new net
+ // Get a copy first
+ auto temp_terminals(out.net().core_terms_copy());
+ // remove all terminals from out.net()
+ out.net().remove_all_terminals();
- for (auto & p : nlstate().core_terms(out.net()))
- {
- p->clear_net(); // de-link from all nets ...
- if (!connect(new_proxy->proxy_term(), *p))
+ for (detail::core_terminal_t * p : temp_terminals)
{
- log().fatal(MF_CONNECTING_1_TO_2(
- new_proxy->proxy_term().name(), (*p).name()));
- throw nl_exception(MF_CONNECTING_1_TO_2(
- new_proxy->proxy_term().name(), (*p).name()));
+ p->clear_net(); // de-link from all nets ...
+ if (!connect(new_proxy->proxy_term(), *p))
+ {
+ log().fatal(MF_CONNECTING_1_TO_2(
+ new_proxy->proxy_term().name(), (*p).name()));
+ throw nl_exception(MF_CONNECTING_1_TO_2(
+ new_proxy->proxy_term().name(), (*p).name()));
+ }
}
- }
- nlstate().core_terms(out.net()).clear();
- add_terminal(out.net(), new_proxy->in());
+ out.net().add_terminal(new_proxy->in());
- auto *proxy(new_proxy.get());
- if (!m_proxies.insert({&out, proxy}).second)
- throw nl_exception(MF_DUPLICATE_PROXY_1(out.name()));
+ auto *proxy(new_proxy.get());
+ if (!m_proxies.insert({&out, proxy}).second)
+ throw nl_exception(MF_DUPLICATE_PROXY_1(out.name()));
- m_nlstate.register_device(new_proxy->name(), std::move(new_proxy));
- return proxy;
-
-}
+ m_nlstate.register_device(new_proxy->name(), std::move(new_proxy));
+ return proxy;
+ }
-//NOLINTNEXTLINE(misc-no-recursion)
-devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
-{
- gsl_Expects(inp.is_logic());
+ //NOLINTNEXTLINE(misc-no-recursion)
+ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
+ {
+ gsl_Expects(inp.is_logic());
- const auto &incast = dynamic_cast<const logic_input_t &>(inp);
+ const auto &logic_input_terminal = dynamic_cast<const logic_input_t &>(inp);
- auto iter_proxy(m_proxies.find(&inp));
+ auto iter_proxy(m_proxies.find(&inp));
- if (iter_proxy != m_proxies.end())
- return iter_proxy->second;
+ if (iter_proxy != m_proxies.end())
+ return iter_proxy->second;
- log().debug("connect_terminal_input: connecting proxy\n");
- auto new_proxy = incast.logic_family()->create_a_d_proxy(m_nlstate,
- plib::pfmt("proxy_ad_{1}_{2}")(inp.name())(m_proxy_cnt), &incast);
+ log().debug("connect_terminal_input: connecting proxy\n");
+ auto new_proxy =
+ logic_input_terminal.logic_family()->create_a_d_proxy(m_nlstate,
+ plib::pfmt("proxy_ad_{1}_{2}")(inp.name())(m_proxy_cnt),
+ &logic_input_terminal);
- auto *ret(new_proxy.get());
+ auto *ret(new_proxy.get());
- if (!m_proxies.insert({&inp, ret}).second)
- throw nl_exception(MF_DUPLICATE_PROXY_1(inp.name()));
+ if (!m_proxies.insert({&inp, ret}).second)
+ throw nl_exception(MF_DUPLICATE_PROXY_1(inp.name()));
- m_proxy_cnt++;
+ m_proxy_cnt++;
- // connect all existing terminals to new net
+ // connect all existing terminals to new net
- if (inp.has_net())
- {
- for (detail::core_terminal_t * p : nlstate().core_terms(inp.net()))
+ if (inp.has_net())
{
- // inp may already belongs to the logic net. Thus skip it here.
- // It will be removed by the clear further down.
- if (p != &inp)
+ auto temp_terminals(inp.net().core_terms_copy());
+
+ inp.net().remove_all_terminals();
+
+ for (detail::core_terminal_t * p : temp_terminals)
{
- p->clear_net(); // de-link from all nets ...
- if (!connect(ret->proxy_term(), *p))
+ // inp may already belongs to the logic net. Thus skip it here.
+ // It will be removed by the clear further down.
+ if (p != &inp)
{
- log().fatal(MF_CONNECTING_1_TO_2(
- ret->proxy_term().name(), (*p).name()));
- throw nl_exception(MF_CONNECTING_1_TO_2(
- ret->proxy_term().name(), (*p).name()));
+ p->clear_net(); // de-link from all nets ...
+ if (!connect(ret->proxy_term(), *p))
+ {
+ log().fatal(MF_CONNECTING_1_TO_2(
+ ret->proxy_term().name(), (*p).name()));
+ throw nl_exception(MF_CONNECTING_1_TO_2(
+ ret->proxy_term().name(), (*p).name()));
+ }
}
}
}
- nlstate().core_terms(inp.net()).clear(); // clear the list
+ inp.clear_net();
+ ret->out().net().add_terminal(inp);
+ m_nlstate.register_device(new_proxy->name(), std::move(new_proxy));
+ return ret;
}
- inp.clear_net();
- add_terminal(ret->out().net(), inp);
- m_nlstate.register_device(new_proxy->name(), std::move(new_proxy));
- return ret;
-}
-detail::core_terminal_t &setup_t::resolve_proxy(detail::core_terminal_t &term)
-{
- if (term.is_logic())
+ detail::core_terminal_t &setup_t::resolve_proxy(detail::core_terminal_t &term)
{
- const auto &out = dynamic_cast<const logic_t &>(term);
- auto iter_proxy(m_proxies.find(&out));
- if (iter_proxy != m_proxies.end())
- return iter_proxy->second->proxy_term();
+ if (term.is_logic())
+ {
+ const auto &out = dynamic_cast<const logic_t &>(term);
+ auto iter_proxy(m_proxies.find(&out));
+ if (iter_proxy != m_proxies.end())
+ return iter_proxy->second->proxy_term();
+ }
+ return term;
}
- return term;
-}
-
-//NOLINTNEXTLINE(misc-no-recursion)
-void setup_t::merge_nets(detail::net_t &this_net, detail::net_t &other_net)
-{
- log().debug("merging nets ...\n");
- if (&other_net == &this_net)
+ //NOLINTNEXTLINE(misc-no-recursion)
+ void setup_t::merge_nets(detail::net_t &this_net, detail::net_t &other_net)
{
- log().warning(MW_CONNECTING_1_TO_ITSELF(this_net.name()));
- return; // Nothing to do
- }
+ log().debug("merging nets ...\n");
+ if (&other_net == &this_net)
+ {
+ log().warning(MW_CONNECTING_1_TO_ITSELF(this_net.name()));
+ return; // Nothing to do
+ }
- if (this_net.is_rail_net() && other_net.is_rail_net())
- {
- log().fatal(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name()));
- throw nl_exception(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name()));
- }
+ if (this_net.is_rail_net() && other_net.is_rail_net())
+ {
+ log().fatal(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name()));
+ throw nl_exception(MF_MERGE_RAIL_NETS_1_AND_2(this_net.name(), other_net.name()));
+ }
- if (other_net.is_rail_net())
- {
- log().debug("other net is a rail net\n");
- merge_nets(other_net, this_net);
- }
- else
- {
- move_connections(other_net, this_net);
+ if (other_net.is_rail_net())
+ {
+ log().debug("other net is a rail net\n");
+ merge_nets(other_net, this_net);
+ }
+ else
+ {
+ move_connections(other_net, this_net);
+ }
}
-}
-
-//NOLINTNEXTLINE(misc-no-recursion)
-void setup_t::connect_input_output(detail::core_terminal_t &in, detail::core_terminal_t &out)
-{
- if (out.is_analog() && in.is_logic())
+ //NOLINTNEXTLINE(misc-no-recursion)
+ void setup_t::connect_input_output(detail::core_terminal_t &in, detail::core_terminal_t &out)
{
- auto *proxy = get_a_d_proxy(in);
+ if (out.is_analog() && in.is_logic())
+ {
+ auto *proxy = get_a_d_proxy(in);
- add_terminal(out.net(), proxy->proxy_term());
- }
- else if (out.is_logic() && in.is_analog())
- {
- devices::nld_base_proxy *proxy = get_d_a_proxy(out);
+ out.net().add_terminal(proxy->proxy_term());
+ }
+ else if (out.is_logic() && in.is_analog())
+ {
+ devices::nld_base_proxy *proxy = get_d_a_proxy(out);
- connect_terminals(proxy->proxy_term(), in);
- //proxy->out().net().register_con(in);
- }
- else
- {
- if (in.has_net())
- merge_nets(out.net(), in.net());
+ connect_terminals(proxy->proxy_term(), in);
+ //proxy->out().net().register_con(in);
+ }
else
- add_terminal(out.net(), in);
+ {
+ if (in.has_net())
+ merge_nets(out.net(), in.net());
+ else
+ out.net().add_terminal(in);
+ }
}
-}
-
-//NOLINTNEXTLINE(misc-no-recursion)
-void setup_t::connect_terminal_input(terminal_t &term, detail::core_terminal_t &inp)
-{
- if (inp.is_analog())
+ //NOLINTNEXTLINE(misc-no-recursion)
+ void setup_t::connect_terminal_input(terminal_t &term, detail::core_terminal_t &inp)
{
- connect_terminals(inp, term);
- }
- else if (inp.is_logic())
- {
- log().verbose("connect terminal {1} (in, {2}) to {3}\n", inp.name(),
- inp.is_analog() ? "analog" : inp.is_logic() ? "logic" : "?", term.name());
- auto *proxy = get_a_d_proxy(inp);
+ if (inp.is_analog())
+ {
+ connect_terminals(inp, term);
+ }
+ else if (inp.is_logic())
+ {
+ log().verbose("connect terminal {1} (in, {2}) to {3}\n", inp.name(),
+ inp.is_analog() ? "analog" : inp.is_logic() ? "logic" : "?", term.name());
+ auto *proxy = get_a_d_proxy(inp);
- //out.net().register_con(proxy->proxy_term());
- connect_terminals(term, proxy->proxy_term());
+ //out.net().register_con(proxy->proxy_term());
+ connect_terminals(term, proxy->proxy_term());
+ }
+ else
+ {
+ log().fatal(MF_OBJECT_INPUT_TYPE_1(inp.name()));
+ throw nl_exception(MF_OBJECT_INPUT_TYPE_1(inp.name()));
+ }
}
- else
- {
- log().fatal(MF_OBJECT_INPUT_TYPE_1(inp.name()));
- throw nl_exception(MF_OBJECT_INPUT_TYPE_1(inp.name()));
- }
-}
-
-//NOLINTNEXTLINE(misc-no-recursion)
-void setup_t::connect_terminal_output(terminal_t &in, detail::core_terminal_t &out)
-{
- if (out.is_analog())
+ //NOLINTNEXTLINE(misc-no-recursion)
+ void setup_t::connect_terminal_output(terminal_t &in, detail::core_terminal_t &out)
{
- log().debug("connect_terminal_output: {1} {2}\n", in.name(), out.name());
- // no proxy needed, just merge existing terminal net
- if (in.has_net())
+ if (out.is_analog())
{
- if (&out.net() != &in.net())
- merge_nets(out.net(), in.net());
+ log().debug("connect_terminal_output: {1} {2}\n", in.name(), out.name());
+ // no proxy needed, just merge existing terminal net
+ if (in.has_net())
+ {
+ if (&out.net() != &in.net())
+ merge_nets(out.net(), in.net());
+ else
+ // Only an info - some ICs (CD4538) connect pins internally to GND
+ // and the schematics again externally. This will cause this warning.
+ // FIXME: Add a hint to suppress the warning.
+ log().info(MI_CONNECTING_1_TO_2_SAME_NET(in.name(), out.name(), in.net().name()));
+ }
else
- // Only an info - some ICs (CD4538) connect pins internally to GND
- // and the schematics again externally. This will cause this warning.
- // FIXME: Add a hint to suppress the warning.
- log().info(MI_CONNECTING_1_TO_2_SAME_NET(in.name(), out.name(), in.net().name()));
+ out.net().add_terminal(in);
}
- else
- add_terminal(out.net(), in);
- }
- else if (out.is_logic())
- {
- log().debug("connect_terminal_output: connecting proxy\n");
- devices::nld_base_proxy *proxy = get_d_a_proxy(out);
+ else if (out.is_logic())
+ {
+ log().debug("connect_terminal_output: connecting proxy\n");
+ devices::nld_base_proxy *proxy = get_d_a_proxy(out);
- connect_terminals(proxy->proxy_term(), in);
- }
- else
- {
- log().fatal(MF_OBJECT_OUTPUT_TYPE_1(out.name()));
- throw nl_exception(MF_OBJECT_OUTPUT_TYPE_1(out.name()));
+ connect_terminals(proxy->proxy_term(), in);
+ }
+ else
+ {
+ log().fatal(MF_OBJECT_OUTPUT_TYPE_1(out.name()));
+ throw nl_exception(MF_OBJECT_OUTPUT_TYPE_1(out.name()));
+ }
}
-}
-void setup_t::connect_terminals(detail::core_terminal_t &t1,detail::core_terminal_t &t2)
-{
- if (t1.has_net() && t2.has_net())
- {
- log().debug("T2 and T1 have net\n");
- merge_nets(t1.net(), t2.net());
- }
- else if (t2.has_net())
- {
- log().debug("T2 has net\n");
- add_terminal(t2.net(), t1);
- }
- else if (t1.has_net())
+ void setup_t::connect_terminals(detail::core_terminal_t &t1,detail::core_terminal_t &t2)
{
- log().debug("T1 has net\n");
- add_terminal(t1.net(), t2);
- }
- else
- {
- log().debug("adding analog net ...\n");
- // FIXME: Nets should have a unique name
- auto anet = plib::make_owned<analog_net_t>(nlstate().pool(), m_nlstate,"net." + t1.name());
- auto *anetp = anet.get();
- m_nlstate.register_net(std::move(anet));
- t1.set_net(anetp);
- add_terminal(*anetp, t2);
- add_terminal(*anetp, t1);
+ if (t1.has_net() && t2.has_net())
+ {
+ log().debug("T2 and T1 have net\n");
+ merge_nets(t1.net(), t2.net());
+ }
+ else if (t2.has_net())
+ {
+ log().debug("T2 has net\n");
+ t2.net().add_terminal(t1);
+ }
+ else if (t1.has_net())
+ {
+ log().debug("T1 has net\n");
+ t1.net().add_terminal(t2);
+ }
+ else
+ {
+ log().debug("adding analog net ...\n");
+ // FIXME: Nets should have a unique name
+ auto new_net_uptr = plib::make_owned<analog_net_t>(nlstate().pool(), m_nlstate,"net." + t1.name());
+ auto *new_net_ptr = new_net_uptr.get();
+ m_nlstate.register_net(std::move(new_net_uptr));
+ t1.set_net(new_net_ptr);
+ new_net_ptr->add_terminal(t2);
+ new_net_ptr->add_terminal(t1);
+ }
}
-}
-//NOLINTNEXTLINE(misc-no-recursion)
-bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_terminal_t &t2)
-{
- bool ret = false;
- if (t1.has_net())
+ //NOLINTNEXTLINE(misc-no-recursion)
+ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_terminal_t &t2)
{
- if (t1.net().is_rail_net())
- ret = connect(t2, t1.net().rail_terminal());
- if (!ret)
+ bool ret = false;
+ if (t1.has_net())
{
- for (auto & t : nlstate().core_terms(t1.net()))
+ if (t1.net().is_rail_net())
+ ret = connect(t2, t1.net().rail_terminal());
+ if (!ret)
{
- if (t->is_type(detail::terminal_type::TERMINAL))
- ret = connect(t2, *t);
- if (ret)
- break;
+ for (detail::core_terminal_t * t : t1.net().core_terms_copy())
+ {
+ if (t->is_type(detail::terminal_type::TERMINAL))
+ ret = connect(t2, *t);
+ if (ret)
+ break;
+ }
}
}
- }
- if (!ret && t2.has_net())
- {
- if (t2.net().is_rail_net())
- ret = connect(t1, t2.net().rail_terminal());
- if (!ret)
+ if (!ret && t2.has_net())
{
- for (auto & t : nlstate().core_terms(t2.net()))
+ if (t2.net().is_rail_net())
+ ret = connect(t1, t2.net().rail_terminal());
+ if (!ret)
{
- if (t->is_type(detail::terminal_type::TERMINAL))
- ret = connect(t1, *t);
- if (ret)
- break;
+ for (detail::core_terminal_t * t : t2.net().core_terms_copy())
+ {
+ if (t->is_type(detail::terminal_type::TERMINAL))
+ ret = connect(t1, *t);
+ if (ret)
+ break;
+ }
}
}
+ return ret;
}
- return ret;
-}
-
-//NOLINTNEXTLINE(misc-no-recursion)
-bool setup_t::connect(detail::core_terminal_t &t1_in, detail::core_terminal_t &t2_in)
-{
- log().debug("Connecting {1} to {2}\n", t1_in.name(), t2_in.name());
- detail::core_terminal_t &t1 = resolve_proxy(t1_in);
- detail::core_terminal_t &t2 = resolve_proxy(t2_in);
- bool ret = true;
-
- if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::INPUT))
+ //NOLINTNEXTLINE(misc-no-recursion)
+ bool setup_t::connect(detail::core_terminal_t &t1_in, detail::core_terminal_t &t2_in)
{
- if (t2.has_net() && t2.net().is_rail_net())
+ log().debug("Connecting {1} to {2}\n", t1_in.name(), t2_in.name());
+ detail::core_terminal_t &t1 = resolve_proxy(t1_in);
+ detail::core_terminal_t &t2 = resolve_proxy(t2_in);
+ bool ret = true;
+
+ if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::INPUT))
{
- log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t2.name()));
- throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t2.name()));
+ if (t2.has_net() && t2.net().is_rail_net())
+ {
+ log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t2.name()));
+ throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t2.name()));
+ }
+ connect_input_output(t2, t1);
}
- connect_input_output(t2, t1);
- }
- else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::OUTPUT))
- {
- if (t1.has_net() && t1.net().is_rail_net())
+ else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::OUTPUT))
{
- log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t1.name()));
- throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t1.name()));
+ if (t1.has_net() && t1.net().is_rail_net())
+ {
+ log().fatal(MF_INPUT_1_ALREADY_CONNECTED(t1.name()));
+ throw nl_exception(MF_INPUT_1_ALREADY_CONNECTED(t1.name()));
+ }
+ connect_input_output(t1, t2);
}
- connect_input_output(t1, t2);
- }
- else if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::TERMINAL))
- {
- connect_terminal_output(dynamic_cast<terminal_t &>(t2), t1);
- }
- else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::OUTPUT))
- {
- connect_terminal_output(dynamic_cast<terminal_t &>(t1), t2);
- }
- else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::TERMINAL))
- {
- connect_terminal_input(dynamic_cast<terminal_t &>(t2), t1);
- }
- else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::INPUT))
- {
- connect_terminal_input(dynamic_cast<terminal_t &>(t1), t2);
- }
- else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::TERMINAL))
- {
- connect_terminals(dynamic_cast<terminal_t &>(t1), dynamic_cast<terminal_t &>(t2));
- }
- else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::INPUT))
- {
- ret = connect_input_input(t1, t2);
- }
- else
- {
- ret = false;
- }
- return ret;
-}
-
-void setup_t::resolve_inputs()
-{
- log().verbose("Resolving inputs ...");
-
- // Netlist can directly connect input to input.
- // We therefore first park connecting inputs and retry
- // after all other terminals were connected.
-
- unsigned tries = m_netlist_params->m_max_link_loops();
-#if 0
- // This code fails for some netlists when the element at position 0
- // is deleted. It will fail somewhere deep in std::pair releasing
- // std::string called from erase.
- //
- // One example is the this netlist:
- //
- // #include "netlist/devices/net_lib.h"
- // NETLIST_START(charge_discharge)
- // SOLVER(solver, 48000) // Fixed frequency solver
- // CLOCK(I, 200) // 200 Hz clock as input, TTL logic output
- // RES(R, RES_K(1))
- // CAP(C, CAP_U(1))
- //
- // NET_C(I.Q, R.1)
- // NET_C(R.2, C.1)
- // NET_C(C.2, GND)
- //
- // ALIAS(O, R.2) // Output O == C.1 == R.2
- // // NETLIST_END()
- //
- // Just save the net list as /tmp/test1.cpp, run
- // ./nltool --cmd=run -t 0.05 -l O -l I /tmp/test1.cpp
- // and see it crash with this code enabled.
- //
- // g++-7 (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0
- //
- while (!m_links.empty() && tries > 0)
- {
- auto li = m_links.begin();
- while (li != m_links.end())
+ else if (t1.is_type(detail::terminal_type::OUTPUT) && t2.is_type(detail::terminal_type::TERMINAL))
{
- const pstring t1s = li->first;
- const pstring t2s = li->second;
- detail::core_terminal_t *t1 = find_terminal(t1s);
- detail::core_terminal_t *t2 = find_terminal(t2s);
-
- if (connect(*t1, *t2))
- li = m_links.erase(li);
- else
- li++;
+ connect_terminal_output(dynamic_cast<terminal_t &>(t2), t1);
}
- tries--;
- }
-#else
- while (!m_abstract.m_links.empty() && tries > 0)
- {
- for (std::size_t i = 0; i < m_abstract.m_links.size(); )
+ else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::OUTPUT))
{
- const pstring t1s(m_abstract.m_links[i].first);
- const pstring t2s(m_abstract.m_links[i].second);
- detail::core_terminal_t *t1 = find_terminal(t1s);
- detail::core_terminal_t *t2 = find_terminal(t2s);
- if (connect(*t1, *t2))
- m_abstract.m_links.erase(m_abstract.m_links.begin() + plib::narrow_cast<std::ptrdiff_t>(i));
- else
- i++;
+ connect_terminal_output(dynamic_cast<terminal_t &>(t1), t2);
}
- tries--;
- }
-#endif
- if (tries == 0)
- {
- for (auto & link : m_abstract.m_links)
- log().warning(MF_CONNECTING_1_TO_2(de_alias(link.first), de_alias(link.second)));
-
- log().fatal(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops()));
- throw nl_exception(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops()));
- }
-
- log().verbose("deleting empty nets ...");
-
- // delete empty nets
-
- delete_empty_nets();
-
- bool err(false);
-
- log().verbose("looking for terminals not connected ...");
- for (auto & i : m_terminals)
- {
- detail::core_terminal_t *term = i.second;
- const pstring name_da = de_alias(term->name());
- bool is_nc_pin(dynamic_cast< devices::NETLIB_NAME(nc_pin) *>(&term->device()) != nullptr);
- bool is_nc_flagged(false);
-
- auto hnc = m_abstract.m_hints.find(name_da + sHINT_NC);
- if (hnc != m_abstract.m_hints.end())
+ else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::TERMINAL))
{
- hnc->second = true; // mark as used
- is_nc_flagged = true;
+ connect_terminal_input(dynamic_cast<terminal_t &>(t2), t1);
}
-
- if (term->has_net() && is_nc_pin)
+ else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::INPUT))
{
- log().error(ME_NC_PIN_1_WITH_CONNECTIONS(name_da));
- err = true;
+ connect_terminal_input(dynamic_cast<terminal_t &>(t1), t2);
}
- else if (is_nc_pin)
+ else if (t1.is_type(detail::terminal_type::TERMINAL) && t2.is_type(detail::terminal_type::TERMINAL))
{
- /* ignore */
+ connect_terminals(dynamic_cast<terminal_t &>(t1), dynamic_cast<terminal_t &>(t2));
}
- else if (!term->has_net())
+ else if (t1.is_type(detail::terminal_type::INPUT) && t2.is_type(detail::terminal_type::INPUT))
{
- log().error(ME_TERMINAL_1_WITHOUT_NET(name_da));
- err = true;
+ ret = connect_input_input(t1, t2);
}
- else if (nlstate().core_terms(term->net()).empty())
+ else
{
- if (term->is_logic_input())
- log().warning(MW_LOGIC_INPUT_1_WITHOUT_CONNECTIONS(name_da));
- else if (term->is_logic_output())
+ ret = false;
+ }
+ return ret;
+ }
+
+ void setup_t::resolve_inputs()
+ {
+ log().verbose("Resolving inputs ...");
+
+ // Netlist can directly connect input to input.
+ // We therefore first park connecting inputs and retry
+ // after all other terminals were connected.
+
+ unsigned tries = m_netlist_params->m_max_link_loops();
+ #if 0
+ // This code fails for some netlists when the element at position 0
+ // is deleted. It will fail somewhere deep in std::pair releasing
+ // std::string called from erase.
+ //
+ // One example is the this netlist:
+ //
+ // #include "netlist/devices/net_lib.h"
+ // NETLIST_START(charge_discharge)
+ // SOLVER(solver, 48000) // Fixed frequency solver
+ // CLOCK(I, 200) // 200 Hz clock as input, TTL logic output
+ // RES(R, RES_K(1))
+ // CAP(C, CAP_U(1))
+ //
+ // NET_C(I.Q, R.1)
+ // NET_C(R.2, C.1)
+ // NET_C(C.2, GND)
+ //
+ // ALIAS(O, R.2) // Output O == C.1 == R.2
+ // // NETLIST_END()
+ //
+ // Just save the net list as /tmp/test1.cpp, run
+ // ./nltool --cmd=run -t 0.05 -l O -l I /tmp/test1.cpp
+ // and see it crash with this code enabled.
+ //
+ // g++-7 (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0
+ //
+ while (!m_links.empty() && tries > 0)
+ {
+ auto li = m_links.begin();
+ while (li != m_links.end())
{
- if (!is_nc_flagged)
- log().info(MI_LOGIC_OUTPUT_1_WITHOUT_CONNECTIONS(name_da));
+ const pstring t1s = li->first;
+ const pstring t2s = li->second;
+ detail::core_terminal_t *t1 = find_terminal(t1s);
+ detail::core_terminal_t *t2 = find_terminal(t2s);
+
+ if (connect(*t1, *t2))
+ li = m_links.erase(li);
+ else
+ li++;
}
- else if (term->is_analog_output())
+ tries--;
+ }
+ #else
+ while (!m_abstract.m_links.empty() && tries > 0)
+ {
+ for (std::size_t i = 0; i < m_abstract.m_links.size(); )
{
- if (!is_nc_flagged)
- log().info(MI_ANALOG_OUTPUT_1_WITHOUT_CONNECTIONS(name_da));
+ const pstring t1s(m_abstract.m_links[i].first);
+ const pstring t2s(m_abstract.m_links[i].second);
+ detail::core_terminal_t *t1 = find_terminal(t1s);
+ detail::core_terminal_t *t2 = find_terminal(t2s);
+ if (connect(*t1, *t2))
+ m_abstract.m_links.erase(m_abstract.m_links.begin() + plib::narrow_cast<std::ptrdiff_t>(i));
+ else
+ i++;
}
- else
- log().warning(MW_TERMINAL_1_WITHOUT_CONNECTIONS(name_da));
+ tries--;
}
- }
+ #endif
+ if (tries == 0)
+ {
+ for (auto & link : m_abstract.m_links)
+ log().warning(MF_CONNECTING_1_TO_2(de_alias(link.first), de_alias(link.second)));
- log().verbose("checking tristate consistency ...");
- for (auto & i : m_terminals)
- {
- detail::core_terminal_t *term = i.second;
- if (term->is_tristate_output())
+ log().fatal(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops()));
+ throw nl_exception(MF_LINK_TRIES_EXCEEDED(m_netlist_params->m_max_link_loops()));
+ }
+
+ log().verbose("deleting empty nets ...");
+
+ // delete empty nets
+
+ delete_empty_nets();
+
+ bool err(false);
+
+ log().verbose("looking for terminals not connected ...");
+ for (auto & i : m_terminals)
{
- const auto &tri(dynamic_cast<tristate_output_t &>(*term));
- // check if we are connected to a proxy
- const auto iter_proxy(m_proxies.find(&tri));
+ detail::core_terminal_t *term = i.second;
+ const pstring name_da = de_alias(term->name());
+ bool is_nc_pin(dynamic_cast< devices::NETLIB_NAME(nc_pin) *>(&term->device()) != nullptr);
+ bool is_nc_flagged(false);
+
+ auto hnc = m_abstract.m_hints.find(name_da + sHINT_NC);
+ if (hnc != m_abstract.m_hints.end())
+ {
+ hnc->second = true; // mark as used
+ is_nc_flagged = true;
+ }
- if (iter_proxy == m_proxies.end() && !tri.is_force_logic())
+ if (term->has_net() && is_nc_pin)
{
- log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name()));
+ log().error(ME_NC_PIN_1_WITH_CONNECTIONS(name_da));
err = true;
}
- else if (iter_proxy != m_proxies.end() && tri.is_force_logic())
+ else if (is_nc_pin)
+ {
+ // ignore
+ }
+ else if (!term->has_net())
{
- log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name()));
+ log().error(ME_TERMINAL_1_WITHOUT_NET(name_da));
err = true;
}
+ else if (term->net().core_terms_empty())
+ {
+ if (term->is_logic_input())
+ log().warning(MW_LOGIC_INPUT_1_WITHOUT_CONNECTIONS(name_da));
+ else if (term->is_logic_output())
+ {
+ if (!is_nc_flagged)
+ log().info(MI_LOGIC_OUTPUT_1_WITHOUT_CONNECTIONS(name_da));
+ }
+ else if (term->is_analog_output())
+ {
+ if (!is_nc_flagged)
+ log().info(MI_ANALOG_OUTPUT_1_WITHOUT_CONNECTIONS(name_da));
+ }
+ else
+ log().warning(MW_TERMINAL_1_WITHOUT_CONNECTIONS(name_da));
+ }
}
- }
- if (err)
- {
- log().fatal(MF_TERMINALS_WITHOUT_NET());
- throw nl_exception(MF_TERMINALS_WITHOUT_NET());
- }
-}
+ log().verbose("checking tristate consistency ...");
+ for (auto & i : m_terminals)
+ {
+ detail::core_terminal_t *term = i.second;
+ if (term->is_tristate_output())
+ {
+ const auto &tri(dynamic_cast<tristate_output_t &>(*term));
+ // check if we are connected to a proxy
+ const auto iter_proxy(m_proxies.find(&tri));
-void setup_t::add_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false)
-{
- for (auto &t : nlstate().core_terms(net))
- if (t == &terminal)
+ if (iter_proxy == m_proxies.end() && !tri.is_force_logic())
+ {
+ log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name()));
+ err = true;
+ }
+ else if (iter_proxy != m_proxies.end() && tri.is_force_logic())
+ {
+ log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name()));
+ err = true;
+ }
+ }
+ }
+ if (err)
{
- log().fatal(MF_NET_1_DUPLICATE_TERMINAL_2(net.name(), t->name()));
- throw nl_exception(MF_NET_1_DUPLICATE_TERMINAL_2(net.name(), t->name()));
+ log().fatal(MF_TERMINALS_WITHOUT_NET());
+ throw nl_exception(MF_TERMINALS_WITHOUT_NET());
}
- terminal.set_net(&net);
-
- nlstate().core_terms(net).push_back(&terminal);
-}
-
-void setup_t::remove_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false)
-{
- if (plib::container::contains(nlstate().core_terms(net), &terminal))
- {
- terminal.set_net(nullptr);
- plib::container::remove(nlstate().core_terms(net), &terminal);
}
- else
+
+ void setup_t::move_connections(detail::net_t &net, detail::net_t &dest_net)
{
- log().fatal(MF_REMOVE_TERMINAL_1_FROM_NET_2(terminal.name(), net.name()));
- throw nl_exception(MF_REMOVE_TERMINAL_1_FROM_NET_2(terminal.name(), net.name()));
- }
-}
+ auto temp(net.core_terms_copy());
-void setup_t::move_connections(detail::net_t &net, detail::net_t &dest_net)
-{
- for (auto &ct : nlstate().core_terms(net))
- add_terminal(dest_net, *ct);
- nlstate().core_terms(net).clear();
-}
+ net.remove_all_terminals();
+ for (detail::core_terminal_t * ct : temp)
+ {
+ dest_net.add_terminal(*ct);
+ }
+ }
+ log_type &setup_t::log() noexcept { return m_nlstate.log(); }
+ const log_type &setup_t::log() const noexcept { return m_nlstate.log(); }
-log_type &setup_t::log() noexcept { return m_nlstate.log(); }
-const log_type &setup_t::log() const noexcept { return m_nlstate.log(); }
+ // ----------------------------------------------------------------------------------------
+ // Models
+ // ----------------------------------------------------------------------------------------
-// ----------------------------------------------------------------------------------------
-// Models
-// ----------------------------------------------------------------------------------------
+ //NOLINTNEXTLINE(misc-no-recursion)
+ void models_t::model_parse(const pstring &model_in, map_t &map)
+ {
+ pstring model = model_in;
+ std::size_t pos = 0;
+ pstring key;
+ while (true)
+ {
+ pos = model.find('(');
+ if (pos != pstring::npos) break;
-//NOLINTNEXTLINE(misc-no-recursion)
-void models_t::model_parse(const pstring &model_in, map_t &map)
-{
- pstring model = model_in;
- std::size_t pos = 0;
- pstring key;
+ key = plib::ucase(model);
+ auto i = m_models.find(key);
+ if (i == m_models.end())
+ {
+ throw nl_exception(MF_MODEL_NOT_FOUND(pstring("xx") + model));
+ }
- while (true)
- {
- pos = model.find('(');
- if (pos != pstring::npos) break;
+ model = i->second;
+ }
+ pstring base_model = plib::left(model, pos);
- key = plib::ucase(model);
- auto i = m_models.find(key);
- if (i == m_models.end())
+ if (base_model == "_")
+ map["COREMODEL"] = key;
+ else
{
- throw nl_exception(MF_MODEL_NOT_FOUND(pstring("xx") + model));
+ auto i = m_models.find(base_model);
+ if (i != m_models.end())
+ model_parse(base_model, map);
+ else
+ throw nl_exception(MF_MODEL_NOT_FOUND(model_in));
}
- model = i->second;
- }
- pstring xmodel = plib::left(model, pos);
+ pstring remainder = plib::trim(model.substr(pos + 1));
+ if (!plib::endsWith(remainder, ")"))
+ throw nl_exception(MF_MODEL_ERROR_1(model));
+ // FIMXE: Not optimal
+ remainder = plib::left(remainder, remainder.length() - 1);
- if (xmodel == "_")
- map["COREMODEL"] = key;
- else
- {
- auto i = m_models.find(xmodel);
- if (i != m_models.end())
- model_parse(xmodel, map);
- else
- throw nl_exception(MF_MODEL_NOT_FOUND(model_in));
+ const auto pairs(plib::psplit(remainder,' ', true));
+ for (const pstring &pe : pairs)
+ {
+ auto pose = pe.find('=');
+ if (pose == pstring::npos)
+ throw nl_exception(MF_MODEL_ERROR_ON_PAIR_1(model));
+ map[plib::ucase(plib::left(pe, pose))] = pe.substr(pose + 1);
+ }
}
- pstring remainder = plib::trim(model.substr(pos + 1));
- if (!plib::endsWith(remainder, ")"))
- throw nl_exception(MF_MODEL_ERROR_1(model));
- // FIMXE: Not optimal
- remainder = plib::left(remainder, remainder.length() - 1);
-
- const auto pairs(plib::psplit(remainder,' ', true));
- for (const pstring &pe : pairs)
+ pstring models_t::model_t::model_string(const map_t &map)
{
- auto pose = pe.find('=');
- if (pose == pstring::npos)
- throw nl_exception(MF_MODEL_ERROR_ON_PAIR_1(model));
- map[plib::ucase(plib::left(pe, pose))] = pe.substr(pose + 1);
- }
-}
+ // operator [] has no const implementation
+ pstring ret = map.at("COREMODEL") + "(";
+ for (const auto & i : map)
+ ret += (i.first + '=' + i.second + ' ');
-pstring models_t::model_t::model_string(const map_t &map)
-{
- // operator [] has no const implementation
- pstring ret = map.at("COREMODEL") + "(";
- for (const auto & i : map)
- ret += (i.first + '=' + i.second + ' ');
-
- return ret + ")";
-}
-
-models_t::model_t models_t::get_model(const pstring &model)
-{
- map_t &map = m_cache[model];
-
- if (map.empty())
- model_parse(model , map);
+ return ret + ")";
+ }
- return { model, map };
-}
+ models_t::model_t models_t::get_model(const pstring &model)
+ {
+ map_t &map = m_cache[model];
-pstring models_t::model_t::value_str(const pstring &entity) const
-{
- if (entity != plib::ucase(entity))
- throw nl_exception(MF_MODEL_PARAMETERS_NOT_UPPERCASE_1_2(entity, model_string(m_map)));
- const auto it(m_map.find(entity));
- if ( it == m_map.end())
- throw nl_exception(MF_ENTITY_1_NOT_FOUND_IN_MODEL_2(entity, model_string(m_map)));
+ if (map.empty())
+ model_parse(model , map);
- return it->second;
-}
+ return { model, map };
+ }
-nl_fptype models_t::model_t::value(const pstring &entity) const
-{
- pstring tmp = value_str(entity);
-
- nl_fptype factor = nlconst::one();
- auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.length() - 1));
- switch (*p)
- {
- case 'M': factor = nlconst::magic(1e6); break; // NOLINT
- case 'k':
- case 'K': factor = nlconst::magic(1e3); break; // NOLINT
- case 'm': factor = nlconst::magic(1e-3); break; // NOLINT
- case 'u': factor = nlconst::magic(1e-6); break; // NOLINT
- case 'n': factor = nlconst::magic(1e-9); break; // NOLINT
- case 'p': factor = nlconst::magic(1e-12); break; // NOLINT
- case 'f': factor = nlconst::magic(1e-15); break; // NOLINT
- case 'a': factor = nlconst::magic(1e-18); break; // NOLINT
- default:
- if (*p < '0' || *p > '9')
- throw nl_exception(MF_UNKNOWN_NUMBER_FACTOR_IN_2(m_model, entity));
- }
- if (factor != nlconst::one())
- tmp = plib::left(tmp, tmp.length() - 1);
- // FIXME: check for errors
- bool err(false);
- auto val = plib::pstonum_ne<nl_fptype>(tmp, err);
- if (err)
- throw nl_exception(MF_MODEL_NUMBER_CONVERSION_ERROR(entity, tmp, "double", m_model));
- return val * factor;
-}
-
-
-// FIXME: all this belongs elsewhere
-
-PENUM(family_type,
- CUSTOM,
- TTL,
- MOS,
- CMOS,
- NMOS,
- PMOS)
-
-class logic_family_std_proxy_t : public logic_family_desc_t
-{
-public:
- logic_family_std_proxy_t(family_type ft)
- : m_family_type(ft)
+ pstring models_t::model_t::value_str(const pstring &entity) const
{
+ if (entity != plib::ucase(entity))
+ throw nl_exception(MF_MODEL_PARAMETERS_NOT_UPPERCASE_1_2(entity, model_string(m_map)));
+ const auto it(m_map.find(entity));
+ if ( it == m_map.end())
+ throw nl_exception(MF_ENTITY_1_NOT_FOUND_IN_MODEL_2(entity, model_string(m_map)));
+
+ return it->second;
}
- // FIXME: create proxies based on family type (far future)
- device_arena::unique_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist,
- const pstring &name, const logic_output_t *proxied) const override
+ nl_fptype models_t::model_t::value(const pstring &entity) const
{
- switch(m_family_type)
+ pstring tmp = value_str(entity);
+
+ nl_fptype factor = nlconst::one();
+ auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.length() - 1));
+ switch (*p)
{
- case family_type::CUSTOM:
- case family_type::TTL:
- case family_type::MOS:
- case family_type::CMOS:
- case family_type::NMOS:
- case family_type::PMOS:
- return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ case 'M': factor = nlconst::magic(1e6); break; // NOLINT
+ case 'k':
+ case 'K': factor = nlconst::magic(1e3); break; // NOLINT
+ case 'm': factor = nlconst::magic(1e-3); break; // NOLINT
+ case 'u': factor = nlconst::magic(1e-6); break; // NOLINT
+ case 'n': factor = nlconst::magic(1e-9); break; // NOLINT
+ case 'p': factor = nlconst::magic(1e-12); break; // NOLINT
+ case 'f': factor = nlconst::magic(1e-15); break; // NOLINT
+ case 'a': factor = nlconst::magic(1e-18); break; // NOLINT
+ default:
+ if (*p < '0' || *p > '9')
+ throw nl_exception(MF_UNKNOWN_NUMBER_FACTOR_IN_2(m_model, entity));
}
- return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ if (factor != nlconst::one())
+ tmp = plib::left(tmp, tmp.length() - 1);
+ // FIXME: check for errors
+ bool err(false);
+ auto val = plib::pstonum_ne<nl_fptype>(tmp, err);
+ if (err)
+ throw nl_exception(MF_MODEL_NUMBER_CONVERSION_ERROR(entity, tmp, "double", m_model));
+ return val * factor;
}
- device_arena::unique_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, const logic_input_t *proxied) const override
- {
- switch(m_family_type)
+ // ----------------------------------------------------------------------------------------
+ // logic_family_std_proxy_t
+ //
+ // FIXME: all this belongs elsewhere
+ // ----------------------------------------------------------------------------------------
+ PENUM(family_type,
+ CUSTOM,
+ TTL,
+ MOS,
+ CMOS,
+ NMOS,
+ PMOS)
+
+ class logic_family_std_proxy_t : public logic_family_desc_t
+ {
+ public:
+ logic_family_std_proxy_t(family_type ft)
+ : m_family_type(ft)
+ {
+ }
+
+ // FIXME: create proxies based on family type (far future)
+ device_arena::unique_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist,
+ const pstring &name, const logic_output_t *proxied) const override
+ {
+ switch(m_family_type)
+ {
+ case family_type::CUSTOM:
+ case family_type::TTL:
+ case family_type::MOS:
+ case family_type::CMOS:
+ case family_type::NMOS:
+ case family_type::PMOS:
+ return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ }
+ return anetlist.make_pool_object<devices::nld_d_to_a_proxy>(anetlist, name, proxied);
+ }
+
+ device_arena::unique_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, const logic_input_t *proxied) const override
+ {
+ switch(m_family_type)
+ {
+ case family_type::CUSTOM:
+ case family_type::TTL:
+ case family_type::MOS:
+ case family_type::CMOS:
+ case family_type::NMOS:
+ case family_type::PMOS:
+ return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
+ }
+ return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
+ }
+ private:
+ family_type m_family_type;
+ };
+
+ /// \brief Class representing the logic families.
+ ///
+ /// This is the model representation of the logic families. This is a
+ /// netlist specific model. Examples give values for TTL family
+ ///
+ //
+ /// |NL? |name |parameter |units| TTL |
+ /// |:--:|:-----|:----------------------------------------------------------|:----|------:|
+ /// | Y |IVL |Input voltage low threshold relative to supply voltage | |1.0e-14|
+ /// | Y |IVH |Input voltage high threshold relative to supply voltage | | 0|
+ /// | Y |OVL |Output voltage minimum voltage relative to supply voltage | |1.0e-14|
+ /// | Y |OVL |Output voltage maximum voltage relative to supply voltage | |1.0e-14|
+ /// | Y |ORL |Output output resistance for logic 0 | | 0|
+ /// | Y |ORH |Output output resistance for logic 1 | | 0|
+ ///
+ class family_model_t
+ {
+ public:
+ template <typename P>
+ family_model_t(P &model)
+ : m_TYPE(model, "TYPE")
+ , m_IVL(model, "IVL")
+ , m_IVH(model, "IVH")
+ , m_OVL(model, "OVL")
+ , m_OVH(model, "OVH")
+ , m_ORL(model, "ORL")
+ , m_ORH(model, "ORH")
+ {}
+
+ param_model_t::value_str_t m_TYPE; //!< Family type (TTL, CMOS, ...)
+ param_model_t::value_t m_IVL; //!< Input voltage low threshold relative to supply voltage
+ param_model_t::value_t m_IVH; //!< Input voltage high threshold relative to supply voltage
+ param_model_t::value_t m_OVL; //!< Output voltage minimum voltage relative to supply voltage
+ param_model_t::value_t m_OVH; //!< Output voltage maximum voltage relative to supply voltage
+ param_model_t::value_t m_ORL; //!< Output output resistance for logic 0
+ param_model_t::value_t m_ORH; //!< Output output resistance for logic 1
+ };
+
+ const logic_family_desc_t *setup_t::family_from_model(const pstring &model)
+ {
+ family_type ft(family_type::CUSTOM);
+
+ auto mod(m_models.get_model(model));
+ family_model_t modv(mod);
+
+ if (!ft.set_from_string(modv.m_TYPE()))
+ throw nl_exception(MF_UNKNOWN_FAMILY_TYPE_1(modv.m_TYPE(), model));
+
+ auto it = m_nlstate.family_cache().find(model);
+ if (it != m_nlstate.family_cache().end())
+ return it->second.get();
+
+ auto ret = plib::make_unique<logic_family_std_proxy_t, host_arena>(ft);
+
+ ret->m_low_threshold_PCNT = modv.m_IVL();
+ ret->m_high_threshold_PCNT = modv.m_IVH();
+ ret->m_low_VO = modv.m_OVL();
+ ret->m_high_VO = modv.m_OVH();
+ ret->m_R_low = modv.m_ORL();
+ ret->m_R_high = modv.m_ORH();
+
+ switch (ft)
{
case family_type::CUSTOM:
case family_type::TTL:
+ case family_type::NMOS:
+ ret->m_vcc = "VCC";
+ ret->m_gnd = "GND";
+ break;
case family_type::MOS:
case family_type::CMOS:
- case family_type::NMOS:
case family_type::PMOS:
- return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
- }
- return anetlist.make_pool_object<devices::nld_a_to_d_proxy>(anetlist, name, proxied);
- }
-private:
- family_type m_family_type;
-};
-
-
-/// \brief Class representing the logic families.
-///
-/// This is the model representation of the logic families. This is a
-/// netlist specific model. Examples give values for TTL family
-///
-//
-/// |NL? |name |parameter |units| TTL |
-/// |:--:|:-----|:----------------------------------------------------------|:----|------:|
-/// | Y |IVL |Input voltage low threshold relative to supply voltage | |1.0e-14|
-/// | Y |IVH |Input voltage high threshold relative to supply voltage | | 0|
-/// | Y |OVL |Output voltage minimum voltage relative to supply voltage | |1.0e-14|
-/// | Y |OVL |Output voltage maximum voltage relative to supply voltage | |1.0e-14|
-/// | Y |ORL |Output output resistance for logic 0 | | 0|
-/// | Y |ORH |Output output resistance for logic 1 | | 0|
-///
-class family_model_t
-{
-public:
- template <typename P>
- family_model_t(P &model)
- : m_TYPE(model, "TYPE")
- , m_IVL(model, "IVL")
- , m_IVH(model, "IVH")
- , m_OVL(model, "OVL")
- , m_OVH(model, "OVH")
- , m_ORL(model, "ORL")
- , m_ORH(model, "ORH")
- {}
-
- param_model_t::value_str_t m_TYPE; //!< Family type (TTL, CMOS, ...)
- param_model_t::value_t m_IVL; //!< Input voltage low threshold relative to supply voltage
- param_model_t::value_t m_IVH; //!< Input voltage high threshold relative to supply voltage
- param_model_t::value_t m_OVL; //!< Output voltage minimum voltage relative to supply voltage
- param_model_t::value_t m_OVH; //!< Output voltage maximum voltage relative to supply voltage
- param_model_t::value_t m_ORL; //!< Output output resistance for logic 0
- param_model_t::value_t m_ORH; //!< Output output resistance for logic 1
-};
-
-
-const logic_family_desc_t *setup_t::family_from_model(const pstring &model)
-{
- family_type ft(family_type::CUSTOM);
-
- auto mod(m_models.get_model(model));
- family_model_t modv(mod);
+ ret->m_vcc = "VDD";
+ ret->m_gnd = "VSS";
+ break;
+ }
- if (!ft.set_from_string(modv.m_TYPE()))
- throw nl_exception(MF_UNKNOWN_FAMILY_TYPE_1(modv.m_TYPE(), model));
+ auto *retp = ret.get();
- auto it = m_nlstate.family_cache().find(model);
- if (it != m_nlstate.family_cache().end())
- return it->second.get();
+ m_nlstate.family_cache().emplace(model, std::move(ret));
- auto ret = plib::make_unique<logic_family_std_proxy_t, host_arena>(ft);
+ return retp;
+ }
- ret->m_low_threshold_PCNT = modv.m_IVL();
- ret->m_high_threshold_PCNT = modv.m_IVH();
- ret->m_low_VO = modv.m_OVL();
- ret->m_high_VO = modv.m_OVH();
- ret->m_R_low = modv.m_ORL();
- ret->m_R_high = modv.m_ORH();
+ // ----------------------------------------------------------------------------------------
+ // Device handling
+ // ----------------------------------------------------------------------------------------
- switch (ft)
+ void setup_t::delete_empty_nets()
{
- case family_type::CUSTOM:
- case family_type::TTL:
- case family_type::NMOS:
- ret->m_vcc = "VCC";
- ret->m_gnd = "GND";
- break;
- case family_type::MOS:
- case family_type::CMOS:
- case family_type::PMOS:
- ret->m_vcc = "VDD";
- ret->m_gnd = "VSS";
- break;
+ m_nlstate.nets().erase(
+ std::remove_if(m_nlstate.nets().begin(), m_nlstate.nets().end(),
+ [](device_arena::owned_ptr<detail::net_t> &net)
+ {
+ if (net->core_terms_empty())
+ {
+ // FIXME: need to remove from state->m_core_terms as well.
+ net->state().log().verbose("Deleting net {1} ...", net->name());
+ net->state().run_state_manager().remove_save_items(net.get());
+ return true;
+ }
+ return false;
+ }), m_nlstate.nets().end());
}
- auto *retp = ret.get();
+ // ----------------------------------------------------------------------------------------
+ // Run preparation
+ // ----------------------------------------------------------------------------------------
- m_nlstate.family_cache().emplace(model, std::move(ret));
+ void setup_t::prepare_to_run()
+ {
+ pstring env_log_setting = plib::util::environment("NL_LOGS", "");
- return retp;
-}
+ if (!env_log_setting.empty())
+ {
+ const auto list_of_logs(plib::psplit(env_log_setting, ':'));
+ m_parser.register_dynamic_log_devices(list_of_logs);
+ }
-// ----------------------------------------------------------------------------------------
-// Device handling
-// ----------------------------------------------------------------------------------------
+ // create default parameters first!
-void setup_t::delete_empty_nets()
-{
- m_nlstate.nets().erase(
- std::remove_if(m_nlstate.nets().begin(), m_nlstate.nets().end(),
- [](device_arena::owned_ptr<detail::net_t> &net)
- {
- if (net->state().core_terms(*net).empty())
- {
- // FIXME: need to remove from state->m_core_terms as well.
- net->state().log().verbose("Deleting net {1} ...", net->name());
- net->state().run_state_manager().remove_save_items(net.get());
- return true;
- }
- return false;
- }), m_nlstate.nets().end());
-}
+ for (auto & e : m_abstract.m_default_params)
+ {
+ auto param(plib::make_unique<param_str_t, host_arena>(nlstate(), e.first, e.second));
+ register_param_t(*param);
+ m_defparam_lifetime.push_back(std::move(param));
+ }
-// ----------------------------------------------------------------------------------------
-// Run preparation
-// ----------------------------------------------------------------------------------------
+ // make sure the solver and parameters are started first!
-void setup_t::prepare_to_run()
-{
- pstring env_log_setting = plib::util::environment("NL_LOGS", "");
+ for (auto & e : m_abstract.m_device_factory)
+ {
+ if ( m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
+ || m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
+ {
+ m_nlstate.register_device(e.first, e.second->make_device(nlstate().pool(), m_nlstate, e.first));
+ }
+ }
- if (!env_log_setting.empty())
- {
- const auto loglist(plib::psplit(env_log_setting, ':'));
- m_parser.register_dynamic_log_devices(loglist);
- }
+ log().debug("Searching for solver and parameters ...\n");
- // create defparams first!
+ auto *solver = m_nlstate.get_single_device<devices::NETLIB_NAME(solver)>("solver");
+ m_netlist_params = m_nlstate.get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
- for (auto & e : m_abstract.m_defparams)
- {
- auto param(plib::make_unique<param_str_t, host_arena>(nlstate(), e.first, e.second));
- register_param_t(*param);
- m_defparam_lifetime.push_back(std::move(param));
- }
+ // set default model parameters
- // make sure the solver and parameters are started first!
+ // FIXME: this is not optimal
+ m_parser.register_model(plib::pfmt("NMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model()));
+ m_parser.register_model(plib::pfmt("PMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model()));
- for (auto & e : m_abstract.m_device_factory)
- {
- if ( m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
- || m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
+ // create devices
+
+ log().debug("Creating devices ...\n");
+ for (auto & e : m_abstract.m_device_factory)
{
- m_nlstate.register_device(e.first, e.second->make_device(nlstate().pool(), m_nlstate, e.first));
+ if ( !m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
+ && !m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
+ {
+ auto dev = e.second->make_device(m_nlstate.pool(), m_nlstate, e.first);
+ m_nlstate.register_device(dev->name(), std::move(dev));
+ }
}
- }
- log().debug("Searching for solver and parameters ...\n");
+ int error_count(0);
- auto *solver = m_nlstate.get_single_device<devices::NETLIB_NAME(solver)>("solver");
- m_netlist_params = m_nlstate.get_single_device<devices::NETLIB_NAME(netlistparams)>("parameter");
+ const bool use_deactivate = m_netlist_params->m_use_deactivate();
- // set default model parameters
+ for (auto &d : m_nlstate.devices())
+ {
+ auto p = m_abstract.m_hints.find(d.second->name() + sHINT_NO_DEACTIVATE);
+ if (p != m_abstract.m_hints.end())
+ {
+ p->second = true; // mark as used
+ d.second->set_hint_deactivate(false);
+ }
+ else
+ d.second->set_hint_deactivate(use_deactivate);
+ }
- // FIXME: this is not optimal
- m_parser.register_model(plib::pfmt("NMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model()));
- m_parser.register_model(plib::pfmt("PMOS_DEFAULT _(CAPMOD={1})")(m_netlist_params->m_mos_cap_model()));
+ if (error_count > 0)
+ {
+ log().fatal(MF_ERRORS_FOUND(error_count));
+ throw nl_exception(MF_ERRORS_FOUND(error_count));
+ }
- // create devices
+ // resolve inputs
+ resolve_inputs();
- log().debug("Creating devices ...\n");
- for (auto & e : m_abstract.m_device_factory)
- {
- if ( !m_parser.factory().is_class<devices::NETLIB_NAME(solver)>(e.second)
- && !m_parser.factory().is_class<devices::NETLIB_NAME(netlistparams)>(e.second))
+ log().verbose("looking for two terms connected to rail nets ...");
+ for (auto & t : m_nlstate.get_device_list<analog::NETLIB_NAME(two_terminal)>())
{
- auto dev = e.second->make_device(m_nlstate.pool(), m_nlstate, e.first);
- m_nlstate.register_device(dev->name(), std::move(dev));
+ if (t->N().net().is_rail_net() && t->P().net().is_rail_net())
+ {
+ log().info(MI_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3(
+ t->name(), t->N().net().name(), t->P().net().name()));
+ // The following would remove internal devices in e.g. MOSFETs as well.
+ #if 0
+ remove_terminal(t->setup_N().net(), t->setup_N());
+ remove_terminal(t->setup_P().net(), t->setup_P());
+ m_nlstate.remove_device(t);
+ #endif
+ }
}
- }
- int error_count(0);
+ log().verbose("looking for unused hints ...");
+ for (auto &h : m_abstract.m_hints)
+ {
+ if (!h.second)
+ {
+ log().fatal(MF_UNUSED_HINT_1(h.first));
+ throw nl_exception(MF_UNUSED_HINT_1(h.first));
+ }
+ }
- const bool use_deactivate = m_netlist_params->m_use_deactivate();
+ log().verbose("initialize solver ...\n");
- for (auto &d : m_nlstate.devices())
- {
- auto p = m_abstract.m_hints.find(d.second->name() + sHINT_NO_DEACTIVATE);
- if (p != m_abstract.m_hints.end())
+ if (solver == nullptr)
{
- p->second = true; // mark as used
- d.second->set_hint_deactivate(false);
+ for (auto &p : m_nlstate.nets())
+ if (p->is_analog())
+ {
+ log().fatal(MF_NO_SOLVER());
+ throw nl_exception(MF_NO_SOLVER());
+ }
}
else
- d.second->set_hint_deactivate(use_deactivate);
- }
-
- if (error_count > 0)
- {
- log().fatal(MF_ERRORS_FOUND(error_count));
- throw nl_exception(MF_ERRORS_FOUND(error_count));
- }
-
- // resolve inputs
- resolve_inputs();
+ solver->post_start();
- log().verbose("looking for two terms connected to rail nets ...");
- for (auto & t : m_nlstate.get_device_list<analog::NETLIB_NAME(two_terminal)>())
- {
- if (t->N().net().is_rail_net() && t->P().net().is_rail_net())
+ error_count = 0;
+ log().debug("Looking for unknown parameters ...\n");
+ for (auto &p : m_abstract.m_param_values)
{
- log().info(MI_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3(
- t->name(), t->N().net().name(), t->P().net().name()));
- // The following would remove internal devices in e.g. MOSFETs as well.
-#if 0
- remove_terminal(t->setup_N().net(), t->setup_N());
- remove_terminal(t->setup_P().net(), t->setup_P());
- m_nlstate.remove_device(t);
-#endif
+ auto f = m_params.find(p.first);
+ if (f == m_params.end())
+ {
+ log().error(ME_UNKNOWN_PARAMETER(p.first));
+ error_count++;
+ }
+ }
+ if (error_count > 0)
+ {
+ log().fatal(MF_ERRORS_FOUND(error_count));
+ throw nl_exception(MF_ERRORS_FOUND(error_count));
}
- }
- log().verbose("looking for unused hints ...");
- for (auto &h : m_abstract.m_hints)
- {
- if (!h.second)
+ for (auto &n : m_nlstate.nets())
{
- log().fatal(MF_UNUSED_HINT_1(h.first));
- throw nl_exception(MF_UNUSED_HINT_1(h.first));
+ for (detail::core_terminal_t * term : n->core_terms_copy())
+ if (term->delegate().isnull())
+ {
+ log().fatal(MF_DELEGATE_NOT_SET_1(term->name()));
+ throw nl_exception(MF_DELEGATE_NOT_SET_1(term->name()));
+ }
+ n->rebuild_list();
}
}
- log().verbose("initialize solver ...\n");
+ // ----------------------------------------------------------------------------------------
+ // base sources
+ // ----------------------------------------------------------------------------------------
- if (solver == nullptr)
+ bool source_netlist_t::parse(nlparse_t &setup, const pstring &name)
{
- for (auto &p : m_nlstate.nets())
- if (p->is_analog())
- {
- log().fatal(MF_NO_SOLVER());
- throw nl_exception(MF_NO_SOLVER());
- }
+ auto strm(stream(name));
+ return (!strm.empty()) ? setup.parse_stream(std::move(strm), name) : false;
}
- else
- solver->post_start();
- error_count = 0;
- log().debug("Looking for unknown parameters ...\n");
- for (auto &p : m_abstract.m_param_values)
+ plib::istream_uptr source_string_t::stream([[maybe_unused]] const pstring &name)
{
- auto f = m_params.find(p.first);
- if (f == m_params.end())
- {
- log().error(ME_UNKNOWN_PARAMETER(p.first));
- error_count++;
- }
- }
- if (error_count > 0)
- {
- log().fatal(MF_ERRORS_FOUND(error_count));
- throw nl_exception(MF_ERRORS_FOUND(error_count));
+ plib::istream_uptr ret(std::make_unique<std::istringstream>(putf8string(m_str)), name);
+ ret->imbue(std::locale::classic());
+ return ret;
}
- for (auto &n : m_nlstate.nets())
+ plib::istream_uptr source_mem_t::stream([[maybe_unused]] const pstring &name)
{
- for (auto & term : m_nlstate.core_terms(*n))
- if (term->delegate().isnull())
- {
- log().fatal(MF_DELEGATE_NOT_SET_1(term->name()));
- throw nl_exception(MF_DELEGATE_NOT_SET_1(term->name()));
- }
- n->rebuild_list();
+ plib::istream_uptr ret(std::make_unique<std::istringstream>(m_str, std::ios_base::binary), name);
+ ret->imbue(std::locale::classic());
+ return ret;
}
-}
-// ----------------------------------------------------------------------------------------
-// base sources
-// ----------------------------------------------------------------------------------------
-
-bool source_netlist_t::parse(nlparse_t &setup, const pstring &name)
-{
- auto strm(stream(name));
- return (!strm.empty()) ? setup.parse_stream(std::move(strm), name) : false;
-}
-
-plib::istream_uptr source_string_t::stream([[maybe_unused]] const pstring &name)
-{
- plib::istream_uptr ret(std::make_unique<std::istringstream>(putf8string(m_str)), name);
- ret->imbue(std::locale::classic());
- return ret;
-}
-
-plib::istream_uptr source_mem_t::stream([[maybe_unused]] const pstring &name)
-{
- plib::istream_uptr ret(std::make_unique<std::istringstream>(m_str, std::ios_base::binary), name);
- ret->imbue(std::locale::classic());
- return ret;
-}
-
-plib::istream_uptr source_file_t::stream([[maybe_unused]] const pstring &name)
-{
- auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(m_filename));
- if (f->is_open())
+ plib::istream_uptr source_file_t::stream([[maybe_unused]] const pstring &name)
{
- return { std::move(f), m_filename };
- }
+ auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(m_filename));
+ if (f->is_open())
+ {
+ return { std::move(f), m_filename };
+ }
- return plib::istream_uptr();
-}
+ return plib::istream_uptr();
+ }
-plib::istream_uptr source_pattern_t::stream([[maybe_unused]] const pstring &name)
-{
- pstring filename = plib::pfmt(m_pattern)(m_force_lowercase ? plib::lcase(name) : name);
- auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(filename));
- if (f->is_open())
+ plib::istream_uptr source_pattern_t::stream([[maybe_unused]] const pstring &name)
{
- return { std::move(f), filename };
+ pstring filename = plib::pfmt(m_pattern)(m_force_lowercase ? plib::lcase(name) : name);
+ auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(filename));
+ if (f->is_open())
+ {
+ return { std::move(f), filename };
+ }
+
+ return plib::istream_uptr();
}
- return plib::istream_uptr();
-}
+ bool source_proc_t::parse(nlparse_t &setup, const pstring &name)
+ {
+ if (name == m_setup_func_name)
+ {
+ m_setup_func(setup);
+ return true;
+ }
+ return false;
+ }
-bool source_proc_t::parse(nlparse_t &setup, const pstring &name)
-{
- if (name == m_setup_func_name)
+ plib::istream_uptr source_proc_t::stream([[maybe_unused]] const pstring &name)
{
- m_setup_func(setup);
- return true;
+ return plib::istream_uptr();
}
- return false;
-}
-
-plib::istream_uptr source_proc_t::stream([[maybe_unused]] const pstring &name)
-{
- return plib::istream_uptr();
-}
-
} // namespace netlist