verilog - 如何理解verilog中的阻塞和非阻塞语句?
问题描述
我了解 Verilog 中阻塞和非阻塞语句的基本区别。但是我仍然无法理解&
何时何地使用阻塞和非阻塞语句发生了什么。例如,考虑简单的 d ff 代码:
module dff (clk, reset,d, q, qb);
input clk;
input reset;
input d;
output q;
output qb;
reg q;
assign qb = ~q;
always @(posedge clk or posedge reset)
begin
if (reset) begin
// Asynchronous reset when reset goes high
q <= 1'b0;
end else begin
// Assign D to Q on positive clock edge
q <= d;
end
end
endmodule
但是,如果我使用两段编码技术编写完全相同的逻辑:
module dff(input wire d,
clk,
reset,
en,
output wire q);
reg q;
reg r_reg, r_next;
always @(posedge clk, posedge reset)
if(reset)
r_reg<=1'b0;
else
r_reg<=r_next;
always @*
if(en)
r_reg=d;
else
r_reg=r_next;
assign q<=r_reg;
endmodule
现在,在这段代码中,我只是不明白为什么<=
在第一个 always 块中使用以及为什么=
在第二个 always 块中使用。我也知道在组合逻辑电路=
中建议&
按顺序使用,<=
建议使用。但是,我仍然无法找到使用阻塞和非阻塞语句的答案。你能帮我么!?
解决方案
阻塞/非阻塞分配只是一个模拟工件。与相信相反,verilog 没有描述硬件。Verilog 描述了硬件的期望行为,试图使其适应事件驱动的仿真方案。
这是一个使用 2 个触发器的移位寄存器的简单示例:
always @(posedge clk)
out1 = in;
always @(posedge clk)
out2 = out1;
现在,out2 的输出是什么?由于我们正在处理模拟,因此它取决于执行这两条语句的顺序。要么是 out1 的旧值,要么是新值(实际上是 in 的值);。
在硬件中没有这样的混乱。它将翻转在 posedge 时间存在的值,即 out1 的旧值(好吧,除非时钟出现异常延迟)。
为了匹配这种行为,引入了非阻塞赋值。Verilog 模拟是在模拟滴答中完成的。只要有可能导致重新评估其他块的事件,每个滴答声都是如此。非阻塞分配被安排在当前 rhs 值的这种滴答结束时执行(实际上有几个调度区域)。因此,请考虑以下事项:
always @(posedge clk)
out1 <= in;
always @(posedge clk)
out2 <= out1;
在上面的例子中,所有的分配都将在滴答结束时发生。'out2' 将被分配一个在 <= 时存在的值,因此,它将是 out1 的旧值。现在,它们执行的顺序无关紧要。
因此,顶级建议是对组合逻辑使用阻塞分配 (=),对状态设备、触发器和锁存器的所有输出使用非阻塞分配 (<=)。请注意,状态设备内部的一些临时变量,仅在内部使用,也应该分配阻塞。此外,切勿在时钟树中使用非阻塞分配。
推荐阅读
- mongodb - mongodb C驱动程序如何使用正则表达式通过_id过滤更改流
- php - 如何使用 SQL 将不同的数据库表组合成一个表?
- gpu - Nvidia v100 上的 HPL HPCG 基准测试仅消耗一半功率
- php - 如何在 Visual Studio Code 中为每个项目/工作区设置 PHP 版本?
- javascript - jQuery-brackets:如何保存到 python/sqlite3?
- python - Python纸牌游戏-尝试将弹出的对象从一个类附加到另一个类
- sql - 我们可以使用动态 SQL 或循环来自动化这个过程吗?
- pandas - 如何从 Pandas 中的 2 个数据框列计算时间差(以分钟为单位)
- python - Python NonExistentTimeError - 不同机器中的不同行为
- python - Numpy数字不是整数?