UCOSII在CORTEX M3上的任务切换汇编代码分析

1.UCOSII的任务切换代码如下:

OS_CPU_PendSVHandler             ;xPSR, PC, LR, R12, R0-R3已自动保存
    CPSID   I                    ;任务切换期间需要关中断
   
    MRS     R0, PSP              ;R0 = PSP
    ;如果PSP == 0,跳到OS_CPU_PendSVHandler_nosave执行 #1
    CBZ     R0, OS_CPU_PendSVHandler_nosave

    ;保存R4-R11到任务堆栈
    SUBS    R0, R0, #0x20        ;R0 -= 0x20                        
    STM     R0, {R4-R11}         ;保存R4-R11到任务堆栈

    ;OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, =OSTCBCur        ;R1 = &OSTCBCur
    LDR     R1, [R1]             ;R1 = *R1 (R1 = OSTCBCur)
    STR     R0, [R1]             ;*R1 = R0 (*OSTCBCur = SP) #2                      

OS_CPU_PendSVHandler_nosave
    ;调用OSTaskSwHook()
    PUSH    {R14}                ;保存R14,因为后面要调用函数           
    LDR     R0, =OSTaskSwHook    ;R0 = &OSTaskSwHook  /*子函数是如何返回的??*/
    BLX     R0                   ;调用OSTaskSwHook()
    POP     {R14}                ;恢复R14

    ;OSPrioCur = OSPrioHighRdy;
    LDR     R0, =OSPrioCur       ;R0 = &OSPrioCur
    LDR     R1, =OSPrioHighRdy   ;R1 = &OSPrioHighRdy
    LDRB    R2, [R1]             ;R2 = *R1 (R2 = OSPrioHighRdy)
    STRB    R2, [R0]             ;*R0 = R2 (OSPrioCur = OSPrioHighRdy)

    ;OSTCBCur = OSTCBHighRdy;
    LDR     R0, =OSTCBCur        ;R0 = &OSTCBCur     
    LDR     R1, =OSTCBHighRdy    ;R1 = &OSTCBHighRdy
    LDR     R2, [R1]             ;R2 = *R1 (R2 = OSTCBHighRdy)
    STR     R2, [R0]             ;*R0 = R2 (OSTCBCur = OSTCBHighRdy)

    LDR     R0, [R2]             ;R0 = *R2 (R0 = OSTCBHighRdy), 此时R0是新任务的SP
                                 ;SP = OSTCBHighRdy->OSTCBStkPtr #3  
    LDM     R0, {R4-R11}         ;从任务堆栈SP恢复R4-R11      
    ADDS    R0, R0, #0x20        ;R0 += 0x20
    MSR     PSP, R0              ;PSP = R0,用新任务的SP加载PSP
    ORR     LR, LR, #0x04        ;确保LR位2为1,返回后使用进程堆栈 #4     
    CPSIE   I                    ;开中断
    BX      LR                   ;中断返回                

    END

#1 如果PSP == 0,说明OSStartHighRdy()启动后第一次做任务切换,而任务刚创建时R4-R11已经保存在堆栈中了,所以不需要再保存一次了。
#2 OSTCBStkPtr是任务控制块结构体的第一个变量,所以*OSTCBCur = SP(不是很科学)就是OSTCBCur->OSTCBStkPtr = SP;
#3 和#2类似。
#4 因为在中断处理函数中使用的是MSP,所以在返回任务后必须使用PSP,所以LR位2必须为1。


因为之前对子函数调用如何被arm-gcc编译器编译成汇编代码的过程不太清楚,其中如下文章具有参考价值:

http://blog.csdn.net/qianlong4526888/article/details/7743489

每个子函数会在调用的结尾调用  bx  lr,即从子函数返回到调用子函数之前的下一条指令地址处。这个指令时编译器自动生成,即使没有使用return关键字。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值