在Thumb多寄存器数据存取指令中,LDM和STM将任何范围为R0~R7的寄存器子集从存储器以及存储到存储器中。PUSH和POP指令使用堆栈指针作为基址实现满递减堆栈。除了可传送R0~R7外,PUSH还可用于存储链接寄存器LR,并且POP可用于加载程序指针PC(R15)。
和ARM指令一样,Thumb多寄存器数据存取指令可用于过程调用与返回以及存储器块拷贝。但为了编码的紧凑性,着2种用法由分开的指令实现,其寻址方式的数量也有所限制。在其他方面这些指令的性质与等价的ARM指令相同。
二进制编码
Thumb多寄存器存取指令的二进制编码如图:
<ignore_js_op>
说明
指令的块拷贝形式只有使用LDMIA和STMIA寻址模式,即Thumb指令集使用LDM和STM指令进行多寄存器的加载和存储操作时,LDM和STM指令必须包括后缀,而且只有IA一个后缀。Lo寄存器中的任何一个可作为基址寄存器。寄存器列表可以是这些寄存器的任意子集,因为总是选择回写,所以寄存器列表中不应包括基址寄存器。
堆栈形式使用指令PUSH和POP,并使用SP作为基址寄存器,并且也总是使用回写。堆栈的模式也固定为满栈递减。寄存器列表除了可以是8个Lo寄存器外,链接寄存器LR可出现在PUSH指令中,PC可出现在POP指令中,以优化过程调用及返回程序。
汇编格式
<reglist>是寄存器列表,寄存器范围是R0~R7。
LDMIA Rn!,{<reglist>}
STMIA Rn!,{<reglist>}
POP {<reglist>{,PC}}
PUSH {<reglist>{,PC}} //该类指令中仅有寄存器列表,默认的基址寄存器
//为R13
下面分别介绍多寄存器传送指令LDMIA和STMIA,堆栈指令PUSH和POP.
(1) LDMIA和STMIA
加载和存储多个寄存器。
句法
OpRn!,{reglist}
其中:reglist为低寄存器(R0~R7)或低寄存器范围的、用逗号隔开的列表。
注意:列表中至少应有一个寄存器。
用法
寄存器以寄存器编号顺序加载或存储。编号最低的寄存器在Rn的初始地址中。Rn的值以reglist中寄存器个数的4倍增加。若Rn在寄存器列表中,则
对于LDMIA指令,Rn的最终值是加载的值,不是增加后的地址。
对于STMIA指令,Rn的存储值有如下2种情况:若Rn是寄存器列表中最低数据的寄存器,则Rn存储的值为Rn的初值;其他情况则不可预知。
例子
LDMIA R3!,{R0,R4}
LDMIA R5!,{R0-R7}
STMIA R0!,{R6,R7}
STMIA R3!,{R3,R5,R7}
(2)PUSH和POP
低寄存器和可选的LR进栈,以及低寄存器和可选的PC出栈。
句法
PUSH {reglist}POP {reglist}
PUSH {reglist,LR} POP {reglist,PC}
其中:reglist为低寄存器(R0~R7)的全部子集的列表。句法说明中的括号是指令格式的一部分。它们不代表指令列表可选。列表中至少必须有一个寄存器。
用法
Thumb堆栈时满递减堆栈。堆栈向下增长,且SP指向堆栈的最后入口。寄存器以数字顺序存储在堆栈中。编号最低的寄存器其地址最低。
POP{reglist,PC}
这条指令引起处理器转移到从堆栈弹出给PC的地址。这通常是从子程序返回,其中LR在子程序开头压进堆栈。该指令不影响条件码标志。
例子
PUSH {R0,R3,R5}
PUSH {R1,R4-R7} ;R1,R4~R7堆栈
PUSH {R0,LR }
POP {R2,R5}
POP {R0-R7,PC} ;出栈,并从子程序返回
(1) 等价的ARM指令
对于前2种块格式,等价的ARM指令有相同的汇编格式。在后2种指令格式中,要以合适的寻址模式来代替POP和PUSH。
块拷贝
LDMIA Rn!,{<reglist>}
STMIA Rn!,{<reglist>}
POP
LDMFD SP!,{<reglist>{,PC}}
PUSH
STMIA SP!,{<reglist>{,LR}} //PC不能进栈,不能弹出到LR
注意
基址寄存器必须是字对齐的,否则一些系统将忽略地址值的低2位,而另一些系统会产生未对齐访问异常。
由于所有这些指令都采用基址回写,因此基址寄存器不应出现在寄存器列表中。
编码后reglist即指令中的位[0:7],它的每一位对应一个寄存器,如位0指示R0寄存器是否传送,送1控制R1等。在POP和PUSH指令中,R位控制PC核LR。
在V5T结构中,装载PC的最低位更新Thumb位,因此可直接返回到Thumb或ARM调用程序。