寻址方式
定义(问题引出):操作数是一条指令的操作对象。在指令执行前,CPU需要按照在指令中给定的方式找到操作数。在指令中给出操作数存放地址的方式,简称寻址方式。处理器可依据给定的寻址方式来获得操作数存放的地址,进而找到操作数。
种类(9种):立即数寻址、寄存器寻址、寄存器移位寻址、寄存器间接寻址、基址变址寻址、相对寻址、多寄存器寻址、块拷贝寻址、堆栈寻址。
1 立即数寻址 :
也称立即寻址,立即数作为操作数在指令中给出。立即数在指令中要以“#”为前缀,后面跟实际数值。数值前缀0x表示十六进制数,0b表示二进制数。
MOV R1,#5 ;R1 =5
MOV R0,#0xFF000 ;R0 = 0xFF000
2 寄存器寻址 :
操作数存放在寄存器中,通过寄存器可以找到该数值。
MOV R1, R2 ;R1 =R2
ADD R0,R1,#3 ;R0=R1+3
3 寄存器间接寻址 :
寄存器中的值为存储操作数单元的物理地址,寄存器起到指针作用。寄存器间接寻址指令举例如下:
MOV R1,#0xE0200000 ;R1 = 0xE0200000
MOV R0,#3 ;R0 = 3
STR R0, [R1] ;[E0200000] = 3
4 寄存器移位寻址 :
寄存器移位寻址是在寄存器寻址得到操作数后再进行移位操作,最终得到操作数。移位的方式在指令中以助记符形式给出,而移位的位数可用立即数或寄存器寻址方式表示。
ADD R0,R1,R2,ROR #5 ;R0=R1+(R2>>5)
ARM指令集提供的移位操作指令如下:
(1)LSL: 逻辑左移(Logical Shift Left),移出空位补0。
(2)LSR: 逻辑右移(Logical Shift Right。
(3)ASL: 算术左移(Arithmetic Shift Left)。
(4)ASR:算术右移(Arithmetic Shift Right)。
(5)ROR:循环右移(Rotate Right)。
(6)RRX进位标志位C作为D32,与Rx组成33位数,执行循环右移操作。
5 基址变址寻址 :
Rx寄存器(基址寄存器)的值与指令中给出的偏移地址量相加,所得结果作为存放操作数存储单元的物理地址。选项“!”表示指令执行完毕把最后的数据地址写到Rx。
LDR R0, [R1,#5] ;R0 = [R1+5]
LDR R0, [R1, #5]! ;R0 = [R1+5], R1 = R1 + 4
ldmia r0!, {r3 - r10} ;copy from source address [r0]
6 相对寻址 :
相对寻址与基址变址寻址相似,区别只是将程序计数器PC作为基址寄存器,指令中的地址标号作为偏移量,将两者相加之后得到操作数的存放地址。
B process1 ;无条件跳转到process1处执行指令
…… ;若干其它指令
process1 MOV R0,#3
;定义指令标号为process1,可供B指令指定跳转位置
…… ;若干其它指令
7.多寄存器寻址
在多寄存器寻址方式中,可以使用一条指令实现一组寄存器值的传送。连续的寄存器间需要使用“-”符号连接,否则用“,”分隔。多寄存器寻址指令举例如下:
LDMIA R0,{R1-R4,R6} ;R1=[R0], R2=[R0+4], R3=[R0+8], R4=[R0+12], R6=[R0+16]
多寄存器寻址方式中,基址寄存器传送一个数据后有4种增长方式,即:
IA(Increment After Operating): 每次传送后地址增加4。
IB(Increment Before Operating): 每次传送前的地址增加4。
DA(Decrement After Operating): 每次传送后地址减少4。
DB(Decrement Before Operating): 每次传送前地址减少4。
在多寄存器寻址指令举例中,指令为寄存器赋值语句。源地址为寄存器R0所指向的内存地址,目的地址为寄存器,为每个指定寄存器赋值之后,R0的内容增4来得到存放下一个数据的内存地址。指令中在助记符字段附加了内存地址增长方式的条件,表示每次传送后地址增加4,依次从源地址开始的20(5*4)个连续存储单元取出数据(字长为4子节)赋值给5个寄存器(R1, R2, R3, R5,R6)。
8.块拷贝寻址
块拷贝寻址可实现数据块的拷贝和复制。块拷贝寻址指令举例如下:
LDMIA R0,{R1-R5} /*从以R0的值为起始地址的存储单元(源数据块首地址)读出5个字(字长为4字节)的数据,依次存入R1-R5寄存器(目的地址)。*/
STMIA R1,{R1-R5} /*将R1-R5中的数值(源数据块)依次存入以R1寄存器中的值为起始地址的存储单元(目的首地址),完成数据块存储。IA表示每次传送后地址增加4。*/
9.堆栈寻址
堆栈寻址用于数据栈与寄存器组之间批量数据传输,实现寄存器数据入栈的保护和出栈的恢复。 R13用于堆栈指针,等同于SP(Stack Pointer)。堆栈是一种数据结构,按先进后出(FILO First In Last Out)的方式工作,使用堆栈指针指示当前操作位置,SP总是指向栈顶。
(1)根据堆栈的生成方式不同,可以把堆栈分为递增堆栈和递减堆栈两种类型。
递增堆栈:向堆栈写入数据时,堆栈由低地址向高地址生长。
递减堆栈:向堆栈写入数据时,堆栈由高地址向低地址生长。
(2)根据SP指向的位置,又可以把堆栈分为满堆栈(Full Stack)和空堆栈(Empty Stack)两种类型。
满堆栈(Full Stack):SP指向最后压入堆栈的数据。满堆栈在向堆栈存放数据时的操作是先移动SP指针,然后存放数据。在从堆栈取数据时,先取出数据,随后移动SP指针。这样保证了SP一直指向有效的数据。
空堆栈(Empty Stack):堆栈指针SP指向下一个将要放入数据的空位置。空堆栈在向堆栈存放数据时的操作是先放数据,然后移动SP指针。在从堆栈取数据时,是先移动指针,再取数据。这种操作方式保证了堆栈指针一直指向一个空地址(没有有效数据的地址)。
(3)上述两种堆栈类型的组合,可以得到四种基本的堆栈类型组合。
满递增堆栈(FA):堆栈指针指向最后压入的数据,且由低地址向高地址生长。
满递减堆栈(FD):堆栈指针指向最后压入的数据,且由高地址向低地址生长。
空递增堆栈(EA):堆栈指针指向下一个要压入数据的地址,由低地址向高地址生长。
空递减堆栈(ED):堆栈指针指向下一个要压入数据的地址,由高地址向低地址生长。
在编写程序中,堆栈操作建议采用统一标准。堆栈寻址指令举例如下:
STMFD R13!,{R0,R1,R2,R3,R4} ;将R0-R4中的数据压入堆栈,R13为堆栈指针
LDMFD R13!,{R0,R1,R2,R3,R4} ;将数据弹出栈,依次送到R0-R4。