summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/2812fifo.cpp
blob: 3cc10965ecb351d8917c0ba38ef68cac9610a480 (plain) (tree)






























                                                                           
                                                                                   










































































































































































































                                                                                                              
// 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 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);
}