uCOS-II移植之os_cpu_a.asm文件说明

uCOS-II移植需要需要改动的文件主要有有os_cpu_a.asm、 .c、os_cpu.h三个文件,首先来讲一下汇编文件os_cpu_a.asm。
os_cpu_a.asm中用到的汇编知识及语法:
1、EXTERN:用于声明变脸,表示被声明的变量在其他文件中定义,在本文件中使用
2、EXPORT:用于定义变量,且此变量被其他文件所使用的,与之相对的是IMPORT,表示只能在本文件中使用。
3、MRS/MSR:读/写特殊功能寄存器(xPSR,PRIMASK,FAULTMASK,BASEPRI,CONTROL,这些特殊功能寄存器只能被这两个指令访问)
4、CPSID/CPSIE     I/F:开启/关闭中断/异常,这是CM3内核专门设置的一条快速开关指令。
.......
其他一些指令为汇编常用指令。
另外再讲一个知识点:PSP和MSP
堆栈,一般是程序运行时用来临时存储数据的存储结构,符合后进先出的原则,就像抽屉一样,后放进的东西总是要先拿出来。
PSP:进程堆栈指针,一般任务运行时使用的是这个堆栈
MSP:主堆栈指针,系统级的代码运行于这个堆栈,比如异常/中断例程,内核。
首先来说一下OS_CPU_SR_Save函数,代码如下:
OS_CPU_SR_Save
    MRS     R0, PRIMASK             ;保存PRIMASK(中断屏蔽寄存器)内容到R0中                            
    CPSID   I                       ;关闭中断                           
    BX      LR                      ;BX为跳转指令,跳转到LR所指向的地址。相当于退出此函数                       
PRIMASK这个寄存器是只有单一比特的寄存器,置1表示关掉所有可屏蔽的异常,置0则不关闭任何中断。LR寄存器为连接寄存器,它用于在调用子程序时存储返回地址。OS_CPU_SR_Save()函数被OS_ENTER_CRITICAL()函数调用,而OS_ENTER_CRITICAL()的作用是关闭所有中断或者说进入临界段,防止某些不允许被中断的代码收到干扰,所以在关闭中断时需要调用OS_CPU_SR_Save()函数将与中断有关的PRIMASK保存到堆栈中,当下次重新开启中断时再将他从堆栈中恢复到PRIMASK中,就好像没发生什么一样。
既然有OS_CPU_SR_Save()保存函数,就肯定有恢复函数OS_CPU_SR_Restore
OS_CPU_SR_Restore
    MSR     PRIMASK, R0                                         ;将之前PRIMASK保存的信息重新还给PRIMASK
    BX      LR                                                  ;跳转至LR所给地址,相当于退出此函数。
此函数功能就像之前所述的将保存的内容恢复到PRIMASK中。此函数一般被OS_EXIT_CRITICAL()函数调用,OS_EXIT_CRITICAL()的作用是开启中断或者说退出临界段。
接着来说说OSStartHighRdy函数,代码如下:
OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14                                  ; 
    LDR     R1, =NVIC_PENDSV_PRI                                ; 
    STRB    R1, [R0]                                            ; 将PendSV优先级保存到优先级寄存器NVIC_SYSPRI14中

    MOVS    R0, #0                                              ; 
    MSR     PSP, R0                                             ;PSP=0 

    LDR     R0, =OSRunning                                      ; 
    MOVS    R1, #1
    STRB    R1, [R0]                                            ;OSRunning=1

    LDR     R0, =NVIC_INT_CTRL                                  ; 
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]                                            ;NVIC_INT_CTRL=NVIC_PENDSVSET,即触发一次PendSV中断。

    CPSIE   I                                                   ; 开启中断
OSStartHighRdy由OSStart()调用,用来启动最高优先级任务,当然任务必须在OSStart()调用前被创建。其中PSP=0是用来告诉具体的任务切换程序这是第一次进行任务切换,做过切换后PSP就不会是0了。需要注意的是,程序中出现了=NVIC_SYSPRI14,NVIC_SYSPRI14表示0xE000ED22这个数,所以LDR     R0, =NVIC_SYSPRI14这条指令就相当于是吧0xE000ED22这个地址保存到R0中,即RO指向0xE000ED22这个地址中的内容,不加“=”会把0xE000ED22地址中所存储的内容放到R0中去。
另外,需要说明的是在CM3内核中,真正的任务之间的切换是由PendSV中断来处理的,而不是OSCtxSw或者OSIntCtxSw。
既然讲到了OSCtxSw和OSIntCtxSw,那就来讲讲它们。代码如下:
OSCtxSw
    LDR     R0, =NVIC_INT_CTRL                                  ; 
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]                  ;NVIC_INT_CTRL=NVIC_PENDSVSET,即触发一次PendSV中断,进行任务调度。
    BX      LR
OSIntCtxSw
    LDR     R0, =NVIC_INT_CTRL                             ; 
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]                  ;NVIC_INT_CTRL=NVIC_PENDSVSET,即触发一次PendSV中断,进行任务调度。
    BX      LR
这两位是孪生兄弟,长得一模一样,但是它们的含义却不相同。OSCtxSw用于正常的任务切换,切位任务级调度,而OSIntCtxSw用于在中断结束后进行任务调度,称为中断级调度。
最后我们来讲讲真正的任务切换函数OS_CPU_PendSVHandler函数。在此之前先来说明一下CM3的寄存器。
CM3有通用目的寄存器R0~R12,用于暂时存储数据;堆栈指针寄存器R13;链接寄存器R14,即LR;程序寄存器R15,存储着下一条要执行的指令的地址。
函数代码如下: 
OS_CPU_PendSVHandler
    CPSID   I                              ; 关闭中断
    MRS     R0, PSP                        ; PSP is process stack pointer
    CBZ     R0, OS_CPU_PendSVHandler_nosave         ; PSP是否为0,不为0继续执行,为0则ti奥转到OS_CPU_PendSVHandler_nosave处,即判断是否为第一次进行任务切换。

    SUBS    R0, R0, #0x20                  ; 切换到存储R4~R11寄存器的堆栈地址
    STM     R0, {R4-R11}                   ; 存储R4~R11寄存器

    LDR     R1, =OSTCBCur                  ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                       ; OSTCBCur->OSTCBStkPtr指向SP,即切换到下一个任务。
OS_CPU_PendSVHandler_nosave
    PUSH    {R14}                                        ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                            ; OSTaskSwHook();
    BLX     R0
    POP     {R14}

    LDR     R0, =OSPrioCur                               ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    LDR     R0, =OSTCBCur                                ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]

    LDR     R0, [R2]            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}        ; 恢复R4~R11
    ADDS    R0, R0, #0x20       ; 调整任务堆栈指针
    MSR     PSP, R0             ; Load PSP with new process SP
    ORR     LR, LR, #0x04       ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                  ; Exception return will restore remaining context
由于CM3内核自动将R0~R3,R12保存到任务堆栈,所以只需要手动保存R4~R11即可。其他说明见代码注释。
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值