ucos-ii中os_cpu_a.asm函数解释

时间:2022-09-12 20:07:37

1、
对进入临界区和跳出临界区的函数理解

#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SRSave();}
#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}
OS_CPU_SR_Save
    MRS     R0, PRIMASK 
    ;把状态寄存器的值保存到R0中
    CPSID   I
    ;关中断
    BX      LR

OS_CPU_SR_Restore
    MSR     PRIMASK, R0R0的值赋值到PRIMASK中
    BX      LR

临界段的代码需要关中断,处理完毕后开中断。为了保存当前系统的中断转态。

一直没理解cpu_sr变量与R0是如何传值的,其实这个属于一个《AAPCS对ARM结构的一些标准做了定义》,也就是说默认是用R0自动做传递的,参考AAPTCS,可以了解到,这里有一个变量,故使用R0做一个传递值的寄存器。

2、
对OS_TSAK_SW()函数的理解
在UCOS-II中对任务进行切换的时候,调用了OS_TSAK_SW()函数,这个函数也是用汇编写成的。这个函数人为的模仿了一次中断。调用PendSV异常,对任务实现了切换。

NVIC_INT_CTRL   EQU     0xE000ED04; 
;中断控制寄存器地址                            
NVIC_PENDSVSET  EQU     0x10000000;
;该值能够触发PendSV异常
 OSCtxSw
    LDR     R0, =NVIC_INT_CTRL
    ;Trigger the PendSV exception (causes context switch)把NVIC_INT_CTRL的值赋值给R0
    LDR     R1, =NVIC_PENDSVSET
    ;把NVIC_PENDSVSET赋值给R1
    STR     R1, [R0]
    ;把R1的值赋值到R0指向的地址中,即R1=*R0
    BX      LR

上面的函数运行结束后,已经触发了一个PendSV异常。运行到PendSV函数中。

   OS_CPU_PendSVHandler
   ;xPSR, PC, LR, R12, R0-R3 已自动保存 
   CPSID I                                                   
   ; Prevent interruption during context switch
   MRS     R0, PSP
   ; PSP is process stack pointer
   CBZ     R0,     OS_CPU_PendSVHandler_nosave                    
   ; Skip register save the first time
   ;如果是第一次任务切换,
   ;直接跳转,不进行下面的这部分

    SUBS    R0, R0, #0x20 
   ; Save remaining regs r4-11 on process stack,
   ;因为CM3是向下满栈的,也就是向下增长的,每入栈一字节之前,
   ;SP每次减4;这里需要入栈,R4-R11为32位的寄存器,8*32/8=32

    STM     R0, {R4-R11}
    ;一次把R4-R11的值放到R0指向的堆栈
    LDR     R1, =OSTCBCur                                       
    ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    ;R1=*R1
    STR     R0, [R1]
    ;*R1=R0
    ; R0 is SP of process being switched out
                                                              ; At this point, entire context of process has been saved

OS_CPU_PendSVHandler_nosave
    PUSH    {R14}                                               
    ; Save LR exc_return value
    ; OSTaskSwHook();
    LDR     R0, =OSTaskSwHook
    BLX     R0
    POP     {R14}

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

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

    LDR     R0, [R2]                                            
    ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}      
    ; Restore r4-11 from new process stack
    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

    END

在上面的代码中主要讲述了使用PendSV中断来对两个任务之间进行切换。主要做的工作是对两个任务的各个寄存器进行PUSH及POP。同时第一个任务切换的时候不需要保存各个寄存器的值。
3、
在OSStart()函数中调用OSStartHighRdy()函数。这部分也是一段汇编代码。

NVIC_INT_CTRL   EQU     0xE000ED04                             
NVIC_SYSPRI14   EQU     0xE000ED22                             
NVIC_PENDSV_PRI EQU           0xFF                              
NVIC_PENDSVSET  EQU     0x10000000                             
OSStartHighRdy
    ; Set the PendSV exception priority,设置PendSV的优先级为0XFF,为最低优先级
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]

    MOVS    R0, #0 
    ; Set the PSP to 0 for initial context switch call
    MSR     PSP, R0;置PSP为0,与上文2的跳转相呼应了

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

    LDR     R0, =NVIC_INT_CTRL                                 
     ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]

    ; Enable interrupts at processor level

这部分的代码是任务在第一次运行的时候,设置PendSV中断以及中断优先级,同时开启PendSV中断,进行第一个任务切换。