more interrupt handling improvements

This commit is contained in:
Patrick Mackinlay 2017-01-04 15:15:29 +07:00
parent 2248bac617
commit c8f4403de6
3 changed files with 67 additions and 20 deletions

View File

@ -136,9 +136,6 @@ void clipper_device::execute_run()
LOG_INTERRUPT("non-maskable interrupt - current pc = 0x%08x\n", m_pc); LOG_INTERRUPT("non-maskable interrupt - current pc = 0x%08x\n", m_pc);
m_pc = intrap(EXCEPTION_INTERRUPT_BASE, m_pc); m_pc = intrap(EXCEPTION_INTERRUPT_BASE, m_pc);
// FIXME: should m_nmi be cleared by the ioga doing CLEAR_LINE after acknowledgement?
m_nmi = 0;
} }
else if (m_ssw.bits.ei && m_irq) else if (m_ssw.bits.ei && m_irq)
{ {
@ -154,9 +151,6 @@ void clipper_device::execute_run()
LOG_INTERRUPT("accepting interrupt vector 0x%04x - current pc = %08x\n", ivec, m_pc); LOG_INTERRUPT("accepting interrupt vector 0x%04x - current pc = %08x\n", ivec, m_pc);
m_pc = intrap(EXCEPTION_INTERRUPT_BASE + ivec * 8, m_pc); m_pc = intrap(EXCEPTION_INTERRUPT_BASE + ivec * 8, m_pc);
// FIXME: should m_irq be cleared by the ioga doing CLEAR_LINE after acknowledgement?
m_irq = 0;
} }
} }

View File

@ -63,7 +63,8 @@ void interpro_ioga_device::device_start()
void interpro_ioga_device::device_reset() void interpro_ioga_device::device_reset()
{ {
m_interrupt = 0; m_irq_active = false;
m_state_drq = 0; m_state_drq = 0;
// configure timer 0 at 60Hz // configure timer 0 at 60Hz
@ -89,7 +90,7 @@ void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, in
if (m_timer_reg[1] == 0) if (m_timer_reg[1] == 0)
{ {
// disable timer // disable timer
m_timer[3]->enable(false); timer.enable(false);
// set expired flag // set expired flag
m_timer_reg[1] |= IOGA_TIMER1_EXPIRED; m_timer_reg[1] |= IOGA_TIMER1_EXPIRED;
@ -104,7 +105,7 @@ void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, in
if (m_timer_reg[3] == 0) if (m_timer_reg[3] == 0)
{ {
// disable timer // disable timer
m_timer[3]->enable(false); timer.enable(false);
// set expired flag // set expired flag
m_timer_reg[3] |= IOGA_TIMER3_EXPIRED; m_timer_reg[3] |= IOGA_TIMER3_EXPIRED;
@ -245,19 +246,55 @@ C8 : ethernet address C 4039f088 // IOGA_ETHADDR_C
17 timer 0 17 timer 0
*/ */
void interpro_ioga_device::update_irq(int state)
{
switch (state)
{
case CLEAR_LINE:
if (m_irq_active)
{
// the cpu has acknowledged the active interrupt, deassert the irq line
m_irq_active = false;
m_out_int_func(CLEAR_LINE);
}
// fall through to handle any pending interrupts
case ASSERT_LINE:
// if an irq is currently active, don't do anything
if (!m_irq_active)
{
// check for any pending interrupts
for (int irq = 0; irq < 19; irq++)
{
if (m_vectors[irq] & IOGA_INTERRUPT_PENDING)
{
m_irq_active = true;
m_irq_current = irq;
m_out_int_func(ASSERT_LINE);
return;
}
}
}
break;
}
}
void interpro_ioga_device::set_irq_line(int irq, int state) void interpro_ioga_device::set_irq_line(int irq, int state)
{ {
LOG_INTERRUPT("set_irq_line(%d, %d)\n", irq, state); LOG_INTERRUPT("set_irq_line(%d, %d)\n", irq, state);
switch (state) switch (state)
{ {
case ASSERT_LINE: case ASSERT_LINE:
// FIXME: handle internal/external interrupts properly
if (m_vectors[irq] & (IOGA_INTERRUPT_ENABLE_EXTERNAL | IOGA_INTERRUPT_ENABLE_INTERNAL)) if (m_vectors[irq] & (IOGA_INTERRUPT_ENABLE_EXTERNAL | IOGA_INTERRUPT_ENABLE_INTERNAL))
{ {
// set interrupt pending bit // set interrupt pending bit
m_vectors[irq] |= IOGA_INTERRUPT_PENDING; m_vectors[irq] |= IOGA_INTERRUPT_PENDING;
m_interrupt = irq; // update irq line state
m_out_int_func(ASSERT_LINE); update_irq(state);
} }
else else
LOG_INTERRUPT("received disabled interrupt irq %d vector 0x%04x\n", irq, m_vectors[irq]); LOG_INTERRUPT("received disabled interrupt irq %d vector 0x%04x\n", irq, m_vectors[irq]);
@ -267,7 +304,8 @@ void interpro_ioga_device::set_irq_line(int irq, int state)
// clear interrupt pending bit // clear interrupt pending bit
m_vectors[irq] &= ~IOGA_INTERRUPT_PENDING; m_vectors[irq] &= ~IOGA_INTERRUPT_PENDING;
m_out_int_func(CLEAR_LINE); // update irq line state
update_irq(state);
break; break;
} }
} }
@ -277,16 +315,24 @@ IRQ_CALLBACK_MEMBER(interpro_ioga_device::inta_cb)
switch (irqline) switch (irqline)
{ {
case -1: case -1:
// return vector for current interrupt without acknowledgement // return vector for current interrupt without clearing irq line
return m_vectors[m_interrupt] & 0xff; return m_vectors[m_irq_current] & 0xff;
case INPUT_LINE_IRQ0: case INPUT_LINE_IRQ0:
// acknowledge interrupt // FIXME: clear pending bit - can't rely on device callbacks
// FIXME: clear IRQ m_vectors[m_irq_current] &= ~IOGA_INTERRUPT_PENDING;
return m_vectors[m_interrupt] & 0xff;
// clear irq line
update_irq(CLEAR_LINE);
// return interrupt vector
return m_vectors[m_irq_current] & 0xff;
case INPUT_LINE_NMI: case INPUT_LINE_NMI:
//return m_nmictrl; // clear nmi line
m_out_nmi_func(CLEAR_LINE);
return 0;
default: default:
return 0; return 0;
@ -351,6 +397,8 @@ WRITE16_MEMBER(interpro_ioga_device::icr_w)
{ {
LOG_INTERRUPT("interrupt vector %d set to 0x%04x at pc 0x%08x\n", offset, data, space.device().safe_pc()); LOG_INTERRUPT("interrupt vector %d set to 0x%04x at pc 0x%08x\n", offset, data, space.device().safe_pc());
// FIXME: now that the interrupt handling only depends on IOGA_INTERRUPT_PENDING, we might be able
// to avoid this hack
if (data & IOGA_INTERRUPT_PENDING) if (data & IOGA_INTERRUPT_PENDING)
m_vectors[offset] = (data | IOGA_INTERRUPT_FORCED) & ~IOGA_INTERRUPT_PENDING; m_vectors[offset] = (data | IOGA_INTERRUPT_FORCED) & ~IOGA_INTERRUPT_PENDING;
else if (m_vectors[offset] & IOGA_INTERRUPT_FORCED) else if (m_vectors[offset] & IOGA_INTERRUPT_FORCED)

View File

@ -117,15 +117,20 @@ private:
void set_irq_line(int irq, int state); void set_irq_line(int irq, int state);
void write_timer(int timer, uint32_t value, device_timer_id id); void write_timer(int timer, uint32_t value, device_timer_id id);
void update_irq(int state);
devcb_write_line m_out_nmi_func; devcb_write_line m_out_nmi_func;
devcb_write_line m_out_int_func; devcb_write_line m_out_int_func;
// a hack to get hold of the dma devices // a hack to get hold of the dma devices
upd765_family_device *m_fdc; upd765_family_device *m_fdc;
uint8_t m_interrupt; bool m_irq_active;
uint32_t m_irq_current;
uint16_t m_vectors[19]; uint16_t m_vectors[19];
uint8_t m_softint, m_nmictrl; uint8_t m_softint;
uint8_t m_nmictrl;
uint32_t m_prescaler; uint32_t m_prescaler;
uint32_t m_timer_reg[4]; uint32_t m_timer_reg[4];