-
传送多个数据
LDM/STM 的主要用途是把需要保存的寄存器复制到栈上。如我们以前见到过的 STMFD R13!, {R0-R12, R14}
。
指令格式是:
xxM{条件}{类型} Rn{!}, <寄存器列表>{^}
‘xx’是 LD 表示装载,或 ST 表示存储。
再加 4 种‘类型’就变成了 8 个指令:
栈 其他 LDMED LDMIB 预先增加装载 LDMFD LDMIA 过后增加装载 LDMEA LDMDB 预先减少装载 LDMFA LDMDA 过后减少装载 STMFA STMIB 预先增加存储 STMEA STMIA 过后增加存储 STMFD STMDB 预先减少存储 STMED STMDA 过后减少存储指令格式
汇编器关照如何映射这些助记符。注意 ED 不同于 IB;只对于预先减少装载是相同的。在存储的时候,ED 是过后减少的。
FD、ED、FA、和 EA 指定是满栈还是空栈,是升序栈还是降序栈。一个满栈的栈指针指向上次写的最后一个数据单元,而空栈的栈指针指向第一个空闲单元。一个降序栈是在内存中反向增长(就是说,从应用程序空间结束处开始反向增长)而升序栈在内存中正向增长。
其他形式简单的描述指令的行为,意思分别是过后增加(Increment After)、预先增加(Increment Before)、过后减少(Decrement After)、预先减少(Decrement Before)。
RISC OS 使用传统的满降序栈。在使用符合 APCS 规定的编译器的时候,它通常把你的栈指针设置在应用程序空间的结束处并接着使用一个 FD (满降序 - Full Descending)栈。如果你与一个高级语言(BASIC 或 C)一起工作,你将别无选择。栈指针(传统上是 R13)指向一个满降序栈。你必须继续这个格式,或则建立并管理你自己的栈(如果你是死硬派人士那么你可能喜欢这样做!)。
‘基址’是包含开始地址的寄存器。在传统的 RISC OS 下,它是栈指针 R13,但你可以使用除了 R15 之外的任何可获得的寄存器。
如果你想把复制操作后栈顶的当前的内存地址保存到栈指针中,可以寄存器按从最低到最高的编号次序与到从低端到高端的内存之间传送数据。并且因为用指令中的一个单一的位来表示是否保存一个寄存器,不可能指定某个寄存器两次。它的副作用是不能用下面这样的代码:
STMFD R13!, {R0, R1} LDMFD R13!, {R1, R0}来交换两个寄存器的内容。
提供了一个有用的简写。要包含一个范围的寄存器,可以简单的只写第一个和最后一个,并在其间加一个横杠。例如 R0-R3
等同与 R0, R1, R2, R3
,只是更加整齐和理智而已...
在把 R15 存储到内存中的时候,还保存了 PSR 位。在重新装载 R15 的时候,除非你要求否则不恢复 PSR 位。要求的方法是在寄存器列表后跟随一个‘^’。
STMFD R13!, {R0-R12, R14} ... LDMFD R13!, {R0-R12, PC}这保存所有的寄存器,做一些事情,接着重新装载所有的寄存器。从 R14 装载 PC,它由一个 BL 或此类指令所设置。不触及 PSR 标志。
STMFD R13!, {R0-R12, R14} ... LDMFD R13!, {R0-R12, PC}^这保存所有的寄存器,做一些事情,接着重新装载所有的寄存器。从 R14 装载 PC,它由一个 BL 或此类指令所设置。变更 PSR 标志。
警告: 这些代码不遵从 32 bit 体系。你需要使用 MRS 和 MSR 来处理 PSR,你不能使用‘^’后缀。
注意在这两个例子中,R14 被直接装载到 PC 中。这节省了对 MOV(S) R14 到 R15 中的需要。
警告: 使用 MOVS PC,... 不遵从 32 bit 体系。你需要使用 MRS 和 MSR 来处理 PSR。
SWP : 单一数据交换
(Swap)
SWP{条件}{B} <dest>, <op 1>, [<op 2>]指令格式
SWP
将:
- 从操作数 2 所指向的内存装载一个字并把这个字放置到目的寄存器中。
- 把寄存器操作数 1 的内容存储到同一个地址中。
如果提供了
B
后缀,则将传送一个字节,否则传送一个字。