启动ucosii之三PC_VectSet(uCOS,OSCtxSw)

来源:互联网 发布:淘宝无线端优惠券设置 编辑:程序博客网 时间:2024/06/05 04:00

原型来自PC.C

PC_VectSet(uCOS,OSCtxSw);
//vect向量号,一个内部中断(软中断)向量号
//参数2-中断处理函数.即中断号为0x80的中断处理函数
void PC_VectSet (INT8U vect, void (*isr)(void))
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif   
    INT16U    *pvect;
       
    pvect    = (INT16U *)MK_FP(0x0000, vect * 4);     /* Point into IVT at desired vector location     */
    OS_ENTER_CRITICAL();
/*
函数名: FP_OFF
功  能: 获取远地址偏移量
用  法: unsigned FP_OFF(void far *farptr);
函数位置: dos.h
*/
    *pvect++ = (INT16U)FP_OFF(isr);                   /* Store ISR offset                              */
/*
函数名: FP_SEG
功  能: 获取远地址段值
用  法: unsigned FP_SEG(void far *farptr);
函数位置: dos.h
*/
    *pvect   = (INT16U)FP_SEG(isr);                   /* Store ISR segment                             */
    OS_EXIT_CRITICAL();
}

奋斗

ucosii的任务切换是在中断中完成的,一个软中断,,不同于硬件中断.那么应用程序就应该在创建任务和调用系统函数OSStart()启动ucosii之前,
向系统的中断向量表安装任务切换函数OSCtxSw()的中断向量.
;OSCtxSw()是一个任务级的任务切换函数(在任务中调用,区别于在中断程序中调用的OSIntCtxSw()).
;在80x86系统上,它通过执行一条软中断的指令0x80H来实现任务切换.软中断向量指向OSCtxSw().
;在uC/OS-II中,如果任务调用了某个函数,而该函数的执行结果可能造成系统任务重新调度(例如试图唤醒了一个优先级更高的任务),则在函数的末尾会调用OSSched(),如果OSSched()判断需要进行任务调度,会找到该任务控制块OS_TCB的地址,并将该地址拷贝到OSTCBHighRdy,
;然后通过宏OS_TASK_SW()执行软中断进行任务切换.注意到在此过程中,变量OSTCBCur始终包含一个指向当前运行任务OS_TCB的指针

PC_VectSet(uCOS,OSCtxSw)
中断处理函数OSCtxSw,原型来自OS_CPU_A.ASM

_OSCtxSw    PROC   FAR
;
;当高优先级任务A正在运行时,此时由于“中断服务程序”或者“等待信号量”或者“时钟节拍”或者调用“延时函数”
;使任务A挂起,进行任务切换
;中断或异常发生时eflags、cs、eip已经被压栈
;接着将通用寄存器的内容压入堆栈.
;这些寄存器按以下顺序存储到堆栈:EAX、ECX、EDX、EBX、EBP、ESP、EBP、ESI 及 EDI
;注意:按照依次压栈顺序,当执行PUSH SP时,把此时堆栈指针SP的位置记录下来,堆栈中记录的是SP_BX(此时SP指向BX存储单元)
            PUSHA                                  ; Save current task's context
            PUSH   ES                              ;
            PUSH   DS                              ;
;
;uCOS_II.H中定义extern OS_TCB *OSTCBCur;
;SEG:汇编程序将回送变量或标号的段地址值
            MOV    AX, SEG _OSTCBCur               ; Reload DS in case it was altered
            MOV    DS, AX                          ;
;
;LES指令的功能是:把内存中指定位置的双字操作数的低位字装入指令中指定的寄存器、高位字装入ES寄存器
            LES    BX, DWORD PTR DS:_OSTCBCur      ; OSTCBCur->OSTCBStkPtr = SS:SP
;将堆栈指针位置SP保存到任务A的任务控制块OS_TCB的OSTCBStkPtr成员中
            MOV    ES:[BX+2], SS                   ;
            MOV    ES:[BX+0], SP                   ;
;
;调用钩子函数OSTaskSwHook().应用程序人员可以在钩子函数中编写需要的代码
            CALL   FAR PTR _OSTaskSwHook           ; Call user defined task switch hook
;
;当任务A再次得到CPU的控制权后,进入OSCtxSW()函数,执行
;将待运行任务A的控制块复制到OSTCBCur
            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       ;
;
;将待运行任务A的优先级复制到OSPrioCur
            MOV    AL, BYTE PTR DS:_OSPrioHighRdy  ; OSPrioCur = OSPrioHighRdy
            MOV    BYTE PTR DS:_OSPrioCur, AL      ;
;
;从高优先级任务控制块OSTCBHighRdy的OSTCBStkPtr成员中取出任务A私栈的堆栈指针.
            LES    BX, DWORD PTR DS:_OSTCBHighRdy  ; SS:SP = OSTCBHighRdy->OSTCBStkPtr
            MOV    SS, ES:[BX+2]                   ;
            MOV    SP, ES:[BX]                     ;
;
;依次执行POP DS/POP ES/POPA,从任务A的私栈中恢复相关寄存器的内容到CPU的相关寄存器中
            POP    DS                              ; Load new task's context
            POP    ES                              ;
;依次弹出 edi, esi, ebp, esp, ebx, edx, ecx, eax
            POPA                                   ;
;
;
;执行IRET中断返回指令,依次从任务A的私栈中弹出: 
;(a)、任务A上次断点地址的偏移地址到IP寄存器 
;(b)、任务A上次断点地址的段移地址到CS寄存器 
;(c)、程序状态字PSW(中断是开放的) 
;然后跳转到CS:IP位置处(上次断点位置)继续执行任务A的代码
            IRET                                   ; Return to new task
;
_OSCtxSw    ENDP