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: TODO:
- FIFO - FIFO flags
- receive - receive
- transmit - transmit
- parity - parity
@ -56,7 +56,8 @@ mc6852_device::mc6852_device(const machine_config &mconfig, const char *tag, dev
m_cts(1), m_cts(1),
m_dcd(1), m_dcd(1),
m_sm_dtr(0), 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_dcd));
save_item(NAME(m_sm_dtr)); save_item(NAME(m_sm_dtr));
save_item(NAME(m_tuf)); 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 */ /* reset and inhibit receiver/transmitter sections */
m_cr[0] |= (C1_TX_RS | C1_RX_RS); m_cr[0] |= (C1_TX_RS | C1_RX_RS);
m_cr[1] &= ~(C2_EIE | C2_PC2 | C2_PC1); 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 */ /* set receiver shift register to all 1's */
m_rsr = 0xff; m_rsr = 0xff;
@ -132,6 +134,51 @@ void mc6852_device::tra_complete()
// TODO // 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 - // rcv_complete -
@ -142,29 +189,113 @@ void mc6852_device::rcv_complete()
// TODO // TODO
} }
//------------------------------------------------- //-------------------------------------------------
// read - // 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 mc6852_device::read(offs_t offset)
{ {
uint8_t data = 0; uint8_t data = 0;
if (BIT(offset, 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(); data = m_rx_fifo.front();
if (!machine().side_effects_disabled()) if (!machine().side_effects_disabled())
{
m_rx_fifo.pop(); m_rx_fifo.pop();
int trigger = (m_cr[1] & C2_1_2_BYTE) ? 1 : 2;
if (size <= trigger)
{
m_status &= ~S_RDA;
}
}
} }
} }
else else
{ {
data = m_status; 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; return data;
} }
@ -201,13 +332,40 @@ void mc6852_device::write(offs_t offset, uint8_t data)
} }
set_data_frame(1, data_bit_count, parity, stop_bits); 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; break;
}
case C1_AC_C3: case C1_AC_C3:
/* control 3 */ /* control 3 */
LOG("MC6852 Control 3 %02x\n", data); LOG("MC6852 Control 3 %02x\n", data);
m_cr[2] = 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; break;
case C1_AC_SYNC: case C1_AC_SYNC:
@ -216,16 +374,28 @@ void mc6852_device::write(offs_t offset, uint8_t data)
m_scr = data; m_scr = data;
break; break;
case C1_AC_TX_FIFO: case C1_AC_TX_FIFO: {
/* transmit data 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); LOG("MC6852 Transmit FIFO %02x\n", data);
m_tx_fifo.push(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; break;
} }
} }
}
else else
{ {
LOG("MC6852 Control 1 %02x\n", data); LOG("MC6852 Control 1 %02x\n", data);
@ -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_status &= ~(S_RX_OVRN | S_PE | S_DCD | S_RDA);
m_rsr = 0xff; m_rsr = 0xff;
m_rx_fifo = std::queue<uint8_t>();
receive_register_reset(); receive_register_reset();
} }
@ -250,22 +421,29 @@ void mc6852_device::write(offs_t offset, uint8_t data)
/* transmitter reset */ /* transmitter reset */
if (data & C1_TX_RS) if (data & C1_TX_RS)
{ {
/* When Tx Rs is set, it clears the transmitter // When Tx Rs is set, it clears the transmitter
control section, Transmitter Shift Register, Tx Data FIFO // control section, Transmitter Shift Register, Tx
Control (the Tx Data FIFO can be reloaded after one E clock // Data FIFO Control (the Tx Data FIFO can be reloaded
pulse), the Transmitter Underflow status bit, and the CTS interrupt, // after one E clock pulse), the Transmitter Underflow
and inhibits the TDRA status bit (in the one-sync-character // status bit, and the CTS interrupt.
and two-sync-character modes).*/
LOG("MC6852 Transmitter Reset\n"); 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(); transmit_register_reset();
} }
if (data & C1_STRIP_SYNC) LOG("MC6852 Strip Synchronization Characters\n"); if (data & C1_STRIP_SYNC)
if (data & C1_CLEAR_SYNC) LOG("MC6852 Clear Synchronization\n"); LOG("MC6852 Strip Synchronization Characters\n");
if (data & C1_CLEAR_SYNC)
{
LOG("MC6852 Clear Synchronization\n");
m_in_sync = 0;
}
m_cr[0] = data; 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( sm_dtr_r ) { return m_sm_dtr; }
DECLARE_READ_LINE_MEMBER( tuf_r ) { return m_tuf; } 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: protected:
// device-level overrides // device-level overrides
virtual void device_start() override; virtual void device_start() override;
@ -148,6 +153,7 @@ private:
int m_dcd; // data carrier detect int m_dcd; // data carrier detect
int m_sm_dtr; // sync match/data terminal ready int m_sm_dtr; // sync match/data terminal ready
int m_tuf; // transmitter underflow int m_tuf; // transmitter underflow
int m_in_sync;
}; };