summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/devices/nlid_proxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/devices/nlid_proxy.cpp')
-rw-r--r--src/lib/netlist/devices/nlid_proxy.cpp263
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