我要成为嵌入式高手之4月11日51ARM第六天!!
 ————————————————————————————
 
b指令
标签:表示这条指令的名称,可跳转至标签
b指令:相当于goto,可随意跳转
如:finish为标签,b finish跳转至该位置
finish
b finish
bl指令:跳转之后将跳转前的位置存储到 lr(链接寄存器) 寄存器中
bx指令:将某个寄存器的保存的地址写入 pc 寄存器
练习:用汇编写出1~100的累加和
	area reset, code, readonly
	code32
	entry
	
	mov r0, #0
	mov r1, #0
loop
	add r1, r1, r0
	add r0, #1
	
	cmp r0, #100
	ble loop
finish
	b finish
	end 
2440栈的实现类型
2440实现保护和恢复现场使用的栈是数组栈,即用一段连续的内存空间为栈提供空间。从数组栈的具体实现来看入栈的方式有四种做法:
- 空增:先写入数据,再让栈指针自增;
 - 空减:先写入数据,再让栈指针自减;
 - 满增:先让栈指针自增,再写入数据;
 - 满减:先让栈指针自减,再写入数据。
 
arm体系采用的方案是满减,但是在进行操作之前,我们必须告诉2440栈底的位置,这里我们把栈底设置为0x40001000,从地址0x40000000开始的0x1000这段内存空间对应的是2440内部的一段ram,总共4k。实际能够使用的内存空间为[0x40000000~0x40000FFF],
设置栈底指针寄存器: ldr sp =0x40001000
入栈保护指令stmfd(STMDB)
STMFD<c> <Rn>{!}, <registers>
其中Rn表示栈底指针寄存器,< registers >表示需要入栈保护的寄存器,!表示入栈之后sp自动自减。如:stmfd sp!, {r0, r1, r2, r3-r12, lr}
  
出栈恢复指令ldmfd(LDM/LDMIA/)
LDMFD<c> <Rn>{!}, <registers>
中Rn表示栈底指针寄存器,< registers >表示需要入栈保护的寄存器,!表示出栈之后sp自动自增。如:ldmfd sp!, {r0, r1, r2, r3-r12, lr}
汇编程序中调用c程序函数
步骤:
1、先用 import 声明c函数
如: import c_add
2、入栈保护{r0 - r12}
3、若是函数参数小于4个时,通过 r0 ~ r3 寄存器进行传参
4、函数调用完的返回值结果通过 r0 寄存器返回
5、若参数个数大于4个,从第五个开始要通过栈进行参数传参
6、出栈恢复{r0 - r12}
	import c_add
	stmfd sp!, {r0-r12}
	mov r0, #1
	mov r1, #2 
	mov r2, #3
	mov r3, #4 
	mov r4, #5
	stmfd sp!, {r4}
	bl c_add
	ldmfd sp!, {r4}
	ldmfd sp!, {r0-r12 
c程序中掉用汇编函数
1、import main
2、b main
3、export 汇编函数名
4、在main中声明汇编函数
5、在汇编函数结尾bx lr
如何切换工作模式
1、把r0中低5位清零
2、把r0中低五位设置为10000(user模式)
3、用msr指令将r0的值写入cpsr寄存器
	ldr sp, =0x40001000
	bic r0, r0, #0x1F
	orr r0, r0, #0x10
	msr cpsr_c, r0 


为什么此处sp变为0?
答:此时的sp为sp_svc,不是user模式下的sp,故需要设置sp_user,且要从栈顶往后走1k


	ldr sp, =0x40001000
	bic r0, r0, #0x1F
	orr r0, r0, #0x10
	msr cpsr_c, r0
	ldr sp, =0x40001000
	sub sp, sp, #1024 
cpsr中指令
msr指令:写入cpsr
mrs指令:读取cpsr中数据
启动代码
异常向量表

初始化代码:
	preserve8
	area reset, code, readonly
	code32
	entry
	
	;用8个代码占用异常向量表的八个格式
	b start
	nop
	nop
	nop
	nop
	nop
	nop
	nop
start
	ldr sp, =0x40001000
	
	;状态切换到user模式下
	mrs r0, cpsr
	bic r0, #0x1F
	orr r0, #0x10
	msr cpsr_c, r0
	ldr sp, =0x40001000
	sub sp, sp, #1024
	import main
	b main
	
finish
	b finish
	end 

中断处理
中断类型:

软件中断SWI
SWI指令:发出一个软件中断,用法:SWI #立即数
作用:产生一个软件中断
流程 :产生一个异常,进入svc模式;查询异常向量表(找软件中断0x08)
	;用8个代码占用异常向量表的八个格式
	b start
	nop
	b do_swi
	nop
	nop
	nop
	nop
	nop
start
	;设置的是svc下的栈指针寄存器
	ldr sp, =0x40001000
	
	;状态切换到user模式下
	mrs r0, cpsr
	bic r0, #0x1F
	orr r0, #0x10
	msr cpsr_c, r0
	ldr sp, =0x40001000
	sub sp, sp, #1024
	import main
	b main
do_swi
	import swi_handle
	stmfd sp!, {r1-r12, lr}
	bl swi_handle
	ldmfd sp!, {r1-r12, pc}^
	;^含义:不但要恢复现场,并且要恢复之前的工作模式
		
	export asm_swi
asm_swi
	swi #10
	bx lr
	;在写完函数之后都应该加上bx lr:将lr写入pc中 
IRQ快速中断
初始化IRQ模式栈指针寄存器
	preserve8
	area reset, code, readonly
	code32
	entry
	
	;用8个代码占用异常向量表的八个格式
	b start
	nop
	b do_swi
	nop
	nop
	nop
	b do_interrupt
	nop
start
	;设置的是svc下的栈指针寄存器
	ldr sp, =0x40001000
	
	;状态切换到user模式下
	mrs r0, cpsr
	bic r0, #0x1F
	orr r0, #0x12;切换到IRQ模式
	bic r0, r0, #(1 << 7);将中断允许清零,意为允许中断
	msr cpsr_c, r0
	
	;初始化的是IRQ模式下的栈指针寄存器
	ldr sp, =0x40001000
	sub sp, sp, #1024
	mrs r0, cpsr
	bic r0, #0x1F
	orr r0, #0x10
	msr cpsr_c, r0
	ldr sp, =0x40001000
	sub sp, sp, #2048
	
	import main
	b main
do_interrupt
	import interrupt_handle
	sub lr, lr, #4;查询中断类型表得出快速中断需要lr寄存器的值-4
	stmfd sp!, {r1-r12, lr}
	bl interrupt_handle
	ldmfd sp!, {r1-r12, pc}^
do_swi
	import swi_handle
	stmfd sp!, {r1-r12, lr}
	bl swi_handle
	ldmfd sp!, {r1-r12, pc}^
	;^含义:不但要恢复现场,并且要恢复之前的工作模式
		
	export asm_swi
asm_swi
	swi #10
	bx lr
	;在写完函数之后都应该加上bx lr:将lr写入pc中	
finish
	b finish
	end 
MINI2440
将软件写入MINI2440,需要修改的操作





若将软件下载进板子成功,会出现如此字样

调试结果与软件调试结果应一致

















