diff options
Diffstat (limited to 'src/devices/cpu/h8/h8_intc.cpp')
-rw-r--r-- | src/devices/cpu/h8/h8_intc.cpp | 421 |
1 files changed, 256 insertions, 165 deletions
diff --git a/src/devices/cpu/h8/h8_intc.cpp b/src/devices/cpu/h8/h8_intc.cpp index 2dda3b5faa2..4598327bb72 100644 --- a/src/devices/cpu/h8/h8_intc.cpp +++ b/src/devices/cpu/h8/h8_intc.cpp @@ -1,61 +1,79 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_intc.cpp + + H8 interrupt controllers family + +***************************************************************************/ + #include "emu.h" #include "h8_intc.h" -DEFINE_DEVICE_TYPE(H8_INTC, h8_intc_device, "h8_intc", "H8 interrupt controller") -DEFINE_DEVICE_TYPE(H8H_INTC, h8h_intc_device, "h8h_intc", "H8H interrupt controller") -DEFINE_DEVICE_TYPE(H8S_INTC, h8s_intc_device, "h8s_intc", "H8S interrupt controller") +#include "h8.h" -h8_intc_device::h8_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + +DEFINE_DEVICE_TYPE(H8_INTC, h8_intc_device, "h8_intc", "H8 interrupt controller") +DEFINE_DEVICE_TYPE(H8325_INTC, h8325_intc_device, "h8325_intc", "H8/325 interrupt controller") +DEFINE_DEVICE_TYPE(H8H_INTC, h8h_intc_device, "h8h_intc", "H8H interrupt controller") +DEFINE_DEVICE_TYPE(H8S_INTC, h8s_intc_device, "h8s_intc", "H8S interrupt controller") +DEFINE_DEVICE_TYPE(GT913_INTC, gt913_intc_device, "gt913_intc", "Casio GT913F interrupt controller") + +h8_intc_device::h8_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : h8_intc_device(mconfig, H8_INTC, tag, owner, clock) { - irq_vector_base = 4; - irq_vector_nmi = 3; + m_irq_vector_base = 4; + m_irq_vector_count = 8; + m_irq_vector_nmi = 3; } -h8_intc_device::h8_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, type, tag, owner, clock), irq_vector_base(0), irq_vector_nmi(0), - cpu(*this, DEVICE_SELF_OWNER), nmi_input(false), irq_input(0), ier(0), isr(0), iscr(0), icr_filter(0), ipr_filter(0) +h8_intc_device::h8_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : + device_t(mconfig, type, tag, owner, clock), m_irq_vector_base(0), m_irq_vector_count(0), m_irq_vector_nmi(0), m_has_isr(false), + m_cpu(*this, finder_base::DUMMY_TAG), m_nmi_type(EDGE_FALL), m_nmi_input(false), m_irq_input(0), m_ier(0), m_isr(0), m_iscr(0), m_icr_filter(0), m_ipr_filter(0) { } void h8_intc_device::device_start() { - memset(pending_irqs, 0, sizeof(pending_irqs)); - save_item(NAME(pending_irqs)); - save_item(NAME(irq_type)); - save_item(NAME(nmi_input)); - save_item(NAME(irq_input)); - save_item(NAME(ier)); - save_item(NAME(isr)); - save_item(NAME(iscr)); - save_item(NAME(icr_filter)); - save_item(NAME(ipr_filter)); + memset(m_pending_irqs, 0, sizeof(m_pending_irqs)); + save_item(NAME(m_pending_irqs)); + save_item(NAME(m_irq_type)); + save_item(NAME(m_nmi_type)); + save_item(NAME(m_nmi_input)); + save_item(NAME(m_irq_input)); + save_item(NAME(m_ier)); + save_item(NAME(m_isr)); + save_item(NAME(m_iscr)); + save_item(NAME(m_icr_filter)); + save_item(NAME(m_ipr_filter)); } void h8_intc_device::device_reset() { - memset(irq_type, 0, sizeof(irq_type)); - memset(pending_irqs, 0, sizeof(pending_irqs)); - ier = isr = irq_input = 0x00; - iscr = 0x0000; + memset(m_irq_type, 0, sizeof(m_irq_type)); // LEVEL_LOW + m_nmi_type = EDGE_FALL; + memset(m_pending_irqs, 0, sizeof(m_pending_irqs)); + m_iscr = 0x0000; + m_ier = m_isr = 0x00; + check_level_irqs(false); } int h8_intc_device::interrupt_taken(int vector) { if(0) logerror("taking internal interrupt %d\n", vector); - pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); - if(vector >= irq_vector_base && vector < irq_vector_base + 8) { - int irq = vector - irq_vector_base; - if(irq_type[irq] != IRQ_LEVEL || !(irq_input & (1 << irq))) - isr &= ~(1 << irq); + m_pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); + if(vector >= m_irq_vector_base && vector < m_irq_vector_base + m_irq_vector_count) { + int irq = vector - m_irq_vector_base; + u8 mask = 1 << irq; + if(m_irq_type[irq] != LEVEL_LOW || !(m_irq_input & mask)) + m_isr &= ~mask; update_irq_state(); return irq; } update_irq_state(); - if(vector == irq_vector_nmi) + if(vector == m_irq_vector_nmi) return INPUT_LINE_NMI; return 8; } @@ -64,8 +82,8 @@ void h8_intc_device::internal_interrupt(int vector) { if(0) logerror("internal interrupt %d\n", vector); - if(!cpu->trigger_dma(vector)) { - pending_irqs[vector >> 5] |= 1 << (vector & 31); + if(!m_cpu->trigger_dma(vector)) { + m_pending_irqs[vector >> 5] |= 1 << (vector & 31); update_irq_state(); } } @@ -73,108 +91,127 @@ void h8_intc_device::internal_interrupt(int vector) void h8_intc_device::set_input(int inputnum, int state) { if(inputnum == INPUT_LINE_NMI) { - if(state == ASSERT_LINE && !nmi_input) - pending_irqs[0] |= 1 << irq_vector_nmi; - nmi_input = state == ASSERT_LINE; - update_irq_state(); + bool set = false; + switch(m_nmi_type) { + case EDGE_FALL: set = state == ASSERT_LINE && !m_nmi_input; break; + case EDGE_RISE: set = state == CLEAR_LINE && m_nmi_input; break; + default: assert(0); break; + } + m_nmi_input = state == ASSERT_LINE; + if(set && machine().time() > attotime::zero) { + m_pending_irqs[0] |= 1 << m_irq_vector_nmi; + update_irq_state(); + } } else { bool set = false; - bool cur = irq_input & (1 << inputnum); - switch(irq_type[inputnum]) { - case IRQ_LEVEL: set = state == ASSERT_LINE; break; - case IRQ_EDGE: set = state == ASSERT_LINE && !cur; break; - case IRQ_DUAL_EDGE: set = (state == ASSERT_LINE && !cur) || (state == CLEAR_LINE && cur); break; + u8 mask = 1 << inputnum; + u8 cur = m_irq_input & mask; + switch(m_irq_type[inputnum]) { + case LEVEL_LOW: + set = state == ASSERT_LINE; + // on base H8, level-triggered IRQ is not latched + if(!set && !m_has_isr) + m_isr &= ~mask; + break; + case EDGE_FALL: set = state == ASSERT_LINE && !cur; break; + case EDGE_RISE: set = state == CLEAR_LINE && cur; break; + case EDGE_DUAL: set = bool(state) != bool(cur); break; } if(state == ASSERT_LINE) - irq_input |= 1 << inputnum; + m_irq_input |= mask; else - irq_input &= ~(1 << inputnum); + m_irq_input &= ~mask; if(set) { - isr |= 1 << inputnum; + m_isr |= mask; update_irq_state(); } } } -void h8_intc_device::set_filter(int _icr_filter, int _ipr_filter) +void h8_intc_device::set_filter(int icr_filter, int ipr_filter) { - icr_filter = _icr_filter; - ipr_filter = _ipr_filter; + m_icr_filter = icr_filter; + m_ipr_filter = ipr_filter; update_irq_state(); } -READ8_MEMBER(h8_intc_device::ier_r) +u8 h8_intc_device::ier_r() { - return ier; + return m_ier; } -WRITE8_MEMBER(h8_intc_device::ier_w) +void h8_intc_device::ier_w(u8 data) { - ier = data; - logerror("ier = %02x\n", data); + m_ier = data; + // logerror("ier = %02x\n", data); update_irq_state(); } -void h8_intc_device::check_level_irqs(bool force_update) +void h8_intc_device::check_level_irqs(bool update) { - logerror("irq_input=%02x\n", irq_input); - bool update = force_update; - for(int i=0; i<8; i++) { - unsigned char mask = 1 << i; - if(irq_type[i] == IRQ_LEVEL && (irq_input & mask) && !(isr & mask)) { - isr |= mask; - update = true; + bool set = false; + for(int i = 0; i < m_irq_vector_count; i++) { + u8 mask = 1 << i; + if(m_irq_type[i] == LEVEL_LOW && (m_irq_input & mask) && !(m_isr & mask)) { + m_isr |= mask; + set = true; } } - if(update) + if(set && update) update_irq_state(); } -READ8_MEMBER(h8_intc_device::iscr_r) +u8 h8_intc_device::iscr_r() { - return iscr; + return m_iscr; } -WRITE8_MEMBER(h8_intc_device::iscr_w) +void h8_intc_device::iscr_w(u8 data) { - iscr = data; - logerror("iscr = %02x\n", iscr); + m_iscr = data; + logerror("iscr = %02x\n", m_iscr); update_irq_types(); } void h8_intc_device::update_irq_types() { - for(int i=0; i<8; i++) - switch((iscr >> (i)) & 1) { + for(int i = 0; i < m_irq_vector_count; i++) + switch((m_iscr >> i) & 1) { case 0: - irq_type[i] = IRQ_LEVEL; + m_irq_type[i] = LEVEL_LOW; break; case 1: - irq_type[i] = IRQ_EDGE; + if(!m_has_isr && m_irq_type[i] == LEVEL_LOW) + m_isr &= ~(1 << i); + m_irq_type[i] = EDGE_FALL; break; } - check_level_irqs(); + check_level_irqs(true); } void h8_intc_device::update_irq_state() { - pending_irqs[0] &= ~(255 << irq_vector_base); - pending_irqs[0] |= (isr & ier) << irq_vector_base; + if(m_irq_vector_count > 0) { + const u32 mask = (1 << m_irq_vector_count) - 1; + + m_pending_irqs[0] &= ~(mask << m_irq_vector_base); + m_pending_irqs[0] |= (m_isr & m_ier & mask) << m_irq_vector_base; + } int cur_vector = 0; int cur_level = -1; - for(int i=0; i<MAX_VECTORS/32; i++) { - unsigned int pending = pending_irqs[i]; + for(int i = 0; i < MAX_VECTORS/32; i++) { + u32 pending = m_pending_irqs[i]; if(pending) - for(int j=0; j<32; j++) + for(int j = 0; j < 32; j++) if(pending & (1 << j)) { int vect = i*32+j; int icr_pri, ipr_pri; get_priority(vect, icr_pri, ipr_pri); - if(icr_pri >= icr_filter && ipr_pri > ipr_filter) { - int level = ipr_filter == -1 ? icr_pri : ipr_pri; + if(icr_pri >= m_icr_filter && ipr_pri > m_ipr_filter) { + int level = m_ipr_filter == -1 ? icr_pri : ipr_pri; if(level > cur_level) { cur_vector = vect; cur_level = level; @@ -182,121 +219,107 @@ void h8_intc_device::update_irq_state() } } } - cpu->set_irq(cur_vector, cur_level, cur_vector == irq_vector_nmi); + m_cpu->set_irq(cur_vector, cur_level, cur_vector == m_irq_vector_nmi); } void h8_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const { - icr_pri = 0; + icr_pri = vect == 3 ? 2 : 0; // NMI ipr_pri = 0; } -h8h_intc_device::h8h_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - h8h_intc_device(mconfig, H8H_INTC, tag, owner, clock) -{ - irq_vector_base = 12; - irq_vector_nmi = 7; -} - -h8h_intc_device::h8h_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : - h8_intc_device(mconfig, type, tag, owner, clock) -{ -} +// H8/325 -void h8h_intc_device::device_start() +h8325_intc_device::h8325_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + h8_intc_device(mconfig, H8325_INTC, tag, owner, clock) { - h8_intc_device::device_start(); - save_item(NAME(icr)); + m_irq_vector_base = 4; + m_irq_vector_count = 3; + m_irq_vector_nmi = 3; } -void h8h_intc_device::device_reset() +void h8325_intc_device::update_irq_types() { - h8_intc_device::device_reset(); - icr = 0x000000; -} - -READ8_MEMBER(h8h_intc_device::isr_r) -{ - return isr; -} - -WRITE8_MEMBER(h8h_intc_device::isr_w) -{ - isr &= data; // edge/level - logerror("isr = %02x / %02x\n", data, isr); + for(int i = 0; i < m_irq_vector_count; i++) { + u8 type = m_irq_type[i]; + switch(bitswap<2>(m_iscr >> i,0,4)) { + case 0: case 1: + m_irq_type[i] = LEVEL_LOW; + break; + case 2: + m_irq_type[i] = EDGE_FALL; + break; + case 3: + m_irq_type[i] = EDGE_RISE; + break; + } + if(type == LEVEL_LOW && m_irq_type[i] != LEVEL_LOW) + m_isr &= ~(1 << i); + } check_level_irqs(true); } -READ8_MEMBER(h8h_intc_device::icr_r) -{ - return icr >> (8*offset); -} -WRITE8_MEMBER(h8h_intc_device::icr_w) +// H8H + +h8h_intc_device::h8h_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + h8h_intc_device(mconfig, H8H_INTC, tag, owner, clock) { - icr = (icr & (0xff << (8*offset))) | (data << (8*offset)); - logerror("icr %d = %02x\n", offset, data); + m_irq_vector_base = 12; + m_irq_vector_count = 8; + m_irq_vector_nmi = 7; } -READ8_MEMBER(h8h_intc_device::icrc_r) +h8h_intc_device::h8h_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : + h8_intc_device(mconfig, type, tag, owner, clock) { - return icr_r(space, 2, mem_mask); } -WRITE8_MEMBER(h8h_intc_device::icrc_w) +void h8h_intc_device::device_start() { - icr_w(space, 2, data, mem_mask); + h8_intc_device::device_start(); + save_item(NAME(m_icr)); + m_has_isr = true; } -READ8_MEMBER(h8h_intc_device::iscrh_r) +void h8h_intc_device::device_reset() { - return iscr >> 8; + h8_intc_device::device_reset(); + m_icr = 0x000000; } -WRITE8_MEMBER(h8h_intc_device::iscrh_w) +u8 h8h_intc_device::isr_r() { - iscr = (iscr & 0x00ff) | (data << 8); - logerror("iscr = %04x\n", iscr); - update_irq_types(); + return m_isr; } -READ8_MEMBER(h8h_intc_device::iscrl_r) +void h8h_intc_device::isr_w(u8 data) { - return iscr; + m_isr &= data; // edge/level + //logerror("isr = %02x / %02x\n", data, m_isr); + check_level_irqs(false); + update_irq_state(); } -WRITE8_MEMBER(h8h_intc_device::iscrl_w) +u8 h8h_intc_device::icr_r(offs_t offset) { - iscr = (iscr & 0xff00) | data; - logerror("iscr = %04x\n", iscr); - update_irq_types(); + return m_icr >> (8*offset); } -void h8h_intc_device::update_irq_types() +void h8h_intc_device::icr_w(offs_t offset, u8 data) { - for(int i=0; i<8; i++) - switch((iscr >> (2*i)) & 3) { - case 0: - irq_type[i] = IRQ_LEVEL; - break; - case 1: case 2: - irq_type[i] = IRQ_EDGE; - break; - case 3: - irq_type[i] = IRQ_DUAL_EDGE; - break; - } - check_level_irqs(); + m_icr = (m_icr & (0xff << (8*offset))) | (data << (8*offset)); + logerror("icr %d = %02x\n", offset, data); } const int h8h_intc_device::vector_to_slot[64] = { -1, -1, -1, -1, -1, -1, -1, -1, // NMI at 7 -1, -1, -1, -1, 0, 1, 2, 2, // IRQ 0-3 - 3, 3, 3, 3, 4, 4, 4, 4, // IRQ 4-5, (reservedx2), WOVI, CMI, (reserved), ADI - 5, 5, 5, 5, 6, 6, 6, 6, // IMIA0, IMIB0, OVI0, (reserved), IMIA1, IMIB1, OVI1, (reserved) - 7, 7, 7, 7, 8, 8, 8, 8, // IMIA2, IMIB2, OVI2, (reserved), CMIA0, CMIB0, CMIx1, TOVI0/1 - 9, 9, 9, 9, 10, 10, 10, 10, // CMIA2, CMIB2, CMIx3, TOVI2/3, DEND0A, DEND0B, DEND1A, DEND1B + 3, 3, 3, 3, 4, 4, 4, 4, // IRQ 4-5, (reservedx2), WOVI, CMI, (reserved), ADI + 5, 5, 5, 5, 6, 6, 6, 6, // IMIA0, IMIB0, OVI0, (reserved), IMIA1, IMIB1, OVI1, (reserved) + 7, 7, 7, 7, 8, 8, 8, 8, // IMIA2, IMIB2, OVI2, (reserved), CMIA0, CMIB0, CMIx1, TOVI0/1 + 9, 9, 9, 9, 10, 10, 10, 10, // CMIA2, CMIB2, CMIx3, TOVI2/3, DEND0A, DEND0B, DEND1A, DEND1B 11, 11, 11, 11, 12, 12, 12, 12, // (reservedx4), ERI0, RXI0, TXI0, TEI0 13, 13, 13, 13, 14, 14, 14, 14 // ERI1, RXI1, TXI1, TEI1, ERI2, RXI2, TXI2, TEI2 }; @@ -315,48 +338,92 @@ void h8h_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const return; } - icr_pri = (icr >> (slot ^ 7)) & 1; + icr_pri = (m_icr >> (slot ^ 7)) & 1; } -h8s_intc_device::h8s_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + +// H8S + +h8s_intc_device::h8s_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : h8h_intc_device(mconfig, H8S_INTC, tag, owner, clock) { - irq_vector_base = 16; - irq_vector_nmi = 7; + m_irq_vector_base = 16; + m_irq_vector_count = 8; + m_irq_vector_nmi = 7; +} + +void h8s_intc_device::device_start() +{ + h8h_intc_device::device_start(); + save_item(NAME(m_ipr)); } void h8s_intc_device::device_reset() { h8h_intc_device::device_reset(); - memset(ipr, 0x77, sizeof(ipr)); + memset(m_ipr, 0x77, sizeof(m_ipr)); } -READ8_MEMBER(h8s_intc_device::ipr_r) +u8 h8s_intc_device::ipr_r(offs_t offset) { - return ipr[offset]; + return m_ipr[offset]; } -WRITE8_MEMBER(h8s_intc_device::ipr_w) +void h8s_intc_device::ipr_w(offs_t offset, u8 data) { - ipr[offset] = data; + m_ipr[offset] = data; logerror("ipr %d = %02x\n", offset, data); } -READ8_MEMBER(h8s_intc_device::iprk_r) +u8 h8s_intc_device::iscrh_r() +{ + return m_iscr >> 8; +} + +void h8s_intc_device::iscrh_w(u8 data) +{ + m_iscr = (m_iscr & 0x00ff) | (data << 8); + logerror("iscr = %04x\n", m_iscr); + update_irq_types(); +} + +u8 h8s_intc_device::iscrl_r() +{ + return m_iscr; +} + +void h8s_intc_device::iscrl_w(u8 data) { - return ipr_r(space, 10, mem_mask); + m_iscr = (m_iscr & 0xff00) | data; + logerror("iscr = %04x\n", m_iscr); + update_irq_types(); } -WRITE8_MEMBER(h8s_intc_device::iprk_w) +void h8s_intc_device::update_irq_types() { - ipr_w(space, 10, data, mem_mask); + for(int i = 0; i < m_irq_vector_count; i++) + switch((m_iscr >> (2*i)) & 3) { + case 0: + m_irq_type[i] = LEVEL_LOW; + break; + case 1: + m_irq_type[i] = EDGE_FALL; + break; + case 2: + m_irq_type[i] = EDGE_RISE; + break; + case 3: + m_irq_type[i] = EDGE_DUAL; + break; + } + check_level_irqs(true); } const int h8s_intc_device::vector_to_slot[92] = { -1, -1, -1, -1, -1, -1, -1, -1, // NMI at 7 -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 2, 3, 3, 4, 4, // IRQ 0-7 - 5, 6, 7, 8, 9, 9, 9, 9, // SWDTEND, WOVI, CMI, (reserved), ADI + 0, 1, 2, 2, 3, 3, 4, 4, // IRQ 0-7 + 5, 6, 7, 8, 9, 9, 9, 9, // SWDTEND, WOVI, CMI, (reserved), ADI 10, 10, 10, 10, 10, 10, 10, 10, // TGI0A, TGI0B, TGI0C, TGI0D, TGI0V 11, 11, 11, 11, 12, 12, 12, 12, // TGI1A, TGI1B, TGI1V, TGI1U, TGI2A, TGI2B, TGI2V, TGI2U 13, 13, 13, 13, 13, 13, 13, 13, // TGI3A, TGI3B, TGI3C, TGI3D, TGI3V @@ -381,6 +448,30 @@ void h8s_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const return; } - icr_pri = (icr >> (slot ^ 7)) & 1; - ipr_pri = (ipr[slot >> 1] >> (slot & 1 ? 4 : 0)) & 7; + icr_pri = (m_icr >> (slot ^ 7)) & 1; + ipr_pri = (m_ipr[slot >> 1] >> (slot & 1 ? 0 : 4)) & 7; +} + + +// GT913 + +gt913_intc_device::gt913_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + h8_intc_device(mconfig, GT913_INTC, tag, owner, clock) +{ + m_irq_vector_base = 4; + m_irq_vector_count = 1; + m_irq_vector_nmi = 3; +} + +void gt913_intc_device::device_reset() +{ + h8_intc_device::device_reset(); + + m_ier = 0x01; +} + +void gt913_intc_device::clear_interrupt(int vector) +{ + m_pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); + update_irq_state(); } |