Quick Start
打开 Vivado 2026.1(或 Quartus Prime Pro 25.1),创建一个新工程,器件选择 xc7k325tffg900-2(或等效)。编写一个简单的计数器模块,使用 always @(posedge clk) 敏感列表,综合后查看资源与 Fmax。修改为 always @(posedge clk or posedge rst),添加异步复位,重新综合,对比资源与 Fmax 变化。编写一个组合逻辑模块,使用 always @(*) 敏感列表,综合后查看 LUT 使用量。将组合逻辑敏感列表改为显式列出所有输入信号(如 always @(a or b or sel)),重新综合,观察资源是否变化。打开综合报告(report_utilization、report_timing_summary),记录 Fmax、LUT、FF 数量,确认无意外锁存器推断。对于时序逻辑,尝试使用 always @(negedge clk) 代替 posedge,重新综合,对比 Fmax(通常无差异,但可能影响时序收敛)。对于多时钟域设计,分别使用 always @(posedge clk1) 和 always @(posedge clk2),综合后检查跨时钟域路径是否被正确约束。
预期结果:在 10 分钟内完成上述步骤,得到对比表格,验证敏感列表写法对综合结果的影响。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| 器件/板卡 | Xilinx Kintex-7 xc7k325tffg900-2 | 主流中端 FPGA,资源适中,适合对比测试 | Artix-7 / Cyclone V / Agilex 7 |
| EDA 版本 | Vivado 2026.1 | 最新版本,综合算法有优化 | Vivado 2024.2 / Quartus Prime Pro 25.1 |
| 仿真器 | Vivado Simulator 或 ModelSim SE-64 2025.1 | 用于功能仿真验证锁存器行为 | Questa / VCS |
| 时钟/复位 | 时钟 100 MHz,异步复位高有效 | 标准测试条件 | 50 MHz / 200 MHz,低有效复位 |
| 接口依赖 | 无外部接口,纯内部逻辑 | 避免 I/O 约束干扰 | 可添加简单 GPIO 输出 |
| 约束文件 | create_clock -period 10 [get_ports clk] | 必须定义主时钟 | set_false_path 用于跨时钟域 |
目标与验收标准
- 功能点:验证不同敏感列表写法(posedge/negedge/电平敏感/混合)对综合结果的影响。
- 性能指标:记录 Fmax(MHz)、LUT 数量、FF 数量、推断的锁存器数量。
- 资源/Fmax:对比显式列表与
always @(*)的资源差异;对比异步复位与同步复位的 Fmax 差异。 - 关键波形/日志:仿真波形中确认无意外锁存器行为;综合日志中无“Inferring latch”警告。
实施步骤
工程结构
创建顶层模块 top,包含一个计数器 counter 和一个组合逻辑 combo。每个模块独立文件,便于单独综合。约束文件 top.xdc 定义时钟与复位。
关键模块:计数器(时序逻辑)
module counter (
input wire clk,
input wire rst,
output reg [7:0] count
);
always @(posedge clk or posedge rst) begin
if (rst)
count <= 8'd0;
else
count <= count + 1;
end
endmodule逐行说明
- 第 1 行:模块声明,输入时钟 clk 和复位 rst,输出 8 位寄存器 count。
- 第 2 行:always 块敏感列表包含时钟上升沿和复位上升沿,这是异步复位的标准写法。
- 第 3 行:if (rst) 判断复位信号有效,综合工具会推断为异步复位 FF。
- 第 4 行:复位时 count 清零。
- 第 5 行:否则在每个时钟上升沿递增。
- 第 6 行:endmodule。
关键模块:组合逻辑(电平敏感)
module combo (
input wire [3:0] a,
input wire [3:0] b,
input wire sel,
output reg [3:0] y
);
always @(*) begin
if (sel)
y = a + b;
else
y = a - b;
end
endmodule逐行说明
- 第 1 行:模块声明,输入 a、b、sel,输出 reg y。
- 第 2 行:always @(*) 表示敏感列表包含所有输入信号,综合工具会自动推断组合逻辑。
- 第 3 行:if (sel) 判断选择信号。
- 第 4 行:sel 为 1 时 y = a + b。
- 第 5 行:else y = a - b。
- 第 6 行:endmodule。注意:使用阻塞赋值 =,因为这是组合逻辑。
时序/CDC/约束
- 时钟约束:
create_clock -period 10 [get_ports clk]。 - 异步复位:无需额外约束,但建议添加
set_false_path -from [get_ports rst]以避免复位路径影响时序。 - 跨时钟域:如果使用多个 always 块驱动不同时钟域,必须添加
set_clock_groups -asynchronous约束。
验证
- 编写 testbench,分别测试计数器递增和组合逻辑加减功能。
- 仿真检查波形:确保计数器在复位后清零,时钟上升沿递增;组合逻辑输出随输入立即变化。
- 检查综合日志:搜索“latch”关键词,确认无意外锁存器。
常见坑与排查
坑 1:在组合逻辑 always 块中使用非阻塞赋值
在组合逻辑中应使用阻塞赋值(=),若误用非阻塞赋值(<=),综合工具可能推断出意外的锁存器或时序逻辑,导致功能错误。排查方法:检查综合日志中是否出现“Inferring latch”警告,并仿真验证组合逻辑是否按预期立即响应。
坑 2:敏感列表遗漏信号
若显式列出敏感列表但遗漏了某个输入信号,组合逻辑可能无法正确更新,综合工具会推断出锁存器。建议优先使用 always @(*) 避免遗漏。排查方法:对比显式列表与 @(*) 的综合结果,检查 LUT 数量是否异常增加。
坑 3:多驱动冲突
同一个 reg 在多个 always 块中赋值会导致多驱动冲突,综合报错或产生意外行为。确保每个 reg 只在一个 always 块中赋值。
扩展与进阶
可进一步测试以下场景:
- 在组合逻辑中使用
always @(posedge clk)模拟时序逻辑,对比资源与 Fmax。 - 在时序逻辑中使用电平敏感列表(如
always @(clk or rst)但缺少边沿),观察综合工具如何推断。 - 使用不同综合工具(Vivado vs Quartus)对比敏感列表优化策略的差异。
参考与附录
IEEE Std 1364-2005 Verilog HDL 标准中关于 always 块敏感列表的规范。Vivado 综合用户指南 (UG901)。Quartus Prime Pro 综合用户指南。


