From 9b768a075db100a5abc2eb52a9c82b54cbd94a6f Mon Sep 17 00:00:00 2001 From: shattered Date: Tue, 15 Feb 2022 21:06:00 +0000 Subject: scnxx562: minor changes to interrupt handling (#9304) --- src/devices/machine/scnxx562.cpp | 45 +++++++++++++++++++++++++++++++++------- src/devices/machine/scnxx562.h | 2 ++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/devices/machine/scnxx562.cpp b/src/devices/machine/scnxx562.cpp index aff96002ecc..1b936cc85e7 100644 --- a/src/devices/machine/scnxx562.cpp +++ b/src/devices/machine/scnxx562.cpp @@ -472,6 +472,35 @@ uint8_t duscc_device::modify_vector(uint8_t vec, int index, uint8_t src) 7. General status register (GSR) */ +int duscc_device::interrupt_priority(int index, int state) +{ + int priority_level = 0; + + switch (m_icr & REG_ICR_PRIO_MASK) + { + case REG_ICR_PRIO_AHI: priority_level = state + (index == CHANNEL_A ? 0 : 4); break; + case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break; + case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break; + case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break; + default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen + } + + return priority_level; +} + +void duscc_device::clear_interrupt(int index, int state) +{ + LOGINT("%s:%c %02x\n", FUNCNAME, 'A' + index, state); + + m_int_state[interrupt_priority(index, state)] &= ~Z80_DAISY_INT; + if ((m_icr & (index == CHANNEL_A ? REG_ICR_CHA : REG_ICR_CHB)) == 0) + { + LOGINT("The Interrupt Control Register [%02x] bit for this channel is not set, blocking attempt to interrupt\n", m_icr); + return; + } + check_interrupts(); +} + //----------------------------------------------------------------------- // trigger_interrupt - called when a potential interrupt condition occurs and will only issue an interrupt if the DUSCC is // programmed to do so. @@ -493,14 +522,7 @@ void duscc_device::trigger_interrupt(int index, int state) } // Modify priority level - switch (m_icr & REG_ICR_PRIO_MASK) - { - case REG_ICR_PRIO_AHI: priority_level = state + (index == CHANNEL_A ? 0 : 4); break; - case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break; - case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break; - case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break; - default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen - } + priority_level = interrupt_priority(index, state); // Vector modification requested? source = state + (index == CHANNEL_A ? 0 : 4); // bit in interrupt queue register of a certain priotiry level @@ -1955,6 +1977,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data) m_tx_fifo_wp = m_tx_fifo_rp = 0; m_trsr &= 0x0f; m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + m_uart->clear_interrupt(m_index, INT_TXREADY); break; /* Enable transmitter. Enables transmitter operation, conditioned by the state of @@ -1975,6 +1998,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data) set_tra_rate(0); m_tra = 0; m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + m_uart->clear_interrupt(m_index, INT_TXREADY); break; // RECEIVER COMMANDS @@ -1989,6 +2013,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data) m_trsr &= 0xf0; m_rsr = 0; m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + m_uart->clear_interrupt(m_index, INT_RXREADY); break; /* Enable receiver. Causes receiver operation to begin, conditioned by the state of the DCD @@ -2004,6 +2029,7 @@ void duscc_channel::do_dusccreg_ccr_w(uint8_t data) case REG_CCR_DISABLE_RX: LOGINT("- Disable Rx\n"); m_rcv = 0; m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + m_uart->clear_interrupt(m_index, INT_RXREADY); break; // COUNTER/TIMER COMMANDS @@ -2070,6 +2096,7 @@ void duscc_channel::do_dusccreg_txfifo_w(uint8_t data) if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) )) { m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + m_uart->clear_interrupt(m_index, INT_TXREADY); } else { @@ -2337,6 +2364,7 @@ void duscc_channel::m_rx_fifo_rp_step() // no more characters available in the FIFO LOGINT("Clear RXRDY in GSR because FIFO is emptied\n"); m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + m_uart->clear_interrupt(m_index, INT_RXREADY); } } @@ -2418,6 +2446,7 @@ void duscc_channel::cts_w(int state) if (m_tpr & REG_TPR_CTS && m_tra) { m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + m_uart->trigger_interrupt(m_index, INT_TXREADY); } // set clear to send diff --git a/src/devices/machine/scnxx562.h b/src/devices/machine/scnxx562.h index ea623140966..9df50f0d16e 100644 --- a/src/devices/machine/scnxx562.h +++ b/src/devices/machine/scnxx562.h @@ -602,7 +602,9 @@ protected: void check_interrupts(); void reset_interrupts(); uint8_t modify_vector(uint8_t vect, int i, uint8_t src); + int interrupt_priority(int index, int state); void trigger_interrupt(int index, int state); + void clear_interrupt(int index, int state); int get_channel_index(duscc_channel *ch) const { return (ch == m_chanA) ? 0 : 1; } // Variants in the DUSCC family -- cgit v1.2.3