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

Verilog中阻塞与非阻塞赋值综合结果深度对比

二牛学FPGA二牛学FPGA
技术分享
1天前
0
0
9

Quick Start

  • 准备 Vivado 2023.2 或更高版本,新建一个 RTL 工程,目标器件选 xc7a35ticsg324-1L(Artix-7)。
  • 编写两个完全相同的逻辑功能模块:一个全部使用阻塞赋值(=),另一个全部使用非阻塞赋值(<=),仅测试一个简单的 4 位计数器。
  • 对两个模块分别运行综合(Synthesis),打开综合后的原理图(Schematic)。
  • 对比两个原理图中的寄存器(FDRE)数量、连线结构、组合逻辑深度。
  • 对两个模块分别运行实现(Implementation),查看时序报告(Setup Slack 与 Hold Slack)。
  • 预期现象:对于同一个计数器逻辑,阻塞赋值版本可能综合出更少的寄存器(因共享/复用),但时序更差;非阻塞赋值版本会综合出标准流水线结构,时序更容易收敛。若两者结构一致,则说明赋值方式对综合结果无影响(仅仿真行为不同)。

前置条件与环境

项目推荐值说明替代方案
器件/板卡xc7a35ticsg324-1LArtix-7 系列,速度等级 -1L任何 7 系列或 UltraScale 器件
EDA 版本Vivado 2023.2综合与实现工具Vivado 2020.1+ 或 Quartus Prime 20.1+
仿真器Vivado Simulator用于验证功能正确性ModelSim/Questa、VCS
时钟100 MHz 单端时钟主时钟周期 10 ns50–200 MHz 均可
复位同步高有效复位避免异步复位的 CDC 问题异步复位也可,但需约束
接口依赖无外部接口纯 RTL 内部逻辑测试可添加 I/O 观察
约束文件XDC 中定义 create_clock周期 10 ns,波形 {0 5}使用默认时序约束也可

目标与验收标准

  • 功能点:两个模块在仿真中实现完全相同的计数功能(从 0 到 15 循环)。
  • 性能指标:非阻塞赋值版本 Setup Slack ≥ 0.5 ns(在 100 MHz 下),阻塞赋值版本 Setup Slack 可能为负或紧裕量。
  • 资源指标:记录两个版本使用的 FDRE 数量、LUT 数量、CARRY4 数量,差异应 ≤ 10%(若逻辑等价)。
  • 验收方式:运行综合后查看 Report Utilization 与 Report Timing Summary,截图保存对比。

实施步骤

工程结构与 RTL 编写

创建两个顶层模块:counter_blockingcounter_nonblocking。每个模块包含一个 4 位计数器,时钟上升沿触发,同步复位。以下给出两个版本的完整 RTL。

// counter_blocking.v - 全部使用阻塞赋值
module counter_blocking (
    input  wire       clk,
    input  wire       rst_n,
    output reg  [3:0] cnt
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt = 4'd0;
        end else begin
            cnt = cnt + 1'b1;
        end
    end
endmodule

逐行说明

  • 第 1 行:模块声明,端口列表包含时钟、复位和输出计数。
  • 第 2 行:output reg [3:0] cnt 声明 cnt 为 reg 类型,因为要在 always 块中被赋值。
  • 第 3 行:always 块敏感列表为时钟上升沿或复位下降沿(异步复位风格)。
  • 第 4–6 行:复位逻辑,当 rst_n 为低时,cnt 被赋值为 0。注意这里使用阻塞赋值 =
  • 第 7–8 行:正常计数逻辑,cnt = cnt + 1,同样使用阻塞赋值。综合工具会推断出 cnt 是一个寄存器(FDRE),因为它在时钟沿被赋值。
// counter_nonblocking.v - 全部使用非阻塞赋值
module counter_nonblocking (
    input  wire       clk,
    input  wire       rst_n,
    output reg  [3:0] cnt
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt &lt;= 4'd0;
        end else begin
            cnt &lt;= cnt + 1'b1;
        end
    end
endmodule

逐行说明

  • 第 1–2 行:模块声明与端口定义,与阻塞版本完全一致。
  • 第 3 行:output reg [3:0] cnt 声明相同。
  • 第 4 行:always 块敏感列表相同。
  • 第 5–7 行:复位逻辑,使用非阻塞赋值 <=
  • 第 8–9 行:计数逻辑,使用非阻塞赋值。综合工具同样推断出 cnt 为寄存器,但仿真行为不同:非阻塞赋值在时钟沿同时更新,避免竞争。

综合与实现

  • 在 Vivado 中分别将两个模块设为顶层(Top Module),运行 Synthesis。
  • 打开综合后的 Schematic,观察寄存器结构:阻塞版本可能将 cnt 推断为单个 4 位寄存器,非阻塞版本同样如此——对于简单计数器,两者综合结果完全相同。
  • 运行 Implementation,查看时序报告。由于逻辑完全相同,Setup Slack 应一致(例如 8.5 ns 左右)。

常见坑与排查

  • 坑 1:误以为阻塞赋值一定综合出组合逻辑。实际上,只要赋值在时钟沿敏感 always 块内,综合工具都会推断寄存器。检查方式:查看综合后的原理图,确认 cnt 是否连接到 FDRE 的 Q 输出。
  • 坑 2:在同一个 always 块内混用阻塞和非阻塞赋值导致仿真与综合不一致。排查:使用 lint 工具(如 Vivado 的 Report HDL Linting)检查赋值风格一致性。

复杂场景:多级逻辑与流水线

当逻辑包含多个赋值语句时,阻塞与非阻塞的综合结果会出现本质差异。以下是一个两级移位寄存器的例子。

// shift_blocking.v - 阻塞赋值实现移位寄存器
module shift_blocking (
    input  wire       clk,
    input  wire       rst_n,
    input  wire       din,
    output reg        dout
);
    reg d1, d2;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            d1 = 1'b0;
            d2 = 1'b0;
        end else begin
            d1 = din;
            d2 = d1;   // 阻塞赋值:d2 立即得到 din 的当前值,不是上一拍的值
        end
    end
    assign dout = d2;
endmodule

逐行说明

  • 第 1–5 行:模块声明,输入 din,输出 dout。
  • 第 6 行:声明两个内部 reg 变量 d1 和 d2。
  • 第 7 行:always 块敏感列表。
  • 第 8–11 行:复位逻辑,两个寄存器清零。
  • 第 12 行:d1 = din;阻塞赋值,d1 立即更新。
  • 第 13 行:d2 = d1;此时 d1 已经是 din 的当前值,所以 d2 也等于 din 的当前值。综合工具会优化掉 d1 寄存器,只保留一个寄存器(d2),因为 d1 的值没有被独立存储。
  • 第 14 行:assign dout = d2;输出。
// shift_nonblocking.v - 非阻塞赋值实现移位寄存器
module shift_nonblocking (
    input  wire       clk,
    input  wire       rst_n,
    input  wire       din,
    output reg        dout
);
    reg d1, d2;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            d1 &lt;= 1'b0;
            d2 &lt;= 1'b0;
        end else begin
            d1 &lt;= din;
            d2 &lt;= d1;   // 非阻塞赋值:d2 得到的是 d1 上一拍的值
        end
    end
    assign dout = d2;
endmodule

逐行说明

  • 第 1–5 行:模块声明相同。
  • 第 6 行:声明 d1、d2。
  • 第 7–11 行:复位逻辑,使用非阻塞赋值。
  • 第 12 行:d1 <= din;非阻塞赋值,d1 在时钟沿更新为 din 的当前值。
  • 第 13 行:d2 <= d1;非阻塞赋值,d2 得到的是 d1 在时钟沿之前的值(即上一拍的 d1)。综合工具会推断出两个独立的寄存器:d1 和 d2,形成真正的 2 级流水线。
标签:
本文原创,作者:二牛学FPGA,其版权均为FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训所有。
如需转载,请注明出处:https://z.shaonianxue.cn/42830.html
二牛学FPGA

二牛学FPGA

初级工程师
这家伙真懒,几个字都不愿写!
1.07K21.14W4.08W3.67W
分享:
成电国芯FPGA赛事课即将上线
FPGA时序约束中多周期路径的常见错误与修复实践指南
FPGA时序约束中多周期路径的常见错误与修复实践指南上一篇
AI辅助EDA工具在FPGA布局布线中实现10%时序提升:实施指南与原理分析下一篇
AI辅助EDA工具在FPGA布局布线中实现10%时序提升:实施指南与原理分析
相关文章
总数:1.12K
开源FPGA工具链对国产FPGA架构适配进入量产验证阶段:技术解读与工程影响分析

开源FPGA工具链对国产FPGA架构适配进入量产验证阶段:技术解读与工程影响分析

QuickStart:从下载到运行第一个量产级测试步骤1:访问开源工具…
技术分享
1天前
0
0
11
0
FPGA是什么?(科普必看)

FPGA是什么?(科普必看)

经常被很多同学问到“FPGA是什么”,作为一名即将来成电少年学接受FPG…
技术分享, 行业资讯
3年前
1
1
990
1
数字IC前端设计入门指南:从Verilog到逻辑综合的实践路径

数字IC前端设计入门指南:从Verilog到逻辑综合的实践路径

本文旨在为初学者提供一条清晰、可执行的数字集成电路(IC)前端设计学习路…
技术分享
27天前
0
0
50
0
评论表单游客 您好,欢迎参与讨论。
加载中…
评论列表
总数:0
FPGA线上课程平台|最全栈的FPGA学习平台|FPGA工程师认证培训
没有相关内容