uC/OS-II源码解析(os_cpu_a.asm)

时间:2021-02-20 20:12:24
;**********************************************************************************
;*
;*ver : 2.52
;* file : os_cpu_a.asm
;* brief : 处理器相关汇编文件
;*
;***********************************************************************************




;***********************************************************************************
; 声明&定义
;***********************************************************************************

PUBLIC _OSTickISR ;时钟节拍中断服务函数
PUBLIC _OSStartHighRdy ;最高优先级任务就绪函数
PUBLIC _OSCtxSw ;任务级的上下文切换
PUBLIC _OSIntCtxSw ;中断级的上下文切换

EXTRN _OSIntExit:FAR ;声明函数OSIntExit()
EXTRN _OSTimeTick:FAR ;声明函数OSTimeTick()
EXTRN _OSTaskSwHook:FAR ;声明函数OSTaskSwHook()

EXTRN _OSIntNesting:BYTE ;声明变量OSIntNesting
EXTRN _OSTickDOSCtr:BYTE ;声明变量OSTickDOSCtr
EXTRN _OSPrioHighRdy:BYTE ;声明变量OSPrioHighRdy
EXTRN _OSPrioCur:BYTE ;声明变量OSPrioCur
EXTRN _OSRunning:BYTE ;声明变量OSRunning
EXTRN _OSTCBCur:DWORD ;声明变量OSTCBCur
EXTRN _OSTCBHighRdy:DWORD ;声明变量OSTCBHighRdy

.MODEL LARGE
.CODE
.186
PAGE ; /*$PAGE*/
;************************************************************************************
; 就绪态最高优先级任务启动函数
; void OSStartHighRdy(void)
;
; 堆栈结构如下 :
;
; OSTCBHighRdy->OSTCBStkPtr --> DS (低地址)
; ES
; DI
; SI
; BP
; SP
; BX
; DX
; CX
; AX
; OFFSET of task code address
; SEGMENT of task code address
; Flags to load in PSW
; OFFSET of task code address
; SEGMENT of task code address
; OFFSET of 'pdata'
; SEGMENT of 'pdata' (高地址)
;
; Note : OSStartHighRdy() 示意性代码:
; a) 调用OSTaskSwHook(),
; b) OSRunning = TRUE,
; c) 得到将要恢复运行任务的堆栈指针,
; Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
; d) 从新任务的堆栈中恢复处理器的所有寄存器
; f) 执行中断返回指令
;**************************************************************************************

_OSStartHighRdy PROC FAR

MOV AX, SEG _OSTCBHighRdy ;
MOV DS, AX ;
;
CALL FAR PTR _OSTaskSwHook ; 调用用户自定义函数 OSTaskSwHook()
;
MOV AL, 1 ; 置变量 OSRunning 为 TRUE
MOV BYTE PTR DS:_OSRunning, AL ; 表明多任务已经启动
; 得到待运行任务的堆栈指针
LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES:[BX+2] ;
MOV SP, ES:[BX+0] ;
;
POP DS ; 弹出寄存器
POP ES ; 必须按照OSTaskStkInit()中相反方向弹出
POPA ;
;
IRET ; 中断返回弹出程序指针、状态寄存器

_OSStartHighRdy ENDP

PAGE ; /*$PAGE*/
;****************************************************************************************
; 任务切换 (任务级)
; void OSCtxSw(void)
;
; Note(s) : 示意性代码如下:
; 1) 保存处理器寄存器
; 2) 在当前任务的TCB中保存当前任务的堆栈指针
; OSTCBCur->OSTCBStkPtr = Stack pointer
; 3) OSTaskSwHook()
; 4) OSTCBCur = OSTCBHighRdy
; 5) OSPrioCur = OSPrioHighRdy
; 6) 得到将要开始重新运行的任务的堆栈指针
; Stack pointer = OSTCBHighRdy->OSTCBStkPtr;
; 7) 从新任务的任务堆栈中恢复处理器所有寄存器的值
; 8) 执行中断返回指令
;
;****************************************************************************************

_OSCtxSw PROC FAR
;
PUSHA ; 保存处理器寄存器
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:[BX+2], SS ;
MOV ES:[BX+0], SP ;
;
CALL FAR PTR _OSTaskSwHook ; 调用用户自定义函数OSTaskSwHook()
; 新任务控制块赋值给当前任务控制块
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:[BX+2] ;
MOV SP, ES:[BX] ;
;
POP DS ; 从新任务堆栈中恢复cpu寄存器
POP ES ;
POPA ;
;
IRET ; 中断返回指令,弹出程序指针和状态寄存器
;
_OSCtxSw ENDP

PAGE ; /*$PAGE*/
;****************************************************************************************
; 任务切换 (中断级)
; void OSIntCtxSw(void)
;
; Note(s): 示意性代码如下:
; 1) 调用用户自定义 OSTaskSwHook()
; 2) OSTCBCur = OSTCBHighRdy
; 3) OSPrioCur = OSPrioHighRdy
; 4) 得到将要重新执行的任务的堆栈指针
; Stack pointer = OSTCBHighRdy->OSTCBStkPtr
; 5) 从新任务的堆栈中恢复所有处理器寄存器
; 6) 执行中断返回指令
;*****************************************************************************************

_OSIntCtxSw PROC FAR
;
CALL FAR PTR _OSTaskSwHook ; 调用用户自定义函数OSTaskSwHook()
;
MOV AX, SEG _OSTCBCur ;
MOV DS, AX ;
; 新任务控制块赋值给当前任务控制块
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:[BX+2] ;
MOV SP, ES:[BX] ;
;
POP DS ; 从新任务堆栈中恢复所有处理器寄存器
POP ES ;
POPA ;
;
IRET ; 执行中断返回指令弹出程序指针和状态寄存器
;
_OSIntCtxSw ENDP

PAGE ; /*$PAGE*/
;*****************************************************************************************
; 时钟节拍中断服务子程序
;
; brief : _OSTickISR1和_OSTickISR2是和PC DOS相关的操作,无需关注
;
; Note(s) : 需要关注的示意性代码如下:
;
; 保存处理器寄存器;
; 调用OSIntEnter()或者直接给OSIntNexting加1
; if (OSIntNesting == 1) {
; OSTCBCur->OSTCBStkPtr = Stack pointer
; }
; 给产生中断的设备清中断
; 重新允许中断(可选)
; OSTimeTick();
; OSIntExit();
; 恢复处理器寄存器
; 执行中断返回指令
;******************************************************************************************
;
_OSTickISR PROC FAR
;
PUSHA ; 保存处理器寄存器
PUSH ES
PUSH DS
;
MOV AX, SEG(_OSIntNesting) ;
MOV DS, AX
INC BYTE PTR DS:_OSIntNesting ; OSIntNesting加1
;
CMP BYTE PTR DS:_OSIntNesting, 1 ; if (OSIntNesting == 1)
JNE SHORT _OSTickISR1
MOV AX, SEG(_OSTCBCur) ;
MOV DS, AX ; 堆栈指针保存到TCB中
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 ; 调用 OSTimeTick()
;
CALL FAR PTR _OSIntExit ; 调用 OSInitExit()
;
POP DS ; 恢复处理器寄存器
POP ES
POPA
;
IRET ; 中断返回弹出程序指针和状态寄存器
_OSTickISR ENDP
;
END