summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/devices/nld_74123.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/devices/nld_74123.cpp')
-rw-r--r--src/lib/netlist/devices/nld_74123.cpp483
1 files changed, 229 insertions, 254 deletions
diff --git a/src/lib/netlist/devices/nld_74123.cpp b/src/lib/netlist/devices/nld_74123.cpp
index 889ba019f78..fc0beef9972 100644
--- a/src/lib/netlist/devices/nld_74123.cpp
+++ b/src/lib/netlist/devices/nld_74123.cpp
@@ -1,72 +1,215 @@
-// license:GPL-2.0+
+// license:BSD-3-Clause
// copyright-holders:Couriersud
/*
- * nld_74123.c
+ * nld_74123.cpp
+ *
+ * 74123: Dual Retriggerable One-Shot with Clear and Complementary Outputs
+ *
+ * +--------------+
+ * A1 |1 ++ 16| VCC
+ * B1 |2 15| RC1
+ * CLR1 |3 14| C1
+ * Q1Q |4 74123 13| Q1
+ * Q2 |5 12| Q2Q
+ * C2 |6 11| CLR2
+ * RC2 |7 10| B2
+ * GND |8 9| A2
+ * +--------------+
+ *
+ * Naming conventions follow Fairchild Semiconductor datasheet
+ *
+ * DM9602: Dual Retriggerable, Resettable One Shots
+ *
+ * +--------------+
+ * C1 |1 ++ 16| VCC
+ * RC1 |2 15| C2
+ * CLR1 |3 14| RC2
+ * B1 |4 9602 13| CLR2
+ * A1 |5 12| B2
+ * Q1 |6 11| A2
+ * Q1Q |7 10| Q2
+ * GND |8 9| Q2Q
+ * +--------------+
+ *
+ * CD4538: Dual Retriggerable, Resettable One Shots
+ *
+ * +--------------+
+ * C1 |1 ++ 16| VCC
+ * RC1 |2 15| C2
+ * CLR1 |3 14| RC2
+ * A1 |4 4538 13| CLR2
+ * B1 |5 12| A2
+ * Q1 |6 11| B2
+ * Q1Q |7 10| Q2
+ * GND |8 9| Q2Q
+ * +--------------+
*
*/
+#include "analog/nlid_twoterm.h"
#include "nlid_system.h"
-#include "netlist/analog/nlid_twoterm.h"
-
-#include <cmath>
-namespace netlist
-{
- namespace devices
+namespace netlist::devices {
+
+ /// \brief Base monostable device
+ ///
+ /// The basic operation is the following:
+ ///
+ /// After a trigger signal has been detected, the output changes to high.
+ /// The capacitor is quickly discharged until it reaches Vlow.
+ /// The device toggles into charging mode until Vhigh is reached. At this
+ /// point, the output is set to low. Charging continues until VCC - or
+ /// more specific VRC is reached.
+ ///
+ /// Using
+ ///
+ /// - Vlow = alpha * VCC
+ /// - Vhigh = (1-alpha) * VCC
+ /// - Ignoring Rext during discharge
+ ///
+ /// we have calculate the following time constants:
+ ///
+ /// - tD = - X*C * ln(alpha)
+ /// - tC = - R*C * ln(alhpa)
+ /// - tL = - R*C * ln(1.0 - alpha)
+ ///
+ /// where tD denotes the time to discharge from VCC to Vlow, tC denotes
+ /// the time to charge from 0.0 to Vhigh and tL denotes the time to charge
+ /// from 0 to Vlow. X denotes the internal resistance used to discharge the
+ /// capacitor. The total impulse duration is thus
+ ///
+ /// tP = tD + tC - tL
+ ///
+ /// Using K = ln(1 - alpha) - ln (alpha) = ln(1/alpha - 1)
+ ///
+ /// we get
+ ///
+ /// tP = R*C*K * (1 + X/R * ln(alpha) / K)
+ ///
+ /// and alpha = 1 / (1 + exp(K))
+ ///
+ /// Datasheets express the right term usually as
+ ///
+ /// (1 + f * 1000 / R) = (1 + X/R * ln(alpha) / K)
+ ///
+ /// and thus
+ ///
+ /// X = f * 1000 * K / ln(alpha)
+ ///
+ /// FIXME: Currently X is given directly (as RI). It would be better to use
+ /// f (usually 0.7) and K to calculate X.
+ ///
+ template <typename D>
+ NETLIB_OBJECT(74123_base)
{
- NETLIB_OBJECT(74123)
- {
- NETLIB_CONSTRUCTOR_EX(74123, int dev_type = 74123)
- , m_dev_type(dev_type)
+ NETLIB_CONSTRUCTOR(74123_base)
, m_RP(*this, "RP")
, m_RN(*this, "RN")
, m_RP_Q(*this, "_RP_Q")
, m_RN_Q(*this, "_RN_Q")
- , m_A(*this, "A")
- , m_B(*this, "B")
- , m_CLRQ(*this, "CLRQ")
+ , m_I(*this, D::names(), NETLIB_DELEGATE(ab_clear))
, m_Q(*this, "Q")
, m_QQ(*this, "QQ")
- , m_CV(*this, "_CV") // internal
+ , m_CV(*this, "_CV", NETLIB_DELEGATE(cv)) // internal
, m_last_trig(*this, "m_last_trig", 0)
, m_state(*this, "m_state", 0)
- , m_KP(*this, "m_KP", 0)
- , m_K(*this, "K", (m_dev_type == 4538) ? 1.0 : 0.4) // CD4538 datasheet states PW=RC
- , m_RI(*this, "RI", 400.0) // around 250 for HC series, 400 on LS/TTL, estimated from datasheets
+ , m_KP(plib::reciprocal(nlconst::one() + plib::exp(D::K())))
+ //, m_power_pins(*this)
{
- if ((m_dev_type != 9602) && (m_dev_type != 4538) )
- m_dev_type = 74123;
- register_subalias("GND", m_RN.m_R.m_N);
- register_subalias("VCC", m_RP.m_R.m_P);
- register_subalias("C", m_RN.m_R.m_N);
- register_subalias("RC", m_RN.m_R.m_P);
+ register_sub_alias(pstring(D::gnd()), "RN.2");
+ register_sub_alias(pstring(D::vcc()), "RP.1");
+ register_sub_alias("C", "RN.2");
+ register_sub_alias("RC", "RN.1");
- connect(m_RP_Q, m_RP.m_I);
- connect(m_RN_Q, m_RN.m_I);
+ connect("_RP_Q", "RP.I");
+ connect("_RN_Q", "RN.I");
- connect(m_RN.m_R.m_P, m_RP.m_R.m_N);
- connect(m_CV, m_RN.m_R.m_P);
+ connect("RN.1", "RP.2");
+ connect("_CV", "RN.1");
- m_RP.m_RON.setTo(m_RI());
- m_RN.m_RON.setTo(m_RI());
+ m_RP().m_RON.set(D::RI());
+ m_RN().m_RON.set(D::RI());
}
- NETLIB_RESETI();
- NETLIB_UPDATEI();
+ NETLIB_HANDLERI(ab_clear)
+ {
+ netlist_sig_t m_trig(0);
+
+ m_trig = D::trigfunc(m_I);
+
+ if (!D::clear(m_I))
+ {
+ m_Q.push(0, D::t_C_to_Q::value());
+ m_QQ.push(1, D::t_C_to_Q::value());
+ /* quick charge until trigger */
+ /* FIXME: SGS datasheet shows quick charge to 5V,
+ * though schematics indicate quick charge to Vhigh only.
+ */
+ m_RP_Q.push(1, D::t_C_to_Q::value()); // R_ON
+ m_RN_Q.push(0, D::t_C_to_Q::value()); // R_OFF
+ m_state = 2; //charging (quick)
+ }
+ else if (!m_last_trig && m_trig)
+ {
+ // FIXME: Timing!
+ m_Q.push(1, D::t_AB_to_Q::value());
+ m_QQ.push(0, D::t_AB_to_Q::value());
+
+ m_RN_Q.push(1, D::t_AB_to_Q::value()); // R_ON
+ m_RP_Q.push(0, D::t_AB_to_Q::value()); // R_OFF
+
+ m_state = 1; // discharging
+ }
+
+ m_last_trig = m_trig;
+ }
+
+ NETLIB_HANDLERI(cv)
+ {
+ if (m_state == 1)
+ {
+ const nl_fptype vLow = m_KP * m_RP().P()();
+ if (m_CV() < vLow)
+ {
+ m_RN_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
+ m_state = 2; // charging
+ }
+ }
+ if (m_state == 2)
+ {
+ const nl_fptype vHigh = (nlconst::one() - m_KP) * m_RP().P()();
+ if (m_CV() > vHigh)
+ {
+ m_RP_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
+
+ m_Q.push(0, NLTIME_FROM_NS(10));
+ m_QQ.push(1, NLTIME_FROM_NS(10));
+ m_state = 0; // waiting
+ }
+ }
+ }
+
+ NETLIB_RESETI()
+ {
+ m_RP().reset();
+ m_RN().reset();
+
+ //m_RP.set_R(R_OFF);
+ //m_RN.set_R(R_OFF);
+
+ m_last_trig = 0;
+ m_state = 0;
+ }
private:
- int m_dev_type;
- public:
- NETLIB_SUB(res_sw) m_RP;
- NETLIB_SUB(res_sw) m_RN;
+ NETLIB_SUB(sys_dsw1) m_RP;
+ NETLIB_SUB(sys_dsw1) m_RN;
logic_output_t m_RP_Q;
logic_output_t m_RN_Q;
- logic_input_t m_A;
- logic_input_t m_B;
- logic_input_t m_CLRQ;
+ object_array_t<logic_input_t, 3> m_I;
logic_output_t m_Q;
logic_output_t m_QQ;
@@ -74,242 +217,74 @@ namespace netlist
state_var<netlist_sig_t> m_last_trig;
state_var<unsigned> m_state;
- state_var<double> m_KP;
-
- param_double_t m_K;
- param_double_t m_RI;
+ nl_fptype m_KP;
+ //nld_power_pins m_power_pins; // not needed, device exposes VCC and GND
};
- NETLIB_OBJECT(74123_dip)
+ struct desc_74123 : public desc_base
{
- NETLIB_CONSTRUCTOR(74123_dip)
- , m_A(*this, "A", 74123)
- , m_B(*this, "B", 74123)
+ using t_AB_to_Q = time_ns<10>;
+ using t_C_to_Q = time_ns<10>;
+ static constexpr nl_fptype K() { return nlconst::magic(0.4); }
+ static constexpr nl_fptype RI() { return nlconst::magic(400.0); }
+
+ static constexpr std::array<const char *, 3> names() { return {"CLRQ", "A", "B"};}
+ template<typename T>
+ static netlist_sig_t trigfunc(const T &in)
{
- register_subalias("1", m_A.m_A);
- register_subalias("2", m_A.m_B);
- register_subalias("3", m_A.m_CLRQ);
- register_subalias("4", m_A.m_QQ);
- register_subalias("5", m_B.m_Q);
- register_subalias("6", m_B.m_RN.m_R.m_N);
- register_subalias("7", m_B.m_RN.m_R.m_P);
- register_subalias("8", m_A.m_RN.m_R.m_N);
- connect(m_A.m_RN.m_R.m_N, m_B.m_RN.m_R.m_N);
-
- register_subalias("9", m_B.m_A);
- register_subalias("10", m_B.m_B);
- register_subalias("11", m_B.m_CLRQ);
- register_subalias("12", m_B.m_QQ);
- register_subalias("13", m_A.m_Q);
- register_subalias("14", m_A.m_RN.m_R.m_N);
- register_subalias("15", m_A.m_RN.m_R.m_P);
- register_subalias("16", m_A.m_RP.m_R.m_P);
- connect(m_A.m_RP.m_R.m_P, m_B.m_RP.m_R.m_P);
+ return ((in[1]() | (in[2]() ^ 1)) ^ 1) & in[0](); // ((m_A() | (m_B() ^ 1)) ^ 1) & m_CLRQ()
}
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- private:
- NETLIB_SUB(74123) m_A;
- NETLIB_SUB(74123) m_B;
+ template<typename T> static constexpr netlist_sig_t clear(const T &in) { return in[0]();}
+
+ static constexpr const char *vcc() { return "VCC"; }
+ static constexpr const char *gnd() { return "GND"; }
};
- NETLIB_OBJECT(9602_dip)
+ struct desc_74121 : public desc_74123
{
- NETLIB_CONSTRUCTOR(9602_dip)
- , m_A(*this, "A", 9602)
- , m_B(*this, "B", 9602)
+ static constexpr nl_fptype K() { return nlconst::magic(0.7); }
+
+ static constexpr std::array<const char *, 3> names() { return {"A1", "A2", "B"};}
+ template<typename T>
+ static netlist_sig_t trigfunc(const T &in)
{
- register_subalias("1", m_A.m_RN.m_R.m_N); // C1
- register_subalias("2", m_A.m_RN.m_R.m_P); // RC1
- register_subalias("3", m_A.m_CLRQ);
- register_subalias("4", m_A.m_B);
- register_subalias("5", m_A.m_A);
- register_subalias("6", m_A.m_Q);
- register_subalias("7", m_A.m_QQ);
- register_subalias("8", m_A.m_RN.m_R.m_N);
- connect(m_A.m_RN.m_R.m_N, m_B.m_RN.m_R.m_N);
-
- register_subalias("9", m_B.m_QQ);
- register_subalias("10", m_B.m_Q);
- register_subalias("11", m_B.m_A);
- register_subalias("12", m_B.m_B);
- register_subalias("13", m_B.m_CLRQ);
- register_subalias("14", m_B.m_RN.m_R.m_P); // RC2
- register_subalias("15", m_B.m_RN.m_R.m_N); // C2
- register_subalias("16", m_A.m_RP.m_R.m_P);
- connect(m_A.m_RP.m_R.m_P, m_B.m_RP.m_R.m_P);
+ return ((in[0]() ^ 1) | (in[1]() ^ 1)) & in[2](); // (~A1 | ~A2) & B
}
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- private:
- NETLIB_SUB(74123) m_A;
- NETLIB_SUB(74123) m_B;
+ template<typename T> static constexpr netlist_sig_t clear([[maybe_unused]] const T &in) { return 1; }
};
- NETLIB_OBJECT(4538_dip)
+ struct desc_9602 : public desc_74123
{
- NETLIB_CONSTRUCTOR(4538_dip)
- NETLIB_FAMILY("CD4XXX")
- , m_A(*this, "A", 4538)
- , m_B(*this, "B", 4538)
+ template<typename T>
+ static netlist_sig_t trigfunc(const T &in)
{
- register_subalias("1", m_A.m_RN.m_R.m_N); // C1
- register_subalias("2", m_A.m_RN.m_R.m_P); // RC1
- register_subalias("3", m_A.m_CLRQ);
- register_subalias("4", m_A.m_A);
- register_subalias("5", m_A.m_B);
- register_subalias("6", m_A.m_Q);
- register_subalias("7", m_A.m_QQ);
- register_subalias("8", m_A.m_RN.m_R.m_N);
- connect(m_A.m_RN.m_R.m_N, m_B.m_RN.m_R.m_N);
-
- register_subalias("9", m_B.m_QQ);
- register_subalias("10", m_B.m_Q);
- register_subalias("11", m_B.m_B);
- register_subalias("12", m_B.m_A);
- register_subalias("13", m_B.m_CLRQ);
- register_subalias("14", m_B.m_RN.m_R.m_P); // RC2
- register_subalias("15", m_B.m_RN.m_R.m_N); // C2
- register_subalias("16", m_A.m_RP.m_R.m_P);
- connect(m_A.m_RP.m_R.m_P, m_B.m_RP.m_R.m_P);
+ return ((in[1]() ^ 1) | in[2]()); // (m_A() ^ 1) | m_B()
}
- NETLIB_RESETI();
- NETLIB_UPDATEI();
- private:
- NETLIB_SUB(74123) m_A;
- NETLIB_SUB(74123) m_B;
};
- NETLIB_UPDATE(74123)
+ struct desc_4538 : public desc_74123
{
- netlist_sig_t m_trig;
- netlist_sig_t res = !m_CLRQ();
- netlist_time t_AB_to_Q = NLTIME_FROM_NS(10);
- netlist_time t_C_to_Q = NLTIME_FROM_NS(10);
+ using t_AB_to_Q = time_ns<300>;
+ using t_C_to_Q = time_ns<250>;
+ static constexpr nl_fptype K() { return nlconst::one(); } // CD4538 datasheet states PW=RC
- if (m_dev_type == 74123)
+ template<typename T>
+ static netlist_sig_t trigfunc(const T &in)
{
- m_trig = (m_A() ^ 1) & m_B() & m_CLRQ();
+ return (in[1]() | (in[2]() ^ 1)); // m_A() | (m_B() ^ 1)
}
- else if (m_dev_type == 9602)
- {
- m_trig = (m_A() ^ 1) | m_B();
- }
- else // 4538
- {
- m_trig = (m_B() ^ 1) | m_A();
- // The line below is from the datasheet truthtable ... doesn't make sense at all
- //res = res | m_A) | (m_B) ^ 1);
- t_AB_to_Q = NLTIME_FROM_NS(300);
- t_C_to_Q = NLTIME_FROM_NS(250);
- }
-
- if (res)
- {
- m_Q.push(0, t_C_to_Q);
- m_QQ.push(1, t_C_to_Q);
- /* quick charge until trigger */
- /* FIXME: SGS datasheet shows quick charge to 5V,
- * though schematics indicate quick charge to Vhigh only.
- */
- m_RP_Q.push(1, t_C_to_Q); // R_ON
- m_RN_Q.push(0, t_C_to_Q); // R_OFF
- m_state = 2; //charging (quick)
- }
- else if (!m_last_trig && m_trig)
- {
- // FIXME: Timing!
- m_Q.push(1, t_AB_to_Q);
- m_QQ.push(0,t_AB_to_Q);
-
- m_RN_Q.push(1, t_AB_to_Q); // R_ON
- m_RP_Q.push(0, t_AB_to_Q); // R_OFF
-
- m_state = 1; // discharging
- }
-
- m_last_trig = m_trig;
-
- if (m_state == 1)
- {
- const nl_double vLow = m_KP * m_RP.m_R.m_P();
- if (m_CV() < vLow)
- {
- m_RN_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
- m_state = 2; // charging
- }
- }
- if (m_state == 2)
- {
- const nl_double vHigh = m_RP.m_R.m_P() * (1.0 - m_KP);
- if (m_CV() > vHigh)
- {
- m_RP_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
-
- m_Q.push(0, NLTIME_FROM_NS(10));
- m_QQ.push(1, NLTIME_FROM_NS(10));
- m_state = 0; // waiting
- }
- }
- }
-
- NETLIB_RESET(74123)
- {
- m_KP = 1.0 / (1.0 + exp(m_K()));
-
- m_RP.reset();
- m_RN.reset();
-
- //m_RP.set_R(R_OFF);
- //m_RN.set_R(R_OFF);
-
- m_last_trig = 0;
- m_state = 0;
- }
-
- NETLIB_UPDATE(74123_dip)
- {
- /* only called during startup */
- //_1.update_dev();
- //m_2.update_dev();
- }
-
- NETLIB_RESET(74123_dip)
- {
- //m_1.reset();
- //m_2.reset();
- }
-
- NETLIB_UPDATE(9602_dip)
- {
- /* only called during startup */
- //m_1.update_dev();
- //m_2.update_dev();
- }
-
- NETLIB_RESET(9602_dip)
- {
- //m_1.reset();
- //m_2.reset();
- }
-
- NETLIB_UPDATE(4538_dip)
- {
- /* only called during startup */
- //m_1.update_dev();
- //m_2.update_dev();
- }
+ static constexpr const char *vcc() { return "VDD"; }
+ static constexpr const char *gnd() { return "VSS"; }
+ };
- NETLIB_RESET(4538_dip)
- {
- m_A.reset();
- m_B.reset();
- }
+ using NETLIB_NAME(74123) = NETLIB_NAME(74123_base)<desc_74123>;
+ using NETLIB_NAME(74121) = NETLIB_NAME(74123_base)<desc_74121>;
+ using NETLIB_NAME(4538) = NETLIB_NAME(74123_base)<desc_4538>;
+ using NETLIB_NAME(9602) = NETLIB_NAME(74123_base)<desc_9602>;
NETLIB_DEVICE_IMPL(74123, "TTL_74123", "")
- NETLIB_DEVICE_IMPL(74123_dip, "TTL_74123_DIP", "")
- NETLIB_DEVICE_IMPL(4538_dip, "CD4538_DIP", "")
- NETLIB_DEVICE_IMPL(9602_dip, "TTL_9602_DIP", "")
+ NETLIB_DEVICE_IMPL(74121, "TTL_74121", "")
+ NETLIB_DEVICE_IMPL(4538, "CD4538", "")
+ NETLIB_DEVICE_IMPL(9602, "TTL_9602", "")
- } //namespace devices
-} // namespace netlist
+} // namespace netlist::devices