FreeRTOS学习(五):ARM架构基础:寄存器、栈操作与指令详解(必看!超重要!建议收藏!)
文章目录
前言
ARM架构是当今最流行的嵌入式处理器架构之一。本文将详细介绍ARM架构中的核心概念,包括重要寄存器、基本指令和栈操作。因为FreeRTOS后面的讲解会用,所以现在给大家普及一下
1.从简单程序讲解
cpu与ram
要是运行a=a+b的话,cpu与ram之间的交互会如下
首先需要从内存读取操作数
然后在CPU中进行计算
最后将结果写回内存
而它是怎么入栈,答案是从flash那里得到指令
R1是参数传递和返回值的寄存器
这个过程展示了:
- CPU中有R0-R15共16个寄存器
- RAM中存储了变量a
- Flash中存储了程序指令
- 通过指令将RAM中的变量a读取到CPU的R1寄存器中
cpu内部的寄存器是怎么样的,指令是如何指导入栈出栈的就是下面的内容
2. ARM核心寄存器详解
2.1 程序计数器(PC)
- 功能:存储当前执行指令的地址
- 特点:自动递增,指向下一条指令
- 应用场景:程序执行流程控制
2.2 链接寄存器(LR/R14)
- 功能:存储函数返回地址
- 特点:函数调用时自动保存返回点
- 使用场景:函数调用与返回
2.3 栈指针(SP/R13)
- 功能:指向当前栈顶位置
- 作用:管理函数调用栈
- 应用:局部变量存储、上下文切换
2.4 通用寄存器(R0-R12)
- R0-R3:参数传递和返回值
// 这是Caller(调用者)函数
int main() {
int result;
// 调用calculate函数,main此时就是Caller
result = calculate(10, 20, 30, 40);
return result;
}
// 这是Callee(被调用者)函数
int calculate(int a, int b, int c, int d) {
// calculate被main调用,所以是Callee
return (a + b) * c / d;
}
对应的ARM汇编示例:
; Caller: main函数
main:
; 准备参数
MOV R0, #10 ; 第一个参数
MOV R1, #20 ; 第二个参数
MOV R2, #30 ; 第三个参数
MOV R3, #40 ; 第四个参数
; 调用calculate函数
BL calculate ; Branch with Link
; 使用返回值(在R0中)
MOV R4, R0
BX LR
; Callee: calculate函数
calculate:
; 保存寄存器
PUSH {R4-R11, LR}
; 使用传入的参数(R0-R3)进行计算
ADD R0, R0, R1 ; R0 = a + b
MUL R0, R0, R2 ; R0 = (a+b) * c
UDIV R0, R0, R3 ; R0 = ((a+b)*c) / d
; 恢复寄存器并返回
POP {R4-R11, PC}
-
R4-R11:局部变量
Stack Memory是栈内存
-
R12:IP(临时寄存器)
3. 栈操作详解
3.1 PUSH指令
- PUSH {R0-R3, LR} ; 将R0-R3和LR压入栈
- PUSH {R4-R11} ; 将R4-R11压入栈
- PUSH {R0-R3, LR} 的执行过程:
3.2 POP指令
- POP {R4-R11} ; 从栈中恢复R4-R11
- POP {R0-R3, PC} ; 从栈中恢复R0-R3,并返回
- POP {R4-R11} 的执行过程:
执行顺序:
3.3 BL指令
跳转到目标地址执行
将下一条指令的地址保存到LR寄存器(R14)中
常用于函数调用
工作过程:
- LR = PC + 4 (保存返回地址)
- PC = 目标地址 (跳转执行)
- 函数返回时使用BX LR指令返回
main:
; 其他代码
BL function1 ; 调用function1函数
; 继续执行
function1:
PUSH {LR} ; 保存返回地址
; 函数代码
POP {PC} ; 返回
PUSH用于将寄存器内容压入栈中进行保存,通常在函数开始时使用以保护现场;POP则相反,用于从栈中恢复寄存器的值,通常在函数返回前使用以恢复现场。BL (Branch with Link) 指令用于函数调用,它会在跳转到目标函数之前,将下一条指令的地址保存到LR寄存器中,这样函数执行完后就能知道返回到哪里继续执行。这三个指令的配合使用构成了ARM汇编中完整的函数调用框架,确保了程序可以正确地进行函数调用、现场保护和恢复,以及函数返回。
function:
PUSH {R4-R8, LR} ; 保护现场
BL other_function ; 调用其他函数
POP {R4-R8, PC} ; 恢复现场并返回
4. 常用ARM指令
4.1 数据移动指令
MOV R0, #1 ; 将立即数1移入R0
LDR R0, [R1] ; 从R1指向的内存加载到R0
STR R0, [R1] ; 将R0存储到R1指向的内存
4.2 函数调用示例
function:
PUSH {R4-R11, LR} ; 保存寄存器
; 函数体
POP {R4-R11, PC} ; 恢复寄存器并返回
; 调用函数
BL function ; 调用函数,自动保存返回地址到LR
5. ARM架构栈结构
5.1 栈的组成部分
- xPSR寄存器 (0x01000000)
- PC寄存器(任务函数地址)
- LR寄存器(任务错误返回地址)
- R12寄存器
- R3-R1寄存器
- R0寄存器
- EXC_RETURN
- R11-R4寄存器
- 从上到下地址依次降低(高地址→低地址)
- 硬件自动保存的寄存器在异常发生时会自动入栈
- 软件手动保存的寄存器需要在代码中显式保存
这种栈结构设计主要用于:
- 中断/异常处理时的上下文保存
- 任务切换时的现场保护
- 函数调用时的参数传递和返回
- 保证程序执行的连续性和正确性
栈的操作通过PUSH和POP指令完成,遵循先进后出(FILO)原则。
总结
本文详细介绍了ARM架构的核心概念,包括:
重要寄存器的功能和用途
栈操作的基本原理
常用指令的使用方法
实际应用场景
这些知识对于理解ARM架构程序执行流程、编写底层代码和驱动、以及程序调试和优化都具有重要意义
- 重要寄存器系统
通用寄存器(R0-R12):
R0-R3常用于函数参数传递和返回值
R4-R11为需要保护的寄存器
R12作为IP(临时)寄存器使用
特殊功能寄存器:
PC(R15): 程序计数器,指向下一条待执行指令
LR(R14): 链接寄存器,保存函数返回地址
SP(R13): 栈指针,维护栈空间
状态寄存器(xPSR):
包含条件标志位(N,Z,C,V等)
控制中断使能/禁止
处理器工作模式标志 - 栈操作机制
基本原理:
向下生长的满栈结构
支持8字节对齐操作
采用FILO(先进后出)原则
主要功能:
函数调用帧的建立和释放
局部变量的动态分配
寄存器现场的保存和恢复
中断和异常处理时的上下文切换
操作指令:
PUSH实现数据入栈
POP实现数据出栈
支持多寄存器同时操作
指令系统特点 - 数据处理指令:
MOV/MVN用于数据传输
ADD/SUB等算术运算
AND/ORR等逻辑运算
存储器访问指令:
LDR/STR实现字数据传输
LDRB/STRB处理字节数据
LDM/STM用于批量数据传输