Verilog阻塞与非阻塞赋值对比分析与实战指南

FPGA小白
文章2026-05-02
46

Quick Start

  • 准备EDA环境:安装Vivado 2021.2或更高版本(也可使用ModelSim/QuestaSim)。
  • 创建工程:新建RTL项目,目标器件选择XC7A35T(Artix-7)。
  • 编写测试模块:分别用阻塞赋值(=)和非阻塞赋值(<=)实现同一逻辑(如移位寄存器或计数器),对比仿真波形。
  • 运行仿真:观察两种赋值方式下信号更新的时序差异。
  • 验证结论:阻塞赋值产生组合逻辑,非阻塞赋值产生时序逻辑。

前置条件

  • 熟悉Verilog基本语法,了解always块和敏感列表。
  • 具备基础数字电路知识(组合逻辑与时序逻辑区别)。
  • 已安装并配置好仿真工具(Vivado/ModelSim/QuestaSim任一即可)。
  • 建议准备一个空项目模板,便于快速开始。

目标与验收标准

  • 理解阻塞赋值与非阻塞赋值的核心区别:阻塞赋值立即更新,非阻塞赋值在块结束时统一更新。
  • 能够通过仿真波形区分两种赋值方式产生的电路类型(组合 vs 时序)。
  • 掌握在实际设计中正确选择赋值方式的原则,避免竞争与冒险。
  • 验收:在仿真中观察到阻塞赋值导致信号链式传播,非阻塞赋值产生寄存器延迟。

实施步骤

步骤1:编写阻塞赋值测试模块

module blocking_test(
    input clk,
    input rst_n,
    input d,
    output reg q1, q2
);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q1 <= 1'b0;
        q2 <= 1'b0;
    end else begin
        q1 = d;      // 阻塞赋值
        q2 = q1;     // 阻塞赋值,q2立即得到q1更新后的值
    end
end
endmodule

此代码中,q2 = q1 在同一个always块内顺序执行,q1 先被赋值为 d,然后 q2 立即得到 q1 的新值。综合后,q1q2 实际上是同一个寄存器(或直接连线),因为阻塞赋值会覆盖中间状态。

步骤2:编写非阻塞赋值测试模块

module nonblocking_test(
    input clk,
    input rst_n,
    input d,
    output reg q1, q2
);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q1 <= 1'b0;
        q2 <= 1'b0;
    end else begin
        q1 <= d;      // 非阻塞赋值
        q2 <= q1;     // 非阻塞赋值,q2得到q1更新前的值
    end
end
endmodule

非阻塞赋值时,所有右值在块开始时被采样,左值在块结束时统一更新。因此,q2 <= q1 采样的是 q1 的旧值(上一个时钟周期的值),实现了一个两拍移位寄存器。

步骤3:编写测试平台并仿真

module tb;
    reg clk, rst_n, d;
    wire q1_blk, q2_blk;
    wire q1_nblk, q2_nblk;

    blocking_test u_blk(.clk(clk), .rst_n(rst_n), .d(d), .q1(q1_blk), .q2(q2_blk));
    nonblocking_test u_nblk(.clk(clk), .rst_n(rst_n), .d(d), .q1(q1_nblk), .q2(q2_nblk));

    initial begin
        clk = 0;
        forever #5 clk = ~clk;
    end

    initial begin
        rst_n = 0; d = 0;
        #20 rst_n = 1;
        #10 d = 1;
        #10 d = 0;
        #20 $finish;
    end
endmodule

运行仿真后,观察波形:在阻塞赋值模块中,q1_blkq2_blk 在同一个时钟沿同时变化,且 q2_blk 紧随 q1_blk 变化;在非阻塞模块中,q2_nblkq1_nblk 延迟一个时钟周期。

验证结果

  • 阻塞赋值:q1_blkq2_blk 波形完全重叠,综合后为同一寄存器或组合逻辑链。
  • 非阻塞赋值:q2_nblkq1_nblk 延迟一个时钟周期,综合后为两级串联的寄存器。
  • 关键差异:阻塞赋值在组合逻辑中模拟数据流,非阻塞赋值在时序逻辑中模拟寄存器传输。

排障指南

  • 问题1:仿真中非阻塞赋值结果与预期不符。检查是否在同一个always块中混用了阻塞与非阻塞赋值,这会导致仿真行为不可预测。
  • 问题2:综合后电路面积异常。阻塞赋值在组合逻辑中产生大量LUT,而非阻塞赋值产生寄存器;若预期为时序电路却用了阻塞赋值,可能导致逻辑错误。
  • 问题3:仿真波形中出现毛刺。检查敏感列表是否完整(如缺少 negedge rst_n),或组合逻辑中使用了非阻塞赋值。

扩展:深入理解赋值机制

原因与机制分析

阻塞赋值(=)本质是“立即执行”操作:赋值语句会阻塞后续语句的执行,直到当前赋值完成。在综合时,它通常映射为组合逻辑(如多路选择器或连线),因为赋值行为不依赖时钟沿的同步。非阻塞赋值(<=)则遵循“采样-更新”两阶段模型:所有右值在时钟沿到来时被采样,然后所有左值在块结束时同时更新。这种机制保证了多个非阻塞赋值之间不会产生数据竞争,因此适合描述寄存器传输。

落地路径

  • 在时序逻辑(如always @(posedge clk))中,始终使用非阻塞赋值,避免产生锁存器或竞争。
  • 在组合逻辑(如always @(*))中,使用阻塞赋值,确保信号传播顺序正确。
  • 避免在同一个always块中混用两种赋值方式,除非有特殊设计意图(如混合逻辑,但风险较高)。

风险边界

  • 阻塞赋值在时序逻辑中可能导致综合结果与仿真不一致,因为综合工具可能将其解释为组合逻辑,而仿真中却表现为顺序执行。
  • 非阻塞赋值在组合逻辑中会导致仿真出现“延迟一个时间步”的假象,综合后可能产生意外的寄存器。
  • 在复杂设计中,混用赋值方式可能增加调试难度,建议通过代码审查和仿真波形双重验证。

参考资源

  • IEEE Std 1364-2001, Verilog HDL语言参考手册。
  • Clifford E. Cummings, “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!”
  • Xilinx Vivado Design Suite用户指南(UG901)。

附录:常见误区总结

  • 误区1:认为阻塞赋值“更快”。实际上,综合后的电路速度取决于逻辑深度,而非赋值方式。
  • 误区2:在always块中随意混用赋值方式。这可能导致仿真通过但综合失败。
  • 误区3:忽略敏感列表完整性。组合逻辑的敏感列表应包含所有输入信号,否则综合会生成锁存器。
分类
技术分享
标签
Verilog阻塞赋值非阻塞赋值
浏览 46
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

FPGA小白查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站