寄存器间接寻址

寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。例如以下指令:

LDR R0,[R1]   /*R0←[R1]*/
STR R0,[R1] /*[R1]←R0*/

第一条指令将以R1的值为地址的存储器中的数据传送到R0中。第二条指令将R0的值传送到以R1的值为地址的存储器中。

ARM的数据传送指令都是基于寄存器间接寻址,即通过Load/Store完成对数据的传送操作。

基址加偏址寻址(变址寻址)

基址变址寻址就是将寄存器(该寄存器一般称作基址寄存器)的内容与指令中给出的地址偏移量(用12位表示,不超过4KB)相加,从而得到一个操作数的有效地址。变址寻址方式常用于访问某基地址附近的地址单元。

变址寻址方式可以分为:前变址(Pre-indexed)、自动变址(Auto-indexed)和后变址(Post-indexed)。

  1. 前变址模式
LDR R0,[R1,#4] ;R0←[R1+4]
  1. 自动变址模式
LDR R0,[R1,#4]! ;R0←[R1+4]、R1←R1+4
  1. 后变址模式
LDR R0,[R1] ,#4 ;R0←[R1]、R1←R1+4

偏移地址

地址偏移除了可以是一个12位的立即数,还可以是另一个寄存器,并且在加到基址寄存器之前还可以先经过移位操作,如:

LDR R0,[R1,R2]    ;R0←[R1+R2]
LDR R0,[R1,R2,LSL #2] ;R0←[R1+R2*4]

传送数据类型

ARM处理器支持的传送数据类型可以是有符号和无符号的8位字节、16位半字、32位字,最高位表示符号位(正数为0,负数为1)。对于字节操作,在指令中增加了字母B,对于半字,在指令中增加了字母H进行标识。默认是字操作,不加数据类型标识。如:

LDRB R0,[R1]  ;R0←mem8[R1], 加载8位字节数据到寄存器R0,零扩展到32位
LDRH R1,[R0,#20] ;R0←mem16[R0+20] 加载16位半字到寄存器R1 ,零扩展到32位

这时,传送的地址可与任意字节、半字对齐,而不限于4字节对齐。

块拷贝寻址(多寄存器寻址)

块拷贝寻址是多寄存器传送指令LDM/STM的寻址方式。通过一条指令可以把一个数据块加载到多个寄存器中,也可以把多个寄存器中的内容保存到存储器中。这种寻址方式中的寄存器可以是R0-R15这16个通用寄存器中的部分或全部。如:

LDMIA   R0,{R1,R2,R3,R4}  
;R1←[R0]
;R2←[R0+4]
;R3←[R0+8]
;R4←[R0+12]

该指令的后缀IA表示在每次执行完加载/存储操作后,R0按字长度增加,因此,指令可将连续存储单元的值传送到R1~R4。

LDM/STM指令依据其后缀名(如:IA,DB)的不同,其寻址的方式也有很大不同。这些后缀可以定义存储器地址的增长是向上还是向下,以及地址的增减与指令操作的先后顺序(即:操作先进行还是地址的增减先进行)。

这些后缀可以分成两大类:一类用于数据的存储与读取,这类后缀有:IA、IB、DA、DB;另一类用于堆栈的操作,即压栈和出栈,这类后缀有:FD、ED、FA、EA。

这些后缀的含义是:

  • IA(Increment After) 操作完成后地址递增
  • IB(Increment Before)地址先增后完成操作
  • DA(Decrement After)操作完成后地址递减
  • DB(Decrement Before)地址先减后完成操作
  • FD (Full Decrement)满递减堆栈
  • ED (Empty Decrement)空递减堆栈
  • FA(Full Aggrandizement)满递增堆栈
  • EA(Empty Aggrandizement)空递增堆栈

块拷贝寻址示例

嵌入式:ARM间接寻址、变址寻址与多寄存器寻址_变址

例:分析下面两条指令的作用,并分析基址寄存器的变化有什么不同?

LDMIA   R0!,{R2-R9} 
STMIA R1,{R2-R9}

这两句的作用是将R0指向的连续8个存储单元的内容拷贝到R1指向的连续8个单元中去。

这两句执行完毕后,R0的内容增加了32个字节,这是由于使用了自动变址符号“!”,而R1的内容保持保持不变。

注意:在堆栈操作中总是要指定自动变址,否则,以前保存的内容会因为堆栈寄存器的基址不变将在下一次堆栈操作时遭到破坏!

参考文献:

孟祥莲.嵌入式系统原理及应用教程(第2版)[M].北京:清华大学出版社,2017.