指令

什么是指令?按我的理解,简单来说,指令就是计算机能识别的完成特定操作的二进制代码。

无论用什么编程语言,最后目标代码都是由二进制指令序列组成的,每条指令指示计算机完成一个最基本的任务。

汇编语言除去伪代码则和指令序列一一对应。高级语言则无对应关系。


指令的格式

指令 = 操作码 + 操作数
例如:

add r0,r1,r2   ; r0 = r1 + r2
add            加法操作码 
r0  r1  r2     操作数
r1  r2         目的操作数
r0             源操作数

ARM的指令集

编译指令 arm架构 关系 arm指令结构_寄存器


数据操作指令

数据操作指令是指对存放在寄存器中的数据进行操作的指令。包括数据传送指令、算术指令、逻辑指令、比较与测试指令及乘法指令。
这些指令类比C语言来学。常用的数据操作指令如下:

MOV指令
MOV指令多用于设置初始值或者在寄存器间传送数据。说白了就跟C语言的赋值操作类似
示例:

MOV R0,R0          ;R0 = R0 相当于Nop指令

MOV R0,R0,LSL#3    ;  R0 = R0 << 3即R0 = R0 * 8

MOV PC,R14        ;恢复PC(R15)的值,回到子程序调用断点处,用于普通函数返回

MOVS PC,R14         ;恢复PC(R15)的值,回到发生中断打断处,用于异常函数返回。

MVN指令
MVN指令多用于向寄存器传送一个负数或生成位掩码。
这是逻辑非操作而不是算术操作,这个取反的值加1才是它的取负的值。
示例:

MVN R0,#4   ;4+1再取负,即R0 = -5

MVN R0,#0   ;0+1再取负,即R0 = -1

AND指令
与C语言的按位与运算符功能一致。

AND R0,R0,#3      ; R0 &  0011,即保留R0的值的第0位和第1位

AND R0,R1,R2      ; R0 = R1 & R2  

ANDs R0,R0,#0x01  ; R0 = R0 & 0x01,取出数据的最低位

EOR指令
异或指令
示例:

EOR R0,R0,#3         ;反转RO中的位0和1

EOR R1,R1,#0x0F      ;将R1的低4位取反:

EOR R2,R1,R0         ;R2 = R1 ^ R0 

EORS R0,R5,#0x01  ;将R5和0x01进行逻辑异或,结果保存到R0,并根据执行结果设置标志位。

SUB指令
做减法的指令。
示例:

SUB R0,R1,R2     ;R0 = R1 - R2

SUB R0,R1,#256   ; R0 = R1 - 256

SUB R0,R2,R3,LSL#1  ;R0 = R 2 - (R3 << 1)

ADD指令
加法指令
示例:

ADD R0,R1,R2   ;即R0  = R1 + R2

ADD  R0,R1,#256   ;即R0 = R1 + 256

ADD R0,R2,R3,LSL#1 ;即R0 = R2 + (R3 << 1)

ORR指令
按位或指令
示例:

ORR R0,R0,#3   ;设置R0中位0和1为1

ORR R0,R0,#0x0F  ;将R0的低4位置1。

BIC指令
位清零操作指令
示例:

BIC R0,R0,#0x1011   ;清除R0中的位0、1和3,保持其余的不变

BIC R1,R2,R3        ;将R3的反码和R2逻辑与,结果保存到R1中

TEQ指令
比较R0和R1是否相等,该指令不影响CPSR中的V位和C位。

TEQ R0,R1

使用TEQ进行相等测试,常与EQ和NE条件码配合使用,当两个数据相等时,条件码EQ有效;否则条件码NE有效。


CMP指令
CMP指令操作后,根据操作的结果更新CPSR中相应的条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
示例:

(1)比较R1和立即数10并设置相关的标志位:
       CMP R1,#10
(2)比较寄存器R1和R2中的值并设置相关的标志位。
       CMP R1,R2

ARM指令条件码

编译指令 arm架构 关系 arm指令结构_编译指令 arm架构 关系_02


Load/Store内存访问指令

用于把单一的数据传入或者传出一个寄存器。支持的数据类型有字节(8位)、半字(16位)和字(32位)

助记符分别为LDR,STR。

编译指令 arm架构 关系 arm指令结构_编译指令 arm架构 关系_03


LDR指令
用于从内存中将一个32位的字读取到目标寄存器。
示例:

LDR  R1,[R0,#0x12] ;将R0+12地址处的数据读出,保存到R1中(R0的值不变)

LDR  R1,[R0]	   ;将R0地址处的数据读出,保存到R1中(零偏移)

LDR  R1,[R0,R2]	   ;将R0+R2地址的数据读出,保存到R1中(R0的值不变)

LDR  R1,[R0,R2,LSL #2] ;将R0+R2×4地址处的数据读出,保存到R1中(R0、R2的值不变)

LDR  Rd,label  ;label为程序标号,label必须是当前指令的-4~4KB范围内

LDR  Rd,[Rn],#0x04 ;Rn的值用作传输数据的存储地址。在数据传送后,将偏移量0x04与Rn相加,结果写回到Rn中。Rn不允许是R15

STR指令
用于将一个32位的字数据写入到指令中指定的内存单元。
示例:
STR指令的用法。

NumCount  EQU  0x40003000 ; 宏定义,宏名为NumCount,值为0x40003000 
LDR  R0,=NumCount    ;使用LDR伪指令装载NumCount的地址到R0
LDR  R1,[R0]		       ;LDR指令取出变量值
ADD  R1,R1,#1	       ;NumCount=NumCount+1
STR   R1,[R0]		      ;STR指令保存变量

使用LDR和STR指令操作单片机GPIO寄存器示例:

GPIO_BASE  EQU   0xe0028000;      定义GPIO寄存器的基地址
......
LDR    R0,=GPIO-BASE
LDR    R1,=0x00ffff00		    ;将设置值放入寄存器
STR    R1,[R0,#0x0C]	;  R0 + 0x0c = 0xE0028004,将地址为0xE0028004的寄存器的值设置为R1即是0x00ffff00。

多寄存器访问的LDR/STR指令

LDM/STM的主要用途有现场保护、数据复制和参数传递等。
助记符为LDM,STM。

编译指令 arm架构 关系 arm指令结构_R3_04


前面4种用于数据块的传输,后面4种是堆栈操作。

示例:
(1)使用LDM/STM进行数据复制。

LDR  R0,=SrcData		;设置源数据地址
LDR  R1,=DstData		;设置目标地址
LDMIA   R0,{R2~R9} 	; 加载8字数据到寄存器R2~R9
STMIA   R1,{R2~R9}	    ;存储寄存器R2~R9到目标地址

(2)使用LDM/STM进行现场寄存器保护,常在子程序或异常处理使用

......
IRQ_HANDLE                         ;中断入口
	ldr sp,=0xd0037f80
	sub lr,lr,#4
	stmfd  sp!,{r0-r12,lr}            ;保护现场
		
	import IRQ_ISR	
	bl IRQ_ISR                         ;中断处理函数
	
	ldmfd sp!,{r0-r12,pc}^          ;恢复现场
	
	......

跳转指令

跳转(B)和跳转连接(BL)指令是改变指令执行顺序的标准方式。ARM一般按照字地址顺序执行指令,需要时使用条件执行跳过某段指令。只要程序必须偏离顺序执行,就要使用控制流指令来修改程序计数器。

跳转指令改变程序的执行流程或者调用子程序。这种指令使得一个程序可以使用子程序、if-then-else结构及循环

编译指令 arm架构 关系 arm指令结构_寄存器_05


示例:

;程序跳转到LABLE标号处
    B  LABLE 
    ADD  R1,R2,#4
    ADD  R3,R2,#8
    SUB  R3,R3,R1
LABLE
    SUB  R1,R2,#8
;调到绝地地址为0x1234去执行
B  0x1234;这里不能写成#0x1234
;跳转到子程序func处执行,同时将当前PC值保存到LR中
	BL  func
func:
	ADD R1,R1,#10
;带条件的跳转:当CPSR寄存器中的C条件标志位为1时,程序跳转到标号LABLE处执行。
	BCC  LABLE
(5)通过跳转指令建立一个死循环。
LOOP
    ADD  R1,R2,#4
    ADD  R3,R2,#8
    SUB  R3,R3,R1
    B  LOOP
;通过使用跳转使程序体循环10次。
    MOV  R0,#10   ;R0 = 10
LOOP                    ;程序标号,也就是地址,C语言函数名也就是一个地址
    SUBS  R0,#1   ;R0 = R0 - 1;
    BNE   LOOP     ;与0不相等跳转到LOOP
;条件子程序调用示例:
CMP  R0,#5                   ;如果R0<5
BLLT  SUB1                    ;则调用
BLGE  SUB2                    ;否则调用SUB2

状态操作指令

编译指令 arm架构 关系 arm指令结构_寄存器_06


MRS指令
示例:

MRS  R1,CPSR	;将CPSR状态寄存器读取,保存到R1中
MRS  R2,SPSR	;将SPSR状态寄存器读取,保存到R1中

MRS指令读取CPSR,可用来判断ALU的状态标志及IRQ/FIQ中断是否允许等;在异常处理程序中,读SPSR可指定进入异常前的处理器状态等。MRS与MSR配合使用,实现CPSR或SPSR寄存器的读—修改—写操作,可用来进行处理器模式切换,允许/禁止IRQ/FIQ中断等设置。另外,进程切换或允许异常中断嵌套时,也需要使用MRS指令读取SPSR状态值并保存起来。


MSR指令
指令格式:
MSR{cond} PSR_field,#immed_8r
MSR{cond} PSR_field,Rm

PSR是指CPSR或SPSR。field是状态寄存器中需要操作的位。状态寄存器的32位可以分为4个8位的域。bits[31:24]为条件标志位域,用f表示;bits[23:16]为状态位域,用s表示;bits[15:8]为扩展位域,用x表示;bits[7:0]为控制位域,用c表示。
示例:

MSR  CPSR_c,#0xD3	;CPSR[7:0]=0xD3,切换到管理模式
MSR  CPSR_cxsf,R3	;CPSR=R3

ARM指令寻址方式

参考该文:https://www.jianshu.com/p/a9d3ceee1d01