ba_wang_mao 发表于 2009-4-13 09:14:02

请教:嵌入式实时操作系统μ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寄存器呢?  

ba_wang_mao 发表于 2009-4-13 09:14:24

http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_435763.JPG
(原文件名:未命名.JPG)

ba_wang_mao 发表于 2009-4-13 10:42:41

我先自己分析一下详细过程:假定高优先级任务为任务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。

ba_wang_mao 发表于 2009-4-13 10:48:47

任务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)

ba_wang_mao 发表于 2009-4-13 10:53:26

(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                     |   
   -----------------------------------

ba_wang_mao 发表于 2009-4-13 10:57:42

(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                     |      
   -----------------------------------

ba_wang_mao 发表于 2009-4-13 11:03:25

(11)执行IRET中断返回指令,依次从任务A的私栈中弹出:
   (a)、任务A上次断点地址的偏移地址到IP寄存器
   (b)、任务A上次断点地址的段移地址到CS寄存器
   (c)、程序状态字PSW(中断是开放的)
      然后跳转到CS:IP位置处(上次断点位置)继续执行任务A的代码。

      任务A的私栈      
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                          |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                                 |   
   -----------------------------------   
      |                             |   
   -----------------------------------   
      |                     |   
   -----------------------------------   
      |                                 |    <-------------- SP      
   -----------------------------------

ba_wang_mao 发表于 2009-4-14 08:52:47

没有人吗?

ba_wang_mao 发表于 2009-4-15 16:06:56

我顶!
页: [1]
查看完整版本: 请教:嵌入式实时操作系统μC/OS-Ⅱ (美) Jean J. Labrosse著 随书光盘 例子1:OSCtxSW