/*---------------------------------------------------------------------------* Project: CtrBrom - libraries - OS File: os_irqHandler.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 #include //#define BROM_ENABLE_THREAD #ifdef SDK_ARM9 #include #endif //---- thread queue for interrupt OSThreadQueue i_osIrqThreadQueue; #ifdef SDK_ARM9 #include #include #endif extern OSIntrFunction osIntrTable[OS_INTR_ID_NUM]; /*---------------------------------------------------------------------------* Name: osIrqHandler Description: IRQ handler. call handler according to OS_InterruptTable Arguments: None Returns: None *---------------------------------------------------------------------------*/ asm void osIrqHandler( void ) { PRESERVE8 INASM_EXTERN( osIntrTable ) #ifdef SDK_ARM11 // 不正確データアボート有効化(clear HW_PSR_IMPRECISE_ABORT) msr cpsr_fsxc, #(HW_PSR_IRQ_MODE | HW_PSR_IRQ_DISABLE | HW_PSR_FIQ_DISABLE) #endif // SDK_ARM11 stmfd sp!, { r0-r4,r12,lr } // 割り込み要因の判定. #ifdef SDK_ARM11 // Interrupt Acknowledge Register ldr lr, =REG_CPUI_ACK_ADDR ldr lr, [lr] ldr r1, =REG_OS_CPUI_ACK_ID_MASK and r4, r1, lr // r4に割り込み要因番号が入ってる cmp r4, #__cpp(OS_INTR_ID_NUM) bge my_undefined_interrupt_1 #else // SDK_ARM9 // get IE address mov r12, #HW_REG_BASE add r12, r12, #REG_IE_OFFSET // r12: REG_IE address // get IE&IF ldmia r12, { r1-r2 } // r1: IE, r2: IF ands r1, r1, r2 // r1: IE & IF //-------------------------------------------------- // IRQ HANDLING CODE for ARCHITECTURE VERSION 5 //-------------------------------------------------- // get lowest 1 bit mov r3, #1<<31 LSYM(1) clz r0, r1 // count zero of high bit bics r1, r1, r3, LSR r0 bne BSYM(1) // clear IF mov r1, r3, LSR r0 str r1, [ r12, #REG_IF_ADDR - REG_IE_ADDR ] rsbs r4, r0, #31 #endif // SDK_ARM9 // get jump vector ldr r1, =osIntrTable ldr r0, [ r1, r4, LSL #2 ] blx r0 // set return address for thread rescheduling #ifdef SDK_ARM11 // End of Interrupt Register ldr lr, =REG_CPUI_EOI_ADDR str r4, [lr] #endif // SDK_ARM11 #ifdef BROM_ENABLE_THREAD bl osIrqHandler_ThreadSwitch #endif // BROM_ENABLE_THREAD my_undefined_interrupt_1 ldmfd sp!, { r0-r4,r12,lr } // return to interrupted address subs pc, lr, #4 } #ifdef BROM_ENABLE_THREAD /*---------------------------------------------------------------------------* Name: OS_IRQHandler_ThreadSwitch Description: 割り込み分岐処理(テーブル OS_InterruptTable 引き) Arguments: なし Returns: なし *---------------------------------------------------------------------------*/ asm void osIrqHandler_ThreadSwitch(void) { INASM_EXTERN( i_osIrqThreadQueue ) INASM_EXTERN( i_osThreadInfo ) INASM_EXTERN( i_osSaveContextVFP ) INASM_EXTERN( i_osLoadContextVFP ) //-------------------------------------------------- // wakeup threads in i_osIrqThreadQueue //-------------------------------------------------- ldr r12, =i_osIrqThreadQueue mov r3, #0 // avoid stall ldr r12, [r12, #__cpp(offsetof(OSThreadQueue,head))] // r12 = i_osIrqThreadQueue.head mov r2, #__cpp(OS_THREAD_STATE_READY) // avoid stall cmp r12, #0 beq thread_switch // if r12 == 0 exit LSYM(1) str r2, [r12, #__cpp(offsetof(OSThread,state))] str r3, [r12, #__cpp(offsetof(OSThread,queue))] str r3, [r12, #__cpp(offsetof(OSThread,link.prev))] ldr r0, [r12, #__cpp(offsetof(OSThread,link.next))] str r3, [r12, #__cpp(offsetof(OSThread,link.next))] mov r12, r0 cmp r12, #0 bne BSYM(1) ldr r12, =i_osIrqThreadQueue str r3, [r12, #__cpp(offsetof(OSThreadQueue,head))] // clear i_osIrqThreadQueue.head str r3, [r12, #__cpp(offsetof(OSThreadQueue,tail))] // clear i_osIrqThreadQueue.tail ldr r12, =i_osThreadInfo // need to do scheduling mov r1, #1 strh r1, [ r12, #OS_THREADINFO_OFFSET_ISNEEDRESCHEDULING ] thread_switch //-------------------------------------------------- // THREAD SWITCH //-------------------------------------------------- // pseudo code // // if ( isNeedRescheduling == FALSE ) return; // isNeedRescheduling = FALSE; // // // OS_SelectThread // OSThread* t = i_osThreadInfo.list; // while( t && ! OS_IsThreadRunnable( t ) ){ t = t->next; } // return t; // // select: // current = CurrentThread; // if ( next == current ) return; // CurrentThread = next; // OS_SaveContext( current ); // OS_LoadContext( next ); // // [[[ new OS_SelectThread ]]] ldr r12, =i_osThreadInfo ldrh r1, [ r12, #OS_THREADINFO_OFFSET_ISNEEDRESCHEDULING ] cmp r1, #0 beq _dont_switched_ // return if i_osIsNeedResceduling == 0 mov r1, #0 strh r1, [ r12, #OS_THREADINFO_OFFSET_ISNEEDRESCHEDULING ] // ---- OS_SelectThread (disable FIQ to support IS-Debugger snooping thread information) mov r3, #HW_PSR_IRQ_MODE|HW_PSR_FIQ_DISABLE|HW_PSR_IRQ_DISABLE|HW_PSR_ARM_STATE msr cpsr_c, r3 add r2, r12, #OS_THREADINFO_OFFSET_LIST // r2 = &i_osThreadInfo.list ldr r1, [r2] // r1 = *r2 = TopOfList LSYM(11) cmp r1, #0 ldrneh r0, [ r1, #__cpp(OS_THREAD_OFFSET_STATE) ] // r0 = t->state cmpne r0, #__cpp(OS_THREAD_STATE_READY) ldrne r1, [ r1, #__cpp(OS_THREAD_OFFSET_NEXT) ] bne BSYM(11) cmp r1, #0 bne FSYM(12) _dont_switched_ mov r3, #HW_PSR_IRQ_MODE|HW_PSR_IRQ_DISABLE|HW_PSR_ARM_STATE msr cpsr_c, r3 bx lr // ldmfd sp!, { lr } // ldmfd sp!, { r0-r3,r12,pc } // return to interrupted address // not reach here LSYM(12) // ---- OS_GetCurrentThread ldr r0, [ r12, #OS_THREADINFO_OFFSET_CURRENT ] cmp r1, r0 beq _dont_switched_ // return if no thread switching // call thread switch callback (need to save register r0, r1, r12) ldr r3, [ r12, #OS_THREADINFO_OFFSET_SWITCHCALLBACK ] cmp r3, #0 beq FSYM(13) // skip calling callback when callback == 0 stmfd sp!, { r0, r1, r12 } mov lr, pc bx r3 ldmfd sp!, { r0, r1, r12 } LSYM(13) // ---- OS_SetCurrentThread str r1, [ r12, #OS_THREADINFO_OFFSET_CURRENT ] // ---- OS_SaveContext // r0=currentThread r1=nextThread // stack=Lo[LR,R0,R1,R2,R3,R12,LR]Hi mrs r2, SPSR str r2, [ r0, #OS_THREAD_OFFSET_CONTEXT ]! // *r0=context:CPSR #ifdef SDK_CONTEXT_HAS_VFP // first, save CP context stmfd sp!, { r0, r1 } add r0, r0, #OS_THREAD_OFFSET_CONTEXT bl i_osSaveContextVFP ldmfd sp!, { r0, r1 } #endif ldmib sp!, { r2,r3 } // Get R0,R1 // *sp=stack:R1 stmib r0!, { r2,r3 } // Put R0,R1 // *r0=context:R1 ldmib sp!, { r2,r3,r12,r14 } // Get R2,R3,R12,LR / *sp=stack:LR stmib r0!, { r2-r14 }^ // Put R2-R14^ // *r0=context:R14 stmib r0!, { r14 } // Put R14_irq // *r0=context:R15+4 #ifdef SDK_CONTEXT_HAS_SP_SVC mov r3, #HW_PSR_SVC_MODE|HW_PSR_FIQ_DISABLE|HW_PSR_IRQ_DISABLE|HW_PSR_ARM_STATE msr cpsr_c, r3 stmib r0!, { sp } #endif // ---- OS_LoadContext #ifdef SDK_CONTEXT_HAS_VFP // first, load CP context stmfd sp!, { r1 } add r0, r1, #OS_THREAD_OFFSET_CONTEXT bl i_osLoadContextVFP ldmfd sp!, { r1 } #endif #ifdef SDK_CONTEXT_HAS_SP_SVC ldr sp, [ r1, #OS_THREAD_OFFSET_CONTEXT+OS_CONTEXT_SP_SVC ] mov r3, #HW_PSR_IRQ_MODE|HW_PSR_FIQ_DISABLE|HW_PSR_IRQ_DISABLE|HW_PSR_ARM_STATE msr cpsr_c, r3 #endif ldr r2, [ r1, #OS_THREAD_OFFSET_CONTEXT ]! // *r1=context:CPSR msr SPSR_cxsf, r2 // Put SPSR ldr r14, [ r1, #OS_CONTEXT_PC_PLUS4 - OS_CONTEXT_CPSR ] // Get R15 ldmib r1, { r0-r14 }^ // Get R0-R14^ // *r1=over written nop stmda sp!, { r0-r3,r12,r14 } // Put R0-R3,R12,LR / *sp=stack:LR ldmfd sp!, { pc } // return to irq master handler } #endif // BROM_ENABLE_THREAD #ifdef SDK_ARM9 #include #endif