汇编语言:基本指令详解

一、数据操作指令

1、数据搬移指令:mov / mvn 
	1)mov:数据传送指令
		语法:mov{cond}{s} Rd, operand2
		eg:mov  r1, r2	@r1 = r2
		注意:操作数2(operand2)可以是寄存器、立即数、有效数
		eg:mov r3, #0xFFF   @ error
				mov r4, #0xFFFF  @ error
				mov r3, #0xFFFFFF00  @ 有效数OK 
			
	2)mvn:数据取反传送指令
		语法:mov{cond}{s} Rd, operand2
		eg:mov  r1, r2	@r1 = ~r2

2、算数指令:add adc sub sbc mul 
	通用语法:opcode{cond}{s}  Rd, Rn, operand2
	1)add:普通的加法指令
	2)adc:带进位的加法指令
		eg: @两个64位的数相加
				@ 第一个64位的数高32位在r1,低32位在r0
				@ 第二个64位的数高32位在r3,低32位在r2
				@ 结果高32位在r5,低32位在r4
				mov r0, #0xFFFFFFFE
				mov r1, #3
				mov r2, #5 
				mov r3, #6
				@ 先算低32位,需要有状态位,因为要使其产生进位标志
				adds r4, r0, r2   @ r4 = r0 + r2 = 0x00000003
				@ 再算高32位,带进位的加法
				adc r5, r1, r3   @ r5 = r1 + r3 + C = 0xA
		注意:产生进位,C为1,否则为0
		
	3)sub :普通的减法指令
	4)sbc :带借位的减法指令
		eg:@ 两个64位的数减法
				@ 第一个64位的数高32位在r1,低32位在r0
				@ 第二个64位的数高32位在r3,低32位在r2
				@ 结果高32位在r5,低32位在r4
				mov r0, #4
				mov r1, #9
				mov r2, #5 
				mov r3, #6
				@ 先算低32位,需要有状态位,因为要使其产生借位标志
				subs r4, r0, r2   @ r4 = r0 - r2 = 0xFFFFFFFF
				@ 再算高32位,带借位的减法
				sbc r5, r1, r3    @ r5 = r1 - r3 - (1 - C) = 0x2
		注意:sbc,当产生借位时C为0,否则C为1
				
	5)mul :普通的乘法指令
		eg:mov r1, #4 
				mov r2, #5
				mul r0, r1, r2	@ r0 = r1 * r2
		注意:乘法指令的第二个操作数只能是一个寄存器

4、位运算指令:and  orr  eor  bic 
	通用语法:opcode{cond}{s}  Rd, Rn, operand2
	1)and  按位与运算指令 ,与0清0,与1不变
	2)orr  按位或运算指令,或1置1,或0不变
	3)eor  按位异或运算指令,相异为1,相同为0,记为:异为1,同为0
	4)bic  按位清除运算指令,根据第二个操作数哪位是1,就将第一个操作寄存器的哪位清0
	eg:mov r0, #0xFF   @ 假设不知道r0寄存器中的值
			@ 1> 将r0寄存器中的,[4]位清0,保证其他位不变 
				a-) and r1, r0, #0xEF
				b-) and r1, r0, #(~0x10)
				c-) and r1, r0, #(~(0x1 << 4))
			@ 2> 将r0寄存器中的第[20]位置1,保证其他位不变	
				orr r3, r0, #(0x1 << 20)
			@ 3> 将r0寄存器的第[11:8]位置1,保证其他位不变
				orr r4, r0, #(0xF << 8)
			@ 4> 将r0寄存器的第[3:0]位清0,保证其他位不变
				a-) bic r5, r0, #(0xF << 0)
				b-) and r5, r0, #~(0xF)
			@ 5> 将r0寄存器的第[29:26]位写成1010,保证其他位不变
				@ 第一步,先清零
					bic r0, r0, #(0xF << 26)
				@ 第二步,相应的位置1
					orr r0, r0, #(0xA << 26)
			@ 6> 将r0寄存器的第[30:25]位写成101010,保证其他位不变
				@ 第一步,先清零
					bic r0, r0, #(0x3F << 25)
				@ 第二步,相应的位置1
					orr r0, r0, #(0x2A << 25)
			@ 7> 将r0寄存器中的[3:0]位清0,结果写到r1寄存器
					bic r1, r0, #0xf  @ 0xF0
5、比较指令:cmp
		语法:cmp{cond} Rn, operand2 
		作用:比较Rn和Operand2两个数的大小,本质做减法运算
		注意:比较指令没有目标寄存器,没有状态 {S} 位,指令结果只影响 CPSR.NZCV 位
		eg:mov r0, #9
				mov r1, #15
				cmp r0, r1
				@ r0 > r1   r0 = r0 - r1 
				subhi r0, r0, r1
				@ r0 < r1   r1 = r1 - r0 
				subcc r1, r1, r0		

汇编语言:基本指令详解_第1张图片
二、跳转指令:b / bl

	跳转指令的本质:修改PC值
	1)b:不保存返回地址到 lr 寄存器中,跳转到标签的位置
		语法:b{cond}  Label
	2)bl:自动保存返回地址到 lr 寄存器中,跳转到标签的位置
		语法:	bl{cond}  Label
		注意:函数的返回需要手动返回:mov pc, lr
	eg:求两数的最大公约数:
		解析: mov r0, #9
					mov r1, #15
					loop:
						cmp r0, r1
						beq stop
						subhi r0, r0, r1
						subcc r1, r1, r0
						b loop

求两数的最大公约数:汇编语言:基本指令详解_第2张图片

三、Load/Store指令

1、单寄存器操作指令:ldr / str      ldrh / strh       ldrb / strb
	1)ldr:将Rm寄存器指向的内存空间的内容读到Rn寄存器中,读4个字节大小的数据,
		语法:ldr{cond} Rn, [Rm]
		eg:ldr r0, =0x800000FF
				ldr r1, [r0]
		注意:不需要是立即数,可以赋值的范围是:0x00000000 - 0xFFFFFFFF
		
	2)str:将Rn寄存器中的值写到Rm寄存器指向的内存地址空间中,写4个字节大小的数据
		语法:str{cond} Rn, [Rm]
		eg:str r1, [r0]		
	3)eg:
		    ldr r0, =0x40000800
			ldr r1, =0x11111111
			ldr r2, =0x22222222
			ldr r3, =0x33333333
			@ 将r1中的值存储到r0+4的地址空间中,r0中的值不变
			str r1, [r0, #4] 
			@ 将r2中的值存储到r0的地址空间中,r0=r0+4 
			str r2, [r0], #4
			@ 将r3中的值存储到r0+4的地址空间中,r0=r0+4
			@ !:更新地址
			str r3, [r0, #4]!
			
	4)ldrh / strh       ldrb / strb
		用法与上述一致
		h(half word):读写半字
		b(byte):读写一个字(可以用作判断大小端)
	
2、多寄存器操作指令:ldm / stm 
	1)ldm: 一次可以完成多个寄存器的读操作
		语法:ldm{cond}  Rn, {寄存器列表}
	2)stm: 一次可以完成多个寄存器的写操作
		语法:stm{cond}  Rn, {寄存器列表}
	eg:将r1-r3中的值,存储到r0指向的内存地址空间中
			ldr r0, =0x40000800
			ldr r1, =0x11111111
			ldr r2, =0x22222222
			ldr r3, =0x33333333
			@ stm r0, {r1-r3}
			@ stm r0, {r1,r2,r3}
			@ stm r0, {r1-r2,r3}
			@ stm r0, {r3, r2, r1} 会报警告但是没错,照样是从r1-r3,不是从r3-r1
		将r0指向的地址空间中连续的20个字节中的内容读到r4-r7寄存器中
			ldm r0, {r4-r7}
	注意:寄存器列表中的寄存器不管顺序如何,都是高地址对应大编号的寄存器,低地址对应小编号的寄存器。
	
3、栈操作指令:ldmfd / stmfd
 	栈指针寄存器 r13(sp):存放栈顶的地址
 	减栈:栈指针向低地址方向移动
	增栈:栈指针向高地址方向移动
	满栈:栈指针指向的栈空间有效的数据,向栈空间压入数据时,应先将栈指针移动到一个空的位置,
		再向栈空间中压入数据,此时栈指针依然指向一块有数据的栈空间。
	空栈:栈指针指向的栈空间没有有效的数据,向栈空间压入数据时可以直接压入,再将栈指针移动到一个空的位置。
	对于栈的操作方式:
		@ 满增栈(FA) :Full Ascending   ldmfa/stmfa
		@ 满减栈(FD) :Full Descending  ldmfd/stmfd
		@ 空增减(EA) :Empty Ascending  ldmea/stmea
		@ 空减栈(ED) :Empty Descending ldmed/stmed
		@ ARM默认采用的是**满减栈**  ldmfd/stmfd
	1)stmfd:看图了解向内存压栈图1,2
		语法:stmfd{cond} sp!, {寄存器列表}
	2)ldmfd:看图了解向内存压栈图3
		语法:ldmfd{cond} sp!, {寄存器列表}
		注意:!:更新栈指针的地址
	eg:看图4

汇编语言:基本指令详解_第3张图片
汇编语言:基本指令详解_第4张图片
汇编语言:基本指令详解_第5张图片
汇编语言:基本指令详解_第6张图片

四、特殊功能寄存器传送指令:msr / mrs

1)msr:cpsr = operand2
	语法:msr{cond} cpsr, operand2
2)mrs:Rm = cpsr
	语法:mrs{cond} Rm, cpsr
应用:从SVC(超级管理员)模式切换到USR(用户)模式
	SVC模式:0b10011
	USR模式:0b10000
方法:修改模式位保证其他位不变,将低四位清零		@ 1 0011 --> 1 0000
	mrs r0, cpsr 
	bic r0, r0, #0x1F
	orr r0, r0, #0x10
	msr cpsr, r0

五、软中断指令

六、混合编程

你可能感兴趣的:(汇编芝士,嵌入式)