ctr_firmware/trunk/bootrom/build/libraries/os/ARM9/os_irqHandler.c
nakasima 7700a72a36 割り込み関数のマージ準備。
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_firmware@127 b871894f-2f95-9b40-918c-086798483c85
2008-12-19 01:38:24 +00:00

261 lines
9.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*---------------------------------------------------------------------------*
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 <brom/code32.h>
#include <brom/os.h>
//#define BROM_ENABLE_THREAD
#ifdef SDK_ARM9
#include <brom/dtcm_begin.h>
#endif
//---- thread queue for interrupt
OSThreadQueue i_osIrqThreadQueue;
#ifdef SDK_ARM9
#include <brom/dtcm_end.h>
#include <brom/itcm_begin.h>
#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 )
sub lr, lr, #4 // •œAƒAƒhƒŒƒX²<E28099>®
stmfd sp!, { r0-r3,r12,lr }
stmfd sp!, { lr } // save LR
// 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
// if IE&IF==0 then return (without changing IF)
ldmeqfd sp!, { lr }
ldmeqfd sp!, { r0-r3,r12,pc }
//--------------------------------------------------
// 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 r0, r0, #31
// get jump vector
ldr r1, =osIntrTable
ldr r0, [ r1, r0, LSL #2 ]
blx r0 // set return address for thread rescheduling
#ifdef BROM_ENABLE_THREAD
bl osIrqHandler_ThreadSwitch
#endif // BROM_ENABLE_THREAD
ldmfd sp!, { lr }
ldmfd sp!, { r0-r3,r12,pc } // return to interrupted address
}
#ifdef BROM_ENABLE_THREAD
/*---------------------------------------------------------------------------*
Name: OS_IRQHandler_ThreadSwitch
Description: Š„è<E2809A>žÝ•ªŠò<C5A0>ˆ<CB86><E28094>iƒe<C692>[ƒuƒ OS_InterruptTable ˆø«<E2809A>j
Arguments: ‚È‚µ
Returns: ‚È‚µ
*---------------------------------------------------------------------------*/
asm void osIrqHandler_ThreadSwitch(void)
{
INASM_EXTERN( i_osIrqThreadQueue )
INASM_EXTERN( i_osThreadInfo )
//--------------------------------------------------
// 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
ldmfd sp!, { lr }
ldmfd sp!, { r0-r3,r12,lr } // return to interrupted address
bx lr
// 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
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_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 <brom/itcm_end.h>
#endif