1、XIP概述:XIP的定义、工作原理、与传统加载执行方式的对比
1.1 什么是XIP?
XIP,全称 Execute In Place,中文叫“就地执行”。说白了,就是程序直接在存储芯片里跑,不用先搬到内存里。
我最早听到这个概念是在做 Nor Flash 驱动的项目时。当时客户要求代码直接在 Flash 上跑,我心想:“这不就省了 RAM 吗?” 嗯,确实省了,但坑也不少。
XIP 的核心是“CPU 可以直接通过地址总线访问存储介质,并把指令取出来执行”。存储介质本身要支持随机读取,而且读取速度得跟得上 CPU 的时钟——不然 CPU 就得等。
1.2 XIP的工作原理
你想想看,CPU 执行代码时,会通过地址总线发出指令地址。传统做法是:地址指向 RAM,RAM 里已经提前把代码从 Flash 拷过来了。XIP 不同——地址直接指向 Flash。
具体流程分三步:
- 地址映射: 系统上电后,存储控制器把 Flash 的某一地址段映射到 CPU 的地址空间。比如 0x0800_0000 ~ 0x0FFF_FFFF 对应 Flash。
- 取指: CPU 程序计数器 PC 指向这个映射区域,总线控制器直接把读请求发给 Flash。
- 执行: Flash 返回数据,CPU 译码执行。如果 Flash 有等待周期,CPU 会插入等待状态。
我记得有次调一个 STM32 的项目,RAM 只有 64KB,但固件有 200KB。没办法,只能把关键函数放到 Flash 里 XIP 执行。结果发现某些循环太慢,硬是等了好几个时钟周期。后来优化了代码布局,把频繁调用的函数放到 Flash 的前 16KB(该 Flash 支持 0-wait 区域),速度才上来。
1.3 与传统加载执行方式的对比
传统加载执行(Load-and-Execute)是什么?就是程序从慢速存储(如 NAND Flash、SD 卡)读到 RAM 里,再在 RAM 里执行。XIP 直接省掉了“读-搬-跳”这个过程。
我列个表对比一下,你一眼就能看出区别:
| 对比项 | XIP | 传统加载执行 |
|---|---|---|
| 存储介质 | Nor Flash、PCM、MRAM 等支持随机读 | NAND Flash、SD 卡、硬盘等块设备 |
| RAM 需求 | 仅需少量 RAM(堆栈、变量) | 需要完整拷贝代码到 RAM,RAM 大小至少 ≥ 代码体量 |
| 启动延迟 | 短(上电后直接跳到 Flash 入口) | 长(需先从存储读到 RAM,再跳转) |
| 执行速度 | 受 Flash 读取速度限制,通常比 RAM 慢 1~5 倍 | RAM 执行速度快,但受限于拷贝时间 |
| 代码更新 | 需支持擦写映射区域,复杂 | 简单,直接覆盖存储介质即可 |
| 功耗 | 较低(省去频繁拷贝,Flash 静态功耗小) | 较高(DMA 拷贝、RAM 读写功耗) |
为什么要关心这个对比?
我碰到过不少选型错误。有人把代码量很大的应用放在 Nor Flash 里 XIP,结果 Flash 速度跟不上 CPU,系统频繁等待。也有人为了省 RAM 硬上 XIP,结果 Flash 写入时不能执行代码(RWW 问题),导致 OTA 失败。
一个典型的权衡场景:
- 如果 RAM 够用(≥ 代码量 2 倍),传统加载执行更简单、更快。
- 如果 RAM 紧张(比如 64KB RAM 装不下 200KB 代码),XIP 几乎是唯一选择。
- 如果代码需要频繁更新(OTA),传统方式更友好,因为可以在后台直接写 Flash,而不影响当前执行。
下面这张图是 XIP 与传统方式的流程对比,我习惯把它画成这种样子,方便向团队解释选型依据:
从图上能看出来,XIP 省了一个“拷贝到 RAM”的大步骤。但它对 Flash 的随机读取能力要求很高。传统方式虽然多了拷贝,但后续执行可以跑满速。
实际选型建议
- RAM 极度受限(< 代码量 20%): 死心吧,必须 XIP。选 Nor Flash 或内置 Flash 的 MCU。
- RAM 足够(> 代码量 2 倍): 传统加载执行更省心,性能更高。
- 代码需要在线升级: 传统方式更好处理,但 XIP 也能做(需要双 Bank Flash 或 RWW 支持)。
- 低功耗场景: XIP 有一定优势,因为 Flash 静态功耗远低于 RAM 保持功耗。