summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/mb89374.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/mb89374.cpp')
-rw-r--r--src/devices/machine/mb89374.cpp617
1 files changed, 617 insertions, 0 deletions
diff --git a/src/devices/machine/mb89374.cpp b/src/devices/machine/mb89374.cpp
new file mode 100644
index 00000000000..f1950c16fb4
--- /dev/null
+++ b/src/devices/machine/mb89374.cpp
@@ -0,0 +1,617 @@
+// 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
+ m_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;
+ }
+}