计算机基本组成:控制器(Controller)、运算器(ALU)、存储器(Memory)、输入设备(Input)和输出设备(Output)。
控制器&运算器->中央处理单元(CPU)。
嵌入式微控制器(MCU)中的运算器和控制器->内核(Core)。
取指(Instruction Fetch)(IF)
解码(Instruction Decoding)(ID)
指令执行(Execution)( EX)
低端的内核比如 Cortex M0 / M0+, M3 和 M4 上, EX 是一个独立的流水线阶段,此时, IF、 ID 和 EX就组成了最基本的三级流水线结构;在追求指令吞吐量的内核流水线上,指令的执行(EX)往往被进一步的拆分以追求流水线的效率。
ARM Cortex M0/M0+和M1都是冯诺依曼结构的内核。
程序的顺序执行是指内核 IF 阶段顺着存储器的地址依次读取指令并执行的过程,如果中途因为某些
原因突然跳转到别的地址去执行,这就叫程序的分支(Branch)。
IF 阶段从什么地址读取指令是由 PC 指针控制的,修改其值就可以实现程序的分支。
(DE->ID)。
流水线分支指令之后、目标指令执行之前引入额外的两个周期延迟——其实内核从未停歇,只不过排空流水线内已有的内容需要时间而已——三级流水线需要 2 个时钟周期,以此类推, 5 级流水线就需要 4 个时钟周期。
函数返回地址的保存:
1. 返回点的地址压栈;
2. 修改 PC 指针,跳转到目标地址执行;
3. 返回时,直接将返回地址从栈中弹出到 PC 指针,实现函数的返回。
叶子函数:一个子函数(subroutine)不再调用别的函数。
热点:指大量占用处理器时间的代码小片段。
LR(Link Register):专门用于保存函数的返回地址。 LR 本质上相当于一个深度为 1 的硬件栈,支持且仅支持 1 级函数调用。
LR 是内核提供的一个辅助寄存器,在函数调用和返回时时是否对其进行压栈和出栈完全由编译器决定。因为只有编译器知道目标函数是叶子函数还是普通函数,所有的调用都是编译器事先计划好的(在“编译时刻”就确定好的)。
内核对叶子函数的调用过程如下:
1. 将返回点的地址放入 LR 中(这是由跳转指令自动完成的);
2. 修改 PC 指针,跳转到目标地址执行(这实际上也是同一条跳转指令完成的);
3. 返回时,直接将 LR 的值赋值给到 PC 指针,实现函数的返回。
在 ARM Cortex M 指令集中, B 表示跳转 branch; BL 表示跳转到固定地址,并自动将返回地址保
存到 LR 寄存器中; BX 表示根据寄存器进行跳转,这里的 X 指代寄存器; BLX 表示跳转到由寄存器指定的地址,并自动将返回地址放入 LR 寄存器。
非叶子函数的调用过程如下:
1. 将当前 LR 的值压栈;
2. 将返回点的地址放入 LR 中(这是由跳转指令自动完成的);
3. 修改 PC 指针,跳转到目标地址执行(这实际上也是同一条跳转指令完成的);
4. 返回时,直接将 LR 的值赋值给到 PC 指针,实现函数的返回;
5. 将先前保存在栈中的 LR 值出栈。
ARM Cortex M 系列( M0+开始)
权利约束的角度:
“特权(Privileged)操作”:拥有最高的自由度,可以访问所有的系统资源;
“非特权(Unprivileged)操作” :受到了严格的限制,不仅针对普通地址空间的访问要受到 MPU 的重重审核,针对内核特殊功能寄存器的访问也受到了全面的禁止。
工作模式角度:
异常/中断处理的“(异常)处理模式(Handler Mode)”:所有的操作都是“特权操作”
普通代码执行的“线程模式(Thread Mode)” :操作可以被指定为“特权”或“非特权”。
对于RTOS 的应用场景,“线程模式”用于执行用户任务,通常运行在“非特权”模式下,以确保任务在规定的安全范围内执行,而不会影响其它任务乃至整个系统;“(异常)处理模式”主要提供给 RTOS 的系统代码使用,用于完成上下文切换、调度、资源管理等系统级任务。