SWI指令---软件中断实例详解

转载自http://hi.baidu.com/joyfly2006/blog/item/eb332d1e8c225919403417d4.html

 

SWI 指令 --- 软件中断实例详解


SWI ,即software interrupt 软件中断。 该指令产生一个 SWI 异常。意思就是处理器模式改变为超级用户模式,CPSR寄存器保存到超级用户模式下的 SPSR 寄存器,并且跳转到 SWI 向量 。其 ARM 指令格式如下:

SWI{cond } immed_24

Cond 域:是可选的条件码 ( 参见 ARM 汇编指令条件执行详解).

immed_24 域:范围从 0 到 224 -1 的表达式, ( 即0-16777215) 。用户程序可以使用该常数来进入不同的处理流程。

一、方法1 :获取immed_24 操作数。

为了能实现根据指令中immed_24 操作数的不同,跳转到不同的处理程序,所以我们往往需要在SWI 异常处理子程序中去获得immed_24 操作数的实际内容。获得该操作数内容的方法是在异常处理函数中使用下面指令:

LDR     R0 ,[LR,#-4]

该指令将链接寄存器LR 的内容减去4 后所获得的值作为一个地址,然后把该地址的内容装载进R0 。此时再使用下面指令,immed_24 操作数的内容就保存到了R0 :

BIC     R0 ,R0 ,#0xFF000000

该指令将R0 的高8 位清零,并把结果保存到R0 ,意思就是取R0 的低24 位。

可能还是有人会问:为什么在SWI 异常处理子程序中执行这两条指令后, immed_24 操作数的内容就保存到了R0 寄存器呢?之所以会有这样的疑问,基本都是因为对LR 寄存器的作用没了解清楚。下面介绍一下链接寄存器LR (R14 )的作用。

寄存器 R14(LR 寄存器 ) 有两种特殊功能 :

·在任何一种处理器模式下,该模式对应的 R14 寄存器用来保存子程序的返回地址。当执行 BL BLX 指令进行子程序调用时,子程序的返回地址被放置在 R14 中。这样,只要把 R14 内容拷贝到 PC 中,就实现了子程序的返回(具体的子程序返回操作,这里不作详细介绍)。

·当某异常发生时,相应异常模式下的 R14 被设置成异常返回的地址 ( 对于某些异常,可能是一个偏移量,一个较小的常量 ) 。异常返回类似于子程序返回,但有小小的不同(这里不作详细介绍)。

所谓的子程序的返回地址,实际就是调用指令的下一条指令的地址,也就是BL或BLX指令的下一条指令的地址。所谓的异常的返回的地址,就是异常发生前,CPU执行的最后一条指令的下一条指令的地址。

例如:(子程序返回地址示例)

指令                        指令所在地址

ADD     R2 ,R1 ,R3             ;0x300000

BL      subC                   ;0x300004

MOV     R1,# 2                  ;0x300008

BL 指令执行后,R14 中保存的子程序subC 的返回地址是0x300008 。

再例如:( 异常返回地址示例)

指令                        指令所在地址

ADD     R2 ,R1 ,R3             ;0x300000

SWI     0x98                   ;0x300004

MOV     R1,#2                  ;0x300008

SWI 指令执行后,进入SWI 异常处理程序,此时R14 中保存的返回地址为0x300008 。

所以,在SWI 异常处理子程序中执行 LDR R0 ,[LR,#-4] 语句,实际就是把产生本次SWI 异常的SWI 指令的内容( 如: SWI   0x98 ) 装进R0 寄存器。又因为SWI 指令的低24 位保存了指令的操作数( 如:0x98) ,所以再执行BIC   R0 ,R0 ,#0xFF000000 语句,就可以获得immed_24 操作数的实际内容。

二、方法2 :使用参数寄存器。

    实际上,在SWI 异常处理子程序的实现时,还可以绕开 immed_24 操作数的获取操作,这就是说,我们可以不去获取immed_24 操作数的实际内容,也能实现SWI 异常的分支处理。这就需要使用R0-R4 寄存器,其中R0-R4 可任意选择其中一个,一般选择R0 ,遵从ATPCS 原则。

    具体方法就是,在执行SWI 指令之前,给R0 赋予某个数值,然后在SWI 异常处理子程序中根据R0 值实现不同的分支处理。例如:

指令                         指令所在地址

MOV     R0,#1                   ; #1 给R0

SWI     0x98                   ; 产生SWI 中断, 执行异常处理程序SoftwareInterrupt

ADD     R2 ,R1 ,R3             ;

;SWI 异常处理子程序如下

SoftwareInterrupt

        CMP     R0, #6              ; if R0 < 6

        LDRLO   PC, [PC, R0, LSL #2] ; if R0 < 6,PC = PC + R0*4,else next

        MOVS    PC, LR

SwiFunction

        DCD     function0     ;0

        DCD     function1     ;1

        DCD     function2     ;2

        DCD     function3     ;3

        DCD     function4     ;4

        DCD     function5    ;5

Function0

    异常处理分支0 代码

Function1

    异常处理分支1 代码

function2

    异常处理分支2 代码

function3

    异常处理分支3 代码

function4

    异常处理分支4 代码

function5

    异常处理分支5 代码

   在ARM 体系结构中,当正确读取了PC 的值时,该值为当前指令地址值加8 字节,也就是说,对于ARM 指令集来说 ,读出的PC 值指向当前指令的下两条指令的地址,本例中就是指向SwiFunction 表头DCD function0 这个地址,在该地址中保存了异常处理子分支function0 的入口地址。所以,当 进入SWI 异常处理子程序SoftwareInterrupt 时,如果R0=0 ,执行 LDRLO   PC, [PC, R0, LSL #2] 语句后,PC 的内容即为function0 的入口地址,即程序跳转到了function0 执行。在本例中,因为R0=1 ,所以,实际程序是跳转到了function1 执行。R0 左移2 位 LDRLO   PC, [PC, R0, LSL #2 ] , 即R0*4 ,是因为ARM 指令是字(4 个字节) 对齐的 DCD function0 等伪指令也是按4 字节对齐的。

    在本方法的实现中,实际指令中的24 位立即数(immed_24 域)被忽略了 , 就是说immed_24 域可以为任意合法的值。如在本例中,不一定使用 SWI 0x98 ,还可以为SWI   0x00 或者SWI 0x01 等等,程序还是会进入SWI 异常处理子程序SoftwareInterrupt ,然后根据R0

的内容跳转到相应的子分支。

三、KEIL CARM 编译器中SWI 的使用方法:

    待续

四、ADS 中C 语言编程SWI 的使用方法:

        待续

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值