📄 os_cpu_a.s
字号:
;/*
;************************************************************************************************************
;* (c) Copyright ARM Limited 1999. All rights reserved.
;*
;* ARM 专用代码
;*
;* 文件名称: os_cpu_a.s
;*
;* 文件说明: 该模块中的函数说明
;*
;* void OSIntCtxSw 中断中的任务切换
;* void OSCtxSw 任务切换
;* void OSCPUSaveSR 保存中断前的寄存器状态
;* void OSCPURestoreSR 中断完成后,恢复中断前的状态
;* void OSStartHighRdy 启动最高优先级任务
;************************************************************************************************************
;*/
;/**********************************异常模式下的向量定义****************************************/
SwiV EQU 0x08
IrqV EQU 0x18
FiqV EQU 0x1c
NoInt EQU 0xc0
SVC32Mode EQU 0x13
IRQ32Mode EQU 0x12
FIQ32Mode EQU 0x11
OSEnterSWI EQU 0x00
AREA |subr|, CODE, READONLY
;/*
;*********************************************************************************************************
; 启动多任务
; void OSStartHighRdy(void)
;
; 注释 : OSStartHighRdy() 函数必须:
; a) 在 OSTaskSwHook() 之后调用,
; b) 设定 OSRunning 为真,
; c) 切换到最高优先级.
;*********************************************************************************************************
;*/
IMPORT OSTCBCur
IMPORT OSTaskSwHook
IMPORT OSRunning
IMPORT OSTCBHighRdy
EXPORT OSStartHighRdy
OSStartHighRdy ;// 寻找最高级任务开始
bl OSTaskSwHook ;// 调用用户定义的任务钩子函数
ldr r4,=OSRunning ;//设定多任务开始标志
mov r5,#1
strb r5,[r4]
ldr r4,=OSTCBCur
ldr r5,=OSTCBHighRdy ;// 得到最高优先级任务的 TCB 地址
ldr r5,[r5] ;// 得到任务堆栈指针
ldr sp,[r5]
str r5,[r4] ;// 把得到的TCB地址指针给当前的TCB
;// 切换到新任务
ldmfd sp!,{r4} ;// 弹出新任务的SPSR
msr SPSR_cxsf,r4 ;// 写入当前状态寄存器
ldmfd sp!,{r4} ;// 弹出新任务的 psr
msr CPSR_cxsf,r4 ;// 写入当前状态寄存器
ldmfd sp!,{r0-r12,lr,pc} ;// 弹出新任务的 r0-r12,lr & pc
;/*
;***********************************************************************************************************
; 执行任务切换 (任务级)
; void OSCtxSw(void)
;
; 注释 : OSTCBCur 指向挂起的任务的OS_TCB
; OSTCBHighRdy 指向恢复的任务的OS_TCB
;
;************************************************************************************************************
;*/
IMPORT OSTCBCur
IMPORT OSTaskSwHook
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
EXPORT OSCtxSw
OSCtxSw ;// 任务切换
stmfd sp!,{lr} ;// 压入PC (lr 应代替 PC被压入)
stmfd sp!,{r0-r12,lr} ;// 压入 lr & register file
mrs r4,cpsr
stmfd sp!,{r4} ;// 压入CPSR
mrs r4,spsr
stmfd sp!,{r4} ;// 压入 spsr
;// OSPrioCur = OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r6,[r5]
strb r6,[r4]
;// 得到当前的TCB的地址
ldr r4,=OSTCBCur
ldr r5,[r4]
str sp,[r5] ;// 在任务TCB中的存放当前任务控制块的栈底指针
bl OSTaskSwHook ;// 调用任务的钩子函数
;// 得到最高优先级TCB的地址
ldr r6,=OSTCBHighRdy
ldr r6,[r6]
ldr sp,[r6] ;// 得到新任务的堆栈栈底指针
;// OSTCBCur = OSTCBHighRdy
str r6,[r4] ;// 设定新任务TCB的地址
ldmfd sp!,{r4} ;// 弹出新任务的 spsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ;// 弹出新任务的 psr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ;// 弹出新任务的 r0-r12,lr & pc
;/*
;************************************************************************************************************
; 执行任务切换 (中断级)
; void OSIntCtxSw(void)
;
; 注释 : 该函数针对中断服务子程序Handler仅设定标志为真。
;
;************************************************************************************************************
;*/
IMPORT OSIntCtxSwFlag
EXPORT OSIntCtxSw
OSIntCtxSw
ldr r0,=OSIntCtxSwFlag
mov r1,#1
str r1,[r0]
mov pc,lr
;/*
;************************************************************************************************************
; IRQ HANDLER
;
; 该段处理所有的 IRQs
; 注意: FIQ Handler 段应该近似此段编程
;
;************************************************************************************************************
;*/
IMPORT C_IRQHandler ;//target.c中定义
IMPORT OSIntEnter
IMPORT OSIntExit
IMPORT OSIntCtxSwFlag
IMPORT OSTCBCur
IMPORT OSTaskSwHook
IMPORT OSTCBHighRdy
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
NOINT EQU 0xc0
EXPORT UCOS_IRQHandler
UCOS_IRQHandler
stmfd sp!,{r0-r3,r12,lr} ;// 保存CPU寄存器内容,进入IRQ后,CPSR 为1,禁止IRQ
bl OSIntEnter ;// 内核进入ISR函数
bl C_IRQHandler
bl OSIntExit ;// 内核退出ISR函数时,如果需要切换到更高优先级中去,该函数在OSIntCtxSw()中,
;// 使OSIntCtxSwFlag为1。
ldr r0,=OSIntCtxSwFlag
ldr r1,[r0]
cmp r1,#1
beq _IntCtxSw ;// 判断是否在中断中发生任务切换?
ldmfd sp!,{r0-r3,r12,lr} ;// 否,则恢复CPU寄存器内容
subs pc,lr,#4 ;// 从IRQ中返回
_IntCtxSw ;// 是, 则发生中断级任务切换
mov r1,#0
str r1,[r0] ;// 清OSIntCtxSwFlag,使它为1
ldmfd sp!,{r0-r3,r12,lr} ;//清IRQ中断堆栈
stmfd sp!,{r0-r3} ;//将要使用R0,R1,R2,R3为暂时寄存器
mov r1,sp ;// 保存IRQ的中断堆栈指针
add sp,sp,#16 ;// 回到IRQ的堆栈栈顶
sub r2,lr,#4 ;// 保存PC的返回地址
mrs r3,spsr ;// 保存被中断的任务的SPSR
orr r0,r3,#NOINT ;//当返回到SVC或SYS模式下,禁止中断
msr spsr_c,r0
ldr r0,=.+8
movs pc,r0 ;//返回到SVC或SYS模式,禁止中断,即把spsr_c装入了cpsr中
stmfd sp!,{r2} ;//此时的SP为SVC或SYS的堆栈指针, 压入被中断的任务的 pc
stmfd sp!,{r4-r12,lr} ;// 压入被中断的任务的 lr,r12-r4
mov r4,r1 ;//保存IRQ的中断堆栈指针到R4
mov r5,r3 ;//保存被中断的任务的SPSR到R5
ldmfd r4!,{r0-r3} ;//从IRQ的中断堆栈中弹出被中断的任务的 r3-r0 到CPU的寄存器中
stmfd sp!,{r0-r3} ;// 压入被中断的任务的 r3-r0 到SVC或SYS模式的堆栈中
stmfd sp!,{r5} ;// 压入被中断的任务的 Cpsr
mrs r4,spsr
stmfd sp!,{r4} ;// 压入被中断的任务的 spsr 系统模式下,没有spsr
;// OSPrioCur = OSPrioHighRdy
ldr r4,=OSPrioCur
ldr r5,=OSPrioHighRdy
ldrb r5,[r5]
strb r5,[r4]
;// 得到当前的TCB的地址
ldr r4,=OSTCBCur
ldr r5,[r4]
str sp,[r5] ;// 在任务TCB中的存放当前任务控制块的指针
bl OSTaskSwHook ;// 调用任务的钩子函数
;// 得到最高优先级TCB的地址
ldr r6,=OSTCBHighRdy
ldr r6,[r6]
ldr sp,[r6] ;// 得到新任务的堆栈指针
;// OSTCBCur = OSTCBHighRdy
str r6,[r4] ;// 设定新任务TCB的地址
ldmfd sp!,{r4} ;// 弹出新任务的 spsr
msr SPSR_cxsf,r4
ldmfd sp!,{r4} ;// 弹出新任务的 cpsr
msr CPSR_cxsf,r4
ldmfd sp!,{r0-r12,lr,pc} ;// 弹出新任务的 r0-r12,lr & pc
;/*
;************************************************************************************************************
; 临界段代码的实现方式3
;
; 函数描述 : 通过预设定中断的状态来开关中断。在局部变量'cpu_sr'中保存中断标志,之后关闭中断。 'cpu_sr' 分配
; 给所有需要关中断的 uC/OS-II'的函数。通过把'cpu_sr' 复制到CPU的状态寄存器中来恢复关中断前的状态。
;
; OS_CPU_SR OSCPUSaveSR()
; 输入参数 : 无
;
; 返回值 : OS_CPU_SR
;
; OSCPURestoreSR(OS_CPU_SR cpu_sr)
; 输入参数 : OS_CPU_SR
;
; 返回值 : 无
;
; 注释 : 该函数使用如下
;
; void Task (void *data)
; {
; #if OS_CRITICAL_METHOD == 3 // Allocate storage for CPU status register
; OS_CPU_SR cpu_sr;
; #endif
; :
; :
; OS_ENTER_CRITICAL(); // cpu_sr = OSCPUSaveSR();
; :
; :
; OS_EXIT_CRITICAL(); // OSCPURestoreSR(cpu_sr);
; :
; :
; }
;*********************************************************************************************************
;*/
EXPORT OSCPUSaveSR
OSCPUSaveSR
mrs r0,CPSR
orr r1,r0,#NOINT
msr CPSR_c,r1
mov pc,lr
EXPORT OSCPURestoreSR
OSCPURestoreSR
msr CPSR_c,r0
mov pc,lr
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -