1、XIP概述:XIP的定义、工作原理、与传统加载执行方式的对比

1.1 什么是XIP?

XIP,全称 Execute In Place,中文叫“就地执行”。说白了,就是程序直接在存储芯片里跑,不用先搬到内存里。

我最早听到这个概念是在做 Nor Flash 驱动的项目时。当时客户要求代码直接在 Flash 上跑,我心想:“这不就省了 RAM 吗?” 嗯,确实省了,但坑也不少。

XIP 的核心是“CPU 可以直接通过地址总线访问存储介质,并把指令取出来执行”。存储介质本身要支持随机读取,而且读取速度得跟得上 CPU 的时钟——不然 CPU 就得等。

关键条件: 存储介质必须支持 字节/字随机访问,且 读取延迟 ≤ CPU 总线周期。

1.2 XIP的工作原理

你想想看,CPU 执行代码时,会通过地址总线发出指令地址。传统做法是:地址指向 RAM,RAM 里已经提前把代码从 Flash 拷过来了。XIP 不同——地址直接指向 Flash。

具体流程分三步:

  1. 地址映射: 系统上电后,存储控制器把 Flash 的某一地址段映射到 CPU 的地址空间。比如 0x0800_0000 ~ 0x0FFF_FFFF 对应 Flash。
  2. 取指: CPU 程序计数器 PC 指向这个映射区域,总线控制器直接把读请求发给 Flash。
  3. 执行: Flash 返回数据,CPU 译码执行。如果 Flash 有等待周期,CPU 会插入等待状态。

我记得有次调一个 STM32 的项目,RAM 只有 64KB,但固件有 200KB。没办法,只能把关键函数放到 Flash 里 XIP 执行。结果发现某些循环太慢,硬是等了好几个时钟周期。后来优化了代码布局,把频繁调用的函数放到 Flash 的前 16KB(该 Flash 支持 0-wait 区域),速度才上来。

我的小技巧: 如果 Flash 有“零等待区域”,尽量把热点函数放在那里。不过零等待区域通常只有前几 KB,需要手动分配。

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,结果发现 Flash 读操作会把 CPU 总线占死,导致中断响应变慢。解决办法是开启 Flash 的“预取缓冲区”和“指令缓存”,或者把中断向量表放在 RAM 里。千万不要直接默认 XIP 没副作用。

下面这张图是 XIP 与传统方式的流程对比,我习惯把它画成这种样子,方便向团队解释选型依据:

XIP 与 传统加载执行 对比流程 XIP vs 传统加载执行 流程对比 XIP 路径 CPU 发出地址 → Flash 映射区 Flash 直接返回指令 CPU 译码执行 传统加载执行路径 从 NAND/SD 读取代码块 DMA 拷贝到 RAM CPU 跳转到 RAM 入口执行 核心区别 XIP:Flash 直接映射到 CPU 地址空间,免去拷贝。 传统:先读后拷,RAM 大则速度快,但启动时间和功耗更高。

从图上能看出来,XIP 省了一个“拷贝到 RAM”的大步骤。但它对 Flash 的随机读取能力要求很高。传统方式虽然多了拷贝,但后续执行可以跑满速。

实际选型建议

  • RAM 极度受限(< 代码量 20%): 死心吧,必须 XIP。选 Nor Flash 或内置 Flash 的 MCU。
  • RAM 足够(> 代码量 2 倍): 传统加载执行更省心,性能更高。
  • 代码需要在线升级: 传统方式更好处理,但 XIP 也能做(需要双 Bank Flash 或 RWW 支持)。
  • 低功耗场景: XIP 有一定优势,因为 Flash 静态功耗远低于 RAM 保持功耗。
个人习惯: 我在做 IoT 设备时,如果 Flash 大于 1MB 且 RAM 只有 64KB,我默认选 XIP 方案,但会加上代码压缩或链接脚本优化,把中断和频繁调用的函数放在最快区域。比如 STM32L4 的 ART 加速器就是为 XIP 量身定做的。