summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/2812fifo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/2812fifo.cpp')
-rw-r--r--src/devices/machine/2812fifo.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/devices/machine/2812fifo.cpp b/src/devices/machine/2812fifo.cpp
new file mode 100644
index 00000000000..250be669639
--- /dev/null
+++ b/src/devices/machine/2812fifo.cpp
@@ -0,0 +1,235 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/**************************************************************************
+
+ 2812 32*8 First-In First-Out Memory (AMD, Plessey, and others)
+
+ These devices contain a file of 32 data registers and corresponding
+ control registers indicating when the data registers are valid.
+ Data ripples from the input register towards the output until it
+ reaches a register containing valid data. The first and last data
+ registers support serial operation.
+
+ The half-full flag responds to the number of valid locations. It
+ favours glitch-free operation over precision. It's never asserted
+ when fewer than 13 registers are valid, and it's always asserted
+ when at least 16 registers are valid.
+
+ TODO:
+ * Propagation delays
+ * Serial I/O
+ * Am2813 32*9 version without serial I/O
+
+**************************************************************************/
+
+#include "emu.h"
+#include "2812fifo.h"
+
+#include <algorithm>
+#include <cassert>
+
+
+DEFINE_DEVICE_TYPE(FIFO2812, fifo2812_device, "fifo2812", "2812 32*8 FIFO Memory");
+
+
+fifo2812_device::fifo2812_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, FIFO2812, tag, owner, clock),
+ m_q_cb(*this),
+ m_ir_cb(*this),
+ m_or_cb(*this),
+ m_flag_cb(*this),
+ m_control(0U),
+ m_count(0U),
+ m_d(0U), m_mr(1U), m_pl(0U), m_pd(0U), m_oe(1U)
+{
+ std::fill(std::begin(m_data), std::end(m_data), 0U);
+}
+
+
+WRITE_LINE_MEMBER(fifo2812_device::mr_w)
+{
+ if (bool(state) != bool(m_mr))
+ {
+ m_mr = state ? 1U : 0U;
+ if (!m_mr)
+ device_reset();
+ }
+}
+
+WRITE_LINE_MEMBER(fifo2812_device::pl_w)
+{
+ if (bool(state) != bool(m_pl))
+ {
+ m_pl = state ? 1U : 0U;
+ if (m_mr)
+ {
+ if (m_pl)
+ {
+ m_data[0] = m_d;
+ if (!BIT(m_control, 0))
+ {
+ m_control |= u32(1) << 0;
+ m_ir_cb(1);
+ if (15U == ++m_count)
+ m_flag_cb(1);
+ }
+ }
+ else if (BIT(m_control, 0) && !BIT(m_control, 1))
+ {
+ unsigned bit(1);
+ m_data[bit] = m_data[bit - 1];
+ m_control |= u32(1) << bit;
+ m_control &= ~(u32(1) << (bit - 1));
+ m_ir_cb(0);
+ for (++bit; ((LENGTH - 1) > bit) && !BIT(m_control, bit); ++bit)
+ {
+ m_data[bit] = m_data[bit - 1];
+ m_control |= u32(1) << bit;
+ m_control &= ~(u32(1) << (bit - 1));
+ }
+ if (!m_pd && ((LENGTH - 1) == bit) && !BIT(m_control, bit))
+ {
+ if (m_data[bit] != m_data[bit - 1])
+ {
+ m_data[bit] = m_data[bit - 1];
+ if (m_oe)
+ m_q_cb(0U, m_data[bit], 0xffU);
+ }
+ m_control |= u32(1) << bit;
+ m_control &= ~(u32(1) << (bit - 1));
+ m_or_cb(1);
+ }
+ }
+ }
+ }
+}
+
+WRITE_LINE_MEMBER(fifo2812_device::pd_w)
+{
+ if (bool(state) != bool(m_pd))
+ {
+ m_pd = state ? 1U : 0U;
+ if (m_mr)
+ {
+ if (m_pd)
+ {
+ if (BIT(m_control, LENGTH - 1))
+ {
+ m_control &= ~(u32(1) << (LENGTH - 1));
+ m_or_cb(0);
+ if (15U == m_count--)
+ m_flag_cb(0);
+ }
+ }
+ else if (BIT(m_control, LENGTH - 2))
+ {
+ unsigned bit(LENGTH - 2);
+ if (m_data[bit + 1] != m_data[bit])
+ {
+ m_data[bit + 1] = m_data[bit];
+ if (m_oe)
+ m_q_cb(0U, m_data[bit + 1], 0xffU);
+ }
+ m_control |= u32(1) << (bit + 1);
+ m_control &= ~(u32(1) << bit);
+ m_or_cb(1);
+ for (--bit; (0U < bit) && BIT(m_control, bit); --bit)
+ {
+ m_data[bit + 1] = m_data[bit];
+ m_control |= u32(1) << (bit + 1);
+ m_control &= ~(u32(1) << bit);
+ }
+ if (!m_pl && (0U == bit) && BIT(m_control, bit))
+ {
+ m_data[bit + 1] = m_data[bit];
+ m_control |= u32(1) << (bit + 1);
+ m_control &= ~(u32(1) << bit);
+ m_ir_cb(0);
+ }
+ }
+ }
+ }
+}
+
+WRITE_LINE_MEMBER(fifo2812_device::oe_w)
+{
+ if (bool(state) != bool(m_oe))
+ {
+ m_oe = state ? 1U : 0U;
+ if (m_oe)
+ m_q_cb(0U, m_data[LENGTH - 1], 0xffU);
+ else
+ m_q_cb(0U, 0xffU, 0x00U);
+ }
+}
+
+
+u8 fifo2812_device::read()
+{
+ if (machine().side_effects_disabled())
+ {
+ return m_data[LENGTH - 1];
+ }
+ else
+ {
+ assert(!m_pd);
+ pd_w(1);
+ u8 const data(m_data[LENGTH - 1]);
+ pd_w(0);
+ return data;
+ }
+}
+
+void fifo2812_device::write(u8 data)
+{
+ assert(!m_pl);
+ d_w(data);
+ pl_w(1);
+ pl_w(0);
+}
+
+
+void fifo2812_device::device_resolve_objects()
+{
+ m_q_cb.resolve_safe();
+ m_ir_cb.resolve_safe();
+ m_or_cb.resolve_safe();
+ m_flag_cb.resolve_safe();
+
+ m_d = 0U;
+ m_mr = 1U;
+ m_pl = 0U;
+ m_pd = 0U;
+ m_oe = 1U;
+}
+
+void fifo2812_device::device_start()
+{
+ save_item(NAME(m_control));
+ save_item(NAME(m_data));
+ save_item(NAME(m_count));
+ save_item(NAME(m_d));
+ save_item(NAME(m_mr));
+ save_item(NAME(m_pl));
+ save_item(NAME(m_pd));
+ save_item(NAME(m_oe));
+}
+
+void fifo2812_device::device_reset()
+{
+ u32 const prev_ir(BIT(m_control, 0));
+ u32 const prev_or(BIT(m_control, LENGTH - 1));
+ u8 const prev_q(m_data[LENGTH - 1]);
+ bool const prev_flag(15U <= m_count);
+ m_control = 0U;
+ std::fill(std::begin(m_data), std::end(m_data), 0U);
+ m_count = 0U;
+ if (m_oe && (0U != prev_q))
+ m_q_cb(0U, 0U, 0xffU);
+ if (prev_ir)
+ m_ir_cb(0);
+ if (prev_or)
+ m_or_cb(0);
+ if (prev_flag)
+ m_flag_cb(0);
+}