From f1d04774893a0b1095176ce0e343b9a688501ea6 Mon Sep 17 00:00:00 2001 From: smf- Date: Wed, 17 Sep 2014 13:58:02 +0000 Subject: [PATCH] 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). --- src/emu/bus/rs232/rs232.c | 16 ++-- src/emu/bus/rs232/ser_mouse.c | 50 +++++++----- src/emu/bus/rs232/ser_mouse.h | 28 +++---- src/emu/machine/ins8250.c | 140 ++++++++++++++++++++-------------- src/emu/machine/ins8250.h | 11 ++- 5 files changed, 143 insertions(+), 102 deletions(-) diff --git a/src/emu/bus/rs232/rs232.c b/src/emu/bus/rs232/rs232.c index 26a0a4ecdd8..24862b22a92 100644 --- a/src/emu/bus/rs232/rs232.c +++ b/src/emu/bus/rs232/rs232.c @@ -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 ) diff --git a/src/emu/bus/rs232/ser_mouse.c b/src/emu/bus/rs232/ser_mouse.c index f942cc2592f..823cf732607 100644 --- a/src/emu/bus/rs232/ser_mouse.c +++ b/src/emu/bus/rs232/ser_mouse.c @@ -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(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); } diff --git a/src/emu/bus/rs232/ser_mouse.h b/src/emu/bus/rs232/ser_mouse.h index fbcbccc6645..02ca3cbe715 100644 --- a/src/emu/bus/rs232/ser_mouse.h +++ b/src/emu/bus/rs232/ser_mouse.h @@ -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; diff --git a/src/emu/machine/ins8250.c b/src/emu/machine/ins8250.c index 8c7b4b90982..fcb9647bd03 100644 --- a/src/emu/machine/ins8250.c +++ b/src/emu/machine/ins8250.c @@ -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<> 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) diff --git a/src/emu/machine/ins8250.h b/src/emu/machine/ins8250.h index cc32242d60c..132d55e258e 100644 --- a/src/emu/machine/ins8250.h +++ b/src/emu/machine/ins8250.h @@ -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