diff options
Diffstat (limited to 'src/lib/netlist/devices/nlid_proxy.cpp')
-rw-r--r-- | src/lib/netlist/devices/nlid_proxy.cpp | 263 |
1 files changed, 124 insertions, 139 deletions
diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp index 2a9fccd1dc6..0ab77e84e7d 100644 --- a/src/lib/netlist/devices/nlid_proxy.cpp +++ b/src/lib/netlist/devices/nlid_proxy.cpp @@ -1,62 +1,100 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Couriersud -/* - * nlid_proxy.cpp - * - */ + +/// +/// \file nlid_proxy.cpp +/// +/// #include "nlid_proxy.h" -#include "netlist/solver/nld_solver.h" +#include "core/setup.h" +#include "nl_errstr.h" +#include "solver/nld_solver.h" -namespace netlist -{ - namespace devices - { +#include <array> + +namespace netlist::devices { // ----------------------------------------------------------------------------- // nld_base_proxy // ----------------------------------------------------------------------------- - nld_base_proxy::nld_base_proxy(netlist_state_t &anetlist, const pstring &name, - logic_t *inout_proxied, detail::core_terminal_t *proxy_inout) - : device_t(anetlist, name) + static constexpr std::array<std::pair<const char *, const char *>, 3> power_syms = {{ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}}; + + nld_base_proxy::nld_base_proxy(device_param_t data, + const logic_t *inout_proxied) + : device_t(data, inout_proxied->logic_family()) + , m_tp(nullptr) + , m_tn(nullptr) { - m_logic_family = inout_proxied->logic_family(); - m_term_proxied = inout_proxied; - m_proxy_term = proxy_inout; + if (logic_family() == nullptr) + { + throw nl_exception(MF_NULLPTR_FAMILY_NP("nld_base_proxy")); + } + + bool f = false; + for (const auto & pwr_sym : power_syms) + { + pstring devname = inout_proxied->device().name(); + + auto *tp_ct(state().setup().find_terminal(devname + "." + pstring(pwr_sym.first), + /*detail::terminal_type::INPUT,*/ false)); + auto *tp_cn(state().setup().find_terminal(devname + "." + pstring(pwr_sym.second), + /*detail::terminal_type::INPUT,*/ false)); + if ((tp_ct != nullptr) && (tp_cn != nullptr)) + { + if (!tp_ct->is_analog()) + throw nl_exception(plib::pfmt("Not an analog terminal: {1}")(tp_ct->name())); + if (!tp_cn->is_analog()) + throw nl_exception(plib::pfmt("Not an analog terminal: {1}")(tp_cn->name())); + + auto tp_t = plib::dynamic_downcast<analog_t* >(tp_ct); + auto tn_t = plib::dynamic_downcast<analog_t *>(tp_cn); + if (f && (tp_t && tn_t)) + log().warning(MI_MULTIPLE_POWER_TERMINALS_ON_DEVICE(inout_proxied->device().name(), + m_tp->name(), m_tn->name(), + tp_t ? (*tp_t)->name() : "", + tn_t ? (*tn_t)->name() : "")); + else if (tp_t && tn_t) + { + m_tp = *tp_t; + m_tn = *tn_t; + f = true; + } + } + } + if (!f) + throw nl_exception(MF_NO_POWER_TERMINALS_ON_DEVICE_2(name(), state().setup().de_alias(inout_proxied->device().name()))); + + log().verbose("D/A Proxy: Found power terminals on device {1}", inout_proxied->device().name()); } // ---------------------------------------------------------------------------------------- // nld_a_to_d_proxy // ---------------------------------------------------------------------------------------- - nld_base_a_to_d_proxy::nld_base_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name, - logic_input_t *in_proxied, detail::core_terminal_t *in_proxy) - : nld_base_proxy(anetlist, name, in_proxied, in_proxy) - , m_Q(*this, "Q") - { - } - - nld_a_to_d_proxy::nld_a_to_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *in_proxied) - : nld_base_a_to_d_proxy(anetlist, name, in_proxied, &m_I) - , m_I(*this, "I") + nld_base_a_to_d_proxy::nld_base_a_to_d_proxy(device_param_t data, + const logic_input_t *in_proxied) + : nld_base_proxy(data, in_proxied) { } - NETLIB_RESET(a_to_d_proxy) + nld_a_to_d_proxy::nld_a_to_d_proxy(device_param_t data, const logic_input_t *in_proxied) + : nld_base_a_to_d_proxy(data, in_proxied) + , m_Q(*this, "Q") + , m_I(*this, "I", nl_delegate(&nld_a_to_d_proxy::input, this)) { } - NETLIB_UPDATE(a_to_d_proxy) + NETLIB_HANDLER(a_to_d_proxy, input) { - nl_assert(m_logic_family != nullptr); - // FIXME: Variable supply voltage! - double supply_V = logic_family()->fixed_V(); - if (supply_V == 0.0) supply_V = 5.0; + const auto v(m_I.Q_Analog()); + const auto vn(m_tn->net().Q_Analog()); + const auto vp(m_tp->net().Q_Analog()); - if (m_I.Q_Analog() > logic_family()->high_thresh_V(0.0, supply_V)) + if (logic_family()->is_above_high_threshold_V(v, vn, vp)) out().push(1, netlist_time::quantum()); - else if (m_I.Q_Analog() < logic_family()->low_thresh_V(0.0, supply_V)) + else if (logic_family()->is_below_low_threshold_V(v, vn, vp)) out().push(0, netlist_time::quantum()); else { @@ -68,132 +106,79 @@ namespace netlist // nld_d_to_a_proxy // ---------------------------------------------------------------------------------------- - nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name, - logic_output_t *out_proxied, detail::core_terminal_t &proxy_out) - : nld_base_proxy(anetlist, name, out_proxied, &proxy_out) - , m_I(*this, "I") + nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(device_param_t data, + const logic_output_t *out_proxied) + : nld_base_proxy(data, out_proxied) { } - nld_d_to_a_proxy::nld_d_to_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *out_proxied) - : nld_base_d_to_a_proxy(anetlist, name, out_proxied, m_RN.m_P) + nld_d_to_a_proxy::nld_d_to_a_proxy(device_param_t data, const logic_output_t *out_proxied) + : nld_base_d_to_a_proxy(data, out_proxied) + , m_I(*this, "I", nl_delegate(&nld_d_to_a_proxy :: input, this)) , m_RP(*this, "RP") , m_RN(*this, "RN") - , m_last_state(*this, "m_last_var", -1) - , m_is_timestep(false) + , m_last_state(*this, "m_last_var", terminal_t::OUT_TRISTATE()) { - const std::vector<std::pair<pstring, pstring>> power_syms = { {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}; + register_sub_alias("Q", "RN.1"); - register_subalias("Q", m_RN.m_P); + connect(m_RN().N(), *m_tn); + connect(m_RP().P(), *m_tp); - bool f = false; - detail::core_terminal_t *tp(nullptr); - detail::core_terminal_t *tn(nullptr); - for (auto & pwr_sym : power_syms) - { - pstring devname = out_proxied->device().name(); - auto tp_t = setup().find_terminal(devname + "." + pwr_sym.first, - /*detail::terminal_type::INPUT,*/ false); - auto tn_t = setup().find_terminal(devname + "." + pwr_sym.second, - /*detail::terminal_type::INPUT,*/ false); - if (f && (tp_t != nullptr && tn_t != nullptr)) - log().warning(MI_MULTIPLE_POWER_TERMINALS_ON_DEVICE(out_proxied->device().name(), - tp->name(), tn->name(), - tp_t ? tp_t->name() : "", - tn_t ? tn_t->name() : "")); - else if (tp_t != nullptr && tn_t != nullptr) - { - /* alternative logic */ - tp = tp_t; - tn = tn_t; - f = true; - } - } - //FIXME: Use power terminals and change info to warning or error - if (!f) - { - if (logic_family()->fixed_V() == 0.0) - log().error(MI_NO_POWER_TERMINALS_ON_DEVICE_1(setup().de_alias(out_proxied->device().name()))); - else - log().info(MI_NO_POWER_TERMINALS_ON_DEVICE_1(setup().de_alias(out_proxied->device().name()))); - m_GNDHack = plib::make_unique<analog_output_t>(*this, "_QGND"); - m_VCCHack = plib::make_unique<analog_output_t>(*this, "_QVCC"); - - connect(m_RN.m_N, *m_GNDHack); - connect(m_RP.m_P, *m_VCCHack); - connect(m_RN.m_P, m_RP.m_N); - } - else - { - log().verbose("D/A Proxy: Found power terminals on device {1}", out_proxied->device().name()); - if (setup().is_validation()) - { - // During validation, don't connect to terminals found - // This will cause terminals not connected to a rail net to - // fail connection stage. - connect(m_RN.m_N, m_RP.m_P); - } - else - { - connect(m_RN.m_N, *tn); - connect(m_RP.m_P, *tp); - } - connect(m_RN.m_P, m_RP.m_N); - } - //printf("vcc: %f\n", logic_family()->fixed_V()); + connect(m_RN().P(), m_RP().N()); } void nld_d_to_a_proxy::reset() { - // FIXME: Variable voltage - double supply_V = logic_family()->fixed_V(); - if (supply_V == 0.0) supply_V = 5.0; - //m_Q.initial(0.0); - m_last_state = -1; - m_RN.reset(); - m_RP.reset(); - if (m_GNDHack) - m_GNDHack->initial(0); - if (m_VCCHack) - m_VCCHack->initial(supply_V); - m_is_timestep = m_RN.m_P.net().solver()->has_timestep_devices(); - m_RN.set_G_V_I(plib::constants<nl_double>::one() / logic_family()->R_low(), - logic_family()->low_offset_V(), 0.0); - m_RP.set_G_V_I(G_OFF, - 0.0, 0.0); + m_last_state = terminal_t::OUT_TRISTATE(); + m_RN().reset(); + m_RP().reset(); + m_RN().set_G_V_I(plib::reciprocal(logic_family()->R_low()), + logic_family()->low_offset_V(), nlconst::zero()); + m_RP().set_G_V_I(G_OFF, + nlconst::zero(), + nlconst::zero()); } - NETLIB_UPDATE(d_to_a_proxy) + NETLIB_HANDLER(d_to_a_proxy ,input) { - const auto state = static_cast<int>(m_I()); + const auto state = m_I(); if (state != m_last_state) { - // We only need to update the net first if this is a time stepping net - if (m_is_timestep) - { - m_RN.update(); // RN, RP are connected ... - } - if (state) - { - m_RN.set_G_V_I(G_OFF, - 0.0, 0.0); - m_RP.set_G_V_I(plib::constants<nl_double>::one() / logic_family()->R_high(), - logic_family()->high_offset_V(), 0.0); - } - else + // RN, RP are connected ... + m_RN().change_state([this, &state]() { - m_RN.set_G_V_I(plib::constants<nl_double>::one() / logic_family()->R_low(), - logic_family()->low_offset_V(), 0.0); - m_RP.set_G_V_I(G_OFF, - 0.0, 0.0); - } - m_RN.solve_later(); // RN, RP are connected ... + switch (state) + { + case 0: + m_RN().set_G_V_I(plib::reciprocal(logic_family()->R_low()), + logic_family()->low_offset_V(), nlconst::zero()); + m_RP().set_G_V_I(G_OFF, + nlconst::zero(), + nlconst::zero()); + break; + case 1: + m_RN().set_G_V_I(G_OFF, + nlconst::zero(), + nlconst::zero()); + m_RP().set_G_V_I(plib::reciprocal(logic_family()->R_high()), + logic_family()->high_offset_V(), nlconst::zero()); + break; + case terminal_t::OUT_TRISTATE(): + m_RN().set_G_V_I(G_OFF, + nlconst::zero(), + nlconst::zero()); + m_RP().set_G_V_I(G_OFF, + nlconst::zero(), + nlconst::zero()); + break; + default: + plib::terminate("unknown state for proxy: this should never happen!"); + } + }); m_last_state = state; } } - - } //namespace devices -} // namespace netlist +} // namespace netlist::devices |