数据处理指令(Data Processing Instructions)
数据处理指令操控着寄存器中的数据。
包含:数据移动指令,算术运算指令,逻辑运算指令,比较指令和乘法指令。大多数数据处理指令可以通过桶型移位器处理其中一个操作数。
ARM指令集中最大的一族,这族指令的格式相同。如果在数据处理指令中看到 'S' 后缀,那么它将在cpsr(计算机程序状寄存器)中更新标志位。移动和逻辑指令更新 进位标志位 'C' ,取反标志位 'N' , 零标志位 'Z'。 'C' 的设置来自上一位移出的结果 ; 将'N' 设置在在结果的31bit上;如果结果为零,设置 'Z'。
记住,这是一个 load / store架构,这些指令只操作寄存器,而不是内存。
他们在两个操作数上执行特定的操作,并将结果存放到目标寄存器。
第一个操作数总是一个寄存器Rn。
第二个操作数通过barrel shifter送往ALU。
1. 数据移动指令 (MOVE INSTRUCTIONS)
- 概念:copy N( 寄存器/值 ) 到 目标寄存器 Rd。
- 常用数据移动指令 及其 语法
-
例子:
2. 桶型移位器 BARREL SHIFTER
-
移位:上述N 在 MOV指令中是一个简单的寄存器,它也可以是一个经过桶型移位器预处理的寄存器Rm。
数据处理指令在算数逻辑单元(ALU内执行),ARM一个独特的特点是可以将32位二进制数在进入ALU之前进行移位,增加了数据处理的灵活性。
ARM 微处理器内嵌的桶型移位器(Barrel Shifter),支持数据的各种移位操作
不需要移位器的指令:MUL(multiply),CLZ(count leading zeros), QADD(signed saturated 32-bit add)
-
ALU 和 BARREL SHIFTER
如图:寄存器Rn不经过预处理进入到ALU。Rm经过预处理进入移位器以后再进入ALU。
例子:寄存器Rm 移动到目标寄存器之前进行逻辑左移logicla shift left(LSL),和标准C语言的 左操作符“<<”是一样的。MOV指令复制左移结果N到寄存器Rd, N代表LSL操作后的结果。
-
操作示例:
MOV R0, R1, LSR#2 ;将 R1 中的内容右移两位后传送到 R0 中,左端用零来填充。
将寄存器r5进行逻辑左移2位后送到r7寄存器中。
十进制5的二进制数值是0101,进行逻辑左移2位就是0001_0100, 也就是十进制中的20。其实每逻辑左移1位就相当于原数值进行乘2操作,5逻辑左移2位其实就是5 x 2^2 = 20。
-
常用移位指令 及其 语法 如下:
- ASL 算术左移 :ASL 和 LSL 是等价的,可以自由互换
- LSR 逻辑右移:LSR 和 ASR 是等价的,可以自由互换
- ASR 算术右移:MOV R0, R1, ASR#2 ;将 R1 中的内容右移两位后传送到 R0 中,左端用第 31 位的值来填充。
- ROR 循环右移:MOV R0, R1, ROR#2 ;将 R1 中的内容循环右移两位后传送到 R0 中。
- RRX 带扩展的循环右移:MOV R0, R1, RRX#2 ;将 R1 中的内容进行带扩展的循环右移两位后传送到 R0 中。
-
MOVS例子:
3. 算数运算指令 (ARITHMETIC INSTRUCTIONS)
-
常用算数运算指令 及其 语法 如下:
N是移位操作后的结果
- 1.ADC :带进位加法指令。将N的数据和Rn的值相加,再加上 CPSR 中的C条件标志位,结果保存在Rd寄存器。
举例如下:- ADC R0,R1,#12 ==== R0 = R1 + 12 + C(NZCV标志位)完成64位加法的高位运算
- 2.ADD : 将N与Rn的值相加,结果保存到Rd寄存器。目标寄存器和操作数是同一个寄存器时,可以省略。
举例如下:- ADD R0, R1, #12 ==== R0 = R1 + 12
- ADD R0, R1, R2 ==== R0 = R1 + R2
- ADD R0, #12 ==== R0 = R0 + 12
- ADD R0, R1 ==== R0 = R0 + r1
- ADDS R3,R1,R2,LSL #2 ====R3 = R1 + R2 * 4
-
3.RSB:逆向减法指令。用N-Rn,结果保存在Rd中。
举例如下:- RSB R3,R1,#0xFF00 ==== R3 = #0xFF00 - R3
- RSBS R1,R2,R2,LSL #2 ==== R1 = R2*4 -R2 = 3R2
-
RSB R0,R1,#0 ==== R0 = #0 - R1 = -R1
-
4.RSC:带进位的逆向减法指令,用N减去N,再减去CPSR 中的C条件标志位,结果保存在Rd寄存器。
举例如下:- RSC R0,R1,#12 ==== R0 = 12 - R1 - C(NZCV标志位)完成64位减法的高位运算
-
5.SBC : 带进位的减法指令。Rn减去N,再减去CPSR 中的C条件标志位的 非(若C标志清零,结果再减去1),结果保存在Rd寄存器。
举例如下:- SBC R0,R1,#12 ==== R0 = R1 - 12 - !C(NZCV标志位)完成64位减法的高位运算
-
6.SUB : 减法指令,寄存器Rn 减去 N ,结果保存在Rd中。
举例如下:- SUBS R0, #1 ==== R0 = R0 - 1
- SUBS R2,R1,R2 ==== R2 = R1 - R2
-
SUB R6,R7,#0X10 ==== R6 = R7 - #0X10
4. 使用移位器进行算数运行指令
- 概念:第二个操作数移位的广泛在算数和逻辑运算可用是ARM一个特征。
- 示例:
r1寄存器首先向左移动一位,得到了2倍r1值以后通过ADD指令加上移位后的结果,最终结果保存在r0寄存器上。
5. 逻辑运算指令(Logical Instructions)
- 概念:逻辑指令在两个源寄存器中执行按位逻辑操作。
- 常用逻辑运算指令 及其 语法 如下:
-
OR 指令示例:
- BIC 指令示例:
6. 比较指令(Comparison Instruction)
- 概念:比较指令用于用一比较或测试一个32位寄存器的值。根据比较结果更新cpsr寄存器的标志位,但是不影响其他寄存器。当标志位设置以后,通过执行条件信息可以被用到程序的执行流图中。不需要使用后缀'S'来更新标志位。
-
常见的比较指令 及其 语法 如下:
比较指令执行后根据结果来修改NZCV。
cmp :比较, 适合所有条件 ;
cmn :cmp的扩展,快速判断两个数是否相反数;
teq :判断相等,只能和NE或EQ使用;
tst :位测试, 判断第一操作数,第二操作数为1的那些位是0还是1
- CMP 指令示例:执行指令前,r0 和 r9 寄存器相等。比较指令执行以后标志位Z由 0 变为 1(由小写z 变成大写 Z),这表示两个寄存器的值相等。
7. 乘法指令(Multiply Instructions)
- 概念:乘法指令将一对儿寄存器的内容相乘。长整型需要一对寄存器,长整型命令格式(结果为64位)。
- 常用乘法指令 及其 语法 如下
其中:长整型指令(SMLAL, UMLAL, SMULL, UMULL)产生64位结果。这个结果很大和32位寄存器不匹配,设置为两个寄存器 RdLo和RdHo,RdLo保存64位结果的低32位,RdHo64位结果的高32位。
- MUL指令示例:
- UMULL指令示例: