FPGA 版本管理三种方式:你会选哪一种?

文章来源:OpenFPGA

FPGA 项目中也离不开版本号管理,不然“这是谁编的”、“板子上跑的到底是哪一版”常常让人头皮发麻。今天来聊聊三种常见方法。

为什么 FPGA 也要版本管理?

  • 一些 Bug 是新逻辑引起的,没版本号很难回溯。

  • FPGA 的 bitstream 文件版本往往难以一眼识别。

  • 软件/底层驱动调试时,FPGA 的版本混乱会导致调试成本翻倍。

方法一:Vivado 自动生成编译时间戳(最简单)

使用 Tcl 脚本,在每次生成 bitstream 时自动写入当前日期和时间。

关键步骤如下:

在工程中新建一个 version_date.v,内容类似:

parameter [31:0] FPGA_VERSION_A = 32'h20250831; // 日期
parameter [31:0] FPGA_VERSION_B = 32'h000000;   // 时间

写一个 Tcl 脚本(例如 update_version.tcl),在 synthesis 设置里设置路径,每次编译时更新 version_date.v:

set file_addr "../../version_date.v"
set time_now [clock seconds]
set time0 [clock format $time_now -format "%Y%m%d"]
set time1 [clock format $time_now -format "%H%M%S"]
set f [open $file_addr w]
puts $f "parameter [31:0] FPGA_VERSION_A = 32'h$time0;"
puts $f "parameter [31:0] FPGA_VERSION_B = 32'h$time1;"
close $f

把这个 version_date.v include 在顶层 Verilog 中:

assign version_date = FPGA_VERSION_A;
assign version_time = FPGA_VERSION_B;

每次上板调试时,在逻辑里或测试接口上读取这两个值,立刻知道这是哪天哪时编译的版本。

优点:全自动,连版本号都不用写,编译就更新

缺点:文件路径很容易搞错,尤其windows系统对文件路径不敏感,这种包含路径的方式不太好掌握

方法二:USR_ACCESS 嵌入 bitstream 编译时间戳(官方推荐)

Xilinx 官方支持在编译 bitstream 时,使用 BITSTREAM.CONFIG.USR_ACCESS 参数设为 TIMESTAMP,将编译时间自动写入配置带中的 32-bit USR_ACCESS 寄存器中 (https://docs.amd.com/v/u/en-US/xapp1232-bitstream-id-with-usr_access)。并且可以在 FPGA 逻辑中通过 USR_ACCESS 原语读出这个值。

具体流程:

在 Vivado GUI 中:Tools → Project Settings → Bitstream 中找到 BITSTREAM.CONFIG.USR_ACCESS,设置为 TIMESTAMP,然后重新生成 bitstream。

在设计中实例化 Xilinx 原语,例如:

wire [31:0] version_id;
USR_ACCESSE2 usr_access_inst (
    .CFGCLK(), 
    .DATA(version_id), 
    .DATAVALID()
);

在 FPGA 里添加一个控制寄存器或通过 JTAG/SPI 接口读取 version_id。

具体可查 Xilinx 应用文档 XAPP1232,有详细操作说明。

https://docs.amd.com/v/u/en-US/xapp1232-bitstream-id-with-usr_access

优点:

自动化——无需手动维护版本号。

信息精准——bitstream 里就带时间戳,不怕忘改。

方便查看——通过逻辑或软件很容易读取版本信息。

缺点:

信息固定为时间戳,不能嵌入 Git Hash 或语义化版本。

仍然需要自己部署读取逻辑。

方法三:自动注入构建信息(工程化最佳实践)

适合 CI/CD、团队项目的现代方法:在 build 流程中动态生成包含版本号和构建时间的 HDL 源文件,然后合入设计中。

// 自动生成文件 build_info.v
module build_info;
  localparam string GIT_HASH = "a1b2c3d";
  localparam string BUILD_DATE = "2025-08-30";
endmodule

通过脚本(shell、Python 等)在 cmake/Makefile 中获取 Git hash 和时间,然后写入:

echo "module build_info; localparam GIT_HASH = \"$HASH\"; localparam BUILD_DATE = \"$DATE\"; endmodule" > build_info.v

然后在主工程中用 include "build_info.v",就能读取版本标识。

优点:

信息最丰富(Git 提交号、日期、分支等都能写进去)。

自动化程度高,适合团队协作。

易于和软件版本同步。

缺点:

初次设置复杂,需要脚本支持。

跨平台(Windows/Linux)脚本兼容性要注意。

三种方式对比表

三种方式对比表.JPG

小结:怎么选最靠谱?

想省事?直接工程重命名就行,但随时可能“纠错成本爆表”。

想要自动、准确知道这板子是哪天编译的?选 USR_ACCESS 时间戳。

想和 Git + 软件版本同步,还希望未来做 CI/CD 打包?上自动注入源码方案。

记住一句话:“没有版本号的 FPGA 比 bit 还混乱。”“不做版本管理的 FPGA 工程,迟早要在调试现场跪下。”