说下面的代码部分(同一块):
A <= 1
A <= 2
Run Code Online (Sandbox Code Playgroud)
变量A总是被分配2吗?或者是否会有竞争条件,将分配1或2?
我对非阻塞分配的理解是,在未来的时间由硬件来分配变量A,因此它可能是随机的结果.但是,这不直观.模拟显示2总是被分配,但我想知道这是否肯定是硬件合成的情况.
A在模拟中为2,最后定义的值生效.如果它们不在同一个程序段中,则可能存在竞争条件,具体取决于模拟器调度程序在模拟中最后定义的情况.
我已经看到这种技术使用了很多,并且从未在合成后看到任何意外的结果,但正如其他人所提到的,这不是由verilog规范保证或涵盖的.
使用它可能是一个稀疏定义其输出的FSM:
always @(posedge clk) begin
out_one <= 1'b0;
out_two <= 1'b0;
out_thr <= 1'b0;
case (state)
2'd1 : out_one <= 1'b1;
2'd2 : out_two <= 1'b1;
2'd3 : out_thr <= 1'b1;
endcase
end
Run Code Online (Sandbox Code Playgroud)
关于A代码的最终价值没有任何不确定性,不是用于模拟,也不是用于合成.
但是,绝对准确的是,如果设计包含触发器,则可能存在仿真合成不匹配A.请考虑以下示例:
module test(input clk, output reg a, b);
always @(posedge clk) begin
a <= 0;
a <= 1;
end
initial b = 0;
always @(posedge a) begin
b <= !b;
end
endmodule
Run Code Online (Sandbox Code Playgroud)
和测试台:
module tb;
reg clk = 0;
always #5 clk = ~clk;
wire a, b;
test uut (clk, a, b);
initial begin
$monitor("clk=%b a=%b b=%b", clk, a, b);
repeat (100) @(posedge clk);
$finish;
end
endmodule
Run Code Online (Sandbox Code Playgroud)
在模拟两个更新a <= 0,并a <= 1推到NBA赛事区域和在顺序执行,所以a最终总是被设置.但是,当a <= 0执行时a,每个时钟周期都有一个负宽度为零的负脉冲.该脉冲触发第二个始终阻塞.这是模拟输出(使用Icarus Verilog和Modelsim测试):
clk=0 a=x b=0
clk=1 a=1 b=1
clk=0 a=1 b=1
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=1
clk=0 a=1 b=1
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=1
clk=0 a=1 b=1
clk=1 a=1 b=0
clk=0 a=1 b=0
...
Run Code Online (Sandbox Code Playgroud)
但是,在合成中,这将简单地分配a常数值1和b常数值零.(经Yosys和Xilinx Vivado测试.)所以后综合模拟输出如下所示:
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
clk=0 a=1 b=0
clk=1 a=1 b=0
Run Code Online (Sandbox Code Playgroud)
(从理论上讲,第一行仍然可以说a=x,但是每个合适的综合工具都会优化a-flip-flop,因为测试中的两个工具都可以.)
除此之外,该代码没有潜在的问题,正如@Morgan在他的回答中正确指出的那样,这是一种非常常用的编码技术,用于在使用条件赋值对特殊情况进行编码之前定义输出信号的"默认值"(使用if和/或case).