Example #1
0
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;
				}
			}
		}
	}
}
Example #2
0
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);
}
Example #3
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);
}
Example #4
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);
}
Example #5
0
inline void lr35902_cpu_device::mem_write_byte( UINT16 addr, UINT8 data )
{
	m_program->write_byte( addr, data );
	cycles_passed( 4 );
}
Example #6
0
inline UINT8 lr35902_cpu_device::mem_read_byte( UINT16 addr )
{
	UINT8 data = m_program->read_byte( addr );
	cycles_passed( 4 );
	return data;
}
Example #7
0
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;
				}
			}
		}
	}
}
Example #8
0
inline void lr35902_cpu_device::mem_write_byte( uint16_t addr, uint8_t data )
{
	m_program->write_byte( addr, data );
	cycles_passed( 4 );
}
Example #9
0
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;
}