Chinaunix首页 | 论坛 | 博客
  • 博客访问: 699721
  • 博文数量: 255
  • 博客积分: 5000
  • 博客等级: 大校
  • 技术积分: 2811
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-09 13:29
个人简介

IT业行者,行者无疆

文章分类

全部博文(255)

文章存档

2011年(121)

2010年(134)

我的朋友

分类: 嵌入式

2010-09-27 09:14:37

ARM在UC/OS II的移植日记(连载8)

(2010-04-02 21:20:35)
标签:

杂谈

       __OSStartHighRdy

__OSStartHighRdy函数是在OSStartHighRdy()函数中调用的,__OSStartHighRdy

已经定义成了一个软件中断函数,即进入这个函数时是在管理模式中的

        MSR     CPSR_c, #(NoInt | SYS32Mode)       ;

没有执行这条指令前是在管理模式,执行之后使系统进入系统模式并禁止IRQ中断,系统模式和用户模式使用相同的寄存器,但是它是特权模式

                                                ;告诉uC/OS-II自身已经运行

        LDR     R4, =OSRunning

OSRunning变量的地址存往R4

        MOV     R5, #1

R5的值置1

        STRB    R5, [R4]                                          ;OSRunning = TRUE  ,代表OS已经运行

R5的置存往R4指向的地址,即R4是一个指针,

OSRunning是uC/OS-II定义的变量,为1时代表uC/OS-II已经运行,否则为0

 

        BL      OSTaskSwHook                    ;调用钩子函数,用户自定义函数接口

目前,这个函数是一个空函数,不执行任何动作

        LDR     R6, =OSTCBHighRdy

OSTCBHighRdy变量的地址存往R6

 

        LDR     R6, [R6]

OSTCBHighRdy变量的值存往R6

OSTCBHighRdy 是一个优先级最高任务的任务控制块,是一个结构类型变量,它的第一个定义的参数是OS_STK  *OSTCBStkPtr;  OSTCBStkPtr是一个指向OS_STK类型的指针,.OSTCBStkPtr是指向当前任务栈顶的指针,故R6现在存的值是指向优先级最高的任务的栈顶的指针

             OSIntCtxSw_1                                  ;执行现场恢复的动作

OSIntCtxSw_1做现场的恢复动作,取出R6所指向的地址的值,即取出优先级最高的任务的堆栈栈顶的地址,然后进行现场的恢复
OSIntCtxSw

这时的系统还是在管理模式中

                                                    ;下面为保存任务环境

        LDR     R2, [SP, #20]                    

一进入软件中断时,有以下的两条指令,然后再到OSIntCtxSw函数的,在后面的指令没有改变过管理模式的SP:

LDR     SP, StackSvc            ; 重新设置堆栈指针,这时已经是管理模式了

STMFD   SP!, {R0-R3, R12, LR}     ; 现场保护,R0-R3在函数参数传递和返回值时使用,R12运算使用,LR调用函数时使用,堆栈结构从上到下为LR、R12、R3、R2、R1、R0

故执行完LDR     R2, [SP, #20]指令后,R2存的值是LR的值,也就是软件中断的返回值啦,就是软件中断的后一条指令

        LDR     R12, [SP, #16]                    

获取R12的值,其实R12没有发生变化,可以省略,个人愚见,呵呵

        MRS     R0, CPSR                                             

备份CPSR的值,下面要改变CPSR的值

        MSR     CPSR_c, #(NoInt | SYS32Mode)            

切换到系统模式,要开始保护旧任务的寄存器了,以下的代码都是在系统模式中运行的

        MOV     R1, LR                                                

系统模式的LR在响应软件中断后一直没有操作,没有发生变化,备份LR值

        STMFD   SP!, {R1-R2}                        ;保存LR,PC

现在操作的是系统模式的SP,PC和LR入栈,同时SP递减

        STMFD   SP!, {R4-R12}                       ;保存R4-R12

R4-R12入栈,同时SP递减,因为汇编的操作只是使用了R0-R3进行操作,但是R0-R3的值已经备份在管理模式的堆栈当中了,下面就是恢复R0-R3的值

        MSR     CPSR_c, R0                                           ;切换到管理模式

R0已经在上面的代码中保存了CPSR的值

        LDMFD   SP!, {R4-R7}                        ;获取R0-R3

把管理模式的SP保存的R0-R3出栈,保存在R4-R7中,同时管理模式的SP递减4个字单元

        ADD     SP, SP, #8

因为管理模式的堆栈结构是R0、R1、R2、R3、R12、LR,R0-R3出栈的时候是用LDMFD指令的,SP会自动调整,但是R12和LR出栈是用MOV指令,没有自动调整SP,故这里需要重新调整管理的SP值

        MSR     CPSR_c, #(NoInt | SYS32Mode)              ;切换到系统模式

        STMFD   SP!, {R4-R7}                        ;保存R0-R3

这里的SP是系统模式的SP,R4-R7保存的是R0-R3的值,实现了任务环境中R0-R3的保护,同时SP也自动调整,截至到这时,旧任务已经完成了R0-R12,LR,PC的入栈保护了,且系统的SP值也是指向最后的有效单元了。

        LDR     R1, =OsEnterSum                     ;获取OsEnterSum

        LDR     R2, [R1]

        STMFD   SP!, {R2, R3}                       ;保存CPSR,OsEnterSum

在进入软件中断时,有以下指令MRS     R3, SPSR,后边R3的值都没有改变过,故这里的R3的值保存的是SPSR的值,就是管理模式的SPSR的值,也就是旧任务的CPSR值(因为中断发生时,CPSR的值复制到了SPSR),这时旧任务的保护已经全部结束了。

;保存当前任务堆栈指针到当前任务的TCB

        LDR     R1, =OSTCBCur

        LDR     R1, [R1]

        STR     SP, [R1]                                           ;SP = OSTCBCur -> OSTCBStkPtr

很简单,系统模式的SP,就是旧任务的环境保护完成后的SP存在旧任务的任务块中

        BL      OSTaskSwHook                        ;调用钩子函数

                                                    ;OSPrioCur <= OSPrioHighRdy

        LDR     R4, =OSPrioCur                                      ;获取当前任务的优先级

        LDR     R5, =OSPrioHighRdy                               ;获取即将运行任务的优先级

        LDRB    R6, [R5]

        STRB    R6, [R4]                                               

;将当前任务的优先级更改成即将运行任务的优先级,就是最高优先级啦。

                                                    ;OSTCBCur <= OSTCBHighRdy

        LDR     R6, =OSTCBHighRdy

        LDR     R6, [R6]

        LDR     R4, =OSTCBCur

        STR     R6, [R4]                                               

;当前任务的任务块更改成最高优先级的任务,任务优先级改了,当然任务控制块也要更新啦,现在R6存的是OSTCBHighRdy->OSTCBStkPtr所指向的内容,即新任务的SP值

 

 

OSIntCtxSw_1

        LDR     R4, [R6]                                               

R4存的是OSTCBHighRdy->OSTCBStkPtr所指向的内容,即新任务的SP

        ADD     SP, R4, #68                       

调整新任务的SP指向,共17个寄存器CPSR,OsEnterSum,R0-R12,LR,SP,指向了PC的前一个单元,SP是系统模式的SP,也就是用户模式的SP

        LDR     LR, [SP, #-8]                                  

恢复LR寄存器,此时系统还是在系统模式下工作的,即恢复了系统模式的LR寄存器,感觉这里的LR恢复是重复的,因为在下面的LDMFD   SP!, {R0-R12, LR, PC }^ 指令中也进行了LR的恢复,不必要在这里多次一举了,但也不会造成错误,不知道这样理解对不对,请高手指教。

        MSR     CPSR_c, #(NoInt | SVC32Mode)     

进入管理模式,同时禁止IRQ中断

短评:在恢复新环境的程序开始,也就是从OSIntCtxSw_1开始,先是在系统模式中恢复了系统模式的SP和LR,也就是恢复了新任务的SP和LR,然后切换到管理模式,进行其它寄存器及一切变量的恢复

        MOV     SP, R4

重新设置管理模式的SP,R4的值还是OSTCBHighRdy->OSTCBStkPtr所指向的内容,即新任务的SP                           

        LDMFD   SP!, {R4, R5}                       ;CPSR,OsEnterSum

拷贝新任务的OsEnterSum和CPSR进入R4R5中,OsEnterSum是一个变量,不能用LDMFD指令恢复,系统模式的CPSR必须先拷贝到管理模式的SPSR中,才能利用LDMFD进行CPSR的恢复

        LDR     R3, =OsEnterSum

        STR     R4, [R3]

恢复OsEnterSum变量的值

        MSR     SPSR_cxsf, R5                     

拷贝系统模式的CPSR到管理模式的SPSR,四个域全部影响,这时系统还在管理模式下呢

        LDMFD   SP!, {R0-R12, LR, PC }^           

运行新任务,这个指令包含了SPSR的恢复指令,同时拷贝SPSR到CPSR中,指令完成后回到了系统模式,这里的SP还是管理模式的SP,最后再拷贝PC寄存器,就是新环境开始运行了啦。

到这时所有的ARM在UC/OS II的移植日记已经完全结束了,这些代码已经成功的运行在了一块仿真板上了,而且运行的任务有10个,任务之间的复杂度也有一定难度,故这些移植代码是可信的,可以应用在产品上,过一段时间打算写一篇关于UC/OS II的学习日记,介绍UC/OS II相关函数的应用及含义。
阅读(498) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~