mirror of
https://github.com/holub/mame
synced 2025-06-01 10:31:48 +03:00
ins8250: Detect framing and parity errors; allow side effects of reads to be disabled
This commit is contained in:
parent
a67dd2df3c
commit
7b8ae74be1
@ -97,6 +97,8 @@ History:
|
||||
#include "emu.h"
|
||||
#include "machine/ins8250.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
//#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);
|
||||
|
@ -20,12 +20,6 @@
|
||||
class ins8250_uart_device : public device_t, public device_serial_interface
|
||||
{
|
||||
public:
|
||||
template <class Object> devcb_base &set_out_tx_callback(Object &&cb) { return m_out_tx_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out_dtr_callback(Object &&cb) { return m_out_dtr_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out_rts_callback(Object &&cb) { return m_out_rts_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out_int_callback(Object &&cb) { return m_out_int_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out_out1_callback(Object &&cb) { return m_out_out1_cb.set_callback(std::forward<Object>(cb)); }
|
||||
template <class Object> devcb_base &set_out_out2_callback(Object &&cb) { return m_out_out2_cb.set_callback(std::forward<Object>(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;
|
||||
|
Loading…
Reference in New Issue
Block a user