📄 os_cpu_a.asm
字号:
;//********************************************************************************************************
;// uC/OS-II
;// The Real-Time Kernel
;//
;// ARM Cortex-M3 Port
;//
;// File : OS_CPU_A.ASM
;// Version : V2.86
;// By :
;// For : ARMv7M Cortex-M3
;// Mode : Thumb2
;// Toolchain : IAR EWARM 5.20
;//********************************************************************************************************
;//*
;//*********************************************************************************************************
;//* 全局常量声明
;//*********************************************************************************************************
;//*
;// 引用外部变量的声明
EXTERN OSRunning
EXTERN OSPrioCur
EXTERN OSPrioHighRdy
EXTERN OSTCBCur
EXTERN OSTCBHighRdy
EXTERN OSIntNesting
EXTERN OSTaskSwHook
EXTERN OSRdyGrp
EXTERN OSRdyTbl
EXTERN OSPrioHighRdy
;// 外部可以调用的函数
PUBLIC OS_CPU_SR_Save
PUBLIC OS_CPU_SR_Restore
PUBLIC OSStartHighRdy
PUBLIC OSCtxSw
PUBLIC OSIntCtxSw
PUBLIC OS_CPU_PendSVHandler
;// PUBLIC OS_SchedNew
;//********************************************************************************************************
;// PendV 所使用的几个寄存器
;//********************************************************************************************************
NVIC_INT_CTRL EQU 0xE000ED04 ;// 中断控制及状态寄存器
NVIC_SYSPRI14 EQU 0xE000ED22 ;// 控制PendSV优先级的寄存器
NVIC_PENDSV_PRI EQU 0xFF ;// PendSV 异常优先级(最低)
NVIC_PENDSVSET EQU 0x10000000 ;// PendSV 异常触发位掩码
;//********************************************************************************************************
;// 以下是汇编程序接口
;//********************************************************************************************************
RSEG CODE:CODE:NOROOT(2)
;//*
;//********************************************************************************************************
;//* 函 数 名 : OS_SchedNew()
;//**------------------------------------------------------------------------------------------------------
;//* 描 述 :
;//* 寻找最高级就绪的任务
;//* 此程序使用了CM3内核的新指令RBIT, CLZ 通过程序计算代替查表, 速度相当不错
;// 不过在任务优先级及任务数小于63的系统,并没有比查表具有优势
;//
;// 如果想使用此函数,请先屏蔽os_core.c下面的OS_SchedNew()
;//**------------------------------------------------------------------------------------------------------
;//* 输入参数 : OSRdyGrp, OSRdyTbl
;//**------------------------------------------------------------------------------------------------------
;//* 输出参数 : OSPrioHighRdy
;//**------------------------------------------------------------------------------------------------------
;//* 返 回 : None.
;//********************************************************************************************************
;//*
;//OS_SchedNew
;// PUSH {R0-R4}
;// LDR R0, =OSRdyGrp
;//
;// LDRH R2, [R0]
;// RBIT R2, R2
;// CLZ R2, R2 ; y = CLZ(OSRdyGrp);
;//
;// LDR R0, =OSRdyTbl
;// ADD R1, R0, R2, LSL #0x01 ; ptbl = &OSRdyTbl[y];
;//
;// LDRH R3, [R1]
;// RBIT R3, R3
;// CLZ R3, R3 ; x = CLZ(*ptbl);
;//
;// LDR R0, =OSPrioHighRdy
;// ADD R4, R3, R2, LSL #0x04
;// STRB R4, [R0] ; OSPrioHighRdy = x + (y << 4);
;//
;// POP {R0-R4}
;// BX LR
;//*
;//********************************************************************************************************
;//* 函 数 名 :
;//* OS_CPU_SR OS_CPU_SR_Save(void);
;//* void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;//**------------------------------------------------------------------------------------------------------
;//* 描 述 : 第3种方法的临界代码处理, 不再啰嗦
;//**------------------------------------------------------------------------------------------------------
;//* 输入参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 输出参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 返 回 :
;//********************************************************************************************************
;//*
OS_CPU_SR_Save
MRS R0, PRIMASK
CPSID I
BX LR
OS_CPU_SR_Restore
MSR PRIMASK, R0
BX LR
;//*
;//********************************************************************************************************
;//* 函 数 名 : OSStartHighRdy();
;//**------------------------------------------------------------------------------------------------------
;//* 描 述 : 多任务开始运行
;//**------------------------------------------------------------------------------------------------------
;//* 输入参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 输出参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 返 回 :
;//********************************************************************************************************
;//*
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ;// 设置PendSV优先级
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
MOVS R0, #0 ;// 初始化线程PSP
MSR PSP, R0
LDR R0, =OSRunning ;// OSRunning = TRUE
MOVS R1, #1
STRB R1, [R0]
LDR R0, =NVIC_INT_CTRL ;// 触发PendSV异常, 让PendSv任务切换开始
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
CPSIE I ;// 打开总中断
OSStartHang
B OSStartHang ;// while(1);
;//*
;//********************************************************************************************************
;//* 函 数 名 : OSCtxSw();
;//**------------------------------------------------------------------------------------------------------
;//* 描 述 : 任务级内容切换
;//**------------------------------------------------------------------------------------------------------
;//* 输入参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 输出参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 返 回 :
;//********************************************************************************************************
;//*
OSCtxSw
LDR R0, =NVIC_INT_CTRL ;// 触发PendSV异常
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
;//*
;//********************************************************************************************************
;//* 函 数 名 : OSIntCtxSw();
;//**------------------------------------------------------------------------------------------------------
;//* 描 述 : 中断级内容切换
;//**------------------------------------------------------------------------------------------------------
;//* 输入参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 输出参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 返 回 :
;//********************************************************************************************************
;//*
OSIntCtxSw
LDR R0, =NVIC_INT_CTRL ;// 触发PendSV异常
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
;//*
;//********************************************************************************************************
;//* 函 数 名 : OS_CPU_PendSVHandler()
;//**------------------------------------------------------------------------------------------------------
;//* 描 述 : 在cm3内核下,真正的任务文本切换是靠本函数实现
;// | .... |
;// |-----------------|
;// | .... |
;// |-----------------|
;// | .... |
;// |-----------------| |---- 任务切换时PSP
;// Low Memory | .... | |
;// |-----------------| | |---------------| |----------------|
;// ^ | R4 | <----|----|--OSTCBStkPtr |<-----| (OS_TCB *) |
;// ^ |-----------------| |---------------| |----------------|
;// ^ | R5 | | | OSTCBHighRdy
;// | |-----------------| |---------------|
;// | | R6 | | |
;// | |-----------------| |---------------|
;// | | R7 | | |
;// | |-----------------| |---------------|
;// | | R8 | Task's
;// | |-----------------| OS_TCB
;// | | R9 |
;// | |-----------------|
;// | | R10 |
;// Stack |-----------------|
;// Growth | R11 |
;// = 1 |-----------------|
;// | | R0 = p_arg | <-------- 异常时的PSP (向下生长的满栈)
;// | |-----------------|
;// | | R1 |
;// | |-----------------|
;// | | R2 |
;// | |-----------------|
;// | | R3 |
;// | |-----------------|
;// | | R12 |
;// | |-----------------|
;// | | LR |
;// | |-----------------|
;// | | PC = task |
;// | |-----------------|
;// | | xPSR |
;// High Memory |-----------------|
;// | .... |
;//**------------------------------------------------------------------------------------------------------
;//* 输入参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 输出参数 :
;//**------------------------------------------------------------------------------------------------------
;//* 返 回 :
;//********************************************************************************************************
;//*
OS_CPU_PendSVHandler
CPSID I ;// 任务context切换是关闭中断
MRS R0, PSP ;// 获取PSP
CBZ R0, OS_CPU_PendSVHandler_nosave ;// 在多任务初始化时,PSP被初始化为0
;// PSP如果是0,标示任务没有运行过,那么不需要压栈
;// 直接加载任务context
SUBS R0, R0, #0x20 ;// 调整PSP指针, R4-R11 共32字节
STM R0, {R4-R11} ;// 压栈R4-R11, 其他8个寄存器是在异常时自动压栈的
LDR R1, =OSTCBCur ;// 获取OSTCBCur->OSTCBStkPtr
LDR R1, [R1]
STR R0, [R1] ;// 将当前任务的堆栈保存到自己的任务控制块
;// OSTCBCur->OSTCBStkPtr = PSP
;// 程序运行此位置,已经保存了当前任务的context了
OS_CPU_PendSVHandler_nosave
;// 使能OSTaskSwHook的时候去掉注释
;//PUSH {R14}
;//LDR R0, =OSTaskSwHook
;//BLX R0
;//POP {R14}
;// 在调度之前,系统内核已经计算好
;// OSPrioHighRdy 和 OSTCBHighRdy
LDR R0, =OSPrioCur ;// 当前任务优先级 = 就绪任务优先级
LDR R1, =OSPrioHighRdy ;// OSPrioCur = OSPrioHighRdy;
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCur ;// 当前任务控制块 = 就绪任务控制块;
LDR R1, =OSTCBHighRdy ;// OSTCBCur = OSTCBHighRdy;
LDR R2, [R1] ;//
STR R2, [R0] ;// 此时 [R2] = 新任务的PSP
LDR R0, [R2] ;// R0 = 新任务的PSP
LDM R0, {R4-R11} ;// 出栈 R4 - R11
ADDS R0, R0, #0x20 ;// 调整PSP
MSR PSP, R0 ;//
;// 当前异常使用的堆栈是MPS
ORR LR, LR, #0x04 ;// 修改LR的BIT2=1, 确保异常退出时堆栈使用PSP
;// 类似修改CONTROL[1] = 1
CPSIE I
BX LR ;// 异常返回
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -