mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
Improved Tx handling with fifo including special case with 1 slot fifo
This commit is contained in:
parent
14a7a262c9
commit
4e5716fa5c
@ -80,10 +80,11 @@ DONE (x) (p=partly) NMOS CMOS ESCC EMSCC
|
||||
|
||||
#define VERBOSE 0
|
||||
#define LOGPRINT(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
#define LOG(x) {}
|
||||
#define LOGR(x) {}
|
||||
#define LOG(x) LOGPRINT(x)
|
||||
#define LOGR(x) LOGPRINT(x)
|
||||
#define LOGSETUP(x) LOGPRINT(x)
|
||||
#define LOGINT(x) {} LOGPRINT(x)
|
||||
#define LOGTX(x) {} LOGPRINT(x)
|
||||
#define LOGRCV(x){}
|
||||
#if VERBOSE == 2
|
||||
#define logerror printf
|
||||
@ -780,7 +781,6 @@ z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, d
|
||||
m_rxd(0),
|
||||
m_cts(0),
|
||||
m_dcd(0),
|
||||
m_tx_data(0),
|
||||
m_tx_clock(0),
|
||||
m_dtr(0),
|
||||
m_rts(0),
|
||||
@ -797,11 +797,14 @@ z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, d
|
||||
m_wr0 = m_wr1 = m_wr2 = m_wr3 = m_wr4 = m_wr5 = m_wr6 = m_wr7 = m_wr7p = m_wr8
|
||||
= m_wr10 = m_wr11 = m_wr12 = m_wr13 = m_wr14 = m_wr15 = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++) // TODO adapt to SCC fifos
|
||||
{
|
||||
m_rx_data_fifo[i] = 0;
|
||||
m_rx_error_fifo[i] = 0;
|
||||
}
|
||||
for (auto & elem : m_rx_data_fifo)
|
||||
elem = 0;
|
||||
for (auto & elem : m_rx_error_fifo) // TODO: Status FIFO needs to be fixed
|
||||
elem = 0;
|
||||
for (auto & elem : m_tx_data_fifo)
|
||||
elem = 0;
|
||||
for (auto & elem : m_tx_error_fifo) // TODO: Status FIFO needs to be fixed
|
||||
elem = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -820,6 +823,9 @@ void z80scc_channel::device_start()
|
||||
m_rx_fifo_sz = (m_uart->m_variant & SET_ESCC) ? 8 : 3;
|
||||
m_rx_fifo_wp = m_rx_fifo_rp = 0;
|
||||
|
||||
m_tx_fifo_sz = (m_uart->m_variant & SET_ESCC) ? 4 : 1;
|
||||
m_tx_fifo_wp = m_tx_fifo_rp = 0;
|
||||
|
||||
#if LOCAL_BRG
|
||||
// baudrate clocks and timers
|
||||
baudtimer = timer_alloc(TIMER_ID_BAUD);
|
||||
@ -859,8 +865,13 @@ void z80scc_channel::device_start()
|
||||
save_item(NAME(m_wr13));
|
||||
save_item(NAME(m_wr14));
|
||||
save_item(NAME(m_wr15));
|
||||
save_item(NAME(m_tx_data_fifo));
|
||||
save_item(NAME(m_tx_error_fifo)); // TODO: Status FIFO needs to be fixed
|
||||
save_item(NAME(m_tx_fifo_rp));
|
||||
save_item(NAME(m_tx_fifo_wp));
|
||||
save_item(NAME(m_tx_fifo_sz));
|
||||
save_item(NAME(m_rx_data_fifo));
|
||||
save_item(NAME(m_rx_error_fifo));
|
||||
save_item(NAME(m_rx_error_fifo)); // TODO: Status FIFO needs to be fixed
|
||||
save_item(NAME(m_rx_fifo_rp));
|
||||
save_item(NAME(m_rx_fifo_wp));
|
||||
save_item(NAME(m_rx_fifo_sz));
|
||||
@ -871,7 +882,6 @@ void z80scc_channel::device_start()
|
||||
save_item(NAME(m_ri));
|
||||
save_item(NAME(m_cts));
|
||||
save_item(NAME(m_dcd));
|
||||
save_item(NAME(m_tx_data));
|
||||
save_item(NAME(m_tx_clock));
|
||||
save_item(NAME(m_dtr));
|
||||
save_item(NAME(m_rts));
|
||||
@ -1013,23 +1023,48 @@ void z80scc_channel::tra_callback()
|
||||
|
||||
void z80scc_channel::tra_complete()
|
||||
{
|
||||
// Delayed baudrate change according to SCC specs
|
||||
if ( m_delayed_tx_brg_change == 1)
|
||||
{
|
||||
m_delayed_tx_brg_change = 0;
|
||||
set_tra_rate(m_brg_rate);
|
||||
LOG(("Delayed setup - Baud Rate Generator: %d mode: %dx\n", m_brg_rate, get_clock_mode() ));
|
||||
}
|
||||
if ((m_wr5 & WR5_TX_ENABLE) && !(m_wr5 & WR5_SEND_BREAK) && !(m_rr0 & RR0_TX_BUFFER_EMPTY))
|
||||
|
||||
if ((m_wr5 & WR5_TX_ENABLE) && !(m_wr5 & WR5_SEND_BREAK))
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Transmit Data Byte '%02x' m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_tx_data, m_wr5));
|
||||
if ( (m_rr0 & RR0_TX_BUFFER_EMPTY) == 0 || // Takes care of the NMOS/CMOS 1 slot TX FIFO
|
||||
m_tx_fifo_rp != m_tx_fifo_wp) // or there are more characters to send in a longer FIFO.
|
||||
{
|
||||
LOGTX((" %s() %s %c done sending, loading data from fifo:%02x '%c'\n", FUNCNAME, m_owner->tag(), 'A' + m_index,
|
||||
m_tx_data_fifo[m_tx_fifo_rp], isascii(m_tx_data_fifo[m_tx_fifo_rp]) ? m_tx_data_fifo[m_tx_fifo_rp] : ' '));
|
||||
transmit_register_setup(m_tx_data_fifo[m_tx_fifo_rp]); // Reload the shift register
|
||||
m_tx_fifo_rp_step();
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY; // Now here is room in the tx fifo again
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGTX((" %s() %s %c done sending, setting all sent bit\n", FUNCNAME, m_owner->tag(), 'A' + m_index));
|
||||
m_rr1 |= RR1_ALL_SENT;
|
||||
|
||||
transmit_register_setup(m_tx_data);
|
||||
|
||||
// empty transmit buffer
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY;
|
||||
// when the RTS bit is reset, the _RTS output goes high after the transmitter empties
|
||||
if (!m_rts) // TODO: Clean up RTS handling
|
||||
set_rts(1);
|
||||
}
|
||||
|
||||
if (m_wr1 & WR1_TX_INT_ENABLE)
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT);
|
||||
{
|
||||
if ((m_uart->m_variant & SET_ESCC) &&
|
||||
(m_wr7p & WR7P_TX_FIFO_EMPTY) &&
|
||||
m_tx_fifo_wp == m_tx_fifo_rp) // ESCC and fifo empty bit set and fifo is completelly empty?
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT); // Set TXIP bit
|
||||
}
|
||||
else if(m_rr0 & RR0_TX_BUFFER_EMPTY) // Check TBE bit and interrupt if one or more FIFO slots availble
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT); // Set TXIP bit
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_wr5 & WR5_SEND_BREAK)
|
||||
{
|
||||
@ -1049,18 +1084,6 @@ void z80scc_channel::tra_complete()
|
||||
else
|
||||
m_uart->m_out_txdb_cb(1);
|
||||
}
|
||||
|
||||
// if transmit buffer is empty
|
||||
if (m_rr0 & RR0_TX_BUFFER_EMPTY)
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Transmit buffer empty m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
// then all characters have been sent
|
||||
m_rr1 |= RR1_ALL_SENT;
|
||||
|
||||
// when the RTS bit is reset, the _RTS output goes high after the transmitter empties
|
||||
if (!m_rts)
|
||||
set_rts(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1322,12 +1345,12 @@ UINT8 z80scc_channel::do_sccreg_rr5()
|
||||
UINT8 z80scc_channel::do_sccreg_rr6()
|
||||
{
|
||||
LOGR(("%s\n", FUNCNAME));
|
||||
if (!(m_uart->m_variant & (SET_NMOS)))
|
||||
if (m_wr15 & WR15_STATUS_FIFO)
|
||||
{
|
||||
logerror(" %s() not implemented feature\n", FUNCNAME);
|
||||
logerror(" - Status FIFO for synchronous mode - not implemented\n");
|
||||
return 0;
|
||||
}
|
||||
return m_rr2;
|
||||
return m_rr2; /* Note that NMOS calls are redirected to do_sccreg_rr2() before getting here */
|
||||
}
|
||||
|
||||
/* (not on NMOS)
|
||||
@ -1731,6 +1754,7 @@ void z80scc_channel::do_sccreg_wr5(UINT8 data)
|
||||
}
|
||||
else
|
||||
{
|
||||
// UINT8 old_wr5 = m_wr5;
|
||||
m_wr5 = data;
|
||||
LOG(("- Transmitter Enable %u\n", (data & WR5_TX_ENABLE) ? 1 : 0));
|
||||
LOG(("- Transmitter Bits/Character %u\n", get_tx_word_length()));
|
||||
@ -1740,6 +1764,10 @@ void z80scc_channel::do_sccreg_wr5(UINT8 data)
|
||||
update_serial();
|
||||
safe_transmit_register_reset();
|
||||
update_rts();
|
||||
#if 0
|
||||
if ( !(old_wr5 & WR5_TX_ENABLE) && m_wr5 & WR5_TX_ENABLE )
|
||||
write_data(m_tx_data);
|
||||
#endif
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY;
|
||||
}
|
||||
}
|
||||
@ -1759,7 +1787,7 @@ void z80scc_channel::do_sccreg_wr7(UINT8 data)
|
||||
/* WR8 is the transmit buffer register */
|
||||
void z80scc_channel::do_sccreg_wr8(UINT8 data)
|
||||
{
|
||||
LOG(("%s(%02x) \"%s\": %c : Transmit Buffer read %02x\n", FUNCNAME, data, m_owner->tag(), 'A' + m_index, data));
|
||||
LOG(("%s(%02x) \"%s\": %c : Transmit Buffer write %02x\n", FUNCNAME, data, m_owner->tag(), 'A' + m_index, data));
|
||||
data_write(data);
|
||||
}
|
||||
|
||||
@ -2133,7 +2161,7 @@ UINT8 z80scc_channel::data_read()
|
||||
data = m_rx_fifo_rp_data();
|
||||
|
||||
// load error status from the FIFO
|
||||
m_rr1 = (m_rr1 & ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR)) | m_rx_error_fifo[m_rx_fifo_rp];
|
||||
m_rr1 = (m_rr1 & ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR)) | m_rx_error_fifo[m_rx_fifo_rp]; // TODO: Status FIFO needs to be fixed
|
||||
|
||||
// trigger interrup and lock the fifo if an error is present
|
||||
if (m_rr1 & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR))
|
||||
@ -2191,7 +2219,7 @@ void z80scc_channel::m_rx_fifo_rp_step()
|
||||
m_rx_fifo_rp = 0;
|
||||
}
|
||||
|
||||
// check if FIFO is empty
|
||||
// check if RX FIFO is empty
|
||||
if (m_rx_fifo_rp == m_rx_fifo_wp)
|
||||
{
|
||||
// no more characters available in the FIFO
|
||||
@ -2199,6 +2227,16 @@ void z80scc_channel::m_rx_fifo_rp_step()
|
||||
}
|
||||
}
|
||||
|
||||
/* Step TX read pointer */
|
||||
void z80scc_channel::m_tx_fifo_rp_step()
|
||||
{
|
||||
m_tx_fifo_rp++;
|
||||
if (m_tx_fifo_rp >= m_tx_fifo_sz)
|
||||
{
|
||||
m_tx_fifo_rp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
READ8_MEMBER (z80scc_device::da_r) { return m_chanA->data_read(); }
|
||||
WRITE8_MEMBER (z80scc_device::da_w) { m_chanA->data_write(data); }
|
||||
READ8_MEMBER (z80scc_device::db_r) { return m_chanB->data_read(); }
|
||||
@ -2209,28 +2247,65 @@ WRITE8_MEMBER (z80scc_device::db_w) { m_chanB->data_write(data); }
|
||||
//-------------------------------------------------
|
||||
void z80scc_channel::data_write(UINT8 data)
|
||||
{
|
||||
m_tx_data = data;
|
||||
|
||||
if ((m_wr5 & WR5_TX_ENABLE) && is_transmit_register_empty())
|
||||
/* Tx FIFO is full or...? */
|
||||
if ( !(m_rr0 & RR0_TX_BUFFER_EMPTY) && // NMOS/CMOS 1 slot "FIFO" is controlled by the TBE bit instead of fifo logic
|
||||
( (m_tx_fifo_wp + 1 == m_tx_fifo_rp) || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) )))
|
||||
{
|
||||
LOG(("%s(%02x) \"%s\": %c : Transmit Data Byte '%02x' %c\n", FUNCNAME, data, m_owner->tag(), 'A' + m_index, m_tx_data, m_tx_data));
|
||||
transmit_register_setup(m_tx_data);
|
||||
|
||||
// empty transmit buffer
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY;
|
||||
|
||||
if (m_wr1 & WR1_TX_INT_ENABLE)
|
||||
logerror("- TX FIFO is full, discarding data\n");
|
||||
LOG(("- TX FIFO is full, discarding data\n"));
|
||||
}
|
||||
else // ..there is still room
|
||||
{
|
||||
m_tx_data_fifo[m_tx_fifo_wp++] = data;
|
||||
if (m_tx_fifo_wp >= m_tx_fifo_sz)
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT);
|
||||
m_tx_fifo_wp = 0;
|
||||
}
|
||||
|
||||
// Check FIFO fullness and set TBE bit accordingly
|
||||
if (m_tx_fifo_sz == 1)
|
||||
{
|
||||
m_rr0 &= ~RR0_TX_BUFFER_EMPTY; // If only one FIFO position it is full now!
|
||||
}
|
||||
else if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) ))
|
||||
{
|
||||
m_rr0 &= ~RR0_TX_BUFFER_EMPTY; // Indicate that the TX fifo is full
|
||||
}else
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY; // or there is a slot in the FIFO available
|
||||
|
||||
m_rr1 &= ~RR1_ALL_SENT; // All is definitelly not sent anymore
|
||||
}
|
||||
|
||||
/* Transmitter enabled? */
|
||||
if (m_wr5 & WR5_TX_ENABLE)
|
||||
{
|
||||
if (is_transmit_register_empty()) // Is the shift register loaded?
|
||||
{
|
||||
LOG(("- Setting up transmitter\n"));
|
||||
transmit_register_setup(m_tx_data_fifo[m_tx_fifo_rp]); // Load the shift register, reload is done in tra_complete()
|
||||
m_tx_fifo_rp_step();
|
||||
m_rr1 |= RR1_ALL_SENT; // Now stuff is on its way again
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY; // And there is a slot in the FIFO available
|
||||
}
|
||||
}
|
||||
else
|
||||
/* "While transmit interrupts are enabled, the nmos/cmos version sets the transmit interrupt pending
|
||||
(TxIP) bit whenever the transmit buffer becomes empty. this means that the transmit buffer
|
||||
must be full before the TxIP can be set. thus, when transmit interrupts are first enabled, the TxIP
|
||||
will not be set until after the first character is written to the nmos/cmos." */
|
||||
// check if to fire interrupt
|
||||
if (m_wr1 & WR1_TX_INT_ENABLE)
|
||||
{
|
||||
m_rr0 &= ~RR0_TX_BUFFER_EMPTY;
|
||||
//LOG(("%s(%02x) \"%s\": %c : failed to send %c,(%02x)\n", FUNCNAME, data, m_owner->tag(), 'A' + m_index, isascii(data) ? data : ' ', data));
|
||||
if ((m_uart->m_variant & SET_ESCC) &&
|
||||
(m_wr7p & WR7P_TX_FIFO_EMPTY) &&
|
||||
m_tx_fifo_wp == m_tx_fifo_rp) // ESCC and fifo empty bit set and fifo is completelly empty?
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT); // Set TXIP bit
|
||||
}
|
||||
else if(m_rr0 & RR0_TX_BUFFER_EMPTY) // Check TBE bit and interrupt if one or more FIFO slots availble
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT); // Set TXIP bit
|
||||
}
|
||||
}
|
||||
|
||||
m_rr1 &= ~RR1_ALL_SENT;
|
||||
}
|
||||
|
||||
|
||||
@ -2245,12 +2320,12 @@ void z80scc_channel::receive_data(UINT8 data)
|
||||
if (m_rx_fifo_wp + 1 == m_rx_fifo_rp || ( (m_rx_fifo_wp + 1 == m_rx_fifo_sz) && (m_rx_fifo_rp == 0) ))
|
||||
{
|
||||
// receive overrun error detected
|
||||
m_rx_error_fifo[m_rx_fifo_wp] |= RR1_RX_OVERRUN_ERROR; // = m_rx_error;
|
||||
m_rx_error_fifo[m_rx_fifo_wp] |= RR1_RX_OVERRUN_ERROR; // = m_rx_error; TODO: Status FIFO needs to be fixed
|
||||
logerror("Receive_data() Error %02x\n", m_rx_error_fifo[m_rx_fifo_wp] & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rx_error_fifo[m_rx_fifo_wp] &= ~RR1_RX_OVERRUN_ERROR; // = m_rx_error;
|
||||
m_rx_error_fifo[m_rx_fifo_wp] &= ~RR1_RX_OVERRUN_ERROR; // = m_rx_error; TODO: Status FIFO needs to be fixed
|
||||
m_rx_fifo_wp++;
|
||||
if (m_rx_fifo_wp >= m_rx_fifo_sz)
|
||||
{
|
||||
|
@ -206,6 +206,7 @@ public:
|
||||
void data_write(UINT8 data);
|
||||
|
||||
void receive_data(UINT8 data);
|
||||
void m_tx_fifo_rp_step();
|
||||
void m_rx_fifo_rp_step();
|
||||
UINT8 m_rx_fifo_rp_data();
|
||||
|
||||
@ -230,7 +231,7 @@ public:
|
||||
UINT8 m_rr5; // REG_RR5_WR5_OR_RR0
|
||||
UINT8 m_rr6; // REG_RR6_LSB_OR_RR2
|
||||
UINT8 m_rr7; // REG_RR7_MSB_OR_RR3
|
||||
UINT8 m_rr7p;
|
||||
UINT8 m_rr7p;
|
||||
UINT8 m_rr8; // REG_RR8_RECEIVE_DATA
|
||||
UINT8 m_rr9; // REG_RR9_WR3_OR_RR13
|
||||
UINT8 m_rr10; // REG_RR10_MISC_STATUS
|
||||
@ -458,7 +459,12 @@ protected:
|
||||
WR5_DTR = 0x80
|
||||
};
|
||||
|
||||
/* SCC specifics */
|
||||
|
||||
enum
|
||||
{
|
||||
WR7P_TX_FIFO_EMPTY = 0x04
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR9_CMD_MASK = 0xC0,
|
||||
@ -575,7 +581,13 @@ protected:
|
||||
int m_dcd; // data carrier detect latch
|
||||
|
||||
// transmitter state
|
||||
UINT8 m_tx_data; // transmit data register
|
||||
UINT8 m_tx_data_fifo[4]; // data FIFO
|
||||
UINT8 m_tx_error_fifo[4]; // error FIFO
|
||||
int m_tx_fifo_rp; // FIFO read pointer
|
||||
int m_tx_fifo_wp; // FIFO write pointer
|
||||
int m_tx_fifo_sz; // FIFO size
|
||||
UINT8 m_tx_error; // current error
|
||||
// UINT8 m_tx_data; // transmit data register
|
||||
int m_tx_clock; // transmit clock pulse count
|
||||
|
||||
int m_dtr; // data terminal ready
|
||||
|
Loading…
Reference in New Issue
Block a user