// 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 #include DEFINE_DEVICE_TYPE(FIFO2812, fifo2812_device, "fifo2812", "2812 32x8 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); }