68307: More accurate emulation of internal priority interrupt controller

This commit is contained in:
AJR 2019-01-01 19:24:56 -05:00
parent 665c37d8bc
commit ccc8aaed97
7 changed files with 224 additions and 67 deletions

View File

@ -66,6 +66,7 @@ m68307_cpu_device::m68307_cpu_device(const machine_config &mconfig, const char *
m_m68307_scrhigh = 0;
m_m68307_scrlow = 0;
m_m68307_currentcs = 0;
m_ipl = 0;
}
@ -85,6 +86,7 @@ void m68307_cpu_device::device_reset()
m_m68307_scrhigh = 0x0007;
m_m68307_scrlow = 0xf010;
set_ipl(0);
}
@ -147,55 +149,78 @@ uint16_t m68307_cpu_device::get_cs(offs_t address)
/* 68307 specifics - MOVE */
void m68307_cpu_device::set_interrupt(int level, int vector)
void m68307_cpu_device::set_ipl(int level)
{
set_input_line_and_vector(level, HOLD_LINE, vector);
if (level != m_ipl)
{
if (m_ipl != 0)
set_input_line(m_ipl, CLEAR_LINE);
m_ipl = level;
if (m_ipl != 0)
set_input_line(m_ipl, ASSERT_LINE);
}
}
void m68307_cpu_device::timer0_interrupt()
WRITE_LINE_MEMBER(m68307_cpu_device::timer0_interrupt)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x7000)>>12;
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xa;
set_interrupt(prioritylevel, vector);
int prioritylevel = (m_m68307SIM->m_picr & 0x7000) >> 12;
if (state && m_ipl < prioritylevel)
set_ipl(prioritylevel);
else if (!state && m_ipl == prioritylevel)
set_ipl(m_m68307SIM->get_ipl(this));
}
void m68307_cpu_device::timer1_interrupt()
WRITE_LINE_MEMBER(m68307_cpu_device::timer1_interrupt)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x0700)>>8;
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xb;
set_interrupt(prioritylevel, vector);
}
void m68307_cpu_device::serial_interrupt(int vector)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x0070)>>4;
set_interrupt(prioritylevel, vector);
int prioritylevel = (m_m68307SIM->m_picr & 0x0700) >> 8;
if (state && m_ipl < prioritylevel)
set_ipl(prioritylevel);
else if (!state && m_ipl == prioritylevel)
set_ipl(m_m68307SIM->get_ipl(this));
}
WRITE_LINE_MEMBER(m68307_cpu_device::m68307_duart_irq_handler)
{
if (state == ASSERT_LINE)
{
serial_interrupt(m_duart->get_irq_vector());
}
int prioritylevel = (m_m68307SIM->m_picr & 0x0070) >> 4;
if (state && m_ipl < prioritylevel)
set_ipl(prioritylevel);
else if (!state && m_ipl == prioritylevel)
set_ipl(m_m68307SIM->get_ipl(this));
}
void m68307_cpu_device::mbus_interrupt()
WRITE_LINE_MEMBER(m68307_cpu_device::mbus_interrupt)
{
int prioritylevel = (m_m68307SIM->m_picr & 0x0007)>>0;
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xd;
set_interrupt(prioritylevel, vector);
int prioritylevel = (m_m68307SIM->m_picr & 0x0007) >> 0;
if (state && m_ipl < prioritylevel)
set_ipl(prioritylevel);
else if (!state && m_ipl == prioritylevel)
set_ipl(m_m68307SIM->get_ipl(this));
}
void m68307_cpu_device::licr2_interrupt()
{
int prioritylevel = (m_m68307SIM->m_licr2 & 0x0007)>>0;
int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0x9;
m_m68307SIM->m_licr2 |= 0x8;
int prioritylevel = (m_m68307SIM->m_licr2 & 0x0007) >> 0;
if (m_ipl < prioritylevel)
set_ipl(prioritylevel);
}
set_interrupt(prioritylevel, vector);
IRQ_CALLBACK_MEMBER(m68307_cpu_device::int_ack)
{
uint8_t type = m_m68307SIM->get_int_type(this, irqline);
logerror("Interrupt acknowledged: level %d, type %01X\n", irqline, type);
// UART provides its own vector
if (type == 0x0c)
return m_duart->get_irq_vector();
else
return (m_m68307SIM->m_pivr & 0xf0) | type;
}
void m68307_cpu_device::device_config_complete()
{
set_irq_acknowledge_callback(device_irq_acknowledge_delegate(FUNC(m68307_cpu_device::int_ack), this));
}
void m68307_cpu_device::device_start()

View File

@ -36,6 +36,7 @@ protected:
class m68307_mbus;
class m68307_timer;
virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
@ -44,11 +45,12 @@ protected:
virtual uint32_t execute_max_cycles() const override { return 158; }
private:
void set_interrupt(int level, int vector);
void timer0_interrupt();
void timer1_interrupt();
void serial_interrupt(int vector);
void mbus_interrupt();
void set_ipl(int level);
DECLARE_WRITE_LINE_MEMBER(timer0_interrupt);
DECLARE_WRITE_LINE_MEMBER(timer1_interrupt);
DECLARE_WRITE_LINE_MEMBER(mbus_interrupt);
IRQ_CALLBACK_MEMBER(int_ack);
DECLARE_WRITE_LINE_MEMBER(m68307_duart_irq_handler);
DECLARE_WRITE_LINE_MEMBER(m68307_duart_txa) { m_write_a_tx(state); }
@ -89,6 +91,8 @@ private:
int m_m68307_currentcs;
uint8_t m_ipl;
porta_read_delegate m_porta_r;
porta_write_delegate m_porta_w;
portb_read_delegate m_portb_r;

View File

@ -44,6 +44,7 @@ READ8_MEMBER( m68307_cpu_device::m68307_internal_mbus_r )
case m68307BUS_MBDR:
logerror("%08x m68307_internal_mbus_r %08x (MBDR - M-Bus Data I/O Register)\n", m_ppc, offset);
mbus.m_intpend = true;
mbus_interrupt(1);
return 0xff;//machine().rand();
default:
@ -77,6 +78,7 @@ WRITE8_MEMBER( m68307_cpu_device::m68307_internal_mbus_w )
{
mbus.m_busy = false;
mbus.m_intpend = false;
mbus_interrupt(0);
}
if (data & 0x20) mbus.m_busy = true;
@ -90,6 +92,7 @@ WRITE8_MEMBER( m68307_cpu_device::m68307_internal_mbus_w )
logerror("%08x m68307_internal_mbus_w %08x, %02x (MBDR - M-Bus Data I/O Register)\n", m_ppc, offset,data);
mbus.m_intpend = true;
mbus_interrupt(1);
break;

View File

@ -3,7 +3,9 @@
/* 68307 SIM module */
#include "emu.h"
#include "68307bus.h"
#include "68307sim.h"
#include "68307tmu.h"
/* ports */
#define m68307SIM_PACNT (0x10)
@ -249,41 +251,66 @@ void m68307_cpu_device::m68307_sim::write_pbdat(m68307_cpu_device* m68k, address
void m68307_cpu_device::m68307_sim::write_licr1(m68307_cpu_device* m68k, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_licr1);
data = m_licr1;
m68k->logerror("m_licr1 value %04x : Details :\n", data);
m68k->logerror("int4ipl %01x\n", (data>>0)&7);
m68k->logerror("pir4 %01x\n", (data>>3)&1);
m68k->logerror("int3ipl %01x\n", (data>>4)&7);
m68k->logerror("pir3 %01x\n", (data>>7)&1);
m68k->logerror("int2ipl %01x\n", (data>>8)&7);
m68k->logerror("pir2 %01x\n", (data>>11)&1);
m68k->logerror("int1ipl %01x\n", (data>>12)&7);
m68k->logerror("pir1 %01x\n", (data>>15)&1);
m68k->logerror("m_licr1 write %04x : Details :\n", data);
if (BIT(data & mem_mask, 3))
{
m_licr1 = (m_licr1 & 0xfff0) | (data & 0x0007);
m68k->logerror("int4ipl %01x\n", (m_licr1>>0)&7);
}
m68k->logerror("pir4 %01x\n", (m_licr1>>3)&1);
if (BIT(data & mem_mask, 7))
{
m_licr1 = (m_licr1 & 0xff0f) | (data & 0x0070);
m68k->logerror("int3ipl %01x\n", (m_licr1>>4)&7);
}
m68k->logerror("pir3 %01x\n", (m_licr1>>7)&1);
if (BIT(data & mem_mask, 11))
{
m_licr1 = (m_licr1 & 0xf0ff) | (data & 0x0700);
m68k->logerror("int2ipl %01x\n", (m_licr1>>8)&7);
}
m68k->logerror("pir2 %01x\n", (m_licr1>>11)&1);
if (BIT(data & mem_mask, 15))
{
m_licr1 = (m_licr1 & 0x0fff) | (data & 0x7000);
m68k->logerror("int1ipl %01x\n", (m_licr1>>12)&7);
}
m68k->logerror("pir1 %01x\n", (m_licr1>>15)&1);
m68k->logerror("\n");
m68k->set_ipl(get_ipl(m68k));
}
void m68307_cpu_device::m68307_sim::write_licr2(m68307_cpu_device* m68k, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_licr2);
uint16_t newdata = m_licr2;
m68k->logerror("m_licr2 value %04x : Details :\n", newdata);
m68k->logerror("int8ipl %01x\n", (newdata>>0)&7);
m68k->logerror("pir8 %01x\n", (newdata>>3)&1);
m68k->logerror("int7ipl %01x\n", (newdata>>4)&7);
m68k->logerror("pir7 %01x\n", (newdata>>7)&1);
m68k->logerror("int6ipl %01x\n", (newdata>>8)&7);
m68k->logerror("pir6 %01x\n", (newdata>>11)&1);
m68k->logerror("int5ipl %01x\n", (newdata>>12)&7);
m68k->logerror("pir5 %01x\n", (newdata>>15)&1);
m68k->logerror("m_licr2 write %04x : Details :\n", data);
if (BIT(data & mem_mask, 3))
{
m_licr2 = (m_licr2 & 0xfff0) | (data & 0x0007);
m68k->logerror("int8ipl %01x\n", (m_licr2>>0)&7);
}
m68k->logerror("pir8 %01x\n", (m_licr2>>3)&1);
if (BIT(data & mem_mask, 7))
{
m_licr2 = (m_licr2 & 0xff0f) | (data & 0x0070);
m68k->logerror("int7ipl %01x\n", (m_licr2>>4)&7);
}
m68k->logerror("pir7 %01x\n", (m_licr2>>7)&1);
if (BIT(data & mem_mask, 11))
{
m_licr2 = (m_licr2 & 0xf0ff) | (data & 0x0700);
m68k->logerror("int6ipl %01x\n", (m_licr2>>8)&7);
}
m68k->logerror("pir6 %01x\n", (m_licr2>>11)&1);
if (BIT(data & mem_mask, 15))
{
m_licr2 = (m_licr2 & 0x0fff) | (data & 0x7000);
m68k->logerror("int5ipl %01x\n", (m_licr2>>12)&7);
}
m68k->logerror("pir5 %01x\n", (m_licr2>>15)&1);
m68k->logerror("\n");
if (data & 0x0008) m_licr2 = m_licr2 & ~0x0008;
if (data & 0x0080) m_licr2 = m_licr2 & ~0x0080;
if (data & 0x0800) m_licr2 = m_licr2 & ~0x0800;
if (data & 0x8000) m_licr2 = m_licr2 & ~0x8000;
m68k->set_ipl(get_ipl(m68k));
}
@ -297,6 +324,8 @@ void m68307_cpu_device::m68307_sim::write_picr(m68307_cpu_device* m68k, uint16_t
m68k->logerror("t2ipl %01x\n", (data>>8)&7);
m68k->logerror("t1ipl %01x\n", (data>>12)&7);
m68k->logerror("\n");
m68k->set_ipl(get_ipl(m68k));
}
void m68307_cpu_device::m68307_sim::write_pivr(m68307_cpu_device* m68k, uint16_t data, uint16_t mem_mask)
@ -308,6 +337,76 @@ void m68307_cpu_device::m68307_sim::write_pivr(m68307_cpu_device* m68k, uint16_t
m68k->logerror("high vector %01x\n", (data>>4)&0xf);
}
uint8_t m68307_cpu_device::m68307_sim::get_ipl(const m68307_cpu_device *m68k) const
{
// INT7 has highest priority
if (0 /*m_int7*/)
return 7;
// LICR1 interrupts from INT1, INT2, INT3, INT4
// LICR2 interrupts from INT5, INT6, INT7, INT8
uint8_t ipl = 0;
uint32_t licr = (m_licr1 << 16) | m_licr2;
while (licr != 0)
{
if (BIT(licr, 31) && (licr >> 28) & 7)
ipl = std::max(ipl, uint8_t((licr >> 28) & 7));
licr <<= 4;
}
// PICR interrupts from T1, T2, UART, MBUS
if (m68k->m_m68307TIMER->timer_int_pending(0))
ipl = std::max(ipl, uint8_t((m_picr >> 12) & 7));
if (m68k->m_m68307TIMER->timer_int_pending(1))
ipl = std::max(ipl, uint8_t((m_picr >> 8) & 7));
if (m68k->m_duart->irq_pending())
ipl = std::max(ipl, uint8_t((m_picr >> 4) & 7));
if (m68k->m_m68307MBUS->m_intpend)
ipl = std::max(ipl, uint8_t((m_picr >> 0) & 7));
return ipl;
}
uint8_t m68307_cpu_device::m68307_sim::get_int_type(const m68307_cpu_device *m68k, uint8_t pri) const
{
// INT7 has highest priority
if (0 /*m_int7*/ && pri == 7)
return 0x01;
// LICR1 interrupts from INT1, INT2, INT3, INT4
else if (BIT(m_licr1, 15) && pri == ((m_licr1 >> 12) & 7))
return 0x02;
else if (BIT(m_licr1, 11) && pri == ((m_licr1 >> 8) & 7))
return 0x03;
else if (BIT(m_licr1, 7) && pri == ((m_licr1 >> 4) & 7))
return 0x04;
else if (BIT(m_licr1, 3) && pri == ((m_licr1 >> 0) & 7))
return 0x05;
// LICR2 interrupts from INT5, INT6, INT7, INT8
else if (BIT(m_licr2, 15) && pri == ((m_licr2 >> 12) & 7))
return 0x06;
else if (BIT(m_licr2, 11) && pri == ((m_licr2 >> 8) & 7))
return 0x07;
else if (BIT(m_licr2, 7) && pri == ((m_licr2 >> 4) & 7))
return 0x08;
else if (BIT(m_licr2, 3) && pri == ((m_licr2 >> 0) & 7))
return 0x09;
// PICR interrupts from T1, T2, UART, MBUS
else if (m68k->m_m68307TIMER->timer_int_pending(0) && pri == ((m_picr >> 12) & 7))
return 0x0a;
else if (m68k->m_m68307TIMER->timer_int_pending(1) && pri == ((m_picr >> 8) & 7))
return 0x0b;
else if (m68k->m_duart->irq_pending() && pri == ((m_picr >> 4) & 7))
return 0x0c;
else if (m68k->m_m68307MBUS->m_intpend && pri == ((m_picr >> 0) & 7))
return 0x0d;
// Spurious interrupt (vectored normally)
return 0x00;
}
void m68307_cpu_device::m68307_sim::reset()
{
for (int i=0;i<4;i++)
@ -315,4 +414,9 @@ void m68307_cpu_device::m68307_sim::reset()
m_br[i] = 0xc001;
m_or[i] = 0xdffd;
}
m_licr1 = 0x0000;
m_licr2 = 0x0000;
m_picr = 0x0000;
m_pivr = 0x0f;
}

View File

@ -43,6 +43,9 @@ public:
void write_picr(m68307_cpu_device* m68k, uint16_t data, uint16_t mem_mask);
void write_pivr(m68307_cpu_device* m68k, uint16_t data, uint16_t mem_mask);
uint8_t get_ipl(const m68307_cpu_device *m68k) const;
uint8_t get_int_type(const m68307_cpu_device* m68k, uint8_t pri) const;
void reset();
};

View File

@ -101,9 +101,10 @@ TIMER_CALLBACK_MEMBER(m68307_cpu_device::m68307_timer::timer0_callback )
{
m68307_cpu_device* m68k = (m68307_cpu_device *)ptr;
single_timer* tptr = &m68k->m_m68307TIMER->singletimer[0];
tptr->regs[m68307TIMER_TMR] |= 0x2;
tptr->regs[m68307TIMER_TER] |= 0x2;
m68k->timer0_interrupt();
if (BIT(tptr->regs[m68307TIMER_TMR], 4))
m68k->timer0_interrupt(1);
tptr->mametimer->adjust(m68k->cycles_to_attotime(20000));
}
@ -112,9 +113,10 @@ TIMER_CALLBACK_MEMBER(m68307_cpu_device::m68307_timer::timer1_callback )
{
m68307_cpu_device* m68k = (m68307_cpu_device *)ptr;
single_timer* tptr = &m68k->m_m68307TIMER->singletimer[1];
tptr->regs[m68307TIMER_TMR] |= 0x2;
tptr->regs[m68307TIMER_TER] |= 0x2;
m68k->timer1_interrupt();
if (BIT(tptr->regs[m68307TIMER_TMR], 4))
m68k->timer1_interrupt(1);
tptr->mametimer->adjust(m68k->cycles_to_attotime(20000));
@ -152,7 +154,14 @@ void m68307_cpu_device::m68307_timer::write_ter(uint16_t data, uint16_t mem_mask
{
assert(which >= 0 && which < ARRAY_LENGTH(singletimer));
single_timer* tptr = &singletimer[which];
if (data & 0x2) tptr->regs[m68307TIMER_TMR] &= ~0x2;
if (data & 0x2)
{
tptr->regs[m68307TIMER_TER] &= ~0x2;
if (which)
parent->timer1_interrupt(0);
else
parent->timer0_interrupt(0);
}
}
void m68307_cpu_device::m68307_timer::write_tmr(uint16_t data, uint16_t mem_mask, int which)
@ -203,7 +212,6 @@ void m68307_cpu_device::m68307_timer::write_tmr(uint16_t data, uint16_t mem_mask
tptr->mametimer->adjust(m68k->cycles_to_attotime(100000));
m68k->logerror("\n");
}
void m68307_cpu_device::m68307_timer::write_trr(uint16_t data, uint16_t mem_mask, int which)
@ -236,3 +244,12 @@ void m68307_cpu_device::m68307_timer::reset()
wd_mametimer->adjust(attotime::never);
}
bool m68307_cpu_device::m68307_timer::timer_int_pending(int which) const
{
assert(which >= 0 && which < ARRAY_LENGTH(singletimer));
const single_timer* tptr = &singletimer[which];
return BIT(tptr->regs[m68307TIMER_TER], 1) && BIT(tptr->regs[m68307TIMER_TMR], 4);
}

View File

@ -28,6 +28,7 @@ public:
void write_trr(uint16_t data, uint16_t mem_mask, int which);
void write_ter(uint16_t data, uint16_t mem_mask, int which);
uint16_t read_tcn(uint16_t mem_mask, int which);
bool timer_int_pending(int which) const;
void init(m68307_cpu_device *device);
void reset();