资讯动态

FPGA软核开发中的JIC文件:从生成原理到固化实操

发布时间:2026/10/13 11:57:57 来源:尧图企业网站定制
大家做 FPGA 加软核嵌入式开发时应该都碰到过这样的场景软硬件全部调试通过板子一断电再开机整个系统像失忆一样回到初始状态又得重新插上下载线把程序灌一遍。原因其实不复杂调试阶段下载到板子上的 SOF 文件FPGA 配置数据和 ELF 文件处理器可执行程序都是加载到 SRAM 里的SRAM 是易失存储断电就清零。要让板子脱离计算机独立运行就必须把 FPGA 配置数据和软件镜像一次性固化到外部 Flash 里。这时候很多工程师会想到 JIC 文件也就是 JTAG Indirect Configuration File。很多人把它理解成“SOF 和 ELF 的打包器”大方向没错但打包并不是简单的拼接里面涉及 Flash 地址布局、启动地址对齐、Flash Loader 中转下载等一连串细节。这篇文章就按我实际调试的流程把 JIC 文件的生成原理、标准操作步骤和踩过的坑完整梳理一遍给正在做类似固化工作的同学一个可直接参考的版本。1. JIC文件是什么为什么非它不可1.1 三个文件的分工逻辑先说清楚三个文件各自是什么。SOF 文件是 FPGA 的配置比特流本质是一大串描述逻辑资源连接关系、查找表内容、布线通道开关状态的二进制数据。它通过 JTAG 或专用配置模式灌进 FPGA 后FPGA 里的可编程逻辑就按你的设计开始工作。但 SOF 写入的存储单元是 SRAM 型断电就丢所以调试阶段每次上电都要重新下载本质上是在把 FPGA 当成一块易失存储器反复使用。ELF 文件是处理器运行的程序镜像里面包含代码段、数据段、堆栈初始化信息以及调试符号表。调试时调试器把 ELF 逐段搬到内存里然后让 CPU 从复位向量开始执行。内存同样是易失的断电后程序区里的内容全部消失重新上电又是一张白纸。JIC 文件则是为“固化发布”设计的一种镜像容器。它同时包含三部分内容FPGA 配置数据、软件运行镜像、以及指导烧写流程的辅助信息。生成 JIC 后通过 JTAG 接口一次下载就能把 FPGA 配置和软件镜像同时写到板载 Flash 里。上电后配置逻辑先从 Flash 中把 FPGA 配起来处理器再从 Flash 中取指令运行整套系统不需要电脑干预就能启动。1.2 为什么要固化而不是继续用加载方式有人可能会想反正调试阶段 SOC 和 JTAG 加载都能跑我每次开机用脚本自动下载一次不就完了对于实验室验证固然可以但进入生产和现场部署阶段就不现实了。现场设备没有上位机、没有调试器甚至可能没有网口唯一可靠的启动方式就是让它从 Flash 自动加载。另外只烧 SOF 不烧 ELF 也不行。FPGA 启动后硬件搭好了但 CPU 没程序可跑。只烧 ELF 不烧 SOF 更不行上电后 FPGA 本来就是空的CPU 压根不存在。因此这两个镜像必须放在一起让启动流程按顺序完成。JIC 的价值就是把这两步揉成一步降低现场操作的复杂度和出错概率。还有一个容易被忽略的点如果在开发板上把 ELF 放到外部 RAM 里运行性能和便利性当然没问题但 RAM 的价格和容量都有限而且上电后 RAM 里的数据谁负责搬这个“谁负责”的问题最终还是要落到 Flash 里的启动代码头上。所以把程序固化和 FPGA 配置固化一起解决才是发版阶段的主路径。1.3 JTAG间接配置的核心原理JIC 里的“间接”两个字值得单独拿出来讲。JTAG 本身是边界扫描协议它可以直接操作 FPGA 内部的 SRAM 配置单元但不能直接写外部 Flash。那凭什么一个 JIC 文件通过 JTAG 下载器就能把数据写进 Flash 呢奥秘在于 Flash Loader。生成 JIC 时工具会在镜像里加入一段专用的 Flash 编程代理 IP。烧写流程启动后JTAG 链先把这段很小的代理 IP 临时配置进 FPGA就像先往 FPGA 里塞了一个中转站。接下来上位机通过 JTAG 发送原始的 Flash 地址和写入数据代理 IP 负责把数据转成对应 Flash 芯片的擦除、写入、校验时序完成烧录。整个过程中CPU 用户逻辑并没有参与Flash 也不是 JTAG 直接连接的。明白这一点后很多现象就解释得通了。比如为什么 JIC 烧写比 SOF 下载慢得多因为多了擦除和逐字节写入 Flash 的过程。比如为什么烧写前先要扫描到 FPGA因为代理 IP 得先配置进去。再比如为什么配置 Flash 型号必须选对因为代理 IP 要按对应芯片的指令集来组织时序型号一旦不匹配写进去的数据就是乱的。2. 生成JIC文件前的准备工作2.1 需要准备哪些输入信息动手转换 JIC 前先别急着打开工具把下面的信息核对一遍能省掉后面大量的排查时间。第一是 SOF 文件路径。通常是 FPGA 工程编译完成后在输出目录下生成的 .sof 文件比如output_files/xxx.sof。确认它是最终要发布的版本别拿旧工程编译结果充数。第二是 ELF 文件路径。这是软件工程编译后的可执行文件通常在软件工程的 debug 或 release 目录下。确认 ELF 对应最新代码而且是用发布配置编译的。调试版 ELF 往往包含大量调试信息体积大放进 Flash 可能放不下。第三是 Flash 型号和容量。这个必须查原理图或板卡手册而不是靠猜。常见的有串行配置 Flash 和通用 SPI NOR Flash容量从几兆位到上百兆位不等。选错型号轻则生成报错重则烧进去起不来。第四是处理器的启动地址Reset Vector。这项信息来自软件工程的 BSP 设置或链接脚本。它决定了 ELF 在 Flash 中的放置位置。很多人栽就栽在这里所以下一节展开说。2.2 启动地址最容易忽略的变量启动地址这个词在不同工具里叫法略有不同比如 Reset Vector、应用起始地址、Flash 偏移但表达的是同一个概念CPU 上电复位后第一条指令从哪里取。调试阶段程序已经由调试器放到了内存里所以把启动地址指向内存区间完全没问题。但发布版本里内存里没有程序启动地址必须指向 Flash 映射区域。而这个地址和 JIC 生成时填入的 ELF 偏移量必须严格对应。举个例子。如果软核处理器的 Flash 映射基地址是 0x00000000意味着复位后 CPU 会去访问地址 0x00000000 处的指令。那么 JIC 里 ELF 的偏移就该设为 0x00000000或者与链接脚本约定一致的值。如果 Flash 挂在一块通用内存控制器上基地址是 0x04000000那 ELF 偏移就要填 0x04000000。不同板子差异很大千万不要照抄别人的教程参数出手前先翻自己的 BSP 配置。这里有一个实用技巧在软件工程里把 Reset Vector 的配置截图存档再和生成 JIC 时的 Offset 字段对照。如果两者对不上哪怕只差一个字节上电后 CPU 取到的都是垃圾数据现象通常就是系统毫无反应或随机死机。重新检查配置比反复怀疑硬件可靠得多。2.3 一个典型工程的配置清单我自己在做这类固化工作时习惯先把配置清单列在一张表里再拿着它去工具里填写。下面是一个虚拟项目的例子参数只做示意实际数值以你们自己的工程为准。项目内容说明FPGA 型号某型号 FPGA从工程器件选型里获取SOF 文件release/xxx.sof最新发布的配置比特流ELF 文件sw_release/xxx.elf最新发布的软件镜像配置 Flash64Mb 串行配置 Flash见原理图 U3 位号SOF 偏移0x00000000配置数据区一般保持默认ELF 偏移0x00000000必须与 Reset Vector 一致压缩选项开启压缩后镜像体积明显减小输出文件release/xxx.jic给烧录使用的最终文件有了这张表后面所有操作都变成对照填参数逻辑清晰也不容易漏项。建议把这张表直接写进项目文档或者 Git 提交说明里过几个月再回来看仍然一目了然。3. 用IDE生成JIC文件的标准操作步骤3.1 打开转换编程文件面板JIC 转换功能通常在 FPGA 开发工具的上方菜单栏里入口一般叫 Convert Programming Files中文版可能显示为“转换编程文件”。它和下载烧录用到的 Programmer 不是同一个窗口注意别打开错。打开后面板结构大致分为两块左侧是输出设置区右侧是输入文件区。输出设置区决定生成什么格式、写进什么 Flash输入文件区决定镜像里包含哪些数据。下面按顺序操作。有一个细节值得提前说明不同版本的工具界面位置和名称会有差异但逻辑高度一致。如果你找不到某个选项优先看菜单栏里的“工具”或“文件”分类通常在那一块。3.2 设置输出格式与配置Flash型号第一步在输出格式下拉框里选择 JTAG Indirect Configuration File (.jic)。选这一项后工具会自动切换到 JTAG 模式一般情况下默认值即可。第二步找到 Configuration Device 或“配置器件”下拉框选择板卡上实际使用的 Flash 型号。这一步很关键它决定了 Flash Loader 代理 IP 的指令集。你选中的型号容量也会作为校验基准如果输入数据超过容量生成时会直接报错。第三步确认“Target Device”或者“FPGA 器件”列表里选中的型号和你工程编译的 FPGA 完全一致。多 FPGA 板卡上有多个目标时需要逐个确认。选错目标器件会导致配置数据不匹配下载时 FPGA 无法识别。这里多提醒一句如果板子上的 Flash 在列表里找不到不要强行选一个容量差不多的普通型号。正确的做法是先查工具支持的 Flash 列表再对照自己的型号做兼容性判断。如果实在找不到可以考虑换用同为 SPI 接口的兼容型号但一定要确认指令集和扇区结构一致否则可能出现烧写成功但启动失败的情况。3.3 挂载SOF与Flash Loader输出设置完成后进入输入文件区。先在空白区域添加目标 FPGA 设备然后把工程编译得到的 SOF 文件挂载到该设备下。常见操作是在文件名区域右键选择 Add File或使用界面上的 Add Device、Add File 按钮。挂载 SOF 后留意列表里是否自动出现 Flash Loader 这一行。有些版本直接内置并在后台应用有些版本需要手动添加。Flash Loader 的作用前面已经说过它就是写 Flash 时临时配置进 FPGA 的代理程序。假如列表里没有这一项可以尝试右键添加选择匹配目标 FPGA 的 Flash Loader 版本。SOF 的偏移地址在绝大多数情况下保持默认的 0x00000000 即可。这个地址表示配置数据放入 Flash 配置区的位置由配置控制器自动处理一般不需要工程师干预。真的需要调整时请先查器件手册确认配置起始地址的约束条件。如果 Flash 容量紧张建议勾选施加于 SOF 的压缩选项。压缩后的配置数据体积往往能减少一半左右读取速度还可能更快代价只是 FPGA 配置时多一次解压。对于容量不够放的工程这几乎是免费的优化。3.4 挂载ELF并设置偏移地址SOF 挂载完成后在同一个 FPGA 设备下继续添加 ELF 文件。添加后工具通常会自动识别 ELF 格式也会自动把它需要的数据段拆分处理。此时关注的重点是偏移地址字段。按照准备阶段查到的 Reset Vector在该字段填入对应数值。比如软核处理器的 Flash 基地址是 0x00000000就填 0x00000000。如果是其他基地址就填那个基地址。不同文件之间的偏移不要重叠否则生成时可能报错或者烧进去后数据互相覆盖导致启动失败。还有一个需要留意的点有些工具版本在添加 ELF 时会要求选择“软件镜像从 Flash 启动”还是“从内存启动”。务必选从 Flash 启动并且确保启动地址与 ELF 偏移一致。这个选项和 BSP 里的设置是联动关系只改这一处而不改另一处上电一样跑不起来。也可以勾选“生成 Memory Map File”选项让工具在输出 JIC 的同时生成一份 .map 文本文件。这份文件会列出每个文件实际占用的 Flash 地址区间用于校对非常好用强烈建议生成阶段勾上。3.5 生成并核对地址映射所有参数填写完毕后点击 Generate。工具开始打包过程可能需要几十秒到几分钟。完成后检查输出目录确认 .jic 文件已经出现。这时先不要急着拿出去烧录打开生成的 .map 文件看一下。重点核实两件事一是 SOF 和 ELF 的地址区间没有重叠二是 ELF 的实际起始地址与你设置的启动地址完全吻合。我自己的习惯是把 .map 文件和工程配置一起提交到版本管理之后排查问题直接打开它比在界面上反复点选高效得多。工具同时生成的一些中间文件比如 .hex 或 .bin一般不需要手动处理它们是转换过程中的中间产物。只需保证最终交付的 .jic 文件是从正确工程派生即可。4. 烧录与验证从JIC到板上运行4.1 下载JIC的完整流程生成 JIC 只是第一步真正放到 Flash 里还有一套流程。先连接好 JTAG 下载器保证板卡供电稳定。接着打开 Programmer 窗口在 Hardware Setup 里选择当前使用的下载器点击 Scan 或自动检测确保 FPGA 能在 JTAG 链上被识别出来。识别成功后在添加文件时选择刚生成的 .jic 文件。工具会自动把它映射到对应的配置器件和 FPGA。勾上 Program/Configure 选项点击 Start 开始烧写。烧写过程会比普通配置下载慢很多。原因前面已经解释过JTAG 要先在 FPGA 里配置 Flash Loader随后再以 Flash 芯片的底层协议完成擦除和写入。如果 Flash 容量大这个过程刷几分钟都正常中间千万不要拔线或断电否则 Flash 可能处于半擦除状态还得重新烧一遍。烧写完成界面上会显示成功提示。如果工具支持 Verify 选项建议烧完后再勾选一次 Verify把 Flash 里的内容和源 JIC 做一次回读比对。这一步成本很低但对发现烧录异常非常有价值。4.2 上电自启动验证方法烧写完成后断开 JTAG 线或者保持连接但重启板卡。上电后观察现象如果系统自动进入应用程序串口能打印出预期日志指示灯按设计流程点亮说明 JIC 里的 SOF 和 ELF 都工作正常。如果上电后 FPGA 有反应但 CPU 没有运行程序重要怀疑对象就是 ELF 偏移地址和启动地址不匹配。此时可以先把 JTAG 接回去用调试器连接 CPU 查看程序计数器的值。如果 PC 在一个奇怪地址停住或者指向非法区域基本可以确定是地址配置问题回去重新生成 JIC 即可。还有一种情况系统启动一半又复位或卡死。这时需要考虑 ELF 是否依赖某些外设初始化代码而该初始化代码在固化模式下提前执行导致的冲突。一般可以先看串口输出停在哪一行日志再定位是哪个外设初始化失败。这类问题大多属于软件启动流程问题和 JIC 转换本身关系不大但表现和地址错误有点像注意区分。4.3 几种典型烧录失败信号失败现象可能原因应对思路工具扫描不到 FPGAJTAG 链路断开、下载器未识别、板卡未上电检查硬件连接重启 Programmer 重新扫描烧录时报器件 ID 不符Flash 型号选错或目标器件选错核对原理图型号重新设置生成时报空间不足镜像体积超过 Flash 容量开启压缩、裁剪程序或改用更大容量 Flash烧录到一半中断供电不稳、下载线过长、温度过高改善电源缩短下载线降低工作环境温度烧录成功但上电无反应ELF 偏移、Reset Vector 未对齐或 Flash 内容异常用 .map 核对地址重新生成并回读校验能启动但程序频繁崩溃ELF 依赖 DMA/中断向量地址不一致检查软件链接脚本确认异常向量表位置这些只是最常见的一部分。大多数问题其实都能通过“先核对配置再检查硬件”的顺序解决。不要一上来就怀疑 Flash 芯片坏了很多时候只是工具里的某个下拉框选错了。5. 常见问题和排查经验速查表结合平时的调试经历我再补充几条容易掉进去的坑以及对应的处理办法。第一个坑Flash 型号只选容量不看接口。有些工程师在配置器件列表里看到容量一样的型号就直接选结果接口协议不同Flash Loader 发出去的命令完全不对。烧写过程可能正常完成但上电配置时序不对系统毫无反应。这种情况只能用正确型号重新生成 JIC再重新烧录。第二个坑ELF 偏移看都不看就填 0x00000000。前面强调过偏移必须和 CPU 启动地址一致。有的软核 BSP 里默认启动地址就是 Flash 基地址填 0 没问题但也有的工程把程序放在 Flash 内某个分区启动地址带了偏移量。这时候填 0 就会导致 CPU 读错位置。正确做法是打开 BSP 设置把启动地址原封不动抄进 JIC 的偏移字段。第三个坑压缩选项没有开启。在大容量 Flash 上这不算什么但如果 Flash 容量只有 16Mb而 SOF 本身就快 10Mb再加上 ELF 和数据很容易爆。开启压缩后镜像体积可能降到原来的 60% 甚至更低。代价是 FPGA 配置时会多花几十毫秒解压时间对绝大多数应用可以接受。第四个坑生产时没有删除调试信息。部分调试版 ELF 带着完整符号表和调试辅助数据体积比发布版大不少。如果一直拿 debug 版 ELF 打包等 Flash 容量报警时才发现来回折腾浪费时间。建议发布流程里固定使用 Release 配置编译的 ELF并在打包前检查文件大小。第五个坑只保留 JIC 不保留 .map。JIC 是个二进制容器直接打开看不出内容布局。过几天回来排查问题如果 .map 丢了你只能重新生成再对比。所以我把 .map 与 .jic 视同一对待改名归档放在同一个版本文件夹。6. 工程化命令行和自动化生成6.1 为什么推荐把JIC生成脚本化项目到了后期固件发布频率会逐渐提高每次都由工程师手工打开页面点选项既慢又容易出错。手工操作最大的隐患在于某一次发布时可能手滑选错 Flash 型号或者漏掉了一个文件的更新而 JIC 烧进产线设备后排查成本非常高。工具本身提供命令行转换入口常见的主程序名形如xxx_cpf具体名称以你安装的工具版本为准。命令行可以将图形界面里所有配置以参数形式传入例如设置输出 JIC、指定配置器件型号、选择 JTAG 模式、开启压缩等。这条命令可以直接写进 Makefile 或批处理脚本里。如果嫌命令行参数难记还有一个更稳妥的办法在图形界面里把设置保存为 .cof 转换工程文件。之后调用xxx_cpf -c 工程.cof就能按相同配置转换非常简洁。.cof 文件本质是文本可以放到版本管理里做差异对比谁改过什么一目了然。6.2 快速接入CI/版本发布团队协作开发时JIC 生成适合放到自动化构建流水线中。编译 FPGA 工程得到 SOF编译软件工程得到 ELF再调用命令行转换生成 JIC最后把 JIC 和 .map 作为发布产物归档。整个过程无需人工干预参数由代码仓库中的配置严格管控。接入流水线后还有一个额外好处每次构建都有唯一的时间戳或版本号可以将 SOF、ELF、JIC 的版本对应关系固化下来。以后若现场设备出现启动故障翻出当时的构建记录就能知道固件内容不用靠人脑记忆“上次是用哪一版软件打包的”。当然自动化也不要完全脱离备份。命令行生成前的 .cof 文件、源 SOF、源 ELF 都要一起归档。产线烧录时只拿 JIC 加一个烧录工装这样既保证一致性也降低了对个人经验的依赖。7. 我踩过的坑和最后的心得做 JIC 固化这几年最让我记忆深刻的一次是现场反馈设备无法自启动但用调试器手动加载 ELF 后系统完全正常。折腾了一整天最后发现是 JIC 里 ELF 偏移填错了。因为当时拿着旧版 BSP 的启动地址做参考而新版 BSP 改了链接脚本起始地址两个版本混用导致地址完全对不上。从那以后每次打包 JIC 我都会把 BSP 启动地址的截图和 .map 文件同时放进发布说明宁可多留信息也不要凭记忆操作。还有一个心得是JIC 生成后不要马上删掉中间文件。转换过程产生的 .map、.hex 甚至 .cof 文件在排查问题时价值极高。尤其是 .map 文件它就像一张行李清单告诉你哪个数据放在哪个地址。启动异常时打开它先做减法能排除一半以上的低级错误。如果你正在为 JIC 生成或上电启动卡壳建议先从“ELF 偏移等于 CPU 启动地址”这条铁律查起。核对完地址再检查 Flash 型号选没选对、压缩选项开没开、文件有没有拿错版本最后再考虑硬件层面。这套检查顺序我用了很久几乎能覆盖绝大多数问题。最后分享一个小习惯正式发布时把 SOF、ELF、JIC、MAP 四个文件放在同一个带版本号的目录里文件名加上日期或提交哈希。三个月后再有人问“这个板子该烧哪个镜像”直接把目录甩给他比任何文档都直观。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑