void lr35902_cpu_device::check_interrupts() { UINT8 irq = m_IE & m_IF; /* Interrupts should be taken after the first instruction after an EI instruction */ if (m_ei_delay) { m_ei_delay = 0; return; } /* logerror("Attempting to process LR35902 Interrupt IRQ $%02X\n", irq); logerror("Attempting to process LR35902 Interrupt IE $%02X\n", m_IE); logerror("Attempting to process LR35902 Interrupt IF $%02X\n", m_IF); */ if (irq) { int irqline = 0; /* logerror("LR35902 Interrupt IRQ $%02X\n", irq); */ for( ; irqline < 5; irqline++ ) { if( irq & (1<<irqline) ) { if (m_enable & HALTED) { m_enable &= ~HALTED; m_PC++; if ( m_features & LR35902_FEATURE_HALT_BUG ) { if ( ! ( m_enable & IME ) ) { /* Old cpu core (dmg/mgb/sgb) */ m_doHALTbug = 1; } } else { /* New cpu core (cgb/agb/ags) */ /* Adjust for internal syncing with video core */ /* This feature needs more investigation */ if ( irqline < 2 ) { cycles_passed( 4 ); } } } if ( m_enable & IME ) { m_enable &= ~IME; m_IF &= ~(1 << irqline); cycles_passed( 12 ); m_SP -= 2; mem_write_word( m_SP, m_PC ); m_PC = 0x40 + irqline * 8; /*logerror("LR35902 Interrupt PC $%04X\n", m_PC );*/ return; } } } } }
void lr35902_cpu_device::check_interrupts() { uint8_t irq = m_IE & m_IF; /* Interrupts should be taken after the first instruction after an EI instruction */ if (m_handle_ei_delay) { m_handle_ei_delay = false; return; } /* logerror("Attempting to process LR35902 Interrupt IRQ $%02X\n", irq); logerror("Attempting to process LR35902 Interrupt IE $%02X\n", m_IE); logerror("Attempting to process LR35902 Interrupt IF $%02X\n", m_IF); */ if (irq) { int irqline = 0; /* logerror("LR35902 Interrupt IRQ $%02X\n", irq); */ bool was_halted = (m_enable & HALTED); for( ; irqline < 5; irqline++ ) { if( irq & (1<<irqline) ) { if (m_enable & HALTED) { m_enable &= ~HALTED; m_PC++; // In general there seems to be a 4 cycle delay to leave the halt state; except when the // trigger is caused by the VBlank interrupt (on DMG/MGB/SGB?/SGB2?). // // On CGB/AGB/AGS this delay to leave the halt seems to always be 4 cycles. // if ( m_has_halt_bug ) { if ( ! ( m_enable & IME ) ) { /* Old cpu core (dmg/mgb/sgb) */ m_PC--; } // TODO: Properly detect when the delay should be skipped. Cases seen so far: // - Vblank irq // - STAT mode 1 irq (triggered at same time as vblank) // - STAT mode 2 irq (8 cycles?, breaks gambatte halt/m2irq_ly tests when always applied but fix other gambatte halt/m2irq and halt/m2int cases) // No delay: // - LY=LYC irq // STAT and not vblank just triggered (this on dmg/mgb/sgb only)? or Timer IRQ // // This is a bit hacky, more testing is needed to determine exact // hardware behavior. if ((irqline == 1 && !(m_IF & 0x01)) || irqline == 2) { // Cycles needed for leaving the halt state cycles_passed(4); if (irqline == 2) { cycles_passed(2); } } } else { /* New cpu core (cgb/agb/ags) */ // Leaving halt state seems to take 4 cycles. cycles_passed(4); if (!(m_enable & IME) && !m_entering_halt) { cycles_passed(4); } } } if ( m_enable & IME ) { m_enable &= ~IME; m_IF &= ~(1 << irqline); cycles_passed( 12 ); m_SP -= 2; mem_write_word( m_SP, m_PC ); m_PC = 0x40 + irqline * 8; /*logerror("LR35902 Interrupt PC $%04X\n", m_PC );*/ if (was_halted) { m_op = mem_read_byte( m_PC ); } return; } } } } }