📄 os_cpu_a.asm
字号:
// os_cpu.asm
EXTERN OSRunning ; 外部参考
EXTERN OSPrioCur
EXTERN OSPrioHighRdy
EXTERN OSTCBCur
EXTERN OSTCBHighRdy
EXTERN OSIntNesting
EXTERN OSIntExit
EXTERN OSTaskSwHook
EXTERN OS_CPU_IRQ_ISR_Handler
EXTERN OS_CPU_FIQ_ISR_Handler
PUBLIC OS_CPU_SR_Save ; 本文件中定义的函数
PUBLIC OS_CPU_SR_Restore
PUBLIC OSStartHighRdy
PUBLIC OSCtxSw
PUBLIC OSIntCtxSw
PUBLIC OS_CPU_IRQ_ISR
PUBLIC OS_CPU_FIQ_ISR
NO_INT EQU 0xC0 ; 用于禁止FIQ和IRQ中断的屏蔽码
SVC32_MODE EQU 0x13
FIQ32_MODE EQU 0x11
IRQ32_MODE EQU 0x12
;*********************************************************************************************************
; 方式3函数的临界部分
; 说明:通过保存中断状态来禁止/允许中断。一般来说应该将中断禁止标志保存在变量cpu_sr中,然后禁止中断。
; 将cpu_sr复制回CPU的状态寄存器即可恢复中断禁止状态。
;
; 原型:OS_CPU_SR OS_CPU_SR_Save(void);
; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
; 注意::1) 函数一般使用方法容下:
; void Task (void *p_arg) {
; #if OS_CRITICAL_METHOD == 3 // 分配CPU状态寄存器存储单元
; OS_CPU_SR cpu_sr;
; #endif
; :
; :
; OS_ENTER_CRITICAL(); // cpu_sr = OS_CPU_SaveSR();
; :
; :
; OS_EXIT_CRITICAL(); // OS_CPU_RestoreSR(cpu_sr);
; :
; :
; }
;
; 2) OS_CPU_SaveSR() // 禁止中断
;*********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
CODE32
OS_CPU_SR_Save
MRS R0,CPSR ; 设置CPSR中的IRQFIQ位以禁止所有中断
ORR R1,R0,#NO_INT
MSR CPSR_c,R1
MRS R1,CPSR ; 确认CPSR中包含了合适的中断禁止标志
AND R1,R1,#NO_INT
CMP R1,#NO_INT
BNE OS_CPU_SR_Save ; 没有恰当禁止,重试
BX LR ; 已禁止
OS_CPU_SR_Restore
MSR CPSR_c,R0
BX LR
;*********************************************************************************************************
; 启动多任务
; 原型:void OSStartHighRdy(void)
;
; 注意:1) OSStartHighRdy()函数必须:
; a) 调用 OSTaskSwHook(),
; b) 然后将 OSRunning 设置为 TRUE,
; c) 切换到最高优先级任务
;*********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
CODE32
OSStartHighRdy
LDR R0, ??OS_TaskSwHook ; OSTaskSwHook();
MOV LR, PC
BX R0
MSR CPSR_cxsf, #0xD3 ; 切换到管理模式,禁止 IRQ 和 FIQ
LDR R4, ??OS_Running ; OSRunning = TRUE
MOV R5, #1
STRB R5, [R4]
; 切换到最高优先级任务
LDR R4, ??OS_TCBHighRdy ; 获得最高优先级任务的TCB地址
LDR R4, [R4] ; 获得堆栈指针
LDR SP, [R4] ; 切换到新堆栈
LDR R4, [SP], #4 ; 弹出新任务的 CPSR
MSR SPSR_cxsf,R4
LDMFD SP!, {R0-R12,LR,PC}^ ; 弹出新任务的上下文(context)
;*********************************************************************************************************
; 执行任务切换(任务级) - OSCtxSw()
;
; 注意:1) OSCtxSw() 应在禁止FIQ和IRQ中断的条件下以系统模式调用
;
; 2) OSCtxSw() 的伪代码如下:
; a) 将当前任务的上下文(context)保存到当前任务的堆栈中
; b) OSTCBCur->OSTCBStkPtr = SP;
; c) OSTaskSwHook();
; d) OSPrioCur = OSPrioHighRdy;
; e) OSTCBCur = OSTCBHighRdy;
; f) SP = OSTCBHighRdy->OSTCBStkPtr;
; g) 从新任务的堆栈中恢复新任务的上下文(context)
; h) 返回到新任务的代码中
;
; 3) 入口:
; OSTCBCur 指向要挂起任务的 OS_TCB
; OSTCBHighRdy 指向要恢复任务的 OS_TCB
;*********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
CODE32
OSCtxSw
; 保存当前任务的上下文(CONTEXT)
STMFD SP!, {LR} ; 当前地址压栈
STMFD SP!, {LR}
STMFD SP!, {R0-R12} ; 寄存器压栈
MRS R4, CPSR ; 当前CPSR压栈
TST LR, #1 ; 测试是否从Thumb模式下调用
ORRNE R4, R4, #0x20 ; 是,置1 T 标志
STMFD SP!, {R4}
LDR R4, ??OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4]
STR SP, [R5]
LDR R0, ??OS_TaskSwHook ; OSTaskSwHook();
MOV LR, PC
BX R0
LDR R4, ??OS_PrioCur ; OSPrioCur = OSPrioHighRdy
LDR R5, ??OS_PrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
LDR R4, ??OS_TCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R6, ??OS_TCBHighRdy
LDR R6, [R6]
STR R6, [R4]
LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;
; 恢复新任务的上下文(CONTEXT)
LDMFD SP!, {R4} ; 新任务的CPSR出栈
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; 新任务的下文(CONTEXT)出栈
;*********************************************************************************************************
; 执行任务切换(中断级) - OSIntCtxSw()
;
; 注意: 1) OSIntCtxSw() 应在禁止FIQ和IRQ中断的条件下以系统模式调用
;
; 2) OSCtxSw() 的伪代码如下:
; a) OSTaskSwHook();
; b) OSPrioCur = OSPrioHighRdy;
; c) OSTCBCur = OSTCBHighRdy;
; d) SP = OSTCBHighRdy->OSTCBStkPtr;
; e) 从新任务的堆栈中恢复新任务的上下文(context)
; f) 返回到新任务的代码中
;
; 3) 入口:
; OSTCBCur 指向要挂起任务的 OS_TCB
; OSTCBHighRdy 指向要恢复任务的 OS_TCB
;*********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
CODE32
OSIntCtxSw
LDR R0, ??OS_TaskSwHook ; OSTaskSwHook();
MOV LR, PC
BX R0
LDR R4,??OS_PrioCur ; OSPrioCur = OSPrioHighRdy
LDR R5,??OS_PrioHighRdy
LDRB R6,[R5]
STRB R6,[R4]
LDR R4,??OS_TCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R6,??OS_TCBHighRdy
LDR R6,[R6]
STR R6,[R4]
LDR SP,[R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;
; 恢复新任务的上下文(CONTEXT)
LDMFD SP!, {R4} ; 新任务的CPSR出栈
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; 新任务的上下文(context)出栈
;*********************************************************************************************************
; IRQ 中断服务子程序
;*********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
CODE32
OS_CPU_IRQ_ISR
STMFD SP!, {R1-R3} ; 工作寄存器压入IRQ堆栈
MOV R1, SP ; 保存IRQ堆栈指针
ADD SP, SP,#12 ; 调整IRQ堆栈指针
SUB R2, LR,#4 ; 调整PC返回地址
MRS R3, SPSR ; 将SPSR(即中断任务的CPSR)复制到R3
MSR CPSR_c, #(NO_INT | SVC32_MODE) ; 切换到管理模式
; 将任务的上下文(CONTEXT)保存到任务堆栈
STMFD SP!, {R2} ; 任务的返回地址压栈
STMFD SP!, {LR} ; 任务的LR压栈
STMFD SP!, {R4-R12} ; 任务的R12-R4压栈
LDMFD R1!, {R4-R6} ; 将任务的R1-R3从IRQ堆栈移动到管理堆栈
STMFD SP!, {R4-R6}
STMFD SP!, {R0} ; 任务的R0压入任务堆栈
STMFD SP!, {R3} ; 任务的CPSR(即IRQ's SPSR)压栈
; 处理嵌套计数器
LDR R0, ??OS_IntNesting ; OSIntNesting++;
LDRB R1, [R0]
ADD R1, R1,#1
STRB R1, [R0]
CMP R1, #1 ; if (OSIntNesting == 1) {
BNE OS_CPU_IRQ_ISR_1
LDR R4, ??OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP
LDR R5, [R4]
STR SP, [R5] ; }
OS_CPU_IRQ_ISR_1
MSR CPSR_c, #(NO_INT | IRQ32_MODE) ; 切换到IRQ模式(使用IRQ堆栈处理中断)
LDR R0, ??OS_CPU_IRQ_ISR_Handler ; OS_CPU_IRQ_ISR_Handler();
MOV LR, PC
BX R0
MSR CPSR_c, #(NO_INT | SVC32_MODE) ; 切换到管理模式
LDR R0, ??OS_IntExit ; OSIntExit();
MOV LR, PC
BX R0
; 恢复新任务的上下文(CONTEXT)
LDMFD SP!, {R4} ; 新任务的CPSR出栈
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; 新任务的上下文(context)出栈
;*********************************************************************************************************
; FIQ 中断服务子程序
;*********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
CODE32
OS_CPU_FIQ_ISR
STMFD SP!, {R1-R3} ; 工作寄存器压入FIQ堆栈
MOV R1, SP ; 保存FIQ堆栈指针
ADD SP, SP,#12 ; 调整FIQ堆栈指针
SUB R2, LR,#4 ; 调整PC返回地址
MRS R3, SPSR ; 将SPSR(即中断任务的CPSR)复制到R3
MSR CPSR_c, #(NO_INT | SVC32_MODE) ; 切换到管理模式
; 将任务的上下文(CONTEXT)保存到任务堆栈
STMFD SP!, {R2} ; 任务的返回地址压栈
STMFD SP!, {LR} ; 任务的LR压栈
STMFD SP!, {R4-R12} ; 任务的R12-R4压栈
LDMFD R1!, {R4-R6} ; 将任务的R1-R3从IRQ堆栈移动到管理堆栈
STMFD SP!, {R4-R6}
STMFD SP!, {R0} ; 任务的R0压入任务堆栈
STMFD SP!, {R3} ; 任务的CPSR(即FIQ's SPSR)压栈
; 处理嵌套计数器
LDR R0, ??OS_IntNesting ; OSIntNesting++;
LDRB R1, [R0]
ADD R1, R1,#1
STRB R1, [R0]
CMP R1, #1 ; if (OSIntNesting == 1) {
BNE OS_CPU_FIQ_ISR_1
LDR R4, ??OS_TCBCur ; OSTCBCur->OSTCBStkPtr = SP
LDR R5, [R4]
STR SP, [R5] ; }
OS_CPU_FIQ_ISR_1
MSR CPSR_c, #(NO_INT | FIQ32_MODE) ; 切换到FIQ模式(使用FIQ堆栈处理中断)
LDR R0, ??OS_CPU_FIQ_ISR_Handler ; OS_CPU_FIQ_ISR_Handler();
MOV LR, PC
BX R0
MSR CPSR_c, #(NO_INT | SVC32_MODE) ; 切换到管理模式
LDR R0, ??OS_IntExit ; OSIntExit();
MOV LR, PC
BX R0
; 恢复新任务的上下文(CONTEXT)
LDMFD SP!, {R4} ; 新任务的CPSR出栈
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; 新任务的上下文(context)出栈
;*********************************************************************************************************
; 变量的指针
;*********************************************************************************************************
DATA
??OS_TaskSwHook:
DC32 OSTaskSwHook
??OS_CPU_IRQ_ISR_Handler:
DC32 OS_CPU_IRQ_ISR_Handler
??OS_CPU_FIQ_ISR_Handler:
DC32 OS_CPU_FIQ_ISR_Handler
??OS_IntExit:
DC32 OSIntExit
??OS_IntNesting:
DC32 OSIntNesting
??OS_PrioCur:
DC32 OSPrioCur
??OS_PrioHighRdy:
DC32 OSPrioHighRdy
??OS_Running:
DC32 OSRunning
??OS_TCBCur:
DC32 OSTCBCur
??OS_TCBHighRdy:
DC32 OSTCBHighRdy
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -