3.6 ARM指令的寻址方式
寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。目前,ARM处理器有以下9种基本寻址方式。
3.6.1 立即寻址
在立即寻址指令中数据就包含在指令中,立即寻址指令的操作码字段后面的地址码部分就是操作数本身,取出指令也就取出了可以立即使用的操作数。立即寻址是一种特殊的寻址方式。
例如,指令:
ADD R0,R0,#1;R0←R0+1
这条指令完成,寄存器R0的内容加1,结果放回R0中。
ADD R0,R0,#0x3f;R0←R0+0x3f
这条指令完成,寄存器R0的32位值和0x3f相与,结果将R0的低8位送回R0中。
在以上两条指令中,第二个源操作数即为立即数,要求以“#”为前缀,对于用十六进制表示的立即数,还要求在“#”后加上“0x”或“&”。
3.6.2 寄存器寻址
操作数的值在寄存器中,指令中的地址码字段给出的是寄存器编号,寄存器的内容是操作数,指令执行时直接取出寄存器值操作。
例如,指令:
ADD R0,R1,R2;R0←R1+R2
这条指令将寄存器R1和寄存器R2的内容相加,结果放入寄存器R0中。
例如,指令:
SUB R0,R1,R2;R0←R1- R2
这条指令将寄存器R1的内容减去寄存器R2的内容,结果放入寄存器R0中。
3.6.3 寄存器间接寻址
指令中的地址码给出的是一个通用寄存器编号,所需要的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针,操作数存放在存储器中。寄存器间接寻址使用一个寄存器的值作为存储器的地址。
例如,指令:
LDR R0,[R1];R0←[R1]
这条指令将寄存器R1指向的地址单元的内容加载到寄存器R0中。
STR R0,[R1];[R1]←R0
这条指令将寄存器R0存入寄存器R1指向的地址单元。
寄存器移位寻址是ARM指令集特有的寻址方式。第2个寄存器操作数在与第1个操作数结合之前,先进行移位操作。
例如,指令:
MOV R0,R2,LSL #3;
这条指令完成,寄存器R2的值左移3位,结果放入R0,即R3←R2+8×R1。
ANDS R1,R1,R2,LSL R3;
这条指令完成,寄存器R2的值左移R3位,然后和R1相与操作,结果放入R1。
可采用的移位操作如下:
LSL:逻辑左移(Logical Shift Left),寄存器中字的低端空出的位补“0”。移位操作过程如图3-11所示。
LSR:逻辑右移(LogicalShiftRight),寄存器中字的高端空出的位补“0”。移位操作过程如图3-12所示。
图3-11 逻辑左移
图3-12 逻辑右移
ASR:算术右移(Arithmetic Shift Right),移位过程中保持符号位不变,即如果源操作数为正数,则字的高端空出的位补“0”,否则补“1”。移位操作过程如图3-13所示。
ROR:循环右移(Rotate Right),由字的低端移出的位填入字的高端空出的位。移位操作过程如图3-14所示。
图3-13 算术右移
图3-14 循环右移
RRX:带扩展的循环右移(Rotate Right extended by 1 place),操作数右移一位,高端空出的位用原C标志值填充。移位操作过程如图3-15所示。
图3-15 带扩展的循环右移
3.6.4 相对寻址
相对寻址是变址寻址的一种变通,由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。
与基址变址寻址方式类似,相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,将两者相加后,得到操作数的有效地址。
例如,指令:
BL ROUTE 1;调用到ROUTE1子程序。 BEQ LOOP;条件跳转到LOOP标号处。 LOOP MOV R2,#2 ROUTE 1
3.6.5 堆栈寻址
堆栈是按FILO的特定顺序进行存储的存储区。堆栈寻址是隐含的,它使用一个专门的寄存器指向一块存储器区域。栈指针所指定的存储单元就是堆栈的栈顶。
存储器生长堆栈可分为两种:
1)向上生长:向高地址方向生长,称为递增堆栈(Ascending Stack)。
2)向下生长:向低地址方向生长,称为递减堆栈(Decending Stack)。
堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈(Full Stack);堆栈指针指向下一个要放入的空位置,称为空堆栈(Empty Stack)。
这样就有4种类型的堆栈工作方式,ARM微处理器支持这4种类型的堆栈工作方式:
1)满递增堆栈:堆栈指针指向最后压入的数据,且由低地址向高地址生成。如指令LDMFA,STMFA等。
2)满递减堆栈:堆栈指针指向最后压入的数据,且由高地址向低地址生成。如指令LDMFD,STMFD等。
3)空递增堆栈:堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。如指令LDMEA,STMEA等。
4)空递减堆栈:堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。如指令LDMED,STMED等。
3.6.6 块复制寻址
块复制寻址用于把块从存储器的某一位置复制到另一位置,是一个多寄存器传送指令。
例如,指令:
STMIA R0!,{R1~R7};
这条指令将R1~R7的数据保存到存储器中,存储器指针在保存第一个值后增加,增长方向为向上增长。
STMDA R0!,{R1~R7};
这条指令将R1~R7的数据保存到存储器中,存储器指针在保存第一个值后增加,增长方向为向下增长。
3.6.7 变址寻址
变址寻址就是将基址寄存器的内容与指令中给出的位移量相加,形成操作数有效地址。变址寻址用于访问基址附近的存储单元,包括基址加偏移和基址加索引寻址。寄存器间接寻址是偏移量为零的基址加偏移寻址。
(1)基址加偏移寻址
1)前索引寻址方式:基址需加或减最大4KB的偏移来计算访问的地址。
例如:
LDR R0,[R1,#4];R0←[R1+4]
2)后索引寻址方式:基址不带偏移作为传送的地址,传送后自动索引。
例如:
LDR R0,[R1],#4;R0←[R1] ;R1←R1+4
(2)基址加索引寻址
指令指定一个基址寄存器,再指定另一个寄存器,其值作为位移加到基址上形成存储器地址。
例如,指令:
LDR R0,[R1,R2] ; R0←[R1+R2]
3.6.8 多寄存器寻址
一次可以传送几个寄存器的值,允许一条指令传送16个寄存器的任何子集(或所有16个寄存器)。例如,指令:
LDMIA R0,{R1,R2,R3,R4} ; R1←[R0] ; R2←[R0+4] ; R3←[R0+8] ; R4←[R0+12]
由于传送的数据项总是32位的字,基址R1应该字对准。这条指令将R0指向的连续存储单元的内容送到寄存器R1、R2、R3和R4。