summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/mc2661.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/mc2661.c')
-rw-r--r--src/devices/machine/mc2661.c499
1 files changed, 499 insertions, 0 deletions
diff --git a/src/devices/machine/mc2661.c b/src/devices/machine/mc2661.c
new file mode 100644
index 00000000000..f93dc1b5ab1
--- /dev/null
+++ b/src/devices/machine/mc2661.c
@@ -0,0 +1,499 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/***************************************************************************
+
+ Motorola MC2661/MC68661 Enhanced Programmable Communications Interface
+
+***************************************************************************/
+
+#include "mc2661.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MC2661 = &device_creator<mc2661_device>;
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+UINT32 baud_rates[16] =
+{
+ 50, 75, 110, 135 /*134.5*/, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 19200
+};
+
+enum
+{
+ REGISTER_HOLDING = 0,
+ REGISTER_STATUS,
+ REGISTER_SYNC = REGISTER_STATUS,
+ REGISTER_MODE,
+ REGISTER_COMMAND
+};
+
+
+#define MODE_BAUD_RATE (m_mr[0] & 0x03)
+#define MODE_CHARACTER ((m_mr[0] >> 2) & 0x03)
+#define MODE_PARITY BIT(m_mr[0], 4)
+#define MODE_PARITY_EVEN BIT(m_mr[0], 5)
+#define MODE_TRANSPARENT BIT(m_mr[0], 6)
+#define MODE_SINGLE_SYN BIT(m_mr[0], 7)
+#define MODE_STOP_BITS ((m_mr[0] >> 6) & 0x03)
+
+
+#define SYN1 m_sync[0]
+#define SYN2 m_sync[1]
+#define DLE m_sync[2]
+
+
+#define COMMAND_TXEN BIT(m_cr, 0)
+#define COMMAND_DTR BIT(m_cr, 1)
+#define COMMAND_RXEN BIT(m_cr, 2)
+#define COMMAND_BREAK BIT(m_cr, 3)
+#define COMMAND_DLE BIT(m_cr, 3)
+#define COMMAND_RESET BIT(m_cr, 4)
+#define COMMAND_RTS BIT(m_cr, 5)
+#define COMMAND_MODE (m_cr >> 6)
+
+
+enum
+{
+ MODE_NORMAL = 0,
+ MODE_ASYNC,
+ MODE_LOCAL_LOOP_BACK,
+ MODE_REMOTE_LOOP_BACK
+};
+
+
+#define STATUS_TXRDY 0x01
+#define STATUS_RXRDY 0x02
+#define STATUS_TXEMT 0x04
+#define STATUS_PE 0x08
+#define STATUS_DLE 0x08
+#define STATUS_OVERRUN 0x10
+#define STATUS_FE 0x20
+#define STATUS_SYN 0x20
+#define STATUS_DCD 0x40
+#define STATUS_DSR 0x80
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mc2661_device - constructor
+//-------------------------------------------------
+
+mc2661_device::mc2661_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, MC2661, "MC2661", tag, owner, clock, "mc2661", __FILE__),
+ device_serial_interface(mconfig, *this),
+ m_write_txd(*this),
+ m_write_rxrdy(*this),
+ m_write_txrdy(*this),
+ m_write_rts(*this),
+ m_write_dtr(*this),
+ m_write_txemt_dschg(*this),
+ m_write_bkdet(*this),
+ m_write_xsync(*this),
+ m_rxc(0),
+ m_txc(0),
+ m_sr(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc2661_device::device_start()
+{
+ // resolve callbacks
+ m_write_txd.resolve_safe();
+ m_write_rxrdy.resolve_safe();
+ m_write_txrdy.resolve_safe();
+ m_write_rts.resolve_safe();
+ m_write_dtr.resolve_safe();
+ m_write_txemt_dschg.resolve_safe();
+ m_write_bkdet.resolve_safe();
+ m_write_xsync.resolve_safe();
+
+ // create the timers
+ if (m_rxc > 0)
+ {
+ set_rcv_rate(m_rxc);
+ }
+
+ if (m_txc > 0)
+ {
+ set_tra_rate(m_txc);
+ }
+
+ // save state
+ save_item(NAME(m_rhr));
+ save_item(NAME(m_thr));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_mr));
+ save_item(NAME(m_sync));
+ save_item(NAME(m_mode_index));
+ save_item(NAME(m_sync_index));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc2661_device::device_reset()
+{
+ receive_register_reset();
+ transmit_register_reset();
+
+ m_mr[0] = m_mr[1] = 0;
+ m_sync[0] = m_sync[1] = m_sync[2] = 0;
+ m_cr = 0;
+ m_sr = 0;
+
+ m_mode_index = 0;
+ m_sync_index = 0;
+
+ m_write_txd(1);
+ m_write_rxrdy(CLEAR_LINE);
+ m_write_txrdy(CLEAR_LINE);
+ m_write_rts(1);
+ m_write_dtr(1);
+ m_write_txemt_dschg(CLEAR_LINE);
+ m_write_bkdet(0);
+ m_write_xsync(0);
+}
+
+
+//-------------------------------------------------
+// tra_callback -
+//-------------------------------------------------
+
+void mc2661_device::tra_callback()
+{
+ m_write_txd(transmit_register_get_data_bit());
+}
+
+
+//-------------------------------------------------
+// tra_complete -
+//-------------------------------------------------
+
+void mc2661_device::tra_complete()
+{
+ // TODO
+ m_sr |= STATUS_TXRDY;
+ m_write_txrdy(ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// rcv_complete -
+//-------------------------------------------------
+
+void mc2661_device::rcv_complete()
+{
+ // TODO
+ receive_register_extract();
+ m_rhr = get_received_char();
+ m_sr |= STATUS_RXRDY;
+ m_write_rxrdy(ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// read - register read
+//-------------------------------------------------
+
+READ8_MEMBER( mc2661_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset & 0x03)
+ {
+ case REGISTER_HOLDING:
+ data = m_rhr;
+ m_sr &= ~STATUS_RXRDY;
+ m_write_rxrdy(CLEAR_LINE);
+ break;
+
+ case REGISTER_STATUS:
+ data = m_sr;
+ break;
+
+ case REGISTER_MODE:
+ data = m_mr[m_mode_index];
+
+ m_mode_index++;
+ m_mode_index &= 0x01;
+
+ break;
+
+ case REGISTER_COMMAND:
+ m_mode_index = 0;
+ m_sync_index = 0;
+
+ data = m_cr;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// write - register write
+//-------------------------------------------------
+
+WRITE8_MEMBER( mc2661_device::write )
+{
+ switch (offset & 0x03)
+ {
+ case REGISTER_HOLDING:
+ if (LOG) logerror("MC2661 '%s' Transmit Holding Register: %02x\n", tag(), data);
+
+ m_thr = data;
+ if(COMMAND_TXEN)
+ {
+ if(COMMAND_MODE != 0x02)
+ transmit_register_setup(m_thr);
+ m_sr &= ~STATUS_TXRDY;
+ m_write_txrdy(CLEAR_LINE);
+ }
+ if(COMMAND_MODE == 0x02) // loopback - the Wicat will set this after enabling the transmitter
+ {
+ m_rhr = data;
+ m_sr |= STATUS_RXRDY; // pcd expects this
+ m_write_rxrdy(ASSERT_LINE);
+ }
+ break;
+
+ case REGISTER_SYNC:
+ if (LOG) logerror("MC2661 '%s' Sync Register %u: %02x\n", tag(), m_sync_index + 1, data);
+
+ m_sync[m_sync_index] = data;
+
+ m_sync_index++;
+ if (m_sync_index == 3) m_sync_index = 0;
+ break;
+
+ case REGISTER_MODE:
+ if (LOG) logerror("MC2661 '%s' Mode Register %u: %02x\n", tag(), m_mode_index + 1, data);
+
+ m_mr[m_mode_index] = data;
+
+ if (m_mode_index == 0)
+ {
+ int data_bit_count = 5 + MODE_CHARACTER;
+ parity_t parity;
+
+ if (!MODE_PARITY) parity = PARITY_NONE;
+ else if (MODE_PARITY_EVEN) parity = PARITY_EVEN;
+ else parity = PARITY_ODD;
+
+ stop_bits_t stop_bits;
+
+ switch (MODE_STOP_BITS)
+ {
+ case 0:
+ default:
+ stop_bits = STOP_BITS_0;
+ break;
+
+ case 1:
+ stop_bits = STOP_BITS_1;
+ break;
+
+ case 2:
+ stop_bits = STOP_BITS_1_5;
+ break;
+
+ case 3:
+ stop_bits = STOP_BITS_2;
+ break;
+ }
+
+ set_data_frame(1, data_bit_count, parity, stop_bits);
+ }
+ if(m_mode_index == 1)
+ {
+ UINT32 rx_baud = baud_rates[data & 0x0f];
+ UINT32 tx_baud = baud_rates[data & 0x0f];
+ if(data & 0x10) // internal receiver clock
+ {
+// if((m_mr[0] & 0x03) != 0)
+// rx_baud *= 16;
+ }
+ else // external receiver clock
+ {
+ switch(m_mr[0] & 0x03)
+ {
+ case 0x02:
+ rx_baud *= 16;
+ break;
+ case 0x03:
+ rx_baud *= 64;
+ break;
+ default:
+ // x1
+ break;
+ }
+ }
+ if(data & 0x20) // internal transmitter clock
+ {
+// if((m_mr[0] & 0x03) != 0)
+// tx_baud *= 16;
+ }
+ else // external transmitter clock
+ {
+ switch(m_mr[0] & 0x03)
+ {
+ case 0x02:
+ tx_baud *= 16;
+ break;
+ case 0x03:
+ tx_baud *= 64;
+ break;
+ default:
+ // x1
+ break;
+ }
+ }
+
+ set_rcv_rate(rx_baud);
+ set_tra_rate(tx_baud);
+ }
+
+ m_mode_index++;
+ m_mode_index &= 0x01;
+ break;
+
+ case REGISTER_COMMAND:
+ if (LOG) logerror("MC2661 '%s' Command Register: %02x\n", tag(), data);
+
+ m_cr = data & 0xef;
+
+ m_write_dtr(!COMMAND_DTR);
+ m_write_rts(!COMMAND_RTS);
+
+ if (COMMAND_MODE == 0x02) // local loopback
+ {
+ if(COMMAND_DTR && COMMAND_RTS) // CR1 and CR5 must be set to 1 to use local loopback
+ {
+ // probably much more to it that this, but this is enough for the Wicat to be happy
+ m_rhr = m_thr;
+ m_sr |= STATUS_RXRDY;
+ m_write_rxrdy(ASSERT_LINE);
+ return;
+ }
+ }
+
+ if (COMMAND_TXEN)
+ {
+ m_sr |= STATUS_TXRDY;
+ m_write_txrdy(ASSERT_LINE);
+ }
+ else
+ {
+ m_sr &= ~STATUS_TXRDY;
+ m_write_txrdy(CLEAR_LINE);
+ }
+ if (!COMMAND_RXEN)
+ {
+ m_sr &= ~STATUS_RXRDY;
+ m_write_rxrdy(CLEAR_LINE);
+ }
+ if (COMMAND_RESET)
+ {
+ m_sr &= ~(STATUS_FE | STATUS_OVERRUN | STATUS_PE);
+ }
+ break;
+ }
+}
+
+//-------------------------------------------------
+// dsr_w - data set ready
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( mc2661_device::dsr_w )
+{
+ if (LOG) logerror("MC2661 '%s' Data Set Ready: %u\n", tag(), state);
+
+ if (state)
+ {
+ m_sr &= ~STATUS_DSR;
+ }
+ else
+ {
+ m_sr |= STATUS_DSR;
+ }
+}
+
+
+//-------------------------------------------------
+// dcd_w - data carrier detect
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( mc2661_device::dcd_w )
+{
+ if (LOG) logerror("MC2661 '%s' Data Carrier Detect: %u\n", tag(), state);
+
+ if (state)
+ {
+ m_sr &= ~STATUS_DCD;
+ }
+ else
+ {
+ m_sr |= STATUS_DCD;
+ }
+}
+
+
+//-------------------------------------------------
+// cts_w - clear to send
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( mc2661_device::cts_w )
+{
+ if (LOG) logerror("MC2661 '%s' Clear to Send: %u\n", tag(), state);
+}
+
+
+//-------------------------------------------------
+// rxrdy_r - receiver ready
+//-------------------------------------------------
+
+READ_LINE_MEMBER( mc2661_device::rxrdy_r )
+{
+ return (m_sr & STATUS_RXRDY) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+//-------------------------------------------------
+// txemt_r - transmitter empty
+//-------------------------------------------------
+
+READ_LINE_MEMBER( mc2661_device::txemt_r )
+{
+ return (m_sr & STATUS_TXEMT) ? ASSERT_LINE : CLEAR_LINE;
+}
+
+
+void mc2661_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ device_serial_interface::device_timer(timer, id, param, ptr);
+}