From 47e32437cd308ece08629e1909cb6d6990ea0d85 Mon Sep 17 00:00:00 2001 From: 68bit <53298758+68bit@users.noreply.github.com> Date: Sat, 11 Jul 2020 05:40:01 +1000 Subject: mc6852 - implement more functionality, add byte interface. (#6931) --- src/devices/machine/mc6852.cpp | 212 +++++++++++++++++++++++++++++++++++++---- src/devices/machine/mc6852.h | 6 ++ 2 files changed, 201 insertions(+), 17 deletions(-) diff --git a/src/devices/machine/mc6852.cpp b/src/devices/machine/mc6852.cpp index 6d5a9876153..714e093aed3 100644 --- a/src/devices/machine/mc6852.cpp +++ b/src/devices/machine/mc6852.cpp @@ -10,7 +10,7 @@ TODO: - - FIFO + - FIFO flags - receive - transmit - parity @@ -56,7 +56,8 @@ mc6852_device::mc6852_device(const machine_config &mconfig, const char *tag, dev m_cts(1), m_dcd(1), m_sm_dtr(0), - m_tuf(0) + m_tuf(0), + m_in_sync(0) { } @@ -88,6 +89,7 @@ void mc6852_device::device_start() save_item(NAME(m_dcd)); save_item(NAME(m_sm_dtr)); save_item(NAME(m_tuf)); + save_item(NAME(m_in_sync)); } @@ -106,7 +108,7 @@ void mc6852_device::device_reset() /* reset and inhibit receiver/transmitter sections */ m_cr[0] |= (C1_TX_RS | C1_RX_RS); m_cr[1] &= ~(C2_EIE | C2_PC2 | C2_PC1); - m_status &= ~S_TDRA; + m_status |= S_TDRA; /* set receiver shift register to all 1's */ m_rsr = 0xff; @@ -132,6 +134,51 @@ void mc6852_device::tra_complete() // TODO } +//------------------------------------------------- +// receive_byte - +//------------------------------------------------- +void mc6852_device::receive_byte(uint8_t data) +{ + // Ignore if the receiver is in reset or sync is not enabled + if (m_cr[0] & (C1_RX_RS | C1_CLEAR_SYNC)) + return; + + // Handle sync detection + if (!m_in_sync) + { + // TODO also handle two sync codes. + if (data == m_scr) + { + m_in_sync = 1; + // TODO handle the various SM responses + } + return; + } + + if ((m_cr[0] & C1_STRIP_SYNC) && (data == m_scr)) + return; + + int size = m_rx_fifo.size(); + + if (size < 3) + { + m_rx_fifo.push(data); + size++; + } + else + { + // Overrun. + // TODO this should override the last data pushed + m_status |= S_RX_OVRN; + } + + int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2; + + if (size >= trigger) + { + m_status |= S_RDA; + } +} //------------------------------------------------- // rcv_complete - @@ -142,32 +189,116 @@ void mc6852_device::rcv_complete() // TODO } - //------------------------------------------------- // read - //------------------------------------------------- +// TODO each RX fifo element needs an associated PE status flag, and reading +// the status register should return the PE for the last element of the fifo. + +// TODO RX overrun should be cleared by reading the status register followed +// by reading the RX fifo. + uint8_t mc6852_device::read(offs_t offset) { uint8_t data = 0; if (BIT(offset, 0)) { - if (m_rx_fifo.size() > 0) + int size = m_rx_fifo.size(); + if (size > 0) { data = m_rx_fifo.front(); if (!machine().side_effects_disabled()) + { m_rx_fifo.pop(); + int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2; + if (size <= trigger) + { + m_status &= ~S_RDA; + } + } } } else { data = m_status; + + // TS reset inhibits the TDRA status bit (in the + // one-sync-character and two-sync-character modes) The + // m_status S_TDRA bit is allowed to reflect the actual fifo + // availability, masking it here on a read of the status, so + // that the TDRA status bit is simply unmasked here when the + // TX is taken out of reset. + if (m_cr[0] & C1_TX_RS) + { + data &= ~S_TDRA; + } + + if (!machine().side_effects_disabled()) + { + // TODO this might not be quite right, the datasheet + // states that the RX overrun flag is cleared by + // reading the status, and the RX data fifo? + m_status &= S_RX_OVRN; + } } return data; } +//------------------------------------------------- +// tx_start - +//------------------------------------------------- + +// The corresponds in time to just before the first bit of the next word is +// transmitted by this device. At this time the TX shift register is loaded +// the TUF line may be asserted if there is a TX FIFO underflow. +uint8_t mc6852_device::get_tx_byte(int *tuf) +{ + if (m_cr[0] & C1_TX_RS) + { + // FIFO is not popped when the TX is reset, but may be loaded + // so that it is pre-loaded when the reset is cleared. But + // will is send a sync code if that is enabled, of just ones? + *tuf = 0; + return 0xff; + } + + int size = m_tx_fifo.size(); + + if (size == 0) + { + // TX underflow + if (m_cr[1] & C2_TX_SYNC) + { + m_status |= S_TUF; + // TODO should the TUF callback be called, TUF is to + // be pulsed. + *tuf = 1; + return m_scr; + } + + *tuf = 0; + return 0xff; + } + + uint8_t data = m_tx_fifo.front(); + m_tx_fifo.pop(); + size--; + + int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2; + int available = 3 - size; + + if (available >= trigger) + { + m_status |= S_TDRA; + } + + *tuf = 0; + return data; +} + //------------------------------------------------- // write - @@ -201,13 +332,40 @@ void mc6852_device::write(offs_t offset, uint8_t data) } set_data_frame(1, data_bit_count, parity, stop_bits); - } + + // The fifo trigger levels may have changed, so update + // the status bits. + + int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2; + + if (m_rx_fifo.size() >= trigger) + m_status |= S_RDA; + else + m_status &= ~S_RDA; + + int tx_fifo_available = 3 - m_tx_fifo.size(); + if (tx_fifo_available >= trigger) + m_status |= S_TDRA; + else + m_status &= ~S_TDRA; + break; + } case C1_AC_C3: /* control 3 */ LOG("MC6852 Control 3 %02x\n", data); m_cr[2] = data; + if (m_cr[2] & C3_CTUF) + { + m_cr[2] &= ~C3_CTUF; + m_status &= ~S_TUF; + } + if (m_cr[2] & C3_CTS) + { + m_cr[2] &= ~C3_CTS; + m_status &= ~S_CTS; + } break; case C1_AC_SYNC: @@ -216,14 +374,26 @@ void mc6852_device::write(offs_t offset, uint8_t data) m_scr = data; break; - case C1_AC_TX_FIFO: + case C1_AC_TX_FIFO: { /* transmit data FIFO */ - if (m_tx_fifo.size() < 3) + int available = 3 - m_tx_fifo.size(); + if (available > 0) { LOG("MC6852 Transmit FIFO %02x\n", data); m_tx_fifo.push(data); + available--; + } + else + { + LOG("MC6852 Transmit FIFO OVERFLOW %02x\n", data); + } + int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2; + if (available < trigger) + { + m_status &= ~S_TDRA; } break; + } } } else @@ -243,6 +413,7 @@ void mc6852_device::write(offs_t offset, uint8_t data) m_status &= ~(S_RX_OVRN | S_PE | S_DCD | S_RDA); m_rsr = 0xff; + m_rx_fifo = std::queue(); receive_register_reset(); } @@ -250,22 +421,29 @@ void mc6852_device::write(offs_t offset, uint8_t data) /* transmitter reset */ if (data & C1_TX_RS) { - /* When Tx Rs is set, it clears the transmitter - control section, Transmitter Shift Register, Tx Data FIFO - Control (the Tx Data FIFO can be reloaded after one E clock - pulse), the Transmitter Underflow status bit, and the CTS interrupt, - and inhibits the TDRA status bit (in the one-sync-character - and two-sync-character modes).*/ + // When Tx Rs is set, it clears the transmitter + // control section, Transmitter Shift Register, Tx + // Data FIFO Control (the Tx Data FIFO can be reloaded + // after one E clock pulse), the Transmitter Underflow + // status bit, and the CTS interrupt. LOG("MC6852 Transmitter Reset\n"); - m_status &= ~(S_TUF | S_CTS | S_TDRA); + m_status &= ~(S_TUF | S_CTS); + m_status |= S_TDRA; + m_tx_fifo = std::queue(); transmit_register_reset(); } - if (data & C1_STRIP_SYNC) LOG("MC6852 Strip Synchronization Characters\n"); - if (data & C1_CLEAR_SYNC) LOG("MC6852 Clear Synchronization\n"); + if (data & C1_STRIP_SYNC) + LOG("MC6852 Strip Synchronization Characters\n"); + + if (data & C1_CLEAR_SYNC) + { + LOG("MC6852 Clear Synchronization\n"); + m_in_sync = 0; + } m_cr[0] = data; } diff --git a/src/devices/machine/mc6852.h b/src/devices/machine/mc6852.h index 3f05182ed6f..27e7ec9f962 100644 --- a/src/devices/machine/mc6852.h +++ b/src/devices/machine/mc6852.h @@ -64,6 +64,11 @@ public: DECLARE_READ_LINE_MEMBER( sm_dtr_r ) { return m_sm_dtr; } DECLARE_READ_LINE_MEMBER( tuf_r ) { return m_tuf; } + // These are to allow integration of this driver with code + // controlling floppy disks. + void receive_byte(uint8_t data); + uint8_t get_tx_byte(int *tuf); + protected: // device-level overrides virtual void device_start() override; @@ -148,6 +153,7 @@ private: int m_dcd; // data carrier detect int m_sm_dtr; // sync match/data terminal ready int m_tuf; // transmitter underflow + int m_in_sync; }; -- cgit v1.2.3