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::execute_run() { do { if (m_dma_cycles_to_burn > 0) { if (m_dma_cycles_to_burn < 4) { cycles_passed(m_dma_cycles_to_burn); m_dma_cycles_to_burn = 0; } else { cycles_passed(4); m_dma_cycles_to_burn -= 4; } } else { if ( m_execution_state ) { uint8_t x; /* Execute instruction */ switch( m_op ) { #include "opc_main.hxx" default: // actually this should lock up the cpu! logerror("LR35902: Illegal opcode $%02X @ %04X\n", m_op, m_PC); break; } } else { /* Fetch and count cycles */ bool was_halted = (m_enable & HALTED); check_interrupts(); debugger_instruction_hook(m_PC); if ( m_enable & HALTED ) { cycles_passed(m_has_halt_bug ? 2 : 4); m_execution_state = 1; m_entering_halt = false; } else { if (was_halted) { m_PC++; } else { m_op = mem_read_byte( m_PC++ ); } } } m_execution_state ^= 1; } } while (m_icount > 0); }
void lr35902_cpu_device::execute_run() { do { if ( m_execution_state ) { UINT8 x; /* Execute instruction */ switch( m_op ) { #include "opc_main.h" } } else { /* Fetch and count cycles */ check_interrupts(); debugger_instruction_hook(this, m_PC); if ( m_enable & HALTED ) { cycles_passed( 4 ); m_execution_state = 1; } else { m_op = mem_read_byte( m_PC++ ); if ( m_doHALTbug ) { m_PC--; m_doHALTbug = 0; } } } m_execution_state ^= 1; } while (m_icount > 0); }
void lr35902_cpu_device::execute_run() { do { if ( m_execution_state ) { UINT8 x; /* Execute instruction */ switch( m_op ) { #include "opc_main.inc" default: // actually this should lock up the cpu! logerror("LR35902: Illegal opcode $%02X @ %04X\n", m_op, m_PC); break; } } else { /* Fetch and count cycles */ check_interrupts(); debugger_instruction_hook(this, m_PC); if ( m_enable & HALTED ) { cycles_passed( 4 ); m_execution_state = 1; } else { m_op = mem_read_byte( m_PC++ ); if ( m_handle_halt_bug ) { m_PC--; m_handle_halt_bug = false; } } } m_execution_state ^= 1; } while (m_icount > 0); }
inline void lr35902_cpu_device::mem_write_byte( UINT16 addr, UINT8 data ) { m_program->write_byte( addr, data ); cycles_passed( 4 ); }
inline UINT8 lr35902_cpu_device::mem_read_byte( UINT16 addr ) { UINT8 data = m_program->read_byte( addr ); cycles_passed( 4 ); return data; }
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; } } } } }
inline void lr35902_cpu_device::mem_write_byte( uint16_t addr, uint8_t data ) { m_program->write_byte( addr, data ); cycles_passed( 4 ); }
inline uint8_t lr35902_cpu_device::mem_read_byte( uint16_t addr ) { uint8_t data = m_program->read_byte( addr ); cycles_passed( 4 ); return data; }