?? os_cpu_a.s
字號:
;********************************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2004, Micrium, Weston, FL
; All Rights Reserved
;
; ARM Generic Port
; IAR C Compiler
;
; File : OS_CPU_A.ASM
; Version : V1.50
; By : Jean J. Labrosse
;********************************************************************************************************
GLOBAL OS_CPU_SR_Save ; Functions declared in this file
GLOBAL OS_CPU_SR_Restore
GLOBAL OSStartHighRdy
GLOBAL OSCtxSw
; GLOBAL OSIntCtxSw
GLOBAL OS_CPU_IRQ_ISR
; GLOBAL OS_CPU_FIQ_ISR
IMPORT OSRunning ; External references
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSIntNesting
IMPORT OSIntCtxSwFlag
IMPORT OSIntEnter
IMPORT OSIntExit
IMPORT OSTaskSwHook
IMPORT OS_CPU_IRQ_ISR_Handler
; IMPORT OS_CPU_FIQ_ISR_Handler
NO_INT EQU 0xC0 ; Mask used to disable interrupts (Both FIR and IRQ)
SYS32_MODE EQU 0x1F
FIQ32_MODE EQU 0x11
IRQ32_MODE EQU 0x12
;*********************************************************************************************************
; 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"
;*********************************************************************************************************
AREA OS_ASM_CODE, CODE, READONLY
CODE32
OS_CPU_SR_Save
mrs r0,CPSR
orr r1,r0,#NO_INT
msr CPSR_c,r1
mov pc,lr
OS_CPU_SR_Restore
msr CPSR_c,r0
mov pc,lr
;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)
; MOV PC,LR ; Disabled, return the original CPSR contents in R0
;
;
;OS_CPU_SR_Restore
; MSR CPSR_c,R0
; MOV PC,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.
;*********************************************************************************************************
OSStartHighRdy
MSR CPSR_cxsf, #0xDF ; Switch to SYS mode with IRQ and FIQ disabled
BL OSTaskSwHook ; OSTaskSwHook();
LDR R4, =OSRunning ; OSRunning = TRUE
MOV R5, #1
STRB R5, [R4]
; SWITCH TO HIGHEST PRIORITY TASK
LDR R4, =OSTCBHighRdy ; Get highest priority task TCB address
LDR R4, [R4] ; get stack pointer
LDR SP, [R4] ; switch to the new stack
ldmfd sp!,{r4} ; pop new task's psr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
;*********************************************************************************************************
; 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
;*********************************************************************************************************
CODE32
OSCtxSw
; SAVE CURRENT TASK'S CONTEXT
stmfd sp!,{lr} ; push pc (lr should be pushed in place of PC)
stmfd sp!,{r0-r12,lr} ; push lr & register file
mrs r4,cpsr
stmfd sp!,{r4} ; push current psr
LDR R4, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4]
STR SP, [R5]
BL OSTaskSwHook ; OSTaskSwHook();
LDR R4, =OSPrioCur ; OSPrioCur = OSPrioHighRdy
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
LDR R4, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
STR R6, [R4]
LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;
; RESTORE NEW TASK'S CONTEXT
ldmfd sp!,{r4} ; pop new task's psr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
;*********************************************************************************************************
; IRQ Interrupt Service Routine
;*********************************************************************************************************
;中斷的處理是操作系統移植的很重要的一部分
;我在移植中完全沒有按官方版的思路,而主要參照Jean J. Labrosse版本
;在此基礎上貫徹了我的一個主要思想,讓中斷發生后,如果需要進行任務切換,
;則場景看起來就像是中斷從新任務中發生的,然后返回來新任務
;如果不進行切換,則場景就是完全和原任務一致
;并且一個很主要的一點,中斷處理過程中,全程都是禁止中斷的
;直到最后一個語句返回到SYS模式(新任務或原任務)才恢復正確的CPSR,允許中斷
;為了達到這個目的,沒有在INTEXIT中調用Intctxsw,而是設置了一個標志位,然后在最后才執行
;*********************************************************************************************************
CODE32
OS_CPU_IRQ_ISR
stmfd sp!,{r0-r12,lr}
bl OSIntEnter
bl OS_CPU_IRQ_ISR_Handler
bl OSIntExit
ldr r0,=OSIntCtxSwFlag
ldr r1,[r0]
cmp r1,#1
beq _IntCtxSw ;if executed, will not return here
ldmfd sp!,{r0-r12,lr}
subs pc,lr,#4
;*********************************************************************************************************
; 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
;*********************************************************************************************************
_IntCtxSw
mov r1,#0
str r1,[r0] ;OSIntCtxSwFlag = 0;
ldmfd sp!,{r0-r12,lr}
stmfd sp!,{r0-r3} ;r0-r3 need use below
mov r1,sp ;r1 is sp of int
add sp,sp,#16
sub r2,lr,#4 ;r2 is old task pc
mrs r3,spsr ;spsr->no int
; orr r0,r3,#NO_INT
; msr spsr_c,r0
msr spsr_c, #0xdf ; Switch to SYS mode with IRQ and FIQ disabled
ldr r0,=.+8 ;r0 = pc+8 僅僅是為了將SPSR賦值到CPSR
movs pc,r0 ;pc = r0, and CPSR=SPSR
;以下已經切換到了SYS模式
stmfd sp!,{r2} ; push old task's pc
stmfd sp!,{r4-r12,lr} ; push old task's lr,r12-r4
mov r4,r1 ; SP_irq->r4
mov r5,r3 ;CSSR->r5
ldmfd r4!,{r0-r3} ;從IRQ的中斷中恢復R0-R3
stmfd sp!,{r0-r3} ; push old task's r3-r0
stmfd sp!,{r5} ; push old task's psr
; mrs r4,spsr ;no spsr in sys mode
; stmfd sp!,{r4} ; push old task's spsr
;to here old task context save finished, except save sp to tcb
mov r7, r4 ;SP_irq->r7
; OSPrioCur = OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r5,[r5]
strb r5,[r4]
; Get current task TCB address
ldr r4,=OSTCBCur
ldr r5,[r4]
str sp,[r5] ; store sp in old tasks's TCB
bl OSTaskSwHook ; call Task Switch Hook
; Get highest priority task TCB address
ldr r6,=OSTCBHighRdy
ldr r6,[r6]
ldr sp,[r6] ; get new task's stack pointer
; OSTCBCur = OSTCBHighRdy
str r6,[r4] ; set new current task TCB address
ldmfd sp!,{r4} ; pop new task's psr to r4
ldmfd sp!,{r0-r3} ; pop new task's r0-r3, r0-r3 used as temp registers
;push to Stack of irq
stmfd r7!,{r0-r3} ; push new task's r0-r3
mov r3, r4 ;save PSR to r3
ldmfd sp!,{r4-r12,lr} ; pop new task's r4-r12,lr
ldmfd sp!,{r2} ; pop new task's pc to r2
;now, all context of new task was poped.
;r0-r3, in irq's stack, r4-r12,lr in place, cpsr in r3, pc in r2, sp in sp_sys
;return IRQ mode!
msr cpsr_c, #0xD2 ; Switch to IRQ mode with IRQ and FIQ disabled
msr spsr_cxsf, r3 ;new task's cpsr to irq's spsr
mov lr, r2 ;new task's pc to lr
sub sp, sp, #16 ;TBD
ldmfd sp!,{r0-r3} ;restore r0-r3
;now all context of new task was in place, just like interrpt was occur in new task
movs pc,lr ;restore cpsr
END
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -