?? os_cpu_c.c
字號:
push cx
push dx
push si
push di
push bp
push sp
pushf
popa可以用
popf
pop sp
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
來代替
如果使用沒有PUSHA指令的8086處理器,就要使用多個PUSH指令壓入上述寄存器,且順序要與PUSHA相同。在程序清單中,每個寄存器被初
始化為不同的值,僅僅是為了調試方便。*/
*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;Borland編譯器支持虛擬寄存器變量操作,可以用_DS關鍵
字取得CPU中DS寄存器的值,程序清單中用_DS直接把DS寄存器復制到堆棧中。*/
return ((OS_STK *)stk); /*堆棧初始化工作結束后,OSTaskStkInit()函數返回新的堆棧棧頂指針,OSTaskCreate()
或OSTaskCreateExt()將指針保存在任務的控制塊OS_TCB中。*/
}
/*$PAGE*/
/*
*********************************************************************************************************
* INITIALIZE A TASK'S STACK FOR FLOATING POINT EMULATION
當使用浮點仿真庫時 見Borland文檔,用Borland編譯器編譯生成的代碼堆棧被安排成如圖見 (邵貝貝UCOS P344)編譯器假設程序運行在
單線程或者說單任務環境下。Borland C浮點仿真庫FPE占用從SS:0x0000開始的大約300B,保存浮點仿真變量。這只適用于大模式。為了到達
到此目的,在調用OSTaskCreate()或者OSTaskCreateExt()建立任何一個用到浮點運算庫的任務前,必須調用專門的函數
OSTaskStkInit_FPE_x86(),對其堆棧結構進行正確的初始化。該函數適用于Borland V3.x和V4.5x編譯器,所以在使用別的編譯器時,最好
不要把OSTaskStkInit_FPE_x86()函數包含進去。浮點仿真庫根據當前的SS寄存器值,將它的數據保存到上述空間中。這里認為從SS:0x0000
開始往上的一些空間是保留給浮點操作用的。
*
* Description: This function MUST be called BEFORE calling either OSTaskCreate() or OSTaskCreateExt() in
* order to initialize the task's stack to allow the task to use the Borland floating-point
* emulation. The returned pointer MUST be used in the task creation call.
*
* Ex.: OS_STK TaskStk[1000];
*
*
* void main (void)
* {
* OS_STK *ptos;
* OS_STK *pbos;
* INT32U size;
*
*
* OSInit();
* .
* .
* ptos = &TaskStk[999];
* pbos = &TaskStk[0];
* psize = 1000;
* OSTaskStkInit_FPE_x86(&ptos, &pbos, &size);
* OSTaskCreate(Task, (void *)0, ptos, 10);
* .
* .
* OSStart();
* }
*
* Arguments : pptos is the pointer to the task's top-of-stack pointer which would be passed to
* OSTaskCreate() or OSTaskCreateExt().一個指向任務棧頂指針TOP的指針(指向指針的指針)。當建立任務
時,任務的棧頂指針TOP會被傳遞給OSTaskCreate()或者OSTaskCreateExt()函數。從數據空間分配到的棧的位置由DS寄存器和一個偏移量確
定。由于OSTaskStkInit_FPE_x86()函數規格化TOP,所以指向初始TOS的指針被傳遞給這個函數,使得TOS值可以修改。
*
* ppbos is the pointer to the new bottom of stack pointer which would be passed to
* OSTaskCreateExt().一個指向任務棧底指針BOS的指針(指向指針的指針)。任務的棧底指針(BOS)不傳遞給
OSTaskCreate()函數,但會傳遞給OSTaskCreateExt()函數。換句話說,ppbos對OSTaskCreateExt()函數是必需的。棧底常常不是在DS:0000
處,而是在DS寄存器加一個偏移量處。因為OSTaskStkInit_FPE_x86()函數規格化BOS,所以指向初試BOS的指針被傳遞給這個函數,使得BOS
值可以修改。
*
* psize is a pointer to the size of the stack (in number of stack elements). You
* MUST allocate sufficient stack space to leave at least 384 bytes for the
* floating-point emulation.一個指向變量的指針,這個變量是堆棧的容量。堆棧的容量參數對于函數
OSTaskCreate()不是必需的,但是對于OSTaskCreateExt()函數卻是必需的。由于OSTaskStkInit_FPE_x86()函數為浮點方針變量保留了一部
分空間,所以實際的堆棧容量會被這個函數修改,這就是要傳遞這個變量指針的原因。必須保證傳遞給OSTaskStkInit_FPE_x86()函數的堆
棧足夠大,能夠容納浮點仿真變量和任務預期的空間。
*
* Returns : The new size of the stack once memory is allocated to the floating-point emulation.
*
* Note(s) : 1) _SS is a Borland 'pseudo-register' and returns the contents of the Stack Segment (SS)
* 2) The pointer to the top-of-stack (pptos) will be modified so that it points to the new
* top-of-stack.
* 3) The pointer to the bottom-of-stack (ppbos) will be modified so that it points to the new
* bottom-of-stack.
* 4) The new size of the stack is adjusted to reflect the fact that memory was reserved on
* the stack for the floating-point emulation.
*********************************************************************************************************
*/
/*$PAGE*/
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;
OSTaskStkInit_FPE_x86()函數從TOS分解出段地址和偏移量開始。*/
off = FP_OFF(*pptos);
lin_tos = ((INT32U)seg << 4) + (INT32U)off; /* Convert seg:off to linear address將棧頂地址轉換為線性地址。
注意:80x86實模式下,段地址乘以16,再加上偏移地址,形成實際內存地址。*/
bytes = *psize * sizeof(OS_STK); /* Determine how many bytes for the stack確定棧的容量,以字節為單位。
注意:在UCOS中,必須將堆棧聲明為OS_STK數據類型,它可以是8位,16位或者32位寬的堆棧。對于Borland編譯器,堆棧寬度是16位,
但最好使用C語言中的sizeof()操作。*/
lin_bos = (lin_tos - bytes + 15) & 0xFFFFFFF0L; /* Ensure paragraph alignment for BOS通過從棧頂地址減去分配給堆棧的
字節數,就得到棧底的線性地址。注意:將棧底地址增加了15B,并且和0xFFFFFFF0L作‘與’運算,用以將BOS與段的邊界,或者說按16
B邊界對齊。就好像是在蓋樓砌磚一樣 為了讓磚的高度相同 而磚的大小不一 就要用水泥填進去 然后抹平 15B就是水泥 然后
& 0xFFFFFFF0L就抹平了 而沒有傷到磚。
所位數據對齊,是指數據所在的內存地址必須是該 數據長度的整數倍,DWORD數據的內存起始地址能被4除盡,WORD數據的內存起始地
址能被2除盡,x86 CPU能直接訪問對齊的數據,當他試圖訪問 一個未對齊的數據時,會在內部進行一系列的調整,這些調整對于程序
來說是透明的,但是會降低運行速度,所以編譯器在編譯程序時會盡量保證數據對齊。
*/
seg = (INT16U)(lin_bos >> 4); /* Get new 'normalized' segment從BOS的線性地址,確定棧底的新的段地址
注意:上一步做了對齊 所以第四位都為0*/
*ppbos = (OS_STK *)MK_FP(seg, 0x0000); /* Create 'normalized' BOS pointer建立一個帶偏移量0x0000的遠程指針,
并賦值給BOS指針。*/
memcpy(*ppbos, MK_FP(_SS, 0), 384); /* Copy FP emulation memory to task's stack為了初始化新任務堆棧的浮點
仿真變量區,只需簡單的將調用本函數任務的堆棧底部復制給新任務的堆棧。注意:調用本函數的任務棧必須是已經初始化了浮點仿真
變量區的棧,不這樣做會引起不可預期的后果。Borland浮點方針FPT庫任務認為,從SS:0x0000開始的大約300B是保留給浮點仿真變量
的。這只適用于大模式下的編譯。筆者決定復制384B(0x0180)。實際上用戶不必復制這么多字節,但筆者認為有一些余量會安全些。這
樣,用戶任務的堆棧至少須有384B加上用戶任務原先的堆棧需求(當然包括中斷嵌套的需求)._SS是Borland的虛擬寄存器,使代碼可以
得到CPU堆棧段寄存器的當前值。而且,筆者決定用ANSI的標準函數memcpy()完成復制,因為Borland優化了該函數。
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include <string.h>
功能:由src所指內存區域復制count個字節到dest所指內存區域。
說明:src和dest所指內存區域不能重疊,函數返回指向dest的指針。
*/
bytes = bytes - 16; /* Loose 16 bytes because of alignment確定規格化的棧頂地址。因為要將
堆棧對齊到段的邊界上,需要先減去16B。如果能保證堆棧段地址的邊界總是對齊的,就不必這么做。這樣作和&0xFFFFFFF0L的做法基本
相同都使得實際地址末四位為零。*/
*pptos = (OS_STK *)MK_FP(seg, (INT16U)bytes); /* Determine new top-of-stack利用新的段地址和新的堆棧容量(對齊到段的
邊界),通過一個遠程指針確定新的棧頂地址TOS。*/
*ppbos = (OS_STK *)MK_FP(seg, 384); /* Determine new bottom-of-stack將BOS上移384B,使之適用于堆棧檢查(如
果程序調用OSTaskStkChk())。*/
bytes = bytes - 384;
*psize = bytes / sizeof(OS_STK); /* Determine new stack size如果使用堆棧檢查,則UCOS需要知道新堆棧的
容量。當然不希望從原先堆棧的底部,而是從新堆棧底部開始檢查。*/
} /*如果任務要作浮點數學運算,那么函數OSTaskStkInit_FPE_x86()的調用必須
在調用OSTaskCreate()或OSTaskCreateExt()函數之前,用以初始化任務堆棧,如同前面描述過的那樣。返回的指針(ptos和pbos)在建立任務
的函數中要用到。注意:pbos被傳遞給OSTaskCreateExt(),作為新堆棧的棧底。若調用OSTaskStkChk()(任務必須是由OSTaskCreateExt()
函數建立的)在運行時檢查堆棧的使用情況,那么OSTaskStkChk()報告的值比堆棧的實際容量少了384B。必須當心,應用代碼不會作任何浮點
異常處理(例如被0除)。這是因為浮點庫在這樣的環境中工作不完全正常,可以通過增加數據范圍檢查,以避免運行中出現異常。*/
/*$PAGE*/
/*
*********************************************************************************************************
* TASK SWITCH HOOK
*
* Description: This function is called when a task switch is performed. This allows you to perform other
* operations during a context switch.作任務切換時,會調用OSTaskSwHook()函數。不管任務切換是通過OSCtxSw()函數
實現的,還是通過OSIntCtxSw()函數(見OS_CPU_A.ASM)實現的,都會調用該函數。OSTaskSwHook()可以直接訪問OSTCBCur和OSTCBHighRdy這
2個全局變量。OSTCBCur指向被切換出去的任務的任務控制塊,而OSTCBHighRdy指向新任務的任務控制塊。注意:在調用OSTaskSwHook()期
間,中斷一直是關掉的。因此附加代碼會影響中斷的響應時間,所以盡量使這部分代碼減至最少。
*
* Arguments : none
*
* Note(s) : 1) Interrupts are disabled during this call.
* 2) It is assumed that the global pointer 'OSTCBHighRdy' points to the TCB of the task that
* will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCur' points to the
* task being switched out (i.e. the preempted task).
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0
void OSTaskSwHook (void)
{
}
#endif
/*
*********************************************************************************************************
* OSTCBInit() HOOK
*
* Description: This function is called by OS_TCBInit() after setting up most of the TCB.OS_TCBInit()函數在調用
OSTaskCreateHook()之前,會先調用OSTCBInitHook()函數中做一些與初始化控制塊OS_TCB有關的處理;在OSTaskCreateHook()中做一些與
初始化任務有關的處理。是否用OSTaskCreateHook()和OSTCBInitHook()函數,完全取決于用戶。同OSTaskCreateHook()一樣,
OSTCBInitHook()會收到指向新添加任務的任務控制塊的指針,而這個新添加任務的任務控制塊絕大部分已經初始化完成,但是還沒有鏈接
到已經建立任務的鏈表中。詳見OS_TCBInit()。
*
* Arguments : ptcb is a pointer to the TCB of the task being created.
*
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203
void OSTCBInitHook (OS_TCB *ptcb)
{
ptcb = ptcb; /* Prevent Compiler warning */
}
#endif
/*
*********************************************************************************************************
* TICK HOOK
*
* Description: This function is called every tick.OSTimeTickHook()函數在每個時鐘節拍都會被OSTimeTick()調用。實際上,
OSTimeTickHook()是在UCOS真正處理時鐘節拍之前被調用的,以便于用戶能先處理應急的事務。
*
* Arguments : none
*
* Note(s) : 1) Interrupts may or may not be ENABLED during this call.
*********************************************************************************************************
*/
#if OS_CPU_HOOKS_EN > 0
void OSTimeTickHook (void)
{
}
#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -