mc6852 - implement more functionality, add byte interface. (#6931)

This commit is contained in:
68bit 2020-07-11 05:40:01 +10:00 committed by GitHub
parent c6c5678815
commit 47e32437cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 201 additions and 17 deletions

View File

@ -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;
}

View File

@ -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;
};