📄 os_cpu_a.asm
字号:
.include hardware.inc
.EXTERNAL _OSTaskSwHook;
.EXTERNAL _OSIntEnter
.EXTERNAL _OSTimeTick
.EXTERNAL _OSIntExit
.EXTERNAL _OSTCBCur
.EXTERNAL _OSTCBHighRdy
.EXTERNAL _OSRunning
.EXTERNAL _OSPrioHighRdy
.EXTERNAL _OSPrioCur
.EXTERNAL _OSIntNesting
.EXTERNAL _InterruptC
.CODE
.PUBLIC _OSStartHighRdy
_OSStartHighRdy:
CALL _OSTaskSwHook
R1=0x0001 //将系统运行标志置1,表示系统开始运行,可以进行任务调度
[_OSRunning]=R1
R1=[_OSTCBCur] //取得当前可以运行的任务的TCB块首地址
SP=[R1] //在TCB块的首地址(第一项)中存放的是该任务的堆栈地址
POP R1 FROM [SP]
[_InterruptC]=R1 //弹出该任务的中断开关次数标志
POP R1,R5 FROM [SP]
RETI
.PUBLIC _OSCtxSw
_OSCtxSw:
PUSH R1,R5 TO [SP] //调用子程序时会自动将PC,SR压入栈中,不需要再保存
R1=[_InterruptC]
PUSH R1 TO [SP] //压入该任务的中断开关次数标志
//保存即将挂起任务的堆栈地址
R2=[_OSTCBCur] //取得当前任务(即将挂起的任务)的TCB首地址
[R2]=SP //在TCB的第一项(首地址)中保存堆栈地址
CALL _OSTaskSwHook
//OSUCBCur=OSTCBHighRdy
R1=_OSTCBCur //取得 OSTCBCur的地址
R2=[_OSTCBHighRdy] //取得 OSTCBHighRdy所指向的TCB的首地址
[R1]=R2 //将优先级最高的就绪态任务的TCB的首地址赋予 OSTCBCur
//OSPrioCur=OSPrioHighRdy
R1=[_OSPrioHighRdy]
[_OSPrioCur]=R1
//切换至新的任务堆栈
R1=[_OSTCBHighRdy] //取得将要运行的任务的TCB块的首地址(其中放置了该任务的堆栈地址)
SP=[R1]
POP R1 FROM [SP]
[_InterruptC]=R1 //弹出将要运行的任务的中断开关次数
CMP R1,0 //查看是否需要开中断
JNE KAI //如果任务原先是关中断下被挂起,则直接返回
INT IRQ //否则开中断返回
KAI: POP R1,R5 FROM [SP]
RETI
.PUBLIC _OSIntCtxSw
_OSIntCtxSw: //将发生任务切换,将要挂起的任务的所有的寄存器包括堆栈地址已经保存
CALL _OSTaskSwHook
//OSUCBCur=OSTCBHighRdy
R1=_OSTCBCur
R2=[_OSTCBHighRdy]
[R1]=R2
//OSPrioCur=OSPrioHighRdy
R1=[_OSPrioHighRdy]
[_OSPrioCur]=R1
//切换至新的任务堆栈
R1=[_OSTCBHighRdy]
SP=[R1]
POP R1 FROM [SP] //弹出将要运行任务的中断开关次数标志
[_InterruptC]=R1
CMP R1,0 //查看是否需要关中断
JE KAI1 //如果任务原先是关中断下被挂起
IRQ OFF //则关中断返回
KAI1: POP R1,R5 FROM [SP]
RETI
.PUBLIC _InitSystem
_InitSystem:
INT OFF
PUSH R1,R5 to [SP]
R1 = 0xFFFF //设定IOB口为同相输出口;
[P_IOB_Attrib] = R1
[P_IOB_Dir] = R1
[P_IOB_Data] = R1
//R1=0xFFFF
[P_TimeBase_Setup]=R1 //设置64Hz TMB1
R1 = 0x0002 //开中断IRQ6_TMB1,64Hz
[P_INT_Ctrl] = R1
[P_INT_Ctrl_New] = R1
INT IRQ //开中断并返回
POP R1,R5 from [SP]
RETF
.public _display
_display:
PUSH R1,R5 to [SP]
R1=SP+8
R1=[R1]
[P_IOB_Data]=R1
POP R1,R5 from [SP]
RETF
.TEXT
.PUBLIC _IRQ6
_IRQ6:
PUSH R1,R5 TO [SP]
R1=0x0002
[P_INT_Clear]=R1 //清中断标志
CALL _Clear_Dog //清看门狗
R1=[_OSIntNesting] //中断嵌套标志加1
R1+=1
[_OSIntNesting]=R1
CMP R1,1
JNE TCB //如果没有发生嵌套中断
R1=[_InterruptC] //保存中断开关次数标志
PUSH R1 TO [SP]
R2=[_OSTCBCur] //则保存当前堆栈地址
[R2]=SP
TCB: CALL _OSTimeTick
CALL _OSIntExit
R1=[_OSIntNesting]
CMP R1,0
JNE TCB1 //不等于0则表示为中断嵌套返回
POP R1 FROM [SP] //如果能执行到此,则说明不需要进行任务切换,也就无需进行开关中断处理
[_InterruptC]=R1 //但需要弹出中断计数器以调整堆栈指针到正确位置
TCB1: POP R1,R5 FROM [SP]
RETI
.PUBLIC _Clear_Dog
_Clear_Dog:
R1 = 0x0001;
[P_Watchdog_Clear] = R1 //清看门狗
RETF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -