mame/src/lib/netlist/devices/nld_ne555.cpp
couriersud e7652e14d6 netlist: Improve validation code.
Adjust warning levels and fix a number of topics identified.
2019-04-16 01:49:44 +02:00

200 lines
4.6 KiB
C++

// license:GPL-2.0+
// copyright-holders:Couriersud
/*!
* \file nld_NE555.cpp
*
* \page NE555 NE555: PRECISION TIMERS
*
* The Swiss army knife for timing purposes
*
* \section ne555_1 Synopsis
*
* \snippet devsyn.dox.h NE555 synopsis
* \snippet devsyn.dox.h NE555_DIP synopsis
* \section ne555_11 "C" Synopsis
*
* \snippet devsyn.dox.h NE555 csynopsis
* \snippet devsyn.dox.h NE555_DIP csynopsis
*
* For the \c NE555 use verbose pin assignments like \c name.TRIG or \c name.OUT.
* For the \c NE555_DIP use pin numbers like \c name.1.
*
* \section ne555_2 Connection Diagram
*
* <pre>
* +--------+
* GND |1 ++ 8| VCC
* TRIG |2 7| DISCH
* OUT |3 6| THRES
* RESET |4 5| CONT
* +--------+
* </pre>
*
* Naming conventions follow Texas Instruments datasheet
*
* \section ne555_3 Function Table
*
* Please refer to the datasheet.
*
* \section ne555_4 Limitations
*
* Internal resistor network currently fixed to 5k.
*
* \section ne555_5 Example
* \snippet ne555_astable.c ne555 example
*/
#include "nld_ne555.h"
#include "netlist/analog/nlid_twoterm.h"
#include "netlist/solver/nld_solver.h"
#define R_OFF (1E20)
#define R_ON (25) // Datasheet states a maximum discharge of 200mA, R = 5V / 0.2
namespace netlist
{
namespace devices
{
NETLIB_OBJECT(NE555)
{
NETLIB_CONSTRUCTOR(NE555)
, m_R1(*this, "R1")
, m_R2(*this, "R2")
, m_R3(*this, "R3")
, m_ROUT(*this, "ROUT")
, m_RDIS(*this, "RDIS")
, m_RESET(*this, "RESET") // Pin 4
, m_THRES(*this, "THRESH") // Pin 6
, m_TRIG(*this, "TRIG") // Pin 2
, m_OUT(*this, "_OUT") // to Pin 3 via ROUT
, m_last_out(*this, "m_last_out", false)
, m_ff(*this, "m_ff", false)
, m_last_reset(*this, "m_last_reset", false)
{
register_subalias("GND", m_R3.m_N); // Pin 1
register_subalias("CONT", m_R1.m_N); // Pin 5
register_subalias("DISCH", m_RDIS.m_P); // Pin 7
register_subalias("VCC", m_R1.m_P); // Pin 8
register_subalias("OUT", m_ROUT.m_P); // Pin 3
connect(m_R1.m_N, m_R2.m_P);
connect(m_R2.m_N, m_R3.m_P);
connect(m_RDIS.m_N, m_R3.m_N);
connect(m_OUT, m_ROUT.m_N);
}
NETLIB_UPDATEI();
NETLIB_RESETI();
private:
analog::NETLIB_SUB(R_base) m_R1;
analog::NETLIB_SUB(R_base) m_R2;
analog::NETLIB_SUB(R_base) m_R3;
analog::NETLIB_SUB(R_base) m_ROUT;
analog::NETLIB_SUB(R_base) m_RDIS;
logic_input_t m_RESET;
analog_input_t m_THRES;
analog_input_t m_TRIG;
analog_output_t m_OUT;
state_var<bool> m_last_out;
state_var<bool> m_ff;
state_var<bool> m_last_reset;
nl_double clamp(const nl_double v, const nl_double a, const nl_double b)
{
nl_double ret = v;
nl_double vcc = m_R1.m_P();
if (ret > vcc - a)
ret = vcc - a;
if (ret < b)
ret = b;
return ret;
}
};
NETLIB_OBJECT_DERIVED(NE555_dip, NE555)
{
NETLIB_CONSTRUCTOR_DERIVED(NE555_dip, NE555)
{
register_subalias("1", "GND"); // Pin 1
register_subalias("2", "TRIG"); // Pin 2
register_subalias("3", "OUT"); // Pin 3
register_subalias("4", "RESET"); // Pin 4
register_subalias("5", "CONT"); // Pin 5
register_subalias("6", "THRESH"); // Pin 6
register_subalias("7", "DISCH"); // Pin 7
register_subalias("8", "VCC"); // Pin 8
}
};
NETLIB_RESET(NE555)
{
m_R1.reset();
m_R2.reset();
m_R3.reset();
m_ROUT.reset();
m_RDIS.reset();
/* FIXME make resistances a parameter, properly model other variants */
m_R1.set_R(5000);
m_R2.set_R(5000);
m_R3.set_R(5000);
m_ROUT.set_R(20);
m_RDIS.set_R(R_OFF);
m_last_out = true;
}
NETLIB_UPDATE(NE555)
{
// FIXME: assumes GND is connected to 0V.
const auto reset = m_RESET();
if (!reset && m_last_reset)
{
m_ff = false;
}
else
{
const nl_double vt = clamp(m_R2.m_P(), 0.7, 1.4);
const bool bthresh = (m_THRES() > vt);
const bool btrig = (m_TRIG() > clamp(m_R2.m_N(), 0.7, 1.4));
if (!btrig)
m_ff = true;
else if (bthresh)
m_ff = false;
}
const bool out = (!reset ? false : m_ff);
if (m_last_out && !out)
{
m_RDIS.update();
m_OUT.push(m_R3.m_N());
m_RDIS.set_R(R_ON);
}
else if (!m_last_out && out)
{
m_RDIS.update();
// FIXME: Should be delayed by 100ns
m_OUT.push(m_R1.m_P());
m_RDIS.set_R(R_OFF);
}
m_last_reset = reset;
m_last_out = out;
}
NETLIB_DEVICE_IMPL(NE555, "NE555", "")
NETLIB_DEVICE_IMPL(NE555_dip, "NE555_DIP", "")
NETLIB_DEVICE_IMPL_ALIAS(MC1455P, NE555, "MC1455P", "")
NETLIB_DEVICE_IMPL_ALIAS(MC1455P_dip, NE555_dip, "MC1455P_DIP", "")
} //namespace devices
} // namespace netlist