ARM资料Word文件下载.docx
《ARM资料Word文件下载.docx》由会员分享,可在线阅读,更多相关《ARM资料Word文件下载.docx(52页珍藏版)》请在冰豆网上搜索。
堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。
存储器堆栈可分为两种:
▪向上生长:
向高地址方向生长,称为递增堆栈
▪向下生长:
向低地址方向生长,称为递减堆栈
堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;
堆栈指针指向下一个待压入数据的空位置,称为空堆栈。
所以可以组合出四种类型的堆栈方式:
▪满递增:
堆栈向上增长,堆栈指针指向内含有效数据项的最高地址。
指令如LDMFA、STMFA等;
(先增后入、先出后减)
▪空递增:
堆栈向上增长,堆栈指针指向堆栈上的第一个空位置。
指令如LDMEA、STMEA等;
(先入后增、先减后出)
▪满递减:
堆栈向下增长,堆栈指针指向内含有效数据项的最低地址。
指令如LDMFD、STMFD等;
(先减后入、先出后增)
▪空递减:
堆栈向下增长,堆栈指针向堆栈下的第一个空位置。
指令如LDMED、STMED等。
(先入后减、先增后出)
8.块拷贝寻址;
多寄存器传送指令用于将一块数据从存储器的某一位置拷贝到另一位置。
如:
STMIAR0!
{R1-R7};
将R1~R7的数据保存到存储器中。
存储指针在保存第一个值之后增加,
;
增长方向为向上增长。
STMIBR0!
存储指针在保存第一个值之前增加,
9.相对寻址。
相对寻址是基址寻址的一种变通。
由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。
相对寻址指令举例如下:
BLSUBR1;
调用到SUBR1子程序
BEQLOOP;
条件跳转到LOOP标号处
...
LOOPMOVR6,#1
SUBR1...
简单的汇编语言程序
文件名:
TEST1.S
功能:
实现两个寄存器相加
说明:
使用ARMulate软件仿真调试
AREAExample1,CODE,READONLY;
声明代码段Example1
ENTRY;
标识程序入口
CODE32;
声明32位ARM指令
STARTMOVR0,#0;
设置参数
MOVR1,#10
LOOPBLADD_SUB;
调用子程序ADD_SUB
BLOOP;
跳转到LOOP
ADD_SUB
ADDSR0,R0,R1;
R0=R0+R1
MOVPC,LR;
子程序返回
END;
文件结束
4.2汇编语言伪指令简介
ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。
伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。
1、AREA段定义(默认段首址以字对齐,最低2位地址为0)
格式:
AREA段名{,属性1}{,属性2}...
代码段属性为CODE,属性2默认为READONLY
数据段属性为DATA,属性2默认为READWRITE
例:
AREAExample3,CODE,READONLY
2、ENTRY
定义一个指向程序的入口。
3、CODE32/CODE16
声明32位ARM指令或16位的Thumb指令。
4、END
指示汇编器,源文件到此结束。
5、EQU
定义一个常量。
例:
abcEQU2
6、SPACE
分配一个值为0的内存数据块
{标号}SPACE数值表达式。
dbufSPAC256;
从标号dbuf开始定义256字节的0
7、DCB/DCW/DCD/DCQ
定义字节/半字/字/双字定义
{标号}DCB/DCW/DCD/DCQ表达式{,表达式}
例:
AREAMyData,DATA,READWRITE
stringDCB"
ABCDEFG"
0;
定义一个字符串
taDCW0x1234,0x5566;
定义2个半字(16位)
data2DCD0x12345678;
定义1个字(32位)
dataDCQ0x1122334455667788;
定义1个双字(64位)
data1SPACE256
8、LDR
LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。
在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。
若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。
格式:
LDR{cond}register,=expr
注意:
从指令位置到文字池的偏移量必须小于4KB;
与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。
LDRR0,=0x12345678;
加载32位立即数0x12345678
LDRR0,=DATA_BUF+60;
加载DATA_BUF地址+60
...
LTORG;
声明文字池
伪指令LDR常用于加载芯片外围功能部件的寄存器地址(32位立即数),以实现各种控制操作。
LDRR0,=IOPIN;
加载GPIO的寄存器IOPIN的地址
LDRR1,[R0];
读取IOPIN寄存器的值
LDRR0,=IOSET
LDRR1,=0X00500500
STRR1,[R0];
IOSET=0x00500500
9、NOP
NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOVR0,R0”指令等。
NOP可用于延时操作。
NOP
Delay
NOP;
空操作
NOP
SUBSR1,R1,#1;
循环次数减一
BNEDelay;
如果循环没有结束,跳转Delay继续
MOVPC,LR;
子程序返回
4.3指令集介绍
一、ARM指令的基本格式如下:
<
opcode>
{<
cond>
}{S}<
Rd>
<
Rn>
{,<
operand2>
}
其中<
>
号内的项是必须的,{}号内的项是可选的。
各项的说明如下:
opcode:
指令助记符;
cond:
执行条件;
S:
是否影响CPSR寄存器的值;
Rd:
目标寄存器;
Rn:
第1个操作数的寄存器;
operand2:
第2个操作数;
第2个操作数“operand2”能够提高代码效率。
它有如下的形式:
▪#immed_8r——常数表达式;
▪Rm——寄存器方式;
▪Rm,shift——寄存器移位方式;
ADDS R2, R1, R1, LSL#3;
R2=R1+R1*8=9R1
(1)#immed_8r——常数表达式
该常数必须对应8位位图,即一个8位的常数通过循环右移偶数位得到。
例如:
MOVR0,#1
ANDR1,R2,#0x0F
而下面的指令因超过8位,所以有错
MOV R1,#0X1234
(2)Rm——寄存器方式
在寄存器方式下,操作数即为寄存器的数值。
SUBR1,R1,R2
MOVPC,R0
(3)Rm,shift——寄存器移位方式
将寄存器的移位结果作为操作数,但Rm值保持不变,移位方法如下:
操作码
说明
ASR#n
算术右移n位
ROR#n
循环右移n位
LSL#n
逻辑左移n位
RRX
带扩展的循环右移1位
LSR#n
逻辑右移n位
TypeRs
Type为移位的一种类型,Rs为偏移量寄存器,低8位有效。
ADDR1,R1,R1,LSL#3;
R1=R1+R1*8=9R1
SUBR1,R1,R2,LSRR3;
R1=R1-(R2/2R3)
执行条件
使用条件码“cond”可以实现高效的逻辑操作,提高代码效率。
所有的ARM指令都可以条件执行,而Thumb指令只有B(跳转)指令具有条件执行功能。
如果指令不标明条件代码,将默认为无条件(AL)执行。
指令条件码表
条件助记符
标志
含义
0000
EQ
Z=1
相等
0001
NE
Z=0
不相等
0010
CS/HS
C=1
无符号数大于或等于
0011
CC/LO
C=0
无符号数小于
0100
MI
N=1
负数
0101
PL
N=0
正数或零
0110
VS
V=1
溢出
0111
VC
V=0
没有溢出
1000
HI
C=1,Z=0
无符号数大于
1001
LS
C=0,Z=1
无符号数小于或等于
1010
GE
N=V
有符号数大于或等于
1011
LT
N!
=V
有符号数小于
1100
GT
Z=0,N=V
有符号数大于
1101
LE
Z=1,N!
有符号数小于或等于
1110
AL
任何
无条件执行(指令默认条件)
1111
NV
从不执行(不要使用)
例如C代码:
if(a>
b)
a++;
else
b++;
对应的汇编代码:
CMPR0,R1;
R0与R1比较
ADDHIR0,R0,#1;
若R0>
R1,则R0=R0+1
ADDLSR1,R1,#1;
若R0≤R1,则R1=R1+1
二、存储器访问指令
ARM处理器是典型的RISC处理器,对存储器的访问只能使用加载和存储指令实现。
ARM处理器是冯•诺依曼存储结构,程序空间、RAM空间及I/O映射空间统一编址,除对RAM操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行。
存储器访问指令分为单寄存器操作指令和多寄存器操作指令。
(一)单寄存器操作指令
单寄存器加载
助记符
操作
条件码位置
LDRRd,addr
加载字数据
Rd←[addr],addr索引
LDR{cond}
LDRBRd,addr
加载无符号字节数据
LDR{cond}B
LDRHRd,addr
加载无符号半字数据
LDR{cond}H
LDRSBRd,addr
加载有符号字节数据
LDR{cond}SB
LDRSHRd,addr
加载有符号半字数据
Rd←[addr],addr索引
LDR{cond}SH
单寄存器存储
STRRd,addr
存储字数据
[addr]←Rd,addr索引
STR{cond}
STRBRd,addr
存储字节数据
STR{cond}B
STRHRd,addr
存储半字数据
[addr]←Rd,addr索引
STR{cond}H
LDR/STR指令用于对内存变量的访问、内存缓冲区数据的访问、查表、外围部件的控制操作等。
若使用LDR指令加载数据到PC寄存器,则实现程序跳转功能,这样也就实现了程序散转。
所有单寄存器加载/存储指令可分为“字和无符号字节加载存储指令”和“半字和有符号字节加载存储指令”。
1、LDR和STR——字和无符号字节加载/存储指令
LDR指令用于从内存中读取单一字或字节数据存入寄存器中,STR指令用于将寄存器中的单一字或字节数据保存到内存。
指令格式如下:
LDR{cond}Rd,<
地址>
将指定地址上的字数据读入Rd
STR{cond}Rd,<
将Rd中的字数据存入指定地址
LDR{cond}BRd,<
将指定地址上的字节数据读入Rd
STR{cond}BRd,<
将Rd中的字节数据存入指定地址
LDR/STR指令寻址非常灵活,它由两部分组成,其中一部分为一个基址寄存器,可以为任一个通用寄存器;
另一部分为一个地址偏移量。
地址偏移量有以下3种格式:
(1)立即数。
立即数可以是一个无符号的数值。
这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
如:
LDRR1,[R0,#0x12]
(2)寄存器。
寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
LDRR1,[R0,R2]
(3)寄存器及移位常数。
寄存器移位后的值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
LDRR1,[R0,R2,LSL#2]
从寻址方式的地址计算方法分,加载/存储指令有以下4种格式:
零偏移。
如:
LDRRd,[Rn]
前索引偏移。
LDRRd,[Rn,#0x04]!
程序相对偏移。
LDRRd,labe1
后索引偏移。
LDRRd,[Rn],#0x04
2、LDR和STR——半字和有符号字节加载/存储指令
这类LDR/STR指令可加载有符号半字或字节,可加载/存储无符号半字。
偏移量格式、寻址方式与加载/存储字和无符号字节指令相同。
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
(二)多寄存器存取
多寄存器加载/存储指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。
LDM为加载多个寄存器;
STM为存储多个寄存器。
允许一条指令传送16个寄存器的任何子集或所有寄存器。
它们主要用于现场保护、数据复制、常数传递等。
多寄存器加载/存储指令格式如下:
LDM{cond}<
模式>
Rn{!
},reglist
STM{cond}<
指令执行的条件;
模式:
控制地址的增长方式,一共有8种模式;
!
:
表示在操作结束后,将最后的地址写回Rn中;
reglist:
表示寄存器列表,可以包含多个寄存器,它们使用“,”隔开,如{R1,R2,R6-R9},寄存器由小到大排列;
多寄存器加载/存储指令的8种模式如下表所示,右边四种为堆栈操作、左边四种为数据传送操作。
模式
IA
每次传送后地址加4
FD
满递减堆栈
IB
每次传送前地址加4
ED
空递减堆栈
DA
每次传送后地址减4
FA
满递增堆栈
DB
每次传送前地址减4
EA
空递增堆栈
数据块传送操作
堆栈操作
进行数据复制时,先设置好源数据指针和目标指针,然后使用块拷贝寻址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB进行读取和存储。
进行堆栈操作操作时,要先设置堆栈指针(SP),然后使用堆栈寻址指令STMFD/LDMFD、STMED/LDMED、STMFA/LDMFA和STMEA/LDMEA实现堆栈操作。
FD满递减堆栈是指数据入栈时指针先减后放数据,出栈时为先取数据后加指针。
所以减是指入栈时减。
其它模式类推。
数据块传送指令操作过程如下图所示,其中R1为指令执行前的基址寄存器,R1’则为指令执行后的基址寄存器。
堆栈操作和数据块传送指令类似,也有4种模式,它们之间的关系如下表所示:
数据块传送
存储
压栈
加载
出栈
STMDA
STMED
空递减
LDMDA
LDMFA
满递减
STMIA
STMEA
空递增
LDMIA
LDMFD
满递增
STMDB
STMFD
LDMDB
LDMEA
STMIB
STMFA
LDMIB
LDMED
下面两段代码的执行结果是一样的,但是使用堆栈指令的压栈和出栈操作编程很简单(只要前后一致即可),而使用数据块指令进行压栈和出栈操作则需要考虑空与满、加与减对应的问题。
(三)寄存器和存储器交换指令
SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm的内容写入到该内存单元中。
使用SWP可实现信号量操作。
SWP{cond}{B}Rd,Rm,[Rn]
其中,B为可选后缀,若有B,则交换字节,否则交换32位字;
Rd用于保存从存储器中读入的数据;
Rm的数据用于存储到存储器中;
Rn为要进行数据交换的存储器地址,Rn不能与Rd和Rm相同。
SWP指令应用示例:
SWPR1,R1,[R0];
将R1的内容与R0指向的存储单元的内容进行交换
SWPBR1,R2,[R0];
将R0指向的存储单元内的容读取一字节数据到R1中
(高24位清零),并将R2的内容写入到该内存单元中
;
(最低字节有效)
三、ARM数据处理指令
数据处理指令大致可分为3类:
数据传送指令;
算术逻辑运算指令;
比较指令。
数据处理指令只能对寄存器的内容进行操作,而不能对内存中的数据进行操作。
所有ARM数据处理指令均可选择使用S后缀,并影响状态标志。
(一)数据传送指令
MOVRd,operand2
数据传送
Rd←operand2
MOV{cond}{S}
MVNRd,operand2
数据非传送
Rd←(~operand2)
MVN{cond}{S}
MOV指令将8位图立即数或寄存器传送到目标寄存器(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
(二)算术运算指令
ADDRd,Rn,operand2
加法运算指令
Rd←Rn+operand2
ADD{cond}{S}
SUBRd,Rn,operand2
减法运算指令
Rd←Rn-operand2
SUB{cond}{S}
RSBRd,Rn,operand2
逆向减法指令
Rd←operand2-Rn
RSB{cond}{S}
ADCRd,Rn,operand2
带进位加法
Rd←Rn+ope