NS8250 Fixes [smf]

Loopback: tx goes high and data is clocked at the correct rate instead of appearing instantly
Modem status register: don't lose track of external signals when starting, resetting, switching loopback off, writing to register
Handshaking: active low for consistency (RS232 port now defaults handshaking lines high and serial mouse dtr/rts handling has been adjusted).
This commit is contained in:
smf- 2014-09-17 13:58:02 +00:00
parent 13537ab5f1
commit f1d0477489
5 changed files with 143 additions and 102 deletions

View File

@ -50,16 +50,16 @@ void rs232_port_device::device_start()
save_item(NAME(m_cts));
m_rxd = 1;
m_dcd = 0;
m_dsr = 0;
m_ri = 0;
m_cts = 0;
m_dcd = 1;
m_dsr = 1;
m_ri = 1;
m_cts = 1;
m_rxd_handler(1);
m_dcd_handler(0);
m_dsr_handler(0);
m_ri_handler(0);
m_cts_handler(0);
m_dcd_handler(1);
m_dsr_handler(1);
m_ri_handler(1);
m_cts_handler(1);
}
WRITE_LINE_MEMBER( rs232_port_device::write_txd )

View File

@ -13,6 +13,8 @@ serial_mouse_device::serial_mouse_device(const machine_config &mconfig, device_t
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
device_rs232_port_interface(mconfig, *this),
device_serial_interface(mconfig, *this),
m_dtr(1),
m_rts(1),
m_x(*this, "ser_mouse_x"),
m_y(*this, "ser_mouse_y"),
m_btn(*this, "ser_mouse_btn")
@ -23,7 +25,6 @@ const device_type MSFT_SERIAL_MOUSE = &device_creator<microsoft_mouse_device>;
microsoft_mouse_device::microsoft_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: serial_mouse_device(mconfig, MSFT_SERIAL_MOUSE, "Microsoft Serial Mouse", tag, owner, clock, "microsoft_mouse", __FILE__)
, m_dtr(0)
{
}
@ -40,9 +41,18 @@ void serial_mouse_device::device_start()
m_enabled = false;
set_frame();
set_tra_rate(1200);
reset_mouse();
save_item(NAME(m_dtr));
save_item(NAME(m_rts));
save_item(NAME(m_queue));
save_item(NAME(m_head));
save_item(NAME(m_tail));
save_item(NAME(m_mb));
save_item(NAME(m_enabled));
}
void serial_mouse_device::device_reset()
void serial_mouse_device::reset_mouse()
{
m_head = m_tail = 0;
output_rxd(1);
@ -202,24 +212,30 @@ void serial_mouse_device::set_mouse_enable(bool state)
}
void microsoft_mouse_device::check_state()
WRITE_LINE_MEMBER(serial_mouse_device::input_dtr)
{
if (m_dtr && m_rts)
m_dtr = state;
check_state();
}
WRITE_LINE_MEMBER(serial_mouse_device::input_rts)
{
m_rts = state;
check_state();
}
WRITE_LINE_MEMBER(microsoft_mouse_device::input_rts)
{
if (!m_dtr && m_rts && !state)
{
/* RTS toggled */
if (!m_old_rts && m_rts)
{
/* reset mouse */
serial_mouse_device::device_reset();
/* Identify as Microsoft 3 Button Mouse */
queue_data('M');
queue_data('3');
}
/* start a timer to scan the mouse input */
set_mouse_enable(true);
reset_mouse();
/* Identify as Microsoft 3 Button Mouse */
queue_data('M');
queue_data('3');
}
else
set_mouse_enable(false);
serial_mouse_device::input_rts(state);
}

View File

@ -21,7 +21,6 @@ public:
protected:
virtual void device_start();
virtual void device_reset();
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
virtual void mouse_trans(int dx, int dy, int nb, int mbc) = 0;
virtual void set_frame() = 0;
@ -30,6 +29,13 @@ protected:
UINT8 unqueue_data() {UINT8 ret = m_queue[m_tail]; ++m_tail %= 256; return ret;}
virtual void tra_complete();
virtual void tra_callback();
void reset_mouse();
virtual WRITE_LINE_MEMBER(input_dtr);
virtual WRITE_LINE_MEMBER(input_rts);
int m_dtr;
int m_rts;
private:
UINT8 m_queue[256];
UINT8 m_head, m_tail, m_mb;
@ -40,25 +46,20 @@ private:
required_ioport m_x;
required_ioport m_y;
required_ioport m_btn;
void check_state() { set_mouse_enable(!m_dtr && !m_rts); }
};
class microsoft_mouse_device : public serial_mouse_device
{
public:
microsoft_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual DECLARE_WRITE_LINE_MEMBER( input_dtr ) { m_dtr = state; check_state(); }
virtual DECLARE_WRITE_LINE_MEMBER( input_rts ) { m_rts = state; check_state(); m_old_rts = state; }
protected:
virtual WRITE_LINE_MEMBER(input_rts);
virtual void set_frame() { set_data_frame(1, 7, PARITY_NONE, STOP_BITS_2); }
virtual void mouse_trans(int dx, int dy, int nb, int mbc);
virtual void device_reset() {m_old_rts = 0; serial_mouse_device::device_reset();}
private:
void check_state();
int m_dtr;
int m_rts;
int m_old_rts;
};
extern const device_type MSFT_SERIAL_MOUSE;
@ -67,17 +68,10 @@ class mouse_systems_mouse_device : public serial_mouse_device
{
public:
mouse_systems_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual DECLARE_WRITE_LINE_MEMBER( input_dtr ) { m_dtr = state; check_state(); }
virtual DECLARE_WRITE_LINE_MEMBER( input_rts ) { m_rts = state; check_state(); }
protected:
virtual void set_frame() { set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2); }
virtual void mouse_trans(int dx, int dy, int nb, int mbc);
private:
void check_state() { set_mouse_enable((m_dtr && m_rts)?true:false); }
int m_dtr;
int m_rts;
};
extern const device_type MSYSTEM_SERIAL_MOUSE;

View File

@ -97,7 +97,12 @@ ins8250_uart_device::ins8250_uart_device(const machine_config &mconfig, device_t
m_out_rts_cb(*this),
m_out_int_cb(*this),
m_out_out1_cb(*this),
m_out_out2_cb(*this)
m_out_out2_cb(*this),
m_rxd(1),
m_dcd(1),
m_dsr(1),
m_ri(1),
m_cts(1)
{
}
@ -212,20 +217,11 @@ WRITE8_MEMBER( ins8250_uart_device::ins8250_w )
{
m_regs.thr = data;
m_regs.lsr &= ~0x20;
if ( m_regs.mcr & 0x10 )
{
m_regs.lsr |= 0x61;
m_regs.rbr = data;
trigger_int(COM_INT_PENDING_RECEIVED_DATA_AVAILABLE);
}
else
{
if((m_device_type >= TYPE_NS16550) && (m_regs.fcr & 1))
push_tx(data);
clear_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY);
if(m_regs.lsr & 0x40)
tra_complete();
}
if((m_device_type >= TYPE_NS16550) && (m_regs.fcr & 1))
push_tx(data);
clear_int(COM_INT_PENDING_TRANSMITTER_HOLDING_REGISTER_EMPTY);
if(m_regs.lsr & 0x40)
tra_complete();
}
break;
case 1:
@ -289,25 +285,25 @@ WRITE8_MEMBER( ins8250_uart_device::ins8250_w )
{
m_regs.mcr = data & 0x1f;
if ( m_regs.mcr & 0x10 ) /* loopback test */
update_msr();
if (m_regs.mcr & 0x10) /* loopback test */
{
data = ( ( m_regs.mcr & 0x0c ) << 4 ) | ( ( m_regs.mcr & 0x01 ) << 5 ) | ( ( m_regs.mcr & 0x02 ) << 3 );
if ( ( m_regs.msr & 0x20 ) != ( data & 0x20 ) )
data |= 0x02;
if ( ( m_regs.msr & 0x10 ) != ( data & 0x10 ) )
data |= 0x01;
if ( ( m_regs.msr & 0x40 ) && ! ( data & 0x40 ) )
data |= 0x04;
if ( ( m_regs.msr & 0x80 ) != ( data & 0x80 ) )
data |= 0x08;
m_regs.msr = data;
m_out_tx_cb(1);
device_serial_interface::rx_w(m_txd);
m_out_dtr_cb(1);
m_out_rts_cb(1);
m_out_out1_cb(1);
m_out_out2_cb(1);
}
else
{
m_out_dtr_cb((m_regs.mcr & 1) ? 1 : 0);
m_out_rts_cb((m_regs.mcr & 2) ? 1 : 0);
m_out_out1_cb((m_regs.mcr & 4) ? 1 : 0);
m_out_out2_cb((m_regs.mcr & 8) ? 1 : 0);
m_out_tx_cb(m_txd);
device_serial_interface::rx_w(m_rxd);
m_out_dtr_cb((m_regs.mcr & 1) ? 0 : 1);
m_out_rts_cb((m_regs.mcr & 2) ? 0 : 1);
m_out_out1_cb((m_regs.mcr & 4) ? 0 : 1);
m_out_out2_cb((m_regs.mcr & 8) ? 0 : 1);
}
}
break;
@ -327,15 +323,7 @@ WRITE8_MEMBER( ins8250_uart_device::ins8250_w )
break;
case 6:
/*
This register can be written, but if you write a 1 bit into any of
bits 3 - 0, you could cause an interrupt if the appropriate IER bit
is set.
*/
m_regs.msr = data;
if ( m_regs.msr & 0x0f )
trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER);
// modem status register is read only
break;
case 7:
m_regs.scr = data;
@ -354,7 +342,7 @@ READ8_MEMBER( ins8250_uart_device::ins8250_r )
data = (m_regs.dl & 0xff);
else
{
if((m_device_type >= TYPE_NS16550) && (m_regs.fcr & 1) && !(m_regs.mcr & 0x10))
if((m_device_type >= TYPE_NS16550) && (m_regs.fcr & 1))
m_regs.rbr = pop_rx();
else
{
@ -482,37 +470,66 @@ void ins8250_uart_device::tra_complete()
void ins8250_uart_device::tra_callback()
{
m_out_tx_cb(transmit_register_get_data_bit());
m_txd = transmit_register_get_data_bit();
if (m_regs.mcr & 0x10)
{
device_serial_interface::rx_w(m_txd);
}
else
{
m_out_tx_cb(m_txd);
}
}
void ins8250_uart_device::update_msr(int bit, UINT8 state)
void ins8250_uart_device::update_msr()
{
UINT8 mask = (1<<bit);
if((m_regs.msr & mask) == (state<<bit))
return;
m_regs.msr |= mask;
m_regs.msr = (m_regs.msr & ~(mask << 4)) | (state<<(bit+4));
trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER);
UINT8 data;
if (m_regs.mcr & 0x10)
data = ((m_regs.mcr & 0x0c) << 4) | ((m_regs.mcr & 0x01) << 5) | ((m_regs.mcr & 0x02) << 3);
else
data = (!m_dcd << 7) | (!m_ri << 6) | (!m_dsr << 5) | (!m_cts << 4);
int change = (m_regs.msr ^ data) >> 4;
if (change)
{
m_regs.msr = data | (m_regs.msr & 0xf) | change;
trigger_int(COM_INT_PENDING_MODEM_STATUS_REGISTER);
}
}
WRITE_LINE_MEMBER(ins8250_uart_device::dcd_w)
{
update_msr(3, (state ? 1 : 0));
m_dcd = state;
update_msr();
}
WRITE_LINE_MEMBER(ins8250_uart_device::dsr_w)
{
update_msr(1, (state ? 1 : 0));
m_dsr = state;
update_msr();
}
WRITE_LINE_MEMBER(ins8250_uart_device::ri_w)
{
update_msr(2, (state ? 1 : 0));
m_ri = state;
update_msr();
}
WRITE_LINE_MEMBER(ins8250_uart_device::cts_w)
{
update_msr(0, (state ? 1 : 0));
m_cts = state;
update_msr();
}
WRITE_LINE_MEMBER(ins8250_uart_device::rx_w)
{
m_rxd = state;
if (!(m_regs.mcr & 0x10))
device_serial_interface::rx_w(m_rxd);
}
void ins8250_uart_device::device_start()
@ -525,7 +542,6 @@ void ins8250_uart_device::device_start()
m_out_out2_cb.resolve_safe();
set_tra_rate(0);
set_rcv_rate(0);
memset(&m_regs, 0x00, sizeof(m_regs));
device_serial_interface::register_save_state(machine().save(), name(), tag());
save_item(NAME(m_regs.thr));
@ -540,24 +556,32 @@ void ins8250_uart_device::device_start()
save_item(NAME(m_regs.msr));
save_item(NAME(m_regs.scr));
save_item(NAME(m_int_pending));
save_item(NAME(m_txd));
save_item(NAME(m_rxd));
save_item(NAME(m_dcd));
save_item(NAME(m_dsr));
save_item(NAME(m_ri));
save_item(NAME(m_cts));
}
void ins8250_uart_device::device_reset()
{
memset(&m_regs, 0x00, sizeof(m_regs));
m_regs.ier = 0;
m_regs.iir = 1;
m_regs.lcr = 0;
m_regs.mcr = 0;
m_regs.lsr = (1<<5) | (1<<6);
update_msr();
m_regs.msr &= 0xf0;
m_int_pending = 0;
receive_register_reset();
transmit_register_reset();
m_out_rts_cb(0);
m_out_dtr_cb(0);
m_out_out1_cb(0);
m_out_out2_cb(0);
m_txd = 1;
m_out_tx_cb(1);
m_out_rts_cb(1);
m_out_dtr_cb(1);
m_out_out1_cb(1);
m_out_out2_cb(1);
}
void ins8250_uart_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)

View File

@ -32,7 +32,7 @@ public:
DECLARE_WRITE_LINE_MEMBER( dsr_w );
DECLARE_WRITE_LINE_MEMBER( ri_w );
DECLARE_WRITE_LINE_MEMBER( cts_w );
DECLARE_WRITE_LINE_MEMBER( rx_w ) { device_serial_interface::rx_w(state); }
DECLARE_WRITE_LINE_MEMBER( rx_w );
protected:
virtual void device_start();
@ -81,7 +81,14 @@ private:
devcb_write_line m_out_out2_cb;
void update_interrupt();
void update_msr(int bit, UINT8 state);
void update_msr();
int m_txd;
int m_rxd;
int m_dcd;
int m_dsr;
int m_ri;
int m_cts;
};
class ins8250_device : public ins8250_uart_device