mame/src/lib/netlist/devices/nlid_proxy.cpp
couriersud f60ed79ed6 netlist: code maintenance. (nw)
- more doxygen \file annotations
- moved MAINCLOCK back to nl_base.h
- remove some const from simple function parameters
2019-11-10 01:18:57 +01:00

205 lines
6.0 KiB
C++

// license:GPL-2.0+
// copyright-holders:Couriersud
/*
* nlid_proxy.cpp
*
*/
#include "nlid_proxy.h"
#include "netlist/solver/nld_solver.h"
namespace netlist
{
namespace 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)
{
m_logic_family = inout_proxied->logic_family();
m_term_proxied = inout_proxied;
m_proxy_term = proxy_inout;
}
// ----------------------------------------------------------------------------------------
// 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")
{
}
NETLIB_RESET(a_to_d_proxy)
{
}
NETLIB_UPDATE(a_to_d_proxy)
{
nl_assert(m_logic_family != nullptr);
// FIXME: Variable supply voltage!
nl_fptype supply_V = logic_family()->fixed_V();
if (supply_V == nlconst::zero()) supply_V = nlconst::magic(5.0);
if (m_I.Q_Analog() > logic_family()->high_thresh_V(nlconst::zero(), supply_V))
out().push(1, netlist_time::quantum());
else if (m_I.Q_Analog() < logic_family()->low_thresh_V(nlconst::zero(), supply_V))
out().push(0, netlist_time::quantum());
else
{
// do nothing
}
}
// ----------------------------------------------------------------------------------------
// 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_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)
, m_RP(*this, "RP")
, m_RN(*this, "RN")
, m_last_state(*this, "m_last_var", -1)
, m_is_timestep(false)
{
const std::vector<std::pair<pstring, pstring>> power_syms = { {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}};
register_subalias("Q", m_RN.m_P);
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 = state().setup().find_terminal(devname + "." + pwr_sym.first,
/*detail::terminal_type::INPUT,*/ false);
auto tn_t = state().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() == nlconst::zero())
log().error(MI_NO_POWER_TERMINALS_ON_DEVICE_1(state().setup().de_alias(out_proxied->device().name())));
else
log().info(MI_NO_POWER_TERMINALS_ON_DEVICE_1(state().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 (state().setup().is_extended_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());
}
void nld_d_to_a_proxy::reset()
{
// FIXME: Variable voltage
nl_fptype supply_V = logic_family()->fixed_V();
// FIXME: comparison to zero
if (supply_V == nlconst::zero())
supply_V = nlconst::magic(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::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)
{
const auto state = static_cast<int>(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,
nlconst::zero(),
nlconst::zero());
m_RP.set_G_V_I(plib::reciprocal(logic_family()->R_high()),
logic_family()->high_offset_V(), nlconst::zero());
}
else
{
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());
}
m_RN.solve_later(); // RN, RP are connected ...
m_last_state = state;
}
}
} //namespace devices
} // namespace netlist