μC/OS中幾個底層相關函數

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



      
      


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章