diff --git a/src/devices/machine/ins8250.cpp b/src/devices/machine/ins8250.cpp index e6f44db4c59..88262cdbac2 100644 --- a/src/devices/machine/ins8250.cpp +++ b/src/devices/machine/ins8250.cpp @@ -97,6 +97,8 @@ History: #include "emu.h" #include "machine/ins8250.h" +#include + //#define VERBOSE 1 #include "logmacro.h" @@ -159,9 +161,9 @@ void pc16552_device::device_start() static constexpr uint8_t INS8250_LSR_TSRE = 0x40; static constexpr uint8_t INS8250_LSR_THRE = 0x20; -//static constexpr uint8_t INS8250_LSR_BI = 0x10; -//static constexpr uint8_t INS8250_LSR_FE = 0x08; -//static constexpr uint8_t INS8250_LSR_PE = 0x04; +static constexpr uint8_t INS8250_LSR_BI = 0x10; +static constexpr uint8_t INS8250_LSR_FE = 0x08; +static constexpr uint8_t INS8250_LSR_PE = 0x04; static constexpr uint8_t INS8250_LSR_OE = 0x02; static constexpr uint8_t INS8250_LSR_DR = 0x01; @@ -406,13 +408,16 @@ READ8_MEMBER( ins8250_uart_device::ins8250_r ) data = (m_regs.dl & 0xff); else { - if((m_device_type >= dev_type::NS16550) && (m_regs.fcr & 1)) - m_regs.rbr = pop_rx(); - else + if (!machine().side_effects_disabled()) { - clear_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); - if( m_regs.lsr & INS8250_LSR_DR ) - m_regs.lsr &= ~INS8250_LSR_DR; + if ((m_device_type >= dev_type::NS16550) && (m_regs.fcr & 1)) + m_regs.rbr = pop_rx(); + else + { + clear_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); + if (m_regs.lsr & INS8250_LSR_DR) + m_regs.lsr &= ~INS8250_LSR_DR; + } } data = m_regs.rbr; } @@ -427,7 +432,7 @@ READ8_MEMBER( ins8250_uart_device::ins8250_r ) data = m_regs.iir; /* The documentation says that reading this register will clear the int if this is the source of the int */ - if ( m_regs.ier & COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY ) + if (!machine().side_effects_disabled() && (m_regs.ier & COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY)) clear_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); break; case 3: @@ -438,19 +443,23 @@ READ8_MEMBER( ins8250_uart_device::ins8250_r ) break; case 5: data = m_regs.lsr; - if( m_regs.lsr & 0x1f ) + if (!machine().side_effects_disabled() && (m_regs.lsr & (INS8250_LSR_BI | INS8250_LSR_FE | INS8250_LSR_PE | INS8250_LSR_OE)) != 0) + { m_regs.lsr &= 0xe1; /* clear FE, PE and OE and BREAK bits */ - /* reading line status register clears int */ - clear_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + /* reading line status register clears int */ + clear_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + } break; case 6: data = m_regs.msr; - m_regs.msr &= 0xf0; /* reset delta values */ - - /* reading msr clears int */ - clear_int(COM_INT_PENDING_MODEM_STATUS_REGISTER); + if (!machine().side_effects_disabled()) + { + m_regs.msr &= 0xf0; /* reset delta values */ + /* reading msr clears int */ + clear_int(COM_INT_PENDING_MODEM_STATUS_REGISTER); + } break; case 7: data = m_regs.scr; @@ -473,8 +482,20 @@ void ns16550_device::rcv_complete() return; } + uint8_t errors = 0; + if (is_receive_framing_error()) + errors |= INS8250_LSR_FE; + if (is_receive_parity_error()) + errors |= INS8250_LSR_PE; + if (m_rnum == 0 && errors != 0) + { + m_regs.lsr |= errors; + trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + } + m_regs.lsr |= INS8250_LSR_DR; m_rfifo[m_rhead] = get_received_char(); + m_efifo[m_rhead] = errors; ++m_rhead &= 0x0f; m_rnum++; if(m_rnum >= m_rintlvl) @@ -514,6 +535,14 @@ void ins8250_uart_device::rcv_complete() { m_regs.lsr |= INS8250_LSR_DR; receive_register_extract(); + + if (is_receive_framing_error()) + m_regs.lsr |= INS8250_LSR_FE; + if (is_receive_parity_error()) + m_regs.lsr |= INS8250_LSR_PE; + if ((m_regs.lsr & (INS8250_LSR_BI | INS8250_LSR_PE | INS8250_LSR_FE)) != 0) + trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + m_regs.rbr = get_received_char(); trigger_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); } @@ -660,6 +689,7 @@ void ns16550_device::device_start() ins8250_uart_device::device_start(); save_item(NAME(m_rintlvl)); save_item(NAME(m_rfifo)); + save_item(NAME(m_efifo)); save_item(NAME(m_tfifo)); save_item(NAME(m_rhead)); save_item(NAME(m_rtail)); @@ -670,8 +700,9 @@ void ns16550_device::device_start() void ns16550_device::device_reset() { - memset(&m_rfifo, '\0', sizeof(m_rfifo)); - memset(&m_tfifo, '\0', sizeof(m_tfifo)); + std::fill(std::begin(m_rfifo), std::end(m_rfifo), 0); + std::fill(std::begin(m_efifo), std::end(m_efifo), 0); + std::fill(std::begin(m_tfifo), std::end(m_tfifo), 0); m_rhead = m_rtail = m_rnum = 0; m_thead = m_ttail = 0; m_timeout->adjust(attotime::never); @@ -702,6 +733,11 @@ uint8_t ns16550_device::pop_rx() { ++m_rtail &= 0x0f; m_rnum--; + if (m_rnum > 0 && m_efifo[m_rtail] != 0) + { + m_regs.lsr |= m_efifo[m_rtail]; + trigger_int(COM_INT_PENDING_RECEIVER_LINE_STATUS); + } } else data = 0; @@ -733,14 +769,15 @@ void ns16550_device::set_fcr(uint8_t data) data |= 0x06; if(data & 2) { - memset(&m_rfifo, '\0', sizeof(m_rfifo)); + std::fill(std::begin(m_rfifo), std::end(m_rfifo), 0); + std::fill(std::begin(m_efifo), std::end(m_efifo), 0); m_rhead = m_rtail = m_rnum = 0; clear_int(COM_INT_PENDING_CHAR_TIMEOUT | COM_INT_PENDING_RECEIVED_DATA_AVAILABLE); m_timeout->adjust(attotime::never); } if(data & 4) { - memset(&m_tfifo, '\0', sizeof(m_tfifo)); + std::fill(std::begin(m_tfifo), std::end(m_tfifo), 0); m_thead = m_ttail = 0; m_regs.lsr |= INS8250_LSR_THRE; trigger_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY); diff --git a/src/devices/machine/ins8250.h b/src/devices/machine/ins8250.h index 454f3ecd9a1..3047b8d6c05 100644 --- a/src/devices/machine/ins8250.h +++ b/src/devices/machine/ins8250.h @@ -20,12 +20,6 @@ class ins8250_uart_device : public device_t, public device_serial_interface { public: - template devcb_base &set_out_tx_callback(Object &&cb) { return m_out_tx_cb.set_callback(std::forward(cb)); } - template devcb_base &set_out_dtr_callback(Object &&cb) { return m_out_dtr_cb.set_callback(std::forward(cb)); } - template devcb_base &set_out_rts_callback(Object &&cb) { return m_out_rts_cb.set_callback(std::forward(cb)); } - template devcb_base &set_out_int_callback(Object &&cb) { return m_out_int_cb.set_callback(std::forward(cb)); } - template devcb_base &set_out_out1_callback(Object &&cb) { return m_out_out1_cb.set_callback(std::forward(cb)); } - template devcb_base &set_out_out2_callback(Object &&cb) { return m_out_out2_cb.set_callback(std::forward(cb)); } auto out_tx_callback() { return m_out_tx_cb.bind(); } auto out_dtr_callback() { return m_out_dtr_cb.bind(); } auto out_rts_callback() { return m_out_rts_cb.bind(); } @@ -133,6 +127,7 @@ private: void set_timer() { m_timeout->adjust(attotime::from_hz((clock()*4*8)/(m_regs.dl*16))); } int m_rintlvl; uint8_t m_rfifo[16]; + uint8_t m_efifo[16]; uint8_t m_tfifo[16]; int m_rhead, m_rtail, m_rnum; int m_thead, m_ttail;