Vivado 实战精要:FPGA 资源利用率优化
在 Vivado 使用过程中,FPGA 资源利用率从来不是'交给工具就行'的事。尤其是在通信、图像处理、AI 边缘推理等高性能需求场景下,有限的 LUT、FF、BRAM 和 DSP 资源,往往成了决定项目成败的关键瓶颈。
一、别让组合逻辑吃掉你的 LUT 池子
为什么同样的功能,有人只用 200 个 LUT,你却用了 600 个?根源往往不在算法本身,而在写的那一行 always 块里。
LUT 是怎么被浪费的?
查找表(LUT)是 FPGA 实现组合逻辑的基本单元。在 7 系列或 UltraScale 架构中,通常是 6 输入 LUT——意味着它可以实现任意一个最多 6 个输入变量的布尔函数。一旦逻辑太复杂,就得多个 LUT 级联,路径变长,资源翻倍。
来看一个经典反例:
// ❌ 危险写法:条件运算全塞进时序逻辑
always @(posedge clk) begin
if (sel)
out <= a + b;
else
out <= c + d;
end
这段代码看似简洁,但综合器会怎么做?它必须把两个加法器都保留,并在寄存器前加一个多路选择器(MUX)。也就是说,无论 sel 当前值是什么,两个加法操作都要准备好结果。这就导致了逻辑冗余:明明同一时间只需要一个加法结果,却占用了两套计算资源。
✅ 正确姿势:把'选哪个'提前到组合逻辑层
wire sum1 = a + b;
wire sum2 = c + d;
assign out_comb = sel ? sum1 : sum2;
always @(posedge clk) begin
out <= out_comb;
end
这样改之后,加法仍在组合逻辑完成,但关键在于——后续流程有机会进行资源共享。如果这两个加法出现在不同分支且不会同时激活(比如来自不同状态机状态),综合器就可以尝试将它们复用为同一个加法器,通过时间分片调度。
这时候再配合一句 Tcl 命令:
set_property max_fanout 10 [get_nets sum1]
或者启用 -resource_sharing 选项,就能进一步引导工具识别可共享的操作。
提示:
synth_design -resource_sharing auto是面积敏感设计的标配。但它不会对所有情况生效——前提是你的 RTL 结构允许共享。这就是为什么'写法'比'开关'更重要。
二、寄存器别乱打拍,打包率才是王道
LUT 之后就是触发器(FF)。很多人只关心用了多少 FF,却忽略了更重要的指标:LUT-FF 打包率。
什么叫打包率?简单说,就是每个 LUT 旁边有没有顺手带一个 FF 一起布线。Xilinx 器件中,每个 Slice 包含 8 个 LUT 和 8 个 FF,理想情况下应尽量让 LUT 驱动就近的 FF,形成紧凑结构。
常见陷阱:过度寄存化 & 扇出爆炸
举个例子:
reg [31:0] delay_chain [0:7];
always @(posedge clk) begin
delay_chain[0] <= din;
for (i=1; i<8; i=i+1)
delay_chain[i] <= delay_chain[i-1];
end
这个移位寄存器看起来没问题,但如果 din 扇出很大,或者中间某一级被其他模块引用,Vivado 可能会被迫复制某些 delay_chain[i] 节点以满足时序,导致 FF 数量激增。
更好的做法是使用专用原语或属性标注:
(* shreg_extract = "no" *) reg [31:0] delay_chain [0:7];
告诉综合器:'别给我展开成移位寄存器优化',强制其保持链式结构,利于布局连续性。
另外,全局复位信号也常是罪魁祸首。如果你用异步复位驱动上千个 FF,布线工具会在全局网络上疯狂挣扎。建议:
- 改为同步复位;
- 或者插入 BUFGCTRL 做局部复位树;

