说出以下代码部分(同一块):
A <= 1
A <= 2
变量 A 总是被赋值为 2 吗?还是会有竞争条件并分配1或2?
我对非阻塞分配的理解是,由硬件在将来分配变量 A ,因此它可能是随机结果。然而,这是不直观的。模拟显示 2 总是被分配,但我想知道这是否绝对是硬件综合的情况。
A 在模拟中为 2,最后定义的值生效。如果它们不在同一个块中,则可能存在竞争条件,具体取决于模拟器调度程序,该调度程序是在模拟中最后定义的。
我已经看到这种技术被大量使用,并且在合成后从未见过任何意想不到的结果。
来自 Verilog IEEE 1364-2005 第 11.4.1 节确定性
begin-end 块中的语句应按照它们在该 begin-end 块中出现的顺序执行。特定开始-结束块中语句的执行可以暂停以支持模型中的其他进程;但是,在任何情况下,begin-end 块中的语句都不应以它们在源代码中出现的顺序以外的任何顺序执行。
这也在 SystemVerilog-IEEE1800 2012 中作为第 4.6 节确定性
这可能是一个 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
代码中的最终值没有任何不确定性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
-flip-flop,就像测试中的两个工具一样。)
Other than that there is no potential issue with that code, and as @Morgan pointed out correctly in his answer, this is a very usual coding technique for defining the "default values" of output signals before encoding the special cases using conditional assignments (using if
and/or case
).
根据 IEEE 标准(例如 1800-2009 年)中的“确定性”部分,如果这些语句位于开始-结束块中,则在模拟中将始终为 A 分配值 2。
但是,Std 不保证如何合成代码。结果门可能取决于综合工具。但是,一个好的 RTL linting 工具会识别出这种糟糕的编码。Cadence 的 Hal lint 工具发出警告。
从 RTL 的角度来看。"A" 将被分配 1 和 2,它可以先是 1,然后是 2,反之亦然,但你无法真正知道在 begin-end 块的末尾将分配哪个值,它可以是 1 或 2(如分配的第二个值)。