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/固件实现,供理解、复现与使用参考。