?? os_cpu_a.asm
字號:
; AX
; OFFSET of task code address
; SEGMENT of task code address
; Flags to load in PSW (High memory)
;*********************************************************************************************************
_OSIntCtxSw PROC FAR
;
CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook;OSIntCtxSw()做的第1件事是,調用可
;由用戶定義的任務接口函數OSTaskSwHook()。注意:當調用OSTaskSwHook()時,OSTCBCur指向當前任務的任務控制塊OS_TCB,而
;OSTCBHighRdy指向新任務的任務控制塊OS_TCB。這樣可以從OSTaskSwHook()中訪問這2個任務的任務控制塊OS_TCB中的任何一個。
;同樣,如果不想使用OSTaskSwHook(),則可以注釋掉這條語句。這樣在任務切換時,可以節省幾個時鐘周期。
;
MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered報警
MOV DS, AX ;
;
MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy當從OSTaskSwHook()返回時,OSTCBHighRdy復制給
;OSTCBCur,這是因為此時新任務應該是當前任務。
MOV DX, WORD PTR DS:_OSTCBHighRdy ;
MOV WORD PTR DS:_OSTCBCur+2, AX ;
MOV WORD PTR DS:_OSTCBCur, DX ;
;
MOV AL, BYTE PTR DS:_OSPrioHighRdy ; OSPrioCur = OSPrioHighRdy;OSPrioHighRdy也復制給OSPrioCur,這也是因為
;此時新任務應該是當前任務。
MOV BYTE PTR DS:_OSPrioCur, AL
;
LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr;至此,OSCtxSw()應該把新任務的運行
;環境裝入到處理器的寄存器中。這是通過從新任務的任務控制塊OS_TCB中獲取寄存器SS和寄存器SP的值來實現的。
MOV SS, ES:[BX+2] ;
MOV SP, ES:[BX] ;
;
POP DS ; Load new task's context從堆棧中彈出和恢復CPU的其余寄存器。
POP ES ;
POPA ;
;
IRET ; Return to new task執行IRET指令,設置新任務的程序計數器和狀態字。執行
;了這一指令后,處理器恢復執行新任務。注意:在執行OSIntCtxSw()時,中斷是關掉的;在執行用戶定義的OSTaskSwHook()接口函數時,
;中斷也是關掉的。
;
_OSIntCtxSw ENDP
PAGE ; /*$PAGE*/
;*********************************************************************************************************
; HANDLE TICK ISR
;
; Description: This function is called 199.99 times per second or, 11 times faster than the normal DOS
; tick rate of 18.20648 Hz. Thus every 11th time, the normal DOS tick handler is called.
; This is called chaining. 10 times out of 11, however, the interrupt controller on the PC
; must be cleared to allow for the next interrupt.
在OS_CPU.H,時鐘節拍頻率中已經提到實時操作系統的時鐘節拍頻率應為10~100Hz。在PC中,時鐘節拍由硬件定時器產生,硬件定時器會中
斷CPU,間隔是54.93ms(18.206 48HZ)。筆者將時鐘節拍頻率設為200HZ。PC機時鐘節拍的中斷向量為0x08,UCOS將此向量截取,使之指向UC
OS的時鐘節拍中斷服務子程序OSTickISR(),而原先的中斷向量保存在中斷向量129(0x81)中(參見PC.C文件中的PC_DOSSaveReturn()函數)。
為滿足DOS的需要,原先的中斷服務還是每隔54.93ms(實際上還要短些)調用1次。在UCOS中,當調用OSStart()啟動多任務環境后,時鐘中斷
的作用是非常重要的但是PC環境下,啟動UCOS之前就已經有時鐘中斷發生了。實際上希望在UCOS初始化完成之后,再發生時鐘中斷,調用
OSTickISR()。為了防止中斷服務子程序ISR在UCOS準備好之前調用OSTickISR(),需要作以下的工作:
Main()
調用OSInit()初始化UCOS;
調用PC_DOSSaveReturn()見PC.C
調用PC_VectSet把OSCtxSw放在向量0x80處;
建立至少1個應用任務
調用OSStart(),以運行多任務。
第一個任務要作的工作有:
把OSTickISR()的起始地址放在向量0x08處
時鐘節拍從18.206 48HZ改變為200HZ。
PC上時鐘處理很巧妙,
;
; Arguments : none
;
; Returns : none
;
; Note(s) : The following C-like pseudo-code describe the operation being performed in the code below.
;
; Save all registers on the current task's stack;如同所有UCOS的中斷服務子程序一樣,所有的寄存器須保存在當前
任務的堆棧中。
; OSIntNesting++;當進入中斷服務子程序ISR時,須告訴UCOS,進入中斷服務子程序了。可以通過OSIntEnter()實現,或以
直接給中斷嵌套OSIntNesting加1的方式實現。直接給OSIntNesting加1會更快一些。OSIntEnter()實現,或以直接給中斷嵌套層數
OSIntNesting加1的方式實現。直接給OSIntNesting加1會更快一些。OSIntEnter()會檢查OSIntNesting是否超過了255,這樣,中斷嵌套會更
安全些
; if (OSIntNesting == 1) {
; OSTCBCur->OSTCBStkPtr = SS:SP;如果中斷服務子程序是中斷的第一層,即沒有中斷嵌套,則需要把堆棧指針保存在
當前任務的任務控制塊OS_TCB中。
; }
; OSTickDOSCtr--;
; if (OSTickDOSCtr == 0) {
; OSTickDOSCtr = 11; 計數器OSTickDOSCtr減一,當OSTickDOSCtr為0時,調用DOS的時鐘節拍處理函數。這種情況每隔
54.93ms發生一次
; INT 81H; Chain into DOS every 54.925 mS
; (Interrupt will be cleared by DOS)清中斷
; } else {
; Send EOI to PIC; Clear tick interrupt by sending an End-Of-Interrupt to the 8259
; PIC (Priority Interrupt Controller)
11次中有10次,中斷優先級控制器PIC會收到一個清除中斷的指令。注意:當調用DOS的時鐘節拍處理函數時,這一操作不是必須的,因為
DOS的時鐘節拍處理函數直接清除中斷源。
; }
; OSTimeTick(); Notify uC/OS-II that a tick has occured;OSTickISR()調用OSTimeTick(),這樣UCOS就
給所有延遲任務的等待時間以及有時限的等待某事件發生的任務的等待時間的節拍參數減1.
; OSIntExit(); Notify uC/OS-II about end of ISR當所有中斷服務子程序完成時,調用OSIntExit()。如
果中斷服務子程序(或者其他嵌套的中斷服務子程序)使一個更高優先級的任務進入了就緒態,并且當前中斷服務子程序已經脫離了中斷嵌套
,那么OSIntExit()不再返回OSTickISR()。OSIntCtxSw()恢復新任務的所有寄存器,并執行一個IRET指令。如果中斷服務子程序沒有脫離
中斷嵌套,或者中斷服務子程序沒有使更高優先級的任務進入就緒態,OSIntExit()就返回OSTickISR()。
; Restore all registers that were save on the current task's stack;
; Return from Interrupt; 如果OSIntExit()返回,則是因為OSIntExit()沒有發現更高優先級的任務。這樣被中斷任務
的寄存器會被恢復。當執行IRET指令時,中斷服務子程序返回,讓被中斷了的任務繼續運行。
;*********************************************************************************************************
;
_OSTickISR PROC FAR
;
PUSHA ; Save interrupted task's context此段注釋同上文
PUSH ES
PUSH DS
;
MOV AX, SEG(_OSIntNesting) ; Reload DS
MOV DS, AX
INC BYTE PTR DS:_OSIntNesting ; Notify uC/OS-II of ISR
;
CMP BYTE PTR DS:_OSIntNesting, 1 ; if (OSIntNesting == 1)
JNE SHORT _OSTickISR1
MOV AX, SEG(_OSTCBCur) ; Reload DS
MOV DS, AX
LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:[BX+2], SS ;
MOV ES:[BX+0], SP ;
;
_OSTickISR1:
MOV AX, SEG(_OSTickDOSCtr) ; Reload DS
MOV DS, AX
DEC BYTE PTR DS:_OSTickDOSCtr
CMP BYTE PTR DS:_OSTickDOSCtr, 0
JNE SHORT _OSTickISR2 ; Every 11 ticks (~199.99 Hz), chain into DOS
;
MOV BYTE PTR DS:_OSTickDOSCtr, 11
INT 081H ; Chain into DOS's tick ISR
JMP SHORT _OSTickISR3
_OSTickISR2:
MOV AL, 20H ; Move EOI code into AL.
MOV DX, 20H ; Address of 8259 PIC in DX.
OUT DX, AL ; Send EOI to PIC if not processing DOS timer.
;
_OSTickISR3:
CALL FAR PTR _OSTimeTick ; Process system tick
;
CALL FAR PTR _OSIntExit ; Notify uC/OS-II of end of ISR
;
POP DS ; Restore interrupted task's context
POP ES
POPA
;
IRET ; Return to interrupted task
;
_OSTickISR ENDP
;
END
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -