/*---------------------------------------------------------------------------* Project: CtrBrom - libraries - OS File: os_interrupt.c Copyright 2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: $ $Rev$ $Author$ *---------------------------------------------------------------------------*/ #include #ifdef SDK_ARM11 OSIntrFunction osIntrTable[OS_INTR_ID_NUM]; #else // SDK_ARM9 OSIntrFunction osIntrTable[OS_INTR_ID_NUM] ATTRIBUTE_SECTION(.dtcm); #endif // SDK_ARM9 void osIrqHandler( void ); /*---------------------------------------------------------------------------* Name: osInitInterrupt Description: Initialize Interrupts Arguments: None Returns: None *---------------------------------------------------------------------------*/ void osInitInterrupt( void ) { static BOOL isInit; if ( isInit == FALSE ) { isInit = TRUE; (void)osDisableIrqAndFiq(); i_osInitInterruptTable(); *(OSIntrHandler*)HW_INTR_VECTOR_BUF = osIrqHandler; #ifdef SDK_ARM11 reg_OS_CPUI_CNT = 0; reg_OS_IDR_CNT = 0; { u32 num = OS_INTR_ID_NUM; u32 conf = 0; u32 ack; int i; for ( i=0; i /*---------------------------------------------------------------------------* Name: osEnableIrq Description: Set CPSR to enable irq interrupt Arguments: None. Returns: last state of HW_PSR_IRQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osEnableIrq( void ) { mrs r0, cpsr #ifdef SDK_USE_MPCORE_EXTEND_OP cpsie i #else bic r1, r0, #HW_PSR_IRQ_DISABLE msr cpsr_c, r1 #endif and r0, r0, #HW_PSR_IRQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osDisableIrq Description: Set CPSR to disable irq interrupt Arguments: None. Returns: last state of HW_PSR_IRQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osDisableIrq( void ) { mrs r0, cpsr #ifdef SDK_USE_MPCORE_EXTEND_OP cpsid i #else orr r1, r0, #HW_PSR_IRQ_DISABLE msr cpsr_c, r1 #endif and r0, r0, #HW_PSR_IRQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osRestoreIrq Description: Restore CPSR irq interrupt Arguments: state of irq and fiq interrupt bit Returns: last state of HW_PSR_IRQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osRestoreIrq( OSIntrMode state ) { mrs r1, cpsr bic r2, r1, #HW_PSR_IRQ_DISABLE orr r2, r2, r0 msr cpsr_c, r2 and r0, r1, #HW_PSR_IRQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osEnableFiq Description: Set CPSR to enable fiq interrupt Arguments: None. Returns: last state of HW_PSR_FIQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osEnableFiq( void ) { mrs r0, cpsr #ifdef SDK_USE_MPCORE_EXTEND_OP cpsie f #else bic r1, r0, #HW_PSR_FIQ_DISABLE msr cpsr_c, r1 #endif and r0, r0, #HW_PSR_FIQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osDisableFiq Description: Set CPSR to disable fiq interrupt Arguments: None. Returns: last state of HW_PSR_FIQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osDisableFiq( void ) { mrs r0, cpsr #ifdef SDK_USE_MPCORE_EXTEND_OP cpsid f #else orr r1, r0, #HW_PSR_FIQ_DISABLE msr cpsr_c, r1 #endif and r0, r0, #HW_PSR_FIQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osRestoreFiq Description: Restore CPSR fiq interrupt Arguments: state of fiq interrupt bit Returns: last state of HW_PSR_FIQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osRestoreFiq( OSIntrMode state ) { mrs r1, cpsr bic r2, r1, #HW_PSR_FIQ_DISABLE orr r2, r2, r0 msr cpsr_c, r2 and r0, r1, #HW_PSR_FIQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osEnableIrqAndFiq Description: Set CPSR to enable irq and fiq interrupts Arguments: None. Returns: last state of HW_PSR_IRQ_DISABLE & HW_PSR_FIQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osEnableIrqAndFiq( void ) { mrs r0, cpsr #ifdef SDK_USE_MPCORE_EXTEND_OP cpsie if #else bic r1, r0, #HW_PSR_IRQ_FIQ_DISABLE msr cpsr_c, r1 #endif and r0, r0, #HW_PSR_IRQ_FIQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osDisableIrqAndFiq Description: Set CPSR to disable irq and fiq interrupts Arguments: None. Returns: last state of HW_PSR_IRQ_DISABLE & HW_PSR_FIQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osDisableIrqAndFiq( void ) { mrs r0, cpsr #ifdef SDK_USE_MPCORE_EXTEND_OP cpsid if #else orr r1, r0, #HW_PSR_IRQ_FIQ_DISABLE msr cpsr_c, r1 #endif and r0, r0, #HW_PSR_IRQ_FIQ_DISABLE bx lr } /*---------------------------------------------------------------------------* Name: osRestoreIrqAndFiq Description: Restore CPSR irq and fiq interrupts Arguments: state of irq and fiq interrupt bit Returns: last state of HW_PSR_IRQ_DISABLE & HW_PSR_FIQ_DISABLE *---------------------------------------------------------------------------*/ ASM OSIntrMode osRestoreIrqAndFiq( OSIntrMode state ) { mrs r1, cpsr bic r2, r1, #HW_PSR_IRQ_FIQ_DISABLE orr r2, r2, r0 msr cpsr_c, r2 and r0, r1, #HW_PSR_IRQ_FIQ_DISABLE bx lr } #include //================================================================================ // InterruptMask //================================================================================ /*---------------------------------------------------------------------------* Name: osEnableInterruptID Description: set Interrupt Set Enable Register Arguments: Interrupt Distributor ID Returns: TRUE if last state is enabled *---------------------------------------------------------------------------*/ BOOL osEnableInterruptID( OSIntrID id ) { BOOL retval; OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; retval = TRUE & (reg_OS_IDR_SET_IE[ofs] >> sft); reg_OS_IDR_SET_IE[ofs] = 1 << sft; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IE; retval = TRUE & (BOOL)(prep >> id); reg_OS_IE = prep | (1 << id); #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return retval; } /*---------------------------------------------------------------------------* Name: osEnableInterruptMask Description: set specified interrupt factor Arguments: mask interrupt factor Returns: previous factors *---------------------------------------------------------------------------*/ OSIntrMask osEnableInterruptMask( OSIntrMask mask ) { OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 OSIntrMask prep = reg_OS_IDR_SET_IE_ALL; reg_OS_IDR_SET_IE_ALL = mask; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IE; reg_OS_IE = prep | mask; #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return prep; } /*---------------------------------------------------------------------------* Name: osDisableInterruptID Description: set Interrupt Clear Enable Register Arguments: Interrupt Distributor ID Returns: TRUE if last state is enabled *---------------------------------------------------------------------------*/ BOOL osDisableInterruptID( OSIntrID id ) { BOOL retval; OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; retval = TRUE & (reg_OS_IDR_SET_IE[ofs] >> sft); reg_OS_IDR_CLR_IE[ofs] = 1 << sft; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IE; retval = TRUE & (BOOL)(prep >> id); reg_OS_IE = prep & ~(1 << id); #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return retval; } /*---------------------------------------------------------------------------* Name: osDisableInterruptMask Description: unset specified interrupt factor Arguments: mask interrupt factor Returns: previous factors *---------------------------------------------------------------------------*/ OSIntrMask osDisableInterruptMask( OSIntrMask mask ) { OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 OSIntrMask prep = reg_OS_IDR_SET_IE_ALL; reg_OS_IDR_CLR_IE_ALL = mask; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IE; reg_OS_IE = prep & ~mask; #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return prep; } /*---------------------------------------------------------------------------* Name: osRestoreInterruptID Description: set Interrupt Clear Enable Register Arguments: id : Interrupt Distributor ID state : state whether interrupt is enabled Returns: TRUE if last state is enabled *---------------------------------------------------------------------------*/ BOOL osRestoreInterruptID( OSIntrID id, BOOL state ) { BOOL retval; OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; retval = TRUE & (reg_OS_IDR_SET_IE[ofs] >> sft); if ( state == TRUE ) { reg_OS_IDR_SET_IE[ofs] = 1 << sft; } else { reg_OS_IDR_CLR_IE[ofs] = 1 << sft; } #else // SDK_ARM9 OSIntrMask prep = reg_OS_IE; retval = TRUE & (BOOL)(prep >> id); if ( state == TRUE ) { reg_OS_IE = prep | (state << id); } else { reg_OS_IE = prep & ~(state << id); } #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return retval; } /*---------------------------------------------------------------------------* Name: osSetInterruptMask Description: set interrupt factor Arguments: mask interrupt factor Returns: previous factors *---------------------------------------------------------------------------*/ OSIntrMask osSetInterruptMask( OSIntrMask mask ) { OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 OSIntrMask prep = reg_OS_IDR_SET_IE_ALL; reg_OS_IDR_CLR_IE[0] = HW_IDR_WORD_MASK; reg_OS_IDR_CLR_IE[1] = HW_IDR_WORD_MASK; reg_OS_IDR_CLR_IE[2] = HW_IDR_WORD_MASK; reg_OS_IDR_CLR_IE[3] = HW_IDR_WORD_MASK; reg_OS_IDR_SET_IE_ALL = mask; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IE; reg_OS_IE = mask; #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return prep; } //================================================================================ // INTERRUPT PENDING //================================================================================ /*---------------------------------------------------------------------------* Name: osClearInterruptPendingID Description: set Interrupt Clear Pending Register Arguments: Interrupt Distributor ID Returns: TRUE if last state is pending *---------------------------------------------------------------------------*/ BOOL osClearInterruptPendingID( OSIntrID id ) { OSIntrMode enabled = osDisableInterrupts(); BOOL retval; #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; retval = TRUE & (reg_OS_IDR_SET_PND[ofs] >> sft); reg_OS_IDR_CLR_PND[ofs] = 1 << sft; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IF; retval = TRUE & (BOOL)(prep >> id); reg_OS_IF = (u32)(1 << id); #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return retval; } /*---------------------------------------------------------------------------* Name: osClearInterruptPendingMask Description: reset IF bit (setting bit causes to clear bit for interrupt) Arguments: mask interrupt factor Returns: previous factors *---------------------------------------------------------------------------*/ OSIntrMask osClearInterruptPendingMask( OSIntrMask mask ) { OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 OSIntrMask prep = reg_OS_IDR_SET_PND_ALL; reg_OS_IDR_CLR_PND_ALL = mask; #else // SDK_ARM9 OSIntrMask prep = reg_OS_IF; reg_OS_IF = mask; #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); return prep; } #ifdef SDK_ARM11 /*---------------------------------------------------------------------------* Name: osSetInterruptPendingID Description: set Interrupt Set Pending Register Arguments: Interrupt Distributor ID Returns: TRUE if last state is pending *---------------------------------------------------------------------------*/ BOOL osSetInterruptPendingID( OSIntrID id ) { u32 ofs = id/32; u32 sft = id%32; BOOL retval; retval = TRUE & (reg_OS_IDR_SET_PND[ofs] >> sft); reg_OS_IDR_SET_PND[ofs] = 1 << sft; return retval; } /*---------------------------------------------------------------------------* Name: osRestoreInterruptPendingID Description: restore Interrupt Pending Arguments: id : Interrupt Distributor ID state : state whether interrupt is enabled Returns: TRUE if last state is pending *---------------------------------------------------------------------------*/ BOOL osRestoreInterruptPendingID( OSIntrID id, BOOL state ) { u32 ofs = id/32; u32 sft = id%32; BOOL retval; retval = TRUE & (reg_OS_IDR_SET_PND[ofs] >> sft); if ( state == TRUE ) { reg_OS_IDR_SET_PND[ofs] = 1 << sft; } else { reg_OS_IDR_CLR_PND[ofs] = 1 << sft; } return retval; } /*---------------------------------------------------------------------------* Name: osSetEndOfInterruptRegister Description: set ID to End of Interrupt Register change state to Inactive. Arguments: Interrupt Distributor ID Returns: None *---------------------------------------------------------------------------*/ void osSetEndOfInterruptRegister( OSIntrID id ) { reg_OS_CPUI_EOI = id; } /*---------------------------------------------------------------------------* Name: i_osReadHighestPendingInterruptRegister Description: read ID from Highest Pending Interrupt Register Arguments: None Returns: Interrupt Distributor ID *---------------------------------------------------------------------------*/ OSIntrID i_osReadHighestPendingInterruptRegister( void ) { return (OSIntrID)(reg_OS_CPUI_HI_PND & REG_OS_CPUI_HI_PND_ID_MASK); } /*---------------------------------------------------------------------------* Name: i_osReadInterruptAcknowledgeRegister Description: read ID from Interrupt Acknowledge Register get interrupt ID and change state to NotPending and Active. Arguments: None Returns: Interrupt Distributor ID *---------------------------------------------------------------------------*/ OSIntrID i_osReadInterruptAcknowledgeRegister( void ) { return (OSIntrID)(reg_OS_CPUI_ACK & REG_OS_CPUI_ACK_ID_MASK); } #endif // SDK_ARM11 /*---------------------------------------------------------------------------* Name: osIsInterruptPendingID Description: set Interrupt Clear Pending Register Arguments: Interrupt Distributor ID Returns: TRUE if last state is pending *---------------------------------------------------------------------------*/ BOOL osIsInterruptPendingID( OSIntrID id ) { BOOL retval; #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; retval = TRUE & (reg_OS_IDR_SET_PND[ofs] >> sft); #else // SDK_ARM9 retval = TRUE & (BOOL)(reg_OS_IF >> id); #endif // SDK_ARM9 return retval; } //================================================================================ // IRQ CHEKE BUFFER //================================================================================ /*---------------------------------------------------------------------------* Name: osSetInterruptCheckID Description: set irq flag to check being called Arguments: irq factors to be set Returns: None *---------------------------------------------------------------------------*/ BOOL osSetInterruptCheckID( OSIntrID id ) { BOOL retval; OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; u32 *buf = &((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[ofs]; #else // SDK_ARM9 u32 sft = id; u32 *buf = (OSIntrMask *)HW_INTR_CHECK_BUF; #endif // SDK_ARM9 retval = TRUE & (*buf >> sft); *buf |= 1 << sft; (void)osRestoreInterrupts( enabled ); return retval; } /*---------------------------------------------------------------------------* Name: osClearInterruptCheckID Description: clear irq flag stored in HW_INTR_CHECK_BUF Arguments: irq factors to be set Returns: None *---------------------------------------------------------------------------*/ BOOL osClearInterruptCheckID( OSIntrID id ) { BOOL retval; OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; u32 *buf = &((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[ofs]; #else // SDK_ARM9 u32 sft = id; u32 *buf = (OSIntrMask *)HW_INTR_CHECK_BUF; #endif // SDK_ARM9 retval = TRUE & (*buf >> sft); *buf &= ~(1 << sft); (void)osRestoreInterrupts( enabled ); return retval; } /*---------------------------------------------------------------------------* Name: osIsInterruptCheckID Description: check irq flag stored in HW_INTR_CHECK_BUF Arguments: irq factors to be set Returns: None *---------------------------------------------------------------------------*/ BOOL osIsInterruptCheckID( OSIntrID id ) { BOOL retval; #ifdef SDK_ARM11 u32 ofs = id/32; u32 sft = id%32; u32 *buf = &((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[ofs]; #else // SDK_ARM9 u32 sft = id; u32 *buf = (OSIntrMask *)HW_INTR_CHECK_BUF; #endif // SDK_ARM9 retval = TRUE & (*buf >> sft); return retval; } /*---------------------------------------------------------------------------* Name: osSetInterruptCheckMask Description: set irq flag to check being called Arguments: irq factors to be set Returns: None *---------------------------------------------------------------------------*/ void osSetInterruptCheckMask( OSIntrMask mask ) { OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[0] |= mask.w[0]; ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[1] |= mask.w[1]; ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[2] |= mask.w[2]; ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[3] |= mask.w[3]; #else // SDK_ARM9 *(OSIntrMask *)HW_INTR_CHECK_BUF |= mask; #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); } /*---------------------------------------------------------------------------* Name: osClearInterruptCheckMask Description: clear irq flag stored in HW_INTR_CHECK_BUF Arguments: irq factors to be cleared Returns: None *---------------------------------------------------------------------------*/ void osClearInterruptCheckMask( OSIntrMask mask ) { OSIntrMode enabled = osDisableInterrupts(); #ifdef SDK_ARM11 ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[0] &= ~mask.w[0]; ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[1] &= ~mask.w[1]; ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[2] &= ~mask.w[2]; ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[3] &= ~mask.w[3]; #else // SDK_ARM9 *(OSIntrMask *)HW_INTR_CHECK_BUF &= ~mask; #endif // SDK_ARM9 (void)osRestoreInterrupts( enabled ); } /*---------------------------------------------------------------------------* Name: osIsInterruptCheckMask Description: check irq flag stored in HW_INTR_CHECK_BUF Arguments: irq factors to be cleared Returns: TRUE if irq flag exists *---------------------------------------------------------------------------*/ BOOL osIsInterruptCheckMask( OSIntrMask mask ) { u32 tmp; #ifdef SDK_ARM11 OSIntrMode enabled = osDisableInterrupts(); tmp = ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[0] & mask.w[0]; tmp |= ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[1] & mask.w[1]; tmp |= ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[2] & mask.w[2]; tmp |= ((OSIntrMask *)HW_INTR_CHECK0_BUF)->w[3] & mask.w[3]; (void)osRestoreInterrupts( enabled ); #else // SDK_ARM9 tmp = osGetInterruptCheckMask() & mask; #endif // SDK_ARM9 return tmp ? TRUE : FALSE; } //============================================================================ // WAIT //============================================================================ /*---------------------------------------------------------------------------* Name: osWaitInterruptID Description: wait specifiled interrupt. OS_WaitInterrupt doesn't switch thread. OS_WaitInterrupt wait by using OS_Halt(). Arguments: clear TRUE if want to clear interrupt flag before wait. FALSE if not. irqFlags bit of interrupts to wait for Returns: None *---------------------------------------------------------------------------*/ void osWaitInterruptID( BOOL clear, OSIntrID id ) { OSIntrMode cpsrIrq = osDisableInterrupts(); if (clear) { (void)osClearInterruptCheckID( id ); } while (! osIsInterruptCheckID(id) ) { osHalt(); (void)osEnableInterrupts(); (void)osDisableInterrupts(); } (void)osClearInterruptCheckID( id ); (void)osRestoreInterrupts( cpsrIrq ); } /*---------------------------------------------------------------------------* Name: osWaitInterruptMask Description: wait specifiled interrupt. OS_WaitInterrupt doesn't switch thread. OS_WaitInterrupt wait by using OS_Halt(). Arguments: clear TRUE if want to clear interrupt flag before wait. FALSE if not. irqFlags bit of interrupts to wait for Returns: None *---------------------------------------------------------------------------*/ void osWaitInterruptMask( BOOL clear, OSIntrMask irqFlags ) { OSIntrMode cpsrIrq = osDisableInterrupts(); if (clear) { (void)osClearInterruptCheckMask( irqFlags ); } while (! osIsInterruptCheckMask(irqFlags) ) { osHalt(); (void)osEnableInterrupts(); (void)osDisableInterrupts(); } (void)osClearInterruptCheckMask( irqFlags ); (void)osRestoreInterrupts( cpsrIrq ); }