原型来自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