任務(wù)堆棧結(jié)構(gòu)的初始化
在uC/OS-II中,任務(wù)是一個無限循環(huán),任務(wù)之間也不會互相調(diào)用,但是uC/OS-II總是執(zhí)行優(yōu)先級最高的任務(wù),假定當(dāng)前有一個更高優(yōu)先級的任務(wù)進(jìn)入就緒狀態(tài),為了保證原來低優(yōu)先級任務(wù)的完整性,uC/OS-II為每個任務(wù)建立了任務(wù)堆棧,就相當(dāng)于函數(shù)調(diào)用時保存返回地址和參數(shù)一樣,用來保存當(dāng)前任務(wù)的狀態(tài),保證任務(wù)切換能和函數(shù)調(diào)用一樣正確.只不過函數(shù)調(diào)用時函數(shù)堆棧的操作過程是編譯器自動完成的,而任務(wù)切換時需要模擬一個和編譯器類似的任務(wù)堆棧的操作過程.
OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
INT16U *stk;
opt = opt; /* 'opt' is not used, prevent warning */
//堆棧棧頂指針
stk = (INT16U *)ptos; /* Load stack pointer */
//堆棧有高地址往低地址增長,故使用*stk--
//pada參數(shù)
//假定pdata會被編譯器保存到堆棧中,OSTaskStkInit()就會模仿編譯器的這種行為,將pdata保存到堆棧中.
*stk-- = (INT16U)FP_SEG(pdata); /* Simulate call to function with argument */
*stk-- = (INT16U)FP_OFF(pdata);
//任務(wù)起始地址.理論上,此處應(yīng)該為任務(wù)的返回地址,但在uC/OS-II中,任務(wù)函數(shù)必須為無限循環(huán)結(jié)構(gòu),不能有返回點
*stk-- = (INT16U)FP_SEG(task);
*stk-- = (INT16U)FP_OFF(task);
/*
PC:是你退出的當(dāng)時執(zhí)行程序時program counter,相當(dāng)于你放下手中的事A去進(jìn)行另一莊事情B,你得記住之前A事情已經(jīng)做到什么階段了,也許B事情你得花上1年2年
PSW:是program status word.同樣道理,你開始做B事情的時候必須記住A事情的大致情況status.
堆棧:stack memory就像是一本舊的筆記本,記下A事情的各種問題,以便以后再做A事情,如果又有一個C事情,那B事情也得記到stack memory中
psw指程序狀態(tài)字(program status word的縮寫),是用來控制指令執(zhí)行順序并且保留和指示與程序相關(guān)的系統(tǒng)狀態(tài).
一般說來,程序狀態(tài)字包含程序基本狀態(tài),、中斷碼、中斷屏蔽位三部分內(nèi)容.
基本狀態(tài)包括:指令地址,,條件碼,目態(tài)管態(tài),,等待計算
中斷碼:保存程序執(zhí)行時當(dāng)前發(fā)生的中斷事件,以便操作系統(tǒng)進(jìn)行分析處理
中斷屏蔽位:用來指出不要響應(yīng)出現(xiàn)的中斷事件,,若設(shè)置了中斷屏蔽位,,則即使出現(xiàn)了中斷事件也不中止程序的執(zhí)行,就像沒有發(fā)生中斷事件一樣
*/
//中斷使能-PSW狀態(tài)字-0000 0010 0000 0010即
//堆棧中的SW初始化為0x0202,這將使任務(wù)啟動后允許中斷發(fā)生;如果設(shè)為0x0002,則任務(wù)啟動后將禁止中斷
*stk-- = (INT16U)0x0202; /* SW = Interrupts enabled */
//堆棧頂端放置指向任務(wù)代碼的指針
*stk-- = (INT16U)FP_SEG(task); /* Put pointer to task on top of stack */
*stk-- = (INT16U)FP_OFF(task);
//注意寄存器在堆棧中的位置要和運行指令PUSHA,PUSH ES,和PUSH DS和壓入堆棧的次序相同
//AX,BX,CX,DX,SP,BP,SI,和DI的次序是和指令PUSHA的壓棧次序相同的.如果使用沒有PUSHA指令的8086處理器,就要使用多個PUSH指令壓入上述寄存器,且順序要與PUSHA相同
//AX……的值在任務(wù)運行前無所謂的,因為在任務(wù)運行后在這些寄存器會有新的需要的值,寫0xAAAA……是為了堆棧的這個位置是AX……,其實用其他的值也行
*stk-- = (INT16U)0xAAAA; /* AX = 0xAAAA */
*stk-- = (INT16U)0xCCCC; /* CX = 0xCCCC */
*stk-- = (INT16U)0xDDDD; /* DX = 0xDDDD */
*stk-- = (INT16U)0xBBBB; /* BX = 0xBBBB */
*stk-- = (INT16U)0x0000; /* SP = 0x0000 */
*stk-- = (INT16U)0x1111; /* BP = 0x1111 */
*stk-- = (INT16U)0x2222; /* SI = 0x2222 */
*stk-- = (INT16U)0x3333; /* DI = 0x3333 */
*stk-- = (INT16U)0x4444; /* ES = 0x4444 */
*stk = _DS; /* DS = Current value of DS */
return ((OS_STK *)stk);
}
//浮點仿真任務(wù)棧初始化函數(shù) OSTaskStkInit_FPE_x86(),其中將分段尋址的地址轉(zhuǎn)換為線性地址
void OSTaskStkInit_FPE_x86 (OS_STK **pptos, OS_STK **ppbos, INT32U *psize)
{
INT32U lin_tos; /* 'Linear' version of top-of-stack address */
INT32U lin_bos; /* 'Linear' version of bottom-of-stack address */
INT16U seg;
INT16U off;
INT32U bytes;
seg = FP_SEG(*pptos); /* Decompose top-of-stack pointer into seg:off */
off = FP_OFF(*pptos);
lin_tos = ((INT32U)seg << 4) + (INT32U)off; /* Convert seg:off to linear address */
bytes = *psize * sizeof(OS_STK); /* Determine how many bytes for the stack */
lin_bos = (lin_tos - bytes + 15) & 0xFFFFFFF0L; /* Ensure paragraph alignment for BOS */
seg = (INT16U)(lin_bos >> 4); /* Get new 'normalized' segment */
*ppbos = (OS_STK *)MK_FP(seg, 0x0000); /* Create 'normalized' BOS pointer */
memcpy(*ppbos, MK_FP(_SS, 0), 384); /* Copy FP emulation memory to task's stack */
bytes = bytes - 16; /* Loose 16 bytes because of alignment */
*pptos = (OS_STK *)MK_FP(seg, (INT16U)bytes); /* Determine new top-of-stack */
*ppbos = (OS_STK *)MK_FP(seg, 384); /* Determine new bottom-of-stack */
bytes = bytes - 384;
*psize = bytes / sizeof(OS_STK); /* Determine new stack size */
}