在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > Qsys與uC/OS學(xué)習(xí)筆記6:任務(wù)切換-續(xù)

            Qsys與uC/OS學(xué)習(xí)筆記6:任務(wù)切換-續(xù)

            作者: 時間:2015-12-09 來源:網(wǎng)絡(luò) 收藏

              -II總是運(yùn)行進(jìn)入就緒態(tài)任務(wù)中優(yōu)先級最高的任務(wù)。確定哪個優(yōu)先級最高,下面要由哪個任務(wù)運(yùn)行了,這一工作是由任務(wù)調(diào)度函數(shù)OS_Sched (void)完成的。當(dāng)前就緒任務(wù)要交出CPU控制權(quán)并進(jìn)行任務(wù)切換的相關(guān)操作都調(diào)用了OS_Sched (void)函數(shù)。

            本文引用地址:http://www.biyoush.com/article/284117.htm

              如圖1所示,當(dāng)前運(yùn)行態(tài)任務(wù)交出CPU控制權(quán)必須是以下某個函數(shù)被調(diào)用或某事件發(fā)生:OSFlagPend()、OSMboxPend()、OSMutexPend()、OSQPend()、OSSemPend()、OSTaskSuspend()、OSTimeDly()、OSTimeDlyHMSM()、OSTaskDel()或中斷等。


              圖1

              我們來看看OS_Sched (void)函數(shù)的程序:

             //*_bspàUCOSIIàsrcàos_core.c

              void OS_Sched (void)

              {

              #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

              OS_CPU_SR cpu_sr = 0;

              #endif

              OS_ENTER_CRITICAL();

              if (OSIntNesting == 0) { /* Schedule only if all ISRs done and ... */

              if (OSLockNesting == 0) { /* ... scheduler is not locked */

              OS_SchedNew();

              if (OSPrioHighRdy != OSPrioCur) {

              /* No Ctx Sw if current task is highest rdy */

              OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

              #if OS_TASK_PROFILE_EN > 0

              OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */

              #endif

              OSCtxSwCtr++; /* Increment context switch counter */

              OS_TASK_SW(); /* Perform a context switch */

              }

              }

              }

              OS_EXIT_CRITICAL();

              }

              在該函數(shù)中,簡單的講,只是做了兩件事,首先找出當(dāng)前優(yōu)先級最高的就緒任務(wù)(也可能是運(yùn)行態(tài)任務(wù)本身),其次調(diào)用了任務(wù)級的任務(wù)切換函數(shù)OS_TASK_SW(),由此進(jìn)行切換任務(wù)間的出棧入棧操作,并模擬一次CPU中斷完成任務(wù)切換。

              任務(wù)級的任務(wù)切換函數(shù)OS_TASK_SW()首先對當(dāng)前運(yùn)行任務(wù)在CPU寄存器中的現(xiàn)場進(jìn)行保存,即入棧;其次把即將運(yùn)行的就緒態(tài)任務(wù)上一次運(yùn)行時的現(xiàn)場恢復(fù)到當(dāng)前CPU寄存器中,即出棧,注意每個任務(wù)都有自己專屬的堆棧區(qū);最后使用軟中斷指令或陷阱TRAP人為模擬一次中斷產(chǎn)生,從而讓這個中斷返回的時候順利的從原任務(wù)程序中切換到了新任務(wù)程序中(因為當(dāng)前CPU寄存器的現(xiàn)場已經(jīng)從原任務(wù)的變成了新任務(wù)的)。

              OS_TASK_SW()實際上是個宏調(diào)用,而OSCtxSw(void)函數(shù)通常是匯編語言編寫的,因為C編譯器通常不支持C語言直接操作CPU的寄存器。

             //*_bspàHALàincàos_cpu.h

              #define OS_TASK_SW OSCtxSw

              void OSCtxSw(void);

              OSCtxSw(void)函數(shù)程序如下:

              //*_bspàHALàsrcàos_cpu_a.S

              /*********************************************************************************

              * PERFORM A CONTEXT SWITCH

              * void OSCtxSw(void) - from task level

              * void OSIntCtxSw(void) - from interrupt level

              *

              * Note(s): 1) Upon entry,

              * OSTCBCur points to the OS_TCB of the task to suspend

              * OSTCBHighRdy points to the OS_TCB of the task to resume

              *

              ********************************************************************************/

              .global OSIntCtxSw

              .global OSCtxSw

              OSIntCtxSw:

              OSCtxSw:

              /*

              * Save the remaining registers to the stack.

              */

              addi sp, sp, -44

              #ifdef ALT_STACK_CHECK

              bltu sp, et, .Lstack_overflow

              #endif

              #if OS_THREAD_SAFE_NEWLIB

              ldw r3, %gprel(_impure_ptr)(gp) /* load the pointer */

              #endif /* OS_THREAD_SAFE_NEWLIB */

              ldw r4, %gprel(OSTCBCur)(gp)

              stw ra, 0(sp)

              stw fp, 4(sp)

              stw r23, 8(sp)

              stw r22, 12(sp)

              stw r21, 16(sp)

              stw r20, 20(sp)

              stw r19, 24(sp)

              stw r18, 28(sp)

              stw r17, 32(sp)

              stw r16, 36(sp)

              #if OS_THREAD_SAFE_NEWLIB

              /*

              * store the current value of _impure_ptr so it can be restored

              * later; _impure_ptr is asigned on a per task basis. It is used

              * by Newlib to achieve reentrancy.

              */

              stw r3, 40(sp) /* save the impure pointer */

              #endif /* OS_THREAD_SAFE_NEWLIB */

              /*

              * Save the current tasks stack pointer into the current tasks OS_TCB.

              * i.e. OSTCBCur->OSTCBStkPtr = sp;

              */

              stw sp, (r4) /* save the stack pointer (OSTCBStkPtr */

              /* is the first element in the OS_TCB */

              /* structure. */

              /*

              * Call the user definable OSTaskSWHook()

              */

              call OSTaskSwHook

              0:

              9:

              /*

              * OSTCBCur = OSTCBHighRdy;

              * OSPrioCur = OSPrioHighRdy;

              */

              ldw r4, %gprel(OSTCBHighRdy)(gp)

              ldb r5, %gprel(OSPrioHighRdy)(gp)

              stw r4, %gprel(OSTCBCur)(gp)

              /* set the current task to be the new task */

              stb r5, %gprel(OSPrioCur)(gp)

              /* store the new task's priority as the current */

              /* task's priority */

              /*

              * Set the stack pointer to point to the new task's stack

              */

              ldw sp, (r4) /* the stack pointer is the first entry in the OS_TCB structure */

              #if defined(ALT_STACK_CHECK) && (OS_TASK_CREATE_EXT_EN > 0)

              ldw et, 8(r4) /* load the new stack limit */

              #endif

              #if OS_THREAD_SAFE_NEWLIB

              /*

              * restore the value of _impure_ptr ; _impure_ptr is asigned on a

              * per task basis. It is used by Newlib to achieve reentrancy.

              */

              ldw r3, 40(sp) /* load the new impure pointer */

              #endif /* OS_THREAD_SAFE_NEWLIB */

              /*

              * Restore the saved registers for the new task.

              */

              ldw ra, 0(sp)

              ldw fp, 4(sp)

              ldw r23, 8(sp)

              ldw r22, 12(sp)

              ldw r21, 16(sp)

              ldw r20, 20(sp)

              ldw r19, 24(sp)

              ldw r18, 28(sp)

              ldw r17, 32(sp)

              ldw r16, 36(sp)

              #if OS_THREAD_SAFE_NEWLIB

              stw r3, %gprel(_impure_ptr)(gp) /* update _impure_ptr */

              #endif /* OS_THREAD_SAFE_NEWLIB */

              #if defined(ALT_STACK_CHECK) && (OS_TASK_CREATE_EXT_EN > 0)

              stw et, %gprel(alt_stack_limit_value)(gp)

              #endif

              addi sp, sp, 44

              /*

              * resume execution of the new task.

              */

              ret

              #ifdef ALT_STACK_CHECK

              .Lstack_overflow:

              break 3

              #endif

              .set OSCtxSw_SWITCH_PC,0b-OSCtxSw

              這個OS_TASK_SW()函數(shù)貌似非常神秘,畢竟是用匯編語言寫的,估計大伙都看不懂。不過沒有關(guān)系,它在做的事情也并不神秘。正如我們前面所言,它首先模擬產(chǎn)生一次軟中斷,接著讓當(dāng)前運(yùn)行的任務(wù)入棧,讓即將運(yùn)行的最高優(yōu)先級的就緒態(tài)任務(wù)出棧,就此完成CPU寄存器現(xiàn)場的轉(zhuǎn)換(偷梁換柱的精髓就在此),最后執(zhí)行一條ret指令表示前面的軟中斷程序已經(jīng)執(zhí)行完畢,返回(即進(jìn)入新的任務(wù)執(zhí)行程序)。

              關(guān)于軟中斷如何產(chǎn)生,開始也讓筆者非常納悶,教科書上總是非常學(xué)術(shù)的告訴我們“使用軟中斷指令或陷阱TRAP人為模擬一次中斷產(chǎn)生”,而理論上這個軟中斷或TRAP指令應(yīng)該是一條簡單的匯編指令而已,但在NIOS II中移植的這個OS_TASK_SW()函數(shù)中卻沒能找到,整個函數(shù)尋覓下來好像真沒有哪條指令看上去像軟中斷或TRAP指令,找遍NIOS II Processor Reference Handbook也沒能看到哪條指令能夠完成軟中斷或TRAP的功能。在原作者的《嵌入式實時操作系統(tǒng)-II(第2版)》第14章給出的80x86上移植的OS_TASK_SW()函數(shù)實例中也沒有找到類似的指令,其操作程序和NIOS II中移植的大同小異,那到底怎么回事?

              有意思的是,最一篇講述軟中斷指令的文章(http://course.cug.edu.cn/21cn/微機(jī)原理與應(yīng)用/0329.htm)中找到了蛛絲馬跡,這里提出了8086/8088中軟中斷的助記符為INT OPR,并且給出了這條指令實際運(yùn)行狀況卻是多個相關(guān)寄存器的“躲閃騰挪”后完成的。那么回頭看作者給出的80x86和NIOS II移植程序,雖然沒有和INT OPR類似的專用的軟中斷指令,但函數(shù)里面某些指令操作卻同樣能夠完成軟中斷這個動作。

              參考資料:

              1. 《嵌入式實時操作系統(tǒng)-II(第2版)》91頁:3.05 任務(wù)調(diào)度。

              2. 《嵌入式實時操作系統(tǒng)uC/OS-II(第2版)》92頁:3.06 任務(wù)級的任務(wù)切換,OS_TASK_SW()。

              3. 《嵌入式實時操作系統(tǒng)uC/OS-II(第2版)》355頁:14.05.02 OSCtxSw()。

              4. Altera Nios II 11.0 Software Build Tools for Eclipse的模板uC/OS-II工程。





            關(guān)鍵詞: Qsys uC/OS

            評論


            相關(guān)推薦

            技術(shù)專區(qū)

            關(guān)閉