ARM指令集之批量Load/Store指令

本文详细介绍了ARM指令集中批量Load/Store指令的工作原理,包括指令编码格式、寻址方式、S位的含义及其对PC和PSR的影响。讨论了事后递增(IA)、事先递增(IB)、事后递减(DA)和事先递减(DI)四种寻址模式,并列举了LDM和STM指令的不同用法,以及它们在栈操作中的应用。
摘要由CSDN通过智能技术生成

批量Load-Store指令可以实现连续内存块和一组寄存器之间的数据交换,它通常使用在运行环境的保存、恢复,以及两个内存块之间的数据拷贝。

指令编码格式

在这里插入图片描述

  • 寄存器列表
    每个bit代表一个寄存器,如果为1表示对应寄存器参与传输,bit0代表R0,依此类推。
  • Rn
    指定了要操作的内存块的基地址。不能使用PC寄存器作为基址寄存器。
  • Load/Store Bit
    0为Store操作,1为Load操作。
  • Write-Back Bit
    指定指令执行后是否要更新基址寄存器Rn的值,0不更新,1更新。
  • PSR & Force User Bit(S位)
    0表示不操作CPSR和SPSR寄存器或者为用户模式,1表示操作程序状态寄存器或者为非用户模式。因为这两种情况是互斥的,所以可以用同一位来表示。更详细的说明见下方介绍。
  • Up/Down Bit
    0表示从基址寄存器递减偏移量,1表示递增。
  • Pre/Post Indexing Bit
    0表示在是每一次寄存器和内存之间的数据传输之后再根据U位更新当前偏移量(事后操作),1表示在数据传输之前更新偏移量(事前操作)。

特别注意:不要将事前事后关联到是否更新基址寄存器Rn上。

关于S位

首先S位应该只在特权模式下使用。指令是否设置S位要看指令中是否有"^"符号。S=1后,根据寄存器列表中是否有PC,分为如下几种情况:

  1. 如果PC在寄存器列表中,LDM指令和STM指令处理方式不同:
    1. 对于LDM指令,处理器会在设置PC寄存器时,同步将SPSR_mode的内容放到CPSR中;
    2. 对于STM指令,处理器会将用户模式的寄存器放入内存,而不是当前模式的寄存器。这种情况也不应该使W=1,即改变基址寄存器;注意:此时会将PC+12保存到内存中;
  2. PC不在寄存器列表中,LDM和STM处理方式相同,都是在用户模式寄存器和内存之间进行数据传输。出于安全考虑,应该在LDM指令之后插入一条NOP指令,然后再访问寄存器内容(不理解,应该和流水线有关系);

寻址方式

从指令编码格式的介绍中,可以看出,批量Load/Store指令的寻址方式应该是由基址寄存器Rn、U位、和P位一起决定的。

此处在理解起来有些绕,需要牢记下面两条原则,这些原则是无论使用哪种寻址方式都是需要遵守的。

  1. 数据传输过程中,一定是按照R0~R15的顺序传输的;
  2. 传输后,一定是R0在内存的低地址,R1在内存的高地址;

下面以一个示例来说明支持的4种寻址方式。示例假定基址寄存器Rn为0x1000,参与批量传输的寄存器列表为R1、R5、R7,且假定数据传输完毕后,都会更新Rn寄存器(W=1)。

在理解下面的4个场景时,不妨想象一下,将批量操作分解成一个个单独的Load/Store步骤,这样便于理解其区别。

事后递增方式IA

在这里插入图片描述
假设当前操作的内存地址为A(A的初始值为Rn),事后递增指的是先执行当前寄存器和地址A的数据传输,然后再递增A的值。

通用伪代码如下:

start_address = Rn
end_address = Rn + (Number_Of_Set_Bits_In(register_list) * 4) - 4
if CondPassed(cond) and W == 1 then
	Rn = Rn + (Number_Of_Set_Bits_In(register_list) * 4)

事先递增方式IB

在这里插入图片描述
假设当前操作的内存地址为A(A的初始值为Rn),事先递增指的是先递增A的值,然后再执行当前寄存器和地址A的数据传输。

通用伪代码如下:

start_address = Rn + 4
end_address = Rn + (Number_Of_Set_Bits_In(register_list) * 4)
if CondPassed(cond) and W == 1 then
	Rn = Rn + (Number_Of_Set_Bits_In(register_list) * 4)

事后递减方式DA

在这里插入图片描述
假设当前操作的内存地址为A(A的初始值为Rn-12+4),事后递减指的是先执行当前寄存器和地址A的数据传输,然后再递减A的值。

通用伪代码如下:

start_address = Rn - (Number_Of_Set_Bits_In(register_list) * 4) + 4
end_address = Rn
if CondPassed(cond) and W == 1 then
	Rn = Rn - (Number_Of_Set_Bits_In(register_list) * 4)

事先递减方式DI

在这里插入图片描述
假设当前操作的内存地址为A(A的初始值为Rn-12),事先递减指的是先递减A的值,然后再执行当前寄存器和地址A的数据传输。

通用伪代码如下:

start_address = Rn - (Number_Of_Set_Bits_In(register_list) * 4)
end_address = Rn - 4
if CondPassed(cond) and W == 1 then
	Rn = Rn - (Number_Of_Set_Bits_In(register_list) * 4)

批量访存指令

ARM有如下批量Load/Store指令。

助记符说明
LDM(1)批量字数据读取指令
LDM(2)用户模式的批量字数据读取指令
LDM(3)带状态寄存器的批量字数据读取指令
STM(1)批量字数据写入指令
STM(2)用户模式的批量字数据写入指令

这些指令的通用语法如下:

<LDM|STM>{cond}<FD|ED|FA|EA|IA|IB|DA|DB> Rn{!},<Rlist>{^}
  • !:如果有该符号,表示指令执行后,修改基址寄存器Rn的值,即W=1;
  • ^:如果有该符号,表示设置S位,此时指令会根据寄存器列表中是否有PC,进而让PSR参与数据传输,或者执行用户模式处理,具体见前面关于S位的介绍。

LDM(1)(批量字数据读取指令)

LDM{<cond>}<address_mode> <Rn>{!}, <registers>

if CondPassed(cond) then
	address = start_address
	for i in [0, 14]
		if register_list[i] == 1 then
			Ri = Mem[address, 4]
			address += 4
	
	if register_list[15] == 1 then
		value = Mem[address, 4]
		if (arch version 5 or above) then
			pc = value & 0xFFFF_FFFE
			T Bit = value[0]
		else
			pc = value & 0xFFFF_FFFC
		address += 4
	
	assert end_address == address - 4

LDM(2)(用户模式的批量字数据读取指令)

和LDM(1)功能类似,不同点在于当在特权模式下使用该指令时,内存系统将以一般用户模式身份进行内存访问,而且最终也是将内存单元中的数据存入用户模式的寄存器中。

LDM{<cond>}<address_mode> <Rn>, <registers_without_pc>^

if CondPassed(cond) then
	address = start_address
	for i in [0, 14]
		if register_list[i] == 1 then
			Ri_usr = Mem[address, 4]
			address += 4
	
	assert end_address == address - 4

LDM(3)(带状态寄存器的批量字数据读取指令)

该指令的寄存器列表必须包含PC。

LDM{<cond>}<address_mode> <Rn>{!}, <registers_and_pc>^

if CondPassed(cond) then
	address = start_address
	for i in [0, 14]
		if register_list[i] == 1 then
			Ri = Mem[address, 4]
			address += 4
	
	CPSR = SPSR
	value = Mem[address, 4]
	if (arch version 4T, 5 or above) and (T Bit == 1) then
		pc = value & 0xFFFF_FFFE
	else
		pc = value & 0xFFFF_FFFC
	address += 4
	assert end_address == address - 4

STM(1)(批量字数据写入指令)

STM{<cond>}<address_mode> <Rn>{!}, <registers>

if CondPassed(cond) then
	address = start_address
	for i in [0, 15]
		if register_list[i] == 1 then
			Mem[address, 4] = Ri
			address += 4

	assert end_address == address - 4

STM(2)(用户模式的批量字数据写入指令)

STM{<cond>}<address_mode> <Rn>, <registers>^

if CondPassed(cond) then
	address = start_address
	for i in [0, 15]
		if register_list[i] == 1 then
			Mem[address, 4] = Ri_usr
			address += 4

	assert end_address == address - 4

栈操作

批量Load/Store指令经常还用于栈操作,由于栈的FIFO操作特性,首先定义4个概念:

  1. 如果栈指针指向最后一个入栈元素地址,那么称该栈为Full栈;如果指向最后一个元素的下一个空位置,那么称该栈为Empty栈
  2. 如果栈向高地址方向增长,那么称该栈为Ascending栈;相反,如果向低地址方向增长,那么称该栈为Descending栈

理解技巧:向栈中放数据时,如果可以先放数据再更新栈指针,那么为Empty栈,否则为Full栈,这意味着Full栈和事先寻址对应,Empty和事后寻址对应。

综上,共有FA、FD、EA、ED四种组合,这四种组合和前面的四种寻址方式是一一对应的,它们有如下的对应关系。而且指令中也是可以根据不同的上下文灵活切换使用的。

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值