```bash /* * 文件名: led.s * 作者: XXX * 描述: 汇编开关icache */ #define WTCON 0xE2700000 #define SVC_STACK 0xd0037d80 .global _start // 把_start将链接属性改为外部,以便可以看到其他文件_start了 _start: // 第一步:关闭门狗(方向:WTCON的bit5写入0即可) ldr r0, =WTCON ldr r1, =0x0 str r1, [r0] // 第2步:设置SVC栈 ldr sp, =SVC_STACK // 第三步:开/关icache mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中 //bic r0, r0, #(1<<12) // bit12 置0 关icache orr r0, r0, #(1<<12) // bit12 置1 开icache mcr p15,0,r0,c1,c0,0; // 从此可以开始调用C程序 bl led_blink // led_blink是C语言实现的函数 // 汇编的最后一个死循环不能丢失 b .
根据上述代码,开始总结。
1.global指令
该指令用于在链接阶段找到文件中的函数名。 例如,如果开始位置只写一个函数名,则在编译阶段会提示警告。正确的方法是:
.global _start // 把_start将链接属性改为外部,以便可以看到其他文件_start了 _start:
2. ldr 和 str
这两个指令是ARM架构汇编的特点之一,ARM单独存储数据和指令,CPU通过寄存器不能直接读取内存。CPU就寄存器而言,load将内存内容加载到寄存器;store将寄存器内容存储在内存中。
ldr r0, =WTCON 将STCON将地址对应的内容加载到寄存器中r0中。 ldr r1, =0x0 将0x0加载地址对应的内容r1中。 str r1, [r0] 将r1内容存储在[r0]对应的内存中去。 ldr sp, =SVC_STACK
- ldr sp, =SVC_STACK 这个指令是在C语言运行的时候堆栈,设置好就可以运行C语言了。
3. 协处理器指令:mcr 和 mrc 指令
mrc用于读取CP寄存器15;mcr用于写入cp寄存器15。
什么是协处理器?(coprocessor)?
协处理器是SoC另一个内部处理器核心协助CPU实现某些功能,被主CPU调用执行某些任务。ARM支持16个协处理器。
mrc p15,0,r0,c1,c0,0; // 读出cp15的c1到r0中
这句汇编的意思是:将协处理器寄存器c0 c1中的内容加载到ARM寄存器r1中;
mcr p15,0,r0,c1,c0,0;
这句代码意思是:将r0寄存器内容送入协处理器的c0 c1 寄存器中。
4. bic 和 orr
bic是某些寄存器的某些位;orr是将某些位置1
//bic r0, r0, #(1<<12) // bit12 置0 关icache
orr r0, r0, #(1<<12) // bit12 置1 开icache
5. bl 有返回的调用函数
bl 指令是有返回的调用函数,调用函数之前保存了现场。
6. 汇编语言死循环写法
b .
b 和 bl 区别:b直接跳转,没有想返回,所以也不用保存值。
7. 再来看看汇编的延时函数写法
delay:
ldr r2, =3000000 进行30万次减法
ldr r3, =0x0
delay_loop:
sub r2, r2, #1 // r2 = r2 - 1
cmp r2,r3 // cmp会影响Z标志位,如果 r2 r3 相等,则z=1, 下一句中beq就会成立。
bne delay_loop // 不相等就继续执行减法,继续延时, delay_loop ,否则直接执行mov pc,lr
mov pc,lr // 程序返回调用的位置,lr保存了现场。