z80scc: basic wait/dma request support (#2441)

* improved initiator transfer information logic
* split transfer count/counter
* added rudimentary 53c90a/53c94 support
* reworked initiator transfer information state machine: should now support all scsi phases
* improved handling of dma/non-dma commands
* added an undocumented hack to make InterPro work
* match updated 5390 device
* inherit memory map
* z80scc: basic wait/dma request implementation
* z80scc: renamed WRDY to WREQ to match datasheet, minor touch-up
This commit is contained in:
Patrick Mackinlay 2017-07-06 14:00:31 +07:00 committed by Vas Crabb
parent af30346e3e
commit 33b04cec42
2 changed files with 54 additions and 18 deletions

View File

@ -174,12 +174,12 @@ z80scc_device::z80scc_device(const machine_config &mconfig, device_type type, co
m_out_txda_cb(*this), m_out_txda_cb(*this),
m_out_dtra_cb(*this), m_out_dtra_cb(*this),
m_out_rtsa_cb(*this), m_out_rtsa_cb(*this),
m_out_wrdya_cb(*this), m_out_wreqa_cb(*this),
m_out_synca_cb(*this), m_out_synca_cb(*this),
m_out_txdb_cb(*this), m_out_txdb_cb(*this),
m_out_dtrb_cb(*this), m_out_dtrb_cb(*this),
m_out_rtsb_cb(*this), m_out_rtsb_cb(*this),
m_out_wrdyb_cb(*this), m_out_wreqb_cb(*this),
m_out_syncb_cb(*this), m_out_syncb_cb(*this),
m_out_int_cb(*this), m_out_int_cb(*this),
m_out_rxdrqa_cb(*this), m_out_rxdrqa_cb(*this),
@ -249,12 +249,12 @@ void z80scc_device::device_start()
m_out_txda_cb.resolve_safe(); m_out_txda_cb.resolve_safe();
m_out_dtra_cb.resolve_safe(); m_out_dtra_cb.resolve_safe();
m_out_rtsa_cb.resolve_safe(); m_out_rtsa_cb.resolve_safe();
m_out_wrdya_cb.resolve_safe(); m_out_wreqa_cb.resolve_safe();
m_out_synca_cb.resolve_safe(); m_out_synca_cb.resolve_safe();
m_out_txdb_cb.resolve_safe(); m_out_txdb_cb.resolve_safe();
m_out_dtrb_cb.resolve_safe(); m_out_dtrb_cb.resolve_safe();
m_out_rtsb_cb.resolve_safe(); m_out_rtsb_cb.resolve_safe();
m_out_wrdyb_cb.resolve_safe(); m_out_wreqb_cb.resolve_safe();
m_out_syncb_cb.resolve_safe(); m_out_syncb_cb.resolve_safe();
m_out_int_cb.resolve_safe(); m_out_int_cb.resolve_safe();
m_out_rxdrqa_cb.resolve_safe(); m_out_rxdrqa_cb.resolve_safe();
@ -1136,6 +1136,8 @@ void z80scc_channel::tra_complete()
set_rts(1); set_rts(1);
} }
check_waitrequest();
if (m_wr1 & WR1_TX_INT_ENABLE && m_tx_int_disarm == 0) if (m_wr1 & WR1_TX_INT_ENABLE && m_tx_int_disarm == 0)
{ {
if ((m_uart->m_variant & z80scc_device::SET_ESCC) && if ((m_uart->m_variant & z80scc_device::SET_ESCC) &&
@ -1790,9 +1792,11 @@ void z80scc_channel::do_sccreg_wr1(uint8_t data)
LOG("- External Interrupt Enable %u\n", (data & WR1_EXT_INT_ENABLE) ? 1 : 0); LOG("- External Interrupt Enable %u\n", (data & WR1_EXT_INT_ENABLE) ? 1 : 0);
LOG("- Transmit Interrupt Enable %u\n", (data & WR1_TX_INT_ENABLE) ? 1 : 0); LOG("- Transmit Interrupt Enable %u\n", (data & WR1_TX_INT_ENABLE) ? 1 : 0);
LOG("- Parity is special condition %u\n", (data & WR1_PARITY_IS_SPEC_COND) ? 1 : 0); LOG("- Parity is special condition %u\n", (data & WR1_PARITY_IS_SPEC_COND) ? 1 : 0);
LOG("- Wait/Ready Enable %u\n", (data & WR1_WRDY_ENABLE) ? 1 : 0); LOG("- Wait/DMA Request Enable %u\n", (data & WR1_WREQ_ENABLE) ? 1 : 0);
LOG("- Wait/Ready Function %s\n", (data & WR1_WRDY_FUNCTION) ? "Ready" : "Wait"); LOG("- Wait/DMA Request Function %s\n", (data & WR1_WREQ_FUNCTION) ? "Request" : "Wait");
LOG("- Wait/Ready on %s\n", (data & WR1_WRDY_ON_RX_TX) ? "Receive" : "Transmit"); LOG("- Wait/DMA Request on %s\n", (data & WR1_WREQ_ON_RX_TX) ? "Receive" : "Transmit");
check_waitrequest();
switch (data & WR1_RX_INT_MODE_MASK) switch (data & WR1_RX_INT_MODE_MASK)
{ {
@ -2410,6 +2414,8 @@ void z80scc_channel::data_write(uint8_t data)
m_rr1 &= ~RR1_ALL_SENT; // All is definitelly not sent anymore m_rr1 &= ~RR1_ALL_SENT; // All is definitelly not sent anymore
} }
check_waitrequest();
/* Transmitter enabled? */ /* Transmitter enabled? */
if (m_wr5 & WR5_TX_ENABLE) if (m_wr5 & WR5_TX_ENABLE)
{ {
@ -2857,3 +2863,32 @@ WRITE_LINE_MEMBER(z80scc_channel::write_rx)
if(m_rxc != 0 || m_brg_rate != 0) if(m_rxc != 0 || m_brg_rate != 0)
device_serial_interface::rx_w(state); device_serial_interface::rx_w(state);
} }
/*
* This is a partial implementation of the "wait/dma request" functionality of the SCC controlled by
* bits D7, D6 and D5 in WR1. This implementation is sufficient to support DMA request on transmit
* used by the InterPro driver.
*
* TODO:
* - wait function (D6=0)
* - wait/request function on receive (D5=1)
*/
void z80scc_channel::check_waitrequest()
{
// don't do anything if wait/request function is not enabled
if ((m_wr1 & WR1_WREQ_ENABLE) == 0)
return;
// wait/request function for receive not implemented
if (m_wr1 & WR1_WREQ_ON_RX_TX)
return;
// if dma request function is enabled
if (m_wr1 & WR1_WREQ_FUNCTION)
{
// assert /W//REQ if transmit buffer is empty, clear if it's not
int state = (m_rr0 & RR0_TX_BUFFER_EMPTY) ? ASSERT_LINE : CLEAR_LINE;
(m_index ? m_uart->m_out_wreqb_cb : m_uart->m_out_wreqa_cb)(state);
}
}

View File

@ -98,8 +98,8 @@
#define MCFG_Z80SCC_OUT_RTSA_CB(_devcb) \ #define MCFG_Z80SCC_OUT_RTSA_CB(_devcb) \
devcb = &z80scc_device::set_out_rtsa_callback(*device, DEVCB_##_devcb); devcb = &z80scc_device::set_out_rtsa_callback(*device, DEVCB_##_devcb);
#define MCFG_Z80SCC_OUT_WRDYA_CB(_devcb) \ #define MCFG_Z80SCC_OUT_WREQA_CB(_devcb) \
devcb = &z80scc_device::set_out_wrdya_callback(*device, DEVCB_##_devcb); devcb = &z80scc_device::set_out_wreqa_callback(*device, DEVCB_##_devcb);
#define MCFG_Z80SCC_OUT_SYNCA_CB(_devcb) \ #define MCFG_Z80SCC_OUT_SYNCA_CB(_devcb) \
devcb = &z80scc_device::set_out_synca_callback(*device, DEVCB_##_devcb); devcb = &z80scc_device::set_out_synca_callback(*device, DEVCB_##_devcb);
@ -120,8 +120,8 @@
#define MCFG_Z80SCC_OUT_RTSB_CB(_devcb) \ #define MCFG_Z80SCC_OUT_RTSB_CB(_devcb) \
devcb = &z80scc_device::set_out_rtsb_callback(*device, DEVCB_##_devcb); devcb = &z80scc_device::set_out_rtsb_callback(*device, DEVCB_##_devcb);
#define MCFG_Z80SCC_OUT_WRDYB_CB(_devcb) \ #define MCFG_Z80SCC_OUT_WREQB_CB(_devcb) \
devcb = &z80scc_device::set_out_wrdyb_callback(*device, DEVCB_##_devcb); devcb = &z80scc_device::set_out_wreqb_callback(*device, DEVCB_##_devcb);
#define MCFG_Z80SCC_OUT_SYNCB_CB(_devcb) \ #define MCFG_Z80SCC_OUT_SYNCB_CB(_devcb) \
devcb = &z80scc_device::set_out_syncb_callback(*device, DEVCB_##_devcb); devcb = &z80scc_device::set_out_syncb_callback(*device, DEVCB_##_devcb);
@ -412,9 +412,9 @@ protected:
WR1_RX_INT_FIRST = 0x08, WR1_RX_INT_FIRST = 0x08,
WR1_RX_INT_ALL = 0x10, WR1_RX_INT_ALL = 0x10,
WR1_RX_INT_PARITY = 0x18, WR1_RX_INT_PARITY = 0x18,
WR1_WRDY_ON_RX_TX = 0x20, WR1_WREQ_ON_RX_TX = 0x20,
WR1_WRDY_FUNCTION = 0x40, WR1_WREQ_FUNCTION = 0x40,
WR1_WRDY_ENABLE = 0x80 WR1_WREQ_ENABLE = 0x80
}; };
enum enum
@ -587,6 +587,7 @@ protected:
int get_rx_word_length(); int get_rx_word_length();
int get_tx_word_length(); int get_tx_word_length();
void safe_transmit_register_reset(); void safe_transmit_register_reset();
void check_waitrequest();
// receiver state // receiver state
uint8_t m_rx_data_fifo[8]; // receive data FIFO uint8_t m_rx_data_fifo[8]; // receive data FIFO
@ -647,12 +648,12 @@ public:
template <class Object> static devcb_base &set_out_txda_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_txda_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_txda_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_txda_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_dtra_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_dtra_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_dtra_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_dtra_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_rtsa_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_rtsa_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_rtsa_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_rtsa_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_wrdya_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_wrdya_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_wreqa_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_wreqa_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_synca_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_synca_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_synca_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_synca_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_txdb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_txdb_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_txdb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_txdb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_dtrb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_dtrb_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_dtrb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_dtrb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_rtsb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_rtsb_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_rtsb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_rtsb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_wrdyb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_wrdyb_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_wreqb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_wreqb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_syncb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_syncb_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_syncb_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_syncb_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_int_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_int_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_int_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_int_cb.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_out_rxdrqa_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_rxdrqa_cb.set_callback(std::forward<Object>(cb)); } template <class Object> static devcb_base &set_out_rxdrqa_callback(device_t &device, Object &&cb) { return downcast<z80scc_device &>(device).m_out_rxdrqa_cb.set_callback(std::forward<Object>(cb)); }
@ -777,13 +778,13 @@ protected:
devcb_write_line m_out_txda_cb; devcb_write_line m_out_txda_cb;
devcb_write_line m_out_dtra_cb; devcb_write_line m_out_dtra_cb;
devcb_write_line m_out_rtsa_cb; devcb_write_line m_out_rtsa_cb;
devcb_write_line m_out_wrdya_cb; devcb_write_line m_out_wreqa_cb;
devcb_write_line m_out_synca_cb; devcb_write_line m_out_synca_cb;
devcb_write_line m_out_txdb_cb; devcb_write_line m_out_txdb_cb;
devcb_write_line m_out_dtrb_cb; devcb_write_line m_out_dtrb_cb;
devcb_write_line m_out_rtsb_cb; devcb_write_line m_out_rtsb_cb;
devcb_write_line m_out_wrdyb_cb; devcb_write_line m_out_wreqb_cb;
devcb_write_line m_out_syncb_cb; devcb_write_line m_out_syncb_cb;
devcb_write_line m_out_int_cb; devcb_write_line m_out_int_cb;