1. 程式人生 > >uc/os中OSSched()函式分析

uc/os中OSSched()函式分析

OS_Sched()分析

uc/os中總是執行優先順序最高的就緒任務,確定哪個任務優先順序最高,該由哪個優先順序人物運行了,這一工作是由任務排程器完成的,(而具體的任務切換,是任務排程器在呼叫其他函式來完成)。其中任務級的排程由函式OS_Sched()來完成,中斷級的排程由OSIntExt()來完成的。

OS_Sched()函式分析

void OSSched (void)

{

INT8U y;

OS_ENTER_CRITICAL();

if ((OSLockNesting | OSIntNesting) == 0) {//判斷是否滿足排程條件,在uc/os中任務級排程的呼叫不允許來自中斷服務子程式(

OSIntNesting) == 0),此外當排程器上鎖時,任務排程函式將直接退出,不做任務排程

y= OSUnMapTbl[OSRdyGrp];

OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);//這兩行程式碼是獲得進入就緒態且優先順序最高的任務

if (OSPrioHighRdy != OSPrioCur) {//檢驗優先順序最高的任務是否是當前正在執行的任務。以避免不必要的的任務排程,畢竟任務排程是需要時間滴。

OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];//通過當前最高優先順序

OSPrioHighRdy,從任務控制塊優先順序表中OSTCBPrioTbl[]獲得當前最高優優先順序任務控制塊

OSCtxSwCtr++;//該全域性變數(32位)用於記錄任務切換的次數,

OS_TASK_SW();最後呼叫OS_TASK_SW巨集來完成實際上的任務切換,該巨集是一個軟中斷

}

}

OS_EXIT_CRITICAL();

}

Ø該函式呼叫所需要的時間是常量,於實際的任務數無關

Øos_sched()所有程式碼都是臨界段程式碼,在準找進入就緒態的優先順序最高任務時,為了防止中斷服務子程式把多個任務的就緒位置位,中斷是關閉的。

OS_TASK_SW()函式分析

任務切換的內容其實是很簡單的:將被掛起任務的暫存器壓入堆疊,然後將高優先順序的暫存器從棧中恢復到CPU的暫存器中。該過程使用軟中斷來實現。

SoftwareInterrupt

LDRSP, StackSvc; 重新設定堆疊指標,在LPC2200開發板中軟中斷觸發後,開發板處於管理模式

STMFDSP!, {R0-R3, R12, LR}//壓棧,在下面過程中使用到了以下以下的暫存器,故需要將這些暫存器壓入管理模式堆疊,來實現原始暫存器的儲存。

MOVR1, SP//R1指向引數儲存位置

MRSR3, SPSR/ARM處理器中,只有MRS指令可以讀取狀態暫存器

TSTR3, #T_bit//中斷前是否是Thumb狀態

LDRNEHR0, [LR,#-2]//: 取得Thumb狀態SWI

BICNER0, R0, #0xff00

LDREQR0, [LR,#-4]//: 取得arm狀態SWI

BICEQR0, R0, #0xFF000000

// r0 = SWI號,R1指向引數儲存位置

CMPR0, #1//比較軟中斷號,確立軟中斷的服務程式

LDRLOPC, =OSIntCtxSw//0號軟中斷用於任務級切換

LDREQPC, =__OSStartHighRdy; SWI 0x01為第一次任務切換

BLSWI_Exception//跳轉到軟中斷服務子程式

LDMFDSP!, {R0-R3, R12, PC}^//SWI異常中斷返回

StackSvcDCD(SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)

Ø對於SWI中斷來說,其格式是SWI{cond} immed_24;後面的24位數字就是軟中斷號,故在SWI異常中斷出路程式中,取出SWI中斷號的方法是首先確定軟中斷SWI指令是ARM指令還是THUMB指令(通過訪問SPSR獲得),然後取得該指令的地址,可通過LR獲得,接著讀出指令,分解出立即數,該立即數就是軟中斷號。

Ø在軟中斷觸發後,處理器應進入管理模式,故需要從新設定堆疊指標。

Ø在軟中斷觸發後,SoftwareInterrupt相當於是一個判斷程式,只是簡單的取出中斷號,具體的實現是呼叫其他函式完成的。

ØSoftwareInterrupt中,進行了一次壓棧,是因為在獲得軟中斷號的過程中使用了R0,R1,R2,R3故需要將這些暫存器壓棧,而使用的SP是管理模式下的暫存器,其於使用者模式下的SP暫存器不是一個暫存器,故不需要進行壓棧。

任務級排程 OSIntCtxsw

OSIntCtxSw

//下面為儲存任務環境

LDRR2, [SP, #20]//此時處理器仍處於管理模式,從管理模式堆疊中獲得PC儲存到R2

LDRR12, [SP, #16]//從堆疊中獲取R12,更新CPU暫存器

MRSR0, CPSR//儲存當前狀態暫存器,用於模式之間的切換

MSRCPSR_c, #(NoInt | SYS32Mode)//進入系統模式,且關中斷

MOVR1, LR//獲得系統模式下的LR儲存到R1中,該LR就是原始任務的LR

STMFDSP!, {R1-R2}//此時處理器處於系統模式,故SP是原始任務的堆疊指標,故原始任務的LR,PC壓入原始任務堆疊

STMFDSP!, {R4-R12}//由於R4-R11暫存器未改變,故其內容是原始任務的內容,直接壓入原始任務堆疊即可。

MSRCPSR_c, R0 //此時切換回管理模式

LDMFDSP!, {R4-R7} //從管理模式堆疊中獲得前面儲存的原是任務的RO-R3,儲存到CPUR4-R7

ADDSP, SP, #8//忽略掉R12,PC,使堆疊指標回到初始位置,使得下次繼續使用

MSRCPSR_c, #(NoInt | SYS32Mode)//進入系統模式

STMFDSP!, {R4-R7}//原始任務的R0-R3入棧儲存

LDRR1, =OsEnterSum//獲取OsEnterSum

LDRR2, [R1]

STMFDSP!, {R2, R3}//從上面知道R3的內容為原始任務的CPSR,故該指令儲存CPSR,OsEnterSum

LDRR1, =OSTCBCur//獲得原始任務的TCB地址

LDRR1, [R1]//該地址的內容是原始任務的SP

STRSP, [R1] //儲存原始任務堆疊指標到原始任務的TCB

BLOSTaskSwHook//呼叫鉤子函式

;OSPrioCur <= OSPrioHighRdy將當前優先順序切換為最高優先順序(優先順序的切換)

LDRR4, =OSPrioCur//當前TCB結構體首地址

LDRR5, =OSPrioHighRdy//最高優先順序TCB結構體首地址

LDRBR6, [R5]

STRBR6, [R4]//更新當前TCB指向最高優先順序TCB

;OSTCBCur <= OSTCBHighRdy將當前TCB切換為最高優先順序的TCB(TCB的切換)

LDRR6, =OSTCBHighRdy

LDRR6, [R6]

LDRR4, =OSTCBCur

STRR6, [R4]

OSIntCtxSw_1

;獲取新任務堆疊指標

LDRR4, [R6]//R6為新任務的TCB地址,其內容是新任務的堆疊指標

ADDSP, R4, #68 //;17暫存器CPSR,OsEnterSum,R0-R12,LR,SP,移動新任務堆疊的SP,指向棧底

LDRLR, [SP, #-8]//新任務LR進入CPU暫存器

MSRCPSR_c, #(NoInt | SVC32Mode)//進入管理模式

MOVSP, R4//設定堆疊指標

LDMFDSP!, {R4, R5}//CPSR,OsEnterSum

//恢復新任務的OsEnterSum

LDRR3, =OsEnterSum

STRR4, [R3]

MSRSPSR_cxsf, R5//恢復CPSR

LDMFDSP!, {R0-R12, LR, PC }^;新任務RO-R12LR,PC出棧,執行新任務

Ø該函式執行前的資料結構:OSTCBCur指向原始任務(低優先順序任務)、CPUSP指向原始任務的棧頂、OSTCBHighRdy指向新任務的TCB

Ø【轉】msr cpsr_cxsf,r1        ;這裡的cxsf表示從低到高分別佔用的48bit的資料域

指令中有時還有出現cpsr_cf, cpsr_all, cpsr_c等,這裡:

        c
CPSR中的control field ( PSR[7:0])
        f
flag field (PSR[31:24])
        x
extend field (PSR[15:8])
        s
status field ( PSR[23:16])

其中cpsr的位表示為:
31 30 29 28 ---   7   6   -   4    3   2   1   0
N   Z   C   V         I   F       M4 M3 M2 M1 M0

                                       0     0   0    0   0     User26
模式
                                       0    0   0    0   1     FIQ26
模式
                                       0    0   0    1   0     IRQ26
模式
                                       0    0   0    1   1     SVC26
模式
                                       1    0   0 0   0     User
模式
                                       1    0   0   0   1     FIQ
模式
                                       1    0   0   1   0     IRQ
模式
                                       1    0   0   1   1     SVC
模式
                                       1    0   1   1 1     ABT
模式
                                       1    1 0    1    1     UND
模式

深入分析:對於MSR(暫存器到狀態暫存器)的指令,
        MSR CPSR,       r0
        MSR CPSR_all,   r0
        MSR CPSR_flg,   r0
都是已經過時的表示方法。對於MRS(狀態暫存器到暫存器)的指令,
        MRS R0,     CPSR       
等同於MRS R0, CPSR_cxsf
        MRS R0,     CPSR_all   
會有waring
        MRS R0,     CPSR_flg  
會有錯誤ADS中使用c,f,x,s表示cpsr的各個部分是推薦的。從指令來說:
        MSR CPSR_f,         r0
機器碼為0xe128f000
        MSR CPSR_c,         r0
機器碼為0xe121f000
        MSR CPSR_x,         r0
機器碼為0xe122f000
        MSR CPSR_s,         r0
機器碼為0xe124f000
可見機器碼中用bit[29:16]4bit表示是f,c,x,s的。所以能夠在機器執行的時候,給予不同的執行結果。為了程式碼向後相容性,建議使用f,c,x,s尾綴