必须知道的ARM指令集Word下载.docx
《必须知道的ARM指令集Word下载.docx》由会员分享,可在线阅读,更多相关《必须知道的ARM指令集Word下载.docx(23页珍藏版)》请在冰豆网上搜索。
首先将这个数转换为32bit16进制形式,例如218=0xDA=0x000000DA
1.除零外,仅有一位数为合法立即数。
2.除零外,仅有二位数,并且相邻(包括首尾,如0x1000000A)的为合法立即数。
3.除零外,仅有三位数,并且相邻(包括中间有0相间,例如0x10800000,包括首尾相邻,如:
0x14000003),这三位数中,最高位取值仅能为1、2、3,最低位取值仅能为4、8、C,中间位0x0~0xF。
这种组合的为合法立即数。
除了以上三种,其他基本是非法立即数。
举例:
0xFF是有效立即数。
0x104是有效立即数。
0xFF0、0xFF00、0xFF000、0xFF000000、0xF000000F都是有效立即数。
反例:
0x101是无效立即数。
0x102是无效立即数。
0xFF1、0xFF04、0xFF003、0xFFFFFFFF都是无效立即数。
还有一个要说的就是:
只要该数,可以通过0x00-0xFF中某个数,循环右移偶数位而产生,就是合法的立即数,否则就是非法的立即数。
练习:
下面哪些立即数是数据处理指令中有效的数据?
a)0x00AB0000b)0x0000FFFFc)0xF000000F
d)0x08000012e)0x00001f80f)0xFFFFFFFF
(2)Rm——寄存器方式
在寄存器方式下,操作数即为寄存器的数值。
SUBR1,R1,R2
MOVPC,R0
(3)Rm,shift——寄存器移位方式
将寄存器的移位结果作为操作数,但Rm值保持不变,移位方法如下:
ADDR1,R1,R1,LSL#3;
R1=R1+R1*8=9R1
SUBR1,R1,R2,LSRR3;
R1=R1-(R2/2R3)
2.ARM指令集——条件码
使用条件码“cond”可以实现高效的逻辑操作,提高代码效率。
所有的ARM指令都可以条件执行,而Thumb指令只有B(跳转)指令具有条件执行功能。
如果指令不标明条件代码,将默认为无条件(AL)执行。
其中上图,红线括起来的必须记住,其他不知道的时候在回过头查即可。
二、ARM指令
1.ARM数据处理指令
数据处理指令大致可分为3类:
数据传送指令,算术逻辑运算指令,比较指令
注意:
数据处理指令只能对寄存器的内容进行操作,而不能对内存中的数据进行操作。
所有ARM数据处理指令均可选择使用S后缀,并影响状态标志。
(1)数据传送
MOV指令将立即数或寄存器传送到目标寄存器(Rd),可用于移位运算等操作。
指令格式如下:
MOV{cond}{S}Rd,operand2
MOV指令举例如下:
MOVR1,#0x10;
R1=0x10
MOVR0,R1;
R0=R1
MOVSR3,R1,LSL#2;
R3=R1<
<
2,并影响标志位
MOVPC,LR;
PC=LR,子程序返回
MVN指令将8位图立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数。
指令格式如下:
MVN{cond}{S}Rd,operand2
MVN指令举例如下:
MVNR1,#0xFF;
R1=0xFFFFFF00
MVNR1,R2;
将R2取反,结果存到R1
(2)算术运算
其中,红线框内的必须掌握。
A、加法运算指令——ADD指令将operand2的值与Rn的值相加,结果保存到Rd寄存器。
ADD{cond}{S}Rd,Rn,operand2
应用示例:
ADDSR1,R1,#1;
R1=R1+1,并影响标志位
ADDR1,R1,R2;
R1=R1+R2
B.减法运算指令——SUB指令用寄存器Rn减去operand2,结果保存到Rd中。
SUB{cond}{S}Rd,Rn,operand2
SUBSR0,R0,#1;
R0=R0-1,并影响标志位
SUBSR2,R1,R2;
R2=R1-R2,并影响标志位
C.逆向减法运算指令——RSB指令将operand2的值减去Rn,结果保存到Rd中。
RSB{cond}{S}Rd,Rn,operand2
RSBR3,R1,#0xFF00;
R3=0xFF00-R1
RSBSR1,R2,R2,LSL#2;
R1=(R2<
2)-R2=R2×
3
D.带进位加法指令——ADC将operand2的值与Rn的值相加,再加上CPSR中的C条件标志位,结果保存到Rd寄存器。
ADC{cond}{S}Rd,Rn,operand2
应用示例(使用ADC实现64位加法,结果存于R1、R0中):
ADDSR0,R0,R2;
R0等于低32位相加,并影响标志位
ADCR1,R1,R3;
R1等于高32位相加,并加上低位进位
E.带进位减法指令——SBC用寄存器Rn减去operand2,再减去CPSR中的C条件标志位的非(即若C标志清零,则结果减去1),结果保存到Rd中。
SBC{cond}{S}Rd,Rn,operand2
应用示例(使用SBC实现64位减法,结果存于R1、R0中):
SUBSR0,R0,R2;
低32位相减,并影响标志位
SBCR1,R1,R3;
高32位相减,并减去低位借位
F.带进位逆向减法指令——RSC指令用寄存器operand2减去Rn,再减去CPSR中的C条件标志位,结果保存到Rd中。
RSC{cond}{S}Rd,Rn,operand2
应用示例(使用RSC指令实现求64位数值的负数):
RSBSR2,R0,#0
RSCR3,R1,#0
(3)逻辑运算指令
A.逻辑与操作指令——AND指令将operand2的值与寄存器Rn的值按位作逻辑“与”操作,结果保存到Rd中。
AND{cond}{S}Rd,Rn,operand2
ANDSR0,R0,#0x01;
R0=R0&
0x01,取出最低位数据
ANDR2,R1,R3;
R2=R1&
R3
B.逻辑或操作指令——ORR指令将operand2的值与寄存器Rn的值按位作逻辑“或”操作,结果保存到Rd中。
ORR{cond}{S}Rd,Rn,operand2
ORRR0,R0,#0x0F;
将R0的低4位置1
MOVR1,R2,LSR#24;
使用ORR指令将R2的高8位
ORRR3,R1,R3,LSL#8;
数据移入到R3低8位中
C.逻辑异或操作指令——EOR指令将operand2的值与寄存器Rn的值按位作逻辑“异或”操作,结果保存到Rd中。
EOR{cond}{S}Rd,Rn,operand2
EORR1,R1,#0x0F;
将R1的低4位取反
EORR2,R1,R0;
R2=R1^R0
EORSR0,R5,#0x01;
将R5和0x01进行逻辑异或,;
结果保存到R0,并影响标志位
D.位清除指令——BIC指令将寄存器Rn的值与operand2的值的反码按位作逻辑“与”操作,结果保存到Rd中。
BIC{cond}{S}Rd,Rn,operand2
BICR1,R1,#0x0F;
将R1的低4位清零,其它位不变
BICR1,R2,R3;
将R3的反码和R2相逻辑“与”,;
结果保存到R1中
(4)比较指令
A.比较指令——CMP指令将寄存器Rn的值减去operand2的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
CMP{cond}Rn,operand2
CMPR1,#10;
R1与10比较,设置相关标志位
CMPR1,R2;
R1与R2比较,设置相关标志位
注意:
CMP指令与SUBS指令的区别在于CMP指令不保存运算结果。
在进行两个数据的大小判断时,常用CMP指令及相应的条件码来操作。
B.负数比较指令——CMN指令使用寄存器Rn的值加上operand2的值,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
CMN{cond}Rn,operand2
CMNR0,#1;
R0+1,判断R0是否为1的补码;
如果是,则设置Z标志位
CMN指令与ADDS指令的区别在于CMN指令不保存运算结果。
CMN指令可用于负数比较,比如CMNR0,#1指令则表示R0与-1比较,若R0为-1(即1的补码),则Z置位;
否则Z复位。
C.位测试指令——TST指令将寄存器Rn的值与operand2的值按位作逻辑“与”操作,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
TST{cond}Rn,operand2
TSTR0,#0x01;
判断R0的最低位是否为0
TSTR1,#0x0F;
判断R1的低4位是否为0
TST指令与ANDS指令的区别在于TST指令不保存运算结果。
TST指令通常与EQ、NE条件码配合使用,当所有测试位均为0时,EQ有效,而只要有一个测试位不为0,则NE有效。
D.相等测试指令——TEQ指令将寄存器Rn的值与operand2的值按位作逻辑“异或”操作,根据操作的结果更新CPSR中的相应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
TEQ{cond}Rn,operand2
TEQR0,R1;
比较R0与R1是否相等(不影响V位和C位)
TEQ指令与EORS指令的区别在于TEQ指令不保存运算结果。
使用TEQ进行相等测试时,常与EQ、NE条件码配合使用。
当两个数据相等时,EQ有效;
否则NE有效。
(5)分支指令
A.分支指令——B指令,该指令跳转范围限制在当前指令的±
32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。
B{cond}Label
BWAITA;
跳转到WAITA标号处
B0x1234;
跳转到绝对地址0x1234处
B.带链接的分支指令——BL指令适用于子程序调用,使用该指令后,下一条指令的地址被拷贝到R14(即LR)连接寄存器中,然后跳转到指定地址运行程序。
跳转范围限制在当前指令的±
32M字节地址内。
BL{cond}Label
BLDELAY;
调用子程序DELAY
C.带状态切换的分支指令——BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态。
其跳转范围限制在当前指令的±
BX{cond}Rm
ADRLR0,ThumbFun+1;
将Thumb程序的入口地址加1存入R0
BXR0;
跳转到R0指定的地址,;
并根据R0的最低位来切换处理器状态
2.存储器访问指令
ARM处理器是典型的RISC处理器,对存储器的访问只能使用加载和存储指令实现。
存储器访问指令分为单寄存器操作指令(LDR/STR)和多寄存器操作指令(LDM/STM)。
(1)存储器访问----单寄存器操作指令
LDR/STR指令用于对内存访问。
所有的单寄存器加载/存储指令可分为"
字和无符号字节加载存储指令"
和"
半字和有符号字节加载存储指令"
。
A.字和无符号字节加载存储指令
LDR指令用于从内存中读取单一字或字节数据存入寄存器中,STR指令用于将寄存器中的单一字或字节数据保存到内存。
LDR{cond}Rd,[地址];
将指定地址上的字数据读入Rd
STR{cond}Rd,[地址];
将Rd中的字数据存入指定地址
LDR{cond}BRd,[地址];
将指定地址上的字节数据读入Rd
STR{cond}BRd,[地址];
将Rd中的字节数据存入指定地址
LDR/STR指令寻址非常灵活,它由两部分组成,其中一部分为一个基址寄存器,它可以为任意一个通用寄存器;
另一部分为一个地址偏移量。
地址偏移量可以有以下三种格式:
1)立即数。
立即数可以是一个无符号的数值。
这个数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:
LDRR1,[R0,#0x12]
LDRR1,[R0,#-0x12]
2)寄存器。
寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
LDRR1,[R0,R2]
LDRR1,[R0,-R2]
3)寄存器及移位常数。
寄存器移位后的值可以加到基址寄存器,也可以从基址中减去这个数值。
LDRR1,[R0,R2,LSL#2]
LDRR1,[R0,-R2,LSL#2]
从寻址方式的地址计算方法分,加载/存储指令可以由以下4种格式:
1)零偏移
如:
LDRRd,[Rn]
2)前索引偏移
如:
LDRRd,[Rn,#0x04]!
这里的"
!
"
表示,先将Rn=Rn+0x04,然后在从[Rn]中加载数据到Rd。
现在大家应该明白这里的"
前"
的含义就是先更新Rn的值,然后在Rn所表示的地址取值。
3)程序相对偏移
LDRRd,labe1
4)后索引偏移
LDRRd,[Rn],#0x04
先将[Rn]地址的值加载到Rd,然后更新Rn=Rn+0x04
大多数情况下,必须保证字数据操作的地址是32位对齐的。
B.半字和有符号字节加载/存储指令
LDR{cond}SBRd,<
地址>
;
将指定地址上的有符号字节读入Rd
LDR{cond}SHRd,<
将指定地址上的有符号半字读入Rd
LDR{cond}HRd,<
将指定地址上的半字数据读入Rd
STR{cond}HRd,<
将Rd中的半字数据存入指定地址
1.有符号位半字/字节加载是指用符号位加载扩展到32位,无符号半字加载是指用零扩展到32位;
2.半字读写的指定地址必须为偶数,否则将产生不可靠的结果;
LDR和STR指令应用示例:
1.加载/存储字和无符号字节指令
LDRR2,[R5];
将R5指向地址的字数据存入R2
STRR1,[R0,#0x04];
将R1的数据存储到R0+0x04地址
LDRBR3,[R2],#1;
将R2指向地址的字节数据存入R3,R2=R2+1
STRBR6,[R7];
将R7指向地址的字节数据存入R6
2.加载/存储半字和有符号字节指令
LDRSBR1,[R0,R3];
将R0+R3地址上的字节数据存入R1,高24位用符号扩展
LDRHR6,[R2],#2;
将R2指向地址的半字数据存入R6,高16位用0扩展,读出后,R2=R2+2
STRHR1,[R0,#2]!
将R1的半字数据保存到R0+2地址,;
只修改低2字节数据,R0=R0+2
(2)存储器访问----多寄存器操作指令
多寄存器加载/存储指令格式如下:
LDM{cond}<
模式>
Rn{!
},{reglist}^
STM{cond}<
},{reglist}^
cond:
指令执行的条件;
可选
模式:
控制地址的增长方式,一共有8种模式;
:
表示在操作结束后,将最后的地址写回Rn中;
可选,通常我们都使用它
reglist:
表示寄存器列表,可以包含多个寄存器,它们使用“,”隔开,如{R1,R2,R6-R9},寄存器由小到大排列;
^:
加入该后缀后,进行数据传送且寄存器列表不包含PC时,加载/存储的寄存器是用户模式下的,而不是当前模式的寄存器。
若在LDM指令且寄存器列表中包含有PC时使用,那么除了正常的多寄存器传送外,还将SPSR也拷贝到CPSR中,这可用于异常处理返回。
该后缀不允许在用户模式或系统模式下使用。
多寄存器加载/存储指令的8种模式如下表所示,左边四种为数据传送操作、右边四种为堆栈操作、。
A.数据块传送指令操作过程如右图所示,其中R1为指令执行前的基址寄存器,R1’则为指令执行后的基址寄存器
B.堆栈操作和数据块传送指令类似,也有4种模式,它们之间的关系如下表所示:
两段代码的执行结果是一样的,但是使用堆栈指令的压栈和出栈操作编程很简单(只要前后一致即可),而使用数据块指令进行压栈和出栈操作则需要考虑空与满、加与减对应的问题。
3.状态寄存器读写指令
A.状态寄存器读指令
在ARM处理器中,只有MRS指令可以对状态寄存器CPSR和SPSR进行读操作。
通过读CPSR可以了解当前处理器的工作状态。
读SPSR寄存器可以了解到进入异常前的处理器状态。
MRSR1,CPSR;
将CPSR状态寄存器读取,保存到R1中
MRSR2,SPSR;
将SPSR状态寄存器读取,保存到R2中
B.状态寄存器写指令
在ARM处理器中,只有MSR指令可以对状态寄存器CPSR和SPSR进行写操作。
与MRS配合使用,可以实现对CPSR或SPSR寄存器的读-修改-写操作,可以切换处理器模式、或者允许/禁止IRQ/FIQ中断等。
4.ARM伪指令
ARM伪指令不属于ARM指令集中的指令,但是编译器能识别,是为了编程方便而定义的。
伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。
ARM伪指令有四条,分别为ADR伪指令、ADRL伪指令、LDR伪指令、NOP伪指令。
(1)ADR小范围的地址读取
ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。
在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。
通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。
地址表达式expr的取指范围:
A.当地址值不是字对齐时,其取指范围为-255~255;
B.当地址值是字对齐时,其取指范围为-1020~1020;
C.当地址值是16字节对齐时,其取指范围将更大。
应用举例:
指定链接-Ttext0x30008000生成的可执行文件反汇编后的结果如下:
可以看到,r3=当前pc-0x14。
ADR这条指令经常用来获取代码运行的地址。
假如,这段代码放在内存中运行,其所在的内存存储空间的首地址为0x30008000。
当CPU运行到红线框起来的那条指令时,大家可以思考一下此时PC的值为多少呀?
聪明的你一定还记得,PC指向的永远都是预取指令的地址,即当前指令所在的地址+8。
呵呵,这样PC=0x3000800c+8=0x30008014。
r3=pc-0x14=0x30008014-0x14=0x30008000。
(2)ADRL中等范围的地址读取
ADRL伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址。
在汇编编译器编译源程序时,ADRL伪指令被编译器替换成两条合适的指令。
若不能用两条指令实现,则产生错误,编译失败。
当地址值是字节对齐时,取值范围为−64~64KB;
当地址值是字对齐时,取值范围为−256~256KB。
(3)LDR大范围的地址读取
LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。
在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。
若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。
从上图可以知道,ldrr6,=0x12指令在进行处理的时候,编译器知道0x12是一个立即数,就直接将其翻译成mov指令的。
如果操作的不是立即数,则用文字池的形式进行存储,然后通过ldr指令从对应的地址读取数据。
1.从指令位置到文字池的偏移量必须小于4KB;
2.与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。
(4)空操作伪指令
NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOVR0,R0”指令等。
NOP可用于延时操作。
应用示例(延时子程序):
Delay
NOP;
空操作
NOP
SUBSR1,R1,#1;
循环次数减一
BNEDelay;
如果循环没有结束,跳转Delay继续
MOVPC,LR;
子程序返回
三、ARM处理器寻址方式
寻址方式是根据指令中给出的地址码字段来实现寻找真实操作数地址的方式。
ARM处理器具有9种基本寻址方式。
1.寄存器寻址;
2.立即寻址;
3.寄存器移位寻址;
4.寄存器间接寻址;
5.基址寻址;
6.多寄存器寻址;
7.堆栈寻址;
8.块拷贝寻址;
9.相对寻址。
(1)寄存器寻址
操作数的值在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直接取