summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Miodrag Milanović <mmicko@gmail.com>2016-10-22 11:16:10 +0200
committer GitHub <noreply@github.com>2016-10-22 11:16:10 +0200
commit255bf78b316a9dc9e4c53a65143000471a6927d3 (patch)
tree5f58601975bcd1534c303d5634509590b630aac3
parenta44ecc354f6203ea589bac435563ce0642fba28b (diff)
parent4e5716fa5cf7a782224e5339640de579ed87a230 (diff)
Merge pull request #1541 from JoakimLarsson/scctxfifo
SCC improved Tx handling [Joakim Larsson]
-rw-r--r--src/devices/machine/z80scc.cpp177
-rw-r--r--src/devices/machine/z80scc.h18
2 files changed, 141 insertions, 54 deletions
diff --git a/src/devices/machine/z80scc.cpp b/src/devices/machine/z80scc.cpp
index 61c341d145c..251596f6fac 100644
--- a/src/devices/machine/z80scc.cpp
+++ b/src/devices/machine/z80scc.cpp
@@ -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))
- {
- 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));
- transmit_register_setup(m_tx_data);
+ if ((m_wr5 & WR5_TX_ENABLE) && !(m_wr5 & WR5_SEND_BREAK))
+ {
+ 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;
- // 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) )))
+ {
+ logerror("- TX FIFO is full, discarding data\n");
+ LOG(("- TX FIFO is full, discarding data\n"));
+ }
+ else // ..there is still room
{
- 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);
+ m_tx_data_fifo[m_tx_fifo_wp++] = data;
+ if (m_tx_fifo_wp >= m_tx_fifo_sz)
+ {
+ m_tx_fifo_wp = 0;
+ }
- // empty transmit buffer
- m_rr0 |= RR0_TX_BUFFER_EMPTY;
+ // 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
- if (m_wr1 & WR1_TX_INT_ENABLE)
+ 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?
{
- m_uart->trigger_interrupt(m_index, INT_TRANSMIT);
+ 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)
{
diff --git a/src/devices/machine/z80scc.h b/src/devices/machine/z80scc.h
index cccdc3be86d..69143eed02a 100644
--- a/src/devices/machine/z80scc.h
+++ b/src/devices/machine/z80scc.h
@@ -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