OS_CPU_C.C

µC/OS-Ⅱ的移植實例要求用戶編寫六個簡單的C函數:
		OSTaskStkInit()
		OSTaskCreateHook()
		OSTaskDelHook()
		OSTaskSwHook()
		OSTaskStatHook()
		OSTimeTickHook()
	唯一必要的函數是OSTaskStkInit(),其它五個函數必須得聲明但沒必要包含代碼。
OSTaskStkInt()
	OSTaskCreate()和OSTaskCreateExt()通過調用OSTaskStkInt()來初始化任務的堆棧結構,因此,堆棧看起來就像剛發生過中斷並將所有的寄存器保存到堆棧中的情形一樣。圖8.3顯示了OSTaskStkInt()放到正被建立的任務堆棧中的東西。注意,在這裏我假定了堆棧是從上往下長的。下面的討論同樣適用於從下往上長的堆棧。
	在用戶建立任務的時候,用戶會傳遞任務的地址,pdata指針,任務的堆棧棧頂和任務的優先級給OSTaskCreate()和OSTaskCreateExt()。雖然OSTaskCreateExt()還要求有其它的參數,但這些參數在討論OSTaskStkInt()的時候是無關緊要的。爲了正確初始化堆棧結構,OSTaskStkInt()只要求剛纔提到的前三個參數和一個附加的選項,這個選項只能在OSTaskCreateExt()中得到。

回顧一下,在µC/OS-Ⅱ中,無限循環的任務看起來就像其它的C函數一樣。當任務開始被µC/OS-Ⅱ執行時,任務就會收到一個參數,好像它被其它的任務調用一樣。

 

void MyTask (void *pdata)

{

    /* 對'pdata'做某些操作 */

    for (;;) {

        /* 任務代碼                      */

    }

}

 

如果我想從其它的函數中調用MyTask()C編譯器就會先將調用MyTask()的函數的返回地址保存到堆棧中,再將參數保存到堆棧中。實際上有些編譯器會將pdata參數傳至一個或多個寄存器中。在後面我會討論這類情況。假定pdata會被編譯器保存到堆棧中,OSTaskStkInit()就會簡單的模仿編譯器的這種動作,將pdata保存到堆棧中[F8.3(1)]。但是結果表明,與C函數調用不一樣,調用者的返回地址是未知的。用戶所擁有的是任務的開始地址,而不是調用該函數(任務)的函數的返回地址!事實上用戶不必太在意這點,因爲任務並不希望返回到其它函數中。

這時,用戶需要將寄存器保存到堆棧中,當處理器發現並開始執行中斷的時候,它會自動地完成該過程的。一些處理器會將所有的寄存器存入堆棧,而其它一些處理器只將部分寄存器存入堆棧。一般而言,處理器至少得將程序計數器的值(中斷返回地址)和處理器的狀態字存入堆棧[F8.3(2)]。很明顯,處理器是按一定的順序將寄存器存入堆棧的,而用戶在將寄存器存入堆棧的時候也就必須依照這一順序。

接着,用戶需要將剩下的處理器寄存器保存到堆棧中[F8.3(3)]。保存的命令依賴於用戶的處理器是否允許用戶保存它們。有些處理器用一個或多個指令就可以馬上將許多寄存器都保存起來。用戶必須用特定的指令來完成這一過程。例如,Intel 80x86使用PUSHA 指令將8個寄存器保存到堆棧中。對Motorola 68HC11處理器而言,在中斷響應期間,所有的寄存器都會按一定順序自動的保存到堆棧中,所以在用戶將寄存器存入堆棧的時候,也必須依照這一順序。

現在是時候討論這個問題了:如果用戶的C編譯器將pdata參數傳遞到寄存器中而不是堆棧中該作些什麼?用戶需要從編譯器的文檔中找到pdata儲存在哪個寄存器中。pdata的內容就會隨着這個寄存器的儲存被放置在堆棧中。


一旦用戶初始化了堆棧,OSTaskStkInit()就需要返回堆棧指針所指的地址[F8.3(4)]。OSTaskCreate()和OSTaskCreateExt()會獲得該地址並將它保存到任務控制塊(OS_TCB)中。處理器文檔會告訴用戶堆棧指針會指向下一個堆棧空閒位置,還是會指向最後存入數據的堆棧單元位置。例如,對Intel 80x86處理器而言,堆棧指針會指向最後存入數據的堆棧單元位置,而對Motorola 68HC11處理器而言,堆棧指針會指向下一個空閒的位置。



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