数据处理指令只能对寄存器的内容进行操作,而不能对内存中的数据进行操作。所有ARM数据处理指令均 可选择使用S后缀,并影响状态标志。
一 数据传送
指令格式 MOV{cond}{S} Rd,operand2
MOV Rd,operand2 数据传送
MOV指令举例如下 :
MOV R1,#0x10 ;R1=0x10
MOV R0,R1 ;R0=R1
MOVS R3,R1,LSL #2 ;R3=R1<<2,并影响标志位
MOV PC,LR ;PC=LR,子程序返回
MVN Rd,operand2 数据非传送
MVN指令举例如下:
MVN R1,#0xFF ;R1=0xFFFFFF00
MVN R1,R2 ;将R2取反,结果存到R1
二算术运算
1、加法运算指令——ADD指令将operand2的值与Rn的值相加,结果保存到Rd寄存器。指令格式如下:
ADD{cond}{S} Rd,Rn,operand2
应用示例:
ADDS R1,R1,#1 ;R1=R1+1,并影响标志位
ADD R1,R1,R2 ;R1=R1+R2
SUBS R0,R0,#1 ;R0=R0-1 ,并影响标志位
SUBS R2,R1,R2 ;R2=R1-R2 ,并影响标志位
RSB R3,R1,#0xFF00 ;R3=0xFF00-R1
RSBS R1,R2,R2,LSL #2 ;R1=(R2<<2)-R2=R2×3
ADDS R0,R0,R2 ;R0等于低32位相加,并影响标志位
ADC R1,R1,R3 ;R1等于高32位相加,并加上低位进位
5、带进位减法指令——SBC用寄存器Rn减去operand2,再减去CPSR中的C条件标志位的非(即若C标志清零,则结果减去1),结果保存到Rd中。指令格式如下:
SUBS R0,R0,R2 ; 低32位相减,并影响标志位
SBC R1,R1,R3 ;高32位相减,并减去低位借位
RSBS R2,R0,#0
RSC R3,R1,#0
三逻辑运算
1、逻辑与操作指令——AND指令将operand2的值与寄存器Rn的值按位作逻辑“与”操作,结果保存到Rd中。指令格式如下:
AND{cond}{S} Rd,Rn,operand2
应用示例:
ANDS R0,R0,#0x01 ;R0=R0&0x01,取出最低位数据
AND R2,R1,R3 ;R2=R1&R3
2、逻辑或操作指令——ORR指令将operand2的值与寄存器Rn的值按位作逻辑“或”操作,结果保存到Rd中。指令格式如下:
ORR R0,R0,#0x0F ;将R0的低4位置1
MOV R1,R2,LSR #24 ;使用ORR指令将R2的高8位
ORR R3,R1,R3,LSL #8 ;数据移入到R3低8位中
3、逻辑异或操作指令——EOR指令将operand2的值与寄存器Rn的值按位作逻辑“异或”操作,结果保存到Rd中。指令格式如下:
EOR R1,R1,#0x0F ;将R1的低4位取反
EOR R2,R1,R0 ;R2=R1^R0
EORS R0,R5,#0x01 ; 将R5和0x01进行逻辑异或,
;结果保存到R0,并影响标志位
4、位清除指令——BIC指令将寄存器Rn的值与operand2的值的反码按位作逻辑“与”操作,结果保存到Rd中。指令格式如下:
BIC R1,R1,#0x0F ;将R1的低4位清零,其它位不变
BIC R1,R2,R3 ;将R3的反码和R2相逻辑“与”,
;结果保存到R1中
比较指令只改变cpsr中的条件标志,不影响参与比较的寄存器的内容。
1、比较指令——CMP指令将寄存器Rn的值减去operand2的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
指令格式如下:
CMP{cond} Rn, operand2
应用示例:
CMP R1,#10 ; R1与10比较,设置相关标志位
CMP R1,R2 ; R1与R2比较,设置相关标志位
注意:CMP指令与SUBS指令的区别在于CMP指令不保存运算结果。在进行两个数据的大小判断时,常用CMP指令及相应的条件码来操作。
CMN R0,#1 ; R0+1,判断R0是否为1的补码
;如果是,则设置Z标志位
注意:CMN指令与ADDS指令的区别在于CMN指令不保存运算结果。CMN指令可用
3、位测试指令——TST指令将寄存器Rn的值与operand2的值按位作逻辑“与”操作,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标
志来判断是否执行。指令格式如下:
TST{cond} Rn, operand2
应用示例:
TST R0,#0x01 ; 判断R0的最低位是否为0
TST R1,#0x0F ; 判断R1的低4位是否为0
注意:TST指令与ANDS指令的区别在于TST指令不保存运算结果。TST指令通常与EQ、NE条件码配合使用,当所有测试位均为0时,EQ有效,而只要有一个测试位不为0,
TEQ R0,R1 ; 比较R0与R1是否相等(不影响V位和C位)
注意:TEQ指令与EORS指令的区别在于TEQ指令不保存运算结果。使用TEQ进行相等测试时,常与EQ、NE条件码配合使用。当两个数据相等时,EQ有效;否则NE有效。
五乘法指令
ARM7TDMI具有三种乘法指令,分别为:
32×32位乘法指令;
32× 32位乘加指令;
32×32位结果为64位的乘/乘加指令。
1、32位乘法指令——MUL指令将Rm和Rs中的值相乘,结果的低32位保存到Rd中。指令格式如下:
MUL{cond}{S} Rd,Rm,Rs
应用示例:
MUL R1,R2,R3 ;R1=R2×R3
MULS R0,R3,R7 ;R0=R3×R7,同时影响CPSR中的N位和Z位
MLA R1,R2,R3,R0 ; R1=R2×R3+R0
3、64位无符号乘法指令——UMULL指令将Rm和Rs中的值作无符号数相乘,结果的低32位保存到RdLo中,而高32位保存到RdHi中。指令格式如下:
UMULL{cond}{S} RdLo,RdHi,Rm,Rs
应用示例:
UMULL R0,R1,R5,R8 ; (R1、R0)=R5×R8
UMLAL R0,R1,R5,R8 ;(R1、R0)=R5×R8+(R1、R0)
5、64位有符号乘法指令——SMULL指令将Rm和Rs中的值作有符号数相乘,结果的低32位保存到RdLo中,而高32位保存到RdHi中。指令格式如下:
SMULL R2,R3,R7,R6 ; (R3、R2)=R7×R6
SMLAL R2,R3,R7,R6 ; (R3、R2)=R7×R6+(R3、R2)
在ARM中有两种方式可以实现程序的跳转,一种使用分支指令直接跳转,另一种则是直接向PC寄存器赋值实现跳转。分支指令有以下三种:
1分支指令B;
2带链接的分支指令BL;
3带状态切换的分支指令BX。
1、分支指令——B指令,该指令跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。指令格式如下:
B{cond} Label
应用示例
B WAITA ; 跳转到WAITA标号处
B 0x1234 ; 跳转到绝对地址0x1234处
2、带链接的分支指令——BL指令适用于子程序调用,使用该指令后,下一条指令的地址被拷贝到R14(即LR) 连接寄存器中,然后跳转到指定地址运行
BL{cond} Label
应用示例:
BL DELAY ; 调用子函数DELAY
3、带状态切换的分支指令——BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态。其跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。指令格式如下:
ADRL R0,ThumbFun+1 ;将Thumb程序的入口地址加1存入R0
BX ; 跳转到R0指定的地址
;并根据R0的最低位来切换处理器状态
七杂项指令
1、SWI指令用于产生软中断,从而实现在从用户模式变换到管理模式,并且将CPSR保存到管理模式的SPSR中,然后程序跳转到SWI异常入口。在其它模式下也可使用SWI指令,处理器同样地切换到管理模式。该指令主要用于用户程序调用操作系统的系统服务,操作系统在SWI异常处理程。指令格式如下:
SWI{cond} immed_24
根据SWI指令传递的参数SWI异常处理程序可以作出相应的处理。SWI指令传递参数有以下两种方法,
(1)指令中的24位立即数指定了用户请求的服务类型,参数通过通用寄存器传递。
MOV R0,#34 ;设置子功能号为34
SWI 12 ;调用12号软中断
MOV R0,#12 ;调用12号软中断
MOV R1,#34 ;设置子功能号为34
SWI 0
在ARM处理器中,只有MRS指令可以对状态寄存器CPSR和SPSR进行读操作。通过读CPSR可以了解当前处理器的工作状态。读SPSR寄存器可了解到进异常前的处理器状态
应用示例:
MRS R1 CPSR ; 将CPSR状态,寄存器读取保存到R1中
R1,,MRS R2,SPSR ; 将SPSR状态寄存器读取,保存到R2中
在ARM处理器中,只有MSR指令可以对状态寄存器CPSR和SPSR进行写操作。与MRS配合使用,可以实现对CPSR或SPSR寄存器的读-修改-写操作,可以切换处理器模式、或者允许/禁止IRQ/FIQ中断等。
MSR指令格式1 MSR{cond} psr_fields, #immed_8r
MSR指令格式2 MSR{cond} psr_fields, Rm
应用示例1(子程序:使能IRQ中断):
ENABLE_IRQ
MRS R0, CPSR
BIC R0, R0, #0x80
MSR CPSR_c. R0
MOV PC, LR
应用示例1(子程序:禁能IRQ中断):
ENABLE_IRQ
MRS R0, CPSR
ORR R0, R0, #0x80
MSR CPSR_c. R0
MOV PC, LR
八伪指令
ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。ARM伪指令有四条,分别为ADR伪指令、ADRL伪指令、LDR伪指令、NOP伪指令。
1、小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。
ADR伪指令格式:ADR{cond} register,expr
地址表达式expr的取指范围:
当地址值不是字对齐时,其取指范围为-255~255;
当地址值是字对齐时,其取指范围为-1020~1020;
应用示例(查表):
ADR R0, DISP_TAB ;加载地址转换表
LDRB R1, [R0,R2] ;使用R2作为参数,进行查表
……
DISP_TAB
DCB 0xc0,0xf9, 0xA4, 0xB0, 0x99,0x92, 0x82, 0xF8
ADRL伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中比ADR伪指令可以读取更大范围的地址。在汇编编译器编译源程序时ADRL伪指令被编译器替换成两条合适的指令。若不能用两条指令实现,则产生错误,编译失败。
ADRL伪指令格式:ADRL{cond} register,expr
地址表达式expr的取指范围:
当地址值不是字对齐时,其取指范围为-64K~64K;
当地址值是字对齐时,其取指范围为-256K~256K;
应用示例(源程序):
ADRL R0, Delay
Delay
MOV R0 , R14
使用伪指令将程序标号Delay的地址存入R0
3、大范围的地址读取
LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。
LDR伪指令格式:LDR{cond} register,=expr
应用示例(源程序):
LDR R1 ,=InitStack
InitStack
MOV R0, LR
使用伪指令将程序标号InitStack的地址存入R1
注意:
1. 从指令位置到文字池的偏移量必须小于4KB;
2. 与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。
4、空操作指令
NOP伪指令在汇编时将会被代替成ARM中的空操作, 比如可能是“MOV R0,R0”指令等。NOP可用于延时操作。
NOP伪指令格式:NOP
九Thumb指令集与ARM指令集的区别
Thumb指令集较ARM指令集有如下限制:
1 只有B指令可以条件执行,其它指令都不能条件执行;
2 分支指令的跳转范围有更多限制;
3 数据处理指令的操作结果必须放入其中一个;
4 单寄存器访问指令,只能操作R0~R7;
5 LDM和STM指令可以对R0~R7的任何子集进行操作;