summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/z80sio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/z80sio.cpp')
-rw-r--r--src/devices/machine/z80sio.cpp405
1 files changed, 397 insertions, 8 deletions
diff --git a/src/devices/machine/z80sio.cpp b/src/devices/machine/z80sio.cpp
index ae93bdd2848..9b259c5c824 100644
--- a/src/devices/machine/z80sio.cpp
+++ b/src/devices/machine/z80sio.cpp
@@ -45,6 +45,15 @@
* Transmitter FIFO 1
-------------------------------------------------------------------------
* = Features that has been implemented n/a = features that will not
+
+ Mostek not only second-sourced the Z80 SIO but redesigned it for
+ 68000 compatibility as the MK68564 SIO. This 48-pin device has a
+ revamped register interface with five address inputs to make every
+ register separately selectable, and most control registers may be read
+ back as written. The RxRDY and TxRDY pins are separate here, and many
+ control bits have been shifted around. The MK68564 also features a
+ built-in baud rate generator (not compatible with the Z8530 SCC's).
+
***************************************************************************/
#include "emu.h"
@@ -237,11 +246,13 @@ constexpr uint16_t SDLC_RESIDUAL = 0x1d0f;
//**************************************************************************
// device type definition
-DEFINE_DEVICE_TYPE(Z80SIO_CHANNEL, z80sio_channel, "z80sio_channel", "Z80 SIO channel")
-DEFINE_DEVICE_TYPE(I8274_CHANNEL, i8274_channel, "i8274_channel", "Intel 8274 MPSC channel")
-DEFINE_DEVICE_TYPE(Z80SIO, z80sio_device, "z80sio", "Z80 SIO")
-DEFINE_DEVICE_TYPE(I8274_NEW, i8274_new_device, "i8274_new", "Intel 8274 MPSC (new)") // Remove trailing N when z80dart.cpp's 8274 implementation is fully replaced
-DEFINE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device, "upd7201_new", "NEC uPD7201 MPSC (new)") // Remove trailing N when z80dart.cpp's 7201 implementation is fully replaced
+DEFINE_DEVICE_TYPE(Z80SIO_CHANNEL, z80sio_channel, "z80sio_channel", "Z80 SIO channel")
+DEFINE_DEVICE_TYPE(I8274_CHANNEL, i8274_channel, "i8274_channel", "Intel 8274 MPSC channel")
+DEFINE_DEVICE_TYPE(MK68564_CHANNEL, mk68564_channel, "mk68564_channel", "Mostek MK68564 SIO channel")
+DEFINE_DEVICE_TYPE(Z80SIO, z80sio_device, "z80sio", "Z80 SIO")
+DEFINE_DEVICE_TYPE(I8274_NEW, i8274_new_device, "i8274_new", "Intel 8274 MPSC (new)") // Remove trailing N when z80dart.cpp's 8274 implementation is fully replaced
+DEFINE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device, "upd7201_new", "NEC uPD7201 MPSC (new)") // Remove trailing N when z80dart.cpp's 7201 implementation is fully replaced
+DEFINE_DEVICE_TYPE(MK68564, mk68564_device, "mk68564", "Mostek MK68564 SIO")
//-------------------------------------------------
// device_add_mconfig - add device configuration
@@ -258,6 +269,12 @@ void i8274_new_device::device_add_mconfig(machine_config &config)
I8274_CHANNEL(config, CHANB_TAG, 0);
}
+void mk68564_device::device_add_mconfig(machine_config &config)
+{
+ MK68564_CHANNEL(config, CHANA_TAG, 0);
+ MK68564_CHANNEL(config, CHANB_TAG, 0);
+}
+
//**************************************************************************
// LIVE DEVICE
@@ -290,11 +307,16 @@ inline bool z80sio_channel::receive_allowed() const
return (m_wr3 & WR3_RX_ENABLE) && (!(m_wr3 & WR3_AUTO_ENABLES) || !m_dcd);
}
-inline bool z80sio_channel::transmit_allowed() const
+bool z80sio_channel::transmit_allowed() const
{
return (m_wr5 & WR5_TX_ENABLE) && (!(m_wr3 & WR3_AUTO_ENABLES) || !m_cts);
}
+bool mk68564_channel::transmit_allowed() const
+{
+ return (m_wr5 & WR5_TX_ENABLE) && (!m_tx_auto_enable || !m_cts);
+}
+
inline void z80sio_channel::set_rts(int state)
{
if (bool(m_rts) != bool(state))
@@ -393,6 +415,11 @@ upd7201_new_device::upd7201_new_device(const machine_config &mconfig, const char
{
}
+mk68564_device::mk68564_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8274_new_device(mconfig, MK68564, tag, owner, clock)
+{
+}
+
//-------------------------------------------------
// device_validity_check - device-specific validation
//-------------------------------------------------
@@ -947,6 +974,14 @@ i8274_channel::i8274_channel(const machine_config &mconfig, const char *tag, dev
{
}
+mk68564_channel::mk68564_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : z80sio_channel(mconfig, MK68564_CHANNEL, tag, owner, clock, RR1_END_OF_FRAME | RR1_CRC_FRAMING_ERROR | RR1_RESIDUE_CODE_MASK)
+ , m_tx_auto_enable(false)
+ , m_brg_tc(0)
+ , m_brg_control(0)
+{
+}
+
//-------------------------------------------------
// resove_objects - channel setup
@@ -1016,6 +1051,15 @@ void z80sio_channel::device_start()
save_item(NAME(m_cts));
}
+void mk68564_channel::device_start()
+{
+ z80sio_channel::device_start();
+
+ save_item(NAME(m_tx_auto_enable));
+ save_item(NAME(m_brg_tc));
+ save_item(NAME(m_brg_control));
+}
+
//-------------------------------------------------
// reset - reset channel status
@@ -1066,6 +1110,15 @@ void z80sio_channel::device_reset()
m_uart->reset_interrupts();
}
+void mk68564_channel::device_reset()
+{
+ z80sio_channel::device_reset();
+
+ m_tx_auto_enable = false;
+ m_brg_tc = 0;
+ m_brg_control = 0;
+}
+
bool z80sio_channel::is_tx_idle() const
{
return (m_tx_sr & TX_SR_MASK) == TX_SR_MASK;
@@ -1337,7 +1390,7 @@ void z80sio_channel::trigger_ext_int()
//-------------------------------------------------
// get_clock_mode - get clock divisor
//-------------------------------------------------
-int z80sio_channel::get_clock_mode()
+int z80sio_channel::get_clock_mode() const
{
//LOG("%s %s\n",FUNCNAME, tag());
int clocks = 1;
@@ -1385,7 +1438,7 @@ void z80sio_channel::update_dtr_rts_break()
//-------------------------------------------------
// get_rx_word_length - get receive word length
//-------------------------------------------------
-int z80sio_channel::get_rx_word_length()
+int z80sio_channel::get_rx_word_length() const
{
LOG("%s %s\n",FUNCNAME, tag());
int bits = 5;
@@ -2524,3 +2577,339 @@ WRITE_LINE_MEMBER( z80sio_channel::txc_w )
}
m_tx_clock = state;
}
+
+//**************************************************************************
+// MK68564 REGISTER INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// cmdreg_r - read from command register
+//-------------------------------------------------
+uint8_t mk68564_channel::cmdreg_r()
+{
+ return m_wr0;
+}
+
+
+//-------------------------------------------------
+// cmdreg_w - write to command register
+//-------------------------------------------------
+void mk68564_channel::cmdreg_w(uint8_t data)
+{
+ // TODO: bit 0 sets loop mode (no register select)
+ // FIXME: no return from interrupt command
+ do_sioreg_wr0(data);
+}
+
+
+//-------------------------------------------------
+// modectl_r - read from mode control register
+//-------------------------------------------------
+uint8_t mk68564_channel::modectl_r()
+{
+ return m_wr4;
+}
+
+
+//-------------------------------------------------
+// modectl_w - write to mode control register
+//-------------------------------------------------
+void mk68564_channel::modectl_w(uint8_t data)
+{
+ do_sioreg_wr4(data);
+}
+
+
+//-------------------------------------------------
+// intctl_r - read from interrupt control register
+//-------------------------------------------------
+uint8_t mk68564_channel::intctl_r()
+{
+ return m_wr1 | (m_wr5 & WR5_CRC16 ? 0x80 : 0);
+}
+
+
+//-------------------------------------------------
+// intctl_w - write to interrupt control register
+//-------------------------------------------------
+void mk68564_channel::intctl_w(uint8_t data)
+{
+ if (BIT(data, 7))
+ m_wr5 |= WR5_CRC16;
+ else
+ m_wr5 &= ~WR5_CRC16;
+
+ // TODO: bits 5 and 6 are independent RxRDY and WxRDY enables
+ do_sioreg_wr1(data & 0x7f);
+}
+
+
+//-------------------------------------------------
+// sync1_r - read from sync word register 1
+//-------------------------------------------------
+uint8_t mk68564_channel::sync1_r()
+{
+ return m_wr6;
+}
+
+
+//-------------------------------------------------
+// sync1_w - write to sync word register 1
+//-------------------------------------------------
+void mk68564_channel::sync1_w(uint8_t data)
+{
+ do_sioreg_wr6(data);
+}
+
+
+//-------------------------------------------------
+// sync2_r - read from sync word register 2
+//-------------------------------------------------
+uint8_t mk68564_channel::sync2_r()
+{
+ return m_wr7;
+}
+
+
+//-------------------------------------------------
+// sync2_w - write to sync word register 2
+//-------------------------------------------------
+void mk68564_channel::sync2_w(uint8_t data)
+{
+ do_sioreg_wr7(data);
+}
+
+
+//-------------------------------------------------
+// rcvctl_r - read from receiver control register
+//-------------------------------------------------
+uint8_t mk68564_channel::rcvctl_r()
+{
+ return bitswap<8>(m_wr3, 6, 7, 5, 4, 3, 2, 1, 0) & ~WR3_ENTER_HUNT_PHASE;
+}
+
+
+//-------------------------------------------------
+// rcvctl_w - write to receiver control register
+//-------------------------------------------------
+void mk68564_channel::rcvctl_w(uint8_t data)
+{
+ do_sioreg_wr3(bitswap<8>(data, 6, 7, 5, 4, 3, 2, 1, 0));
+}
+
+
+//-------------------------------------------------
+// xmtctl_r - read from transmitter control
+// register
+//-------------------------------------------------
+uint8_t mk68564_channel::xmtctl_r()
+{
+ uint8_t xmtctl = 0;
+ if (m_wr5 & WR5_TX_ENABLE)
+ xmtctl |= 0x01;
+ if (m_wr5 & WR5_RTS)
+ xmtctl |= 0x02;
+ if (m_wr5 & WR5_DTR)
+ xmtctl |= 0x04;
+ if (m_wr5 & WR5_TX_CRC_ENABLE)
+ xmtctl |= 0x08;
+ if (m_wr5 & WR5_SEND_BREAK)
+ xmtctl |= 0x10;
+ if (m_tx_auto_enable)
+ xmtctl |= 0x20;
+ xmtctl |= (m_wr5 & 0x40) << 1;
+ xmtctl |= (m_wr5 & 0x80) >> 1;
+ return xmtctl;
+}
+
+
+//-------------------------------------------------
+// xmtctl_w - write to transmitter control
+// register
+//-------------------------------------------------
+void mk68564_channel::xmtctl_w(uint8_t data)
+{
+ uint8_t control =
+ (BIT(data, 0) ? WR5_TX_ENABLE : 0) |
+ (BIT(data, 1) ? WR5_RTS : 0) |
+ (BIT(data, 2) ? WR5_DTR : 0) |
+ (BIT(data, 3) ? WR5_TX_CRC_ENABLE : 0) |
+ (BIT(data, 4) ? WR5_SEND_BREAK : 0) |
+ (data & 0x40) << 1 |
+ (data & 0x80) >> 1 |
+ (m_wr5 & WR5_CRC16);
+ do_sioreg_wr5(control);
+
+ m_tx_auto_enable = BIT(data, 5);
+}
+
+
+//-------------------------------------------------
+// tcreg_r - read from time constant register
+//-------------------------------------------------
+uint8_t mk68564_channel::tcreg_r()
+{
+ return m_brg_tc;
+}
+
+
+//-------------------------------------------------
+// tcreg_w - write to time constant register
+//-------------------------------------------------
+void mk68564_channel::tcreg_w(uint8_t data)
+{
+ logerror("Time constant = %d\n", data);
+ m_brg_tc = data;
+}
+
+
+//-------------------------------------------------
+// brgctl_r - read from baud rate generator
+// control register
+//-------------------------------------------------
+uint8_t mk68564_channel::brgctl_r()
+{
+ return m_brg_control;
+}
+
+
+//-------------------------------------------------
+// brgctl_w - write to baud rate generator
+// control register
+//-------------------------------------------------
+void mk68564_channel::brgctl_w(uint8_t data)
+{
+ // TODO: actually emulate this
+ logerror("BRG %sabled, divide by %d, RxC %sternal, TxC %sternal\n",
+ BIT(data, 0) ? "en" : "dis",
+ BIT(data, 1) ? 64 : 4,
+ BIT(data, 2) ? "in" : "ex",
+ BIT(data, 3) ? "in" : "ex");
+
+ // unused bits are always zero
+ m_brg_control = data & 0x0f;
+}
+
+
+//-------------------------------------------------
+// vectrg_w - write to the interrupt vector
+// register (only one exists)
+//-------------------------------------------------
+void mk68564_device::vectrg_w(uint8_t data)
+{
+ m_chanB->do_sioreg_wr2(data);
+}
+
+
+//-------------------------------------------------
+// read - 68000 compatible bus read
+//-------------------------------------------------
+uint8_t mk68564_device::read(offs_t offset)
+{
+ mk68564_channel &channel = downcast<mk68564_channel &>(BIT(offset, 4) ? *m_chanB : *m_chanA);
+
+ switch (offset & 0x0f)
+ {
+ case 0x00:
+ return channel.cmdreg_r();
+
+ case 0x01:
+ return channel.modectl_r();
+
+ case 0x02:
+ return channel.intctl_r();
+
+ case 0x03:
+ return channel.sync1_r();
+
+ case 0x04:
+ return channel.sync2_r();
+
+ case 0x05:
+ return channel.rcvctl_r();
+
+ case 0x06:
+ return channel.xmtctl_r();
+
+ case 0x07:
+ return channel.do_sioreg_rr0();
+
+ case 0x08:
+ return channel.do_sioreg_rr1();
+
+ case 0x09:
+ return channel.data_read();
+
+ case 0x0a:
+ return channel.tcreg_r();
+
+ case 0x0b:
+ return channel.brgctl_r();
+
+ case 0x0c: // vector register is addressable through either channel
+ return read_vector();
+
+ default: // unused registers read as FF
+ return 0xff;
+ }
+}
+
+
+//-------------------------------------------------
+// write - 68000 compatible bus write
+//-------------------------------------------------
+void mk68564_device::write(offs_t offset, uint8_t data)
+{
+ mk68564_channel &channel = downcast<mk68564_channel &>(BIT(offset, 4) ? *m_chanB : *m_chanA);
+
+ switch (offset & 0x0f)
+ {
+ case 0x00:
+ channel.cmdreg_w(data);
+ break;
+
+ case 0x01:
+ channel.modectl_w(data);
+ break;
+
+ case 0x02:
+ channel.intctl_w(data);
+ break;
+
+ case 0x03:
+ channel.sync1_w(data);
+ break;
+
+ case 0x04:
+ channel.sync2_w(data);
+ break;
+
+ case 0x05:
+ channel.rcvctl_w(data);
+ break;
+
+ case 0x06:
+ channel.xmtctl_w(data);
+ break;
+
+ case 0x09:
+ channel.data_write(data);
+ break;
+
+ case 0x0a:
+ channel.tcreg_w(data);
+ break;
+
+ case 0x0b:
+ channel.brgctl_w(data);
+ break;
+
+ case 0x0c: // vector register is addressable through either channel
+ vectrg_w(data);
+ break;
+
+ default:
+ LOG("Write %02X to unused/read-only register %02X\n", data, offset & 0x1f);
+ break;
+ }
+}