?? os_cpu_a.asm
字號:
;********************************************************************************************************
; uC/OS-II
; The Real-Time Kernel
;
; (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
; All Rights Reserved
;
;
; 80x86/80x88 Specific code
; LARGE MEMORY MODEL
;
; Borland C/C++ V4.51
; (IBM/PC Compatible Target)
;
; File : OS_CPU_A.ASM
; By : Jean J. Labrosse
;********************************************************************************************************
;********************************************************************************************************
; PUBLIC and EXTERNAL REFERENCES
;********************************************************************************************************
PUBLIC _OSTickISR ;匯編的子程序共享的方法
;把一個程序中多次重復出現的程序段編寫成子程序是為了個別程序的簡化,而把具有固定功能的程序段寫成子程序則是為了
;在多個程序間共享。因此有必要對那些普遍適用的子程序進行適當的管理,當需要使用它們時,可以很方便的取出。子程序
;共享的方式大致有以下3種。
;1:復制子程序的源代碼,但要注意去了子程序名之外可能還會用到一些標識符,如子程序內需要使用的變量,標號等。當
;子程序清單復制到某個源程序之后,子程序內的標識符有可能與程序的其余部分的標識符同名,這種標識符的重復定義是不
;符合匯編語言語法規定的,需要修改。
;2:INCLUDE 偽指令 每個子程序以獨立的文本文件的形式存在,有利有弊,其中使程序員感到不便的是,每當需要使用某個
;子程序時,總是要手工地把這個子程序的程序清單調到使用它的源程序中。如果能夠把源程序和所用到的子程序分別放在不同
;的問家中,只在源程序中很簡潔的申明在何處需要引用哪個子程序文件,那么使用起來就方便多了。使用INCLUDE偽指令可以
;解決這個問題。
;3,庫文件.LIB 子程序共享還有一種方法是建立子程序的庫文件.LIB 在微軟提供的匯編語言工作環境中,有一個專門管理子程序
;庫文件的程序LIB.EXE,它的主要功能包括建立新的庫文件,向庫文件中放入新的子程序和從中取出子程序,以及更新其中的子程序
;市容LIB軟件之前,必須先把子程序寫入一個段中,并且用PUBLIC偽指令說明該子程序可供外部調用,然后把子程序匯編成目標程序。
;PUBLIC 指令功能:由PUBLIC定義的符號名為全局符號名,由本模塊程序定義,允許程序中其他模塊直接調用,沒有被說明的符號名
;不能被其他模塊調用。
;EXTRN 指令功能:通知匯編程序本模塊中的符號名是外部符號名,已在其他模塊中被定義,即被其他模塊中的PUBLIC說明,在本模塊
;中可被調用,沒有定義的外部符號名不能被引用。EXTRN定義的符號名為變量名,類型可以為BYTE,WORD,DWORD,或QWORD。若定義的
;符號名為標號,則類型為NEAR或FAR。若定義的符號名為常量,則類型為ABS。注意:PUBLIC模塊定義偽指令和SEGMENT偽指令中的
;PUBLIC組合類型是兩個不同的概念。個模塊內的PUBLIC語句和EXTRN語句應相關聯,在EXTRN中出現的符號名必須在PUBIL中被定義,且
;類型要相一致,否則鏈接會出錯。
PUBLIC _OSStartHighRdy
PUBLIC _OSCtxSw
PUBLIC _OSIntCtxSw
EXTRN _OSIntExit:FAR
EXTRN _OSTimeTick:FAR
EXTRN _OSTaskSwHook:FAR
EXTRN _OSIntNesting:BYTE
EXTRN _OSTickDOSCtr:BYTE
EXTRN _OSPrioHighRdy:BYTE
EXTRN _OSPrioCur:BYTE
EXTRN _OSRunning:BYTE
EXTRN _OSTCBCur:DWORD
EXTRN _OSTCBHighRdy:DWORD
.MODEL LARGE;指令功能:定義數據段和代碼段存儲模式,常用存儲模式選擇符有 TINY,SMALL,MEDIUM,COMPACT,LARGE,HUGE,FLAT
;LARGE 大型模式:代碼段和數據段分別放在多個64K段中,但全部靜態數據長度不能超過64KB。代碼段和數據段默認為遠訪問。
.CODE ;指令功能:定義一個代碼段,對多個代碼段各段應有自己的段名。在LARGE模式下,默認代碼段名為 模塊名_TEXT
.186 ;這是一條說明處理器類型的偽指令 .186,只支持對80186指令的匯編
PAGE ;規定段從頁邊界開始,即該段起始地址的最低字節位必須為‘00000000B’,屬性為256
; /*$PAGE*/
;*********************************************************************************************************
; START MULTITASKING
; void OSStartHighRdy(void)
該函數由OSStart()函數調用,功能是讓進入就緒態的優先級最高的任務運行。在調用OSStart()之前,必須先調用OSInit()函數,且已經
建立了只好一個任務(見OSTaskCreate()和OSTaskCreateExt()函數)。OSStartHighRdy()默認指針OSTCBHighRdy指向優先級最高的就緒態任
務的任務控制塊(OS_TCB)
;
; The stack frame is assumed to look as follows:
;
; OSTCBHighRdy->OSTCBStkPtr --> DS (Low memory)
; ES
; DI
; SI
; BP
; SP
; BX
; DX
; CX
; AX
; OFFSET of task code address
; SEGMENT of task code address
; Flags to load in PSW
; OFFSET of task code address
; SEGMENT of task code address
; OFFSET of 'pdata'
; SEGMENT of 'pdata' (High memory)
;
; Note : OSStartHighRdy() MUST:
; a) Call OSTaskSwHook() then,
; b) Set OSRunning to TRUE,
; c) Switch to the highest priority task.
;*********************************************************************************************************
_OSStartHighRdy PROC FAR ;PROC定義了一個子程序子程序名是一個標識符_OSStartHighRdy,它即是編程者給子程序起的名字,也是子
;程序第一條指令所在的邏輯地址,成為子程序的入口地址。PROC后面的類型 只有FAR和NEAR兩種,它將影響匯編程序對子程序調用指令
;CALL和返回指令RET的翻譯方式。通常指令序列的最后一條指令是返回指令RET。
MOV AX, SEG _OSTCBHighRdy ; Reload DS
MOV DS, AX ;
;
CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook在第13章提到過的,在OSStartHighRdy()
; 啟動之前,必須先調用函數OSTaskSwHook(),而OSTaskSwHook()函數必須查詢OSRunning的狀態(此時OSRunning的狀態是FALSE
; )。OSTaskSwHook()只做恢復CPU寄存器的操作,并不需要作先保存,再恢復的操作。注意操作符PTR 這里指定了標號跳轉遠跳
;轉。如果是 JMP DWORD PTR[SI] 則是CS<-((SI+2)),IP<-((SI))
;
MOV AL, 1 ; OSRunning = TRUE;OSStartHighRdy()函數把OSRunning設成TRUE,這樣以后在
;調用OSTaskSwHook()時,OSTaskSwHook()函數便可以進行先保存,再恢復環境的操作了。由于代碼是用匯編語言寫的,不能從C編譯器中
;得到TURE的準確值。這里假設TRUE是1.
MOV BYTE PTR DS:_OSRunning, AL ; (Indicates that multitasking has started)
;
LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr;OSStartHighRdy()從任務控制塊OS_TCB
;中獲得并恢復堆棧指針。如同前面提到的,堆棧指針的值保存在任務控制塊TCB的開始處(也就是任務控制塊OS_TCB),這樣較容易用匯編
;語言訪問該指針。這里DWORD PTR 強制轉換了類型
MOV SS, ES:[BX+2] ;
MOV SP, ES:[BX+0] ;
;
POP DS ; Load task's context;OSStartHighRdy()把CPU所有整數寄存器的值保存在任務
;堆棧中
POP ES ;
POPA ;等價于
; popf
; pop sp
; pop bp
; pop di
; pop si
; pop dx
; pop cx
; pop bx
; pop ax
; 來代替
;
IRET ; Run task;執行IRET指令,從中斷返回。這里建立了任務的堆棧結構,看起來好
;像剛發生了中斷,所有的CPU寄存器都被推入堆棧中。IRET指令將任務的入口地址從堆棧中彈出,并把任務入口地址放在CS:IP寄存器中,
;地址后面跟著的值(叫做狀態字或者狀態位)放在SW寄存器中。 IRET的作用是 出棧三個字,依次是IP,CS,標志寄存器。注意使用IRET比
;使用RET多了 一個返回標志寄存器的功能。
;執行IRET指令,堆棧指針SS:SP指向任務返回地址,這樣看起來好像是任務被一個普通函數調用了。SS:SP+4指向自變量pdata,pdata會給
;任務傳遞參數。換句話說,任務無須了解它是被OSStartHighRdy函數調用的,還是被其他函數調用的。
_OSStartHighRdy ENDP
PAGE ; /*$PAGE*/
;*********************************************************************************************************
; PERFORM A CONTEXT SWITCH (From task level)
; void OSCtxSw(void)
OSCtxSw()是一個任務級的任務切換函數,在任務中調用,區別在于中斷程序中調用的OSIntCtxSw()。80X86系統上,它通過執行一條軟中斷
指令實現任務切換,軟中斷向量指向OSCtxSw()。在UCOS中,如果任務調用了某函數,而該函數的執行結果可能造成系統任務重新調度,例
如喚醒了一個優先級更高的任務,使當前運行著的任務已經不是最重要的任務了,則UCOS會在函數的末尾調用OSSched(),如果OSSched()
判斷需要進行任務調度,則會找到該任務控制塊OS_TCB的地址,并將該地址復制給OSTCBHighRdy,然后通過宏OS_TASK_SW()執行軟中斷,
進行任務切換。
注意:在此過程中變量OSTCBCur始終包含指向當前運行任務的控制塊OS_TCB的指針。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -