首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

UC OS ARM移植(6)

UC OS ARM移植(6)

调用高优先级就绪任务启动函数OSStartHighRdy。OSStartHighRdy函数与选择的微处理器相关,也就是与移植相关,实际上,函数OSStartHighRdy是将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码,该函数永远不会返回到OSStart

软中断:

中断不返回形式:void _swi(swi_num)  swi_name(arguments)

返回一个结果到R0中  int _swi(swi_num)  swi_name(arguments);

最多可以返回四个结果R0-R3到一个结构

struct type{ int a,b,c,d}中 type(返回类型)

_value_in_regs(返回多个结果的修饰符) _swi(swi_num) swi_name(arguments);

比如在程序运行到调用OS_TASK_SW(void)函数时,就产生软件中断,然后就进入中断服务子程序,按照什么指令走呢?恩,就按照下面这个代码,这个代码是将软件中断异常处理程序挂接到内核的作用的,是在启动代码中实现的:

LDR   PC,SWI_Addr


SWI_Addr   DCD     SoftwareInterrupt

因此当产生软中断之后PC就跳到了SoftwareInterrupt,这时就算真正进入了软件异常中断处理部分了,然后就是执行下面的汇编代码

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

        MRS     R3, SPSR
        TST     R3, #T_bit              ; 中断前是否是Thumb状态,判断SPSR的T位是不是为零

        LDRNEH  R0, [LR,#-2]            ; 不为零即THUMB指令集: 取得Thumb状态SWI号
        BICNE   R0, R0, #0xff00          ;在THUMB指令集中软中断功能号为8位,所以取低八位即为功能号
        LDREQ   R0, [LR,#-4]            ; 为零即ARM指令集: 取得arm状态SWI号
        BICEQ   R0, R0, #0xFF000000         ;在ARM指令集中软中断功能号为24位,所以取低6位即为功能号
                                        ; r0 = SWI号,R1指向参数存储位置
        CMP     R0, #1
        LDRLO   PC, =OSIntCtxSw      ;功能号为0到OSIntCtxSw执行中断任务切换函数
        LDREQ   PC, =__OSStartHighRdy   ; SWI 0x01为第一次任务切换

        BL      SWI_Exception           ;否则进入c编写的中断服务函数
        
        LDMFD   SP!, {R0-R3, R12, PC}^
        
StackSvc           DCD     (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)

怎么进入c编写的中断服务子程序SWI_Exception呢?通过下面的申明

IMPORT  SWI_Exception               ;软中断异常处理程序,表示将c程序中的该函数挂接到此段汇编代码中

同样的道理

EXPORT  __OSStartHighRdy            
EXPORT  OSIntCtxSw                  ;中断退出时的入口,参见startup.s中的IRQ_Handler

EXPORT  SoftwareInterrupt           ;软中断入口

上面的申明是将该段汇编代码挂接到外面,因此在外部可以直接调用函数名


继续看OS_CPU_A.S的其他部分代码,就是两个软件异常中断处理函数OSIntCtxSw和OSStarHighRdy

OSIntCtxSw代码是中断服务子程序使得更高优先级的任务进入就绪状态后,中断返回后需要切换到该任务时调用的,这是被切换的任务的CPU寄存器的值已经在响应中断后存入了堆栈中,因此,这里不需要重复保存了直接切换任务即可,具体过程看代码

OSIntCtxSw
                                                    ;下面为保存任务环境

                                                    ;当响应软件异常中断后进入了系统模式,在上面的代码中我们可以看到,进入系统模式时保存的堆栈结构从顶到底依次是:R0,R1,R2,R3,R12,LR,而在用户模式中任务的堆栈结构应该是:OsEnterSum,CPSR,RO-12,LR,PC,所以在进行软件中断任务切换之前先要保存原来任务的堆栈结构。
        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]
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 }^             ;运行新任务


--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

返回列表