| 4.2  内存访问指令寻址 
 根据内存访问指令的分类,内存访问指令的寻址方式可以分为以下几种。
 ① 字及无符号字节的Load/Store指令的寻址方式。
 ② 杂类Load/Store指令的寻址方式。
 ③ 批量Load/Store指令的寻址方式。
 ④ 协处理器Load/Store指令的寻址方式。
 
 4.2.1  字及无符号字节的Load/Store指令的寻址方式
 
 字及无符号字节的Load/Store指令语法格式如下:
 
 LDR|STR{<cond>}{B}{T}  <Rd>,<addressing_mode>
 
 其中<addressing_mode>共有9种寻址方式,如表4.2所示。
 表4.2   字及无符合字节的Load/Store指令的寻址方式
 
 | 
 | 格    式 
 | 模    式 
 |  | 1 
 | [Rn,#±<offset_12>] 
 | 立即数偏移寻址 (Immediate offset)
 
 |  | 2 
 | [Rn,±Rm] 
 | 寄存器偏移寻址 (Register offset)
 
 |  | 3 
 | [Rn,Rm,<shift>#< offset_12>] 
 | 带移位的寄存器偏移寻址 (Scaled register offset)
 
 |  | 4 
 | [Rn,#±< offset_12>]! 
 | 立即数前索引寻址 (Immediate pre-indexed)
 
 |  | 5 
 | [Rn,±Rm]! 
 | 寄存器前索引寻址 (Register post-indexed)
 
 |  | 6 
 | [Rn,Rm,<shift>#< offset_12>]! 
 | 带移位的寄存器前索引寻址 (Scaled register pre-indexed)
 
 |  | 7 
 | [Rn],#±< offset_12> 
 | 立即数后索引寻址 (Immediate post-indeded)
 
 |  | 8 
 | [Rn],±<Rm> 
 | 寄存器后索引寻址 (Register post-indexed)
 
 |  | 9 
 | [Rn],±<Rm>,<shift>#< offset_12> 
 | 带移位的寄存器后索引寻址 (Scaled register post-indexed)
 
 | 
 字及无符号字节的Load/Store指令的解码格式如图4.13所示。
 
 
         图4.13  字及无符号字节的Load/Store指令的解码格式 
           编码格式中各位的含义如表4.3所示。
 表4.3           字和无符号半字Load/Store指令编码格式各位含义
 
 | 位  标  识 
 | 取    值 
 | 含    义 
 |  | P 
 | P=0 
 | 使用后索引寻址 
 |  | P=1 
 | 使用偏移地址或前索引寻址(由W位决定) 
 |  | U 
 | U=0 
 | 访问的地址=基址寄存器的值-偏移量(offset) 
 |  | U=1 
 | 访问的地址=基址寄存器的值+偏移量(offset) 
 |  | B 
 | B=0 
 | 字访问Load/Store 
 |  | B=1 
 | 无符号字节访问Load/Store 
 |  | W 
 | W=0 
 | 如果P=0,该指令为LDR、LDRB、STR或STRB指令,且内存访问指令为正常访问指令;如果P=1,指令执行不更新基地址 
 |  | W=1 
 | 如果P=0,该指令为LDRBT、LDRT、STRBT或STRT,且指令为非特权(用户模式)访问指令;如果P=1,计算内存地址并更新基地址 
 |  | L 
 | L=0 
 | Store指令 
 |  | L=1 
 | Load指令 
 | 
 1.[Rn,#±<offset_12>]
 
 (1)编码格式
 指令的编码格式如图4.14所示。
 
 
         图4.14  内存访问指令——立即数偏移寻址编码格式 
 内存访问地址为基址寄存器Rn的值加(或减)立即数offset_12。
 
 编程中,在访问结构体或记录(record)类型的变量时,这些内存的操作指令是十分有效的。另外,在子程序中也常用这些指令访问本地变量和堆栈。
 
 (2)语法格式
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,#±<offset_12>]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <offset_12>为12位立即数,内存访问地址偏移量。
 
 (3)操作伪代码
 
 If  U = = 1  then
 Address = Rn + offset_12
 Else
 Address = Rn – offset_12
 
 (4)说明
 ① 如果指令中没有指定立即数,使用[<Rn>],编译器按[<Rn>,#0]形式编码。
 ② 如果Rn被指定为程序计数器r15,其值为当前指令地址加8。
 
 2.[Rn,±Rm]
 
 (1)编码格式
 指令的编码格式如图4.15所示。
 
 
         图4.15  内存访问指令——寄存器偏移寻址编码格式 
 内存访问地址为基址寄存器Rn的值加(或减)偏移寄存器Rm的值。
 该寻址方式适合使用指针访问字节数组中的数据成员。
 
 (2)语法格式
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量。
 
 (3)操作伪代码
 
 If  U = = 1  then
 Address = Rn + Rm
 Else
 Address = Rn – Rm
 
 (4)说明
 如果Rn被指定为程序计数器r15,其值为当前指令地址加8;如果r15被用作偏移地址寄存器Rm的值,指令的执行结果不可预知。
 
 3.[Rn,Rm,<shift>#< offset_12>]
 
 (1)编码格式
 指令的编码格式如图4.16所示。
 
 
         图4.16  内存访问指令——带移位的寄存器偏移寻址编码格式 
 内存地址为Rn的值加/减通过移位操作后的Rm的值。
 当数组中的成员长度大于1个字节时,使用该寻址方式可高效率地访问数组成员。
 
 (2)语法格式
 语法格式有以下5种。
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,LSL #< offset_12>]
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,LSR #< offset_12>]
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,ASR #< offset_12>]
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,ROR #< offset_12>]
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,RRX]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量;
 ·  LSL表示逻辑左移操作;
 ·  LSR表示逻辑右移操作;
 ·  ASR表示算术右移操作;
 ·  ROR表示循环右移操作;
 ·  RRX表示扩展的循环右移。
 ·  <shift_imm>为移位立即数。
 
 (3)操作伪代码
 
 Case  shift  of
 0b00  /*LSL*/
 Index = Rm logic_shift_left  shift_imm
 0b01  /*LSR*/
 If  shift_imm = = 0  then /*LSR  #32*/
 Index = 0
 Else
 Index = Rm logical_shift_right  shift_imm
 0b10  /*ASR*/
 If  shift_imm = = 0 then /*ASR  #32*/
 If  Rm[31] = = 1 then
 Index = 0xffffffff
 Else
 Index = 0
 Else
 Index = Rm  Arithmetic_shift_Right  shift_imm
 0b11  /* ROR or RRX*/
 If  shift_imm = = 0 then /*RRX*/
 Index = (C flag Logical_shift_left 31) OR
 (Rm logical_shift_Right 1)
 Else /*ROR*/
 Index = Rm Rotate_Right shift_imm
 Endcase
 If  U = = 1 then
 Address = Rn + index
 Else /*U = = 0*/
 Address = Rn – index
 
 (4)说明
 如果Rn被指定为程序计数器r15,其值为当前指令地址加8;如果r15被用作偏移地址寄存器Rm的值,指令的执行结果不可预知。
 
 4.[Rn,#±< offset_12>]!
 
 (1)编码格式
 指令的编码格式如图4.17所示。
 
 
         图4.17  内存访问指令——前索引立即数偏移寻址编码格式 
 内存地址为基址寄存器Rn加/减立即数offset_8的值。当指令执行的条件<cc>满足时,生成的地址写回基址寄存器Rn中。
 该寻址方式适合访问数组自动进行数组下标的更新。
 
 (2)语法格式
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<offset_12>] !
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <offset_12>为12位立即数,内存访问地址偏移量;
 ·  !设置指令编码中的W位,更新指令基址寄存器。
 
 (3)操作伪代码
 
 If  U == 1  then
 Address = Rn + offset_12
 Else
 Address = Rn – offset_12
 If  ConditionPassed{cond}  then
 Rn = address
 
 (4)说明
 ① 如果指令中没有指定立即数,使用[<Rn>],编译器按[<Rn>,#0] ! 形式编码。
 ② 如果Rn被指定为程序计数器r15,指令的执行结果不可预知。
 
 5.[Rn,±Rm]!
 
 (1)编码格式
 指令的编码格式如图4.18所示。
 
 
         图4.18  内存访问指令——前索引寄存器偏移寻址编码格式 
 内存访问地址为基址寄存器Rn的值加(或减)偏移寄存器Rm的值。当指令的执行条件<cc>满足时,生成地地址将写回基址寄存器。
 
 (2)语法格式
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量;
 ·  !设置指令编码中的W位,更新指令基址寄存器。
 
 (3)操作伪代码
 
 If  U = = 1  then
 Address = Rn + Rm
 Else
 Address = Rn – Rm
 If  ConditionPassed{cond}  then
 Rn = address
 
 (4)说明
 如果Rn和Rm指定为同一寄存器,指令的执行结果不可预知。
 
 6.[Rn,±Rm,<shift>#< offset_12>]!
 
 (1)编码格式
 指令的编码格式如图4.19所示。
 
 
         图4.19  内存访问指令——带移位的前索引寄存器偏移寻址编码格式 
 内存地址为Rn的值加/减通过移位操作后的Rm的值。当指令的执行条件<cc>满足时,生成地地址将写回基址寄存器。
 
 (2)语法格式
 语法格式有以下5种。
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,LSL #< offset_12>] !
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,LSR #< offset_12>] !
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,ASR #< offset_12>] !
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,ROR #< offset_12>] !
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>,±<Rm>,RRX] !
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量;
 ·  LSL表示逻辑左移操作;
 ·  LSR表示逻辑右移操作;
 ·  ASR表示算术右移操作;
 ·  ROR表示循环右移操作;
 ·  RRX表示扩展的循环右移。
 ·  <shift_imm>为移位立即数。
 ·  !设置指令编码中的W位,更新指令基址寄存器。
 
 (3)操作伪代码
 
 Case  shift  of
 0b00  /*LSL*/
 Index = Rm logic_shift_left  shift_imm
 0b01  /*LSR*/
 If  shift_imm = = 0  then /*LSR  #32*/
 Index = 0
 Else
 Index = Rm logical_shift_right  shift_imm
 0b10  /*ASR*/
 If  shift_imm = = 0 then /*ASR  #32*/
 If  Rm[31] = = 1 then
 Index = 0xffffffff
 Else
 Index = 0
 Else
 Index = Rm  Arithmetic_shift_Right  shift_imm
 0b11  /* ROR or RRX*/
 If  shift_imm = = 0 then /*RRX*/
 Index = (C flag Logical_shift_left 31) OR
 (Rm logical_shift_Right 1)
 Else /*ROR*/
 Index = Rm Rotate_Right shift_imm
 Endcase
 If  U = = 1 then
 Address = Rn + index
 Else /*U = = 0*/
 Address = Rn – index
 If  ConditionPassed{cond}  then
 Rn = address
 (4)说明
 ① 当PC用作基址寄存器Rn或Rm时,指令执行结果不可预知。
 ② 当Rn和Rm是同一个寄存器时,指令的执行结果不可预知。
 
 7.[Rn],#±< offset_12>
 
 (1)编码格式
 指令的编码格式如图4.20所示。
 
 
         图4.20  内存访问指令——后索引立即数偏移寻址编码格式 
 指令使用基址寄存器Rn的值作为实际内存访问地址。当指令的执行条件满足时,将基址寄存器的值加/减偏移量产生新的地址值回写到Rn寄存器中。
 
 (2)语法格式
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>],±<offset_12>
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <offset_12>为12位立即数,内存访问地址偏移量。
 
 (3)操作伪代码
 
 Address = Rn
 If  conditionPassed{cond}  then
 If  U = = 1 then
 Rn = Rn + offset_12
 Else
 Rn = Rn – offset_12
 
 (4)说明
 ① LDRBT、LDRT、STRBT和STRT指令只支持后索引寻址。
 ② 如果Rn被指定为程序计数器r15,指令的执行结果不可预知。
 
 8.[Rn],±<Rm>
 
 (1)编码格式
 指令的编码格式如图4.21所示。
 
 
         图4.21  内存访问指令——后索引寄存器偏移寻址编码格式 
 指令访问地址为实际的基址寄存器的值。当指令的执行条件满足时,将基址寄存器的值加/减索引寄存器Rm的值回写到Rn基址寄存器。
 (2)语法格式
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[Rn],±<Rm>
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量。
 (3)操作伪代码
 
 Address = Rn
 If  conditionPassed{cond}  then
 If  U = = 1  then
 Rn = Rn + Rm
 Else
 Rn = Rn – Rm
 
 (4)说明
 ① LDRBT、LDRT、STRBT和STRT指令只支持后索引寻址。
 ② 如果Rm和Rn指定为同一寄存器,指令的执行结果不可预知。
 
 9.[Rn],±Rm,<shift>#< offset_12>]
 
 (1)编码格式
 指令的编码格式如图4.22所示。
 
 
         图4.22  内存访问指令——带移位的后索引寄存器偏移寻址编码格式 
 实际的内存访问地址为寄存器Rn的值。当指令的执行条件满足时,将基址寄存器值加/减一个地址偏移量产生新的地址值。
 
 (2)语法格式
 语法格式有以下5种。
 
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>],±<Rm>,LSL #< offset_12>
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>],±<Rm>,LSR #< offset_12>
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>],±<Rm>,ASR #< offset_12>
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>],±<Rm>,ROR #< offset_12>
 LDR|STR{<cond>}{B}{T}  <Rd>,[<Rn>],±<Rm>,RRX
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量;
 ·  LSL表示逻辑左移操作;
 ·  LSR表示逻辑右移操作;
 ·  ASR表示算术右移操作;
 ·  ROR表示循环右移操作;
 ·  RRX表示扩展的循环右移。
 ·  <shift_imm>为移位立即数。
 
 (3)操作伪代码
 
 Address = Rn
 Case  shift  of
 0b00  /*LSL*/
 Index = Rm logic_shift_left  shift_imm
 0b01  /*LSR*/
 If  shift_imm = = 0  then /*LSR  #32*/
 Index = 0
 Else
 Index = Rm logical_shift_right  shift_imm
 0b10  /*ASR*/
 If  shift_imm = = 0 then /*ASR  #32*/
 If  Rm[31] = = 1 then
 Index = 0xffffffff
 Else
 Index = 0
 Else
 Index = Rm  Arithmetic_shift_Right  shift_imm
 0b11  /* ROR or RRX*/
 If  shift_imm = = 0 then /*RRX*/
 Index = (C flag Logical_shift_left 31) OR
 (Rm logical_shift_Right 1)
 Else /*ROR*/
 Index = Rm Rotate_Right shift_imm
 Endcase
 If  ConditionPassed{cond}  then
 If  U = = 1 then
 Rn = Rn + index
 Else /*U = = 0*/
 Rn = Rn – index
 
 (4)说明
 ① LDRBT、LDRT、STRBT和STRT指令只支持后索引寻址。
 ② 当PC用作基址寄存器Rn或Rm时,指令执行结果不可预知。
 ③ 当Rn和Rm是同一个寄存器时,指令的执行结果不可预知。
 
 4.2.2  杂类Load/Store指令的寻址方式
 
 使用该类寻址方式的指令的语法格式如下。
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,<addressing_mode>
 
 使用该类寻址方式的指令包括:(有符号/无符号)半字Load/Store指令、有符号字节Load/Store指令和双字Load/Store指令。
 
 该类寻址方式分为6种类型,如表4.4所示。
 表4.4   杂类Load/Store指令的寻址方式
 
 | 
 | 格    式 
 | 模    式 
 |  | 1 
 | [Rn,#±<offset_8>] 
 | 立即数偏移寻址 (Immediate offset)
 
 |  | 2 
 | [Rn,±Rm] 
 | 寄存器偏移寻址 (Register offset)
 
 |  | 3 
 | [Rn,#±< offset_8>]! 
 | 立即数前索引寻址 (Immediate pre-indexed)
 
 |  | 4 
 | [Rn,±Rm]! 
 | 寄存器前索引寻址 (Register post-indexed)
 
 |  | 5 
 | [Rn],#±< offset_8> 
 | 立即数后索引寻址 (Immediate post-indeded)
 
 |  | 6 
 | [Rn],±<Rm> 
 | 寄存器后索引寻址 (Register post-indexed)
 
 | 
 杂类Load/Store指令的解码格式如图4.23所示。
 
 
         图4.23  杂类Load/Store指令解码格式 
 编码格式中各标志位的含义如表4.5所示。
 表4.5        杂类Load/Store指令编码格式各标志位含义
 
 | 位  标  识 
 | 取    值 
 | 含    义 
 |  | P 
 | P=0 
 | 使用后索引寻址 
 |  | P=1 
 | 使用偏移地址或前索引寻址(由W位决定) 
 | 
         续表 
 | 位  标  识 
 | 取    值 
 | 含    义 
 |  | U 
 | U=0 
 | 访问的地址=基址寄存器的值-偏移量(offset) 
 |  | U=1 
 | 访问的地址=基址寄存器的值+偏移量(offset) 
 |  | W 
 | W=0 
 | 如果P=0,使用后索引寻址;P=1,指令不改变基址寄存器的值 
 |  | W=1 
 | 如果P=0,未定义指令;如果P=1,将计算的内存访问地址回写到基址寄存器 
 |  | L 
 | L=0 
 | Store指令 
 |  | L=1 
 | Load指令 
 |  | S 
 | S=0 
 | 无符号半字内存访问 
 |  | S=1 
 | 有符号半字内存访问 
 |  | H 
 | H=0 
 | 字节访问 
 |  | H=1 
 | 半字访问 
 | 
 
 |   
 | 注意 
 | 当S=0并且H=0时,并非无符号的字节内存访问指令。无符号的内存访问指令不使用该种寻址方式,详见本章上一节。 当S=1并且L=0时,并非是有符号的存储指令,而是未定义指令。ARM指令并未区分有符号和无符号的字节和半字存储。
 
 | 
 1.[Rn,#±<offset_8>]
 
 (1)编码格式
 指令的编码格式如图4.24所示。
 
 
         图4.24  杂项内存访问指令——立即数偏移寻址编码格式 
 内存访问地址为基址寄存器Rn的值加(或减)立即数offset_8。
 编程中,在访问结构体或记录(record)类型的变量时,这些内存的操作指令是十分有效的。另外,在子程序中,也常用这些指令访问本地变量和堆栈。当offset_8=0时,内存访问地址即基址寄存器Rn的值。
 
 (2)语法格式
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,[<Rn>,#±<offset_12>]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址。
 ·  <offset_8>为8位立即数,内存访问地址偏移量。
 
 (3)操作伪代码
 
 offset_8 = (immedH << 4) OR immedL
 If  U = = 1  then
 Address = Rn + offset_8
 Else
 Address = Rn – offset_8
 
 (4)说明
 ① 如果指令中没有指定立即数,使用[<Rn>],编译器按[<Rn>,#0]形式编码。
 ② 如果Rn被指定为程序计数器r15,其值为当前指令地址加8。
 
 2.[Rn,±Rm]
 
 (1)编码格式
 指令的编码格式如图4.25所示。
 
 
         图4.25  杂项内存访问指令——寄存器偏移寻址编码格式 
 内存访问地址为基址寄存器Rn的值加(或减)偏移寄存器Rm的值。
 该寻址方式适合使用指针访问数组中的单个数据成员。
 
 (2)语法格式
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,[<Rn>,±<Rm>]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量。
 
 (3)操作伪代码
 
 If  U = = 1  then
 Address = Rn + Rm
 Else
 Address = Rn – Rm
 
 (4)说明
 如果Rn被指定为程序计数器r15,其值为当前指令地址加8;如果r15被用作偏移地址寄存器Rm的值,指令的执行结果不可预知。
 
 3.[Rn,#±< offset_8>]!
 
 (1)编码格式
 指令的编码格式如图4.26所示。
 
 
         图4.26  杂类内存访问指令——前索引立即数偏移寻址编码格式 
 内存地址为基址寄存器Rn加/减立即数offset_8的值。当指令执行的条件<cc>满足时,生成的地址写回基址寄存器Rn中。
 
 该寻址方式适合访问数组自动进行数组下标的更新。
 
 (2)语法格式
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,[<Rn>,±<offset_8>] !
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <offset_8>为8位立即数,内存访问地址偏移量,在指令编码格式中被拆为immedH和immedL两部分;
 ·  !设置指令编码中的W位,更新指令基址寄存器。
 
 (3)操作伪代码
 
 offset_8 = (immedH) << 4 OR immedL
 If  U == 1  then
 Address = Rn + offset_8
 Else
 Address = Rn – offset_8
 If  ConditionPassed{cond}  then
 Rn = address
 
 (4)说明
 ① 如果指令中没有指定立即数,使用[<Rn>],编译器按[<Rn>,#0] ! 形式编码。
 ② 如果Rn被指定为程序计数器r15,指令的执行结果不可预知。
 
 4.[Rn,±Rm] !
 
 (1)编码格式
 指令的编码格式如图4.27所示。
 
 
         图4.27  杂项内存访问指令——前索引寄存器偏移寻址编码格式 
 内存访问地址为基址寄存器Rn的值加(或减)偏移寄存器Rm的值。当指令的执行条件<cc>满足时,生成地地址将写回基址寄存器。
 
 (2)语法格式
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,[<Rn>,±<Rm>]
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量;
 ·  !设置指令编码中的W位,更新指令基址寄存器。
 
 (3)操作伪代码
 
 If  U = = 1  then
 Address = Rn + Rm
 Else
 Address = Rn – Rm
 If  ConditionPassed{cond}  then
 Rn = address
 
 (4)说明
 ① 如果Rn和Rm指定为同一寄存器,指令的执行结果不可预知。
 ② 如果程序计数器r15被用作Rm或Rn,则指令的执行结果不可预知。
 
 5.[Rn],#±< offset_8>
 
 (1)编码格式
 指令的编码格式如图4.28所示。
 
 
         图4.28  杂项内存访问指令——后索引立即数偏移寻址编码格式 
 指令使用基址寄存器Rn的值作为实际内存访问地址。当指令的执行条件满足时,将基址寄存器的值加/减偏移量生产新的地址值回写到Rn寄存器中。
 
 (2)语法格式
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,[<Rn>],±<offset_8>
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <offset_8>为8位立即数,内存访问地址偏移量。
 
 (3)操作伪代码
 
 Address = Rn
 Offset_8 = (immedH << 4) OR immedL
 If  conditionPassed{cond}  then
 If  U = = 1 then
 Rn = Rn + offset_8
 Else
 Rn = Rn – offset_8
 
 (4)说明
 ① 当指令中没有指定立即数时,汇编器按“[<Rn>],#0”编码。
 ② 如果Rn被指定为程序计数器r15,指令的执行结果不可预知。
 
 6.[Rn],±<Rm>
 
 (1)编码格式
 指令的编码格式如图4.29所示。
 
 
         图4.29  杂项内存访问指令——后索引寄存器偏移寻址编码格式 
 指令访问地址为实际的基址寄存器的值。当指令的执行条件满足时,将基址寄存器的值加/减索引寄存器Rm的值回写到Rn基址寄存器。
 
 (2)语法格式
 
 LDR|STR{<cond>}H|SH|SB|D  <Rd>,[Rn],±<Rm>
 
 其中:
 ·  Rn为基址寄存器,该寄存器包含内存访问的基地址;
 ·  <Rm>为偏移地址寄存器,包含内存访问地址偏移量。
 
 (3)操作伪代码
 
 Address = Rn
 If  conditionPassed{cond}  then
 If  U = = 1  then
 Rn = Rn + Rm
 Else
 Rn = Rn – Rm
 
 (4)说明
 ① 程序寄存器r15被指定为Rm或Rn,指令的执行结果不可预知。
 ② 如果Rm和Rn指定为同一寄存器,指令的执行结果不可预知。
 
 4.2.3  批量Load/Store指令寻址方式
 
 批量Load/Store指令将一片连续内存单元的数据加载到通用寄存器组中或将一组通用寄存器的数据存储到内存单元中。
 
 批量Load/Store指令的寻址模式产生一个内存单元的地址范围,指令寄存器和内存单元的对应关系满足这样的规则,即编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中的高地址单元。
 
 指令的语法格式如下。
 
 LDM|STM{<cond>}<addressing_mode>  <Rn>{!},<registers><^>
 
 指令的寻址方式如表4.6所示。
 表4.6      批量Load/Store指令的寻址方式
 
 | 
 | 格    式 
 | 模    式 
 |  | 1 
 | IA(Increment After) 
 | 后递增方式 
 |  | 2 
 | IB(Increment Before) 
 | 先递增方式 
 |  | 3 
 | DA(Decrement After) 
 | 后递减方式 
 |  | 4 
 | DB(Decrement Before) 
 | 先递减方式 
 | 
 指令的编码格式如图4.30所示。
 
 
         图4.30  批量Load/Store指令编码格式 
 编码格式中各标志位的含义如表4.7所示。
 表4.7        批量Load/Store指令编码格式各标志位含义
 
 | 位标识 
 | 取    值 
 | 含    义 
 |  | P 
 | P=0 
 | Rn包含的地址,是所要访问的内存块的高地址(U=0)还是低地址(U=1) 
 |  | P=1 
 | 标识Rn所指向的内存单元是否被访问 
 |  | U 
 | U=0 
 | Rn所指内存单元为所要访问的内存单元块的高地址 
 |  | U=1 
 | Rn所指内存单元为所要访问的内存单元块的低地址 
 |  | S 
 | S=0 
 | 当程序计数器PC作为要加载的寄存器之一时,S标识是否将spsr内容拷贝到cpsr;对于不加载PC的load指令和所有store指令,S标识特权模式下,使用用户模式寄存器组代替当前模式下寄存器组 
 |  | S=1 
 |  | W 
 | W=0 
 | 数据传送完毕,更新地址寄存器内容 
 |  | W=1 
 |  | L 
 | L=0 
 | Store指令 
 |  | L=1 
 | Load指令 
 | 
 1.IA寻址
 
 (1)编码格式
 指令的编码格式如图4.31所示。
 
 该寻址方式指定一片连续的内存地址空间,地址空间的大小<address_length>等于寄存器列表中寄存器数目的4倍。内存地址范围起始地址<start_address>等于基址寄存器Rn的值。结束地址<end_address>等于起始地址<start_address>加上地址空间大小<address_length>。
 
 
 
         图4.31  批量Load/Store指令——后增加寻址 
 地址空间中的每个内存单元对应寄存器列表中的一个寄存器。编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中的高地址单元。
 
 当指令执行条件满足并且指令编码格式中W位置位,基址寄存器Rn的值等于内存地址范围结束地址<end_address>加4。
 
 (2)语法格式
 
 LDM|STM{<cond>}IA  <Rn>{!},<registers><^>
 
 其中:
 ·  IA标识指令使用“后增加”寻址方式;
 ·  Rn为基址寄存器,包含内存访问的基地址;
 ·  <registers>为指令操作的寄存器列表;
 ·  <^>表示如果寄存器列表中包含程序计数器PC,是否将spsr拷贝到cpsr。
 
 (3)操作伪代码
 
 Start_address = Rn
 End_address = Rn + (Number_of_Set_Bits_In(register_list)*4) – 4
 If  conditionPassed(cond) and W = = 1 then
 Rn = Rn + (Number_of_Set_Bits_In(register_list)*4)
 
 2.DA寻址
 
 (1)编码格式
 
 指令的编码格式如图4.32所示。
 
 
         图4.32  批量Load/Store指令——后递减寻址 
 该寻址方式指定一片连续的内存地址空间,地址空间的大小<address_length>等于寄存器列表中寄存器数目的4倍。内存地址范围起始地址<start_address>等于基址寄存器Rn的值减去地址空间大小<address_length>并加4。结束地址<end_address>等于基址寄存器的值。
 
 地址空间中的每个内存单元对应寄存器列表中的一个寄存器。编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中的高地址单元。
 
 当指令执行条件满足并且指令编码格式中W位置位时,基址寄存器Rn的值等于内存地址范围起始地址<start_address>减4。
 
 (2)语法格式
 
 LDM|STM{<cond>}IA  <Rn>{!},<registers><^>
 
 其中:
 ·  DA标识指令使用“后递减”寻址方式;
 ·  Rn为基址寄存器,包含内存访问的基地址;
 ·  <registers>为指令操作的寄存器列表;
 ·  <^>表示如果寄存器列表中包含程序计数器PC,是否将spsr拷贝到cpsr。
 
 (3)操作伪代码
 
 Start_address = Rn – (Number_of_Set_Bits_In(register_list)*4) + 4
 End_address = Rn
 If  conditionPassed(cond) and W = = 1 then
 Rn = Rn - (Number_of_Set_Bits_In(register_list)*4)
 
 3.IB寻址
 
 (1)编码格式
 
 指令的编码格式如图4.33所示。
 
 
         图4.33  批量Load/Store指令——前增加寻址 
 该寻址方式指定一片连续的内存地址空间,地址空间的大小<address_length>等于寄存器列表中寄存器数目的4倍。内存地址范围起始地址<start_address>等于基址寄存器Rn的值加4。结束地址<end_address>等于起始地址<start_address>加上地址空间大小<address_length>。
 
 地址空间中的每个内存单元对应寄存器列表中的一个寄存器。编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中的高地址单元。
 
 当指令执行条件满足并且指令编码格式中W位置位,基址寄存器Rn的值等于内存地址范围结束地址<end_address>。
 
 (2)语法格式
 
 LDM|STM{<cond>}IB  <Rn>{!},<registers><^>
 
 其中:
 ·  IB标识指令使用“前增加”寻址方式;
 ·  Rn为基址寄存器,包含内存访问的基地址;
 ·  <registers>为指令操作的寄存器列表;
 ·  <^>表示如果寄存器列表中包含程序计数器PC,是否将spsr拷贝到cpsr。
 
 (3)操作伪代码
 
 Start_address = Rn + 4
 End_address = Rn + (Number_of_Set_Bits_In(register_list)*4)
 If  ConditionPassed(cond) and W= = 1  then
 Rn = Rn + (Number_Of_Set_Bits_In(register_list)*4)
 
 4.DB寻址
 
 (1)编码格式
 
 指令的编码格式如图4.34所示。
 
 
         图4.34  批量Load/Store指令——前递减寻址 
 该寻址方式指定一片连续的内存地址空间,地址空间的大小<address_length>等于寄存器列表中寄存器数目的4倍。内存地址范围起始地址<start_address>等于基址寄存器Rn的值减地址空间的大小<address_length>。结束地址<end_address>等于基址寄存器的值减4。
 
 地址空间中的每个内存单元对应寄存器列表中的一个寄存器。编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中的高地址单元。
 
 当指令执行条件满足并且指令编码格式中W位置位,基址寄存器Rn的值等于内存地址范围起始地址<address_address>。
 
 (2)语法格式
 
 LDM|STM{<cond>}DB  <Rn>{!},<registers><^>
 
 其中:
 ·  DB标识指令使用“前递减”寻址方式;
 ·  Rn为基址寄存器,包含内存访问的基地址;
 ·  <registers>为指令操作的寄存器列表;
 ·  <^>表示如果寄存器列表中包含程序计数器PC,是否将spsr拷贝到cpsr。
 
 (3)操作伪代码
 
 Start_address = Rn - (Number_Of_Set_Bits_In(register_list)*4)
 End_address = Rn - 4
 If  ConditionPassed(cond) and W = = 1  then
 Rn = Rn – (Number_Of_Set_Bits_In(register_list)*4)
 
 4.2.4  堆栈操作寻址方式
 
 堆栈操作寻址方式和批量Load/Store指令寻址方式十分类似。但对于堆栈的操作,数据写入内存和从内存中读出要使用不同的寻址模式,因为进栈操作(pop)和出栈操作(push)要在不同的方向上调整堆栈。
 
 下面详细讨论如何使用合适的寻址方式实现数据的堆栈操作。
 
 根据不同的寻址方式,将堆栈分为以下4种。
 ① Full栈:堆栈指针指向栈顶元素(last used location)。
 ② Empty栈:堆栈指针指向第一个可用元素(the first unused location)。
 ③ 递减栈:堆栈向内存地址减小的方向生长。
 ④ 递增栈:堆栈向内存地址增加的方向生长。
 
 根据堆栈的不同种类,将其寻址方式分为以下4种。
 ① 满递减FD(Full Descending)。
 ② 空递减ED(Empty Descending)。
 ③ 满递增FA(Full Ascending)。
 ④ 空递增EA(Empty Ascending)。
 
 
 | ![]() 
 | 注意 
 | 如果程序中有对协处理器数据的进栈/出栈操作,最好使用FD或EA类型堆栈。这样可以使用一条STC或LDC指令将数据进栈或出栈。 
 | 
 表4.8显示了堆栈的寻址方式和批量Load/Store指令寻址方式的对应关系。
 表4.8     堆栈寻址方式和批量Load/Store指令寻址方式对应关系
 
 | 批量数据寻址方式 
 | 堆栈寻址方式 
 | L位 
 | P位 
 | U位 
 |  | LDMDA 
 | LDMFA 
 | 1 
 | 0 
 | 0 
 |  | LDMIA 
 | LDMFD 
 | 1 
 | 0 
 | 1 
 |  | LDMDB 
 | LDMEA 
 | 1 
 | 1 
 | 0 
 |  | LDMIB 
 | LDMED 
 | 1 
 | 1 
 | 1 
 |  | STMDA 
 | STMED 
 | 0 
 | 0 
 | 0 
 |  | STMIA 
 | STMEA 
 | 0 
 | 0 
 | 1 
 |  | STMDB 
 | STMFD 
 | 0 
 | 1 
 | 0 
 |  | STMIB 
 | STMFA 
 | 0 
 | 1 
 | 1 
 | 
 4.2.5  协处理器Load/Store寻址方式
 
 协处理器Load/Store指令的语法格式如下。
 
 <opcode>{<cond>}{L}  <coproc>,<CRd>,<addressing_mode>
 
 表4.9显示了该类指令的寻址方式。
 表4.9   协处理器Load/Store指令寻址方式
 
 | 
 | 格    式 
 | 说    明 
 |  | 1 
 | [<Rn>,#±<offset_8>*4] 
 | 立即数偏移寻址 
 |  | 2 
 | [<Rn>,#±<offset_8>*4]! 
 | 前索引立即数偏移寻址 
 |  | 3 
 | [<Rn>],#±<offset_8>*4 
 | 后索引立即数偏移寻址 
 |  | 4 
 | [<Rn>], <option> 
 | 直接寻址 
 | 
 协处理器Load/Store指令的编码方式如图4.35所示。
 编码格式中各标志位的含义如表4.10所示。
 
 
         图4.35  协处理器Load/Store指令编码格式 
 表4.10     协处理器Load/Store指令编码格式各标志位含义
 
 | 位  标  识 
 | 取    值 
 | 含    义 
 |  | P 
 | P=0 
 | 标识使用偏移寻址还是前索引寻址(由W位决定) 
 |  | P=1 
 | 标识使用后索引寻址还是直接寻址(由W位决定) 
 |  | U 
 | U=0 
 | 从基地址中减去偏移量offset 
 |  | U=1 
 | 从基地址中加上偏移量offset 
 |  | N 
 | N=0 
 | 和具体使用的协处理器相关 
 |  | N=1 
 |  | W 
 | W=0 
 | 指令执行结束,不改变基址寄存器的值 
 |  | W=1 
 | 访问的内存地址回写到基址寄存器 
 |  | L 
 | L=0 
 | Store指令 
 |  | L=1 
 | Load指令 
 | 
 1.[<Rn>,#±<offset_8>*4]
 
 (1)编码格式
 指令的编码格式如图4.36所示。
 
 
         图4.36  协处理器Load/Store指令——立即数寻址 
 该寻址方式指定一片连续的内存地址空间。访问内存单元的第一个地址<first_addressing>等于基址寄存器<Rn>的值加上/减去指令中寄存器值的4倍。接下来的内存访问地址是前一个访问地址加4。当协处理器发出传输中止信号时,数据传送结束。
 
 这种寻址方式的数据传输数目由协处理器决定。
 
 
 | ![]() 
 | 注意 
 | 这种寻址方式最多允许传输16的字。 
 | 
 (2)语法格式
 
 <opcode>{<cond>}{L}  <coproc>,<CRd>,[<Rn>,#±<offset_8>*4]
 
 其中:
 ·  <Rn>为基址寄存器,包含寻址操作的基地址;
 ·  <offset_8>为8位立即数,该值的4倍为地址偏移量。
 
 (3)操作伪代码
 
 If  ConditionPassed(cond)  then
 If  U = = 1 then
 Address = Rn + offset_8 * 4
 Else  /*U = = 0*/
 Address = Rn – offset_8 * 4
 Start_address = address
 While (NotFinished(coprocessor[cp_num]))
 Address = address +4
 End_address = address
 
 (4)说明
 如果基址寄存器指定为程序计数器r15,则基地址为当前执行指令地址加8。
 
 2.[<Rn>,#±<offset_8>*4]!
 
 (1)编码格式
 指令的编码格式如图4.37所示。
 
 
         图4.37  协处理器Load/Store指令——前索引立即数寻址 
 该寻址方式指定一片连续的内存地址空间。访问内存单元的第一个地址<first_addressing>等于基址寄存器<Rn>的值加上/减去指令中寄存器值的4倍。如果指令的条件域满足,产生的<first_addressing>回写到基址寄存器Rn中。接下来的内存访问地址是前一个访问地址加4。当协处理器发出传输中止信号时,数据传送结束。
 
 这种寻址方式的数据传输数目由协处理器决定。
 
 
 | ![]() 
 | 注意 
 | 这种寻址方式最多允许传输16的字。 
 | 
 (2)语法格式
 
 <opcode>{<cond>}{L}  <coproc>,<CRd>,[<Rn>,#±<offset_8>*4]!
 
 其中:
 ·  <Rn>为基址寄存器,包含寻址操作的基地址;
 ·  <offset_8>为8位立即数,该值的4倍为地址偏移量;
 ·  !设置指令编码中的W位,更新指令基地址。
 
 (3)操作伪代码
 
 If  ConditionPassed(cond)  then
 If  U = = 1 then
 Rn = Rn + offset_8 * 4
 Else  /*U = = 0*/
 Rn = Rn – offset_8 * 4
 Start_address = Rn
 Address = start_address
 While (NotFinished(coprocessor[cp_num]))
 Address = address +4
 End_address = address
 
 (4)说明
 如果基址寄存器指定为程序计数器r15,则指令的执行结果不可预知。
 
 3.[<Rn>],#±<Offset_8>*4
 
 (1)编码格式
 指令的编码格式如图4.38所示。
 
 
         图4.38  协处理器Load/Store指令——后索引立即数寻址 
 该寻址方式指定一片连续的内存地址空间。访问内存单元的第一个地址<first_addressing>等于基址寄存器<Rn>的值。接下来的内存访问地址是前一个访问地址加4。当协处理器发出传输中止信号时,数据传送结束。如果指令的条件域满足,Rn基址寄存器的值更新为Rn的值加上/减去8位立即数的4倍。
 
 这种寻址方式的数据传输数目由协处理器决定。
 
 
 | ![]() 
 | 注意 
 | 这种寻址方式最多允许传输16的字。 
 | 
 (2)语法格式
 
 <opcode>{<cond>}{L}  <coproc>,<CRd>,[<Rn>],#±<offset_8>*4
 
 其中:
 ·  <Rn>为基址寄存器,包含寻址操作的基地址;
 ·  <offset_8>为8位立即数,该值的4倍为地址偏移量。
 
 (3)操作伪代码
 
 If  ConditionPassed(cond)  then
 Start_address = Rn
 If  U = = 1 then
 Rn = Rn + offset_8 * 4
 Else  /*U = = 0*/
 Rn = Rn – offset_8 * 4
 Address = start_address
 While (NotFinished(coprocessor[cp_num]))
 Address = address +4
 End_address = address
 
 (4)说明
 如果基址寄存器指定为程序计数器r15,则指令的执行结果不可预知。
 
 4.[<Rn>], <Option>
 
 (1)编码格式
 
 指令的编码格式如图4.39所示。
 
 
         图4.39  协处理器Load/Store指令——直接寻址 
 该寻址方式指定一片连续的内存地址空间。访问内存单元的第一个地址<first_addressing>等于基址寄存器<Rn>的值。接下来的内存访问地址是前一个访问地址加4。当协处理器发出传输中止信号时,数据传送结束。
 
 指令不更新基址寄存器的值。指令编码格式中bits[7:0]保留,所以可以将空闲位用作协处理器指令扩展。
 
 这种寻址方式的数据传输数目由协处理器决定,最多可以传输16字。
 
 (2)语法格式
 
 <opcode>{<cond>}{L}  <coproc>,<CRd>,[<Rn>],<Option>
 
 其中:
 ·  <Rn>为基址寄存器,包含寻址操作的基地址;
 ·  <option>用作协处理器指令扩展。
 
 (3)操作伪代码
 
 If  ConditionPassed(cond)  then
 Start_address = Rn
 Address = start_address
 While (NotFinished(coprocessor[cp_num]))
 Address = address +4
 End_address = address
 
 (4)说明
 如果基址寄存器指定为程序计数器r15,则寻址基地址为当前指令地址加8。
 |