sinclair/next/specnext.cpp: Implemented DMA delay (allows to stop DMA in Continious mode for ISR)

This commit is contained in:
Andrei Holub 2026-04-17 08:42:15 -04:00 committed by Andrei I. Holub
parent c65da9b69d
commit fdce3c40fa
6 changed files with 87 additions and 22 deletions

View File

@ -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);
}

View File

@ -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,

View File

@ -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<int, 10> 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<u16, 10> 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();
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}
}