ARM常用指令集
(2011-10-11 21:26:46)
标签:
杂谈 |
分类: AMR |
常用ARM指令及汇编包括
1、ARM处理器寻址方式
2、指令集介绍
3、伪指令
4、ARM汇编程序设计
5、C与汇编混合编程
ARM处理器寻址方式
1、寄存器寻址:操作数的值在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直接取出寄存器值操作
MOV
SUB
2、立即寻址:立即寻址指令中的操作码字段后面的地址码部分就是操作数本身,也就是说,数据就包含在指令当中,取出指令就取出了可以立即使用的操作数
SUBS
R0,R0,#1
MOV
注:立即数要以"#"为前缀,表示16进制数值时以"0x"表示
3、寄存器偏移寻址:是ARM指令集特有的寻址方式,当第2操作数是寄存器偏移方式时,第2个寄存器操作数在与第1个操作数结合之前选择进行移位操作
MOV
ANDS R1,R1,R2,LSL R3
寄存器偏移寻址可采用的移位操作如下
(1)、LSL(Logical Shift Left)逻辑左移,寄存器中字的低端空出补0
(2)、LSR(Logical Shift Right)逻辑右移,寄存器中字的高端空出补0
(3)、ASR(Arthmetic Shift
Right)算术右移,移位中保持符号位不变,即如果源操作数为正数,字高端空出补0,否则补1
(4)、ROR(Rotate Right)循环右移,由字的低端移出的位填入高端空出的位
(5)、RRX(Rotate Right eXtended by 1
place),操作数右移一位,左侧空位由CPSR的C填充
4、寄存器间接寻址:寄存器间接寻址指令中的地址码给出的是一个通用寄存器的编号,所需要的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针
LDR
SWP R1,R1,[R2] ;将R2中的数值作为地址,取出此地址中的数值与R1中的值交换
5、基址寻址:将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址,基址寻址用于访问基址附近的存储单元,常用于查表,数组操作,功能部件寄存器访问等。
LDR
R2,[R3,#0x0F]
STR
R1,[R0,#-2]
6、多寄存器寻址:一次可以传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器
LDMIA R1!,{R2-R7,R12}
STMIA
R0!,{R3-R6,R10}
7、堆栈寻址:堆栈是特定顺序进行存取的存储区,堆栈寻址时隐含的使用一个专门的寄存器(堆栈指针),指向一块存储区域(堆栈),存储器堆栈可分为两种:
向上生长:向高地址方向生长,称为递增堆栈
向下生长:向低地址方向生长,称为递减堆栈
如此可结合出四中情况:
1、满递增:堆栈通过增大存储器的地址向上增长,堆栈指针指向内含有效数据项的最高地址,指令如 LDMFA,STMFA
2、空递增:堆栈通过增大存储器的地址向上增长,堆栈指针指向堆栈上的第一个空位置,指令如 LDMEA,STMEA
3、满递减:堆栈通过减小存储器的地址向下增长,堆栈指针指向内含有效数据项的最低地址,指令如 LDMFD,STMFD
4、空递减:堆栈通过减小存储器的地址向下增长,堆栈指针指向堆栈下的第一个空位置,指令如 LDMED,STMED
STMFD SP!,{R1-R7,LR}
LDMFD SP!,{R1-R7,LR}
8、块拷贝寻址:多寄存器传送指令用于一块数据从存储器的某一位置拷贝到另一位置
STMIA
R0!,{R1-R7}
STMIB
R0!,{R1-R7}
SIMDA
R0!,{R1-R7}
STMDB
R0!,{R1-R7}
不论是向上还是向下递增,存储时高编号的寄存器放在高地址的内存,出来时,高地址的内容给编号高的寄存器
9、相对寻址:是基址寻址的一种变通,由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址
BL ROUTE1
BEQ
LOOP
================================================================================================================
指令集介绍
指令格式:<opcode>
{<cond>}{S}<Rd>,<Rn>,{<operand2>}
其中<>内的项是必须的,{}内的项是可选的
opcode
cond
S
Rd
Rn
operand2 第二个操作数
指令格式举例如下:
LDR
R0,[R1]
BEQ
DATAEVEN
ADDS R1,R1,#1
SUBNES R1,R1,#0xD ;条件执行减法运算(NE),R1-0xD =>
R1,影响CPSR寄存器,带有S
条件码表
条件码助记符 |
标志 |
含义 |
EQ |
Z=1 |
相等 |
NE |
Z=0 |
不相等 |
CS/HS |
C=1 |
无符号数大于或等于 |
CC/LO |
C=0 |
无符号数小于 |
MI |
N=1 |
负数 |
PL |
N=0 |
正数 |
VS |
V=1 |
溢出 |
VC |
V=0 |
没有溢出 |
HI |
C=1,Z=0 |
无符号数大于 |
LS |
C=0,Z=1 |
无符号数小于或等于 |
GE |
N=V |
带符号数大于或等于 |
LT |
N!=V |
带符号数小于 |
GT |
Z=0,N=V |
带符号数大于 |
LE |
Z=1,N!=V |
带符号数小于或等于 |
AL |
|
任何无条件执行(指令默认条件) |
条件码应用举例:
1、比较两个值大小,C代码如下:
if(a>b) a++;
else b++;
写出相应的ARM指令
代码如下:设R0为a,R1为b
CMP R0,
R1
ADDHI
R0,R0,#1
ADDLS
R1,R1,#1
2、若两个条件均成立,则将这两个数值相加
C代码为: if((a!=10)&&(b!=20))
a=a+b;
对应的ARM指令为:
CMP
R0,#10
CMPNE R1,#20
ADDNE R0,R0,R1; 若R0不为10且R1不为20,则执行 R0 = R0+R1
3、若两个条件有一个成立,则将这两个数值相加
C代码为:
对应的ARM指令为:
CMP
R0,#10
CMPEQ R1,#20
ADDNE R0,R0,R1
ARM存储访问指令:
LDR、STR、LDM、STM、SWP
LDR/STR:加载/存储字和无符号字节指令
从寻址方式的地址计算方法分,加载/存储指令有以下4种形式:
1,零偏移:LDR Rd,[Rn]
2,前索引偏移: LDR Rd,[Rn,#0x04]!,LDR Rd,[Rn,#-0x04] Rn不允许为R15
3,程序相对偏移:LDR Rd,label,label为程序标号,该形式不能使用后缀!
4,后索引偏移: LDR Rd,[Rn],#0x04,Rn不允许是R15
指令举例如下:
LDR
R2,[R5]
STR
R1,[R0,#0x04]
LDRB
R3,[R2],#1
STRH R1,[R0,#2]!
LDM和STM是批量加载/存储指令,LDM为加载多个寄存器,STM为存储多个寄存器,主要用途是现场保护,数据复制、参数传递等,其模式有8种,前4种用于数据块的传输,后4种用于堆栈操作
IA:每次传送后地址加4
IB:每次传动前地址加4
DA:每次传送后地址减4
DB:每次传送前地址减4
FD:满递减堆栈
ED:空递增堆栈
FA:满递增堆栈
EA:空递增堆栈
批量加载/存储指令举例如下:
LDMIA
R0!,{R3-R9}
STMIA
R1!,{R3-49}
STMFD SP!,{R0-R7,LR}
LDMFD SP!,{R0-R7,PC}^ ;恢复现场,异常处理返回
使用LDM/STM进行数据复制
LDR
R0,=SrcData
LDR
R1,=DstData
LDMIA R0,{R2-R9}
STMIA R1,{R2-R9}
使用LDM/STM进行现场保护,常用在子程序或异常处理中
STMFD SP!,{R0-R7,LR} ;寄存器入栈
.....
BL
DELAY
.....
LDMFD SP!,{R0-R7,PC}
SWP是寄存器和存储器交换指令,可使用SWP实现信号量操作
12C_SEM EQU 0x40003000
12C_SEM_WAIT
MOV R1,#0
LDR
R0,=12C_SEM
SWP
R1,R1,[R0]
CMP
R1,#0
BEQ
12C_SEM_WAIT
ARM数据处理指令包括
1、数据传送指令
2、算术逻辑运算指令
3、比较指令
4、乘法指令
ADC指令:带进位加法指令,将操作数2的数据与Rn的值相加,再加上CPSR中C条件标志位,结果保存到Rd中
使用ADC指令实现64位加法
ADDS R0,R0,R2
ADC
SBC指令:带借位减法指令,用寄存器Rn减去操作数2,再减去CPSR中的C条件标志位的非(即若C标志清零,则结果减去1),结果保存在Rd中
使用SBC实现64位减法
SUBS R0,R0,R2
SBC
AND指令:按位与操作
ANDS R0,R0,#0x01
ORR指令:按位或操作
ORR R0,R0,#0x0F
EOR指令是进行异或操作,BIC指令是位清除指令(遇1清0)
TST:位测试指令
TST
R0,#0x01
TEQ:相等测试指令
TEQ
R0,R1
MUL指令:乘法指令
MUL R1,R2,R3
MULS R0,R3,R7
MLA是乘加指令,将操作数1和操作数2相乘再加上第3个操作数,结果的低32位存入到Rd中
UMULL是64位无符号乘法指令
UMULL R0,R1,R5,R8
BL指令:带链接的跳转指令,指令将下一条指令拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行
BL指令用于子程序调用,例如:BL DELAY
BX指令:带状态切换的跳转指令,例如 BX R0 ;跳转到R0指定的地址,并根据R0的最低位来切换处理器的状态
MCR:ARM寄存器到协处理器寄存器的数据传送指令
MRC:协处理器寄存器到ARM寄存器的数据传送指令
MRC/MCR指令格式如下:
MRC/MCR {cond} coproc,opcode1,Rd,CRn,CRm{,opcode2}
coproc是指令操作的协处理器名,标准名为pn,n为0-15
opcode1 协处理器的特定操作码
Rd
CRn 存放第1个操作数的协处理器寄存器
CRm 存放第2个操作数的协处理器寄存器
opcode2 可选的协处理器特定操作码
MRC/MCR指令举例如下:
mcr/mrc p15,0,r0,c1,c0,0
SWI指令:SWI指令用于产生中断,从而实现用户模式变换到管理模式,CPSR保存到管理模式的SPSR中,执行转移到SWI向量
SWI 0x123456
在SWI异常中断处理程序中,取出SWI立即数的步骤为:首先确定引起软中断的SWI指令是ARM指令还是THUMB指令,这可通过对SPSR访问得到,然后要取得该SWI指令的地址,这可通过访问LR寄存器得到,接着读出指令,分解出立即数
程序代码如下:
T_bit EQU
0x20
SWI_Hander
MRS指令:读状态寄存器指令,在ARM处理器中,只有MRS指令可以从状态寄存器CPSR或SPSR读出到通用寄存器
MRS
R1,CPSR
MRS
R2,SPSR
MRS应用:
1、使能IRQ中断
ENABLE_IRQ
MRS R0,CPSR
BIC
R0,R0,#0x80
MSR CPSR,R0
MOV PC,LR
2、禁止IRQ中断
DISABLE_IRQ
MRS R0,CPSR
ORR R0,R0,#0x80
MSR CPSR,R0
MOV PC,LR
MSR:写状态寄存器指令,在ARM处理器中,只有MSR指令可以直接设置状态寄存器CPSR或SPSR
================================================================================================================
ARM伪指令介绍
ARM伪指令不是ARM指令集中的指令,只是为了编程方便编译器定义了伪指令
ARM地址读取伪指令有四条,分别是
ADR
ADRL
LDR
NOP
作用的范围不一样,由小到大: ADR,ADRL,LDR
ADR、ADRL指令将基于PC相对偏移的地址读取到存储器中,例如
ADR
LDR
.....
DISP_TAB
DCB
LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器,前加 =
LDR
R0,=0x123456
LDR R0,=DATA_BUF+60
NOP是空操作伪指令
宏是一段独立的程序代码,它是通过伪指令定义的,在程序中使用宏指令即可调用宏,当程序被汇编时,汇编程序将对每个调用进行展开,用宏定义取代源程序中的宏指令
符号定义伪指令
1、全局变量声明:GBLA、GBLL 和 GBLS
2、局部变量声明:LCLA、LCLL 和 LCLS
3、变量赋值:SETA、SETL、和 SETS
4、为一个通用寄存器列表定义名称:RLIST
5、为一个协处理器的寄存器定义名称:CN
6、为一个协处理器定义名称:CP
最后一个字符 A代表算术变量,初始值为0,L代表逻辑变量,初值为FALSE,S代表字符串,初值为空
伪指令应用举例如下:
MACRO
SENDDAT
$dat
LCLA
bitno
...
bitno SETA
8
...
MEND
RLIST指令格式:
name RLIST {reglist},例如: LoReg RLIST
{R0-R7}
CN指令的用法:
name CN expr,其中name是要定义的协处理器的寄存器名称,expr对应的协处理器的寄存器编号,数值范围 0 ~
15
MemSet CN 1
CP指令的用法,举例如下:
DivRun CP
5
数据定义伪指令:
1、声明一个文字池:LTORG
2、定义一个结构化的内存表的首地址:MAP 或 ^
3、定义结构化内存表中的一个数据域:FIELD 或 #
4、分配一块内存空间,并用0初始化: SPACE 或 %
5、分配一段字节内存单元,并用指定的数据初始化: DCB
6、分配一段字的内存单元,并用指令的数据初始化: DCD 和 DCDU
7、分配一段双字的内存单元,并用64位整数数据初始化: DCQ 和 DCQU
8、分配一段半字的内存单元,并用指定的数据初始化: DCW 和 DCWU
LTORG
用于声明一个文子池,在使用LDR伪指令时,要在适当的地址加入LTORG声明文子池,这样就会把要加载的数据保存在文子池内,再用ARM的加载指令读出数据(若没有使用LTORG声明文子池,则汇编器会在程序末尾自动声明)
LTORG伪指令应用举例如下:
...
LDR R0,=0x12345678
ADD R1,R1,R0
MOV PC,LR
LTORG
DCD
DCD 0x555
MAP 用于定义一个结构化的内存表的首地址,^与MAP同义
MAP 0x00, R9
FIELD 用于定义一个结构化内存表的数据域,#与FIELD同义
^
_ISR_STARTADDRESS
HandleReset
SPACE用于分配一块内存单元,并用0初始化,%与SPACE同义
伪指令应用举例如下:
AREA DataRAM,DATA,READWROTE
DataBuf
SPACE
DCB伪指令格式:
{label} DCB expr{,expr} ...
加{}的代表可有可无,DCD、DCW指令格式与DCB基本相同
ASSERT为断言错误伪指令,在汇编编译器对汇编程序的第二遍扫描中,若其中ASSERT条件不成立,ASSERT伪指令将报告该错误信息
ASSERT
Top<>Temp
ASSERT
:DEF:ENDIAN_CHANGE
汇编控制伪指令
1、条件汇编控制:IF、ELSE 和 ENDIF
IF、ELSE 和 ENDIF 伪指令能够根据条件把一段代码包括在汇编程序内或将其排除在程序之外
[ 与 IF同义 ,| 与 ELSE 同义, ] 与 ENDIF 同义
伪指令应用举例如下:
[ {CONFIG} =
16
BL __rt_udiv_1
|
BL __rt_div0
]
2、MACRO 和 MEND
MACRO 和 MEND
伪指令用于宏定义,MACRO表示宏定义的开始,MEND表示宏定义的结束,用MACRO和MEND定义的一段代码,称为宏定义体,伪指令应用如下:
MACRO
CSI_SETB
LDR R0,=rPDATG
LDR R1,[R0]
ORR R1,R1,#0x01
STR
R1,[R0]
MEND
3、WHILE 和 WEND
WHILE 和 WEND 伪指令用于根据条件重复 编相同的或几乎相同的一段源程序
伪指令应用举例
WHILE no< 5
no SETA no+1
...
WEND
杂项伪指令:在汇编程序设计较为常用,如段定义伪指令,入口点设置伪指令,包含文件伪指令,标号导出或引入声明
1、边界对齐:ALIGN
2、段定义: AREA
3、指令集定义:CODE16 和 CODE32
4、汇编结束: END
5、程序入口: ENTRY
6、常量定义:EQU
7、声明一个符号可以被其它文件引用:EXPORT 和 GLOBAL
8、声明一个外部符号:IMPORT 和 EXTERN
9、包含文件: GET 和 INCLUDE
10、给特定的寄存器命名: RN