文章目录
函数发生调用时,需要进行线程保护,简单来说,就是先进行压栈操作,将调用函数参数、返回值等存到R0-15寄存器中,在执行完毕后,需要将数据内容从寄存器读出,进行出栈操作,而这一系列操作需要SP指针。芯片上电后SP指针(堆栈指针寄存器)还未初始化完毕,无法执行C代码,所以必须要用汇编设置好C语言环境。
GNU汇编语法
c
label:instruction @ comment
# label:标号,表示地址位置
# instruction:指令,代表汇编指令或伪指令
# comment:注释
/*例子:
add:
MOVS R0, #0X12 @设置 R0=0X12
/*
.global _start @设置start函数为全局,供加载器找到该函数,之后再实现该函数即可
指令不可大小写混用
常用汇编指令
处理器内部数据传输指令
**1)MOV指令 **
将数据从一个寄存器拷贝到另外的寄存器,或者将立即数传递到寄存器中
MOV R0, R1 @寄存器R0 = R1
MOV R0, #0X12 @R0=0X12
2)MRS指令
读取特殊寄存器(CPSR、SPSR)中数据传递给通用寄存器
MRS R0, CPSP @R0=CPSR
3)MSR指令
写特殊寄存器
MSR CPSR, R0 @CPSR=R0
存储器访问指令
访问IMX6UL存储器,需要借助存储器访问指令,先写入到R0-R12寄存器,再写入到指定存储器(RAM)中的寄存器中。
1)LDR、STR指令
LDR Rd, [Rn,#offset] 从寄存器Rn+offset位置读数据到寄存器Rd中
STR Rd,[Rn,#offset] 将Rd中的数据写入到存储器的Rn+offset位置
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中,即地址0X0209C004的值为0X20000002
LDR、STR 按32位数据操作
LDRB、STRB 按字节操作、
LDRH、STRH 按半字操作
压栈和出栈指令
在函数执行到一半时,如果需要执行另外一个函数,则需要保留当前处理器状态到寄存器,在执行完毕后,从寄存器中读取数据恢复现场,其中涉及到压栈和出栈。
PUSH 将寄存器列表入栈
POP 从栈中恢复寄存器
等价于
STMFD SP!
LDMFD SP!!
处理器堆栈向下增长,栈由高地址向低地址增长,起始地址为0x80000000,向0x70000000增长
PUSH {R0~R3,R12} @将 R0~R3 和 R12 压栈
PUSH {LR} @将LR进行压栈
POP {LR} @先恢复 LR
POP {R0~R3,R12} @在恢复 R0~R3,R12
跳转指令
1)B指令
B ,跳转到 label,如果跳转范围超过了+/-2KB,可以指定 B.W 使用 32 位版本的跳转指令, 这样可以得到较大范围的跳转.
2)BL指令
BL ,在跳转到子程序前,将PC寄存器值保存到LR(R14)寄存器,执行完后,重新将LR寄存器中的值取出,继续从跳转之前的代码处运行。
算术指令
ADD 加法
ADC 带进位的加法
SUB 减法
SBC 带借位的减法
MUL 乘法
UDIV 无符号除法
SDIV 有符号除法
逻辑运算指令
AND 按位与
ORR 按位或
BIC 位清除
ORN 按位与非
EOR 按位异或
实战
github路径:linux_bsp/board_driver/1.ledc