Verilog 阻塞与非阻塞赋值深度解析:设计与验证指南

二牛学FPGA
文章2026-04-26
68

Quick Start

在 Vivado 或 Quartus 中新建一个 Verilog 工程,选择任意 FPGA 器件(如 XC7A35T)。创建一个顶层模块 blocking_nonblocking,包含时钟 clk、复位 rst_n、输入 d 和输出 q_blockingq_nonblocking。编写两个 2 级移位寄存器:一个使用阻塞赋值(=),另一个使用非阻塞赋值(<=)。

前置条件

  • 熟悉 Verilog 基本语法,了解 always 块与敏感列表。
  • 已安装 Vivado 或 Quartus 开发环境,并具备基本工程创建能力。
  • 理解寄存器传输级(RTL)设计概念,包括时钟边沿触发行为。

目标与验收标准

  • 目标:通过对比实验,深入理解阻塞赋值与非阻塞赋值在时序逻辑中的行为差异,掌握各自的适用场景。
  • 验收标准
    • 仿真波形显示:阻塞赋值移位寄存器输出 q_blocking 在时钟上升沿后立即更新,但可能产生竞争;非阻塞赋值移位寄存器输出 q_nonblocking 在时钟上升沿后稳定移位,无竞争风险。
    • 综合后网表检查:非阻塞赋值版本生成正确级联的 D 触发器链;阻塞赋值版本可能产生组合逻辑环或非预期锁存器。

实施步骤

步骤 1:创建工程与模块

  • 在 Vivado 中新建工程,器件选择 XC7A35T-1CSG324C。
  • 添加设计源文件 blocking_nonblocking.v
  • 定义端口:input clk, rst_n, doutput reg [1:0] q_blocking, q_nonblocking

步骤 2:编写阻塞赋值移位寄存器

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q_blocking[0] <= 1'b0;
        q_blocking[1] <= 1'b0;
    end else begin
        q_blocking[0] = d;
        q_blocking[1] = q_blocking[0];
    end
end

步骤 3:编写非阻塞赋值移位寄存器

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q_nonblocking[0] <= 1'b0;
        q_nonblocking[1] <= 1'b0;
    end else begin
        q_nonblocking[0] <= d;
        q_nonblocking[1] <= q_nonblocking[0];
    end
end

步骤 4:编写仿真测试文件

  • 生成时钟周期 10 ns,复位低有效。
  • 输入 d 在复位释放后依次变为 1、0、1,间隔 2 个时钟周期。
  • 运行仿真至少 100 ns,观察波形。

步骤 5:综合与实现

  • 运行综合,查看 RTL 原理图。
  • 对比两个移位寄存器的硬件结构差异。
  • 运行实现,检查时序报告,确认无建立时间违例。

验证结果

仿真波形分析

  • 非阻塞赋值q_nonblocking[0] 在时钟上升沿后延迟一个 delta 周期更新为 dq_nonblocking[1] 在同一个时钟沿后更新为 q_nonblocking[0] 的旧值,实现正确移位。
  • 阻塞赋值q_blocking[0] 立即更新为 d,然后 q_blocking[1] 立即更新为 q_blocking[0] 的新值,导致两个寄存器在同一个时钟沿同时获得 d 的值,移位功能失效。

综合结果对比

  • 非阻塞赋值版本综合为两个级联的 D 触发器,符合预期。
  • 阻塞赋值版本综合后可能产生组合逻辑反馈或锁存器,取决于综合工具优化策略。

排障指南

  • 问题:仿真波形显示非阻塞赋值移位寄存器输出未按预期延迟

    原因:测试文件中未正确设置输入 d 的变化时机,或时钟边沿对齐错误。确保 d 在时钟上升沿之前稳定。

  • 问题:综合后网表出现锁存器警告

    原因:阻塞赋值在 always 块中未覆盖所有分支,或敏感列表不完整。检查条件语句是否完备。

  • 问题:时序报告显示建立时间违例

    原因:阻塞赋值导致的组合逻辑路径过长。改用非阻塞赋值并重新综合。

扩展应用

  • 多级流水线设计:在流水线寄存器中必须使用非阻塞赋值,确保数据在时钟边沿同步传递。
  • 组合逻辑建模:在描述组合逻辑的 always 块(如敏感列表为 @(*))中,应使用阻塞赋值,以模拟硬件中连续赋值的行为。
  • 混合赋值风格:同一个 always 块中不要混用阻塞与非阻塞赋值,否则会导致仿真与综合行为不一致。

参考资源

  • IEEE Std 1364-2001, Verilog Hardware Description Language
  • Clifford E. Cummings, “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!”
  • Xilinx Vivado Design Suite User Guide: Synthesis (UG901)

附录:完整代码示例

module blocking_nonblocking (
    input clk,
    input rst_n,
    input d,
    output reg [1:0] q_blocking,
    output reg [1:0] q_nonblocking
);

// 阻塞赋值移位寄存器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q_blocking[0] <= 1'b0;
        q_blocking[1] <= 1'b0;
    end else begin
        q_blocking[0] = d;
        q_blocking[1] = q_blocking[0];
    end
end

// 非阻塞赋值移位寄存器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        q_nonblocking[0] <= 1'b0;
        q_nonblocking[1] <= 1'b0;
    end else begin
        q_nonblocking[0] <= d;
        q_nonblocking[1] <= q_nonblocking[0];
    end
end

endmodule

分类
技术分享
标签
Verilog阻塞赋值非阻塞赋值
浏览 68
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

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

探索全站