μC/OS中几个底层相关函数

OS_TASK_SW, OS_CPU_IRQ_ISR,OSIntCtxSw,OS_CPU_FIQ_ISR,OSStarHighRdy

下面是关于这个几个函数的汇编,处理是基于ARM的S3C2410,其中的一些有关汇编的知识在

http://blog.youkuaiyun.com/cangencong/article/details/6890933这篇博文中已经讲到了,但是对于这几个函数的一些注解,自己也有一些不懂的地方,并且标注出来了,希望如果有知道的人,看到还望他不吝赐教。

OS_TASK_SW

是一个普通的任务级的任务调度

;以下是定义全局变量的定义
;IMPORT伪操作告诉编译器当前的符号不是在本源文件中定义的,
;而是在其他源文件中定义的,在本源文件中可能引用该符号,
;而且不论本源文件是否实际引用该符号,该符号都将被加入到本源文件的符号表中。
;
    IMPORT  OSTCBCur    
addr_OSTCBCur      DCD OSTCBCur     ;当前任务TCB指针    
    IMPORT  OSTCBHighRdy
addr_OSTCBHighRdy  DCD OSTCBHighRdy  ;当前最高优先级的TCB指针
    IMPORT  OSPrioCur               
addr_OSPrioCur     DCD OSPrioCur     ;当前任务优先级
    IMPORT  OSPrioHighRdy    
addr_OSPrioHighRdy DCD OSPrioHighRdy  ;新就绪最高优先级任务

OS_TASK_SW                            ;只是一个标号,相当于函数名
      STMFD   sp!,{lr}                
                                      
                                      
      STMFD   sp!,{lr}                
        STMFD   sp!,{r0-r12}          
      MRS r4,CPSR
        STMFD   sp!,{r4}
      MRS r4,SPSR
        STMFD   sp!{r4}
;最高优先级的值放入当前优先级的值中     
      LDR r4,addr_OSPrioCur
        LDR r5,addr_OSPrioHighRdy
      LDRB r6,[r5]
        STRB r6,[r4]
;把此时的sp地址作为(旧任务的栈顶值),说明入栈需要保存的数据保存结束
      LDR r4,addr_OSTCBCur
        LDR r5,[r4]
       STR sp,[r5]             ;任务控制块的第一个成员就是OS_STK *OSTCBSTKPT,专门用来存放栈顶
 ;把此时最高优先级的任务(新任务)的栈顶指针放入sp中
      LDR r6,addr_OSTCBHighRdy
        LDR r6,[r6]
      LDR sp,[r6]
;把OSTCBCur的值修改为新就绪最高优先级任务的控制块地址
;并且进行出栈,则开始执行此新任务,完成任务调度功能
    STR r6,[r4]               ;r4指向当前任务控制块指针的地址,r6是最高优先级任务控制块指针
;按照入栈相反的顺序出栈所保存的数据,此时的sp已经是最高优先级任务的栈顶了
     LDMFD sp!,{r4}
     MSR SPSR_cxsf,{r4}
      LDR sp,{r4}
     MSR CPSR_cxsf,{r4}
    LDMFD sp!,{r0-r12,lr,pc}


 

OS_CPU_IRQ_ISR

普通中断处理函数方式,

 

;整个过程方式是:在产生中断时,必须快速进入中断,避免中断丢失,
;当保存了最主要的中断信息后,再次回到SVC模式中存储正在执行任务的信息。
;结束后,在回到IRQ模式中,执行中断服务程序,执行完成后,再次返回SVC模式。
;OS_CPU_IRQ_ISR函数
;以下是部分定义
NO_INT   EQU   0xc0           ;用于禁止FIR和IRQ
NO_IRQ   EQU   0x80           ;用于禁止IRQ
NO_FIQ   EQU   0x40           ;用于禁止FIR  
SVC32_MODE   EQU  0x13        ;处理器模式为32位SVC模式
FIQ32_MODE   EQU  0x11        ;处理器模式为32位FIQ模式
IRQ32_MODE   EQU  0x12        ;处理器模式为32位IRQ模式
;IRQ中断处理函数
OS_CPU_IRQ_ISR              ;标号,可以在C语言程序中调用此函数
;首先禁止CPU的FIQ中断,并切换到IRQ中断模式
          MSR    CPSR_c,#(NO_INT|IRQ32_MODE)
            STMFD  SP!,{R1-R3};将R1-R3通用寄存器存入IRQ模式下的栈(SP_IRQ)中
          MOV R1,SP                 ;①
          ADD SP,SP,#12            ;???为什么留出3个字的空间
          SUB R2,LR,#4              ;获取返回值??是因为ARM预读指令的原因吗
          MRS R3,SPSR               ;②读取SPSR寄存器
          MSR CPSR_c,#(NO_INT|SVC32_MODE)   ;切换到SVC模式
          ;存储任务的上下在SVC模式的栈空间中
          STMFD SP!,{R2}            ;存储返回地址
          STMFD SP!,{LR}            ;存储LR寄存器的值
          STMFD SP!,{R4-R12}        ;存储R4-R12通用寄存器的值
          LDMFD R1!,{R4-R6}         ;因为在①出获得了SP的值,可以把IRQ的寄存器R1-R3的值取出来
          STMFD SP!,{R4-R6}         ;把IRQ模式中的R1-R3原始值入栈到SVC模式栈中
          STMFD SP!,{R0}            ;将R0入SVC模式栈中
 ;将全局变量OSTntNesting自动加1,也可以执行OSIntEnter()代替
          LDR R0,OS_IntNesting      
          LDRB R1,[R0]        ;只传递后8位,难道是可以提高效率????
          ADD R1,R1,#1        
          STRB R1,[R0]
;如果条件满足(OSIntNesting==1)即,只有这一个中断,
;将设置当前任务控制块成员变量OSTCBCur->OSTCBStrPtr=SP
          CMP R1,#1         ;R1与1比较,结果会改变状态寄存器
          BNE OS_CPU_IRQ_ISR_1  ;如果R1不等1则跳转
          LDR R4,OS_TCBCur
          LDR R5,[R4]
          STR SP,[R5]         ;第一个成员变量是OSTCBCur->OSTCBStrPtr = SP
OS_CPU_IRQ_ISR_1
;返回到IRQ中断,使能FIQ中断,执行中断子程序OS_CPU_IRQ_ISR_Handler()
          MSR CPSR_c,#(NO_IRQ|IRQ32_MODE)
          LDR R0,OS_CPU_IRQ_IRQ_Handler
          MOV LR,PC             ;因为LR在执行BL子程序调用指令时,作为R15的备份
          BX R0
;当中断服务程序执行结束后,返回这里,CPU的状态切换为SVC模式
          MSR CPSR_c,#(NO_INT|SVC32_MODE)
;调用OSIntExit()函数,引发新的调用
          LDR R0,OS_IntExit
          MOV LR,PC
          BX R0
;读取新任务的上下文信息
          LDMFD SP!,{R4}
          MSR SPSR_cxsf,R4
          LDMFD SP!,{R0-R12,LR,PC}^
;在特权模式下(SVC)下,"S"或者"^"的作用就是使指令在执行时,同时从SPSR到CPSR的复制,
;达到恢复状态寄存器。

          


OSIntCtxSw

;中断级任务调度切换函数
;由于ARM有各种不同的模式,因此在普通模式下的任务切换和中断后的任务切换是不同的
OSIntCtxSw
      LDR R0,OS_TaskSwHook        ;执行特殊的钩子函数①OSTaskSwHook()
        MOV LR,PC
      BX R0
;将全局变量OS_PrioCur的值修改为OS_PrioHighRdy
      LDR R4,OS_PrioCur
      LDR R5,OS_PrioHighRdy
      LDRB R6,[R5]
      STRB R6,[R4]
;将全局变量OS_TCBCur的值修改为OS_TCBHighRdy
      LDR R4,OS_TCBCur
      LDR R5,OS_TCBHighRdy
      LDR R6,[R5]
      STR R6,[R4]
;读出新任务的堆栈指针SP = OSTCBHighRdy->OSTCBStrPtr
      LDR SP,{R6}
;恢复新任务的上下文内容,然后自动跳转,因为PC值变了      
      LDMFD SP!,{R4}
      MSR SPSR_cxsf,R4
      LDMFD SP!,{R0-R12,LR,PC}^
      
;子函数①OSTaskSwHook()由移植此系统的用户添加代码,
;默认为空,当用户认为有必要执行某些特殊功能时,在函数中添加相应的代码
        


OS_CPU_FIQ_ISR

FIQ中断与普通中断比较类似,但是更为紧急,能够中断IRQ。

OS_CPU_FIQ_ISR
;为什么不手动进入FIQ模式,IRQ模式是手动进入的
      STMFD SP!,{R1-R4}     ;将会使用到的寄存器压入FIQ栈中
      MOV R1,SP             ;②读取FIQ的SP指针
      SUB R2,LR,#4          ;①调整LR,以得到PC返回值
      MRS R3,SPSR           ;读取SPSR_fiq的值
      MOV R4,R3
      AND R4,R4,#0x1F       ;提取SPSR后5位
      CMP R4,#IRQ32_MODE    ;测试FIQ是否在IRQ模式下发生的,即是否中断嵌套了
      BEQ OS_CPU_FIQ_ISR_2  ;如果是,则跳到OS_CPU_FIQ_ISR;如果不是直接执行FIQ中断处理
      MSR CPSR_c,#(NO_INT|SVC32_MODE)     ;将当前CPU修改为SVC模式
      ;保存上下文内容到任务栈中
      STMFD SP!,{R2}        ;将PC放入SVC模式栈中,在①出,R2已经得到PC值
      STMFD SP!,{LR}        ;将LR保存到SVC模式中
      LDMFD R1!,{R5-R8}     ; 将FIQ栈中的R1-R4存储到SVC栈中,在②处,已经获得FIQ栈指针
      STMFD SP!,{R5-R8}
      STMFD SP!,{R0}
      STMFD SP!,{R3}        ;将SPSR_fiq存储到SVC栈中
      LDR R0,OS_IntNesting  ;中断嵌套次数加1,
      LDRB R1,[R0]
      ADD R1,R1,#1
      STRB R1,[R0]
;如果条件满足OS_IntNesting=1
;设置当前任务的任务控制块成员变量OSTCBCur->OSTCBStrPtr = SP
      CMP R1,#1
      BNE OS_CPU_FIQ_ISR_1    
                
OS_CPU_FIQ_ISQ_1
      MSR CPSR_c,#(ON_INT|FIQ32_MODE)       ;进入FIQ模式
      ADD SP,SP,#16                         ;修改FIQ栈指标(为什么要修改)
      LDR R0,OS_CPU_FIQ_ISR_Handler         ;调用中断服务程序
      MOV LR,PC
      BX R0
      
;读取新任务的上下文内容,开始执行新任务
      LDMFD SP!,{R4}                        ;将新任务的cpsr出栈
      MSR SPSR_cxsf,R4
      LDMFD SP!,{R0-R12,LR,PC}^             ;由于PC值改变,相当于return了。
      
      
;FIQ中断将中断IRQ中断      
OS_CPU_FIQ_ISR_2
      ;将IRQ的上下文存储到FIQ的栈中
      STMFD SP!,{R0-R7,LR}
      ;中断次数加一,相当于执行OSIntEnter()函数
      LDR R0,OS_IntNesting
      LDRB R1,[R0]
      ADD R1,R1,#1
      STRB R1,[R0]
      
      LDR R0,OS_CPU_FIQ_ISR_Handler       
      MOV LR,PC
      BX R0
;全局变量OSIntNesting自动减一,此处没有必要执行OSIntExit()函数
;因为返回到IRQ模式下时将调用此函数,另外,在中断嵌套中不允许引发新的调度
      LDR R0,OS_IntNesting
      LDR R1,[R0]
      SUB R1,R1,#1
      STRB R1,[R0]
;恢复IRQ模式下的上下文内容,然后返回到IRQ模式执行IRQ中断
      LDMFD SP!,{R0-R7,LR}
      LDMFD SP!,{R1-R4}
      SUBS PC,LR,#4
      
      
      


OSStarHighRdy

 

;运行最高优先级任务
;GLOBAL 与 EXPORT 相同,EXTERN 与 IMPORT 相同
        IMPORT OSTCBCur
addr_OSTCBCur   DCD OSTCBCur
        IMPORT OSTCBHighRdy
addr_OSTCBHighRdy  DCD OSTCBHighRdy
    EXPORT OSStarHighRdy
OSStarHighRdy
    LDR R4,addr_OSTCBCur          ;获取当前任务TCB的地址
    LDR R5,addr_OSTCBHighRdy      ;获取最高优先级的TCB地址
    LDR R5,[R5]
    LDR SP,[R4]
    LDMFD SP!,{R4}
    MSR SPSR_cxsf,R4
    LDMFD SP!,{R4}
    MSR CPSR_cxsf,R4
    LDMFD SP!,{R0-R12,LR,PC}
    END



      
      


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值