;******************************************************************************************************** ; uC/OS-II ; The Real-Time Kernel ; ; (c) Copyright 1992-2005, Micrium, Weston, FL ; All Rights Reserved ; ; Generic ARM Port ; ; File : OS_CPU_A.ASM ; Version : V1.61(Rev) ; By : Jean J. Labrosse ; Rev By : leafboy(2006.08.02) ; ; For : ARM7 or ARM9 ; Mode : ARM or Thumb ; Toolchain : IAR's EWARM V4.11a and higher ;******************************************************************************************************** #include "AT91SAM7S64_inc.h" #define _ASSEMBLER #include ;To determine 'OSTaskSwHook' defined or not? EXTERN OSRunning ; External references EXTERN OSPrioCur EXTERN OSPrioHighRdy EXTERN OSTCBCur EXTERN OSTCBHighRdy EXTERN OSIntNesting EXTERN OSIntExit EXTERN OSTaskSwHook PUBLIC OS_CPU_SR_Save ; Functions declared in this file PUBLIC OS_CPU_SR_Restore PUBLIC OSStartHighRdy PUBLIC OSCtxSw PUBLIC OSIntCtxSw PUBLIC OS_CPU_IRQ_ISR PUBLIC OS_CPU_FIQ_ISR ; Mode, correspords to bits 0-5 in CPSR USR_MODE EQU 0x10 ; User mode FIQ_MODE EQU 0x11 ; Fast Interrupt Request mode IRQ_MODE EQU 0x12 ; Interrupt Request mode SVC_MODE EQU 0x13 ; Supervisor mode ABT_MODE EQU 0x17 ; Abort mode UND_MODE EQU 0x1B ; Undefined Instruction mode SYS_MODE EQU 0x1F ; System mode I_BIT EQU 0x80 F_BIT EQU 0x40 NO_INT EQU 0xC0 ; Mask used to disable interrupts (Both FIR and IRQ) ;********************************************************************************************************* ; CRITICAL SECTION METHOD 3 FUNCTIONS ; ; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you ; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then ; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to ; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr' ; into the CPU's status register. ; ; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void); ; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr); ; ; ; Note(s) : 1) These functions are used in general like this: ; ; void Task (void *p_arg) ; { ; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ ; OS_CPU_SR cpu_sr; ; #endif ; ; : ; : ; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */ ; : ; : ; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */ ; : ; : ; } ; ; 2) OS_CPU_SaveSR() is implemented as recommended by Atmel's application note: ; ; "Disabling Interrupts at Processor Level" ;********************************************************************************************************* RSEG CODE:CODE:NOROOT(2) CODE32 OS_CPU_SR_Save MRS R0,CPSR ; Set IRQ and FIQ bits in CPSR to disable all interrupts ORR R1,R0,#NO_INT MSR CPSR_c,R1 MRS R1,CPSR ; Confirm that CPSR contains the proper interrupt disable flags AND R1,R1,#NO_INT CMP R1,#NO_INT BNE OS_CPU_SR_Save ; Not properly disabled (try again) BX LR ; Disabled, return the original CPSR contents in R0 OS_CPU_SR_Restore MSR CPSR_c,R0 BX LR ;********************************************************************************************************* ; START MULTITASKING ; void OSStartHighRdy(void) ; ; Note(s) : 1) OSStartHighRdy() MUST: ; a) Call OSTaskSwHook() then, ; b) Set OSRunning to TRUE, ; c) Switch to the highest priority task. ;********************************************************************************************************* RSEG CODE:CODE:NOROOT(2) CODE32 OSStartHighRdy #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0) LDR R0, ??OS_TaskSwHook ; OSTaskSwHook(); MOV LR, PC BX R0 #endif MSR CPSR_c, #(NO_INT | SYS_MODE) ; Switch to SYS mode with IRQ and FIQ disabled LDR R4, ??OS_Running ; OSRunning = TRUE MOV R5, #1 STRB R5, [R4] ; SWITCH TO HIGHEST PRIORITY TASK LDR R4, ??OS_TCBHighRdy ; Get highest priority task TCB address LDR R4, [R4] ; get stack pointer LDR SP, [R4] ; switch to the new stack LDR R4, [SP], #4 ; pop new task's CPSR MSR CPSR_cxsf, R4 ; has CPSR only at SYS mode LDMFD SP!, {R0-R12,LR,PC} ; pop new task's context ;********************************************************************************************************* ; PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw() ; ; Note(s) : 1) OSCtxSw() is called in SYS mode with BOTH FIQ and IRQ interrupts DISABLED ; ; 2) The pseudo-code for OSCtxSw() is: ; a) Save the current task's context onto the current task's stack ; b) OSTCBCur->OSTCBStkPtr = SP; ; c) OSTaskSwHook(); ; d) OSPrioCur = OSPrioHighRdy; ; e) OSTCBCur = OSTCBHighRdy; ; f) SP = OSTCBHighRdy->OSTCBStkPtr; ; g) Restore the new task's context from the new task's stack ; h) Return to new task's code ; ; 3) Upon entry: ; OSTCBCur points to the OS_TCB of the task to suspend ; OSTCBHighRdy points to the OS_TCB of the task to resume ;********************************************************************************************************* RSEG CODE:CODE:NOROOT(2) CODE32 OSCtxSw ; SAVE CURRENT TASK'S CONTEXT STMFD SP!, {LR} ; Push return address STMFD SP!, {R0-R12, LR} ; Push registers MRS R4, CPSR ; Push current CPSR TST LR, #1 ; See if called from Thumb mode ORRNE R4, R4, #0x20 ; If yes, Set the T-bit STMFD SP!, {R4} OSCtxSw1: LDR R4, ??OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP; LDR R5, [R4] STR SP, [R5] #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0) LDR R0, ??OS_TaskSwHook ; OSTaskSwHook(); MOV LR, PC BX R0 #endif LDR R4, ??OS_PrioCur ; OSPrioCur = OSPrioHighRdy LDR R5, ??OS_PrioHighRdy LDRB R6, [R5] STRB R6, [R4] LDR R4, ??OS_TCBCur ; OSTCBCur = OSTCBHighRdy; LDR R6, ??OS_TCBHighRdy LDR R6, [R6] STR R6, [R4] LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr; ; RESTORE NEW TASK'S CONTEXT LDMFD SP!, {R4} ; Pop new task's CPSR MSR CPSR_cxsf, R4 ; has CPSR only at SYS mode LDMFD SP!, {R0-R12,LR,PC} ; pop new task's context ;********************************************************************************************************* ; PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw() ; ; Note(s) : 1) OSIntCtxSw() is called in SYS mode with BOTH FIQ and IRQ interrupts DISABLED ; ; 2) The pseudo-code for OSCtxSw() is: ; a) OSTaskSwHook(); ; b) OSPrioCur = OSPrioHighRdy; ; c) OSTCBCur = OSTCBHighRdy; ; d) SP = OSTCBHighRdy->OSTCBStkPtr; ; e) Restore the new task's context from the new task's stack ; f) Return to new task's code ; ; 3) Upon entry: ; OSTCBCur points to the OS_TCB of the task to suspend ; OSTCBHighRdy points to the OS_TCB of the task to resume ;********************************************************************************************************* RSEG CODE:CODE:NOROOT(2) CODE32 OSIntCtxSw ;*********************************************************** ; IRQ STACK R4 R14 R0 R1 R2 R3 R12 SPSR LR(PC) ;*********************************************************** ; SAVE TASK'S CONTEXT ONTO TASK'S STACK ADD SP, SP, #(7 + 2)*4 ; Adjust IRQ stack pointer ; {R0-R3, R12, SPSR, LR}=7*4, OSIntExit=2*4 SUB R0, SP, #3*4 ; R0->R12 MSR CPSR_c, #NO_INT | SYS_MODE ; Change to SYS mode LDMIA R0, {R1-R3} ; R12,SPSR,LR(PC)=>R1,R2,R3 SUB R0, R0, #4*4 ; Moving (R3-R0) STMFD SP!, {R3} ; R3(PC)=>[SP] STMFD SP!, {R1, LR} ; R1(R12),LR=>[SP] STMFD SP!, {R4-R11} ; R4-R11=>[SP] LDMIA R0, {R4-R7} ; R0-R3=>R4-R7 STMFD SP!, {R2,R4-R7} ; R2(SPSR),R4-R11(R0-R3)=>[SP] B OSCtxSw1 ;********************************************************************************************************* ; IRQ Interrupt Service Routine ;********************************************************************************************************* RSEG CODE:CODE:NOROOT(2) CODE32 OS_CPU_IRQ_ISR SUB LR, LR, #4 ;- Adjust and save LR_irq in IRQ stack STMFD SP!, {LR} MRS R14, SPSR ;- Save SPSR need to be saved for nested interrupt STMFD SP!, {R12, R14} ; HANDLE NESTING COUNTER LDR R14, ??OS_IntNesting ; OSIntNesting++; LDRB R12, [R14] ADD R12, R12,#1 STRB R12, [R14] ;- Write in the IVR to support Protect Mode ;- No effect in Normal Mode ;- De-assert the NIRQ and clear the source in Protect Mode LDR R14, =AT91C_BASE_AIC LDR R12 , [R14, #AIC_IVR] STR R14, [R14, #AIC_IVR] ;IRQ_ISR_Handler { MSR CPSR_c, #IRQ_MODE ;- Enable Interrupt STMFD SP!, {R0-R3} ;- Save scratch/used registers and LR in IRQ Stack MOV LR, PC ;- Branch to the routine pointed by the AIC_IVR BX R12 ; IRQ_ISR_Handler() MSR CPSR_c, #I_BIT | IRQ_MODE ;- Disable Interrupt and switch back in IRQ mode ;} IRQ_ISR_Handler LDR R14, =AT91C_BASE_AIC ;- Mark the End of Interrupt on the AIC STR R14, [R14, #AIC_EOICR] LDR R12, ??OS_IntExit ; OSIntExit(); MOV LR, PC BX R12 LDMIA SP!, {R0-R3} ;- Restore scratch/used registers and LR from User Stack LDMIA SP!, {R12, R14} ;- Restore SPSR_irq and r12 from IRQ stack MSR SPSR_cxsf, R14 LDMIA SP!, {PC}^ ;- Restore adjusted LR_irq from IRQ stack directly in the PC ;********************************************************************************************************* ; FIQ Interrupt Service Routine ;********************************************************************************************************* RSEG CODE:CODE:NOROOT(2) CODE32 OS_CPU_FIQ_ISR B . ;********************************************************************************************************* ; POINTERS TO VARIABLES ;********************************************************************************************************* DATA #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0) ??OS_TaskSwHook: DC32 OSTaskSwHook #endif ??OS_IntExit: DC32 OSIntExit ??OS_IntNesting: DC32 OSIntNesting ??OS_PrioCur: DC32 OSPrioCur ??OS_PrioHighRdy: DC32 OSPrioHighRdy ??OS_Running: DC32 OSRunning ??OS_TCBCur: DC32 OSTCBCur ??OS_TCBHighRdy: DC32 OSTCBHighRdy END