嵌入式硬件学习(二)——汇编指令

一、汇编作用

为了编写ARM的启动代码,启动代码启动以后,引导程序到C语言环境下运行。启动代码的主要任务有:
(1)初始化异常向量表
(2)初始化各工作模型的栈指针寄存器
(3)将工作模式设置为USR模型
(4)开启ARM内核中端允许
(5)完成上述后,引导程序进行c语言主函数执行。

二、汇编指令

1、mov

作用:加载立即数到寄存器或者将一个寄存器中的值放入另一个寄存器
	mov r0, #2 ;加载立即数2到寄存器r0,	MOV{S}<c> <Rd>, #<const>
	mov r1, r0 ;将r0寄存器的值加载到r1,	MOV{S}<c> <Rd>, <Rm>
	其中,{S}如果加上,表示执行后会影响cpsr寄存器的NZCV位,<c>表示条件

2、add、sub

作用:加法、减法
	ADD{S}<c> <Rd>, <Rn>, #<const>
	ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
	SUB{S}<c> <Rd>, <Rn>, #<const>
	SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}

3、ldr

作用:多用于讲一个32位数据加载到目的寄存器
	LDR{<c>}{<q>} <Rt>, <label> ;如ldr r0, =0x2FAB4
	LDR<c> <Rt>, [<Rn>{, #+/-<imm12>}] 如:LDR   R0[R1,#8];将内存地址为R1+8的字数据读入寄存器R0
	LDR<c> <Rt>, [<Rn>], #+/-<imm12> 如:LDR r0, [r1], #8 ;将内存地址R1的字数据读入r0,之后r1+8
	LDR<c> <Rt>, [<Rn>, #+/-<imm12>]! 如:LDR R0[R1,#8] !;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R18写入R1

4、bic、orr

作用:bic——指定为清0,orr——指定位置1
	BIC{S}<c> <Rd>, <Rn>, #<const>;将rn中的字节数据const1的比特清0,把结果放入rd
	ORR{S}<c> <Rd>, <Rn>, #<const>;将rn中的字节数据const1的比特置1,把结果放入rd

5、cmp

作用:用于比较两个寄存器的值,比较后的结果会存入CPSR中的NVCZ中。
		mov r0, #100
		cmp r0, #100	;会导致Z置位,从条件码表可知,只要Z置位就是两数相等。

执行条件表:
在这里插入图片描述

6、b

作用:跳转指令,跳转时需要一个lable,表示要跳转到什么地方去
	b func 		;跳转到func中
	bl func 	;会在lr寄存器中保存回来的地址
	bx lr 	<==>	mov pc, lr

7、stmfd、ldmfd

作用:入栈保护和出栈恢复
	STMFD<c> <Rn>{!}, <registers>	;入栈之后sp自动自减,如:stmfd sp!, {r0, r1, r2, r3-r12, lr}
	LDMFD<c> <Rn>{!}, <registers>	;如:ldmfd sp!, {r0, r1, r2, r3-r12, lr}

8、msr、mrs

作用:加载立即数到寄存器或者将一个寄存器中的值放入另一个寄存器
		mrs r0, cpsr	;读取cpsr中的值给r0
		msr cpsr_c, r0	;将r0写入cpsr

三、栈

数组栈,即用一段连续的内存空间为栈提供空间。从数组栈的具体实现来看,入栈的方式有四种做法:
(1)空增:增完之后是空的,即先写入数据,再让栈指针自增。
(2)空减:减完之后是空的,即先写入数据,再让栈指针自减。
(3)满增:增完之后是满的,即先让栈指针自增,再写入数据。
(4)满减:减完之后是空的,即先让栈指针自减,再写入数据。
ARM体系采用的是满减栈,从地址0x40000000开始的0x1000这段内存空间对应的是2440内部的一段ram,总共4k。实际能够使用的内存空间为[0x40000000~0x40000FFF],设置栈底指针寄存器: ldr sp =0x40001000。

作用:入栈保护和出栈恢复
	STMFD<c> <Rn>{!}, <registers>	;入栈之后sp自动自减,如:stmfd sp!, {r0, r1, r2, r3-r12, lr}
	LDMFD<c> <Rn>{!}, <registers>	;如:ldmfd sp!, {r0, r1, r2, r3-r12, lr}

四、CPSR寄存器及切换工作模式

1、CPSR寄存器

在这里插入图片描述

N:在结果是有符号的二进制补码情况下,如果结果为负数,则N=1;如果结果为非负数,则N=0
Z:如果结果为0,则Z=1;如果结果为非零,否则Z=0
C:是针对无符号数最高有效位向更高位进位时C=1;减法中运算结果的最高有效位从更高位借位时C=0
V:针对有符号数的操作,会在下面两种情形变为1,两个最高有效位均为0的数相加,得到的结果最高有效位为1;
	两个最高有效位均为1的数相加,得到的结果最高有效位为0;除了这两种情况以外V位为0。

2、切换工作模式

使用CPSR中的低5位 M[4:0] 来设置:
(1)先把 cpsr 读出来,更改低5位之后再设置进去,这里读取cpsr使用mrs指令,
(2)写cpsr寄存器用msr指令,需要注意的是在keil环境下写cpsr需要写成:msr cpsr_c r0;将r0的值写入到cpsr寄存器。

ldr sp, =0x40001000
mrs r0, cpsr			;从cpsr中读取r0
bic r0, r0, #0x1f		;5位清零
orr r0, r0, #0x12		;置为IRQ模式
bic r0, r0, #(0x01 << 7);允许IRQ中断
msr cpsr_c, r0			;送入CPSR

ldr sp, =0x40001000
sub sp, sp, #1024		;从下一个1kRAM中开始存储下一个模式
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0x10
msr cpsr_c, r0

在这里插入图片描述不同

五、C语言和汇编之间的相互调用

1、在汇编中调用C语言

(1)设有c语言定义的函数void func_c(void);在汇编代码中调用该函数,只需用import声明函数名即可,之后就可以使用bl指令调用该函数,注意,既然是调函数,就一定要保护现场。
在这里插入图片描述

(2)向c函数传参:如果参数个数小于等于4个,就直接用r0~r3传参,c函数返回值通过r0寄存器返回。如果参数个数大于4个,从第五个参数开始就需要通过栈来传参。
在这里插入图片描述

2、在C中调用汇编

在汇编中用export声明函数,同时需要在c语言中用extern声明函数。
在这里插入图片描述

六、添加异常向量表

如果发生异常,程序将跳转到指定地址执行相应中断,例如:

	swi #{const}	;软中断,将跳转到0x08去执行

图片

七、启动代码

	preserve8
	area reset, code, readonly
	code32
	entry

	;添加异常向量表
	ldr pc, =start	  		;resnet
	nop						;Undef
	ldr pc, =swi_handler   	;SVC
	nop					   	;prefetch Abort
	nop						;data Abort
	nop						;Not Used
	nop					  	;IRQ
	nop						;FIQ

swi_handler
	import swi_function
	stmfd sp!, {r0-r12, lr}
	bl swi_function
	ldmfd sp!, {r0-r12, pc}^

start
	ldr sp, =0x40001000
	
	mrs r0, cpsr			;从cpsr中读取r0
	bic r0, r0, #0x1f		;5位清零
	orr r0, r0, #0x12		;置为IRQ模式
	bic r0, r0, #(0x01 << 7);允许IRQ中断
	msr cpsr_c, r0			;送入CPSR

	ldr r0, =0x40001000
	sub r0, r0, #1024
	mov sp, r0 		  ;	IRQ模式下的sp寄存器赋值

	mrs r0, cpsr	   ;	切换为USR模式
	bic r0, r0, #0x1f
	orr r0, r0, #0x10
	msr cpsr_c, r0

	ldr r0, =0x40001000
	sub r0, r0, #2048
	mov sp, r0
	
	swi #7
	mov r5, #4 

	end

结束咯,点赞支持一波!!~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值