ARM指令寻址方式之: 内存访问指令寻址

本文涉及的产品
数据传输服务 DTS,数据同步 small 3个月
推荐场景:
数据库上云
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
数据传输服务 DTS,数据同步 1个月
简介:

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。


参考网址:http://www.eefocus.com/embedded/322869/r0

相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
相关文章
|
28天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
46 6
|
10天前
|
存储 缓存 数据安全/隐私保护
DMA(Direct Memory Access):直接内存访问
DMA(Direct Memory Access)是一种允许外设直接与内存进行数据传输的技术,无需 CPU 干预。它通过减轻 CPU 负担、提高数据传输效率来提升系统性能。DMA 的工作模式包括直接模式和 FIFO 模式,数据传输方式有单字传送和块传送,寻址模式有增量寻址和非增量寻址。通过缓存一致性协议、同步机制、数据校验和合理的内存管理,DMA 确保了数据在内存中的一致性和完整性。
42 0
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
111 4
|
2月前
|
缓存 算法 数据处理
如何选择合适的内存访问模式
【10月更文挑战第20天】如何选择合适的内存访问模式
57 1
|
2月前
|
存储 容器
内存越界访问(Out-of-Bounds Access)
【10月更文挑战第12天】
279 2
|
2月前
|
Rust 编译器
|
3月前
|
存储 网络协议 大数据
一文读懂RDMA: Remote Direct Memory Access(远程直接内存访问)
该文档详细介绍了RDMA(远程直接内存访问)技术的基本原理、主要特点及其编程接口。RDMA通过硬件直接在应用程序间搬移数据,绕过操作系统协议栈,显著提升网络通信效率,尤其适用于高性能计算和大数据处理等场景。文档还提供了RDMA编程接口的概述及示例代码,帮助开发者更好地理解和应用这一技术。
|
2月前
|
存储 移动开发 C语言
【ARM汇编速成】零基础入门汇编语言之指令集(三)
【ARM汇编速成】零基础入门汇编语言之指令集(三)
|
2月前
|
编译器 C语言 计算机视觉
【ARM汇编速成】零基础入门汇编语言之指令集(二)
【ARM汇编速成】零基础入门汇编语言之指令集(二)
261 0
|
3月前
|
存储 安全 Linux
将文件映射到内存,像数组一样访问
将文件映射到内存,像数组一样访问
40 0

热门文章

最新文章