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.cpp986
1 files changed, 749 insertions, 237 deletions
diff --git a/src/devices/machine/z80sio.cpp b/src/devices/machine/z80sio.cpp
index f0a867833b8..15561da267c 100644
--- a/src/devices/machine/z80sio.cpp
+++ b/src/devices/machine/z80sio.cpp
@@ -3,6 +3,9 @@
/***************************************************************************
Z80-SIO Serial Input/Output emulation
+ Z80-DART Dual Asynchronous Receiver/Transmitter emulation
+ Intel 8274 Multi-Protocol Serial Controller emulation
+ NEC µPD7201 Multiprotocol Serial Communications Controller emulation
The variants in the SIO family are only different in the packaging
but has the same register features. However, since some signals are
@@ -11,7 +14,10 @@
check that an operation is invalid because of package type but relies
on the software to be adapated for the particular version.
- Package: DIP40 SIO/0, SIO/1, SIO/2, SIO/9
+ Package: DIP40 SIO/0 (RxCB and TxCB share one pin)
+ DIP40 SIO/1 (no DTRB pin)
+ DIP40 SIO/2 (no SYNCB pin)
+ DIP40 SIO/9 (channel B is nonfunctional)
QFP44 SIO/3
PLCC44 SIO/4
-------------------------------------------------------------------
@@ -45,6 +51,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"
@@ -57,19 +72,20 @@
// MACROS / CONSTANTS
//**************************************************************************
-//#define LOG_GENERAL (1U << 0)
-#define LOG_SETUP (1U << 1)
-#define LOG_READ (1U << 2)
-#define LOG_INT (1U << 3)
-#define LOG_CMD (1U << 4)
-#define LOG_TX (1U << 5)
-#define LOG_RCV (1U << 6)
-#define LOG_CTS (1U << 7)
-#define LOG_DCD (1U << 8)
-#define LOG_SYNC (1U << 9)
-#define LOG_BIT (1U << 10)
-
-//#define VERBOSE (LOG_INT | LOG_READ | LOG_SETUP | LOG_TX | LOG_CMD | LOG_CTS)
+#define LOG_SETUP (1U << 1)
+#define LOG_READ (1U << 2)
+#define LOG_INT (1U << 3)
+#define LOG_CMD (1U << 4)
+#define LOG_TX (1U << 5)
+#define LOG_RCV (1U << 6)
+#define LOG_CTS (1U << 7)
+#define LOG_DCD (1U << 8)
+#define LOG_SYNC (1U << 9)
+#define LOG_BIT (1U << 10)
+#define LOG_RTS (1U << 11)
+#define LOG_BRG (1U << 12)
+
+//#define VERBOSE (LOG_CMD | LOG_SETUP | LOG_SYNC | LOG_BIT | LOG_TX )
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
@@ -81,9 +97,11 @@
#define LOGTX(...) LOGMASKED(LOG_TX, __VA_ARGS__)
#define LOGRCV(...) LOGMASKED(LOG_RCV, __VA_ARGS__)
#define LOGCTS(...) LOGMASKED(LOG_CTS, __VA_ARGS__)
+#define LOGRTS(...) LOGMASKED(LOG_RTS, __VA_ARGS__)
#define LOGDCD(...) LOGMASKED(LOG_DCD, __VA_ARGS__)
#define LOGSYNC(...) LOGMASKED(LOG_SYNC, __VA_ARGS__)
#define LOGBIT(...) LOGMASKED(LOG_BIT, __VA_ARGS__)
+#define LOGBRG(...) LOGMASKED(LOG_BRG, __VA_ARGS__)
#ifdef _MSC_VER
#define FUNCNAME __func__
@@ -101,7 +119,7 @@ enum : uint8_t
RR0_INTERRUPT_PENDING = 0x02,
RR0_TX_BUFFER_EMPTY = 0x04,
RR0_DCD = 0x08,
- RR0_SYNC_HUNT = 0x10,
+ RR0_SYNC_HUNT = 0x10, // RI on DART
RR0_CTS = 0x20,
RR0_TX_UNDERRUN = 0x40,
RR0_BREAK_ABORT = 0x80
@@ -110,6 +128,12 @@ enum : uint8_t
enum : uint8_t
{
RR1_ALL_SENT = 0x01,
+ // This bit is not actually present in RR1 register
+ // It's enqueued in the rx error FIFO to mark the spot
+ // where "interrupt on 1st rx character" should occur.
+ // It's stripped off before head of error FIFO is dequeued
+ // into RR1
+ RR1_HIDDEN_1ST_MARKER = 0x01,
RR1_RESIDUE_CODE_MASK = 0x0e,
RR1_PARITY_ERROR = 0x10,
RR1_RX_OVERRUN_ERROR = 0x20,
@@ -155,7 +179,7 @@ enum : uint8_t
WR1_RX_INT_ALL_PARITY = 0x10,
WR1_RX_INT_ALL = 0x18,
WR1_WRDY_ON_RX_TX = 0x20,
- WR1_WRDY_FUNCTION = 0x40, // WAIT not supported
+ WR1_WRDY_FUNCTION = 0x40,
WR1_WRDY_ENABLE = 0x80
};
@@ -235,11 +259,15 @@ 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(Z80DART_CHANNEL, z80dart_channel, "z80dart_channel", "Z80 DART 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(Z80DART, z80dart_device, "z80dart", "Z80 DART")
+DEFINE_DEVICE_TYPE(I8274, i8274_device, "i8274", "Intel 8274 MPSC")
+DEFINE_DEVICE_TYPE(UPD7201, upd7201_device, "upd7201", "NEC uPD7201 MPSC")
+DEFINE_DEVICE_TYPE(MK68564, mk68564_device, "mk68564", "Mostek MK68564 SIO")
//-------------------------------------------------
// device_add_mconfig - add device configuration
@@ -250,12 +278,24 @@ void z80sio_device::device_add_mconfig(machine_config &config)
Z80SIO_CHANNEL(config, CHANB_TAG, 0);
}
-void i8274_new_device::device_add_mconfig(machine_config &config)
+void z80dart_device::device_add_mconfig(machine_config &config)
+{
+ Z80DART_CHANNEL(config, CHANA_TAG, 0);
+ Z80DART_CHANNEL(config, CHANB_TAG, 0);
+}
+
+void i8274_device::device_add_mconfig(machine_config &config)
{
I8274_CHANNEL(config, CHANA_TAG, 0);
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
@@ -276,11 +316,31 @@ inline void z80sio_channel::out_dtr_cb(int state)
m_uart->m_out_dtr_cb[m_index](state);
}
-inline void z80sio_channel::set_ready(bool ready)
+inline void z80sio_channel::update_wait_ready()
{
- // WAIT mode not supported yet
- if (m_wr1 & WR1_WRDY_FUNCTION)
- m_uart->m_out_wrdy_cb[m_index](ready ? 0 : 1);
+ bool ready = false;
+
+ if (m_wr1 & WR1_WRDY_ENABLE)
+ {
+ if (m_wr1 & WR1_WRDY_ON_RX_TX)
+ {
+ // Monitor rx
+ ready = bool(m_rr0 & RR0_RX_CHAR_AVAILABLE);
+ }
+ else
+ {
+ // Monitor tx
+ ready = get_tx_empty();
+ }
+ if (!(m_wr1 & WR1_WRDY_FUNCTION))
+ {
+ // Ready function has opposite polarity of wait function
+ ready = !ready;
+ }
+ }
+
+ // ready/wait is active low
+ m_uart->m_out_wrdy_cb[m_index](ready ? 0 : 1);
}
inline bool z80sio_channel::receive_allowed() const
@@ -288,16 +348,21 @@ 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))
{
- LOG("%s(%d) \"%s\" Channel %c \n", FUNCNAME, state, owner()->tag(), 'A' + m_index);
+ LOGRTS("%s(%d) \"%s\" Channel %c \n", FUNCNAME, state, owner()->tag(), 'A' + m_index);
out_rts_cb(m_rts = state);
}
}
@@ -327,7 +392,7 @@ inline void z80sio_channel::tx_setup(uint16_t data, int bits, bool framing, bool
LOGBIT("%.6f TX_SR %05x data %04x flags %x\n" , machine().time().as_double() , m_tx_sr & TX_SR_MASK , data , m_tx_flags);
}
-inline void z80sio_channel::tx_setup_idle()
+void z80sio_channel::tx_setup_idle()
{
switch (m_wr4 & WR4_SYNC_MODE_MASK)
{
@@ -341,12 +406,19 @@ inline void z80sio_channel::tx_setup_idle()
break;
case WR4_SYNC_MODE_SDLC:
// SDLC transmit examples don't show flag being loaded, implying it's hard-coded on the transmit side
- tx_setup(0x7e, 8, true, false, false);
+ //tx_setup(0x7e, 8, true, false, false);
+ // Verified on a 8274, the 0x7e SYNC byte is required in CR7 to start transmitting, other values fails
+ tx_setup(m_wr7, 8, true, false, false);
break;
}
m_tx_in_pkt = false;
}
+void z80dart_channel::tx_setup_idle()
+{
+ logerror("%s (sync mode not supported by DART)\n", FUNCNAME);
+}
+
//-------------------------------------------------
// z80sio_device - constructor
//-------------------------------------------------
@@ -356,14 +428,14 @@ z80sio_device::z80sio_device(const machine_config &mconfig, device_type type, co
m_chanA(*this, CHANA_TAG),
m_chanB(*this, CHANB_TAG),
m_hostcpu(*this, finder_base::DUMMY_TAG),
- m_out_txd_cb{ { *this }, { *this } },
- m_out_dtr_cb{ { *this }, { *this } },
- m_out_rts_cb{ { *this }, { *this } },
- m_out_wrdy_cb{ { *this }, { *this } },
- m_out_sync_cb{ { *this }, { *this } },
+ m_out_txd_cb(*this),
+ m_out_dtr_cb(*this),
+ m_out_rts_cb(*this),
+ m_out_wrdy_cb(*this),
+ m_out_sync_cb(*this),
m_out_int_cb(*this),
- m_out_rxdrq_cb{ { *this }, { *this } },
- m_out_txdrq_cb{ { *this }, { *this } }
+ m_out_rxdrq_cb(*this),
+ m_out_txdrq_cb(*this)
{
for (auto & elem : m_int_state)
elem = 0;
@@ -374,18 +446,28 @@ z80sio_device::z80sio_device(const machine_config &mconfig, const char *tag, dev
{
}
-i8274_new_device::i8274_new_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+z80dart_device::z80dart_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ z80sio_device(mconfig, Z80DART, tag, owner, clock)
+{
+}
+
+i8274_device::i8274_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
z80sio_device(mconfig, type, tag, owner, clock)
{
}
-i8274_new_device::i8274_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- i8274_new_device(mconfig, I8274_NEW, tag, owner, clock)
+i8274_device::i8274_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8274_device(mconfig, I8274, tag, owner, clock)
{
}
-upd7201_new_device::upd7201_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- i8274_new_device(mconfig, UPD7201_NEW, tag, owner, clock)
+upd7201_device::upd7201_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8274_device(mconfig, UPD7201, tag, owner, clock)
+{
+}
+
+mk68564_device::mk68564_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ i8274_device(mconfig, MK68564, tag, owner, clock)
{
}
@@ -399,31 +481,6 @@ void z80sio_device::device_validity_check(validity_checker &valid) const
}
//-------------------------------------------------
-// device_resolve_objects - device-specific setup
-//-------------------------------------------------
-void z80sio_device::device_resolve_objects()
-{
- LOG("%s\n", FUNCNAME);
-
- // resolve callbacks
- m_out_txd_cb[CHANNEL_A].resolve_safe();
- m_out_dtr_cb[CHANNEL_A].resolve_safe();
- m_out_rts_cb[CHANNEL_A].resolve_safe();
- m_out_wrdy_cb[CHANNEL_A].resolve_safe();
- m_out_sync_cb[CHANNEL_A].resolve_safe();
- m_out_txd_cb[CHANNEL_B].resolve_safe();
- m_out_dtr_cb[CHANNEL_B].resolve_safe();
- m_out_rts_cb[CHANNEL_B].resolve_safe();
- m_out_wrdy_cb[CHANNEL_B].resolve_safe();
- m_out_sync_cb[CHANNEL_B].resolve_safe();
- m_out_int_cb.resolve_safe();
- m_out_rxdrq_cb[CHANNEL_A].resolve_safe();
- m_out_txdrq_cb[CHANNEL_A].resolve_safe();
- m_out_rxdrq_cb[CHANNEL_B].resolve_safe();
- m_out_txdrq_cb[CHANNEL_B].resolve_safe();
-}
-
-//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void z80sio_device::device_start()
@@ -456,7 +513,7 @@ int z80sio_device::z80daisy_irq_state()
// loop over all interrupt sources
int state = 0;
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// if we're servicing a request, don't indicate more interrupts
if (m_int_state[prio[i]] & Z80_DAISY_IEO)
@@ -481,7 +538,7 @@ int z80sio_device::z80daisy_irq_ack()
// loop over all interrupt sources
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// find the first channel with an interrupt requested
if (m_int_state[prio[i]] & Z80_DAISY_INT)
@@ -508,7 +565,7 @@ int z80sio_device::z80daisy_irq_ack()
return -1;
}
-int i8274_new_device::z80daisy_irq_ack()
+int i8274_device::z80daisy_irq_ack()
{
// FIXME: we're not modelling the full behaviour of this chip
// The 8274 is designed to work with Intel processors with multiple interrupt acknowledge cycles
@@ -547,7 +604,7 @@ int i8274_new_device::z80daisy_irq_ack()
{
// loop over all interrupt sources
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// find the first channel with an interrupt requested
if (m_int_state[prio[i]] & Z80_DAISY_INT)
@@ -586,7 +643,7 @@ void z80sio_device::z80daisy_irq_reti()
return_from_interrupt();
}
-void i8274_new_device::z80daisy_irq_reti()
+void i8274_device::z80daisy_irq_reti()
{
LOGINT("%s - i8274/uPD7201 lacks RETI detection, no action taken\n", FUNCNAME);
}
@@ -627,6 +684,8 @@ void z80sio_device::trigger_interrupt(int index, int type)
{{"INT_TRANSMIT", "INT_EXTERNAL", "INT_RECEIVE"}}[type]);
// trigger interrupt
+ if (m_int_state[(index * 3) + type] & Z80_DAISY_INT)
+ return;
m_int_state[(index * 3) + type] |= Z80_DAISY_INT;
m_chanA->m_rr0 |= RR0_INTERRUPT_PENDING;
@@ -644,6 +703,8 @@ void z80sio_device::clear_interrupt(int index, int type)
{{"INT_TRANSMIT", "INT_EXTERNAL", "INT_RECEIVE"}}[type]);
// clear interrupt
+ if (!(m_int_state[(index * 3) + type] & Z80_DAISY_INT))
+ return;
m_int_state[(index * 3) + type] &= ~Z80_DAISY_INT;
if (std::find_if(std::begin(m_int_state), std::end(m_int_state), [] (int state) { return bool(state & Z80_DAISY_INT); }) == std::end(m_int_state))
m_chanA->m_rr0 &= ~RR0_INTERRUPT_PENDING;
@@ -661,7 +722,7 @@ void z80sio_device::return_from_interrupt()
{
// loop over all interrupt sources
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
// find the first channel with an interrupt requested
if (m_int_state[prio[i]] & (Z80_DAISY_IEO))
@@ -691,7 +752,7 @@ uint8_t z80sio_device::read_vector()
// modify vector for highest-priority pending interrupt
int const *const prio = interrupt_priorities();
vec &= 0xf1U;
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
if (m_int_state[prio[i]] & Z80_DAISY_INT)
{
@@ -702,9 +763,7 @@ uint8_t z80sio_device::read_vector()
case 0 + z80sio_channel::INT_EXTERNAL:
return vec | 0x0aU;
case 0 + z80sio_channel::INT_RECEIVE:
- if (((m_chanA->m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_ALL_PARITY) && (m_chanA->m_rr1 & (m_chanA->get_special_rx_mask() | RR1_PARITY_ERROR)))
- return vec | 0x0eU;
- else if (((m_chanA->m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_ALL) && (m_chanA->m_rr1 & m_chanA->get_special_rx_mask()))
+ if (m_chanA->m_rr1 & m_chanA->get_special_rx_mask())
return vec | 0x0eU;
else
return vec | 0x0cU;
@@ -713,9 +772,7 @@ uint8_t z80sio_device::read_vector()
case 3 + z80sio_channel::INT_EXTERNAL:
return vec | 0x02U;
case 3 + z80sio_channel::INT_RECEIVE:
- if (((m_chanB->m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_ALL_PARITY) && (m_chanB->m_rr1 & (m_chanB->get_special_rx_mask() | RR1_PARITY_ERROR)))
- return vec | 0x06U;
- else if (((m_chanB->m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_ALL) && (m_chanB->m_rr1 & m_chanB->get_special_rx_mask()))
+ if (m_chanB->m_rr1 & m_chanB->get_special_rx_mask())
return vec | 0x06U;
else
return vec | 0x04U;
@@ -734,7 +791,7 @@ uint8_t z80sio_device::read_vector()
interrrupt is generated, otherwise it will indicate the previous state."
8274: "If RR2 is specified but not read, no internal interrupts, regardless of priority, are accepted."
*/
-uint8_t i8274_new_device::read_vector()
+uint8_t i8274_device::read_vector()
{
// 8086 and 8085 modes have different variable bits
bool const aff(m_chanB->m_wr1 & WR1_STATUS_VECTOR);
@@ -747,7 +804,7 @@ uint8_t i8274_new_device::read_vector()
// modify vector for highest-priority pending interrupt
int const *const prio = interrupt_priorities();
- for (int i = 0; ARRAY_LENGTH(m_int_state) > i; ++i)
+ for (int i = 0; std::size(m_int_state) > i; ++i)
{
if (m_int_state[prio[i]] & Z80_DAISY_INT)
{
@@ -809,7 +866,7 @@ int const *z80sio_device::interrupt_priorities() const
return prio;
}
-int const *i8274_new_device::interrupt_priorities() const
+int const *i8274_device::interrupt_priorities() const
{
static constexpr EQUIVALENT_ARRAY(m_int_state, int) prio_a{
0 + z80sio_channel::INT_RECEIVE, 3 + z80sio_channel::INT_RECEIVE,
@@ -832,12 +889,6 @@ int z80sio_device::m1_r()
return z80daisy_irq_ack();
}
-int i8274_new_device::m1_r()
-{
- LOGINT("%s %s \n",FUNCNAME, tag());
- return 0;
-}
-
//-------------------------------------------------
// cd_ba_r -
@@ -918,12 +969,13 @@ z80sio_channel::z80sio_channel(
, m_rx_count(0)
, m_rx_bit(0)
, m_rx_sr(0)
- , m_rx_first(0)
+ , m_rx_first(false)
, m_rxd(1)
, m_tx_data(0)
, m_tx_clock(0), m_tx_count(0), m_tx_parity(0), m_tx_sr(0), m_tx_crc(0), m_tx_hist(0), m_tx_flags(0)
, m_txd(1), m_dtr(0), m_rts(0)
- , m_ext_latched(0), m_brk_latched(0), m_cts(0), m_dcd(0), m_sync(0)
+ , m_ext_latched(false), m_brk_latched(false)
+ , m_cts(0), m_dcd(0), m_sync(0)
, m_rr1_auto_reset(rr1_auto_reset)
{
LOG("%s\n",FUNCNAME);
@@ -934,7 +986,12 @@ z80sio_channel::z80sio_channel(
}
z80sio_channel::z80sio_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : z80sio_channel(mconfig, Z80SIO_CHANNEL, tag, owner, clock, RR1_END_OF_FRAME | RR1_CRC_FRAMING_ERROR | RR1_RESIDUE_CODE_MASK)
+ : z80sio_channel(mconfig, Z80SIO_CHANNEL, tag, owner, clock, RR1_CRC_FRAMING_ERROR | RR1_RESIDUE_CODE_MASK)
+{
+}
+
+z80dart_channel::z80dart_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : z80sio_channel(mconfig, Z80DART_CHANNEL, tag, owner, clock, RR1_END_OF_FRAME | RR1_CRC_FRAMING_ERROR | RR1_RESIDUE_CODE_MASK)
{
}
@@ -943,6 +1000,16 @@ 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)
+ , m_brg_state(false)
+ , m_brg_timer(nullptr)
+{
+}
+
//-------------------------------------------------
// resove_objects - channel setup
@@ -970,23 +1037,13 @@ void z80sio_channel::device_start()
save_item(NAME(m_wr3));
save_item(NAME(m_wr4));
save_item(NAME(m_wr5));
- save_item(NAME(m_wr6));
- save_item(NAME(m_wr7));
save_item(NAME(m_rx_fifo_depth));
save_item(NAME(m_rx_data_fifo));
save_item(NAME(m_rx_error_fifo));
save_item(NAME(m_rx_clock));
save_item(NAME(m_rx_count));
- save_item(NAME(m_dlyd_rxd));
save_item(NAME(m_rx_bit));
- save_item(NAME(m_rx_bit_limit));
- save_item(NAME(m_rx_sync_fsm));
- save_item(NAME(m_rx_one_cnt));
save_item(NAME(m_rx_sr));
- save_item(NAME(m_rx_sync_sr));
- save_item(NAME(m_rx_crc_delay));
- save_item(NAME(m_rx_crc));
- save_item(NAME(m_rx_crc_en));
save_item(NAME(m_rx_parity));
save_item(NAME(m_rx_first));
save_item(NAME(m_tx_data));
@@ -994,10 +1051,8 @@ void z80sio_channel::device_start()
save_item(NAME(m_tx_count));
save_item(NAME(m_tx_phase));
save_item(NAME(m_tx_parity));
- save_item(NAME(m_tx_in_pkt));
- save_item(NAME(m_tx_forced_sync));
+ save_item(NAME(m_tx_in_pkt)); // TODO: does this actually function in async mode?
save_item(NAME(m_tx_sr));
- save_item(NAME(m_tx_crc));
save_item(NAME(m_tx_hist));
save_item(NAME(m_tx_flags));
save_item(NAME(m_tx_delay));
@@ -1010,6 +1065,41 @@ void z80sio_channel::device_start()
save_item(NAME(m_dcd));
save_item(NAME(m_sync));
save_item(NAME(m_cts));
+ sync_save_state();
+}
+
+void z80sio_channel::sync_save_state()
+{
+ save_item(NAME(m_wr6));
+ save_item(NAME(m_wr7));
+ save_item(NAME(m_dlyd_rxd));
+ save_item(NAME(m_rx_bit_limit));
+ save_item(NAME(m_rx_sync_fsm));
+ save_item(NAME(m_rx_one_cnt));
+ save_item(NAME(m_rx_sync_sr));
+ save_item(NAME(m_rx_crc_delay));
+ save_item(NAME(m_rx_crc));
+ save_item(NAME(m_rx_crc_en));
+ //save_item(NAME(m_tx_in_pkt));
+ save_item(NAME(m_tx_forced_sync));
+ save_item(NAME(m_tx_crc));
+}
+
+void z80dart_channel::sync_save_state()
+{
+ // no need to save the above members
+}
+
+void mk68564_channel::device_start()
+{
+ z80sio_channel::device_start();
+
+ m_brg_timer = timer_alloc(FUNC(mk68564_channel::brg_timeout), this);
+
+ save_item(NAME(m_tx_auto_enable));
+ save_item(NAME(m_brg_tc));
+ save_item(NAME(m_brg_control));
+ save_item(NAME(m_brg_state));
}
@@ -1029,7 +1119,7 @@ void z80sio_channel::device_reset()
m_tx_count = 0;
m_rr0 &= ~RR0_RX_CHAR_AVAILABLE;
m_rr0 |= RR0_SYNC_HUNT;
- m_rr1 &= ~(RR1_PARITY_ERROR | RR1_RX_OVERRUN_ERROR | RR1_CRC_FRAMING_ERROR);
+ m_rr1 &= ~(RR1_PARITY_ERROR | RR1_RX_OVERRUN_ERROR | RR1_CRC_FRAMING_ERROR | RR1_END_OF_FRAME);
// disable receiver
m_wr3 &= ~WR3_RX_ENABLE;
@@ -1047,7 +1137,9 @@ void z80sio_channel::device_reset()
out_txd_cb(1);
m_tx_sr = ~0;
- // TODO: what happens to WAIT/READY?
+ // Disable wait & ready
+ m_wr1 &= ~WR1_WRDY_ENABLE;
+ update_wait_ready();
// reset external lines
out_rts_cb(m_rts = 1);
@@ -1057,11 +1149,22 @@ void z80sio_channel::device_reset()
m_uart->clear_interrupt(m_index, INT_TRANSMIT);
m_uart->clear_interrupt(m_index, INT_RECEIVE);
reset_ext_status();
- // FIXME: should this actually reset all the interrtupts, or just the prioritisation (daisy chain) logic?
+ // FIXME: should this actually reset all the interrupts, or just the prioritisation (daisy chain) logic?
if (m_index == z80sio_device::CHANNEL_A)
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;
+ m_brg_state = false;
+ m_brg_timer->adjust(attotime::never);
+}
+
bool z80sio_channel::is_tx_idle() const
{
return (m_tx_sr & TX_SR_MASK) == TX_SR_MASK;
@@ -1073,6 +1176,8 @@ bool z80sio_channel::is_tx_idle() const
//-------------------------------------------------
void z80sio_channel::transmit_enable()
{
+ LOGTX("%s\n", FUNCNAME);
+
if (transmit_allowed())
{
if (is_tx_idle())
@@ -1082,8 +1187,7 @@ void z80sio_channel::transmit_enable()
LOGTX("Channel %c synchronous transmit enabled - load sync pattern\n", 'A' + m_index);
tx_setup_idle();
m_tx_forced_sync = false;
- if ((m_wr1 & WR1_WRDY_ENABLE) && !(m_wr1 & WR1_WRDY_ON_RX_TX))
- set_ready(true);
+ update_wait_ready();
}
else if (!(m_rr0 & RR0_TX_BUFFER_EMPTY))
async_tx_setup();
@@ -1113,7 +1217,7 @@ void z80sio_channel::transmit_enable()
//-------------------------------------------------
void z80sio_channel::transmit_complete()
{
- LOG("%s %s\n",FUNCNAME, tag());
+ if (!m_rts) LOGTX("%s %s\n",FUNCNAME, tag());
if ((m_wr4 & WR4_STOP_BITS_MASK) == WR4_STOP_BITS_SYNC)
sync_tx_sr_empty();
@@ -1131,7 +1235,7 @@ void z80sio_channel::sync_tx_sr_empty()
{
if (!transmit_allowed())
{
- LOGTX("%s() Channel %c Transmitter Disabled m_wr5:%02x\n", FUNCNAME, 'A' + m_index, m_wr5);
+ if (!m_rts) LOGTX("%s() Channel %c Transmitter Disabled m_wr5:%02x\n", FUNCNAME, 'A' + m_index, m_wr5);
m_tx_flags = 0;
}
else if (m_tx_forced_sync ||
@@ -1198,6 +1302,11 @@ void z80sio_channel::sync_tx_sr_empty()
}
}
+void z80dart_channel::sync_tx_sr_empty()
+{
+ LOG("%s (sync mode not supported by DART)\n", FUNCNAME);
+}
+
bool z80sio_channel::get_tx_empty() const
{
// During CRC transmission, tx buffer is shown as full
@@ -1212,19 +1321,13 @@ void z80sio_channel::set_tx_empty(bool prev_state, bool new_state)
else
m_rr0 &= ~RR0_TX_BUFFER_EMPTY;
+ update_wait_ready();
+
bool curr_tx_empty = get_tx_empty();
- if (!prev_state && curr_tx_empty)
+ if (!prev_state && curr_tx_empty && (m_wr1 & WR1_TX_INT_ENABLE))
{
- if ((m_wr1 & WR1_WRDY_ENABLE) && !(m_wr1 & WR1_WRDY_ON_RX_TX))
- set_ready(true);
- if (m_wr1 & WR1_TX_INT_ENABLE)
- m_uart->trigger_interrupt(m_index, INT_TRANSMIT);
- }
- else if (prev_state && !curr_tx_empty)
- {
- if ((m_wr1 & WR1_WRDY_ENABLE) && !(m_wr1 & WR1_WRDY_ON_RX_TX))
- set_ready(false);
+ m_uart->trigger_interrupt(m_index, INT_TRANSMIT);
}
}
@@ -1275,8 +1378,8 @@ void z80sio_channel::async_tx_setup()
void z80sio_channel::reset_ext_status()
{
// this will clear latched external pin state
- m_ext_latched = 0;
- m_brk_latched = 0;
+ m_ext_latched = false;
+ m_brk_latched = false;
read_ext();
// Clear any pending External interrupt
@@ -1320,7 +1423,7 @@ void z80sio_channel::trigger_ext_int()
// update line
if (!m_ext_latched)
read_ext();
- m_ext_latched = 1;
+ m_ext_latched = true;
// trigger interrupt if enabled
if (m_wr1 & WR1_EXT_INT_ENABLE)
@@ -1331,7 +1434,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;
@@ -1379,7 +1482,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;
@@ -1420,10 +1523,10 @@ int z80sio_channel::get_tx_word_length() const
* Break/Abort latch. */
uint8_t z80sio_channel::do_sioreg_rr0()
{
- LOGR("%s\n", FUNCNAME);
uint8_t tmp = m_rr0 & ~RR0_TX_BUFFER_EMPTY;
if (get_tx_empty())
tmp |= RR0_TX_BUFFER_EMPTY;
+ LOGR("%s: %02x\n", FUNCNAME, tmp);
return tmp;
}
@@ -1507,7 +1610,7 @@ void z80sio_channel::do_sioreg_wr0_resets(uint8_t data)
LOGCMD("Z80SIO Channel %c : CRC_RESET_NULL\n", 'A' + m_index);
break;
case WR0_CRC_RESET_RX: /* In Synchronous mode: all Os (zeros) (CCITT-O CRC-16) */
- LOGCMD("Z80SIO Channel %c : CRC_RESET_RX - not implemented\n", 'A' + m_index);
+ LOGCMD("Z80SIO Channel %c : CRC_RESET_RX\n", 'A' + m_index);
m_rx_crc = ((m_wr4 & WR4_SYNC_MODE_MASK) == WR4_SYNC_MODE_SDLC) ? ~uint16_t(0U) : uint16_t(0U);
m_rx_crc_en = false;
break;
@@ -1520,6 +1623,8 @@ void z80sio_channel::do_sioreg_wr0_resets(uint8_t data)
// Command is accepted in active part of packet only
if (m_tx_in_pkt)
m_rr0 &= ~RR0_TX_UNDERRUN;
+ else
+ LOGCMD(" - not accepted as not in active part of packet\n");
break;
default: /* Will not happen unless someone messes with the mask */
logerror("Z80SIO Channel %c : %s Wrong CRC reset/init command:%02x\n", 'A' + m_index, FUNCNAME, data & WR0_CRC_RESET_CODE_MASK);
@@ -1531,7 +1636,7 @@ void z80sio_channel::do_sioreg_wr0(uint8_t data)
m_wr0 = data;
if ((data & WR0_COMMAND_MASK) != WR0_NULL)
- LOGSETUP(" * %s %c Reg %02x <- %02x \n", owner()->tag(), 'A' + m_index, 0, data);
+ LOGSETUP("\n * %s %c Reg %02x <- %02x \n", owner()->tag(), 'A' + m_index, 0, data);
switch (data & WR0_COMMAND_MASK)
{
case WR0_NULL:
@@ -1563,7 +1668,7 @@ void z80sio_channel::do_sioreg_wr0(uint8_t data)
case WR0_ENABLE_INT_NEXT_RX:
// enable interrupt on next receive character
LOGINT("%s Ch:%c : Enable Interrupt on Next Received Character\n", FUNCNAME, 'A' + m_index);
- m_rx_first = 1;
+ m_rx_first = true;
break;
case WR0_RESET_TX_INT:
LOGCMD("%s Ch:%c : Reset Transmitter Interrupt Pending\n", FUNCNAME, 'A' + m_index);
@@ -1573,7 +1678,7 @@ void z80sio_channel::do_sioreg_wr0(uint8_t data)
case WR0_ERROR_RESET:
// error reset
LOGCMD("%s Ch:%c : Error Reset\n", FUNCNAME, 'A' + m_index);
- if ((WR1_RX_INT_FIRST == (m_wr1 & WR1_RX_INT_MODE_MASK)) && (m_rr1 & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR)))
+ if ((WR1_RX_INT_FIRST == (m_wr1 & WR1_RX_INT_MODE_MASK)) && (m_rr1 & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_END_OF_FRAME)))
{
// clearing framing and overrun errors advances the FIFO
// TODO: Intel 8274 manual doesn't mention this behaviour - is it specific to Z80 SIO?
@@ -1583,6 +1688,7 @@ void z80sio_channel::do_sioreg_wr0(uint8_t data)
else
{
m_rr1 &= ~(RR1_END_OF_FRAME | RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR);
+ update_rx_int();
}
break;
case WR0_RETURN_FROM_INT:
@@ -1601,44 +1707,35 @@ void z80sio_channel::do_sioreg_wr1(uint8_t data)
{
/* TODO: implement vector modifications when WR1 bit D2 is changed */
m_wr1 = data;
- LOG("Z80SIO \"%s\" Channel %c : External Interrupt Enable %u\n", owner()->tag(), 'A' + m_index, (data & WR1_EXT_INT_ENABLE) ? 1 : 0);
- LOG("Z80SIO \"%s\" Channel %c : Transmit Interrupt Enable %u\n", owner()->tag(), 'A' + m_index, (data & WR1_TX_INT_ENABLE) ? 1 : 0);
- LOG("Z80SIO \"%s\" Channel %c : Status Affects Vector %u\n", owner()->tag(), 'A' + m_index, (data & WR1_STATUS_VECTOR) ? 1 : 0);
- LOG("Z80SIO \"%s\" Channel %c : Wait/Ready Enable %u\n", owner()->tag(), 'A' + m_index, (data & WR1_WRDY_ENABLE) ? 1 : 0);
- LOG("Z80SIO \"%s\" Channel %c : Wait/Ready Function %s\n", owner()->tag(), 'A' + m_index, (data & WR1_WRDY_FUNCTION) ? "Ready" : "Wait");
- LOG("Z80SIO \"%s\" Channel %c : Wait/Ready on %s\n", owner()->tag(), 'A' + m_index, (data & WR1_WRDY_ON_RX_TX) ? "Receive" : "Transmit");
-
- switch (data & WR1_RX_INT_MODE_MASK)
- {
- case WR1_RX_INT_DISABLE:
- LOG("Z80SIO \"%s\" Channel %c : Receiver Interrupt Disabled\n", owner()->tag(), 'A' + m_index);
- break;
+ LOGSETUP("Z80SIO \"%s\" Channel %c :\n", owner()->tag(), 'A' + m_index);
+ LOGSETUP(" - External Interrupt Enable %u\n", (data & WR1_EXT_INT_ENABLE) ? 1 : 0);
+ LOGSETUP(" - Transmit Interrupt Enable %u\n", (data & WR1_TX_INT_ENABLE) ? 1 : 0);
+ LOGSETUP(" - Status Affects Vector %u\n", (data & WR1_STATUS_VECTOR) ? 1 : 0);
+ LOGSETUP(" - Wait/Ready Enable %u\n", (data & WR1_WRDY_ENABLE) ? 1 : 0);
+ LOGSETUP(" - Wait/Ready Function %s\n", (data & WR1_WRDY_FUNCTION) ? "Ready" : "Wait");
+ LOGSETUP(" - Wait/Ready on %s\n", (data & WR1_WRDY_ON_RX_TX) ? "Rx" : "Tx");
+ LOGSETUP(" - Receiver Interrupt %s\n", std::array<char const *, 4>
+ {{"Disabled", "on First Character", "on All Characters, Parity Affects Vector", "on All Characters"}}[(m_wr2 >> 3) & 0x03]);
- case WR1_RX_INT_FIRST:
- LOG("Z80SIO \"%s\" Channel %c : Receiver Interrupt on First Character\n", owner()->tag(), 'A' + m_index);
- break;
-
- case WR1_RX_INT_ALL_PARITY:
- LOG("Z80SIO \"%s\" Channel %c : Receiver Interrupt on All Characters, Parity Affects Vector\n", owner()->tag(), 'A' + m_index);
- break;
-
- case WR1_RX_INT_ALL:
- LOG("Z80SIO \"%s\" Channel %c : Receiver Interrupt on All Characters\n", owner()->tag(), 'A' + m_index);
- break;
- }
-
- if (!(data & WR1_WRDY_ENABLE))
- set_ready(false);
- else if (data & WR1_WRDY_ON_RX_TX)
- set_ready(bool(m_rr0 & RR0_RX_CHAR_AVAILABLE));
- else
- set_ready(m_rr0 & RR0_TX_BUFFER_EMPTY);
+ update_wait_ready();
}
void z80sio_channel::do_sioreg_wr2(uint8_t data)
{
m_wr2 = data;
- LOG("Z80SIO \"%s\" Channel %c : Interrupt Vector %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOGSETUP("Z80SIO \"%s\" Channel %c : ", owner()->tag(), 'A' + m_index);
+ if (m_index == 0)
+ {
+ LOGSETUP(" - INT/DMA priority and mode: %02x\n", m_wr2 & 0x07);
+ LOGSETUP(" - Interrupt mode: %s\n", std::array<char const *, 4> {{"85-1", "85-2", "85-3", "86"}}[(m_wr2 >> 3) & 0x03]);
+ LOGSETUP(" - Vector mode: %s\n", (m_wr2 & 0x20) ? "Vectored" : "Non-vectored");
+ LOGSETUP(" - Rx INT mask: %d\n", (m_wr2 >> 6) & 0x01 );
+ LOGSETUP(" - Pin 10: %s\n", (m_wr2 & 0x80) ? "SYNCB" : "RTSB");
+ }
+ else
+ {
+ LOGSETUP("Interrupt Vector %02x\n", m_wr2);
+ }
}
void z80sio_channel::do_sioreg_wr3(uint8_t data)
@@ -1647,12 +1744,13 @@ void z80sio_channel::do_sioreg_wr3(uint8_t data)
LOGSETUP("Z80SIO Channel %c : Sync Character Load Inhibit %u\n", 'A' + m_index, (data & WR3_SYNC_CHAR_LOAD_INHIBIT) ? 1 : 0);
LOGSETUP("Z80SIO Channel %c : Receive CRC Enable %u\n", 'A' + m_index, (data & WR3_RX_CRC_ENABLE) ? 1 : 0);
LOGSETUP("Z80SIO Channel %c : Auto Enables %u\n", 'A' + m_index, (data & WR3_AUTO_ENABLES) ? 1 : 0);
- LOGSETUP("Z80SIO Channel %c : Receiver Bits/Character %u\n", 'A' + m_index, get_rx_word_length());
- if (data & WR3_ENTER_HUNT_PHASE)
- LOGCMD("Z80SIO Channel %c : Enter Hunt Phase\n", 'A' + m_index);
+ LOGSETUP("Z80SIO Channel %c : Enter Hunt Phase %u\n", 'A' + m_index, (data & WR3_ENTER_HUNT_PHASE) ? 1 : 0);
+ //if (data & WR3_ENTER_HUNT_PHASE)
+ //LOGCMD("Z80SIO Channel %c : Enter Hunt Phase\n", 'A' + m_index);
bool const was_allowed(receive_allowed());
m_wr3 = data;
+ LOG("Z80SIO Channel %c : Receiver Bits/Character %u\n", 'A' + m_index, get_rx_word_length()); // depends on m_wr3 being updated
if (!was_allowed && receive_allowed())
{
@@ -1668,25 +1766,27 @@ void z80sio_channel::do_sioreg_wr3(uint8_t data)
void z80sio_channel::do_sioreg_wr4(uint8_t data)
{
m_wr4 = data;
- LOG("Z80SIO \"%s\" Channel %c : Parity Enable %u\n", owner()->tag(), 'A' + m_index, (data & WR4_PARITY_ENABLE) ? 1 : 0);
- LOG("Z80SIO \"%s\" Channel %c : Parity %s\n", owner()->tag(), 'A' + m_index, (data & WR4_PARITY_EVEN) ? "Even" : "Odd");
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Parity Enable %u\n", owner()->tag(), 'A' + m_index, (data & WR4_PARITY_ENABLE) ? 1 : 0);
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Parity %s\n", owner()->tag(), 'A' + m_index, (data & WR4_PARITY_EVEN) ? "Even" : "Odd");
if ((m_wr4 & WR4_STOP_BITS_MASK) == WR4_STOP_BITS_SYNC)
- LOG("Z80SIO \"%s\" Channel %c : Synchronous Mode\n", owner()->tag(), 'A' + m_index);
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Synchronous Mode %s\n", owner()->tag(), 'A' + m_index,
+ std::array<char const *, 4> {{"Monosync", "Bisync", "HDLC/SDLC", "External"}}[(m_wr4 >> 4) & 0x03]);
else
- LOG("Z80SIO \"%s\" Channel %c : Stop Bits %g\n", owner()->tag(), 'A' + m_index, (((m_wr4 & WR4_STOP_BITS_MASK) >> 2) + 1) / 2.);
- LOG("Z80SIO \"%s\" Channel %c : Clock Mode %uX\n", owner()->tag(), 'A' + m_index, get_clock_mode());
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Stop Bits %g\n", owner()->tag(), 'A' + m_index, (((m_wr4 & WR4_STOP_BITS_MASK) >> 2) + 1) / 2.);
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Clock Mode %uX\n", owner()->tag(), 'A' + m_index, get_clock_mode());
}
void z80sio_channel::do_sioreg_wr5(uint8_t data)
{
m_wr5 = data;
- LOG("Z80SIO Channel %c : Transmitter Enable %u\n", 'A' + m_index, (data & WR5_TX_ENABLE) ? 1 : 0);
- LOG("Z80SIO Channel %c : Transmitter Bits/Character %u\n", 'A' + m_index, get_tx_word_length());
- LOG("Z80SIO Channel %c : Transmit CRC Enable %u\n", 'A' + m_index, (data & WR5_TX_CRC_ENABLE) ? 1 : 0);
- LOG("Z80SIO Channel %c : %s Frame Check Polynomial\n", 'A' + m_index, (data & WR5_CRC16) ? "CRC-16" : "SDLC");
- LOG("Z80SIO Channel %c : Send Break %u\n", 'A' + m_index, (data & WR5_SEND_BREAK) ? 1 : 0);
- LOG("Z80SIO Channel %c : Request to Send %u\n", 'A' + m_index, (data & WR5_RTS) ? 1 : 0);
- LOG("Z80SIO Channel %c : Data Terminal Ready %u\n", 'A' + m_index, (data & WR5_DTR) ? 1 : 0);
+ LOGSETUP("Z80SIO Channel %c\n", 'A' + m_index);
+ LOGSETUP(" - Transmitter Enable %u\n", (data & WR5_TX_ENABLE) ? 1 : 0);
+ LOGSETUP(" - Transmitter Bits/Character %u\n", get_tx_word_length());
+ LOGSETUP(" - Transmit CRC Enable %u\n", (data & WR5_TX_CRC_ENABLE) ? 1 : 0);
+ LOGSETUP(" - %s Frame Check Polynomial\n", (data & WR5_CRC16) ? "CRC-16" : "SDLC");
+ LOGSETUP(" - Send Break %u\n", (data & WR5_SEND_BREAK) ? 1 : 0);
+ LOGSETUP(" - Request to Send %u\n", (data & WR5_RTS) ? 1 : 0);
+ LOGSETUP(" - Data Terminal Ready %u\n", (data & WR5_DTR) ? 1 : 0);
if (~data & WR5_TX_ENABLE)
m_uart->clear_interrupt(m_index, INT_TRANSMIT);
@@ -1694,13 +1794,13 @@ void z80sio_channel::do_sioreg_wr5(uint8_t data)
void z80sio_channel::do_sioreg_wr6(uint8_t data)
{
- LOG("Z80SIO \"%s\" Channel %c : Transmit Sync/Sync 1/SDLC Address %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Transmit Sync/Sync 1/SDLC Address %02x\n", owner()->tag(), 'A' + m_index, data);
m_wr6 = data;
}
void z80sio_channel::do_sioreg_wr7(uint8_t data)
{
- LOG("Z80SIO \"%s\" Channel %c : Receive Sync/Sync 2/SDLC Flag %02x\n", owner()->tag(), 'A' + m_index, data);
+ LOGSETUP("Z80SIO \"%s\" Channel %c : Receive Sync/Sync 2/SDLC Flag %02x\n", owner()->tag(), 'A' + m_index, data);
m_wr7 = data;
}
@@ -1714,7 +1814,7 @@ void z80sio_channel::control_write(uint8_t data)
if (reg != 0)
{
LOGSETUP(" * %s %c Reg %02x <- %02x - %s\n", tag(), 'A' + m_index, reg, data, std::array<char const *, 8>
- {{"WR0", "WR1", "WR2", "WR3 - Async Rx setup", "WR4 - Async Clock, Parity and stop bits", "WR5 - Async Tx setup", "WR6", "WR7"}}[reg]);
+ {{"WR0", "WR1", "WR2", "WR3", "WR4", "WR5", "WR6", "WR7"}}[reg]);
// mask out register index
m_wr0 &= ~WR0_REGISTER_MASK;
}
@@ -1771,10 +1871,14 @@ void z80sio_channel::data_write(uint8_t data)
m_tx_data = data;
set_tx_empty(get_tx_empty() , false);
if ((m_wr4 & WR4_STOP_BITS_MASK) == WR4_STOP_BITS_SYNC)
+ {
+ LOGTX("Z80SIO: WR4_STOP_BITS_SYNC detected\n");
m_tx_in_pkt = true;
+ }
else
{
// ALL_SENT is only meaningful in async mode, in sync mode it's always 1
+ LOGTX("Z80SIO: WR4_STOP_BITS_SYNC *not* detected\n");
m_rr1 &= ~RR1_ALL_SENT;
m_all_sent_delay = 0;
}
@@ -1804,37 +1908,59 @@ void z80sio_channel::advance_rx_fifo()
m_rx_error_fifo >>= 8;
// load error status from the FIFO
- m_rr1 = (m_rr1 & ~m_rr1_auto_reset) | uint8_t(m_rx_error_fifo & 0x000000ffU);
-
- // if we're in interrupt-on-first mode, clear interrupt if there's no pending error condition
- if ((m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_FIRST)
- {
- for (int i = 0; m_rx_fifo_depth > i; ++i)
- {
- if (uint8_t(m_rx_error_fifo >> (i * 8)) & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR))
- return;
- }
- m_uart->clear_interrupt(m_index, INT_RECEIVE);
- }
+ m_rr1 = (m_rr1 & ~m_rr1_auto_reset) | uint8_t(m_rx_error_fifo & 0x000000ffU & ~RR1_HIDDEN_1ST_MARKER);
}
else
{
// no more characters available in the FIFO
m_rr0 &= ~RR0_RX_CHAR_AVAILABLE;
- if ((m_wr1 & WR1_WRDY_ENABLE) && (m_wr1 & WR1_WRDY_ON_RX_TX))
- set_ready(false);
- m_uart->clear_interrupt(m_index, INT_RECEIVE);
+ update_wait_ready();
}
}
+ update_rx_int();
}
uint8_t z80sio_channel::get_special_rx_mask() const
{
- return ((m_wr4 & WR4_STOP_BITS_MASK) == WR4_STOP_BITS_SYNC) ?
- (RR1_RX_OVERRUN_ERROR | RR1_END_OF_FRAME) :
- (RR1_RX_OVERRUN_ERROR | RR1_CRC_FRAMING_ERROR);
+ if ((m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_DISABLE)
+ {
+ return 0;
+ }
+ else
+ {
+ uint8_t mask = ((m_wr4 & WR4_STOP_BITS_MASK) == WR4_STOP_BITS_SYNC) ?
+ (RR1_RX_OVERRUN_ERROR | RR1_END_OF_FRAME) :
+ (RR1_RX_OVERRUN_ERROR | RR1_CRC_FRAMING_ERROR);
+ if ((m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_ALL_PARITY)
+ mask |= RR1_PARITY_ERROR;
+ return mask;
+ }
}
+void z80sio_channel::update_rx_int()
+{
+ bool state = false;
+
+ auto rx_int_mode = m_wr1 & WR1_RX_INT_MODE_MASK;
+ if (rx_int_mode != WR1_RX_INT_DISABLE)
+ {
+ if (m_rr1 & get_special_rx_mask())
+ state = true;
+ else if (m_rx_fifo_depth)
+ {
+ // FIFO not empty
+ if (rx_int_mode != WR1_RX_INT_FIRST)
+ state = true;
+ else if (m_rx_error_fifo & RR1_HIDDEN_1ST_MARKER)
+ state = true;
+ }
+ }
+ LOGINT("rx %d wr1 %02x rr1 %02x fd %u ref %06x\n", state, m_wr1, m_rr1, m_rx_fifo_depth, m_rx_error_fifo);
+ if (state)
+ m_uart->trigger_interrupt(m_index, INT_RECEIVE);
+ else
+ m_uart->clear_interrupt(m_index, INT_RECEIVE);
+}
//-------------------------------------------------
// receive_enabled - conditions have changed
@@ -1860,6 +1986,11 @@ void z80sio_channel::enter_hunt_mode()
}
}
+void z80dart_channel::enter_hunt_mode()
+{
+ LOG("%s (sync mode not supported by DART)\n", FUNCNAME);
+}
+
//-------------------------------------------------
// sync_receive - synchronous reception handler
//-------------------------------------------------
@@ -1977,6 +2108,11 @@ void z80sio_channel::sync_receive()
m_dlyd_rxd = m_rxd;
}
+void z80dart_channel::sync_receive()
+{
+ LOG("%s (sync mode not supported by DART)\n", FUNCNAME);
+}
+
//-------------------------------------------------
// sdlc_receive - SDLC reception handler
//-------------------------------------------------
@@ -2003,7 +2139,7 @@ void z80sio_channel::sdlc_receive()
LOGRCV("SDLC Abort detected\n");
m_rr0 |= RR0_BREAK_ABORT;
if (!m_brk_latched) {
- m_brk_latched = 1;
+ m_brk_latched = true;
trigger_ext_int();
}
enter_hunt_mode();
@@ -2023,7 +2159,7 @@ void z80sio_channel::sdlc_receive()
{
m_rr0 &= ~RR0_BREAK_ABORT;
if (!m_brk_latched) {
- m_brk_latched = 1;
+ m_brk_latched = true;
trigger_ext_int();
}
}
@@ -2112,7 +2248,13 @@ void z80sio_channel::sdlc_receive()
data |= ~((1U << m_rx_bit_limit) - 1);
LOGRCV("SDLC rx data=%02x (%d bits)\n" , data , m_rx_bit_limit);
queue_received(data , 0);
- m_rx_sync_fsm = SYNC_FSM_IN_FRAME;
+ if (m_rx_sync_fsm == SYNC_FSM_1ST_CHAR)
+ {
+ // reception of 1st char clears END-OF-FRAME
+ m_rr1 &= ~RR1_END_OF_FRAME;
+ update_rx_int();
+ m_rx_sync_fsm = SYNC_FSM_IN_FRAME;
+ }
}
}
}
@@ -2124,6 +2266,11 @@ void z80sio_channel::sdlc_receive()
}
}
+void z80dart_channel::sdlc_receive()
+{
+ logerror("%s (sync mode not supported by DART)\n", FUNCNAME);
+}
+
//-------------------------------------------------
// receive_data - receive data word
//-------------------------------------------------
@@ -2138,6 +2285,13 @@ void z80sio_channel::receive_data()
void z80sio_channel::queue_received(uint16_t data, uint32_t error)
{
+ if ((m_wr1 & WR1_RX_INT_MODE_MASK) == WR1_RX_INT_FIRST && m_rx_first)
+ {
+ // insert a hidden marker for 1st received character
+ error |= RR1_HIDDEN_1ST_MARKER;
+ m_rx_first = false;
+ }
+
if (3 == m_rx_fifo_depth)
{
LOG(" Receive FIFO overrun detected\n");
@@ -2155,38 +2309,22 @@ void z80sio_channel::queue_received(uint16_t data, uint32_t error)
m_rx_data_fifo |= uint32_t(data & 0x00ffU) << (8 * m_rx_fifo_depth);
m_rx_error_fifo |= error << (8 * m_rx_fifo_depth);
if (!m_rx_fifo_depth)
- m_rr1 = (m_rr1 & ~m_rr1_auto_reset) | uint8_t(error);
+ m_rr1 = (m_rr1 & ~m_rr1_auto_reset) | uint8_t(error & ~RR1_HIDDEN_1ST_MARKER);
++m_rx_fifo_depth;
}
m_rr0 |= RR0_RX_CHAR_AVAILABLE;
- if ((m_wr1 & WR1_WRDY_ENABLE) && (m_wr1 & WR1_WRDY_ON_RX_TX))
- set_ready(true);
+ update_wait_ready();
// receive interrupt
- switch (m_wr1 & WR1_RX_INT_MODE_MASK)
- {
- case WR1_RX_INT_FIRST:
- if (m_rx_first || (error & get_special_rx_mask()))
- m_uart->trigger_interrupt(m_index, INT_RECEIVE);
- m_rx_first = 0;
- break;
-
- case WR1_RX_INT_ALL_PARITY:
- case WR1_RX_INT_ALL:
- m_uart->trigger_interrupt(m_index, INT_RECEIVE);
- break;
-
- default:
- LOG("No receive interrupt triggered\n");
- }
+ update_rx_int();
}
//-------------------------------------------------
// cts_w - clear to send handler
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::cts_w )
+void z80sio_channel::cts_w(int state)
{
if (bool(m_cts) != bool(state))
{
@@ -2204,11 +2342,11 @@ WRITE_LINE_MEMBER( z80sio_channel::cts_w )
//-------------------------------------------------
// dcd_w - data carrier detected handler
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::dcd_w )
+void z80sio_channel::dcd_w(int state)
{
if (bool(m_dcd) != bool(state))
{
- LOG("Z80SIO Channel %c : DCD %u\n", 'A' + m_index, state);
+ LOGDCD("Z80SIO Channel %c : DCD %u\n", 'A' + m_index, state);
bool const was_allowed(receive_allowed());
m_dcd = state;
@@ -2224,11 +2362,11 @@ WRITE_LINE_MEMBER( z80sio_channel::dcd_w )
//-------------------------------------------------
// sh_w - Sync Hunt handler
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::sync_w )
+void z80sio_channel::sync_w(int state)
{
if (bool(m_sync) != bool(state))
{
- LOG("Z80SIO Channel %c : Sync %u\n", 'A' + m_index, state);
+ LOGSYNC("Z80SIO Channel %c : Sync %u\n", 'A' + m_index, state);
m_sync = state;
@@ -2242,7 +2380,7 @@ WRITE_LINE_MEMBER( z80sio_channel::sync_w )
//-------------------------------------------------
// rxc_w - receive clock
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::rxc_w )
+void z80sio_channel::rxc_w(int state)
{
//LOG("Z80SIO \"%s\" Channel %c : Receiver Clock Pulse\n", owner()->tag(), m_index + 'A');
//if ((receive_allowed() || m_rx_bit != 0) && state && !m_rx_clock)
@@ -2275,7 +2413,7 @@ WRITE_LINE_MEMBER( z80sio_channel::rxc_w )
LOGRCV("Break termination detected\n");
m_rr0 &= ~RR0_BREAK_ABORT;
if (!m_brk_latched) {
- m_brk_latched = 1;
+ m_brk_latched = true;
trigger_ext_int();
}
}
@@ -2342,7 +2480,7 @@ WRITE_LINE_MEMBER( z80sio_channel::rxc_w )
{
LOGRCV("Break detected\n");
m_rr0 |= RR0_BREAK_ABORT;
- m_brk_latched = 1;
+ m_brk_latched = true;
trigger_ext_int();
}
}
@@ -2367,7 +2505,7 @@ WRITE_LINE_MEMBER( z80sio_channel::rxc_w )
//-------------------------------------------------
// txc_w - transmit clock
//-------------------------------------------------
-WRITE_LINE_MEMBER( z80sio_channel::txc_w )
+void z80sio_channel::txc_w(int state)
{
//LOG("Z80SIO \"%s\" Channel %c : Transmitter Clock Pulse\n", owner()->tag(), m_index + 'A');
if (!state && m_tx_clock)
@@ -2389,9 +2527,10 @@ WRITE_LINE_MEMBER( z80sio_channel::txc_w )
m_tx_count = get_clock_mode() / 2;
// Send out a delayed half bit
bool new_txd = BIT(m_tx_delay , 3);
+ if ((m_wr4 & WR4_STOP_BITS_MASK) == WR4_STOP_BITS_SYNC || !(m_rr1 & RR1_ALL_SENT))
+ LOGBIT("%.6f TX %d DLY %x\n" , machine().time().as_double() , new_txd , m_tx_delay & 0xf);
if (new_txd != m_txd && !(m_wr5 & WR5_SEND_BREAK))
{
- LOGBIT("%.6f TX %d DLY %x\n" , machine().time().as_double() , new_txd , m_tx_delay & 0xf);
out_txd_cb(new_txd);
}
m_txd = new_txd;
@@ -2412,9 +2551,11 @@ WRITE_LINE_MEMBER( z80sio_channel::txc_w )
// Generate a new bit
bool new_bit = false;
if ((m_wr4 & (WR4_SYNC_MODE_MASK | WR4_STOP_BITS_MASK)) == (WR4_SYNC_MODE_SDLC | WR4_STOP_BITS_SYNC) &&
- !(m_tx_flags & TX_FLAG_FRAMING) && (m_tx_hist & 0x1f) == 0x1f)
- // SDLC, not sending framing & 5 ones in a row: do zero insertion
+ (m_tx_flags & (TX_FLAG_DATA_TX | TX_FLAG_CRC_TX)) && (m_tx_hist & 0x1f) == 0x1f)
+ {
+ // SDLC, sending data/CRC & 5 ones in a row: do zero insertion
new_bit = false;
+ }
else
{
bool get_out = false;
@@ -2502,10 +2643,10 @@ WRITE_LINE_MEMBER( z80sio_channel::txc_w )
else
m_all_sent_delay = 0;
}
- if (m_tx_flags & TX_FLAG_FRAMING)
- m_tx_hist = 0;
- else
+ if (m_tx_flags & (TX_FLAG_DATA_TX | TX_FLAG_CRC_TX))
m_tx_hist = (m_tx_hist << 1) | new_bit;
+ else
+ m_tx_hist = 0;
// Insert new bit in delay register
m_tx_delay = (m_tx_delay & ~1U) | new_bit;
}
@@ -2513,3 +2654,374 @@ 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)
+{
+ m_brg_tc = data;
+}
+
+
+//-------------------------------------------------
+// brgctl_r - read from baud rate generator
+// control register
+//-------------------------------------------------
+uint8_t mk68564_channel::brgctl_r()
+{
+ // unused bits are all zero
+ return m_brg_control & 0x0f;
+}
+
+
+//-------------------------------------------------
+// brgctl_w - write to baud rate generator
+// control register
+//-------------------------------------------------
+void mk68564_channel::brgctl_w(uint8_t data)
+{
+ if (BIT(data, 0))
+ LOGBRG("%s: BRG enabled, divide by %d, RxC %sternal, TxC %sternal (TC = %d, %.1f Hz)\n",
+ machine().describe_context(),
+ BIT(data, 1) ? 64 : 4,
+ BIT(data, 2) ? "in" : "ex",
+ BIT(data, 3) ? "in" : "ex",
+ m_brg_tc,
+ clocks_to_attotime((m_brg_tc ? m_brg_tc : 256) * (BIT(data, 1) ? 64 : 4)).as_hz());
+ else
+ LOGBRG("%s: BRG disabled\n", machine().describe_context());
+
+ m_brg_control = data & 0x0f;
+ m_brg_state = false;
+ brg_update();
+}
+
+
+//-------------------------------------------------
+// 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:
+ logerror("Write %02X to unused/read-only register %02X\n", data, offset & 0x1f);
+ break;
+ }
+}
+
+//**************************************************************************
+// MK68564 BAUD RATE GENERATOR
+//**************************************************************************
+
+void mk68564_device::set_xtal(uint32_t clock)
+{
+ assert(!configured());
+ subdevice<mk68564_channel>(CHANA_TAG)->set_clock(clock);
+ subdevice<mk68564_channel>(CHANB_TAG)->set_clock(clock);
+}
+
+void mk68564_channel::brg_update()
+{
+ if (BIT(m_brg_control, 2))
+ rxc_w(m_brg_state);
+ if (BIT(m_brg_control, 3))
+ txc_w(m_brg_state);
+
+ if (BIT(m_brg_control, 0))
+ m_brg_timer->adjust(clocks_to_attotime((m_brg_tc ? m_brg_tc : 256) * (BIT(m_brg_control, 1) ? 32 : 2)));
+ else
+ m_brg_timer->adjust(attotime::never);
+}
+
+TIMER_CALLBACK_MEMBER(mk68564_channel::brg_timeout)
+{
+ m_brg_state = !m_brg_state;
+ brg_update();
+}