|  | 
 
| 11.5  单寄存器数据传送指令 
 Thumb指令集支持寄存器的装载和存储,即LDR和STR指令。8和类型的Load/Store指令在Thumb指令集中可用。这些指令使用两种寻址模式:寄存器偏移和立即数偏移。指令所能存取的数据包括字、半字和字节,同时半字和字节可以为有符号数或无符号数。
 
 表11.4总结了Thumb状态下可用的数据传送指令。
 表11.4 Thumb状态数据传送指令
 
 | 助  记  符 
 | 说    明 
 | 操    作 
 |  | LDR 
 | 传送32位字到寄存器 
 | Rd<- mem32[address] 
 |  | STR 
 | 存储32位寄存器的值 
 | Rd-> mem32[address] 
 |  | LDRB 
 | 传送8位字节到寄存器 
 | Rd<- mem8[address] 
 |  | STRB 
 | 保存寄存器中的字节 
 | Rd-> mem8[address] 
 |  | LDRH 
 | 传送16位半字到寄存器 
 | Rd<- mem16[address] 
 |  | STRH 
 | 保存寄存器中的半字 
 | Rd-> mem16[address] 
 |  | LDRSB 
 | 装载有符号字节到寄存器 
 | Rd<- sighExtend(mem8[address]) 
 |  | STRSB 
 | 装载有符号半字到寄存器 
 | Rd<- sighExtend(mem16[address]) 
 | 
 Thumb数据传送指令的基本语法格式分为以下4种。
 
 ① <opcode1>  <Rd>,[<Rn>,#<5_bit_offset>]
 
 其中,<opcode1>:= LDR|LDRH|LDRB|STR|STRH|STRB
 
 ② <opcode2>  <Rd>,[<Rn>,<Rm>]
 
 其中,<opcode2>:= LDR|LDRH|LDRB|LSRSH|STR|STRH|STRB
 
 ③ LDR  <Rd>,[PC,<8_bit_offset>]
 ④ <opcode3>  <Rd>,[SP,#<8_bit_offset>]
 
 其中,<opcode3>:= LDR|STR
 下面详细介绍各数据传送指令的语法和使用。
 
 11.5.1  寄存器装载指令LDR(1)
 
 (1)编码格式
 寄存器装载指令LDR(1)的编码格式如图11.42所示。
 
 
         图11.42  LDR(1)指令的编码格式 
 这种形式的LDR指令将32位内存数据装载到通用寄存器。常用于结构体的数据访问。域的基地址放在Rn寄存器中。
 
 (2)指令的语法格式
 
 LDR  <Rd>,[<Rn>,#<immed_5>*4]
 
 ① <Rd>
 目的寄存器。用于存放从内存中取出的数据。
 ② <Rn>
 基址寄存器,用于存放所取数据的基地址。
 ③ <immed_5>
 5位立即数。该立即数的4倍加上基址寄存器的值形成目标地址。
 
 (3)指令操作的伪代码
 
 Address = Rn + (immed_5 * 4)
 If  address[1:0] = = 0b00
 Data = Memory[address,4]
 Else
 Data = UNPREDICTABLE
 Rd = data
 
 (4)对应的ARM指令
 
 LDR  <Rd>,[<Rn>,#<immed_5>*4]
 
 
 |   
 | 注意 
 | 如果指令访问地址非字对齐,则指令的执行结果不可预知。 
 | 
 11.5.2  寄存器装载指令LDR(2)
 
 (1)编码格式
 寄存器装载指令LDR(2)的编码格式如图11.43所示。
 
 
         图11.43  LDR(2)指令的编码格式 
 寄存器装载指令LDR(2)允许将一个32位内存数据装载到通用寄存器。此种形式的LDR指令常被用于访问数组中的元素。
 
 (2)指令的语法格式
 
 LDR  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 寄存器存放内存访问基地址。
 ③ <Rm>
 寄存器存放内存访问偏移地址。
 
 (3)指令操作的伪代码
 
 Address = Rn + Rm
 If  address[1:0] = = 0b00
 Data = Memory[address,4]
 Else
 Data = UNPREDICTABLE
 Rd = data
 
 (4)对应的ARM指令
 
 LDR  <Rd>,[<Rn>,<Rm>]
 
 11.5.3  寄存器装载指令LDR(3)
 
 (1)编码格式
 寄存器装载指令LDR(3)的编码格式如图11.44所示。
 
 
         图11.44  LDR(3)指令的编码格式 
 寄存器装载指令LDR(3)允许将一个32位内存数据装载到通用寄存器。此种形式的LDR指令常被用于访问PC相关(PC-relative)数据。
 
 (2)指令的语法格式
 
 LDR  <Rd>,[PC,#<immed_8>*4]
 
 ① <Rd>
 目的寄存器。
 ② PC
 程序指针寄存器,用于计算内存访问的地址。计算地址时,PC值的bit[1]被系统默认为0进行计算,所以产生的内存访问地址必为字对齐。
 ③ <immed_8>
 8位立即数。该立即数的4倍将和PC值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 Address = (PC[31:2] << 2) + (immed_8*4)
 Rd = Memory[address,4]
 
 (4)对应的ARM指令
 
 LDR  <Rd>,[PC,#<immed_8>*4]
 
 11.5.4  寄存器装载指令LDR(4)
 
 (1)编码格式
 寄存器装载指令LDR(4)的编码格式如图11.45所示。
 
 
         图11.45  LDR(4)指令的编码格式 
 寄存器装载指令LDR(4)允许将一个32位内存数据装载到通用寄存器。此种形式的LDR指令常被用于访问堆栈数据。
 
 (2)指令的语法格式
 
 LDR  <Rd>,SP,#<immed_8>*4]
 
 ① <Rd>
 目的寄存器。
 ② SP
 堆栈指针寄存器,用于计算内存访问地址。
 ③ <immed_8>
 8位立即数。该立即数的4倍将和SP值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 Address = SP + (immed_8*4)
 If  address[1:0] = = 0b00
 Data = memory[address,4]
 Else
 Data = UNPREDICTABLE
 Rd = data
 
 (4)对应的ARM指令
 
 LDR  <Rd>,[SP,#<immed_8>*4]
 
 11.5.5  字节加载指令LDRB(1)
 
 (1)编码格式
 字节加载指令LDRB(1)的编码格式如图11.46所示。
 
 
         图11.46  LDRB(1)指令的编码格式 
 LDRB(1)字节数据加载指令用于从内存中将一个8位的字节数据读取到指令中的目标寄存器中,并将寄存器的高24位清零。常用于结构体的数据访问。域的基地址放在Rn寄存器中。
 
 (2)指令的语法格式
 
 LDRB  <Rd>,[<Rn>,#<immed_5>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 指令的基址寄存器。
 ③ <immed_5>
 5位立即数。用于与<Rn>寄存器中的数值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 address = Rn + immed_5
 Rd = memory[address,1]
 
 (4)对应的ARM指令
 
 LDRB  <Rd>,[<Rn>,#<immed_5>]
 
 11.5.6  字节加载指令LDRB(2)
 
 (1)编码格式
 字节加载指令LDRB(2)的编码格式如图11.47所示。
 
 
         图11.47  LDRB(2)指令的编码格式 
 LDRB(2)字节数据加载指令用于从内存中将一个8位的字节数据读取到指令中的目标寄存器中,并将寄存器的高24位清零。此种形式的LDRB(2)指令常用于数组元素的访问。
 
 (2)指令的语法格式
 
 LDRB  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 存放形成内存访问地址的第一个寄存器。
 ③ <Rm>
 存放形成内存访问地址的第二个寄存器。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 Rd = Memory[address,1]
 
 (4)对应的ARM指令
 
 LDRB  <Rd>,[<Rn>,<Rm>]
 
 11.5.7  半字加载指令LDRH(1)
 
 (1)编码格式
 半字数据加载指令LDRH(1)的编码格式如图11.48所示。
 
 
         图11.48  LDRH(1)指令的编码格式 
 LDRH(1)半字数据加载指令用于从内存中将一个16位的半字数据读取到指令中的目标寄存器中,并将寄存器的高16位清零。常用于结构体的数据访问。域的基地址放在Rn寄存器中。
 
 (2)指令的语法格式
 
 LDRH  <Rd>,[<Rn>,#<immed_5>*2]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 指令的基址寄存器。
 ③ <immed_5>
 5位立即数。该寄存器数值的2倍将与<Rn>寄存器中的数值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 address = Rn + (immed_5 *2)
 if  address[0] = = 0
 data = Memory[address,2]
 else
 data = UNPREDICTABLE
 Rd = data
 
 (4)对应的ARM指令
 
 LDRH  <Rd>,[<Rn>,#<immed_5>*2]
 
 11.5.8  半字数据加载指令LDRH(2)
 
 (1)编码格式
 半字数据加载指令LDRH(2)的编码格式如图11.49所示。
 
 LDRH(2)字节数据加载指令用于从内存中将一个16位的半字数据读取到指令中的目标寄存器中,并将寄存器的高16位清零。此种形式的LDRH(2)指令常用于数组元素的访问。
 
 
         图11.49  LDRH(2)指令的编码格式 
 (2)指令的语法格式
 
 LDRB  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 此寄存器存放内存访问基地址。
 ③ <Rm>
 此寄存器存放内存访问偏移地址。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 if  address[0] = = 0
 data = memory[address,2]
 else
 data = UNPREDICTABLE
 Rd = data
 
 (4)对应的ARM指令
 
 LDRH  <Rd>,[<Rn>,<Rm>]
 
 11.5.9  有符号字节数据加载指令LDRSB
 
 (1)编码格式
 有符号字节数据加载指令LDRSB的编码格式如图11.50所示。
 
 
         图11.50  LDRSB指令的编码格式 
 LDRSB指令用于从内存中将一个8位的字节数据读取到指令中的目标寄存器中,并将寄存器的高24位设置成该字节数据的符号位的值(即将该8位字节数据进行符号位扩展,生成32位字数据)。
 
 (2)指令的语法格式
 
 LDRSB  <Rd>,[<Rn>,<Rm>]
 ① <Rd>
 目的寄存器。
 ② <Rn>
 此寄存器存放内存访问基地址。
 ③ <Rm>
 此寄存器存放内存访问偏移地址。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 Rd = SignExtend(Memory[address,1])
 
 (4)对应的ARM指令
 
 LDRSB  <Rd>,[<Rn>,<Rm>]
 
 11.5.10  有符号半字数据加载指令LDRSH
 
 (1)编码格式
 有符号字节数据加载指令LDRSH的编码格式如图11.51所示。
 
 
         图11.51  LDRSH指令的编码格式 
 LDRSH指令用于从内存中将一个16位的半字数据读取到指令中的目标寄存器中,并将寄存器的高16位设置成该半字数据的符号位的值(即将该16位半字数据进行符号位扩展,生成32位字数据)。
 
 (2)指令的语法格式
 
 LDRBH  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 此寄存器存放内存访问基地址。
 ③ <Rm>
 此寄存器存放内存访问偏移地址。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 if  address[0] = = 0
 data = memory[address,2]
 else
 data = UNPREDICTABLE
 Rd = SignExtend[data]
 (4)对应的ARM指令
 
 LDRSH  <Rd>,[<Rn>,<Rm>]
 
 11.5.11  寄存器存储指令STR(1)
 
 (1)编码格式
 寄存器存储指令STR(1)的编码格式如图11.52所示。
 
 
         图11.52  STR(1)指令的编码格式 
 这种形式的STR指令将32位通用寄存器的数值存储到内存中。该指令常用于结构体的数据访问。域的基地址放在Rn寄存器中。
 
 (2)指令的语法格式
 
 STR  <Rd>,[<Rn>,#<immed_5>*4]
 
 ① <Rd>
 目的寄存器。用于存放从内存中取出的数据。
 ② <Rn>
 基址寄存器,用于存放所取数据的基地址。
 ③ <immed_5>
 5位立即数。该立即数的4倍加上基址寄存器的值为目标地址。
 
 (3)指令操作的伪代码
 
 address = Rn + (immed_5*4)
 if  address[1:0] = = 0b00
 Memory[address,4] = Rd
 Else
 Memory[address,4] = UNPREDICTABLE
 
 (4)对应的ARM指令
 
 STR  <Rd>,[<Rn>,#<immed_5>*4]
 
 11.5.12  寄存器存储指令STR(2)
 
 (1)编码格式
 寄存器存储指令STR(2)的编码格式如图11.53所示。
 
 
         图11.53  STR(2)指令的编码格式 
 寄存器装载指令STR(2)将一个32位通用寄存器数据存储到内存单元中。此种形式的STR指令常被用于访问数组中的元素。
 
 (2)指令的语法格式
 
 LDR  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 存放形成内存访问地址的第一个寄存器。
 ③ <Rm>
 存放形成内存访问地址的第二个寄存器。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 if  address[1:0] = = 0b00
 Memory[address,4] = = Rd
 Else
 Memory[address,4] = = UNPREDICTABLE
 
 (4)对应的ARM指令
 
 STR  <Rd>,[<Rn>,<Rm>]
 
 11.5.13  寄存器存储指令STR(3)
 
 (1)编码格式
 寄存器存储指令STR(3)的编码格式如图11.54所示。
 
 
         图11.54  STR(3)指令的编码格式 
 寄存器存储指令STR(3)允许将一个32位通用寄存器的值存储到内存。此种形式的STR指令常被用于访问堆栈数据。
 
 (2)指令的语法格式
 
 STR  <Rd>,[SP,#<immed_8>*4]
 
 ① <Rd>
 目的寄存器。
 ② SP
 堆栈指针寄存器,用于计算内存访问的地址。
 ③ <immed_8>
 8位立即数。该立即数的4倍将和堆栈指针寄存器SP的值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 address = SP + (immed_8 * 4)
 if  address[1:0] = = 0b00
 Memory[address,4] = Rd
 Else
 Memory[address,4] = UNPREDICTABLE
 
 (4)对应的ARM指令
 
 STR  <Rd>,[SP,#<immed_8>*4]
 
 11.5.14  字节存储指令STRB(1)
 
 (1)编码格式
 字节存储加载指令STRB(1)的编码格式如图11.55所示。
 
 
         图11.55  STRB(1)指令的编码格式 
 STRB(1)字节数据存储指令用于将一个8位的字节数据写入到指令中指定的内存单元,该字节数据为指令中存放源操作数寄存器的低8位。常用于结构体的数据访问。域的基地址放在Rn寄存器中。
 
 (2)指令的语法格式
 
 STRB  <Rd>,[<Rn>,#<immed_5>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 指令的基址寄存器。
 ③ <immed_5>
 5位立即数。用于与<Rn>寄存器中的数值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 address = Rn + immed_5
 Memory[address,1] = Rd[7:0]
 
 (4)对应的ARM指令
 
 STRB  <Rd>,[<Rn>,#<immed_5>]
 
 11.5.15  寄存器存储指令STRB(2)
 
 (1)编码格式
 寄存器存储指令STRB(2)的编码格式如图11.56所示。
 
 
         图11.56  STRB(2)指令的编码格式 
 寄存器存储指令STRB(2)用于将一个8位的字节数据写入到指令中指定的内存单元。此种形式的LDRB指令常被用于访问数组中的元素。
 
 (2)指令的语法格式
 
 STRB  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 此寄存器存放内存访问基地址。
 ③ <Rm>
 此寄存器存放内存访问偏移地址。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 Memory[address,1] = Rd[7:0]
 
 (4)对应的ARM指令
 
 STRB  <Rd>,[<Rn>,<Rm>]
 
 11.5.16  半字存储指令STRH(1)
 
 (1)编码格式
 半字存储加载指令STRH(1)的编码格式如图11.57所示。
 
 
         图11.57  STRH(1)指令的编码格式 
 STRH(1)半字数据存储指令用于将一个16位的半字数据写入到指令中指定的内存单元,该半字数据为指令中存放源操作数寄存器的低16位。常用于结构体的数据访问。域的基地址放在Rn寄存器中。
 
 (2)指令的语法格式
 
 STRH  <Rd>,[<Rn>,#<immed_5>*2]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 指令的基址寄存器。
 ③ <immed_5>
 5位立即数。该立即数的2倍与<Rn>寄存器中的数值相加,形成内存访问地址。
 
 (3)指令操作的伪代码
 
 address = Rn + (immed_5*2)
 if  address[1:0] = = 0
 Memory[address,2] = Rd[15:0]
 Else
 Memory[address,2] = UNPREDICTABLE
 
 (4)对应的ARM指令
 
 STRH  <Rd>,[<Rn>,#<immed_5>*2]
 
 11.5.17  寄存器存储指令STRH(2)
 
 (1)编码格式
 寄存器存储指令STRH(2)的编码格式如图11.58所示。
 
   图11.58  STRH(2)指令的编码格式
 
 寄存器存储指令STRH(2)用于将一个8位的半字数据写入到指令中指定的内存单元。此种形式的STRH指令常被用于访问数组中的元素。
 
 (2)指令的语法格式
 
 STRH  <Rd>,[<Rn>,<Rm>]
 
 ① <Rd>
 目的寄存器。
 ② <Rn>
 存放形成内存访问地址的第一个寄存器。
 ③ <Rm>
 存放形成内存访问地址的第二个寄存器。
 
 (3)指令操作的伪代码
 
 address = Rn + Rm
 if  address[1:0] = = 0
 Memory[address,2] = Rd[15:0]
 Else
 Memory[address,2] = UNPREDICTABLE
 (4)对应的ARM指令
 
 STRH  <Rd>,[<Rn>,<Rm>]
 
 11.5.18  数据传送指令举例
 
 下面的例子程序综合使用了各种数据传送指令,通过该例可以对Thumb状态下数据传送指令有更深入的了解。
 
 LDR  r4,[r2,#4] ;将[r2+4]地址单元字数据加载到寄存器r4
 LDR  r4,[r2,r1] ;将[r2+r4]地址单元字数据加载到寄存器r4
 STR  r0,[r7,#0x7c] ;将r0中的字数据存储到[r7+124]的内存地址单元中
 STRB  r1,[r5,#31] ;将r1的低8位数据存储到[r5+31]的内存地址单元中
 STRH  r4,[r2,r3] ;将r4的低16位数据存储到[r2+r3]的内存地址单元中
 LDRH  r3,[r6,r5] ;将[r6+r5]地址单元低16位数据加载到寄存器r3中
 LDRB  r2,[r1,#5] ;将[r1+5]地址单元低8位数据加载到寄存器r2中
 LDR  r6,[PC,#0xFC] ;将[PC+0x3FC]地址单元数据加载到寄存器r6中
 LDR  r5,[SP,#64] ;将[SP+64]地址单元数据加载到寄存器r5中
 STR  r4,[SP,#0x260] ;将寄存器r4中的数据存储到[SP+0x260]内存地址单元中
 | 
 |