summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author 68bit <53298758+68bit@users.noreply.github.com>2020-07-11 05:40:01 +1000
committer GitHub <noreply@github.com>2020-07-10 15:40:01 -0400
commit47e32437cd308ece08629e1909cb6d6990ea0d85 (patch)
treed66fcca21a908b9b65ae14d91bb3559528d49209
parentc6c5678815d5077bb1092a91949adcdf584e250c (diff)
mc6852 - implement more functionality, add byte interface. (#6931)
-rw-r--r--src/devices/machine/mc6852.cpp212
-rw-r--r--src/devices/machine/mc6852.h6
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<uint8_t>();
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<uint8_t>();
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;
};