2.寄存器方式

寄存器的值可以被直接用于数据操作指令,如:

?

MOV? r2,r0????????????????? ;r0的值送r2

ADD? r4,r3,r2?????????????? ;r2加r3,结果送r4

CMP? r7,r8????????????????? ;比较r7和r8的值

?

3.寄存器移位方式

寄存器的值在被送到ALU之前,可以事先经过桶形移位寄存器的处理。预处理和移位发生在同一周期内,所以有效的使用移位寄存器,可以增加代码的执行效率。

?

具体的移位(或者循环移位)方式有下面几种。

·? ASR:算术右移。

·? LSL:逻辑左移。

·? LSR:逻辑右移。

·? ROR:循环右移。

·? RRX:扩展的循环右移。

?

以上5种移位方式,移位值均可以由立即数或寄存器指定。下面是一些在指令中使用了移位操作的例子。

?

ADD? r2,r0,r1,LSR? #5

MOV? r1,LSL? #2

RSB? r9,r5,LSL? #1

SUB? r1,r2,LSR #4

MOV? r2,r4,ROR? r0

?

4.1.4? 寻址方式分类详解

数据处理指令的寻址方式根据<shifter_operand>的不同,相应的分为11种。详见表4.1。下面对各类寻址方式进行详细说明。

?

1.#<immediate>

(1)编码格式

指令的编码格式如图4.2所示。

图4.2? 数据处理指令——立即数寻址编码格式

?

立即数寻址为数据处理指令提供了一个可直接操作的立即数。立即数的生成方法见前面章节介绍。如果移位值为0,则移位进位值为程序状态寄存器CPSR的C标志位;否则,为32-bit立即数的bit[31]。

?

(2)操作伪代码

?

Shifter_operand = immed_8 Rotate_Right (rotate_imm*2)

if? rotate_imm == 0 then

????? shifter_carry_out = C flag

else? /* rotate_imm != 0*/

????? shifter_carry_out = shifter_operand[31]

?

(3)说明

① 并不是所有的32-bit立即数都是可以使用的合法立即数。只有那些通过将一个8-bit的立即数循环右移偶数位可以得到的立即数才可以在指令中使用。

?

② 有些立即数可以通过不止一种方法得到。由于立即数的构造方法中移位包含了循环操作,而循环移位操作会影响CPSR的条件标志位C。因此,同一个合法的立即数由于采用了不同的编码方式,将使这些指令的执行产生不同的结果,这是不能允许的。ARM汇编器按照下面的规则来生成立即数的编码。

·? 当立即数数值在0和0xFF范围时,令immed_8=<immediate>,immed_4=0。

·? 其他情况下,汇编编译器选择使用immed_4数值最小的编码方式。

?

③? 为了更精确地控制立即数的生成,可以使用下面的语法格式控制立即数的生成。

?

#<immed_8>,<rotate_amout>

?

其中,<rotate_amout> = 2*rotate_imm

?

(4)举例

?

SUBS? r0,#1????????????????????? ;寄存器r0中的数值减1,结果保存到r0

MOV? r0,#0xff00???? ; 0xff00 → r0????? ;将立即数0xff00放入r0保存

?

2.<Rm>

(1)编码格式

指令的编码格式如图4.3所示。

图4.3? 数据处理指令——寄存器寻址编码格式

指令的操作数即为寄存器中的数值。移位寄存器的进位为程序状态寄存器CPSR的C标志位。

指令的语法格式为:<opcode> {<cond>} {S} <Rd>,<Rm>

?

(2)操作伪代码

?

Shifter_operand = Rm

Shifter_carry_out = C Flag

?

(3)说明

① 从指令的解码格式来看,寄存器寻址方式和使用立即数逻辑左移寻址解码格式是相同的,只是其移位数为0。

② 如果指令中的Rm或Rn指定为程序计数器r15,则操作数的值为当前指令地址加8。

?

(4)举例

MOV? r1,r2??? ; r2 → r1

SUB? r0,r2?? ; r1 – r2 → r0

?

3.<Rm>,LSL? #<shift_imm>

(1)编码格式

指令的编码格式如图4.4所示。

?

图4.4? 数据处理指令——立即数逻辑左移寻址编码格式

?

指令的操作数为寄存器Rm的数值逻辑左移shift_imm位。左移的范围在0到31之间。左移移出的位用0补齐。进位标志位是最后移出的位(如果移位数为0,则为C标志位)。

?

指令的语法格式为:<opcode> {<cond>} {S} <Rd>,<Rm>,LSL #<shift_imm>,其中:

·? <Rm>为进行逻辑左移操作的寄存器;

·? LSL为逻辑左移操作标识;

·? <shift_imm>为逻辑左移位数,范围为0~31。

?

(2)操作伪代码

?

if? shift_imm == 0 then /*执行寄存器操作*/

????? shifter_operand = Rm

????? shifter_carry_out = C flag

else? /*移位寄存器大于零*/

????? shifter_operand = Rm logical_shift_left shift_imm

????? shifter_carry_out = Rm[32 – shift_imm]

?

(3)说明

① 如果移位立即数<shift_imm> =0,则该寻址方式为立即数直接寻址。

② 如果指令中的Rm或Rn指定为程序计数器r15,则操作数的值为当前指令地址加8。

?

(4)举例

?

SUB r0,r1,r2,LSL #10??????? ;r1的值减去r2的值左移10bit,结果放到r0寄存器

MOV r0,r2,LSL #3??????????? ;r2的值左移3bit,结果放入r0,即r0 = r2×8

?

4.<Rm>,LSL? <Rs>

(1)编码格式

指令的编码格式如图4.5所示。

图4.5? 数据处理指令——寄存器逻辑左移寻址编码格式

?

寄存器逻辑左移十分适合寄存器值乘2的倍数操作。

这个指令是将寄存器Rm的值逻辑左移一定的位数。位移的位数由Rs的最低8位bit[7∶0]决定。Rm移出的位用0补齐。进位值是移位寄存器最后移出的位,如果移位数大于0,则进位值为0。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,LSL? <Rs>

?

其中:

·? <Rm>为指令被移位的寄存器;

·? LSL为逻辑左移操作标识;

·? <Rs>为包含逻辑左移位数的寄存器。

?

(3)操作伪代码

?

if? Rs[7:0] = = 0 then

???? shifter_operand = Rm

???? shifter_carry_out = C flag

else? if? Rs[7:0] < 32 then

???? shifter_operand = Rm? logical_shift_left? Rs[7:0]

???? shifter_carry_out = Rm[32 – Rs[7:0]]

else? if? Rs[7:0] = = 32 then

???? shifter_operand = 0

???? shifter_carry_out = Rm[0]

else? /*Rs的后8位大于零*/

???? shifter_operand = 0

???? shifter_carry_out = 0

?

(4)说明

如果程序计数器r15被用作Rd,Rm,Rn或Rs中的任意一个,则指令的执行结果不可预知。

?

(5)举例

?

MOV? r0,r2,LSL r3????????? ;r2的值左移r3位,结果放入r0

ANDS r1,r1,r2,LSL r3????? ;r2的值左移r3位,然后和r1相与,结果放入r1

?

5.<Rm>,LSR #<shift_imm>

(1)编码格式

指令的编码格式如图4.6所示。

图4.6? 数据处理指令——立即数逻辑右移寻址编码格式

?

指令的操作数为寄存器Rm的值右移<shift_imm>位,相当于Rm的值除以一个2的倍数。<shift_imm>值的范围为0~31,移位后空出的位添0。循环器进位值为Rm最后移出的位。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,LSR #<shift_imm>

?

其中:

·? <Rm>为被移位的寄存器;

·? LSR为逻辑右移操作标识;

·? <shift_imm>为逻辑右移位数,范围为0~31。

?

(3)操作伪代码

?

if? shift_imm == 0 then /*执行寄存器操作*/

????? shifter_operand = 0

????? shifter_carry_out = Rm[31]

else? /*移位立即数大于零*/

????? shifter_operand = Rm logical_shift_Right shift_imm

????? shifter_carry_out = Rm[shift_imm - 1]

?

(4)说明

① shift_imm的取值范围为0~31,当shift_imm=0时,移位位数为32,所以移位位数范围为1~32位。

② 如果指令中的Rm或Rn指定为程序计数器r15,则操作数的值为当前指令地址加8。

?

6.<Rm>,LSR? <Rs>

(1)编码格式

指令的编码格式如图4.7所示。

图4.7? 数据处理指令——寄存器逻辑右移寻址编码格式

?

此操作将寄存器Rm的数值逻辑右移一定的位数。移位的位数由Rs的最低8位bit[7∶0]决定。移出的位由0补齐。当Rs[7∶0]大于0而小于32时,进位标志C由最后移出的位决定,当Rs[7∶0]大于32时,进位标志位为0,当Rs[7∶0]等于0时,进位标志不变。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,LSR? <Rs>

?

其中:

·? <Rm>为指令被移位的寄存器;

·? LSR为逻辑右移操作标识;

·? <Rs>为包含逻辑右移位数的寄存器。

?

(3)操作伪代码

?

if? Rs[7:0] = = 0 then

???? shifter_operand = Rm

???? shifter_carry_out = C flag

else? if? Rs[7:0] < 32 then

???? shifter_operand = Rm? logical_shift_Right? Rs[7:0]

???? shifter_carry_out = Rm[Rs[7:0] - 1]

else? if? Rs[7:0] = = 32 then

???? shifter_operand = 0

???? shifter_carry_out = Rm[31]

else? /*Rs的后8位大于零*/

???? shifter_operand = 0

???? shifter_carry_out = 0

?

(4)说明

如果程序计数器r15被用作Rd、Rm、Rn或Rs中的任意一个,则指令的执行结果不可预知。

?

7.<Rm>,ASR #<shift_imm>

(1)编码格式

指令的编码格式如图4.8所示。

图4.8? 数据处理指令——立即数算术右移寻址编码格式

?

指令的操作数为寄存器Rm的数值逻辑右移<shift_imm>位。<shift_imm>的值范围为0~31,当<shift_imm>等于0时,移位位数为32,所以移位位数范围为1~32位。进位移位操作后,空出的位添Rm的最高位Rm[31]。进位标志为Rm最后被移出的数值。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,ASR #<shift_imm>

?

其中:

·? <Rm>为被移位的寄存器;

·? ASR为算术右移操作标识;

·? <shift_imm>为算术右移位数,范围为1~32,当shift_imm等于0时移位位数为32。

?

(3)操作伪代码

?

if? shift_imm == 0 then /*执行寄存器操作*/

???? if? Rm[31] = = 0 then

????????? shifter_operand = 0

????????? shifter_carry_out = Rm[31]

???? else /*Rm[31] = = 1*/

????????? shifter_operand = 0xffffffff

????????? shifter_carry_out = Rm[31]

else? /*shift_imm > 0*/

???? shifter_operand = Rm Arithmetic_shift_Right <shift_imm>

???? shifter_carry_out = Rm[shift_imm - 1]

?

(4)说明

① 如果指令中的Rm或Rn指定为程序计数器r15,则操作数的值为当前指令地址加8。

?

8.<Rm>,ASR? <Rs>

(1)编码格式

指令的编码格式如图4.9所示。

图4.9? 数据处理指令——寄存器算术右移寻址编码格式

?

此操作将寄存器Rm的数值算术右移一定的位数。移位后空缺的位由Rm的符号位(Rm[31])填充。位移的位数由Rs的最低8位bit[7∶0]决定。当Rs[7∶0]大于零而小于32时,指令的操作数为寄存器Rm的数值算术右移Rs[7∶0]位,进位标志C为Rm最后被移出的位。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,ASR? <Rs>

?

其中:

·? <Rm>为指令被移位的寄存器;

·? ASR为算术右移操作标识;

·? <Rs>为包含算术右移位数的寄存器。

?

(3)操作伪代码

?

if? Rs[7:0] = = 0 then

???? shifter_operand = Rm

???? shifter_carry_out = C flag

else? if? Rs[7:0] < 32 then

???? shifter_operand = Rm? Arithmeticl_shift_Right? Rs[7:0]

???? shifter_carry_out = Rm[Rs[7:0] - 1]

else?

???? if? Rm[31] = =0 then

????????? shifter_operand = 0

????????? shifter_carry_out = Rm[31]

??? else?

????????? shifter_operand = 0xffffffff

????????? shifter_carry_out = Rm[31]

?

(4)说明

如果程序计数器r15被用作Rd、Rm、Rn或Rs中的任意一个,则指令的执行结果不可预知。

?

9.<Rm>,ROR #<shift_imm>

(1)编码格式

指令的编码格式如图4.10所示。

图4.10? 数据处理指令——立即数循环右移寻址编码格式

?

指令的操作数由寄存器Rm的数值循环右移一定的位数得到。移位的位数由Rs的最低8位bits[7∶0]决定。当Rs[7∶0]=0时,指令的操作数为寄存器Rm的值,循环器的进位值为CPSR中的C条件标志位;否则,循环器的进位值为Rm最后被移出的位。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,ROR #<shift_imm>

其中:

·? <Rm>为被移位的寄存器;

·? ROR为循环右移操作标识;

·? <shift_imm>为循环右移位数,范围为1~31,当shift_imm等于0时执行RRX操作。

?

(3)操作伪代码

?

if? shift_imm == 0 then /*执行寄存器操作*/

???? 执行RRX操作

else

???? shifter_operand = Rm Rotate_Right shift_imm

???? shifter_carry_out = Rm[shift_imm - 1]

?

(4)说明

如果指令中的Rm或Rn指定为程序计数器r15,则操作数的值为当前指令地址加8。

?

10.<Rm>,ROR? <Rs>

(1)编码格式

指令的编码格式如图4.11所示。

图4.11? 数据处理指令——寄存器循环右移寻址编码格式

?

指令的操作数由寄存器Rm的数值循环右移一定的位数。移位的位数由Rs的最低8位bits[7∶0]决定。当Rs[7∶0]=0时,指令的操作数为寄存器Rm的值,循环器的进位值为CPSR中的C条件标志位;否则,循环器的进位值为Rm最后被移出的位。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,ROR? <Rs>

?

其中:

·? <Rm>为指令被移位的寄存器;

·? ROR为循环右移操作标识;

·? <Rs>为包含循环右移位数的寄存器。

?

(3)操作伪代码

?

if? Rs[7:0] = = 0 then

???? shifter_operand = Rm

???? shifter_carry_out = C flag

else? if? Rs[4:0] == 0 then

???? shifter_operand = Rm

???? shifter_carry_out = Rm[31]

else?

???? shifter_operand = Rm Rotate_Right Rs[4:0]

???? shifter_carry_out = Rm[Rs[4:0] - 1]

?

(4)说明

如果程序计数器r15被用作Rd、Rm、Rn或Rs中的任意一个,则指令的执行结果不可预知。

?

11.<Rm>,RRX

(1)编码格式

指令的编码格式如图4.12所示。

图4.12? 数据处理指令——扩展右移寻址编码格式

?

指令的操作数为寄存器Rm的数值右移一位,并用CPSR中的C条件标志位填补空出的位。CPSR中的C条件标志位则用移出的位代替。

?

(2)语法格式

?

<opcode> {<cond>} {S} <Rd>,RRX

?

其中:

·? <Rm>为指令被移位的寄存器;

·? RRX为扩展的循环右移操作。

?

(3)操作伪代码

?

shifter_operand = (C flag logical_shift_left 31) OR (Rm logical_shift_Right 1)

shifter_carry_out = Rm[0]

?

(4)说明

① 此种寻址方式的编码形式和“ROR #0”一致。

② 如果程序计数器r15被用作Rd、Rm、Rn或Rs中的任意一个,则指令的执行结果不可预知。

③ 可以实现ADC指令的功能。