FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
登录
首页-技术文章/快讯-技术分享-正文

2026年Q2:Verilog中阻塞与非阻塞赋值的综合陷阱与最佳实践

FPGA小白FPGA小白
技术分享
10小时前
0
0
7

Quick Start

  • 1. 准备环境:安装Vivado 2024.2(或更高版本)与ModelSim/QuestaSim 2025.1仿真器。
  • 2. 创建工程:新建Vivado工程,选择xc7a35ticsg324-1L(Artix-7)作为目标器件。
  • 3. 编写RTL代码:创建三个模块——bad_comb阻塞赋值组合逻辑)、good_seq(非阻塞赋值时序逻辑)、mixed(混合赋值演示)。
  • 4. 编写Testbench:用时钟周期驱动输入,观察输出波形,重点检查always @(posedge clk)always @(*)中赋值行为。
  • 5. 运行行为仿真:在QuestaSim中运行vsim work.tb_top,添加clkabcq1q2信号到波形窗口。
  • 6. 观察现象:对于时序逻辑,非阻塞赋值在时钟上升沿后同时更新;阻塞赋值则在时钟沿前立即更新,导致仿真与综合结果不一致。
  • 7. 运行综合:在Vivado中运行synth_design -rtl,检查综合后网表是否出现意外锁存器或组合反馈。
  • 8. 验收:确保good_seq综合为D触发器链,bad_comb综合为组合逻辑(无寄存器),mixed中无意外锁存器。

前置条件与环境

项目推荐值说明替代方案
器件/板卡Artix-7 xc7a35ticsg324-1L典型FPGA,支持所有基本原语Kintex-7 / Zynq-7000
EDA版本Vivado 2024.2综合与实现工具Vivado 2023.1+ / Quartus Prime 23+
仿真器QuestaSim 2025.1支持SystemVerilog与VHDL混合仿真Vivado Simulator / ModelSim SE
时钟/复位100 MHz系统时钟,异步复位高有效用于时序逻辑验证50 MHz / 200 MHz
接口依赖无外部IP,纯RTL仅需标准Verilog-2001语法
约束文件XDC约束:create_clock -period 10.0 [get_ports clk]定义时钟周期SDC格式

目标与验收标准

  • 功能点:在时序逻辑中,非阻塞赋值实现寄存器传输;组合逻辑中,阻塞赋值实现立即更新。
  • 性能指标:综合后无意外锁存器(latch)或组合反馈(combinatorial loop);Fmax ≥ 200 MHz(示例值,以实际时序报告为准)。
  • 资源消耗:good_seq使用约4个FDRE(D触发器);bad_comb使用0个FDRE;mixed使用2个FDRE + 少量LUT。
  • 关键波形:在仿真中,非阻塞赋值在时钟上升沿同时更新;阻塞赋值在时钟沿前立即更新,导致仿真与综合结果不一致。
  • 日志验收:Vivado综合日志中无“WARNING: [Synth 8-327] inferring latch”或“WARNING: [Synth 8-333] combinatorial loop”警告。

实施步骤

1. 工程结构与模块划分

  • 创建顶层模块top,实例化三个子模块:bad_combgood_seqmixed
  • 每个子模块使用独立的always块,避免跨模块赋值干扰。
  • 编写Testbenchtb_top,提供时钟、复位和输入激励。

2. 关键模块:阻塞赋值组合逻辑(bad_comb)

module bad_comb (
    input  wire [3:0] a,
    input  wire [3:0] b,
    output reg  [3:0] c
);
    always @(*) begin
        c = a & b;  // 阻塞赋值,组合逻辑
    end
endmodule

逐行说明

  • 第1行:声明模块名bad_comb,端口列表。
  • 第2-3行:输入ab为4位wire类型,输出c为4位reg类型(在always块中必须用reg)。
  • 第5行:always @(*)表示组合逻辑敏感列表,自动包含所有输入。
  • 第6行:阻塞赋值=,立即计算并更新c。综合为组合与门,无寄存器。
  • 第8行:结束模块。注意:如果always块中未覆盖所有分支,会综合出锁存器(此处无分支,安全)。

3. 关键模块:非阻塞赋值时序逻辑(good_seq)

module good_seq (
    input  wire       clk,
    input  wire       rst_n,
    input  wire [3:0] d,
    output reg  [3:0] q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 4'b0;  // 异步复位
        else
            q <= d;      // 非阻塞赋值,在时钟沿同时更新
    end
endmodule

逐行说明

  • 第1行:模块名good_seq
  • 第2-5行:时钟clk、异步复位rst_n(低有效)、数据输入d、输出q
  • 第7行:敏感列表为时钟上升沿或复位下降沿,这是标准时序逻辑模板。
  • 第8行:若复位有效,将q清零(非阻塞赋值)。
  • 第10行:否则,在时钟上升沿将d赋值给q。非阻塞赋值<=保证所有赋值在时钟沿后同时生效,避免竞争。
  • 第12行:综合为FDRE(D触发器)加异步复位。

4. 关键模块:混合赋值演示(mixed)

module mixed (
    input  wire       clk,
    input  wire       rst_n,
    input  wire [3:0] a,
    input  wire [3:0] b,
    output reg  [3:0] q1,
    output reg  [3:0] q2
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            q1 &lt;= 4'b0;
            q2 &lt;= 4'b0;
        end else begin
            q1 &lt;= a;      // 非阻塞
            q2 &lt;= q1;     // 非阻塞,q2得到的是q1旧值
        end
    end
endmodule

逐行说明

  • 第1-7行:模块声明,包含两个输出q1q2
  • 第9行:时序逻辑敏感列表。
  • 第11-12行:复位时清零两个输出。
  • 第14行:非阻塞赋值,q1在时钟沿后变为a
  • 第15行:非阻塞赋值,q2得到的是q1在时钟沿前的旧值(即上一个时钟周期的q1)。这模拟了移位寄存器的行为。
  • 第17行:综合为两个D触发器链,q2q1延迟一个时钟周期。

5. 时序/CDC/约束

  • 时钟约束:在XDC文件中添加create_clock -period 10.0 [get_ports clk],对应100 MHz。
  • 输入延迟:使用set_input_delay约束输入端口,避免时序违规。
  • CDC处理:本示例无跨时钟域,但若引入多时钟,必须使用双级同步器(非阻塞赋值实现)。
  • 复位约束:异步复位需满足恢复/移除时间,使用set_max_delay约束复位网络。

6. 验证

  • 编写Testbench,驱动时钟周期为10 ns,复位持续5个时钟周期。
  • 输入ab在复位释放后随机变化,观察q1q2的波形。
  • 检查bad_combc是否立即响应输入变化(无延迟)。
  • 检查good_seqq是否在时钟上升沿后延迟一个时钟周期更新。
  • 检查mixedq2是否比q1延迟一个时钟周期。

7. 上板(可选)

  • q1q2连接到LED,通过按键输入ab
  • 观察LED变化:按下按键后,q1立即变化,q2延迟一个时钟周期变化。
  • 注意:上板前务必运行实现后仿真,确认时序满足要求。

原理与设计说明

阻塞赋值(=)和非阻塞赋值(<=)的核心区别在于更新时机仿真语义。在Verilog仿真中,每个时间片(time step)分为多个区域:阻塞赋值在“阻塞赋值区域”立即执行,而非阻塞赋值在“非阻塞赋值区域”延迟更新(在时钟沿后同时生效)。这种机制模拟了硬件寄存器的行为:所有寄存器在时钟沿同时采样输入,并在时钟沿后同时更新输出。

关键矛盾:在时序逻辑中使用阻塞赋值会导致仿真与综合行为不一致。例如,在always @(posedge clk)中使用q = d,仿真中q会立即更新,可能影响同一时钟沿的其他赋值;而综合工具会将其视为组合逻辑或锁存器,导致硬件行为与仿真不符。这是最常见的综合陷阱。

最佳实践:

  • 时序逻辑(always @(posedge clk)):使用非阻塞赋值(<=)。
  • 组合逻辑(always @(*)):使用阻塞赋值(=)。
  • 混合逻辑:将时序和组合逻辑分离到不同的always块中。
  • 锁存器:避免在组合逻辑中遗漏分支(如缺少else),否则会综合出锁存器。

Trade-off分析:

  • 资源 vs Fmax:使用非阻塞赋值不会引入额外资源,但错误的赋值风格可能导致组合反馈,降低Fmax。
  • 吞吐 vs 延迟:非阻塞赋值在时钟沿同时更新,保证流水线级间延迟一致;阻塞赋值可能导致数据过早到达,破坏时序。
  • 易用性 vs 可移植性:遵循此规则可确保代码在Vivado、Quartus、Synplify等工具中行为一致。

验证与结果

模块仿真行为综合结果资源(LUT/FF)Fmax(MHz,示例值)
bad_combc立即响应a,b组合与门1 LUT / 0 FF无时序路径
good_seqq在时钟沿后延迟1周期D触发器0 LUT / 4 FF350+
mixedq2比q1延迟1周期2级D触发器链0 LUT / 8 FF350+

测量条件:Vivado 2024.2,Artix-7速度等级-1L,时钟约束10 ns,未使用任何优化选项。Fmax值基于综合后时序报告,实际值以具体工程为准。

故障排查(Troubleshooting)

  • 现象:仿真波形中q在时钟沿前变化。原因:在时序逻辑中使用了阻塞赋值。检查点:查看always块中赋值符号。修复建议:改为非阻塞赋值。
  • 现象:综合后出现“inferring latch”警告。原因:组合逻辑中未覆盖所有分支(缺少else或case默认项)。检查点:检查always @(*)块是否完整。修复建议:添加else或default赋值。
  • 现象:综合后出现“combinatorial loop”警告。原因:组合反馈,如输出赋值给自身。检查点:检查组合逻辑中是否有c = c + 1。修复建议:使用时序逻辑实现反馈。
  • 现象:上板后LED不按预期变化。原因:复位极性错误或时钟未连接。检查点:检查复位信号是否低有效,时钟是否约束正确。修复建议:核对原理图与约束。
  • 现象:仿真中q2与q1同时变化。原因:在时序逻辑中使用了阻塞赋值。检查点:查看mixed模块的赋值符号。修复建议:改为非阻塞赋值。
  • 现象:综合后资源消耗异常高。原因:意外生成了大量锁存器。检查点:查看综合日志中的latch inference。修复建议:重构组合逻辑,确保所有分支有赋值。
  • 现象:时序违规严重。原因:组合逻辑路径过长。检查点:查看时序报告中的最差路径。修复建议:插入流水线寄存器(使用非阻塞赋值)。
  • 现象:跨时钟域数据错误。原因:未使用同步器。检查点:检查CDC路径是否经过双级触发器。修复建议:添加两个非阻塞赋值触发器级联。
  • 现象:仿真与综合后仿真结果不一致。原因:RTL中使用了阻塞赋值建模时序逻辑。检查点:对比行为仿真与门级仿真波形。修复建议:修正赋值风格。
  • 现象:Vivado综合报错“unsupported conditional statement”。原因:在always @(*)中使用了非阻塞赋值。检查点:查看错误行。修复建议:组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值。

扩展与下一步

  • 参数化:将数据位宽改为参数WIDTH,使模块可复用。
  • 带宽提升:使用流水线结构(非阻塞赋值实现级间寄存器)提高吞吐率。
  • 跨平台:将代码移植到Quartus Prime,验证综合结果一致性。
  • 加入断言:使用SystemVerilog断言(SVA)检查时序逻辑中非阻塞赋值的正确性。
  • 覆盖分析:在仿真中收集代码覆盖率,确保所有分支被测试。
  • 形式验证:使用Synopsys VC Formal或Cadence JasperGold验证赋值风格是否符合规则。

参考与信息来源

  • IEEE Std 1364-2005, Verilog Hardware Description Language
  • Clifford E. Cummings, “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!” (SNUG 2000)
  • Xilinx UG901, Vivado Design Suite User Guide: Synthesis
  • Intel Quartus Prime Handbook, Volume 1: Design and Synthesis
  • 成电国芯FPGA云课堂内部培训材料(2026版)

技术附录

术语表

  • 阻塞赋值:使用=,立即更新变量,用于组合逻辑建模。
  • 非阻塞赋值:使用<=,在时钟沿后同时更新,用于时序逻辑建模。
  • 锁存器(Latch):电平敏感存储单元,由组合逻辑中未覆盖分支综合产生。
  • 组合反馈(Combinatorial Loop):输出通过组合逻辑直接反馈到输入,导致时序不稳定。
  • FDRE:Xilinx原语,带时钟使能和同步复位的D触发器。

检查清单

  • 所有时序逻辑的always块使用非阻塞赋值。
  • 所有组合逻辑的always块使用阻塞赋值。
  • 组合逻辑中每个分支都有赋值(无锁存器)。
  • 跨时钟域信号经过两级同步器(非阻塞赋值)。
  • 复位信号在时序逻辑的敏感列表中。
  • 综合后日志无latch或combinatorial loop警告。
标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/42875.html
FPGA小白

FPGA小白

初级工程师
成电国芯®的讲师哦,专业FPGA已有10年。
43321.82W7.29W34.40W
分享:
成电国芯FPGA赛事课即将上线
跨时钟域同步器的仿真与时序约束实践指南
跨时钟域同步器的仿真与时序约束实践指南上一篇
2026年Q2半导体与FPGA行业深度观察:国产AI边缘芯片、Chiplet桥接、AI辅助EDA与开源工具链量产验证下一篇
2026年Q2半导体与FPGA行业深度观察:国产AI边缘芯片、Chiplet桥接、AI辅助EDA与开源工具链量产验证
相关文章
总数:1.12K
FPGA中LUT与BRAM资源分配实践指南:以CNN加速为例(2026年)

FPGA中LUT与BRAM资源分配实践指南:以CNN加速为例(2026年)

QuickStart安装Vivado2025.2或更高版本(支持Ul…
技术分享
9天前
0
0
39
0
基于FPGA的边缘AI可定制化推理实现指南(2026架构趋势与落地实践)

基于FPGA的边缘AI可定制化推理实现指南(2026架构趋势与落地实践)

随着边缘计算与人工智能应用的深度融合,2026年的边缘AI芯片架构正朝着…
技术分享
23天前
0
0
40
0
Verilog 与 Python:学习方向的抉择与前景分析

Verilog 与 Python:学习方向的抉择与前景分析

在科技不断发展的当下,学习Verilog和Python都有着广阔…
技术分享, 行业资讯
1年前
0
0
474
5
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容