坠落尘埃 - seu_dust的BLOG http://seu_dust.52rd.net - 复制 - 收藏
seu_dust 发表于 2007-9-9 17:42:00

os_cpu_a.s

;定义系统模式堆栈的大小
SVC_STACK_LEGTH     EQU         32

NoInt       EQU 0x80

USR32Mode   EQU 0x10
SVC32Mode   EQU 0x13
SYS32Mode   EQU 0x1f
IRQ32Mode   EQU 0x12
FIQ32Mode   EQU 0x11

;T_bit用于检测进入异常前cpu是否处于THUMB状态
T_bit               EQU         0x20

    CODE32

    AREA    |subr|, CODE, READONLY

            IMPORT  OSTCBCur                    ;指向当前任务TCB的指针
            IMPORT  OSTCBHighRdy                ;指向将要运行的任务TCB的指针
            IMPORT  OSPrioCur                   ;当前任务的优先级
            IMPORT  OSPrioHighRdy               ;将要运行的任务的优先级
            IMPORT  OSTaskSwHook                ;任务切换的钩子函数
            IMPORT  OSRunning                   ;uC/OS-II运行标志

            IMPORT  OsEnterSum                  ;关中断计数器(关中断信号量)
            IMPORT  SWI_Exception               ;软中断异常处理程序
           
            EXPORT  __OSStartHighRdy           
            EXPORT  OSIntCtxSw                  ;中断退出时的入口,参见startup.s中的IRQ_Handler
            EXPORT  SoftwareInterrupt           ;软中断入口


SoftwareInterrupt软件中断,用于提供一些系统服务,功能参考os_cpu_c.c文件,在调用SWI_Exception前进行处理。

SoftwareInterrupt
        LDR     SP, StackSvc            ; 重新设置堆栈指针
        STMFD   SP!, {R0-R3, R12, LR}
        MOV     R1, SP                  ; R1指向参数存储位置

        MRS     R3, SPSR
        TST     R3, #T_bit              ; 中断前是否是Thumb状态
        LDRNEH  R0, [LR,#-2]            ; 是: 取得Thumb状态SWI号
        BICNE   R0, R0, #0xff00
        LDREQ   R0, [LR,#-4]            ; 否: 取得arm状态SWI号
        BICEQ   R0, R0, #0xFF000000
                                        ; r0 = SWI号,R1指向参数存储位置
        CMP     R0, #1
        LDRLO   PC, =OSIntCtxSw
        LDREQ   PC, =__OSStartHighRdy   ; SWI 0x01为第一次任务切换

        BL      SWI_Exception
       
        LDMFD   SP!, {R0-R3, R12, PC}^
       
StackSvc           DCD     (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)

说明:异常开始,根据ATPCS的描述,只有r0-r3以及r12需要由调用函数负责保存,这里还要保存LR功能函数地址。

入栈保存,判断代码状态,之所以LR-2或-4是因为编译器自动的把lr指向中断指令的下一条指令的地址,减去后才是SWI指令。至于进行BIC高位清零,是因为中断号的范围,对于ARM指令是0-224,判读号SWI号,就BL到相应的异常函数处理了。

 

OSIntCtxSw() 中断退出时的入口,R3    :当前任务的状态寄存器CPSR(即SPSR的值),R4-R12:当前任务的R4-R11, 当前处理器模式的堆栈结构(出栈次序):R0-R3、R12、PC(当前任务的)

OSIntCtxSw
                                                    ;下面为保存任务环境
        LDR     R2, [SP, #20]                       ;获取PC
        LDR     R12, [SP, #16]                      ;获取R12
        MRS     R0, CPSR

        MSR     CPSR_c, #(NoInt | SYS32Mode)
        MOV     R1, LR
        STMFD   SP!, {R1-R2}                        ;保存LR,PC
        STMFD   SP!, {R4-R12}                       ;保存R4-R12

        MSR     CPSR_c, R0
        LDMFD   SP!, {R4-R7}                        ;获取R0-R3
        ADD     SP, SP, #8                          ;出栈R12,PC
       
        MSR     CPSR_c, #(NoInt | SYS32Mode)
        STMFD   SP!, {R4-R7}                        ;保存R0-R3
       
        LDR     R1, =OsEnterSum                     ;获取OsEnterSum
        LDR     R2, [R1]
        STMFD   SP!, {R2, R3}                       ;保存CPSR,OsEnterSum

                                                    ;保存当前任务堆栈指针到当前任务的TCB
        LDR     R1, =OSTCBCur
        LDR     R1, [R1]
        STR     SP, [R1]

        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]

 

__OSStartHighRdy uC/OS-II启动时使用。OSStartHighRdy运行第一个任务,OS_cpc_c.c中的OSStartHighRdy会调用__OSStartHighRdy。

OSIntCtxSw_1
                                                    ;获取新任务堆栈指针
        LDR     R4, [R6]
        ADD     SP, R4, #68                         ;17寄存器CPSR,OsEnterSum,R0-R12,LR,SP
        LDR     LR, [SP, #-8]
        MSR     CPSR_c, #(NoInt | SVC32Mode)        ;进入管理模式
        MOV     SP, R4                              ;设置堆栈指针

        LDMFD   SP!, {R4, R5}                       ;CPSR,OsEnterSum
                                                    ;恢复新任务的OsEnterSum
        LDR     R3, =OsEnterSum
        STR     R4, [R3]
   
        MSR     SPSR_cxsf, R5                       ;恢复CPSR
        LDMFD   SP!, {R0-R12, LR, PC }^             ;运行新任务


__OSStartHighRdy
        MSR     CPSR_c, #(NoInt | SYS32Mode)
                                                ;告诉uC/OS-II自身已经运行
        LDR     R4, =OSRunning
        MOV     R5, #1
        STRB    R5, [R4]

        BL      OSTaskSwHook                    ;调用钩子函数

        LDR     R6, =OSTCBHighRdy
        LDR     R6, [R6]
        B       OSIntCtxSw_1

        AREA    SWIStacks, DATA, NOINIT,ALIGN=2
SvcStackSpace      SPACE   SVC_STACK_LEGTH * 4  ;管理模式堆栈空间


结束语:本人参考了网上一些朋友的移植文章和zlg的移植代码,写了以上小文,如有错误还请大家指出,多多交流。

 

 

阅读全文(1367) | 评论(3)
评 论
3楼 52RD网友(游客) 发表于 2009-5-27 20:08:00
你的函数说明是周立功公司提供的原版的代码说明,都没有做任何的修改,
2楼 52RD网友(游客) 发表于 2008-12-9 14:04:00
对代码的分析不够,比如说:上面一条指令(LDR R1,[SP,#20]),它为什么要这样,希望能解说一下
1楼 52RD网友(游客) 发表于 2008-7-14 14:34:00
SoftwareInterrupt LDR SP, StackSvc ; 重新设置堆栈指针 STMFD SP!, {R0-R3, R12, LR} MOV R1, SP ; R1指向参数存储位置 MRS R3, SPSR TST R3, #T_bit ; 中断前是否是Thumb状态 LDRNEH R0, [LR,#-2] ; 是: 取得Thumb状态SWI号 BICNE R0, R0, #0xff00 LDREQ R0, [LR,#-4] ; 否: 取得arm状态SWI号 BICEQ R0, R0, #0xFF000000 ; r0 = SWI号,R1指向参数存储位置 你好,总体说来,你写的还是蛮好的,不过写得很多东西和网上的类似,我还有几个疑点: 1、 MOV R1, SP ; R1指向参数存储位 这个语句,起到什么作用?我知道是把SP保存到R1,我是想说到底是后面哪儿用到了? OSIntCtxSw_1 ;获取新任务堆栈指针 LDR R4, [R6] ADD SP, R4, #68 ;17寄存器CPSR,OsEnterSum,R0-R12,LR,SP LDR LR, [SP, #-8] 2、OSIntCtxSw_1中的LDR LR, [SP, #-8]起到什么作用,好像是多余的
9 1 :
昵 称: 匿名
验证码: 5596
博 主
进入seu_dust的首页
博客名称:坠落尘埃
日志总数:40
评论数量:41
访问次数:78613
建立时间:2007年8月29日
导 航
日 历
«Mar.2010»
123456
78910111213
14151617181920
21222324252627
28293031
公 告
本博客停止使用!
日 志
评 论
链 接