原文:http://www.eefocus.com/article/08-08/49786s.html
ARM指令的编码格式
实际指令语法格式为:
ADDEQS R0,R1,R2;
该指令的编码格式为:
ARM指令的助记符
ARM指令在汇编程序中用助记符表示,一般ARM指令的助记符格式为:
<opcode>{<cond>} {S} <Rd>,<Rn>,<op2>
其中:
<opcode> 操作码,如ADD表示算术加操作指令;
{<cond>} 决定指令执行的条件域;
{S} 决定指令执行是否影响CPSR寄存器的值;
<Rd> 目的寄存器;
<Rn> 第一个操作数,为寄存器;
<op2> 第二个操作数。
例如,指令 ADDEQS R1,R2,#5
条件域<cond>
几乎所有的ARM指令都可以根据当前程序状态寄存器CPSR中标志位的值,有条件地执行。
ARM指令的条件域<cond>有16种类型。
ARM指令中的第二操作数
灵活的使用第2个操作数“operand2”能够提高代码效率。它有如下的形式:
#immed_8r——常数表达式;
Rm——寄存器方式;
Rm,shift——寄存器移位方式
ARM指令中的第二操作数
如果一个32位立即数直接用在32位指令编码中,就有可能完全占据32位指令编码空间。因此,ARM指令的32位立即数是通过循环右移偶数位得到的。
立即数是由一个8位的常数循环右移位偶数位得到的。
<immediate>=immed_8循环右移(2×rotate_imm)
例如:下面的代码段:
MOV R0, #0x0000F200
MOV R1, #0x00110000
MOV R4, #0x00012800
上面的指令经过汇编之后得到的二进制编码为:
8000:E3A00CF2 (0xF200是由0xF2循环右移24位得到的)
8004:E3A01811(0x110000是由0x11循环右移16位得到的)
8008: E3A04B4A(0x12800是由0下4A循环右移24位得到的)
非法的立即数:0x1010,0x00102,0xFF1000
寻址方式
9种:
立即数寻址
寄存器寻址
寄存器移位寻址
寄存器间接寻址
基址变址寻址
相对寻址
多寄存器寻址
块拷贝寻址
堆栈寻址
立即数寻址
在立即数寻址中,操作数本身直接在指令中给出,取出指令也就获得了操作数,这个操作数也称为立即数。
#后接0x或&表示十六进制数,0b表示二进制数,0d或缺省表示十进制数。
例:
ADD R0,R1,#5; R0=R1+5
MOV R0,#0x55; R0=0x55
其中:操作数5,0x55就是立即数,立即数在指令中要以“#”为前缀,后面跟实际数值。
寄存器寻址
在寄存器寻址方式下,寄存器的值即为操作数。ARM指令普遍采用此种寻址方式。
例:
ADD R0,R1,R2 ; R0=R1+R2
MOV R0,R1 ; R0=R1
寄存器移位寻址
寄存器移位寻址的操作数由寄存器的数值做相应移位而得到。
移位的方式在指令中以助记符的形式给出,而移位的位数可用立即数或寄存器寻址方式表示。
例:
ADD R0,R1,R2,ROR #5
;R0=R1+R2循环右移5位
MOV R0,R1,LSL R3
;R0=R1逻辑左移R3位
移位操作在ARM指令集中不作为单独的指令使用,ARM指令集共有5种位移操作。
ARM指令集的5种位移操作
LSL逻辑左移 :Rx,LSL <op1>
LSR逻辑右移 : Rx,LSR <op1>
ASR算术右移 :Rx,ASR <op1>
ROR循环右移 :Rx,ROR <op1>
RRX带扩展的循环右移:Rx,RRX
寄存器间接寻址
寄存器中的值为操作数的物理地址,而实际的操作数存放在存储器中。
例:
STR R0,[R1] ; [R1]=R0
LDR R0,[R1] ; R0=[R1]
基址变址寻址
将寄存器(称为基址寄存器)的值与指令中给出的偏移地址量相加,所得结果作为操作数的物理地址。
例:
LDR R0,[R1,#5] ; R0=[R1+5]
LDR R0,[R1,R2] ; R0=[R1+R2]
相对寻址
相对寻址同基址变址寻址相似,区别只是将程序计数器PC作为基址寄存器,指令中的标记作为地址偏移量。
例:
BEQ process1
……
process1
……
多寄存器寻址
在多寄存器寻址方式中,一条指令可实现一组寄存器值的传送。
连续的寄存器间用“-”连接,否则用“,”分隔。
例:
LDMIA R0,{R1-R5}
;R1=[R0],R2=[R0+4],R3=[R0+8]
;R4=[R0+12],R5=[R0+16]
指令中IA表示在执行完一次Load操作后,R0自增4。该指令将以R0为起始地址的5个字数据分别装入R1,R2,R3,R4,R5中。
多寄存器寻址
多寄存器寻址一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。多寄存器寻址指令举例如下:
块拷贝寻址
块拷贝寻址可实现连续地址数据从存储器的某一位置拷贝到另一位置。
例:
LDMIA R0,{R1-R5};
STMIA R1,{R1-R5};
第一条指令从以R0的值为起始地址的存储单元中取出5个字的数据,第二条指令将取出的数据存入以R1的值为起始地址的存储单元中。
实际上是多寄存器寻址的组合。
堆栈寻址
堆栈寻址用于数据栈与寄存器组之间批量数据传输。
当数据写入和读出内存的顺序不同时,使用堆栈寻址可以很好的解决这问题。
例:
STMFD R13!,{R0,R1,R2,R3,R4};
LDMFD R13!,{R0,R1,R2,R3,R4}
第一条指令,将R0-R4中的数据压入堆栈,R13为堆栈指针;
第二条指令,将数据出栈,恢复R0-R4原先的值。
存储器堆栈可分为两种:
向上生长:向高地址方向生长,称为递增堆栈
向下生长:向低地址方向生长,称为递减堆栈