请教:嵌入式实时操作系统μC/OS-Ⅱ (美) Jean J. Labrosse著 随书光盘 例子1:OSCtxSW
;*********************************************************************************************************; PERFORM A CONTEXT SWITCH (From task level)
; void OSCtxSw(void)
;
; 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
;
; 2) The stack frame of the task to suspend looks as follows:
;
; SP -> OFFSETof task to suspend (Low memory)
; SEGMENT of task to suspend
; PSW of task to suspend (High memory)
;
; 3) The stack frame of the task to resume looks as follows:
;
; OSTCBHighRdy->OSTCBStkPtr --> DS (Low memory)
; ES
; DI
; SI
; BP
; SP
; BX
; DX
; CX
; AX
; OFFSETof task code address
; SEGMENT of task code address
; Flags to load in PSW (High memory)
;*********************************************************************************************************
_OSCtxSw PROC FAR
;
PUSHA ; Save current task's context
PUSH ES ;
PUSH DS ;
;
MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered
MOV DS, AX ;
;
LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:, SS ;
MOV ES:, SP ;
;
CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook
;
MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy
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
MOV BYTE PTR DS:_OSPrioCur, AL ;
;
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES: ;
MOV SP, ES: ;
;
POP DS ; Load new task's context
POP ES ;
POPA ;
;
IRET ; Return to new task
问题:
1、
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES: ;
MOV SP, ES: ;
执行上面3条语句,得到高优先级任务(准备运行任务)私栈的栈项指针SS:SP
2、 POP DS ; Load new task's context
POP ES ;
POPA ;
执行上面3条语句,将高优先级任务私栈中上次保存的现场恢复到CPU相关寄存器中
3、现在主要问题集中在POPA 这条语句上
由于POPA是80386指令,是
; POP DI
; POP SI
; POP BP
; POP SP
; POP BX
; POP DX
; POP CX
; POP AX
的简写。
既然前面SS:SP已经指向高优先级任务(准备运行任务)私栈的栈项,那么当执行POP SP时,又将SP指向了另外一个位置,
又怎么能继续从高优先级任务私栈中弹出其余的BX、DX、CX、AX寄存器呢? http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_435763.JPG
(原文件名:未命名.JPG) 我先自己分析一下详细过程:假定高优先级任务为任务A
(1)、当高优先级任务A正在运行时,此时由于“中断服务程序”或者“等待信号量”或者“时钟节拍”或者调用“延时函数”,使任务A挂起,进行任务切换,此时堆栈示意图如下:
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| | <--------- SP
-----------------------------------
图1
(2)、执行OS_TASK_SW(),也就是说执行了一条软件中断指令(INT80H)
,此时任务A堆栈示意图如下:
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| OFF task A (断点位置) |<--------- SP
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
-----------------------------------
图2
(3)、进入OSCtxSW()函数后,执行PUSHA/PUSH ES/PUSH DS
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| BX |<-------------- SP
-----------------------------------
| DX |
-----------------------------------
| CX |
-----------------------------------
| AX |
-----------------------------------
| OFF task A (断点位置) |
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
-----------------------------------
图3
(4)当执行PUSH SP时,把此时堆栈指针SP的位置记录下来,堆栈中记录的是SP_BX(此时SP指向BX存储单元)
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| SP = SP_BX |<-------------- SP
-----------------------------------
| BX |<-------------- SP_BX
-----------------------------------
| DX |
-----------------------------------
| CX |
-----------------------------------
| AX |
-----------------------------------
| OFF task A (断点位置) |
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
-----------------------------------
图4
(5)继续执行PUSHA/PUSH ES/PUSH DS
任务A的私栈
-----------------------------------
| DS |<-------------- SP
-----------------------------------
| ES |
-----------------------------------
| DI |
-----------------------------------
| SI |
-----------------------------------
| BP |
-----------------------------------
| SP = SP_BX |
-----------------------------------
| BX |<-------------- SP_BX
-----------------------------------
| DX |
-----------------------------------
| CX |
-----------------------------------
| AX |
-----------------------------------
| OFF task A (断点位置) |
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
-----------------------------------
图5
(6)、执行 LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:, SS ;
MOV ES:, SP ;
将堆栈指针位置SP(见上图5中的SP)保存到任务A的任务控制块OS_TCB的OSTCBStkPtr成员中。
(7)当任务A再次得到CPU的控制权后,进入OSCtxSW()函数,执行
MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy
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
MOV BYTE PTR DS:_OSPrioCur, AL ;
;
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES: ;
MOV SP, ES:
将任务A的私栈的堆栈指针从任务A的任务控制块OS_TCB的在成员OSTCBStkPtr中取出来,指针位置SP参见图5中的SP。 任务A的私栈
-----------------------------------
| DS |<-------------- SP
-----------------------------------
| ES |
-----------------------------------
| DI |
-----------------------------------
| SI |
-----------------------------------
| BP |
-----------------------------------
| SP = SP_BX |
-----------------------------------
| BX |<-------------- SP_BX
-----------------------------------
| DX |
-----------------------------------
| CX |
-----------------------------------
| AX |
-----------------------------------
| OFF task A (断点位置) |
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
-----------------------------------
图6 当任务A再次获得CPU ,执行
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES: ;
MOV SP, ES:
从高优先级任务控制块OSTCBHighRdy的OSTCBStkPtr成员中取出任务A私栈的堆栈指针,见图6中的SP
http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_435861.JPG
(原文件名:未命名1.JPG) (8)依次执行POP DS/POP ES/POPA,从任务A的私栈中恢复相关寄存器的内容到CPU的相关寄存器中。
当执行完(POPA)的POP BP时的堆栈示意图如下:
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| SP = SP_BX | <-------------- SP
-----------------------------------
| BX |
-----------------------------------
| DX |
-----------------------------------
| CX |
-----------------------------------
| AX |
-----------------------------------
| OFF task A (断点位置) |
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
----------------------------------- (9)由于任务A的私栈中,堆栈指针SP指向单元的内容(SP=SP_BX)为BX存储单元,因此执行POP SP后,堆栈指针位置如下:
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| BX |<-------------- SP
-----------------------------------
| DX |
-----------------------------------
| CX |
-----------------------------------
| AX |
-----------------------------------
| OFF task A (断点位置) |
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
-----------------------------------
(10)继续执行完POPA指令其余的弹栈指令后,堆栈指针位置如下:
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| OFF task A (断点位置) | <-------------- SP
-----------------------------------
| SEG task A(断点位置) |
-----------------------------------
| PSW |
----------------------------------- (11)执行IRET中断返回指令,依次从任务A的私栈中弹出:
(a)、任务A上次断点地址的偏移地址到IP寄存器
(b)、任务A上次断点地址的段移地址到CS寄存器
(c)、程序状态字PSW(中断是开放的)
然后跳转到CS:IP位置处(上次断点位置)继续执行任务A的代码。
任务A的私栈
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| |
-----------------------------------
| | <-------------- SP
----------------------------------- 没有人吗? 我顶!
页:
[1]