diff options
Diffstat (limited to 'src/devices/cpu/h8/h8_intc.cpp')
-rw-r--r-- | src/devices/cpu/h8/h8_intc.cpp | 295 |
1 files changed, 176 insertions, 119 deletions
diff --git a/src/devices/cpu/h8/h8_intc.cpp b/src/devices/cpu/h8/h8_intc.cpp index a2fdcdd7cfc..4598327bb72 100644 --- a/src/devices/cpu/h8/h8_intc.cpp +++ b/src/devices/cpu/h8/h8_intc.cpp @@ -1,5 +1,12 @@ // license:BSD-3-Clause // copyright-holders:Olivier Galibert +/*************************************************************************** + + h8_intc.cpp + + H8 interrupt controllers family + +***************************************************************************/ #include "emu.h" #include "h8_intc.h" @@ -8,11 +15,12 @@ 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, uint32_t clock) : +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) { m_irq_vector_base = 4; @@ -20,9 +28,9 @@ h8_intc_device::h8_intc_device(const machine_config &mconfig, const char *tag, d 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), m_irq_vector_base(0), m_irq_vector_count(0), m_irq_vector_nmi(0), - m_cpu(*this, finder_base::DUMMY_TAG), 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) +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) { } @@ -31,6 +39,7 @@ void h8_intc_device::device_start() 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)); @@ -42,10 +51,12 @@ void h8_intc_device::device_start() void h8_intc_device::device_reset() { - memset(m_irq_type, 0, sizeof(m_irq_type)); + 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_ier = m_isr = m_irq_input = 0x00; m_iscr = 0x0000; + m_ier = m_isr = 0x00; + check_level_irqs(false); } int h8_intc_device::interrupt_taken(int vector) @@ -55,8 +66,9 @@ int h8_intc_device::interrupt_taken(int vector) 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; - if(m_irq_type[irq] != IRQ_LEVEL || !(m_irq_input & (1 << irq))) - m_isr &= ~(1 << irq); + u8 mask = 1 << irq; + if(m_irq_type[irq] != LEVEL_LOW || !(m_irq_input & mask)) + m_isr &= ~mask; update_irq_state(); return irq; } @@ -79,24 +91,38 @@ 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 && !m_nmi_input) - m_pending_irqs[0] |= 1 << m_irq_vector_nmi; + 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; - update_irq_state(); + if(set && machine().time() > attotime::zero) { + m_pending_irqs[0] |= 1 << m_irq_vector_nmi; + update_irq_state(); + } } else { bool set = false; - bool cur = m_irq_input & (1 << inputnum); + u8 mask = 1 << inputnum; + u8 cur = m_irq_input & mask; switch(m_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; + 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) - m_irq_input |= 1 << inputnum; + m_irq_input |= mask; else - m_irq_input &= ~(1 << inputnum); + m_irq_input &= ~mask; if(set) { - m_isr |= 1 << inputnum; + m_isr |= mask; update_irq_state(); } } @@ -109,40 +135,39 @@ void h8_intc_device::set_filter(int icr_filter, int ipr_filter) update_irq_state(); } -uint8_t h8_intc_device::ier_r() +u8 h8_intc_device::ier_r() { return m_ier; } -void h8_intc_device::ier_w(uint8_t data) +void h8_intc_device::ier_w(u8 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", m_irq_input); - bool update = force_update; - for(int i=0; i<8; i++) { - unsigned char mask = 1 << i; - if(m_irq_type[i] == IRQ_LEVEL && (m_irq_input & mask) && !(m_isr & mask)) { + 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; - update = true; + set = true; } } - if(update) + if(set && update) update_irq_state(); } -uint8_t h8_intc_device::iscr_r() +u8 h8_intc_device::iscr_r() { return m_iscr; } -void h8_intc_device::iscr_w(uint8_t data) +void h8_intc_device::iscr_w(u8 data) { m_iscr = data; logerror("iscr = %02x\n", m_iscr); @@ -151,22 +176,24 @@ void h8_intc_device::iscr_w(uint8_t data) void h8_intc_device::update_irq_types() { - for(int i=0; i<8; i++) - switch((m_iscr >> (i)) & 1) { + for(int i = 0; i < m_irq_vector_count; i++) + switch((m_iscr >> i) & 1) { case 0: - m_irq_type[i] = IRQ_LEVEL; + m_irq_type[i] = LEVEL_LOW; break; case 1: - m_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() { if(m_irq_vector_count > 0) { - const unsigned mask = (1 << m_irq_vector_count) - 1; + 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; @@ -175,10 +202,10 @@ void h8_intc_device::update_irq_state() int cur_vector = 0; int cur_level = -1; - for(int i=0; i<MAX_VECTORS/32; i++) { - unsigned int pending = m_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; @@ -202,29 +229,41 @@ void h8_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const } -gt913_intc_device::gt913_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - h8_intc_device(mconfig, GT913_INTC, tag, owner, clock) +// H8/325 + +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) { m_irq_vector_base = 4; - m_irq_vector_count = 1; + m_irq_vector_count = 3; m_irq_vector_nmi = 3; } -void gt913_intc_device::device_reset() +void h8325_intc_device::update_irq_types() { - h8_intc_device::device_reset(); - - m_ier = 0x01; + 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); } -void gt913_intc_device::clear_interrupt(int vector) -{ - m_pending_irqs[vector >> 5] &= ~(1 << (vector & 31)); - update_irq_state(); -} +// H8H -h8h_intc_device::h8h_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : +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) { m_irq_vector_base = 12; @@ -232,7 +271,7 @@ h8h_intc_device::h8h_intc_device(const machine_config &mconfig, const char *tag, m_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) : +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) { } @@ -241,6 +280,7 @@ void h8h_intc_device::device_start() { h8_intc_device::device_start(); save_item(NAME(m_icr)); + m_has_isr = true; } void h8h_intc_device::device_reset() @@ -249,80 +289,30 @@ void h8h_intc_device::device_reset() m_icr = 0x000000; } -uint8_t h8h_intc_device::isr_r() +u8 h8h_intc_device::isr_r() { return m_isr; } -void h8h_intc_device::isr_w(uint8_t data) +void h8h_intc_device::isr_w(u8 data) { m_isr &= data; // edge/level - logerror("isr = %02x / %02x\n", data, m_isr); - check_level_irqs(true); + //logerror("isr = %02x / %02x\n", data, m_isr); + check_level_irqs(false); + update_irq_state(); } -uint8_t h8h_intc_device::icr_r(offs_t offset) +u8 h8h_intc_device::icr_r(offs_t offset) { return m_icr >> (8*offset); } -void h8h_intc_device::icr_w(offs_t offset, uint8_t data) +void h8h_intc_device::icr_w(offs_t offset, u8 data) { m_icr = (m_icr & (0xff << (8*offset))) | (data << (8*offset)); logerror("icr %d = %02x\n", offset, data); } -uint8_t h8h_intc_device::icrc_r() -{ - return icr_r(2); -} - -void h8h_intc_device::icrc_w(uint8_t data) -{ - icr_w(2, data); -} - -uint8_t h8h_intc_device::iscrh_r() -{ - return m_iscr >> 8; -} - -void h8h_intc_device::iscrh_w(uint8_t data) -{ - m_iscr = (m_iscr & 0x00ff) | (data << 8); - logerror("iscr = %04x\n", m_iscr); - update_irq_types(); -} - -uint8_t h8h_intc_device::iscrl_r() -{ - return m_iscr; -} - -void h8h_intc_device::iscrl_w(uint8_t data) -{ - m_iscr = (m_iscr & 0xff00) | data; - logerror("iscr = %04x\n", m_iscr); - update_irq_types(); -} - -void h8h_intc_device::update_irq_types() -{ - for(int i=0; i<8; i++) - switch((m_iscr >> (2*i)) & 3) { - case 0: - m_irq_type[i] = IRQ_LEVEL; - break; - case 1: case 2: - m_irq_type[i] = IRQ_EDGE; - break; - case 3: - m_irq_type[i] = IRQ_DUAL_EDGE; - break; - } - check_level_irqs(); -} - 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 @@ -351,7 +341,10 @@ void h8h_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const 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) { m_irq_vector_base = 16; @@ -359,38 +352,78 @@ h8s_intc_device::h8s_intc_device(const machine_config &mconfig, const char *tag, 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(m_ipr, 0x77, sizeof(m_ipr)); } -uint8_t h8s_intc_device::ipr_r(offs_t offset) +u8 h8s_intc_device::ipr_r(offs_t offset) { return m_ipr[offset]; } -void h8s_intc_device::ipr_w(offs_t offset, uint8_t data) +void h8s_intc_device::ipr_w(offs_t offset, u8 data) { m_ipr[offset] = data; logerror("ipr %d = %02x\n", offset, data); } -uint8_t h8s_intc_device::iprk_r() +u8 h8s_intc_device::iscrh_r() { - return ipr_r(10); + return m_iscr >> 8; } -void h8s_intc_device::iprk_w(uint8_t data) +void h8s_intc_device::iscrh_w(u8 data) { - ipr_w(10, 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) +{ + m_iscr = (m_iscr & 0xff00) | data; + logerror("iscr = %04x\n", m_iscr); + update_irq_types(); +} + +void h8s_intc_device::update_irq_types() +{ + 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 @@ -418,3 +451,27 @@ void h8s_intc_device::get_priority(int vect, int &icr_pri, int &ipr_pri) const 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(); +} |