打印
[应用方案]

Cortex-M内核知识点总结

[复制链接]
4395|105
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
总览
Cortex内核 基础寄存器组


  • 程序在经过编译后,生成可执行二进制文件,如上图,是截取某个函数在flash中存储的内容 (反汇编文件)



使用特权

评论回复
沙发
米多0036|  楼主 | 2023-9-15 12:07 | 只看该作者
可以看到以下信息:
指令的存储地址 ,指令的二进制内容 , 指令代表的汇编类容
指令存在32位指令和 16位指令 ,具体可参考权威指南中的 :Thumb指令集 和 ARM指令集

使用特权

评论回复
板凳
米多0036|  楼主 | 2023-9-15 12:08 | 只看该作者
此函数的执行过程细节:
PC指针指向函数开始执行地址 0x0800d130 , 内核的取指单元根据地址,将内容 f24754a0 由flash读取到内核
译码单元翻译 f24754a0 ----> MOV r4 , #0x75a0 , 可以看出二进制格式和汇编是相关的,内核存在一套译码规则,比如 f2 表示 MOV
执行单元执行此指令 ,将立即数 0x75a0 存到 通用寄存器 R0
PC 增加,继续上述过程,直到整个函数执行完成

使用特权

评论回复
地板
米多0036|  楼主 | 2023-9-15 12:29 | 只看该作者

使用特权

评论回复
5
米多0036|  楼主 | 2023-9-15 12:30 | 只看该作者

使用特权

评论回复
6
米多0036|  楼主 | 2023-9-15 12:30 | 只看该作者

使用特权

评论回复
7
米多0036|  楼主 | 2023-9-15 12:30 | 只看该作者
指令流水线

使用特权

评论回复
8
米多0036|  楼主 | 2023-9-15 12:31 | 只看该作者
流水线的引入充分利用到了3个指令控制单元,提高了指令处理效率,同时也引入了一些问题。在时钟周期1完成了指令1的取指 ,在时钟周期3才执行指令1,若指令1是个条件分支语句 ,那个指令1的下一条指令是不确定的,这时候内核的取指2和取指3 是进行分支预测的,若预测失败,那么这两次的预先取指将无效,将花费更多的时间重新取指,因此在写if else 时,尽可能将最大可能发生的条件放在首位,这样能减小分支预测错误的概率。

使用特权

评论回复
9
米多0036|  楼主 | 2023-9-15 12:35 | 只看该作者
复位序列
启动文件分析
栈与堆空间分配 (在不使用标准库中的malloc时,堆空间被优化)

使用特权

评论回复
10
米多0036|  楼主 | 2023-9-15 12:35 | 只看该作者
中断向量表

使用特权

评论回复
11
米多0036|  楼主 | 2023-9-15 12:35 | 只看该作者
复位处理函数

SystemInit : 初始化时钟,初始化中断向量表偏移
__main
将未初始化内存区(.BSS or ZI)清零
调用下面的堆栈初始化函数 __user_initial_stackheap
进入main函数

使用特权

评论回复
12
米多0036|  楼主 | 2023-9-15 12:36 | 只看该作者

使用特权

评论回复
13
米多0036|  楼主 | 2023-9-15 12:36 | 只看该作者
堆栈初始化函数

使用特权

评论回复
14
米多0036|  楼主 | 2023-9-15 12:36 | 只看该作者
复位过程

使用特权

评论回复
15
米多0036|  楼主 | 2023-9-15 12:37 | 只看该作者
中断向量表的存储地址 0x08000000 + 4 , 0x08000000存储的为MSP的值 , ARM会将flash的0地址自动映射到 0x8000000。这里有一个需要思考的问题, 为什么需要将MSP的初值放到0地址?这个初值又是多少?原因如下:

在Reset_Hander中 , 首先会调用 SystemInit 函数,这是一个C函数,且函数里边还会调用其他函数,此时汇编文件中的栈还未进行初始化(_main), 因此需要一个栈空间来保存函数调用过成,仿真可发现 初值MSP是一段内存0x20000000很靠前的一个地址,MSP会零时使用此值,待SystemInit 执行完后归还,在调用 __main后 MSP的值初始化成map文件中的值。

使用特权

评论回复
16
米多0036|  楼主 | 2023-9-15 12:37 | 只看该作者
数据结构-栈

使用特权

评论回复
17
米多0036|  楼主 | 2023-9-15 12:37 | 只看该作者
走迷宫的过程:

每次经过一个分叉口 , 给分叉口一个编号 , 选择一个岔路口走下去
循环上诉过程,直到走出迷宫,或者走到死路
若走到死路,则根据记录的信息,回退到上一个岔路口,走之前未选的岔路 , 循环直到走出迷宫或者走到死路
重复此过程,直到找到出口

使用特权

评论回复
18
米多0036|  楼主 | 2023-9-15 12:37 | 只看该作者
/*函数调用过程与走迷宫类似,下面的函数 func1在执行过程中 , 会打断当前执行流程,去执行func2 ,
去执行func2前,应该记录当前func1的执行环境,如记录c的值 ,记录参数a和b , 当func2执行完后,
要退回func1继续执行*/

uint16_t func1(uint8_t a , uint8_t b)
{
    uint16_t c = 0;
    c = a + b;           /*a 和 b 作为参数 通过 R0 和 R1传递 , 计算结果会存在 R0 , R1 , R3*/
    func_2(c);           /*在跳转执行func2 前 , 参数 a ,b ,c 需要保存 ,*/
    return c;
}

void func2(uint16_t d)
{
    uint32_t e;
    e = d*d +2*d;
}

使用特权

评论回复
19
米多0036|  楼主 | 2023-9-15 12:37 | 只看该作者
栈在内存中的地方

使用特权

评论回复
20
米多0036|  楼主 | 2023-9-15 12:37 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

128

主题

1392

帖子

0

粉丝