diff options
author | 2020-05-17 15:17:20 +0200 | |
---|---|---|
committer | 2020-05-17 19:52:09 +0200 | |
commit | 22fb995337f7f1d666f411c15873c7fe858e022f (patch) | |
tree | 23d551612dcec40d44de58bd9fca7436143518f8 /src | |
parent | 7d8384419f05006e8971aaf7727bbadf03a0cd32 (diff) |
netlist: Add working 74125 and 74126 implementations. [Couriersud]
These tristate buffers natively support tristate outputs. For use cases
with fixed enable inputs the devices support a parameter
FORCE_TRISTATE_LOGIC which if being set to 1 makes the device behave
like a logic output.
Added additional syntax and consistency checks for tristate outputs.
Updated the example and added dip implementations including
documentation.
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/netlist/devices/net_lib.h | 1 | ||||
-rw-r--r-- | src/lib/netlist/devices/nld_74125.cpp | 90 | ||||
-rw-r--r-- | src/lib/netlist/devices/nld_74125.h | 81 | ||||
-rw-r--r-- | src/lib/netlist/devices/nld_9316.cpp | 40 | ||||
-rw-r--r-- | src/lib/netlist/devices/nld_ne555.cpp | 25 | ||||
-rw-r--r-- | src/lib/netlist/devices/nld_roms.cpp | 36 | ||||
-rw-r--r-- | src/lib/netlist/devices/nlid_proxy.cpp | 2 | ||||
-rw-r--r-- | src/lib/netlist/examples/74125.cpp | 8 | ||||
-rw-r--r-- | src/lib/netlist/macro/nlm_ttl74xx.cpp | 97 | ||||
-rw-r--r-- | src/lib/netlist/nl_base.cpp | 13 | ||||
-rw-r--r-- | src/lib/netlist/nl_base.h | 154 | ||||
-rw-r--r-- | src/lib/netlist/nl_errstr.h | 9 | ||||
-rwxr-xr-x | src/lib/netlist/nl_setup.cpp | 22 | ||||
-rw-r--r-- | src/lib/netlist/nltypes.h | 50 |
14 files changed, 321 insertions, 307 deletions
diff --git a/src/lib/netlist/devices/net_lib.h b/src/lib/netlist/devices/net_lib.h index 9d36c9a48ad..decca40aac7 100644 --- a/src/lib/netlist/devices/net_lib.h +++ b/src/lib/netlist/devices/net_lib.h @@ -54,6 +54,7 @@ #include "nld_4316.h" #include "nld_74107.h" #include "nld_74123.h" +#include "nld_74125.h" #include "nld_74153.h" #include "nld_74161.h" #include "nld_74164.h" diff --git a/src/lib/netlist/devices/nld_74125.cpp b/src/lib/netlist/devices/nld_74125.cpp index bac94c18d22..92a800d7038 100644 --- a/src/lib/netlist/devices/nld_74125.cpp +++ b/src/lib/netlist/devices/nld_74125.cpp @@ -1,13 +1,15 @@ // license:GPL-2.0+ // copyright-holders:Couriersud /* - * nld_74125.c + * nld_74125.cpp * */ #include "nld_74125.h" #include "nl_base.h" +#include <type_traits> + namespace netlist { template <typename T> @@ -17,16 +19,9 @@ namespace netlist using base_type = unique_pool_ptr<T>; - template<typename O, typename... Args, class = typename std::enable_if< - std::is_base_of<core_device_t, O>::value>::type> - uptr(O &owner, const pstring &name, Args&&... args) - : unique_pool_ptr<T>(static_cast<core_device_t &>(owner).state().make_object<T>(owner, name, std::forward<Args>(args)...)) - { } - template<typename O, typename... Args> - uptr(typename std::enable_if< - std::is_base_of<netlist_state_t, O>::value, O>::type &owner, const pstring &name, Args&&... args) - : unique_pool_ptr<T>(static_cast<netlist_state_t>(owner).make_object<T>(owner, name, std::forward<Args>(args)...)) + uptr(O &owner, const pstring &name, Args&&... args) + : unique_pool_ptr<T>(owner.template make_object<T>(owner, name, std::forward<Args>(args)...)) { } C14CONSTEXPR auto operator ()() noexcept -> decltype((*unique_pool_ptr<T>::get())()) { return (*this->get())(); } @@ -36,13 +31,15 @@ namespace netlist namespace devices { - template <netlist_sig_t INVERT_G> + template <typename D> NETLIB_OBJECT(74125_base) { NETLIB_CONSTRUCTOR(74125_base) + , m_TE(*this, "FORCE_TRISTATE_LOGIC", 0) , m_A(*this, "A", NETLIB_DELEGATE(74125_base, A)) - , m_G(*this, "G", NETLIB_DELEGATE(74125_base, G)) - , m_Y(*this, "Y", NLTIME_FROM_NS(11), NLTIME_FROM_NS(13)) + , m_G(*this, pstring(D::invert_g::value ? "GQ" : "G"), NETLIB_DELEGATE(74125_base, G)) + , m_Y(*this, "Y", m_TE()) + //, m_Y(*this, "Y") , m_power_pins(*this) { } @@ -56,67 +53,48 @@ namespace netlist { // this one is only called during startup. Ensure all outputs // are in a consistent state. - m_Y.set_tristate(m_G() ^ INVERT_G); - m_Y.push(m_A(), m_A() ? NLTIME_FROM_NS(8) : NLTIME_FROM_NS(12)); + m_Y.set_tristate(m_G() ^ D::invert_g::value, + D::ts_off_on::value(), D::ts_on_off::value()); + m_Y.push(m_A(), m_A() ? D::sig_off_on::value() : D::sig_on_off::value()); } NETLIB_HANDLERI(A) { - m_Y.push(m_A(), m_A() ? NLTIME_FROM_NS(8) : NLTIME_FROM_NS(12)); + m_Y.push(m_A(), m_A() ? D::sig_off_on::value() : D::sig_on_off::value()); } NETLIB_HANDLERI(G) { - m_Y.set_tristate(m_G() ^ INVERT_G); + m_Y.set_tristate(m_G() ^ D::invert_g::value, + D::ts_off_on::value(), D::ts_on_off::value()); } + param_logic_t m_TE; logic_input_t m_A; uptr<logic_input_t> m_G; tristate_output_t m_Y; nld_power_pins m_power_pins; }; -#if 0 - template <bool ASYNC> - NETLIB_OBJECT(74125_dip_base) + struct desc_74125 { - NETLIB_CONSTRUCTOR(74125_dip_base) - , A(*this, "A") - { - this->register_subalias("1", "A.CLRQ"); - this->register_subalias("2", "A.CLK"); - this->register_subalias("3", "A.A"); - this->register_subalias("4", "A.B"); - this->register_subalias("5", "A.C"); - this->register_subalias("6", "A.D"); - this->register_subalias("7", "A.ENP"); - this->register_subalias("8", "A.GND"); - - this->register_subalias("9", "A.LOADQ"); - this->register_subalias("10", "A.ENT"); - this->register_subalias("11", "A.QD"); - this->register_subalias("12", "A.QC"); - this->register_subalias("13", "A.QB"); - this->register_subalias("14", "A.QA"); - this->register_subalias("15", "A.RC"); - this->register_subalias("16", "A.VCC"); - } - private: - NETLIB_SUB(74125_base)<ASYNC> A; + using invert_g = desc_const<1>; + using ts_off_on = time_ns<11>; + using ts_on_off = time_ns<13>; + using sig_off_on = time_ns<8>; + using sig_on_off = time_ns<12>; + }; + + struct desc_74126 : public desc_74125 + { + using invert_g = desc_const<0>; }; - using NETLIB_NAME(74163) = NETLIB_NAME(74125_base)<false>; - using NETLIB_NAME(74125_dip) = NETLIB_NAME(74125_dip_base)<true>; - using NETLIB_NAME(74163_dip) = NETLIB_NAME(74125_dip_base)<false>; - NETLIB_DEVICE_IMPL(74125_dip, "TTL_74125_DIP", "") - - NETLIB_DEVICE_IMPL(74163, "TTL_74163", "+CLK,+ENP,+ENT,+CLRQ,+LOADQ,+A,+B,+C,+D,@VCC,@GND") - NETLIB_DEVICE_IMPL(74163_dip, "TTL_74163_DIP", "") -#endif - using NETLIB_NAME(74125) = NETLIB_NAME(74125_base)<1>; - using NETLIB_NAME(74126) = NETLIB_NAME(74125_base)<0>; - - NETLIB_DEVICE_IMPL(74125, "TTL_74125", "") - NETLIB_DEVICE_IMPL(74126, "TTL_74126", "") + + using NETLIB_NAME(74125) = NETLIB_NAME(74125_base)<desc_74125>; + using NETLIB_NAME(74126) = NETLIB_NAME(74125_base)<desc_74126>; + + NETLIB_DEVICE_IMPL(74125, "TTL_74125_GATE", "") + NETLIB_DEVICE_IMPL(74126, "TTL_74126_GATE", "") } //namespace devices } // namespace netlist diff --git a/src/lib/netlist/devices/nld_74125.h b/src/lib/netlist/devices/nld_74125.h index 38f9f245a9a..d192d776977 100644 --- a/src/lib/netlist/devices/nld_74125.h +++ b/src/lib/netlist/devices/nld_74125.h @@ -3,49 +3,6 @@ /* * nld_74125.h * - * DM74125: Synchronous 4-Bit Counters - * - * +--------------+ - * /CLEAR |1 ++ 16| VCC - * CLOCK |2 15| RC (Ripple Carry) - * A |3 14| QA - * B |4 74125 13| QB - * C |5 12| QC - * D |6 11| QD - * Enable P |7 10| Enable T - * GND |8 9| /LOAD - * +--------------+ - * - * Counter Sequence - * - * +-------++----+----+----+----+----+ - * | COUNT || QD | QC | QB | QA | RC | - * +=======++====+====+====+====+====+ - * | 0 || 0 | 0 | 0 | 0 | 0 | - * | 1 || 0 | 0 | 0 | 1 | 0 | - * | 2 || 0 | 0 | 1 | 0 | 0 | - * | 3 || 0 | 0 | 1 | 1 | 0 | - * | 4 || 0 | 1 | 0 | 0 | 0 | - * | 5 || 0 | 1 | 0 | 1 | 0 | - * | 6 || 0 | 1 | 1 | 0 | 0 | - * | 7 || 0 | 1 | 1 | 1 | 0 | - * | 8 || 1 | 0 | 0 | 0 | 0 | - * | 9 || 1 | 0 | 0 | 1 | 0 | - * | 10 || 1 | 0 | 1 | 0 | 0 | - * | 11 || 1 | 0 | 1 | 1 | 0 | - * | 12 || 1 | 1 | 0 | 0 | 0 | - * | 13 || 1 | 1 | 0 | 1 | 0 | - * | 14 || 1 | 1 | 1 | 0 | 0 | - * | 15 || 1 | 1 | 1 | 1 | 1 | - * +-------++----+----+----+----+----+ - * - * Reset count function: Please refer to - * National Semiconductor datasheet (timing diagram) - * - * Naming conventions follow National Semiconductor datasheet - * - * TODO: DM74161 is compatible to DM74125 (both asynchronous clear) - * DM74163 has asynchronous clear (on L to H transition of clock) */ #ifndef NLD_74125_H_ @@ -53,40 +10,10 @@ #include "netlist/nl_setup.h" -#if 0 -#define TTL_74125(name, cCLK, cENP, cENT, cCLRQ, cLOADQ, cA, cB, cC, cD) \ - NET_REGISTER_DEV(TTL_74125, name) \ - NET_CONNECT(name, GND, GND) \ - NET_CONNECT(name, VCC, VCC) \ - NET_CONNECT(name, CLK, cCLK) \ - NET_CONNECT(name, ENP, cENP) \ - NET_CONNECT(name, ENT, cENT) \ - NET_CONNECT(name, CLRQ, cCLRQ) \ - NET_CONNECT(name, LOADQ, cLOADQ) \ - NET_CONNECT(name, A, cA) \ - NET_CONNECT(name, B, cB) \ - NET_CONNECT(name, C, cC) \ - NET_CONNECT(name, D, cD) - -#define TTL_74163(name, cCLK, cENP, cENT, cCLRQ, cLOADQ, cA, cB, cC, cD) \ - NET_REGISTER_DEV(TTL_74163, name) \ - NET_CONNECT(name, GND, GND) \ - NET_CONNECT(name, VCC, VCC) \ - NET_CONNECT(name, CLK, cCLK) \ - NET_CONNECT(name, ENP, cENP) \ - NET_CONNECT(name, ENT, cENT) \ - NET_CONNECT(name, CLRQ, cCLRQ) \ - NET_CONNECT(name, LOADQ, cLOADQ) \ - NET_CONNECT(name, A, cA) \ - NET_CONNECT(name, B, cB) \ - NET_CONNECT(name, C, cC) \ - NET_CONNECT(name, D, cD) - -#define TTL_74125_DIP(name) \ - NET_REGISTER_DEV(TTL_74125_DIP, name) +#define TTL_74125_GATE(...) \ + NET_REGISTER_DEV(TTL_74125_GATE, __VA_ARGS__) -#define TTL_74163_DIP(name) \ - NET_REGISTER_DEV(TTL_74163_DIP, name) -#endif +#define TTL_74126_GATE(...) \ + NET_REGISTER_DEV(TTL_74126_GATE, __VA_ARGS__) #endif /* NLD_74125_H_ */ diff --git a/src/lib/netlist/devices/nld_9316.cpp b/src/lib/netlist/devices/nld_9316.cpp index a6879ff6f47..7404370205c 100644 --- a/src/lib/netlist/devices/nld_9316.cpp +++ b/src/lib/netlist/devices/nld_9316.cpp @@ -31,9 +31,7 @@ namespace netlist , m_ABCD(*this, {"A", "B", "C", "D"}, NETLIB_DELEGATE(9316_base, abcd)) , m_Q(*this, { "QA", "QB", "QC", "QD" }) , m_cnt(*this, "m_cnt", 0) - , m_abcd(*this, "m_abcd", 0) - , m_loadq(*this, "m_loadq", 0) - , m_ent(*this, "m_ent", 0) + //, m_abcd(*this, "m_abcd", 0) , m_power_pins(*this) { } @@ -43,16 +41,14 @@ namespace netlist { m_CLK.set_state(logic_t::STATE_INP_LH); m_cnt = 0; - m_abcd = 0; + //m_abcd = 0; } NETLIB_UPDATEI() { const auto CLRQ(m_CLRQ()); - m_ent = m_ENT(); - m_loadq = m_LOADQ(); - if (((m_loadq ^ 1) || (m_ent && m_ENP())) && (!ASYNC || CLRQ)) + if (((m_LOADQ() ^ 1) || (m_ENT() && m_ENP())) && (!ASYNC || CLRQ)) { m_CLK.activate_lh(); } @@ -61,11 +57,11 @@ namespace netlist m_CLK.inactivate(); if (ASYNC && !CLRQ && (m_cnt>0)) { - update_outputs_all(0, NLTIME_FROM_NS(36)); m_cnt = 0; + m_Q.push(m_cnt, NLTIME_FROM_NS(36)); } } - m_RC.push(m_ent && (m_cnt == MAXCNT), NLTIME_FROM_NS(27)); + m_RC.push(m_ENT() && (m_cnt == MAXCNT), NLTIME_FROM_NS(27)); } @@ -73,21 +69,22 @@ namespace netlist { if (!ASYNC && !m_CLRQ()) { - update_outputs_all(0, NLTIME_FROM_NS(36)); - m_cnt = 0; + m_cnt = 0; + m_Q.push(m_cnt, NLTIME_FROM_NS(36)); } else { - auto cnt = (m_loadq ? (m_cnt + 1) & MAXCNT: m_abcd); - m_RC.push(m_ent && (cnt == MAXCNT), NLTIME_FROM_NS(27)); - update_outputs_all(cnt, NLTIME_FROM_NS(20)); - m_cnt = cnt; + //const auto cnt = (m_LOADQ() ? (m_cnt + 1) & MAXCNT: m_abcd); + const auto cnt = (m_LOADQ() ? (m_cnt + 1) & MAXCNT: m_ABCD()); + m_RC.push(m_ENT() && (cnt == MAXCNT), NLTIME_FROM_NS(27)); + m_Q.push(cnt, NLTIME_FROM_NS(20)); + m_cnt = static_cast<unsigned>(cnt); } } NETLIB_HANDLERI(abcd) { - m_abcd = static_cast<unsigned>((m_ABCD[0]() << 0) | (m_ABCD[1]() << 1) | (m_ABCD[2]() << 2) | (m_ABCD[3]() << 3)); + //m_abcd = static_cast<unsigned>(m_ABCD()); } logic_input_t m_CLK; @@ -106,18 +103,9 @@ namespace netlist /* counter state */ state_var<unsigned> m_cnt; /* cached pins */ - state_var<unsigned> m_abcd; - state_var_sig m_loadq; - state_var_sig m_ent; + //state_var<unsigned> m_abcd; nld_power_pins m_power_pins; - void update_outputs_all(unsigned cnt, netlist_time out_delay) noexcept - { - m_Q[0].push((cnt >> 0) & 1, out_delay); - m_Q[1].push((cnt >> 1) & 1, out_delay); - m_Q[2].push((cnt >> 2) & 1, out_delay); - m_Q[3].push((cnt >> 3) & 1, out_delay); - } }; template <bool ASYNC> diff --git a/src/lib/netlist/devices/nld_ne555.cpp b/src/lib/netlist/devices/nld_ne555.cpp index ae8cb1b0d52..f77d2302955 100644 --- a/src/lib/netlist/devices/nld_ne555.cpp +++ b/src/lib/netlist/devices/nld_ne555.cpp @@ -115,7 +115,7 @@ namespace netlist return ret; } }; -#if 1 + NETLIB_OBJECT(NE555_dip) { NETLIB_CONSTRUCTOR(NE555_dip) @@ -138,32 +138,9 @@ namespace netlist private: NETLIB_SUB(NE555) A; }; -#else - NETLIB_OBJECT_DERIVED(NE555_dip, NE555) - { - NETLIB_CONSTRUCTOR_DERIVED(NE555_dip) - { - 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 - } - }; -#endif NETLIB_RESET(NE555) { -#if 0 - m_R1.reset(); - m_R2.reset(); - m_R3.reset(); - m_ROUT.reset(); - m_RDIS.reset(); -#endif /* FIXME make resistances a parameter, properly model other variants */ m_R1.set_R(nlconst::magic(5000)); m_R2.set_R(nlconst::magic(5000)); diff --git a/src/lib/netlist/devices/nld_roms.cpp b/src/lib/netlist/devices/nld_roms.cpp index 5a7bc9fa59b..47adbc9d9fa 100644 --- a/src/lib/netlist/devices/nld_roms.cpp +++ b/src/lib/netlist/devices/nld_roms.cpp @@ -25,42 +25,6 @@ namespace netlist namespace devices { - template<netlist_time::internal_type value0> - struct times_ns1 - { - static constexpr netlist_time value(std::size_t N = 0) - { - plib::unused_var(N); - return NLTIME_FROM_NS(value0); - } - }; - - template <netlist_time::internal_type value0> - using time_ns = times_ns1<value0>; - - template<netlist_time::internal_type value0, - netlist_time::internal_type value1> - struct times_ns2 - { - static constexpr netlist_time value(std::size_t N) - { - return NLTIME_FROM_NS(N == 0 ? value0 : value1); - } - }; - - template<netlist_time::internal_type value0, - netlist_time::internal_type value1, - netlist_time::internal_type value2> - struct times_ns3 - { - static constexpr netlist_time value(std::size_t N) - { - return NLTIME_FROM_NS(N == 0 ? value0 : - N == 1 ? value1 : - value2); - } - }; - template <typename D> NETLIB_OBJECT(generic_prom) { diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp index fb0ba84c5a8..74ba40f5fe3 100644 --- a/src/lib/netlist/devices/nlid_proxy.cpp +++ b/src/lib/netlist/devices/nlid_proxy.cpp @@ -187,7 +187,7 @@ namespace netlist nlconst::zero()); break; default: - printf("this should never happen!"); + throw nl_exception("unknown state for proxy: this should never happen! %d\n", static_cast<int>(state)); } }); m_last_state = state; diff --git a/src/lib/netlist/examples/74125.cpp b/src/lib/netlist/examples/74125.cpp index 807d8bf27c8..640e2bd8b86 100644 --- a/src/lib/netlist/examples/74125.cpp +++ b/src/lib/netlist/examples/74125.cpp @@ -18,8 +18,9 @@ NETLIST_START(main) ANALOG_INPUT(VCC, 5.0) - TTL_74125(X1) - TTL_74126(X2) + TTL_74125_GATE(X1) + TTL_74126_GATE(X2) + PARAM(X2.FORCE_TRISTATE_LOGIC, 0) CLOCK(C1, 100) CLOCK(C2, 300) @@ -29,9 +30,10 @@ NETLIST_START(main) NET_C(C1.Q, X1.A) NET_C(C2.Q, X2.A) - NET_C(C3.Q, X1.G, X2.G) + NET_C(C3.Q, X1.GQ, X2.G) NET_C(X1.Y, X2.Y, RL.1) + //NET_C(X1.Y, RL.1) NET_C(GND, RL.2, C1.GND, C2.GND, C3.GND, X1.GND, X2.GND) NET_C(VCC, C1.VCC, C2.VCC, C3.VCC, X1.VCC, X2.VCC) diff --git a/src/lib/netlist/macro/nlm_ttl74xx.cpp b/src/lib/netlist/macro/nlm_ttl74xx.cpp index 8485ce86c86..28c8daf6fe8 100644 --- a/src/lib/netlist/macro/nlm_ttl74xx.cpp +++ b/src/lib/netlist/macro/nlm_ttl74xx.cpp @@ -694,6 +694,101 @@ NETLIST_END() * */ +//- Identifier: TTL_74125_DIP +//- Title: SN74125 QUADRUPLE BUS BUFFERS WITH 3-STATE OUTPUTS +//- Description: These bus buffers feature three-state outputs +//- that, when enabled, have the low impedance characteristics of a +//- TTL output with additional drive capability at high logic levels +//- to permit driving heavily loaded bus lines without external +//- pullup resistors. When disabled, both output transistors are turned +//- off, presenting a high-impedance state to the bus so the output will +//- act neither as a significant load nor as a driver. The ’125 and +//- ’LS125A devices’ outputs are disabled when G is high. +//- The ’126 and ’LS126A devices’ outputs are disabled when G is low +//- +//- Pinalias: 1GQ,1A,1Y,2GQ,2A,2Y,GND,3Y,3A,3GQ,4Y,4A,4GQ,VCC +//- Package: DIP +//- NamingConvention: Naming conventions follow Texas instruments datasheet +//- Limitations: +//- No limitations +//- +//- Example: 74125.cpp,74125_example +//- +//- FunctionTable: +//- +//- | GQ | A | Y | +//- |:---:|:--:|:--:| +//- | L | L | L | +//- | L | H | H | +//- | H | X | Z | +//- + +static NETLIST_START(TTL_74125_DIP) + + TTL_74125_GATE(A1) + TTL_74125_GATE(A2) + TTL_74125_GATE(A3) + TTL_74125_GATE(A4) + + DEFPARAM(FORCE_TRISTATE_LOGIC, 0) + PARAM(A1.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + PARAM(A2.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + PARAM(A3.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + PARAM(A4.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + + ALIAS(1, A1.GQ) + ALIAS(2, A1.A) + ALIAS(3, A1.Y) + ALIAS(4, A2.GQ) + ALIAS(5, A2.A) + ALIAS(6, A2.Y) + ALIAS(7, A1.GND) + + ALIAS(8, A3.Y) + ALIAS(9, A3.A) + ALIAS(10, A3.GQ) + ALIAS(11, A4.Y) + ALIAS(12, A4.A) + ALIAS(13, A4.GQ) + ALIAS(14, A1.VCC) + + NET_C(A1.VCC, A2.VCC, A3.VCC, A4.VCC) + NET_C(A1.GND, A2.GND, A3.GND, A4.GND) +NETLIST_END() + +static NETLIST_START(TTL_74126_DIP) + + TTL_74126_GATE(A1) + TTL_74126_GATE(A2) + TTL_74126_GATE(A3) + TTL_74126_GATE(A4) + + DEFPARAM(FORCE_TRISTATE_LOGIC, 0) + PARAM(A1.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + PARAM(A2.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + PARAM(A3.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + PARAM(A4.FORCE_TRISTATE_LOGIC, "$(@.FORCE_TRISTATE_LOGIC)") + + ALIAS(1, A1.G) + ALIAS(2, A1.A) + ALIAS(3, A1.Y) + ALIAS(4, A2.G) + ALIAS(5, A2.A) + ALIAS(6, A2.Y) + ALIAS(7, A1.GND) + + ALIAS(8, A3.Y) + ALIAS(9, A3.A) + ALIAS(10, A3.G) + ALIAS(11, A4.Y) + ALIAS(12, A4.A) + ALIAS(13, A4.G) + ALIAS(14, A1.VCC) + + NET_C(A1.VCC, A2.VCC, A3.VCC, A4.VCC) + NET_C(A1.GND, A2.GND, A3.GND, A4.GND) +NETLIST_END() + static NETLIST_START(TTL_74155_DIP) NET_REGISTER_DEV(TTL_74155A_GATE, A) NET_REGISTER_DEV(TTL_74155B_GATE, B) @@ -1514,6 +1609,8 @@ NETLIST_START(TTL74XX_lib) LOCAL_LIB_ENTRY(TTL_7448_DIP) #endif LOCAL_LIB_ENTRY(TTL_7486_DIP) + LOCAL_LIB_ENTRY(TTL_74125_DIP) + LOCAL_LIB_ENTRY(TTL_74126_DIP) #if (NL_USE_TRUTHTABLE_74107) LOCAL_LIB_ENTRY(TTL_74107_DIP) #endif diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp index 3da7fa70ba9..f0e3516ea68 100644 --- a/src/lib/netlist/nl_base.cpp +++ b/src/lib/netlist/nl_base.cpp @@ -77,14 +77,6 @@ namespace netlist } } -#if 0 - // ---------------------------------------------------------------------------------------- - // netlist_ref_t - // ---------------------------------------------------------------------------------------- - - detail::netlist_ref::netlist_ref(netlist_t &nl) - : m_netlist(nl) { } -#endif // ---------------------------------------------------------------------------------------- // device_object_t // ---------------------------------------------------------------------------------------- @@ -907,6 +899,11 @@ namespace netlist return dynamic_cast<const logic_output_t *>(this) != nullptr; } + bool detail::core_terminal_t::is_tristate_output() const noexcept + { + return dynamic_cast<const tristate_output_t *>(this) != nullptr; + } + bool detail::core_terminal_t::is_analog() const noexcept { return dynamic_cast<const analog_t *>(this) != nullptr; diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 6d52fed38ea..5f4a576207d 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -565,6 +565,10 @@ namespace netlist netlist_t & exec() noexcept { return m_netlist; } const netlist_t & exec() const noexcept { return m_netlist; } + // to ease template design + template<typename T, typename... Args> + unique_pool_ptr<T> make_object(Args&&... args); + private: netlist_t & m_netlist; @@ -672,6 +676,7 @@ namespace netlist bool is_logic() const noexcept; bool is_logic_input() const noexcept; bool is_logic_output() const noexcept; + bool is_tristate_output() const noexcept; bool is_analog() const noexcept; bool is_analog_input() const noexcept; bool is_analog_output() const noexcept; @@ -1024,17 +1029,28 @@ namespace netlist // tristate_output_t // ----------------------------------------------------------------------------- + /// \brief Tristate output + /// + /// In a lot of applications tristate enable inputs are just connected to + /// VCC/GND to permanently enable the outputs. In this case a pure + /// implementation using analog outputs would not perform well. + /// + /// For this object during creation it can be decided if a logic output or + /// a tristate output is used. Generally the owning device uses parameter + /// FORCE_TRISTATE_LOGIC to determine this. + /// + /// This is the preferred way to implement tristate outputs. + /// + class tristate_output_t : public logic_output_t { public: - tristate_output_t(device_t &dev, const pstring &aname, - netlist_time ts_off_on, netlist_time ts_on_off) + tristate_output_t(device_t &dev, const pstring &aname, bool force_logic) : logic_output_t(dev, aname) - , m_last_logic(dev, name() + "." + "m_last_logic", 2) // force change + , m_last_logic(dev, name() + "." + "m_last_logic", 1) // force change , m_tristate(dev, name() + "." + "m_tristate", 2) // force change - , m_ts_off_on(ts_off_on) - , m_ts_on_off(ts_on_off) + , m_force_logic(force_logic) {} void push(netlist_sig_t newQ, netlist_time delay) noexcept @@ -1044,13 +1060,21 @@ namespace netlist m_last_logic = newQ; } - void set_tristate(bool v) noexcept + void set_tristate(bool v, + netlist_time ts_off_on, netlist_time ts_on_off) noexcept { - if (v != m_tristate) - { - logic_output_t::push(v ? OUT_TRISTATE() : m_last_logic, v ? m_ts_off_on : m_ts_on_off); - m_tristate = v; - } + //printf("%s %d\n", this->name().c_str(), (int) m_force_logic); + if (!m_force_logic) + if (v != m_tristate) + { + logic_output_t::push(v ? OUT_TRISTATE() : m_last_logic, v ? ts_off_on : ts_on_off); + m_tristate = v; + } + } + + bool is_force_logic() const noexcept + { + return m_force_logic; } private: @@ -1058,9 +1082,10 @@ namespace netlist using logic_output_t::set_Q_time; state_var<netlist_sig_t> m_last_logic; state_var<netlist_sig_t> m_tristate; - const netlist_time m_ts_off_on; - const netlist_time m_ts_on_off; + bool m_force_logic; }; + + // ----------------------------------------------------------------------------- // analog_output_t // ----------------------------------------------------------------------------- @@ -1893,33 +1918,6 @@ namespace netlist this->emplace(i++, dev, pstring(n), std::forward<Args>(args)...); } -#if 0 - template<class D, typename... Args> - object_array_base_t(D &dev, const pstring &fmt, Args&&... args) - { - for (std::size_t i = 0; i<N; i++) - this->emplace(i, dev, formatted(fmt, i), std::forward<Args>(args)...); - } - - template<class D, typename... Args> - object_array_base_t(D &dev, std::size_t offset, const pstring &fmt, Args&&... args) - { - for (std::size_t i = 0; i<N; i++) - this->emplace(i, dev, formatted(fmt, i+offset), std::forward<Args>(args)...); - } - - template<class D, typename... Args> - object_array_base_t(D &dev, std::size_t offset, std::size_t qmask, const pstring &fmt, Args&&... args) - { - for (std::size_t i = 0; i<N; i++) - { - pstring name(formatted(fmt, i+offset)); - if ((qmask >> i) & 1) - name += "Q"; - this->emplace(i, dev, name, std::forward<Args>(args)...); - } - } -#else template<class D> object_array_base_t(D &dev, const pstring &fmt) { @@ -1954,7 +1952,6 @@ namespace netlist } protected: object_array_base_t() = default; -#endif protected: static pstring formatted(const pstring &fmt, std::size_t n) @@ -2002,27 +1999,33 @@ namespace netlist } - using value_type = typename plib::least_type_for_bits<N>::type; + //using value_type = typename plib::least_type_for_bits<N>::type; + using value_type = std::uint_fast32_t; value_type operator ()() { - if (N <= 8) - return tobits(N, *this); - else - { - value_type r(0); - for (std::size_t i = 0; i < N; i++) - r = static_cast<value_type>((*this)[i]() << (N-1)) | (r >> 1); - return r; - } + if (N == 1) return e<0>(); + if (N == 2) return e<0>() | (e<1>() << 1); + if (N == 3) return e<0>() | (e<1>() << 1) | (e<2>() << 2); + if (N == 4) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3); + if (N == 5) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4); + if (N == 6) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4) | (e<5>() << 5); + if (N == 7) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4) | (e<5>() << 5) | (e<6>() << 6); + if (N == 8) return e<0>() | (e<1>() << 1) | (e<2>() << 2) | (e<3>() << 3) + | (e<4>() << 4) | (e<5>() << 5) | (e<6>() << 6) | (e<7>() << 7); + + value_type r(0); + for (std::size_t i = 0; i < N; i++) + r = static_cast<value_type>((*this)[i]() << (N-1)) | (r >> 1); + return r; } private: - template <typename T> - static constexpr value_type tobits(std::size_t n, T &a) - { - return (n == 0 ? 0 : (tobits(n-1, a) | static_cast<value_type>(a[n-1]() << (n-1)))); - } + template <std::size_t P> + inline constexpr value_type e() const { return (*this)[P](); } }; template<std::size_t N> @@ -2032,30 +2035,22 @@ namespace netlist using base_type = object_array_base_t<logic_output_t, N>; using base_type::base_type; - using value_type = typename plib::least_type_for_bits<N>::type; + using value_type = std::uint_fast32_t; + //using value_type = typename plib::least_type_for_bits<N>::type; void push(value_type v, netlist_time t) { - if (N <= 8) - rpush(N, *this, v, t); - else - { - for (std::size_t i = 0; i < N; v = v >> 1, i++) - (*this)[i].push(v & 1, t); - } - } + if (N >= 1) (*this)[0].push((v >> 0) & 1, t); + if (N >= 2) (*this)[1].push((v >> 1) & 1, t); + if (N >= 3) (*this)[2].push((v >> 2) & 1, t); + if (N >= 4) (*this)[3].push((v >> 3) & 1, t); + if (N >= 5) (*this)[4].push((v >> 4) & 1, t); + if (N >= 6) (*this)[5].push((v >> 5) & 1, t); + if (N >= 7) (*this)[6].push((v >> 6) & 1, t); + if (N >= 8) (*this)[7].push((v >> 7) & 1, t); - private: - template <typename A, typename V, typename X> - static V rpush(std::size_t n, A &a, V value, X time) - { - if (n > 0) - { - value = rpush(n-1, a, value, time); - a[n-1].push((value & 1), time); - return value >> 1; - } - return value; + for (std::size_t i = 8; i < N; i++) + (*this)[i].push((v >> i) & 1, t); } }; @@ -2107,6 +2102,13 @@ namespace netlist return m_netlist.nlstate(); } + template<typename T, typename... Args> + inline unique_pool_ptr<T> detail::netlist_object_t::make_object(Args&&... args) + { + return state().make_object<T>(std::forward<Args>(args)...); + } + + inline void param_t::update_param() noexcept { device().update_param(); diff --git a/src/lib/netlist/nl_errstr.h b/src/lib/netlist/nl_errstr.h index 243b7c0812f..49fc786ee56 100644 --- a/src/lib/netlist/nl_errstr.h +++ b/src/lib/netlist/nl_errstr.h @@ -98,6 +98,15 @@ namespace netlist PERRMSGV(ME_TERMINAL_1_WITHOUT_NET, 1, "Found terminal {1} without a net") PERRMSGV(MF_TERMINALS_WITHOUT_NET, 0, "Found terminals without a net") + PERRMSGV(ME_TRISTATE_NO_PROXY_FOUND_2, 2, + "Tristate output {1} on device {2} is not connected to a proxy. You " + "need to set parameter FORCE_TRISTATE_LOGIC for device {2} if " + "tristate enable inputs are all connected to fixed inputs. If this " + "is not the case: Review your netlist. Something is wrong.") + PERRMSGV(ME_TRISTATE_PROXY_FOUND_2, 2, + "The tristate output {1} on device {2} is connected to an analog net " + "but has been forced to act as a logic output. Parameter " + " FORCE_TRISTATE_LOGIC for device {2} needs to be disabled!.") PERRMSGV(MI_REMOVE_DEVICE_1_CONNECTED_ONLY_TO_RAILS_2_3, 3, "Found device {1} connected only to railterminals {2}/{3}. Will be removed") diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp index 1fb515f346a..202bbc33f49 100755 --- a/src/lib/netlist/nl_setup.cpp +++ b/src/lib/netlist/nl_setup.cpp @@ -1084,6 +1084,28 @@ void setup_t::resolve_inputs() log().warning(MW_TERMINAL_1_WITHOUT_CONNECTIONS(term->name())); } } + log().verbose("checking tristate consistency ..."); + for (auto & i : m_terminals) + { + detail::core_terminal_t *term = i.second; + if (term->is_tristate_output()) + { + const auto *tri(static_cast<tristate_output_t *>(term)); + // check if we are connected to a proxy + const auto iter_proxy(m_proxies.find(tri)); + + if (iter_proxy == m_proxies.end() && !tri->is_force_logic()) + { + log().error(ME_TRISTATE_NO_PROXY_FOUND_2(term->name(), term->device().name())); + err = true; + } + else if (iter_proxy != m_proxies.end() && tri->is_force_logic()) + { + log().error(ME_TRISTATE_PROXY_FOUND_2(term->name(), term->device().name())); + err = true; + } + } + } if (err) { log().fatal(MF_TERMINALS_WITHOUT_NET()); diff --git a/src/lib/netlist/nltypes.h b/src/lib/netlist/nltypes.h index 03bb7e30fc0..2e1a4227177 100644 --- a/src/lib/netlist/nltypes.h +++ b/src/lib/netlist/nltypes.h @@ -162,6 +162,56 @@ namespace netlist template <typename T> inline constexpr netlist_time NLTIME_FROM_US(T &&t) noexcept { return netlist_time::from_usec(t); } template <typename T> inline constexpr netlist_time NLTIME_FROM_MS(T &&t) noexcept { return netlist_time::from_msec(t); } + /// \brief: used to hold one static netlist_time value + /// + template<netlist_time::internal_type value0> + struct times_ns1 + { + static constexpr netlist_time value(std::size_t N = 0) + { + plib::unused_var(N); + return NLTIME_FROM_NS(value0); + } + }; + + template <netlist_time::internal_type value0> + using time_ns = times_ns1<value0>; + + /// \brief: used to hold two static netlist_time values + /// + template<netlist_time::internal_type value0, + netlist_time::internal_type value1> + struct times_ns2 + { + static constexpr netlist_time value(std::size_t N) + { + return NLTIME_FROM_NS(N == 0 ? value0 : value1); + } + }; + + /// \brief: used to hold two static netlist_time values + /// + template<netlist_time::internal_type value0, + netlist_time::internal_type value1, + netlist_time::internal_type value2> + struct times_ns3 + { + static constexpr netlist_time value(std::size_t N) + { + return NLTIME_FROM_NS(N == 0 ? value0 : + N == 1 ? value1 : + value2); + } + }; + + /// \brief: used define a constant in device description struct + /// + /// See the 74125 implementation + /// + template <std::size_t V> + using desc_const = std::integral_constant<std::size_t, V>; + + } // namespace netlist |