嵌入式:Load/Store之单寄存器的存取指令

时间:2022-12-21 14:12:15

ARM处理器是Load/Store型的,即它对数据的操作是通过将数据从存储器加载到片内寄存器中进行处理,处理完成后的结果经过寄存器存回到存储器中,以加快对片外存储器进行数据处理的速度。

ARM的数据存取指令Load/Store是唯一用于寄存器和存储器之间进行数据传送的指令。

在ARM系统中I/O操作是通过存储器映射进行寻址的,对I/O设备的操作可以和对存储器的操作一样,因此,也是使用Load/Store指令完成。

Load/Store指令分类

ARM指令集中有三种基本的数据存取指令:

  • 单寄存器的存取指令(LDR,STR):提供寄存器和存储器之间最灵活的单数据项传送方式,传送的数据可以是8位字节、16位半字或32位字。
  • 多寄存器存取指令(LDM,STM):可有效地用于大批数据的传送。一般这些指令用于进程的进入和退出,保存和恢复工作寄存器以及拷贝存储器中一块数据。
  • 单寄存器交换指令(SWP):用于寄存器和存储器中的数据交换。在一个指令中完成存取操作。该指令常用来完成信号量操作,而信号量是一种解决进程同步和互斥问题的机制。
单寄存器的存取指令

单寄存器存取指令是ARM在寄存器和存储器间传送单个字节和字的最灵活方式。根据传送数据的类型不同,单个寄存器存取指令又可以分为以下两类:

  • 单字和无符号字节的数据传送指令
  • 半字和有符号字节的数据传送指令
1、单字和无符号字节的数据传送指令

这一类数据传送指令的编码格式如下:

嵌入式:Load/Store之单寄存器的存取指令

指令说明

基址寄存器加上或减去一个无符号立即数或者 寄存器偏移量构成存储器访问地址。
当从存储器读取一个无符号字节数据时,需要将它用0扩展到32位,然后放置到目的寄存器中。
当从一个寄存器向存储器写一个字节的数据时,写的是寄存器的低8位。
前变址的寻址模式使用计算出的地址作为存储器地址进行数据存取操作,然后,当要求回写(W=1)(即自动变址方式),将基址寄存器更新为计算出的地址值。
后变址的寻址模式用未修改的基址寄存器来传送数据,然后将基址寄存器更新为计算出的地址,而不管W位如何。

指令汇编格式

前变址格式

LDR|STR {<cond>} {B} Rd, [Rn, <offset>] {!}

​ 其中B表示是按字节传送,缺省时按字传送,offset可能是±12位立即数,或者±Rm{<shift>},这里shift包括移位方式和移位位数,移位位数只能是5位立即数,而不能再来自于寄存器Rs。根据有无{!}选择是否回写(自动变址)。
后变址格式

LDR|STR {<cond>} {B} {T} Rd, [Rn],<offset>

​ 其中T标志只能在非用户模式(即特权模式)下使用,作用是选择用户角度的存储器访问。
相对PC的形式

LDR|STR {<cond>} {B} Rd, LABEL

举例:

LDR  R8,[R10]   ;R8←[R10]
LDRNE R1,[R5,#960]! ;(有条件地)R1←[R5+960],R5 ←R5+960
STR R2,[R9,#consta-struc] ;consta-struc是常量表达式,范围为-4095~4095
STRB R0,[R3,-R8,ASR #2] ;R0→[R3-R8÷4],存储R0的最低有效字节,但R3和R8的内容不变
LDR R1,localdata ;加载一个字,该字位于标号localdata所在地址。(相对PC形式)
LDR R0,[R1],R2,LSL #2 ;将地址为R1的内存单元数据读取到R0中,然后R1←R1+R2*4
LDRB R0,[R2,#3] ;将内存单元(R2+3)中的字节数据读到R0中,R0的高24位被设置为0
LDR R1,[R0,-R2,LSL #2] ;将R0-R2*4地址处的数据读出,保存到R1中,R0,R2的值保持不变。
STR R0,[R7],#-8 ;将R0的内容存到R7中地址对应的内存中,R7←R7-8

在编程中,常使用相对PC的形式将R0中的一个字存到外设UART,如:

LDR    R1,UARTADD
STR R0,[R1]

或者,使用相对PC形式将外设UART数据读到R0 ,如:

LDR    R1,UARTADD
LDR R0,[R1]

注意:

这里UARTADD标号在附近4KB范围之内。

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

把一个字读到PC可以使程序转移到读取的地址,从而实现程序跳转。但应避免将一个字节读取到PC。应尽量避免把PC存储到存储器,因为不同处理器可能会产生不同的结果。

只要不使用自动变址,Rd=Rn是可以的,但在一般情况下,Rd、Rn和Rm应是不同的。

2、半字和有符号字节的数据传送指令

有符号的字节或半字的传送用“符号位”扩展到32位。无符号半字的传送用0扩展到32位。这类数据传送的二进制编码如下:

嵌入式:Load/Store之单寄存器的存取指令

嵌入式:Load/Store之单寄存器的存取指令

立即数偏移量只能8位之内。
寄存器偏移量不可移位得到。
S、H用于定义所传送的数据类型。

S

H

数据类型

1

0

有符号字节

0

1

无符号半字

1

1

有符号半字

指令汇编格式

这一类数据传送指令的汇编格式如下:

前变址格式

LDR|STR{ <cond>} H|SH|SB  Rd,  [Rn, <offest>]{!}

后变址格式

LDR|STR {<cond>} H|SH|SB  Rd,  [Rn], <offest>

式中<offset>是#±<8位立即数>或#±Rm;H|SH|SB选择传送数据类型;其它部分的汇编器格式与传送字和无符号字节相同。所有半字传送应使用半字对齐的地址。

举例:

LDREQSH  R11,[R6];(有条件地) R11←[R6],加载16位半字,有符号扩展到32位
LDRH R1,[R0,#20]! ;R1←[R0+20],加载16位半字,0扩展到32位
STRH R4,[R3,R2] ;R4→[R3+R2],存储最低的有效半字到R3+R2
LDRSB R0,const ;加载位于标号const地址的字节,有符号扩展
LDRH R6,[R2],#2 ;将R2地址上的半字数据读出到R6,高16位用0扩展,R2=R2+2
LDRSH R1,[R9];将R9地址上的半字数据读取到R1中,高16位用符号位扩展
STRNEH R0,[R2,#960] ;(有条件地)将R0的内容送到(R2+960)的内存中,R2=R2+960

参考文献:

孟祥莲.嵌入式系统原理及应用教程(第2版)[M].北京:清华大学出版社,2017.