OS_TASK_SW, OS_CPU_IRQ_ISR,OSIntCtxSw,OS_CPU_FIQ_ISR,OSStarHighRdy
下面是關於這個幾個函數的彙編,處理是基於ARM的S3C2410,其中的一些有關彙編的知識在
http://blog.csdn.net/cangencong/article/details/6890933這篇博文中已經講到了,但是對於這幾個函數的一些註解,自己也有一些不懂的地方,並且標註出來了,希望如果有知道的人,看到還望他不吝賜教。
OS_TASK_SW
是一個普通的任務級的任務調度
;以下是定義全局變量的定義
;IMPORT僞操作告訴編譯器當前的符號不是在本源文件中定義的,
;而是在其他源文件中定義的,在本源文件中可能引用該符號,
;而且不論本源文件是否實際引用該符號,該符號都將被加入到本源文件的符號表中。
;
IMPORT OSTCBCur
addr_OSTCBCur DCD OSTCBCur ;當前任務TCB指針
IMPORT OSTCBHighRdy
addr_OSTCBHighRdy DCD OSTCBHighRdy ;當前最高優先級的TCB指針
IMPORT OSPrioCur
addr_OSPrioCur DCD OSPrioCur ;當前任務優先級
IMPORT OSPrioHighRdy
addr_OSPrioHighRdy DCD OSPrioHighRdy ;新就緒最高優先級任務
OS_TASK_SW ;只是一個標號,相當於函數名
STMFD sp!,{lr}
STMFD sp!,{lr}
STMFD sp!,{r0-r12}
MRS r4,CPSR
STMFD sp!,{r4}
MRS r4,SPSR
STMFD sp!{r4}
;最高優先級的值放入當前優先級的值中
LDR r4,addr_OSPrioCur
LDR r5,addr_OSPrioHighRdy
LDRB r6,[r5]
STRB r6,[r4]
;把此時的sp地址作爲(舊任務的棧頂值),說明入棧需要保存的數據保存結束
LDR r4,addr_OSTCBCur
LDR r5,[r4]
STR sp,[r5] ;任務控制塊的第一個成員就是OS_STK *OSTCBSTKPT,專門用來存放棧頂
;把此時最高優先級的任務(新任務)的棧頂指針放入sp中
LDR r6,addr_OSTCBHighRdy
LDR r6,[r6]
LDR sp,[r6]
;把OSTCBCur的值修改爲新就緒最高優先級任務的控制塊地址
;並且進行出棧,則開始執行此新任務,完成任務調度功能
STR r6,[r4] ;r4指向當前任務控制塊指針的地址,r6是最高優先級任務控制塊指針
;按照入棧相反的順序出棧所保存的數據,此時的sp已經是最高優先級任務的棧頂了
LDMFD sp!,{r4}
MSR SPSR_cxsf,{r4}
LDR sp,{r4}
MSR CPSR_cxsf,{r4}
LDMFD sp!,{r0-r12,lr,pc}
OS_CPU_IRQ_ISR
普通中斷處理函數方式,
;整個過程方式是:在產生中斷時,必須快速進入中斷,避免中斷丟失,
;當保存了最主要的中斷信息後,再次回到SVC模式中存儲正在執行任務的信息。
;結束後,在回到IRQ模式中,執行中斷服務程序,執行完成後,再次返回SVC模式。
;OS_CPU_IRQ_ISR函數
;以下是部分定義
NO_INT EQU 0xc0 ;用於禁止FIR和IRQ
NO_IRQ EQU 0x80 ;用於禁止IRQ
NO_FIQ EQU 0x40 ;用於禁止FIR
SVC32_MODE EQU 0x13 ;處理器模式爲32位SVC模式
FIQ32_MODE EQU 0x11 ;處理器模式爲32位FIQ模式
IRQ32_MODE EQU 0x12 ;處理器模式爲32位IRQ模式
;IRQ中斷處理函數
OS_CPU_IRQ_ISR ;標號,可以在C語言程序中調用此函數
;首先禁止CPU的FIQ中斷,並切換到IRQ中斷模式
MSR CPSR_c,#(NO_INT|IRQ32_MODE)
STMFD SP!,{R1-R3};將R1-R3通用寄存器存入IRQ模式下的棧(SP_IRQ)中
MOV R1,SP ;①
ADD SP,SP,#12 ;???爲什麼留出3個字的空間
SUB R2,LR,#4 ;獲取返回值??是因爲ARM預讀指令的原因嗎
MRS R3,SPSR ;②讀取SPSR寄存器
MSR CPSR_c,#(NO_INT|SVC32_MODE) ;切換到SVC模式
;存儲任務的上下在SVC模式的棧空間中
STMFD SP!,{R2} ;存儲返回地址
STMFD SP!,{LR} ;存儲LR寄存器的值
STMFD SP!,{R4-R12} ;存儲R4-R12通用寄存器的值
LDMFD R1!,{R4-R6} ;因爲在①出獲得了SP的值,可以把IRQ的寄存器R1-R3的值取出來
STMFD SP!,{R4-R6} ;把IRQ模式中的R1-R3原始值入棧到SVC模式棧中
STMFD SP!,{R0} ;將R0入SVC模式棧中
;將全局變量OSTntNesting自動加1,也可以執行OSIntEnter()代替
LDR R0,OS_IntNesting
LDRB R1,[R0] ;只傳遞後8位,難道是可以提高效率????
ADD R1,R1,#1
STRB R1,[R0]
;如果條件滿足(OSIntNesting==1)即,只有這一個中斷,
;將設置當前任務控制塊成員變量OSTCBCur->OSTCBStrPtr=SP
CMP R1,#1 ;R1與1比較,結果會改變狀態寄存器
BNE OS_CPU_IRQ_ISR_1 ;如果R1不等1則跳轉
LDR R4,OS_TCBCur
LDR R5,[R4]
STR SP,[R5] ;第一個成員變量是OSTCBCur->OSTCBStrPtr = SP
OS_CPU_IRQ_ISR_1
;返回到IRQ中斷,使能FIQ中斷,執行中斷子程序OS_CPU_IRQ_ISR_Handler()
MSR CPSR_c,#(NO_IRQ|IRQ32_MODE)
LDR R0,OS_CPU_IRQ_IRQ_Handler
MOV LR,PC ;因爲LR在執行BL子程序調用指令時,作爲R15的備份
BX R0
;當中斷服務程序執行結束後,返回這裏,CPU的狀態切換爲SVC模式
MSR CPSR_c,#(NO_INT|SVC32_MODE)
;調用OSIntExit()函數,引發新的調用
LDR R0,OS_IntExit
MOV LR,PC
BX R0
;讀取新任務的上下文信息
LDMFD SP!,{R4}
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^
;在特權模式下(SVC)下,"S"或者"^"的作用就是使指令在執行時,同時從SPSR到CPSR的複製,
;達到恢復狀態寄存器。
OSIntCtxSw
;中斷級任務調度切換函數
;由於ARM有各種不同的模式,因此在普通模式下的任務切換和中斷後的任務切換是不同的
OSIntCtxSw
LDR R0,OS_TaskSwHook ;執行特殊的鉤子函數①OSTaskSwHook()
MOV LR,PC
BX R0
;將全局變量OS_PrioCur的值修改爲OS_PrioHighRdy
LDR R4,OS_PrioCur
LDR R5,OS_PrioHighRdy
LDRB R6,[R5]
STRB R6,[R4]
;將全局變量OS_TCBCur的值修改爲OS_TCBHighRdy
LDR R4,OS_TCBCur
LDR R5,OS_TCBHighRdy
LDR R6,[R5]
STR R6,[R4]
;讀出新任務的堆棧指針SP = OSTCBHighRdy->OSTCBStrPtr
LDR SP,{R6}
;恢復新任務的上下文內容,然後自動跳轉,因爲PC值變了
LDMFD SP!,{R4}
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^
;子函數①OSTaskSwHook()由移植此係統的用戶添加代碼,
;默認爲空,當用戶認爲有必要執行某些特殊功能時,在函數中添加相應的代碼
OS_CPU_FIQ_ISR
FIQ中斷與普通中斷比較類似,但是更爲緊急,能夠中斷IRQ。
OS_CPU_FIQ_ISR
;爲什麼不手動進入FIQ模式,IRQ模式是手動進入的
STMFD SP!,{R1-R4} ;將會使用到的寄存器壓入FIQ棧中
MOV R1,SP ;②讀取FIQ的SP指針
SUB R2,LR,#4 ;①調整LR,以得到PC返回值
MRS R3,SPSR ;讀取SPSR_fiq的值
MOV R4,R3
AND R4,R4,#0x1F ;提取SPSR後5位
CMP R4,#IRQ32_MODE ;測試FIQ是否在IRQ模式下發生的,即是否中斷嵌套了
BEQ OS_CPU_FIQ_ISR_2 ;如果是,則跳到OS_CPU_FIQ_ISR;如果不是直接執行FIQ中斷處理
MSR CPSR_c,#(NO_INT|SVC32_MODE) ;將當前CPU修改爲SVC模式
;保存上下文內容到任務棧中
STMFD SP!,{R2} ;將PC放入SVC模式棧中,在①出,R2已經得到PC值
STMFD SP!,{LR} ;將LR保存到SVC模式中
LDMFD R1!,{R5-R8} ; 將FIQ棧中的R1-R4存儲到SVC棧中,在②處,已經獲得FIQ棧指針
STMFD SP!,{R5-R8}
STMFD SP!,{R0}
STMFD SP!,{R3} ;將SPSR_fiq存儲到SVC棧中
LDR R0,OS_IntNesting ;中斷嵌套次數加1,
LDRB R1,[R0]
ADD R1,R1,#1
STRB R1,[R0]
;如果條件滿足OS_IntNesting=1
;設置當前任務的任務控制塊成員變量OSTCBCur->OSTCBStrPtr = SP
CMP R1,#1
BNE OS_CPU_FIQ_ISR_1
OS_CPU_FIQ_ISQ_1
MSR CPSR_c,#(ON_INT|FIQ32_MODE) ;進入FIQ模式
ADD SP,SP,#16 ;修改FIQ棧指標(爲什麼要修改)
LDR R0,OS_CPU_FIQ_ISR_Handler ;調用中斷服務程序
MOV LR,PC
BX R0
;讀取新任務的上下文內容,開始執行新任務
LDMFD SP!,{R4} ;將新任務的cpsr出棧
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^ ;由於PC值改變,相當於return了。
;FIQ中斷將中斷IRQ中斷
OS_CPU_FIQ_ISR_2
;將IRQ的上下文存儲到FIQ的棧中
STMFD SP!,{R0-R7,LR}
;中斷次數加一,相當於執行OSIntEnter()函數
LDR R0,OS_IntNesting
LDRB R1,[R0]
ADD R1,R1,#1
STRB R1,[R0]
LDR R0,OS_CPU_FIQ_ISR_Handler
MOV LR,PC
BX R0
;全局變量OSIntNesting自動減一,此處沒有必要執行OSIntExit()函數
;因爲返回到IRQ模式下時將調用此函數,另外,在中斷嵌套中不允許引發新的調度
LDR R0,OS_IntNesting
LDR R1,[R0]
SUB R1,R1,#1
STRB R1,[R0]
;恢復IRQ模式下的上下文內容,然後返回到IRQ模式執行IRQ中斷
LDMFD SP!,{R0-R7,LR}
LDMFD SP!,{R1-R4}
SUBS PC,LR,#4
OSStarHighRdy
;運行最高優先級任務
;GLOBAL 與 EXPORT 相同,EXTERN 與 IMPORT 相同
IMPORT OSTCBCur
addr_OSTCBCur DCD OSTCBCur
IMPORT OSTCBHighRdy
addr_OSTCBHighRdy DCD OSTCBHighRdy
EXPORT OSStarHighRdy
OSStarHighRdy
LDR R4,addr_OSTCBCur ;獲取當前任務TCB的地址
LDR R5,addr_OSTCBHighRdy ;獲取最高優先級的TCB地址
LDR R5,[R5]
LDR SP,[R4]
LDMFD SP!,{R4}
MSR SPSR_cxsf,R4
LDMFD SP!,{R4}
MSR CPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}
END