您的位置:首页 > 编程语言

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

2009-12-07 20:00 281 查看
转载自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
 
c2a7
          
;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
的使用方法:


        待续
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息