summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/devices/nld_4029.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/devices/nld_4029.cpp')
-rw-r--r--src/lib/netlist/devices/nld_4029.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/lib/netlist/devices/nld_4029.cpp b/src/lib/netlist/devices/nld_4029.cpp
new file mode 100644
index 00000000000..2e18ba9f4e1
--- /dev/null
+++ b/src/lib/netlist/devices/nld_4029.cpp
@@ -0,0 +1,272 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud, Jonathan Gevaryahu
+/*
+ * nld_4029.cpp
+ *
+ * CD4029BM/CD4029BC Presettable Binary/Decade Up/Down Counter
+ *
+ * +--------------+
+ * PE |1 ++ 16| VDD
+ * Q4 |2 15| CLK
+ * J4 |3 14| Q3
+ * J1 |4 4029 13| J3
+ * CI |5 12| J2
+ * Q1 |6 11| Q2
+ * CO |7 10| U/D
+ * VSS |8 9| B/D
+ * +--------------+
+ *
+ * Counter Sequences:
+ *
+ * B/D high (Binary), U/D high (Up)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || A |
+ * | A || 1 | 0 | 1 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 | 1 || C |
+ * | C || 1 | 1 | 0 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 | 1 || E |
+ * | E || 1 | 1 | 1 | 0 | 1 || F |
+ * | F || 1 | 1 | 1 | 1 |0|CI|| 0 |
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * B/D high (Binary), U/D low (Down)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | F || 1 | 1 | 1 | 1 | 1 || E |
+ * | E || 1 | 1 | 1 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 | 1 || C |
+ * | C || 1 | 1 | 0 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 | 1 || A |
+ * | A || 1 | 0 | 1 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 0 |
+ * | 0 || 0 | 0 | 0 | 0 |0|CI|| F |
+ * | F || 1 | 1 | 1 | 1 | 1 || E |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * B/D low (Decimal), U/D high (Up)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 |0|CI|| 0 |
+ * | A || 1 | 0 | 1 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 |0|CI|| 6 |
+ * | C || 1 | 1 | 0 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 |0|CI|| 4 |
+ * | E || 1 | 1 | 1 | 0 | 1 || F |
+ * | F || 1 | 1 | 1 | 1 |0|CI|| 2 |
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * B/D low (Decimal), U/D low (Down)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | F || 1 | 1 | 1 | 1 | 1 || E |
+ * | E || 1 | 1 | 1 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 | 1 || C |
+ * | C || 1 | 1 | 0 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 | 1 || A |
+ * | A || 1 | 0 | 1 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 0 |
+ * | 0 || 0 | 0 | 0 | 0 |0|CI|| 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * Note that in all cases where Carry-out is generating a non-1 signal (0 | Carry-in),
+ * this signal is asynchronous, so if carry-in changes the carry-out value will
+ * change immediately.
+ *
+ *
+ * Preset/Carry in function table
+ * +-----+-----+-----++----+----+----+----+
+ * | PE | CLK | CI || Q1 | Q2 | Q3 | Q4 |
+ * +=====+=====+=====++====+====+====+====+
+ * | 1 | X | X || J1 | J2 | J3 | J4 |
+ * | 0 | X | 1 || Q1 | Q2 | Q3 | Q4 |
+ * | 0 | ./` | 0 || COUNT |
+ * +-----+-----+-----++----+----+----+----+
+ *
+ * Naming conventions follow National Semiconductor datasheet
+ *
+ */
+
+#include "nl_base.h"
+
+namespace netlist
+{
+namespace devices
+{
+
+ NETLIB_OBJECT(CD4029)
+ {
+ NETLIB_CONSTRUCTOR_MODEL(CD4029, "CD4XXX")
+ , m_PE(*this, "PE", NETLIB_DELEGATE(inputs))
+ , m_J(*this, {"J1", "J2", "J3", "J4"}, NETLIB_DELEGATE(inputs))
+ , m_CI(*this, "CI", NETLIB_DELEGATE(inputs))
+ , m_UD(*this, "UD", NETLIB_DELEGATE(inputs))
+ , m_BD(*this, "BD", NETLIB_DELEGATE(inputs))
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(clk))
+ , m_clk_old(*this, "m_clk_old", false)
+ , m_Q(*this, {"Q1", "Q2", "Q3", "Q4"})
+ , m_CO(*this, "CO", 0)
+ , m_cnt(*this, "m_cnt", 0)
+ , m_power_pins(*this)
+ {
+ }
+
+ private:
+ inline NETLIB_HANDLERI(inputs) // pe causes an asynchronous counter load on level so has to be handled separately; if pe is high, then J changing will asynchronously change the Q state. changing J in this state does affect CO as well; CI will affect CO asynchronously if there is currently a carry
+ {
+ if (m_PE())
+ {
+ m_cnt = m_J()&0xf;
+ }
+ m_Q.push(m_cnt, NLTIME_FROM_NS(200));
+ // figure out CO
+ if (!m_UD()) // downward is the same for binary and decimal
+ {
+ m_CO.push(m_cnt||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // upward mode differs
+ {
+ if (!m_BD()) // decimal mode
+ {
+ m_CO.push((m_cnt<8)||(~m_cnt&1)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // binary mode
+ {
+ m_CO.push((m_cnt!=0xf)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ }
+ }
+
+ inline NETLIB_HANDLERI(clk)
+ {
+ // clocking only happens if m_clk_old was low, m_CLK is high, m_PE is NOT high, and m_CI is NOT high.
+ if (!m_PE() && !m_CI() && !m_clk_old && m_CLK())
+ {
+ if (m_BD()) // binary
+ {
+ m_cnt += (m_UD() ? 1 : -1);
+ m_cnt &= 0xf;
+ }
+ else // decimal
+ {
+ if (m_UD()) // upward
+ {
+ switch(m_cnt)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ case 8: case 0xa: case 0xc: case 0xe:
+ m_cnt++;
+ break;
+ case 9:
+ m_cnt = 0;
+ break;
+ case 0xb:
+ m_cnt = 6;
+ break;
+ case 0xd:
+ m_cnt = 4;
+ break;
+ case 0xf:
+ m_cnt = 2;
+ break;
+ }
+ }
+ else // downward
+ {
+ if (m_cnt>0)
+ {
+ m_cnt--;
+ }
+ else // m_cnt == 0
+ {
+ m_cnt = 9;
+ }
+ }
+ }
+ }
+ m_clk_old = m_CLK();
+ m_Q.push(m_cnt, NLTIME_FROM_NS(200));
+ // figure out CO
+ if (!m_UD()) // downward is the same for binary and decimal
+ {
+ m_CO.push(m_cnt||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // upward mode differs
+ {
+ if (!m_BD()) // decimal mode
+ {
+ m_CO.push((m_cnt<8)||(~m_cnt&1)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // binary mode
+ {
+ m_CO.push((m_cnt!=0xf)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ }
+ }
+
+ NETLIB_RESETI()
+ {
+ m_cnt = 0;
+ m_clk_old = false;
+ }
+
+ logic_input_t m_PE;
+ object_array_t<logic_input_t, 4> m_J;
+ logic_input_t m_CI;
+ logic_input_t m_UD;
+ logic_input_t m_BD;
+ logic_input_t m_CLK;
+
+ state_var<netlist_sig_t> m_clk_old;
+ object_array_t<logic_output_t, 4> m_Q;
+ logic_output_t m_CO;
+ state_var_u8 m_cnt;
+ nld_power_pins m_power_pins;
+ };
+
+ NETLIB_DEVICE_IMPL(CD4029, "CD4029", "+PE,+J1,+J2,+J3,+J4,+CI,+UD,+BD,+CLK,@VCC,@GND")
+
+} // namespace devices
+} // namespace netlist