说出以下代码部分(同一块):
A <= 1
A <= 2
变量A总是被分配2吗?或是否会有竞争条件,将分配1或2?
我对非阻塞分配的理解是,在未来的时间由硬件来分配变量A,因此它可能是随机结果。但是,这不直观。模拟显示2总是被分配,但我想知道这是否肯定是硬件综合的情况。
答案 0 :(得分:8)
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
答案 1 :(得分:5)
在代码中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
和测试台:
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
在模拟过程中,更新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
...
然而,在综合中,这将简单地将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
(从理论上讲,第一行仍然可以说a=x
,但是每个体面的综合工具都会优化a
- 触发器,就像测试中的两个工具一样。)
除此之外,该代码没有潜在的问题,正如@Morgan在他的回答中正确指出的那样,这是一种非常常用的编码技术,用于在使用条件编码特殊情况之前定义输出信号的“默认值”作业(使用if
和/或case
)。
答案 2 :(得分:0)
根据IEEE标准(例如1800-2009)中的“确定性”部分,如果这些语句位于开始结束块中,则A将始终在模拟中分配值2.
但是,Std并不保证如何合成代码。重新分配门可能取决于综合工具。但是,一个好的RTL linting工具将识别这种糟糕的编码。 Cadence的Hal lint工具发出警告。
答案 3 :(得分:-3)
从RTL的角度来看。 “A”将被分配1和2,它可以是1,然后是2,反之亦然,但你不能真正知道在开始 - 结束块的末尾将分配哪个值,它可以是1或2(如分配的第二个值。