<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • x
    x

    Qsys與uC/OS學習筆記6:任務切換-續

    發布時間:2016-1-26 11:55    發布者:designapp
    關鍵詞: Qsys
    uC/OS-II總是運行進入就緒態任務中優先級最高的任務。確定哪個優先級最高,下面要由哪個任務運行了,這一工作是由任務調度函數OS_Sched (void)完成的。當前就緒任務要交出CPU控制權并進行任務切換的相關操作都調用了OS_Sched (void)函數。
    如圖1所示,當前運行態任務交出CPU控制權必須是以下某個函數被調用或某事件發生:OSFlagPend()、OSMboxPend()、OSMutexPend()、OSQPend()、OSSemPend()、OSTaskSuspend()、OSTimeDly()、OSTimeDlyHMSM()、OSTaskDel()或中斷等。



    圖1

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

    //*_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();
    }

    在該函數中,簡單的講,只是做了兩件事,首先找出當前優先級最高的就緒任務(也可能是運行態任務本身),其次調用了任務級的任務切換函數OS_TASK_SW(),由此進行切換任務間的出棧入棧操作,并模擬一次CPU中斷完成任務切換。

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

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

    //*_bspàHALàincàos_cpu.h
    #define OS_TASK_SW OSCtxSw
    void OSCtxSw(void);

    OSCtxSw(void)函數程序如下:

    //*_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()函數貌似非常神秘,畢竟是用匯編語言寫的,估計大伙都看不懂。不過沒有關系,它在做的事情也并不神秘。正如我們前面所言,它首先模擬產生一次軟中斷,接著讓當前運行的任務入棧,讓即將運行的最高優先級的就緒態任務出棧,就此完成CPU寄存器現場的轉換(偷梁換柱的精髓就在此),最后執行一條ret指令表示前面的軟中斷程序已經執行完畢,返回(即進入新的任務執行程序)。

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

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

    參考資料:
    1. 《嵌入式實時操作系統uC/OS-II(第2版)》91頁:3.05 任務調度。
    2. 《嵌入式實時操作系統uC/OS-II(第2版)》92頁:3.06 任務級的任務切換,OS_TASK_SW()。
    3. 《嵌入式實時操作系統uC/OS-II(第2版)》355頁:14.05.02 OSCtxSw()。
    4. Altera Nios II 11.0 Software Build Tools for Eclipse的模板uC/OS-II工程。
    本文地址:http://www.portaltwn.com/thread-160378-1-1.html     【打印本頁】

    本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
    您需要登錄后才可以發表評論 登錄 | 立即注冊

    廠商推薦

    • Microchip視頻專區
    • 我們是Microchip
    • 想要避免發生災難,就用MPLAB SiC電源仿真器!
    • 利用模擬開發工具生態系統進行安全電路設計
    • 更佳設計的解決方案——Microchip模擬開發生態系統
    • 貿澤電子(Mouser)專區
    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷