summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2019-01-01 19:24:56 -0500
committer AJR <ajrhacker@users.noreply.github.com>2019-01-01 19:25:47 -0500
commitccc8aaed9781af8e49645b27ea771aaaea28fa06 (patch)
tree56801954da416b5b9a19959f5ff0943b035fb678 /src/devices/machine
parent665c37d8bc7f43a20213852e971c9fc94322635e (diff)
68307: More accurate emulation of internal priority interrupt controller
Diffstat (limited to 'src/devices/machine')
-rw-r--r--src/devices/machine/68307.cpp81
-rw-r--r--src/devices/machine/68307.h14
-rw-r--r--src/devices/machine/68307bus.cpp3
-rw-r--r--src/devices/machine/68307sim.cpp160
-rw-r--r--src/devices/machine/68307sim.h3
-rw-r--r--src/devices/machine/68307tmu.cpp29
-rw-r--r--src/devices/machine/68307tmu.h1
7 files changed, 224 insertions, 67 deletions
diff --git a/src/devices/machine/68307.cpp b/src/devices/machine/68307.cpp
index 91a85f10a90..421d5f06da2 100644
--- a/src/devices/machine/68307.cpp
+++ b/src/devices/machine/68307.cpp
@@ -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);
-}
-
-void 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);
+ 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::timer1_interrupt()
+WRITE_LINE_MEMBER(m68307_cpu_device::timer0_interrupt)
{
- int prioritylevel = (m_m68307SIM->m_picr & 0x0700)>>8;
- int vector = (m_m68307SIM->m_pivr & 0x00f0) | 0xb;
- 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::serial_interrupt(int vector)
+WRITE_LINE_MEMBER(m68307_cpu_device::timer1_interrupt)
{
- 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);
+}
+
+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;
+}
- set_interrupt(prioritylevel, vector);
+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()
diff --git a/src/devices/machine/68307.h b/src/devices/machine/68307.h
index 401dbde007b..591d0c9cced 100644
--- a/src/devices/machine/68307.h
+++ b/src/devices/machine/68307.h
@@ -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;
diff --git a/src/devices/machine/68307bus.cpp b/src/devices/machine/68307bus.cpp
index f06f586fb7e..e6698e588ca 100644
--- a/src/devices/machine/68307bus.cpp
+++ b/src/devices/machine/68307bus.cpp
@@ -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;
diff --git a/src/devices/machine/68307sim.cpp b/src/devices/machine/68307sim.cpp
index e912d434006..b5363ecf6af 100644
--- a/src/devices/machine/68307sim.cpp
+++ b/src/devices/machine/68307sim.cpp
@@ -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;
}
diff --git a/src/devices/machine/68307sim.h b/src/devices/machine/68307sim.h
index e709f11a96f..08c284c44c3 100644
--- a/src/devices/machine/68307sim.h
+++ b/src/devices/machine/68307sim.h
@@ -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();
};
diff --git a/src/devices/machine/68307tmu.cpp b/src/devices/machine/68307tmu.cpp
index cdcb2c6c44a..2b5e3efd2b2 100644
--- a/src/devices/machine/68307tmu.cpp
+++ b/src/devices/machine/68307tmu.cpp
@@ -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);
+}
diff --git a/src/devices/machine/68307tmu.h b/src/devices/machine/68307tmu.h
index 25b782fcacb..3c3984e56c8 100644
--- a/src/devices/machine/68307tmu.h
+++ b/src/devices/machine/68307tmu.h
@@ -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();