diff --git a/src/devices/machine/z80dma.cpp b/src/devices/machine/z80dma.cpp index e99f71e8c..78b35f89d 100644 --- a/src/devices/machine/z80dma.cpp +++ b/src/devices/machine/z80dma.cpp @@ -184,7 +184,7 @@ void z80dma_device::device_reset() m_timer->reset(); m_status = 0; - m_dma_seq = ~0; + m_dma_seq = SEQ_IDLE; m_rdy = 0; m_force_ready = 0; m_wait = 0; @@ -298,6 +298,8 @@ void z80dma_device::disable() { set_busrq(CLEAR_LINE); } + m_dma_seq = SEQ_IDLE; + LOGDMA("IDLE\n"); } void z80dma_device::update_bao() @@ -607,6 +609,7 @@ TIMER_CALLBACK_MEMBER(z80dma_device::clock_w) } break; + case SEQ_IDLE: default: break; } @@ -919,6 +922,9 @@ void z80dma_device::bai_w(int state) { m_busrq_ack = state; update_bao(); + + if (m_busrq_ack && m_dma_seq == SEQ_IDLE) + set_busrq(CLEAR_LINE); } diff --git a/src/devices/machine/z80dma.h b/src/devices/machine/z80dma.h index 657cc6f36..cf3eca50d 100644 --- a/src/devices/machine/z80dma.h +++ b/src/devices/machine/z80dma.h @@ -93,7 +93,8 @@ protected: enum { - SEQ_WAIT_READY = 0, + SEQ_IDLE = 0, + SEQ_WAIT_READY, SEQ_REQUEST_BUS, SEQ_WAITING_ACK, SEQ_TRANS1_INC_DEC_SOURCE_ADDRESS, diff --git a/src/mame/sinclair/next/specnext.cpp b/src/mame/sinclair/next/specnext.cpp index a4073eaef..b3cf0d7fb 100644 --- a/src/mame/sinclair/next/specnext.cpp +++ b/src/mame/sinclair/next/specnext.cpp @@ -1523,6 +1523,8 @@ void specnext_state::update_dma_delay() const u16 dma_int_mask = (m_nr_cc_dma_int_en_0_7 << INT_PRIORITY_NMI) | ((m_nr_cc_dma_int_en_0_10 & 1) << INT_PRIORITY_ULA) | (m_nr_cd_dma_int_en_1 << INT_PRIORITY_CTC) | ((m_nr_cc_dma_int_en_0_10 >> 1) << INT_PRIORITY_LINE); m_dma->dma_delay_w((m_nr_c0_int_mode_pulse_0_im2_1 && (dma_int_mask & m_im2_int_status)) ? 1 : 0); + if (m_nr_c0_int_mode_pulse_0_im2_1) + LOGINTVVV("DMA delay %d (int_status=%04x, int_mask=%04x)\n", (dma_int_mask & m_im2_int_status) ? 1 : 0, m_im2_int_status, dma_int_mask); } u8 specnext_state::reg_r(offs_t nr_register) @@ -2714,19 +2716,44 @@ void specnext_state::irq_w(int state) { m_maincpu->set_input_line(INPUT_LINE_IRQ0, state); + const std::array states = + { + m_im2_line->z80daisy_irq_state(), + m_im2_uart0_rx->z80daisy_irq_state(), + m_im2_uart1_rx->z80daisy_irq_state(), + m_ctc->z80daisy_chanel_irq_state(0), + m_ctc->z80daisy_chanel_irq_state(1), + m_ctc->z80daisy_chanel_irq_state(2), + m_ctc->z80daisy_chanel_irq_state(3), + m_im2_ula->z80daisy_irq_state(), + m_im2_uart0_tx->z80daisy_irq_state(), + m_im2_uart1_tx->z80daisy_irq_state() + }; + + const std::array masks = + { + 1 << INT_PRIORITY_LINE, + 1 << INT_PRIORITY_UART0_RX, + 1 << INT_PRIORITY_UART1_RX, + 1 << (INT_PRIORITY_CTC + 0), + 1 << (INT_PRIORITY_CTC + 1), + 1 << (INT_PRIORITY_CTC + 2), + 1 << (INT_PRIORITY_CTC + 3), + 1 << INT_PRIORITY_ULA, + 1 << INT_PRIORITY_UART0_TX, + 1 << INT_PRIORITY_UART1_TX + }; + const int tmp = m_im2_int_status; - m_im2_int_status &= 1 << INT_PRIORITY_NMI; - m_im2_int_status |= ((m_im2_uart0_tx->z80daisy_irq_state() & Z80_DAISY_IEO) != 0) << INT_PRIORITY_UART0_TX; - m_im2_int_status |= ((m_im2_uart1_tx->z80daisy_irq_state() & Z80_DAISY_IEO) != 0) << INT_PRIORITY_UART1_TX; - m_im2_int_status |= ((m_im2_ula->z80daisy_irq_state() & Z80_DAISY_IEO) != 0) << INT_PRIORITY_ULA; - m_im2_int_status |= ((m_ctc->z80daisy_chanel_irq_state(3) & Z80_DAISY_IEO) != 0) << (INT_PRIORITY_CTC + 3); - m_im2_int_status |= ((m_ctc->z80daisy_chanel_irq_state(2) & Z80_DAISY_IEO) != 0) << (INT_PRIORITY_CTC + 2); - m_im2_int_status |= ((m_ctc->z80daisy_chanel_irq_state(1) & Z80_DAISY_IEO) != 0) << (INT_PRIORITY_CTC + 1); - m_im2_int_status |= ((m_ctc->z80daisy_chanel_irq_state(0) & Z80_DAISY_IEO) != 0) << (INT_PRIORITY_CTC + 0); - m_im2_int_status |= ((m_im2_uart0_rx->z80daisy_irq_state() & Z80_DAISY_IEO) != 0) << INT_PRIORITY_UART0_RX; - m_im2_int_status |= ((m_im2_uart1_rx->z80daisy_irq_state() & Z80_DAISY_IEO) != 0) << INT_PRIORITY_UART1_RX; - m_im2_int_status |= ((m_im2_line->z80daisy_irq_state() & Z80_DAISY_IEO) != 0) << INT_PRIORITY_LINE; - LOGINTVVV("IRQ%s: %04x -> %04x\n", state ? "+" : "-", tmp, m_im2_int_status); + m_im2_int_status = 0; + for(int i = 0; i < states.size(); ++i) + { + m_im2_int_status |= (states[i] & Z80_DAISY_IEO) ? masks[i] : 0; + if ((states[i] & Z80_DAISY_INT) && !m_im2_int_status) // only highest priority IRQ + m_im2_int_status |= masks[i]; + } + m_im2_int_status |= tmp & (1 << INT_PRIORITY_NMI); + LOGINTVVV("IRQs: %s %04x -> %04x\n", state ? "+" : "-", tmp, m_im2_int_status); update_dma_delay(); } diff --git a/src/mame/sinclair/next/specnext_dma.cpp b/src/mame/sinclair/next/specnext_dma.cpp index dd1ed0dfb..3f6b0aea8 100644 --- a/src/mame/sinclair/next/specnext_dma.cpp +++ b/src/mame/sinclair/next/specnext_dma.cpp @@ -42,6 +42,16 @@ specnext_dma_device::specnext_dma_device(const machine_config &mconfig, const ch { } +void specnext_dma_device::dma_delay_w(bool dma_delay) +{ + if (m_dma_delay && !dma_delay && (m_dma_seq == SEQ_WAIT_READY)) + { + set_busrq(ASSERT_LINE); + m_dma_seq = SEQ_WAITING_ACK; + } + m_dma_delay = dma_delay; +} + void specnext_dma_device::reset_byte_counter() { m_byte_counter = m_dma_mode ? 0 : 1; @@ -97,8 +107,8 @@ TIMER_CALLBACK_MEMBER(specnext_dma_device::clock_w) { set_busrq(CLEAR_LINE); m_dma_seq = SEQ_WAIT_READY; - return; } + return; } } diff --git a/src/mame/sinclair/next/specnext_dma.h b/src/mame/sinclair/next/specnext_dma.h index cf1f3e996..c7553d549 100644 --- a/src/mame/sinclair/next/specnext_dma.h +++ b/src/mame/sinclair/next/specnext_dma.h @@ -13,7 +13,7 @@ public: specnext_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); void dma_mode_w(bool dma_mode) { m_dma_mode = dma_mode; } - void dma_delay_w(bool dma_delay) { m_dma_delay = dma_delay; } + void dma_delay_w(bool dma_delay); virtual void write(u8 data) override; diff --git a/src/mame/sinclair/next/specnext_im2.cpp b/src/mame/sinclair/next/specnext_im2.cpp index b4c385c6c..368584d4d 100644 --- a/src/mame/sinclair/next/specnext_im2.cpp +++ b/src/mame/sinclair/next/specnext_im2.cpp @@ -8,6 +8,10 @@ #include "specnext_im2.h" +#define VERBOSE 0 +#include "logmacro.h" + + // device type definition DEFINE_DEVICE_TYPE(SPECNEXT_IM2, specnext_im2_device, "specnext_im2", "Spectrum Next IM2") @@ -35,17 +39,34 @@ int specnext_im2_device::z80daisy_irq_ack() void specnext_im2_device::z80daisy_irq_reti() { - m_state = 0; - m_irq_cb(CLEAR_LINE); + if (m_state & Z80_DAISY_IEO) + { + m_state &= ~Z80_DAISY_IEO; + m_irq_cb((m_state & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE); + } } void specnext_im2_device::irq_w(int state) { - if (state != CLEAR_LINE) - m_state = Z80_DAISY_INT; + if (state == CLEAR_LINE) + { + m_state = 0; + m_irq_cb(CLEAR_LINE); + } + else if (m_state & Z80_DAISY_IEO) + { + LOG("IM2: Ignoring IRQ while in IEO\n"); + } else - m_state &= ~Z80_DAISY_INT; - m_irq_cb(state); + { + // FPGA im2_device in S_ISR cannot transition to S_REQ; + // don't assert INT while being serviced (IEO set), or + // the daisy chain would ACK this device, consuming the + // new INT, and a subsequent RETI would clear IEO while + // the original ISR still runs. + m_state |= Z80_DAISY_INT; + m_irq_cb(ASSERT_LINE); + } }