首页 理论教育 嵌入式系统存储器访问指令

嵌入式系统存储器访问指令

时间:2023-11-23 理论教育 版权反馈
【摘要】:下面详细介绍以上三类存储器访问指令。只要寄存器已被初始化并指向接近所需的存储器地址的某处,这些指令就可提供有效的存储器存取机制。图3.4单字和无符号字节数据存取指令的二进制编码指令构造的地址是基址寄存器加上或减去一个无符号立即数或寄存器偏移量。用法与3.2 节寄存器寻址和数据处理指令中寄存器的移位操作的用法相同。

嵌入式系统存储器访问指令

ARM 处理器是RISC 架构的处理器,它无法像CISC 架构的处理器一样让存储器中的内容直接参与操作运算,而是需要将存储单元中的内容先读取到内部寄存器中,ARM 处理器是加载/存储体系结构的典型RISC 处理器,对存储器的访问只能使用加载、存储和交换指令实现。

因此,ARM 指令集中有三类基本的存储器访问指令:

①单寄存器存取指令(LDR,STR)

单寄存器的存取指令提供ARM 寄存器和存储器间最灵活的单数据项传送方式,存取的数据类型可以是8 位字节、16 位半字或32 位字。

②多寄存器存取指令(LDM,STM)

与单寄存器的存取指令相比,虽然这些指令的灵活性要差一些,但它们可以更有效地用于批量数据的传送。 多寄存器存取指令一般用于进程的进入和退出、堆栈保护和恢复工作寄存器以及拷贝存储器中块数据。

③存储器和寄存器交换指令(SWP)

信号量是最早出现的用来解决进程同步与互斥问题的机制,包括一个称为信号量变量及对它进行的两个原语操作。 通过PV 原语对信号量的操作,可以完成进程间的同步和互斥,对信号量的操作要求在一条指令中完成读取和修改(具体解释请参见相关的专业书籍)。ARM 提供了此指令完成信号量的操作,该指令用于寄存器和存储器中的数据交换,在一个指令中有效地完成存取操作。

下面详细介绍以上三类存储器访问指令。

(1)单寄存器存取指令(LDR,STR)

单寄存器存取指令是ARM 在寄存器和存储器间传送单个字节和字的最灵活方式。 只要寄存器已被初始化并指向接近(通常在4 KB 内)所需的存储器地址的某处,这些指令就可提供有效的存储器存取机制。 它支持几种寻址模式,包括立即数和寄存器偏移、自动变址和相对PC 的寻址。

根据传送数据的类型不同,单个寄存器存取指令又可以分为单字和无符号字节的数据存取指令、半字和有符号字节的数据存取指令两种形式,这两种形式的数据存取指令构成完整的各种数据类型(字、有符号和无符号的半字、有符号和无符号的字节)存取。

1)单字和无符号字节的数据存取指令

LDR 从内存中取32 位字或8 位无符号字节数据放入寄存器,STR 将寄存器中的32 位字或8 位无符号字节数据保存到内存中。 字节传送时是用“0”将8 位的操作数扩展到32 位。

图3.4 中Rn 是基址寄存器,Rd 是源/目的寄存器,offset 是无符号立即数或寄存器偏移量。 P=1,表示使用前变址的寻址模式进行存取操作;P=0,表示使用后变址的寻址模式进行存取操作。 U=1,表示基址寄存器加上偏移量;U =0,表示基址寄存器减去偏移量。B =1,表示传送的是无符号字节;B =0,表示传送的是无符号字。 W =1,表示要求回写,即自动变址。 W=0,表示不要求回写。 L=1,表示从存储器中读取数据;L=0,表示向存储器中写入数据。

图3.4 单字和无符号字节数据存取指令的二进制编码

指令构造的地址是基址寄存器加上或减去一个无符号立即数或寄存器偏移量。 基址或计算出的地址用于从存储器读取一个无符号字节或字,或者向存储器写入一个无符号字节或字。 当一个字节读取到寄存器,需要用“0”将它扩展到32 位。 当一个字节存入到存储器,寄存器的低8 位写到地址指向的位置。

前变址的寻址模式使用计算出的地址作为存储器的地址进行数据存取操作,然后当要求回写时(W=1),将基址寄存器更新为计算出的地址值。

后变址的寻址模式是用未修改的基址寄存器来存取数据,然后将基址寄存器更新为计算出的地址,而不管W 位如何(因为偏移除了作为基址寄存器的修改量之外已没有其他意义,但是,如果希望基址寄存器的值不变化,可将偏移量设置为立即数“0”)。 由于在这种情况下W 位是不使用的,所以它有一个不运行在用户模式的仅在代码上相关的替换功能:设置W=1,使处理器以用户模式访问存储器,这样使操作系统采用用户角度来看待存储器变换和保护方案。

①指令格式

A.前变址的指令格式

B.后变址的指令格式

C.相对PC 的指令格式(汇编器自动计算所需偏移量——立即数)

其中:

a.LDR 指令是“将存储器中的数据读入到寄存器中”,STR 指令是“将寄存器的数据存储到存储器中”。

b.选择项“B”用来控制是传送无符号字节还是字,缺省时B=0,即传送字。

c. <offeset>可能是#± <12 位立即数>或±Rm{ <shift>},其中Rm{ <shift >}用作移位偏移地址的计算,Rm 是第二操作数寄存器,可以对它进行移位或循环移位产生偏移地址。<shift>用来指定移位类型(LSL、LSR、ASL、ASR、ROR 或RRX)和移位位数。 在此和3.2 节的寄存器寻址中已经详细讲述的不同在于,移位位数只能是5 位立即数(#shift),而不存在寄存器(Rs)指定移位位数的形式。 用法与3.2 节寄存器寻址和数据处理指令中寄存器的移位操作的用法相同。

d.在前变址寻址的方式下,“!”的有无来选择是否回写(自动变址)。

e.T 标志位只能在非用户模式(即特权模式)下使用,作用是选择用户角度的存储器变换保护系统。 当在特权级的处理器模式下使用带“T”的指令时,内存系统将该操作当作一般的内存访问操作。

举例如下:

在编程中常使用相对PC 的形式将外设UART 数据读到r0 中:

汇编器将使用前变址的PC 相对寻址模式将地址装入r1。 要做到这一点,字符必须限定在一定的范围(这就是load 指令附近4 KB 范围之内)。

②注意事项

a.使用PC 作为基址时得到的传送地址为当前指令地址加8 字节;PC 不能用作偏移寄存器,也不能用于任何自动变址寻址模式(包括任何后变址模式)。

b.可以把一个字读取到PC 将使程序转移到所读取的地址,从而实现程序跳转,但是应当避免将一字节读取到PC。

c.应尽可能避免将PC 存到存储器的操作,因为在不同体系结构的处理器中,这样的操作会产生不同的结果。

d.只要同一指令中不使用自动变址,则Rd =Rn 是可以的。 但是,在一般情况下,Rd、Rn和Rm 应当是不同的寄存器。

e.当从非字对齐的地址读取一个字时,所读取的数据是包含所寻址字节的字对齐的字。通过循环移位使寻址字节处于目的寄存器最低有效字节。 对于这些情况(由CP15 寄存器1中第一位的A 标志位控制),一些ARM 可能产生异常。

f.当一个字存入到非字对齐的地址时,地址的低两位被忽略,存入这个字时将这两位当作“0”。 对于这些情况(也是由CP15 寄存器1 中的A 标志位控制),一些ARM 系统可能产生异常。

2)半字和有符号字节的数据存取指令

ARM 提供了专门的半字(带符号和无符号)、有符号字节数据存取指令。 LDR 从内存中取半字(带符号和无符号)、有符号字节数据放入寄存器,STR 将寄存器中的半字(带符号和无符号)、有符号字节数据保存到内存中。 有符号字节或有符号半字传送时是用“符号位”扩展到32 位,无符号半字的传送是用“0”扩展到32 位。

这些指令使用的寻址模式是无符号字节和字的指令所用寻址模式的子集。

这些指令与上面的字和无符号字节的指令形式类似,不同之处在于在这些指令中立即数偏移量限定在8 位,寄存器偏移量也不可以经过移位得到。

在图3.5 中,P、U、W 和L 位的作用与单字和无符号字节数据传送指令的二进制编码图中的P、U、W 和L 位的作用相同。 S 和H 位用来定义所传送的操作数的类型,见表3.5。 注意,这些位的第四种组合在这种格式中没有使用,它对应于无符号字节的数据类型。 无符号字节的传送应当使用上面的格式。 因为在存入有符号数据和无符号数据间没有差别,这条指令唯一的相关形式是:读取有符号字节、有符号半字或无符号半字;存入有符号字节、有符号半字或无符号半字;无符号数在读取时,用“0”扩展到32 位;有符号数读取时,则用其符号扩展到32 位。

表3.5 数据类型编码

(www.xing528.com)

图3.5 半字和有符号字节数据存取指令的二进制编码

①指令格式

A.前变址格式

B.后变址格式

式中<offset>是#± <8 位立即数>或#±Rm;H|SH|SB 选择传送数据类型;其他部分的汇编器格式与传送字和无符号字节相同。

举例如下:

②注意事项

a.与前面所讲的字和无符号字节传送指令的情况相同,对使用r15 和寄存器操作数也有一定的限制。

b.所有的半字传送应当使用半字对齐的地址。

(2)多寄存器存取指令(LDM,STM)

当需要存取大量的数据时,希望能同时存取多个寄存器。 多寄存器传送指令,可以用一条指令将16 个可见寄存器(R0 ~R15)的任意子集合(或全部)存储到存储器,或从存储器中读取数据到该寄存器集合中。 此外,这种指令还有两个特殊用法:一是指令的一种形式可以允许操作系统加载或存储用户模式寄存器来恢复或保存用户处理状态;二是它的另一种形式可以作为从异常处理返回的一部分,完成从SPSR 中恢复CPSR。 例如,可以将寄存器列表保存到堆栈,也可以将寄存器列表从堆栈中恢复,这一节中有具体的例子请读者仔细体会。 但是,与单寄存器存取指令相比,多寄存器数据存取可用的寻址模式更加有限。

图3.6 中,指令的二进制编码的低16 位为寄存器列表,每一位对应一个可见寄存器。 例如第0 位控制r0,第1 位控制r1,依次类推。 P、U、W 和L 位的作用与前面单寄存器数据存取指令中的相同。

图3.6 多寄存器存取指令的二进制编码

寄存器从存储器读取连续字或将连续的字块存入到存储器中,可以通过基址寄存器和寻址模式的定义来实现。 在传送每一个字之前或之后,基址将增加或减少。 如果W=1,即支持自动变址,则当指令完成时,基址寄存器将增加或减少所传送的字节数。

S 位(位[22])用于该指令的特殊用法。 如果PC 在读取多寄存器的寄存器列表中且S 位置位,则当前模式的SPSR 将被拷贝到CPSR,成为一个原子的返回和恢复状态的指令。 但是,注意这种形式不能在用户模式的代码中使用,因为在用户模式下没有SPSR。 如果PC 不在寄存器列表中且S 位置位,在非用户模式执行读取和存入多寄存器指令,将传送用户模式下寄存器(虽然使用当前模式的基址寄存器),这使得操作系统可以保存和恢复用户处理状态。

1)指令格式

其中<add mode>指定一种寻址模式,表明地址的变化是操作执行前还是执行后,是在基址的基础上增加还是减少。 “!”表示是自动变址(W =1)。 <registers >是寄存器列表,用大括弧将寄存器组括起来,例如:{r0,r3—r7,pc}。 寄存器列表可以包含16 个可见寄存器(从r0 到r15)的任意集合或全部寄存器。 列表中寄存器的次序是不重要的,它不影响存取的次序和指令执行后寄存器中的值,因为有个约定:编号低的寄存器在存储数据或者是加载数据时对应于存储器的低地址;也就是说,编号最低的寄存器保存到存储器的最低地址或从最低地址取数;其次是其他寄存器按照寄存器编号的次序保存到第一个地址后面的相邻地址或从中取数;但是,一般的习惯是在列表中按递增的次序设定寄存器。 注意,如果在列表中含有r15将引起控制流的变化,因为r15 是PC。

在非用户模式下,而且寄存器列表包含PC 时,CPSR 可以由下式恢复:

在非用户模式下,并且寄存器列表不得包含PC,不允许回写,则用户寄存器可以通过下式保存和恢复:

举例如下:

因为存取数据项总是32 位字,基址地址(r1)应是字对准的。

这类指令的一般特征是:最低的寄存器保存到最低地址或从最低地址取数;其他寄存器按照寄存器号的次序保存到第一个地址后面的相邻地址或从中取数。 然而依第一个地址形成的方式会产生几种变形,而且还可以使用自动变址(也是在基址寄存器后加“!”)。

在进入子程序前,保存三个工作寄存器和返回地址:

STMFD  r13!,{r0—r2,r14}

这里假设r13 已被初始化用作堆栈指针。 恢复工作寄存器和返回:

LDMFD  r13!,{r0—r2,pc}

2)注意事项

①如果在保存多寄存器指令的寄存器列表里指定了PC,保存的值与体系结构实现方式有关。 因此,一般应当避免在STM 指令中指定PC。 (向PC 读取会得到预期的结果,这是从过程返回的标准方法。)

②如果在读取或存入多寄存器指令的传送列表中包含基址寄存器,则在该指令中不能使用回写模式,因为这样做的结果是不可预测的。

③如果基址寄存器包含的地址不是字对齐的,则忽略最低两位。 一些ARM 系统可能产生异常。

④只有在v5T 体系结构中,读取到PC 的最低位才会更新Thumb 位。

(3)单寄存器交换指令(SWP)

交换指令将字或无符号字节的读取和存入组合在一条指令中。 通常都将这两种传送结合成为一个不能被外部存储器的访问(例如,来自DMA 控制器的访问)分隔开的基本的存储器操作,因此,本指令一般用于处理器之间或处理器与DMA 控制器之间共享的信号量、数据结构进行互斥的访问。

图3.7 存储器与寄存器交换指令的二进制编码

如图3.7 所示,本指令将存储器中地址为寄存器Rn 处的字(B=0)或无符号字节(B=1)读入寄存器Rd,又将Rm 中同样类型的数据存入存储器中同样的地址。 Rd 和Rm 可以是同一寄存器,但两者应与Rn 不同。 在这种情况下,寄存器和存储器中的值交换。 ARM 对存储器的读写周期是分开的,但应产生一个“锁”信号向存储器系统指明两个周期不应分离。

1)指令格式

举例如下:

2)注意事项

①PC 不能用作指令中的任何寄存器。

②基址寄存器(Rn)不应和源寄存器(Rm)或目的寄存器(Rd)相同,但是Rd 和Rm 可以相同。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈