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

Verilog入门:阻塞与非阻塞赋值深度解析

FPGA小白FPGA小白
技术分享
1天前
0
0
7

Quick Start

  • 步骤1:打开任意文本编辑器(如 VS Code、Notepad++),创建文件 blocking_nonblocking.v
  • 步骤2:写入以下两个模块:一个用阻塞赋值always @(posedge clk) a = b;),一个用非阻塞赋值always @(posedge clk) a <= b;)。
  • 步骤3:安装或打开支持 Verilog 仿真的工具(如 ModelSim、Vivado Simulator、Icarus Verilog)。
  • 步骤4:编写 Testbench,实例化两个模块,输入相同的时钟和激励(如 b 在时钟沿变化)。
  • 步骤5:运行仿真,时长至少 10 个时钟周期。
  • 步骤6:观察波形:对比 a 的输出时序。阻塞赋值下,a 在时钟沿立即反映 b 的旧值(若在赋值前 b 已更新);非阻塞赋值下,a 在时钟沿后延迟一个时钟周期更新。
  • 步骤7:修改代码,在同一个 always 块中混合使用阻塞和非阻塞赋值,观察仿真警告或错误。
  • 步骤8:验收点:非阻塞赋值在时序逻辑中模拟寄存器行为,阻塞赋值在组合逻辑中模拟连线行为。

前置条件与环境

项目/推荐值说明替代方案
器件/板卡任意 FPGA(如 Xilinx Artix-7、Intel Cyclone IV)无(仅仿真可不依赖板卡)
EDA 版本Vivado 2020.1+ 或 ModelSim SE-64 10.6+Icarus Verilog 11+(开源)
仿真器Vivado Simulator 或 ModelSimVerilator(仅支持可综合子集)
时钟/复位时钟周期 10 ns(100 MHz),同步复位高有效异步复位也可,但需注意时序
接口依赖无外部接口,纯 RTL 仿真
约束文件仅仿真不需要 XDC/SDC;综合时需定义时钟周期

目标与验收标准

  • 功能点:能清晰区分阻塞与非阻塞赋值在时序逻辑中的行为差异。
  • 性能指标:无。
  • 资源/Fmax:无。
  • 关键波形:在时钟上升沿,阻塞赋值输出的 a 与输入 b 同时变化(若 b 在沿前稳定);非阻塞赋值输出的 a 比输入 b 晚一个时钟周期。
  • 验收方式:仿真波形图上,用游标测量 a 相对于 b 的延迟。阻塞赋值延迟为 0,非阻塞赋值延迟为 1 个时钟周期。

实施步骤

阶段一:工程结构与代码编写

创建以下两个模块,分别演示阻塞和非阻塞赋值。

// blocking.v
module blocking (
    input wire clk,
    input wire rst_n,
    input wire [3:0] b,
    output reg [3:0] a
);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        a = 4'b0;
    else
        a = b;  // 阻塞赋值
end
endmodule

// nonblocking.v
module nonblocking (
    input wire clk,
    input wire rst_n,
    input wire [3:0] b,
    output reg [3:0] a
);
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        a &lt;= 4&#039;b0;
    else
        a &lt;= b;  // 非阻塞赋值
end
endmodule

注意:阻塞赋值在时序逻辑中虽可综合,但会生成组合逻辑或锁存器,而非预期的寄存器。非阻塞赋值才是时序逻辑的标准写法。

阶段二:Testbench 编写

module tb;
reg clk, rst_n;
reg [3:0] b;
wire [3:0] a_block, a_nonblock;

blocking u_block (.clk(clk), .rst_n(rst_n), .b(b), .a(a_block));
nonblocking u_nonblock (.clk(clk), .rst_n(rst_n), .b(b), .a(a_nonblock));

initial begin
    clk = 0;
    forever #5 clk = ~clk;  // 10 ns 周期
end

initial begin
    rst_n = 0;
    b = 4'b0000;
    #20 rst_n = 1;
    #10 b = 4'b1010;
    #10 b = 4'b0110;
    #20 $finish;
end
endmodule

预期结果:在时钟上升沿,a_block 立即等于 b(阻塞),a_nonblock 延迟一个时钟周期。

阶段三:仿真与波形分析

运行仿真后,观察波形。常见坑:

  • 坑1:若在时钟沿同时改变 b(如 Testbench 中 @(posedge clk) b <= ...),非阻塞赋值可能造成输出 a_nonblock 延迟两个周期。原因是 Testbench 中的非阻塞赋值在时钟沿后更新,导致本周期采样到旧值。
  • 坑2:阻塞赋值在组合逻辑中若未完整赋值,会产生锁存器。例如 if (sel) a = b; else a = c; 缺少 else 分支会推断锁存。

阶段四:综合与上板验证(可选)

综合时,阻塞赋值模块 blocking 会被综合为组合逻辑(无寄存器),而非阻塞赋值模块 nonblocking 会被综合为 D 触发器。上板后,可用逻辑分析仪观察输出延迟。

原理与设计说明

阻塞赋值(=)在 always 块中顺序执行,立即更新左侧变量。非阻塞赋值(<=)在块结束时并行更新,右侧表达式在块开始时采样。这一机制源于 Verilog 的仿真事件调度:非阻塞赋值更新事件被排在当前时间片的末尾,而阻塞赋值立即生效。

关键矛盾:在时序逻辑(always @(posedge clk))中,使用阻塞赋值会导致仿真行为与硬件行为不一致。例如,多个阻塞赋值在同一个时钟沿可能产生竞争,而硬件寄存器是并行更新的。非阻塞赋值模拟了寄存器的并行更新行为,避免了仿真竞争。

可执行方案:

  • 时序逻辑:始终使用非阻塞赋值(<=)。
  • 组合逻辑:始终使用阻塞赋值(=)。
  • 混合逻辑:将组合和时序逻辑分离到不同 always 块中。

风险边界:违反上述规则会导致仿真与综合结果不一致,或产生意外的锁存器。在大型设计中,混合赋值可能造成仿真通过但综合失败。

验证与结果

指标阻塞赋值非阻塞赋值测量条件
输出延迟(时钟周期)01时钟 100 MHz,输入变化在时钟沿前 2 ns
综合后资源组合逻辑(无寄存器)1 个 D 触发器Vivado 2020.1,Artix-7
仿真竞争风险多个赋值在同一 always 块

波形特征:在仿真波形中,阻塞赋值的输出 a 与输入 b 在时钟沿对齐;非阻塞赋值的输出 a 在时钟沿后一个周期才变化。

故障排查(Troubleshooting)

  • 现象1:仿真波形中非阻塞赋值输出延迟超过1个周期。原因:Testbench 中也在时钟沿使用非阻塞赋值。检查点:b 的更新方式。修复:在时钟沿前(如 #1)更新 b
  • 现象2:综合报告显示生成了锁存器。原因:组合逻辑中缺少 else 分支或 case 默认项。检查点:always @* 块中的赋值完整性。修复:补全所有分支。
  • 现象3:仿真结果与综合后仿真不一致。原因:时序逻辑中使用了阻塞赋值。检查点:always @(posedge clk) 块内的赋值类型。修复:改为非阻塞赋值。
  • 现象4:多个非阻塞赋值在同一个时钟沿产生 X 态。原因:同一变量在多个 always 块中被赋值。检查点:变量驱动源数量。修复:确保单驱动。
  • 现象5:仿真速度极慢。原因:非阻塞赋值在大型设计中导致大量事件。检查点:仿真日志中的事件数。修复:使用优化编译选项。
  • 现象6:综合工具报“inferring latch”。原因:组合逻辑中阻塞赋值未覆盖所有条件。检查点:ifcase 的完整性。修复:添加 elsedefault
  • 现象7:后仿时序不满足。原因:非阻塞赋值导致数据路径延迟。检查点:时序报告中 setup/hold 违反。修复:调整时钟周期或流水线。
  • 现象8:上板后输出不稳定。原因:异步复位未同步,或赋值导致 glitch。检查点:复位信号和组合逻辑路径。修复:同步复位,或使用寄存器。

扩展与下一步

  • 扩展1:参数化设计:将数据位宽改为可配置参数,验证不同位宽下的行为一致性。
  • 扩展2:带宽提升:在时序逻辑中引入流水线,使用非阻塞赋值实现多级寄存器链。
  • 扩展3:跨平台:用 Verilator 编译并对比仿真速度,理解非阻塞赋值在 C++ 仿真中的实现。
  • 扩展4:加入断言:使用 SystemVerilog 断言(SVA)检查输出延迟是否为 1 个时钟周期。
  • 扩展5:覆盖分析:用仿真工具的覆盖率功能检测赋值语句的触发次数。
  • 扩展6:形式验证:用 SymbiYosys 等工具形式化验证阻塞与非阻塞赋值的行为等价性。

参考与信息来源

  • IEEE Std 1364-2005, Verilog Hardware Description Language
  • Clifford E. Cummings, “Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!” (Sunburst Design)
  • Xilinx UG901, Vivado Design Suite User Guide: Synthesis
  • Intel Quartus Prime Handbook, Volume 1: Design and Synthesis

技术附录

术语表

  • 阻塞赋值(Blocking Assignment):使用 =,顺序执行,立即更新。
  • 非阻塞赋值(Nonblocking Assignment):使用 <=,并行更新,在块结束时生效。
  • 锁存器(Latch):电平敏感存储单元,由组合逻辑中不完整赋值产生。
  • D 触发器(D Flip-Flop):边沿敏感存储单元,由时序逻辑中非阻塞赋值产生。

检查清单

  • 时序逻辑中是否全部使用 <=
  • 组合逻辑中是否全部使用 =
  • 组合逻辑中是否所有分支都有赋值?
  • 同一变量是否只在一个 always 块中被赋值?
  • Testbench 中是否避免在时钟沿使用非阻塞赋值驱动输入?

关键约束速查

  • 时序逻辑:always @(posedge clk) begin ... end → 内部用 <=
  • 组合逻辑:always @* begin ... end → 内部用 =
  • 避免:在同一个 always 块中混合 =<=
  • 综合约束:在 XDC/SDC 中定义时钟周期,确保非阻塞赋值路径满足 setup/hold
标签:
本文原创,作者:FPGA小白,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/39678.html
FPGA小白

FPGA小白

初级工程师
成电国芯®的讲师哦,专业FPGA已有10年。
34220.71W7.20W34.38W
分享:
成电国芯FPGA赛事课即将上线
FPGA时序约束实战指南:时钟周期与偏斜优化方法
FPGA时序约束实战指南:时钟周期与偏斜优化方法上一篇
2026年国产FPGA在AI边缘推理中动态部分重配置生态加速:现状、挑战与学习路径下一篇
2026年国产FPGA在AI边缘推理中动态部分重配置生态加速:现状、挑战与学习路径
相关文章
总数:855
FPGA中PLL与MMCM的区别及时钟管理应用实践指南

FPGA中PLL与MMCM的区别及时钟管理应用实践指南

QuickStart:快速上手PLL/MMCM配置打开Vivado(或…
技术分享
6天前
0
0
16
0
FPGA工程师十大职业病深度解析:技术人苦中作乐实录

FPGA工程师十大职业病深度解析:技术人苦中作乐实录

作为一名资深FPGA工程师,这些症状早已成为日常的勋章。下面从技术根源到…
技术分享
1年前
0
0
383
1
FPGA进阶课程 高速接口+国产FPGA平台

FPGA进阶课程 高速接口+国产FPGA平台

近年来,FPGA技术因其在各个领域的广泛应用而备受瞩目。然而,与其火爆的…
技术分享
2年前
0
0
672
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容