diff options
author | 2019-01-01 19:24:56 -0500 | |
---|---|---|
committer | 2019-01-01 19:25:47 -0500 | |
commit | ccc8aaed9781af8e49645b27ea771aaaea28fa06 (patch) | |
tree | 56801954da416b5b9a19959f5ff0943b035fb678 /src/devices/machine | |
parent | 665c37d8bc7f43a20213852e971c9fc94322635e (diff) |
68307: More accurate emulation of internal priority interrupt controller
Diffstat (limited to 'src/devices/machine')
-rw-r--r-- | src/devices/machine/68307.cpp | 81 | ||||
-rw-r--r-- | src/devices/machine/68307.h | 14 | ||||
-rw-r--r-- | src/devices/machine/68307bus.cpp | 3 | ||||
-rw-r--r-- | src/devices/machine/68307sim.cpp | 160 | ||||
-rw-r--r-- | src/devices/machine/68307sim.h | 3 | ||||
-rw-r--r-- | src/devices/machine/68307tmu.cpp | 29 | ||||
-rw-r--r-- | src/devices/machine/68307tmu.h | 1 |
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(); |