summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/mb89374.cpp
blob: 561d0bf34dfde0f0a1c948a37bf4f2122ab91132 (plain) (tree)
1
2
3
4
5
6
7


                                   
           
 

                        



























































































































                                                                                                                 
                                



















































































































































                                                                
 















































































































































































































































































































































                                                                                                                 
// license:BSD-3-Clause
// copyright-holders:Ariane Fugmann
/**
    MB89374

    Fujitsu
    Data Link Controller

 **/

#include "emu.h"
#include "mb89374.h"
#include "emuopts.h"

//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

// device type definition
DEFINE_DEVICE_TYPE(MB89374, mb89374_device, "mb89374", "MB89374 Data Link Controller")


enum
{
	REGISTER_SMR0 = 0x00,
	REGISTER_SMR1,
	REGISTER_SMR2,
	REGISTER_CHRR0,
	REGISTER_CHRR1,

	REGISTER_MSR = 0x06,
	REGISTER_MCR,
	REGISTER_RXSR0,
	REGISTER_RXSR1,
	REGISTER_RXCR,
	REGISTER_RXIER,
	REGISTER_TXSR,
	REGISTER_TXCR,
	REGISTER_TXIER,
	REGISTER_SDR,
	REGISTER_TXBCR0,
	REGISTER_TXBCR1,
	REGISTER_TXFR0,
	REGISTER_TXFR1,
	REGISTER_SMR3,
	REGISTER_PORTR,
	REGISTER_REQR,
	REGISTER_MASKR,
	REGISTER_B1PSR,
	REGISTER_B1PCR,
	REGISTER_BG1DR,

	REGISTER_B2SR = 0x1c,
	REGISTER_B2CR,
	REGISTER_BG2DR
};

#define SMR0_MASK     0xf0

#define SMR1_MASK     0xe3

#define MSR_MASK      0x80

#define MCR_MASK      0x14

#define RXSR1_MASK    0x08

#define RXCR_MASK     0x7c
#define RXCR_HUNT     BIT(m_rxcr, 1)
#define RXCR_RXE      BIT(m_rxcr, 7)

#define RXIER_RXDI    BIT(m_rxier, 7)

#define TXSR_MASK     0x60
#define TXSR_TXRDY    BIT(m_txsr, 0)
#define TXSR_TXEND    BIT(m_txsr, 4)

#define TXCR_TXRST    BIT(m_txcr, 3)
#define TXCR_TXE      BIT(m_txcr, 7)

#define TXIER_MASK    0x60
#define TXIER_TXDI    BIT(m_txier, 7)

#define TXFR1_MASK    0x70

#define SMR3_MASK     0x80

#define REQR_MASK     0x38

#define MASKR_MASK    0x38
#define MASKR_MRXDRQ  BIT(m_maskr, 6)
#define MASKR_MTXDRQ  BIT(m_maskr, 7)

#define B1PSR_MASK    0xfc

#define B2SR_MASK     0xfe

//-------------------------------------------------
//  mb89374_device - constructor
//-------------------------------------------------

mb89374_device::mb89374_device( const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock )
	: device_t(mconfig, MB89374, tag, owner, clock),
	device_execute_interface(mconfig, *this),
	m_icount(0),
	m_out_irq_cb(*this),
	m_out_po_cb{ { *this }, { *this }, { *this }, { *this } }
{
	// prepare localhost "filename"
	m_localhost[0] = 0;
	strcat(m_localhost, "socket.");
	strcat(m_localhost, mconfig.options().comm_localhost());
	strcat(m_localhost, ":");
	strcat(m_localhost, mconfig.options().comm_localport());

	// prepare remotehost "filename"
	m_remotehost[0] = 0;
	strcat(m_remotehost, "socket.");
	strcat(m_remotehost, mconfig.options().comm_remotehost());
	strcat(m_remotehost, ":");
	strcat(m_remotehost, mconfig.options().comm_remoteport());
}


//-------------------------------------------------
//  device_start - device-specific startup
//------------------------------------------------

void mb89374_device::device_start()
{
	// set our instruction counter
	set_icountptr(m_icount);

	// resolve callbacks
	m_out_irq_cb.resolve_safe();
	for(auto &cb : m_out_po_cb)
		cb.resolve_safe();

	// state saving
	save_item(NAME(m_irq));
	save_item(NAME(m_po));
	save_item(NAME(m_pi));
	save_item(NAME(m_ci));

	save_item(NAME(m_smr0));
	save_item(NAME(m_smr1));
	save_item(NAME(m_smr2));
	save_item(NAME(m_chrr0));
	save_item(NAME(m_chrr1));
	save_item(NAME(m_msr));
	save_item(NAME(m_mcr));
	save_item(NAME(m_rxsr0));
	save_item(NAME(m_rxsr1));
	save_item(NAME(m_rxcr));
	save_item(NAME(m_rxier));
	save_item(NAME(m_txsr));
	save_item(NAME(m_txcr));
	save_item(NAME(m_txier));
	save_item(NAME(m_sdr));
	save_item(NAME(m_txbcr0));
	save_item(NAME(m_txbcr1));
	save_item(NAME(m_txfr0));
	save_item(NAME(m_txfr1));
	save_item(NAME(m_smr3));
	save_item(NAME(m_portr));
	save_item(NAME(m_reqr));
	save_item(NAME(m_maskr));
	save_item(NAME(m_b1psr));
	save_item(NAME(m_b1pcr));
	save_item(NAME(m_bg1dr));
	save_item(NAME(m_b2sr));
	save_item(NAME(m_b2cr));
	save_item(NAME(m_bg2dr));

	save_item(NAME(m_intr_delay));
	save_item(NAME(m_sock_delay));

	save_item(NAME(m_rx_buffer));
	save_item(NAME(m_rx_offset));
	save_item(NAME(m_rx_length));

	save_item(NAME(m_tx_buffer));
	save_item(NAME(m_tx_offset));
}


//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void mb89374_device::device_reset()
{
	m_smr0   = SMR0_MASK;
	m_smr1   = SMR1_MASK;
	m_smr2   = 0x00;
	m_chrr0  = 0x00;
	m_chrr1  = 0x00;
	m_msr    = MSR_MASK;
	m_mcr    = MCR_MASK;
	m_rxsr0  = 0x00;
	m_rxsr1  = RXSR1_MASK;
	m_rxcr   = RXCR_MASK;
	m_rxier  = 0x00;
	m_txsr   = TXSR_MASK;
	m_txcr   = 0x00;
	m_txier  = TXIER_MASK;
	m_sdr    = 0x00;
	m_txbcr0 = 0x00;
	m_txbcr1 = 0x00;
	m_txfr0  = 0x00;
	m_txfr1  = TXFR1_MASK;
	m_smr3   = SMR3_MASK;
	m_portr  = 0x00;
	m_reqr   = REQR_MASK;
	m_maskr  = MASKR_MASK;
	m_b1psr  = B1PSR_MASK;
	m_b1pcr  = 0x00;
	m_bg1dr  = 0x00;
	m_b2sr   = B2SR_MASK;
	m_b2cr   = 0x00;
	m_bg2dr  = 0x00;

	set_irq(0);
	set_po0(0);
	set_po1(0);
	set_po2(0);
	set_po3(0);

	m_intr_delay = 0;
	m_sock_delay = 0x20;

	m_rx_length = 0x0000;
	m_rx_offset = 0x0000;

	m_tx_offset = 0x0000;
}


//-------------------------------------------------
//  execute_run -
//-------------------------------------------------

void mb89374_device::execute_run()
{
	while (m_icount > 0)
	{
		// TODO waste some cycles before triggering ints
		if (m_intr_delay > 0)
		{
			m_intr_delay--;
			if (m_intr_delay == 0)
			{
			}
		}
		if (m_sock_delay > 0)
		{
			m_sock_delay--;
			if (m_sock_delay == 0)
			{
				m_sock_delay = 0x20;
				checkSockets();
			}
		}
		m_icount--;
	}
}


//-------------------------------------------------
//  read - handler for register reading
//-------------------------------------------------

READ8_MEMBER(mb89374_device::read)
{
	uint8_t data = 0xff;
	switch (offset & 0x1f)
	{
		case REGISTER_RXSR0:
			data = m_rxsr0;
			break;

		case REGISTER_RXSR1:
			data = m_rxsr1;
			break;

		case REGISTER_TXSR:
			data = m_txsr;
			break;

		case REGISTER_SDR:
			m_sdr = rxRead();
			data = m_sdr;
			break;

		case REGISTER_PORTR:
			data = m_portr;
			break;

		default:
			logerror("MB89374 unimplemented register read @%02X\n", offset);
	}
	return data;
}


//-------------------------------------------------
//  write - handler for register writing
//-------------------------------------------------

WRITE8_MEMBER(mb89374_device::write)
{
	switch (offset & 0x1f)
	{
		case REGISTER_SMR2:
			m_smr2 = data;
			break;

		case REGISTER_MCR:
			m_mcr = data | MCR_MASK;
			break;

		case REGISTER_RXCR:
			m_rxcr = data | RXCR_MASK;
			if (RXCR_HUNT)
				rxReset();
			break;

		case REGISTER_RXIER:
			m_rxier = data;

		case REGISTER_TXSR:
			m_txsr = data | TXSR_MASK;
			txReset();
			break;

		case REGISTER_TXCR:
			m_txcr = data;
			if (TXCR_TXRST)
				txReset();
			break;

		case REGISTER_TXIER:
			m_txier = data | TXIER_MASK;
			break;

		case REGISTER_SMR3:
			m_smr3 = data | SMR3_MASK;
			break;

		case REGISTER_PORTR:
			m_portr = data;
			break;

		case REGISTER_MASKR:
			m_maskr = data | MASKR_MASK;
			set_po2((!MASKR_MTXDRQ && TXCR_TXE && TXIER_TXDI) ? 1 : 0);
			break;

		default:
			logerror("MB89374 unimplemented register write @%02X = %02X\n", offset, data);
	}
}


//-------------------------------------------------
//  pi0_w - handler for RxCI#/PI0
//-------------------------------------------------

WRITE_LINE_MEMBER(mb89374_device::pi0_w)
{
	m_pi[0] = state;
}


//-------------------------------------------------
//  pi1_w - handler for TxCI#/PI1
//-------------------------------------------------

WRITE_LINE_MEMBER(mb89374_device::pi1_w)
{
	m_pi[1] = state;
}


//-------------------------------------------------
//  pi2_w - handler for TxDACK#/PI2
//-------------------------------------------------

WRITE_LINE_MEMBER(mb89374_device::pi2_w)
{
	m_pi[2] = state;
}


//-------------------------------------------------
//  pi3_w - handler for RxDACK#/PI3
//-------------------------------------------------

WRITE_LINE_MEMBER(mb89374_device::pi3_w)
{
	m_pi[3] = state;
}


//-------------------------------------------------
//  ci_w - handler for TxLAST#/CI#
//-------------------------------------------------

WRITE_LINE_MEMBER(mb89374_device::ci_w)
{
	m_ci = state;
	if (m_ci == 1 && m_pi[2] == 0)
	{
		txComplete();
	}

}


//-------------------------------------------------
//  read - handler for dma reading (rx buffer)
//-------------------------------------------------

READ8_MEMBER(mb89374_device::dma_r)
{
	uint8_t data = rxRead();
	if (m_rx_offset == m_rx_length)
		set_po3(0); // transfer finished; release dma
	return data;
}


//-------------------------------------------------
//  write - handler for dma writing (tx buffer)
//-------------------------------------------------

WRITE8_MEMBER(mb89374_device::dma_w)
{
	txWrite(data);
}


//**************************************************************************
//  buffer logic
//**************************************************************************

void mb89374_device::rxReset()
{
	m_rx_length = 0;
	m_rx_offset = 0;
	m_rxsr0 = 0x06; // RXIDL | DIDL
}

uint8_t mb89374_device::rxRead()
{
	uint8_t data = m_rx_buffer[m_rx_offset];
	m_rx_offset++;
	if (m_rx_offset == m_rx_length)
		m_rxsr0 |= 0x40; // EOF
	if (m_rx_offset >= m_rx_length)
		rxReset();
	return data;
}

void mb89374_device::txReset()
{
	m_tx_offset = 0;
	m_txsr |= 0x05;
}

void mb89374_device::txWrite(uint8_t data)
{
	m_tx_buffer[m_tx_offset] = data;
	m_tx_offset++;
	m_txsr = 0x6b;

	// prevent overflow
	if (m_tx_offset >= 0x0f00)
		m_tx_offset = 0x0eff;
}

void mb89374_device::txComplete()
{
	if (m_tx_offset > 0)
	{
		if (m_line_rx && m_line_tx)
		{
			m_socket_buffer[0x00] = m_tx_offset & 0xff;
			m_socket_buffer[0x01] = (m_tx_offset >> 8) & 0xff;
			for (int i = 0x00 ; i < m_tx_offset ; i++)
			{
				m_socket_buffer[i + 2] = m_tx_buffer[i];
			}

			std::uint32_t dataSize = m_tx_offset + 2;
			std::uint32_t written;

			m_line_tx->write(&m_socket_buffer, 0, dataSize, written);
		}
	}

	m_txsr = 0x6f;

	txReset();
}

void mb89374_device::checkSockets()
{
	// check rx socket
	if (!m_line_rx)
	{
		osd_printf_verbose("MB89374 listen on %s\n", m_localhost);
		uint64_t filesize; // unused
		osd_file::open(m_localhost, OPEN_FLAG_CREATE, m_line_rx, filesize);
	}

	// check tx socket
	if (!m_line_tx)
	{
		osd_printf_verbose("MB89374 connect to %s\n", m_remotehost);
		uint64_t filesize; // unused
		osd_file::open(m_remotehost, 0, m_line_tx, filesize);
	}

	if (m_line_rx && m_line_tx)
	{
		if (RXCR_RXE)
		{
			if (m_rx_length == 0)
			{
				std::uint32_t recv = 0;
				m_line_rx->read(m_socket_buffer, 0, 2, recv);
				if (recv > 0)
				{
					if (recv == 2)
						m_rx_length = m_socket_buffer[0x01] << 8 | m_socket_buffer[0x00];
					else
					{
						m_rx_length = m_socket_buffer[0x00];
						m_line_rx->read(m_socket_buffer, 0, 1, recv);
						while (recv == 0) {}
						m_rx_length |= m_socket_buffer[0x00] << 8;
					}

					int offset = 0;
					int togo = m_rx_length;
					while (togo > 0)
					{
						m_line_rx->read(m_socket_buffer, 0, togo, recv);
						for (int i = 0x00 ; i < recv ; i++)
						{
							m_rx_buffer[offset] = m_socket_buffer[i];
							offset++;
						}
						togo -= recv;
					}

					m_rx_offset = 0;
					m_rxsr0 = 0x01; // RXRDY
					if (m_rx_offset + 1 == m_rx_length)
						m_rxsr0 |= 0x40; // EOF
					m_rxsr1 = 0xc8;
					set_po3(!MASKR_MRXDRQ && RXIER_RXDI ? 1 : 0);
				}
			}
		}
	}
}

//**************************************************************************
//  INLINE HELPERS
//**************************************************************************

inline void mb89374_device::set_irq(int state)
{
	if (m_irq != state)
	{
		m_out_irq_cb(state);
		m_irq = state;
	}
}

inline void mb89374_device::set_po0(int state)
{
	if (m_po[0] != state)
	{
		m_out_po_cb[0](state);
		m_po[0] = state;
	}
}

inline void mb89374_device::set_po1(int state)
{
	if (m_po[1] != state)
	{
		m_out_po_cb[1](state);
		m_po[1] = state;
	}
}

inline void mb89374_device::set_po2(int state)
{
	if (m_po[2] != state)
	{
		m_out_po_cb[2](state);
		m_po[2] = state;
	}
}

inline void mb89374_device::set_po3(int state)
{
	if (m_po[3] != state)
	{
		m_out_po_cb[3](state);
		m_po[3] = state;
	}
}