新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > μC/OS-II在80x86上的移植

        μC/OS-II在80x86上的移植

        作者: 時間:2016-10-08 來源:網絡 收藏

        在文件OS_CPU.H的末尾聲明了一個8位變量OSTickDOSCtr,將保存時鐘節拍發生的次數,每發生11次,調用DOS的時鐘節拍函數一次,從而實現與DOS時鐘的同步。OSTickDOSCtr是專門為PC環境而聲明的,如果在其他非PC的系統中運行μC/OS-II,就不用這種同步方法,直接設定時鐘節拍發生頻率就行了。

        9.04 OS_CPU_A.ASM

        μC/OS-II的移植需要用戶改寫OS_CPU_A.ASM中的四個函數:

        OSStartHighRdy()

        OSCtxSw()

        OSIntCtxSw()

        OSTickISR()

        9.04.01 OSStartHighRdy()

        該函數由SStart()函數調用,功能是運行優先級最高的就緒任務,在調用OSStart()之前,用戶必須先調用OSInit(),并且已經至少創建了一個任務(請參考OSTaskCreate()和OSTaskCreateExt()函數)。OSStartHighRdy()默認指針OSTCBHighRdy指向優先級最高就緒任務的任務控制塊(OS_TCB)(在這之前OSTCBHighRdy已由OSStart()設置好了)。圖F9.3給出了由函數OSTaskCreate()或OSTaskCreateExt()創建的任務的堆棧結構。很明顯,OSTCBHighRdy-

        >OSTCBStkPtr指向的是任務堆棧的頂端。

        函數OSStartHighRdy()的代碼見程序清單L9.3。

        圖F9.3 任務創立時的80x86堆棧結構.

        為了啟動任務,OSStartHighRdy()從任務控制塊(OS_TCB)[程序清單L9.3(1)]中找到指向堆棧的指針,然后運行POPDS[程序清單L9.3(2)],POPES[程序清單L9.3(3)],POPA[程序清單L9.3(4)],和IRET[程序清單L9.3(5)]指令。此處筆者將任務堆棧指針保存在任務控制塊的開頭,這樣使得堆棧指針的存取在匯編語言中更容易操作。

        當執行了IRET指令后,CPU會從(SS:SP)指向的堆棧中恢復各個寄存器的值并執行中斷前的指令。SS:SP+4指向傳遞給任務的參數pdata。

        程序清單L 9.3 OSStartHighRdy().

        _OSStartHighRdyPROCFAR

        MOVAX,SEG_OSTCBHighRdy; 載入 DS

        MOVDS,AX;

        LESBX,DWORDPTRDS:_OSTCBHighRdy;SS:SP=OSTCBHighRdy-

        >OSTCBStkPtr (1)

        MOVSS,ES:[BX+2];

        MOVSP,ES:[BX+0];

        ;

        POPDS; 恢復任務環境 (2)

        POPES;(3)

        POPA;(4)

        ;

        IRET; 運行任務 (5)

        _OSStartHighRdyENDP

        9.04.02 OSCtxSw()

        OSCtxSw()是一個任務級的任務切換函數(在任務中調用,區別于在中斷程序中調用的

        OSIntCtxSw())。在80x86系統上,它通過執行一條軟中斷的指令來實現任務切換。軟中斷向量

        指向OSCtxSw()。在μC/OS-II中,如果任務調用了某個函數,而該函數的執行結果可能造成系統

        任務重新調度(例如試圖喚醒了一個優先級更高的任務),則在函數的末尾會調用OSSched(),

        如果OSSched()判斷需要進行任務調度,會找到該任務控制塊OS_TCB的地址,并將該地址拷貝到

        OSTCBHighRdy,然后通過宏OS_TASK_SW()執行軟中斷進行任務切換。注意到在此過程中,變量

        OSTCBCur始終包含一個指向當前運行任務OS_TCB的指針。程序清單L9.4為OSCtxSw()的代碼。

        圖F9.4是任務被掛起或被喚醒時的堆棧結構。在80x86處理器上,任務調用OS_TASK_SW()執

        行軟中斷指令后[圖F9.4/程序清單L9.4(1)],先向堆棧中壓入返回地址(段地址和偏移量),

        然后是狀態字寄存器SW。緊接著用PUSHA[圖F9.4/程序清單L9.4(2)],PUSHES[圖F9.4/程序

        清單L9.4(3)],和PUSHDS[圖F9.4/程序清單L9.4(4)]保存任務運行環境。最后用OSCtxSw()在

        任務OS_TCB中保存SS和SP寄存器。

        任務環境保存完后,將調用用戶定義的對外接口函數OSTaskSwHook()[程序清單L9.4(6)]。

        請注意,此時OSTCBCur指向當前任務OS_TCB,OSTCBHighRdy指向新任務的OS_TCB。在

        OSTaskSwHook()中,用戶可以訪問這兩個任務的OS_TCB。如果不使用對外接口函數,請在頭文

        件中把相應的開關選項關閉,加快任務切換的速度。

        程序清單L9.4 OSCtxSw().

        _OSCtxSwPROCFAR(1)

        ;

        PUSHA; 保存當前任務環境 (2)

        PUSHES (3)

        PUSHDS (4)

        ;

        MOVAX,SEG_OSTCBCur; 載入DS

        MOVDS,AX

        ;

        LESBX,DWORDPTRDS:_OSTCBCur;OSTCBCur->OSTCBStkPtr=SS:S(5)

        MOVES:[BX+2],SS

        MOVES:[BX+0],SP

        ;

        CALLFARPTR_OSTaskSwHook(6)

        ;

        MOVAX,WORDPTRDS:_OSTCBHighRdy+2;OSTCBCur=OSTCBHighRdy(7)

        MOVDX,WORDPTRDS:_OSTCBHighRdy

        MOVWORDPTRDS:_OSTCBCur+2,AX

        MOVWORDPTRDS:_OSTCBCur,DX

        ;

        MOVAL,BYTEPTRDS:_OSPrioHighRdy;OSPrioCur=OSPrioHighRdy(8)

        MOVBYTEPTRDS:_OSPrioCur,AL

        ;

        LESBX,DWORDPTRDS:_OSTCBHighRdy;SS:SP=OSTCBHighRdy-

        >OSTCBStkPtr (9)

        MOVSS,ES:[BX+2]

        MOVSP,ES:[BX]

        ;

        POPDS; 載入新任務的CPU環境 (10)

        POPES (11)

        POPA (12)

        ;

        IRET; 返回新任務 (13)

        ;

        _OSCtxSwENDP

        從對外接口函數OSTaskSwHook()返回后,由于任務的更替,變量OSTCBHighRdy被拷貝到

        OSTCBCur中[程序清單L9.4(7)],同樣,OSPrioHighRdy被拷貝到OSPrioCur中[程序清單

        L9.4(8)]。OSCtxSw()將載入新任務的CPU環境,首先從新任務OS_TCB中取出SS和SP寄存器的值

        [圖F9.4(6)/程序清單L9.4(9)],然后運行POPDS[圖F9.4(7)/程序清單L9.4(10)],POPES

        [圖F9.4(8)/程序清單L9.4(11)],POPA[圖F9.4(9)/程序清單L9.4(12)]取出其他寄存器的值,

        最后用中斷返回指令IRET[圖F9.4(10)/L9.4(13)]完成任務切換。

        需要注意的是在運行OSCtxSw()和OSTaskSwHook()函數期間,中斷是禁止的。

        9.04.03 OSIntCtxSw()

        在μC/OS-II中,由于中斷的產生可能會引起任務切換,在中斷服務程序的最后會調用



        關鍵詞:

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 抚顺县| 红河县| 敖汉旗| 新蔡县| 克东县| 永济市| 昂仁县| 龙口市| 渭南市| 宁波市| 榆林市| 嘉善县| 平安县| 彭阳县| 邢台县| 鹤岗市| 新绛县| 通州市| 东辽县| 都昌县| 平原县| 鹤岗市| 彰武县| 荃湾区| 高邑县| 黄陵县| 双桥区| 公主岭市| 宣化县| 工布江达县| 延长县| 淮南市| 乐东| 长汀县| 克什克腾旗| 临西县| 当涂县| 威远县| 华阴市| 东乌| 葫芦岛市|