Buck Blog · 博客正文

返回技术分享首页
fpga_golden 黄金恢复镜像 —— 完整设计与使用文档

fpga_golden 黄金恢复镜像 —— 完整设计与使用文档

一份关于 FPGA 黄金恢复镜像(Golden Recovery Image) 的完整说明:为什么需要它、它是怎么工作的、以及怎么构建和使用。基于项目 doc/design.md(设计唯一依据)与 RTL / 固件实现整理。


一、为什么需要它(实现必要性)

现场部署的 FPGA,固件(bitstream)迟早会更新。更新有两种方式:

  • 在线重配置:把新位流写进 SPI Flash,重启后配置引擎从 Flash 读新位流加载。
  • 远程升级:通过网口把新位流下发、写入 Flash。

但这里有个致命风险:如果 update 位流本身是坏的、或写到一半断电、或缺失了,板子上电时配置引擎读不到可用的 update 位流,整块板子就"砖"了——没有任何网络通道、没有任何手段能把板子救回来,只能拆机用 JTAG 手动救。

fpga_golden 就是来解决这个问题的:

它是一份住在 SPI Flash 0x0 的、极简且永不远程更新的"黄金恢复镜像"。当 update 镜像(0x400000)缺失或损坏时,golden 会拉起一个网页恢复通道,让你通过网口把 update 位流重新烧进 Flash,然后跳回 update。

设计上它满足三个硬性要求:

原则 含义
极简 只保留恢复所需的最小能力(网口 + flash 写 + 跳转),砍掉一切无关外设
冻结 一旦验证通过就永不远程更新——否则 golden 自己出 bug 就无路可退
通用 update 镜像可以是任意东西(纯逻辑 / RISC-V / DSP),golden 是通用恢复层,不绑定具体应用

关键机制依托 FPGA 原生的 MultiBoot + Fallback:Xilinx 7 系列支持"主镜像失败时硬件自动回退到 fallback 镜像",golden 正是利用这一点把自己做成"永远能兜底"的那一层。


二、硬件平台

项 值
器件 XC7A35T-FGG484-2(Artix-7,无硬核)
板卡 ACX750,RGMII 网口(RTL8211E PHY)
Flash MX25L12845(128Mbit = 16MB,SPI Mode 0,JEDEC ID C2 20 18)
时钟 50MHz 输入,PLL 出 50 / 125MHz

三、Flash 布局(16MB)

地址 内容 远程可写
0x000000 Golden 镜像(~2.2MB,固件烘焙进位流) ❌ 永不
0x400000 Update 位流槽(~2.2MB) ✅
0x800000 RISC-V firmware(update 用) ✅
0x820000 HTML 页面 ✅
0xC20000 配置 + boot flag ✅

位流长度 XC7A35T ≈ 17.5Mb ≈ 2.2MB,4MB 槽位足够。注意 0x0 这一格物理上不提供远程写(DMA 有地址白名单硬保护),保证 golden 自己绝对安全。


四、启动链(MultiBoot + Fallback + 60s 窗口)


上电 → 配置引擎读 0x0(golden) → RISC-V 启动 → 60s 倒计时
  ├─ 网页「停倒计时」→ 留在 golden 配置 flash
  ├─ 网页「跳 update」→ 立即 IPROG
  └─ 超时 → IPROG 跳 update(0x400000)
        ├─ 成功 → update 跑起来
        └─ 失败 → 硬件 Fallback 弹回 golden
                  → 读 BOOTSTS 检测到 fallback → 停住(不跳,避免震荡)

bitstream 属性(Golden 与 Update 都设):


set_property CONFIG_MODE SPIx1                        [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1          [current_design]
set_property BITSTREAM.CONFIG.CONFIGFALLBACK Enable   [current_design]

几个关键点:

  • SPI x1:XAPP1247 要求 fallback 只走 x1,Golden/Update 的 SPI_BUSWIDTH 必须一致。
  • 跳 update 用 ICAP IPROG(固件写 WBSTAR=0x400000),因此不设 NEXT_CONFIG_ADDR。
  • 双镜像烧写:gen_multiboot_mcs.tcl 生成 golden@0x0 + update@0x400000 的 .mcs。
  • update 位流要求:update 应用位流须在其自身工程里设同样的 SPIx1 + CONFIGFALLBACK。
  • barrier/timer 镜像(后续增强):防止 update 写一半断电(同步字缺失)导致上电扫全片死机。

五、系统组成(Golden SoC)

5.1 golden 自己(rtl/,薄一层)

  • golden_xc7a35tfgg484_top.v — 顶层(PLL + RGMII + MAC + RISC-V + lcpu_sflash + flash 写 DMA + ICAPE2 + 精简 reg_webserver + STARTUPE2)
  • flash 写 DMA 引擎
  • ICAPE2 + IPROG 触发 + BOOTSTS 读取
  • 精简版 reg_webserver

相对 fpga_webserver 砍掉的:SFP 1000BASE-X(eth1/eth2)、ILA 调试、MAC 白名单、多口 L2 桥。

5.2 共用库(build 时 clone + 锁版本)

ip_common / ip_riscv / fpga_cpu / ip_lcpu

5.3 golden 拷贝(非共用库)

  • pll_50m.xci(从 fpga_webserver/ip_vendor 拷,Vivado 自动重生成)
  • gig_ethernet_pcs_pma_0 不拷(SFP 用不到)

六、实现原理

6.1 ICAPE2 IPROG(热启动到 update)

FPGA 的 ICAPE2 原语可以在运行中通过内部配置端口下发 IPROG 命令,让 FPGA 立即重新从 Flash 指定地址加载位流——这是 golden 能"跳回 update"的核心机制。

golden 的 icap_iprog.v 封装了两个操作:

操作 触发寄存器 作用
iprog_trigger WC 写 0x14 写 WBSTAR=0x400000 + IPROG 命令 → 热启动到 update 镜像
bootsts_read WC 写 0x15 读 BOOTSTS(0x16) → 固件据此判断是否 fallback 弹回

关键实现细节:ICAPE2 的 I[31:0] 是 LSB-first(I[0] 先发),逻辑配置字需整字 32bit 位反转后写入。IPROG 写序列:


DUMMY → SYNC → NOOP → 写 WBSTAR(0x00400000) → NOOP → 写 CMD → IPROG(0x0F)

(代码里的 W_WBSTAR_V = 32'h00000200 等常量都是预反转后的总线值。)

6.2 BOOTSTS 读取(Fallback 检测)

当 update 位流损坏、配置失败时,FPGA 硬件会自动 Fallback 回 golden。golden 启动后读 BOOTSTS 寄存器(0x16)的 fallback 位,就能知道自己是被"弹回来"的:

  • 检测到 fallback → 停住,不再跳(否则会 update→fallback→update 无限震荡)。
  • 未检测到 fallback → 正常走 60s 倒计时 → 跳 update。

6.3 Flash 写 DMA

golden 的 flash 写走硬件 DMA,而不是 RISC-V 逐字节怼 SPI(那样会把 CPU 占死,且无法做进度条)。

项 值
接口 写 FIFO + 状态(busy / done / error / 已写字节数 / FIFO 空满)+ 命令(地址+长度+go)
内部缓冲 1KB(4 页)
命令 erase(block erase 0xD8)+ program(page program 0x02,页内 256B 不跨页)
时钟/CDC 复用 spi_clk_bl 5MHz,照抄 spi_bootloader 的 4 相位握手 + 5MHz 域
背压 FIFO 满 → RISC-V 停塞 → 停 ACK → 客户端限速

选 DMA 的三个理由:① 进度条(RISC-V 不被 SPI 占死);② 固件更简单(只塞 FIFO + 查状态);③ 复用 spi_bootloader 成熟架构。SPI 先 5MHz,不提频。

6.4 恢复固件 + 网页

固件是 bare-metal C(复制 fpga_webserver 的 eth/arp/ip/icmp/tcp/http.c,独立优化解耦),新增 recovery.c + flash_dma.c,烘焙进 InstructRAM(走 XPM MEMORY_INIT_FILE,不走 Flash)。

HTTP 端点:

端点 作用
GET / 恢复页
POST /flash 4KB 分块上传写 flash
POST /boot ICAPE2 IPROG 跳 update

网页功能:选段下拉 + 文件选择 + 上传 + 两段进度(擦除% / 写入%)+ 停倒计时 + 跳 update 按钮。

bit-swap:用户上传 write_cfgmem -format bin 出的 .bin(已经 bit-swap 好)。

管理 IP:固定 192.168.1.158(不读 config flash,杜绝恢复时又依赖 flash)。

6.5 流式上传(4KB 分块 + 应用层 ACK)

bare-metal TCP 没有流控,2.2MB 会溢出 8KB 包缓冲。解决办法:

  • 浏览器 JS 把文件切 4KB 一块,每块一个 HTTP POST。
  • RISC-V 写进 flash 后回 OK,浏览器再发下一块。
  • 应用层 ACK 天然对齐 flash 写速度,实现背压。

6.6 校验与安全

  • bitstream 段:读回同步字(bit-swap 后 0x5599AA66)+ 全量 CRC。
  • firmware/html:CRC。
  • 0x0 段:从网页选段列表物理移除,DMA 加地址白名单硬保护。

七、使用方法

7.1 编译恢复固件


cd c_build
make PLATFORM=xilinx riscv_reset_addr=0xf TCL_BASE=0x8000 all

产物:out/firmware.elf/.bin/.pads.bin、../rtl/InstructRAM.mem/.hex/.v、../tcl/InstructRAM.tcl 等。

7.2 构建位流


cd build_xilinx_xc7a35tfgg484
./build_fpga.sh 0007    # 版本号 1~4 位十六进制

脚本自动:clone 共用库 → 生成版本化项目目录 golden_xilinx_xc7a35tfgg484_v0007_<时间戳>/ → 拷 RTL/约束 → Vivado 综合 + 实现 + 出 .bit。

7.3 生成双镜像 .mcs

用 tcl/gen_multiboot_mcs.tcl 生成 golden@0x0 + update@0x400000 的 .mcs(烧写用)。

7.4 烧录

  • 开发调试:JTAG 直接下载 .bit。
  • 正式部署:把双镜像 .mcs 烧进 SPI Flash(0x0 是 golden)。

7.5 恢复操作流程(现场)

  • 板子上电,golden 从 0x0 加载,RISC-V 启动,开始 60s 倒计时。
  • 电脑接网口,浏览器访问 http://192.168.1.158。
  • 打开恢复页,可「停倒计时」留在 golden 里配置 flash。
  • 选段(update 位流槽 0x400000 / firmware / html / config),上传 .bin 文件。
  • 看两段进度(擦除% / 写入%)直到完成。
  • 点「跳 update」→ IPROG 立即重配置到 update 镜像。
  • 若 update 又坏 → 硬件 Fallback 弹回 golden,读 BOOTSTS 停住,回到步骤 2 重新烧。

八、工程结构


fpga_golden/
├── rtl/                         # golden 专属 RTL
│   ├── golden_xc7a35tfgg484_top.v   # 顶层
│   ├── golden_wrapper.v             # SoC 封装
│   ├── icap_iprog.v                 # ICAPE2 IPROG + BOOTSTS
│   ├── flash_mem_reader.v           # flash 读路径(内存映射读)
│   ├── reg_golden.v / reg_golden.xls  # 寄存器文件(xls 是源,v 由工具生成)
│   ├── cpu_channel.v                # 包 FIFO / 通道
│   └── InstructRAM.mem/.hex/.v      # 固件烘焙产物
├── c/                          # 恢复固件(TCP/IP 栈 + recovery + flash_dma + http)
├── c_build/                    # 固件构建(Makefile + bin→mem/tcl 工具)
├── sim/                        # 仿真(flash 写 DMA)
├── tcl/                        # JTAG 加载脚本
├── doc/design.md               # 设计规格(唯一依据)
├── ip_vendor/                  # 拷贝的厂商 IP(pll_50m)
└── build_xilinx_xc7a35tfgg484/ # Vivado 构建脚本 + 约束 + filelist


九、分阶段进度与已知问题

Phase 内容 状态
0 建骨架(目录 + 构建脚本 + clone 共用库) ✅ 完成
1 Golden SoC RTL(顶层 + ICAPE2/IPROG + BOOTSTS) ✅ 完成
2 Flash 写 DMA ✅ 完成
3 恢复固件 + 网页(分块上传) ✅ 完成
4 联调写链路 ⏳ 联调中
5 MultiBoot + Fallback(双镜像 .mcs + x1 + barrier) ⏳ 待做

已知待办/坑(截至 2026-08):

  • BOOTSTS 的 fallback 位(BOOTSTS_FALLBACK_BIT)占位,需上板校准。
  • 软件写 flash 速度慢(当前走 5MHz SPI,未提频)。
  • 恢复页内嵌 http.c、Content-Length 写死等历史问题已在修。
  • 真机联调中发现过「sw_build_date(0x02) 寄存器读 0」问题,正在定位(疑似第一条外部 store 丢失或读 mux,而非综合误裁)。

十、关键决策记录

决策点 结论
golden 角色 住 0x0 的黄金恢复镜像(非独立烧写工具)
启动行为 有 update 跳、无/坏停 golden(MultiBoot+Fallback)
进 golden 上电 60s 倒计时窗口,网页可停/可立即跳
fallback 震荡 读 BOOTSTS 检测 fallback → 停住,不跳
update 烧写能力 不带(A 方案,golden 通用)
可烧地址段 0x400000 / 0x800000 / 0x820000 / 0xC20000,0x0 排除
bit-swap 用户上传 Vivado 生成的 .bin
flash 写路径 硬件 DMA(写 FIFO + 状态,erase/program 两条命令)
SPI 时钟 5MHz(不提频)
流式上传 4KB 分块 + 应用层 ACK
管理 IP 固定 192.168.1.158

附:关键寄存器速查

地址 寄存器 说明
0x00 fpga_build_date 硬件位流合成日期(烤进位流)
0x01 fpga_build_time 硬件位流合成时间
0x02 sw_build_date 软件固件编译日期(固件启动时写)
0x03 sw_build_time 软件固件编译时间
0x14 REG_ICAP_IPROG WC 触发 IPROG 跳 update
0x15 REG_ICAP_BOOTSTS_RD WC 触发读 BOOTSTS
0x20 REG_ICAP_BOOTSTS BOOTSTS 值
0x21 REG_ICAP_BOOTSTS_VALID BOOTSTS 读取有效标志

本文档整理自 fpga_golden/doc/design.md(设计唯一依据)与项目 RTL/固件实现,供理解、复现与使用参考。