文章来源: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)脚本兼容性要注意。
三种方式对比表
小结:怎么选最靠谱?
想省事?直接工程重命名就行,但随时可能“纠错成本爆表”。
想要自动、准确知道这板子是哪天编译的?选 USR_ACCESS 时间戳。
想和 Git + 软件版本同步,还希望未来做 CI/CD 打包?上自动注入源码方案。
记住一句话:“没有版本号的 FPGA 比 bit 还混乱。”“不做版本管理的 FPGA 工程,迟早要在调试现场跪下。”