以下 verilog 代码是否存在竞争条件问题?
Does the following verilog code have a race condition issue?
我正在使用一个 verilog 模块(如下所示),它有两个 always 块。不会有某种竞争条件,因为一个块设置一个寄存器而另一个块使用寄存器。这会导致什么样的问题?
谢谢,
斯蒂芬
module XYZ
(
input wire CLK,
input wire Reset,
input wire nReset,
input wire [15:0] X,
input wire [15:0] A,
input wire T,
input wire B,
output reg M
);
assign C = X > A;
reg P;
reg N;
always @(posedge CLK, negedge nReset)
begin
if (~nReset)
begin
P <= 1;
N <= 1;
end else begin
if (Reset)
begin
P <= 1;
N <= 1;
end else begin
P <= T? 1: ((C & ~M)? 0: P);
N <= B? 1: ((M & ~C)? 0: N);
end
end
end
always @(posedge CLK, negedge nReset)
begin
if (~nReset)
begin
M <= 0;
end else begin
if (Reset)
begin
M <= 0;
end else begin
M <= M? ~(N & ~C): (P & C);
end
end
end
结束模块
不,没有竞争条件。 Verilog 是一个事件驱动的模拟器。 Posedge(除非时钟或重置出现故障)通常在每个模拟节拍执行一次。如果你正确地使用了非阻塞赋值(看起来你确实这样做了),每个由边缘触发的总是块将使用旧版本的输入变量值,这些值在之前存在时钟边沿。
这是一个简化的例子:
always @(posedge clk)
r <= in;
always @(posedge clk)
out <= r;
在这种情况下会发生以下情况:
r
将在稍后的模拟刻度中分配 in
的值,在评估了 always 块之后(请参阅 nba 调度区域)。
由于r
还没有真正改变,所以out
会被调度赋值给r
边缘之前的值。
如果r
在边缘之前为0,in
为1,则在模拟结束时r
将变为1,而out
将变为0.
这模拟了硬件中真实触发器的行为。
在您的情况下,它可能看起来像一个循环依赖项。实际上它是 none。出于与上述相同的原因,M
值将是 posedge 之前的值,并且不会导致任何竞争。由于触发器的属性逻辑属性,触发器不能参与组合循环。
我完全同意上面的答案,我会建议上面的答案更多,当我开始学习 Verilog 时,我也有同样的疑问,这些行来自 ref。书澄清了我的疑惑。我正在处理这里的声明
如有进一步疑问,您可以在此处发表评论,或者您可以查看
- 参考。书页码 135
- 书名:Verilog HDL:数字设计与合成指南,
Samir Palnitkar 第二版
nonblocking statements used in Example 2 eliminate the race condition.
At the positive edge of clock, the values of all right-hand-side
variables are "read," and the right-hand-side expressions are
evaluated and stored in temporary variables. During the write
operation, the values stored in the temporary variables are assigned
to the left-handside variables. Separating the read and write
operations ensures that the values of registers a and b are swapped
correctly, regardless of the order in which the write operations are
performed.
On the downside, nonblocking assignments can potentially cause a
degradation in the simulator performance and increase in memory usage.
//Example 2: Two concurrent always blocks with nonblocking
//statements
always @(posedge clock)
a <= b;
always @(posedge clock)
b <= a;
而且你可以使用这种类型的编码风格,但不是强制性的,但为了便于调试和加强模拟,你可以尽可能减少开始结束块的使用
module XYZ
(
input wire CLK,
input wire Reset,
input wire nReset,
input wire [15:0] X,
input wire [15:0] A,
input wire T,
input wire B,
output reg M
);
reg P,N;
always @(posedge CLK, negedge nReset)
if (~nReset)begin
P <= #10 1;
N <= #10 1;
end else if (Reset) begin
P <= #10 1;
N <= #10 1;
end else begin
P <= #10 T ? 1 : ((C & ~M) ? 0: P);
N <= #10 B ? 1 : ((M & ~C) ? 0: N);
end
always @(posedge CLK, negedge nReset)
if (~nReset) M <= #10 0 ;
else if ( Reset) M <= #10 0 ;
else M <= #10 M ? ~(N & ~C): (P & C);
assign C = X > A;
endmodule
我正在使用一个 verilog 模块(如下所示),它有两个 always 块。不会有某种竞争条件,因为一个块设置一个寄存器而另一个块使用寄存器。这会导致什么样的问题?
谢谢, 斯蒂芬
module XYZ
(
input wire CLK,
input wire Reset,
input wire nReset,
input wire [15:0] X,
input wire [15:0] A,
input wire T,
input wire B,
output reg M
);
assign C = X > A;
reg P;
reg N;
always @(posedge CLK, negedge nReset)
begin
if (~nReset)
begin
P <= 1;
N <= 1;
end else begin
if (Reset)
begin
P <= 1;
N <= 1;
end else begin
P <= T? 1: ((C & ~M)? 0: P);
N <= B? 1: ((M & ~C)? 0: N);
end
end
end
always @(posedge CLK, negedge nReset)
begin
if (~nReset)
begin
M <= 0;
end else begin
if (Reset)
begin
M <= 0;
end else begin
M <= M? ~(N & ~C): (P & C);
end
end
end
结束模块
不,没有竞争条件。 Verilog 是一个事件驱动的模拟器。 Posedge(除非时钟或重置出现故障)通常在每个模拟节拍执行一次。如果你正确地使用了非阻塞赋值(看起来你确实这样做了),每个由边缘触发的总是块将使用旧版本的输入变量值,这些值在之前存在时钟边沿。
这是一个简化的例子:
always @(posedge clk)
r <= in;
always @(posedge clk)
out <= r;
在这种情况下会发生以下情况:
r
将在稍后的模拟刻度中分配in
的值,在评估了 always 块之后(请参阅 nba 调度区域)。由于
r
还没有真正改变,所以out
会被调度赋值给r
边缘之前的值。
如果r
在边缘之前为0,in
为1,则在模拟结束时r
将变为1,而out
将变为0.
这模拟了硬件中真实触发器的行为。
在您的情况下,它可能看起来像一个循环依赖项。实际上它是 none。出于与上述相同的原因,M
值将是 posedge 之前的值,并且不会导致任何竞争。由于触发器的属性逻辑属性,触发器不能参与组合循环。
我完全同意上面的答案,我会建议上面的答案更多,当我开始学习 Verilog 时,我也有同样的疑问,这些行来自 ref。书澄清了我的疑惑。我正在处理这里的声明 如有进一步疑问,您可以在此处发表评论,或者您可以查看
- 参考。书页码 135
- 书名:Verilog HDL:数字设计与合成指南, Samir Palnitkar 第二版
nonblocking statements used in Example 2 eliminate the race condition. At the positive edge of clock, the values of all right-hand-side variables are "read," and the right-hand-side expressions are evaluated and stored in temporary variables. During the write operation, the values stored in the temporary variables are assigned to the left-handside variables. Separating the read and write operations ensures that the values of registers a and b are swapped correctly, regardless of the order in which the write operations are performed. On the downside, nonblocking assignments can potentially cause a degradation in the simulator performance and increase in memory usage.
//Example 2: Two concurrent always blocks with nonblocking
//statements
always @(posedge clock)
a <= b;
always @(posedge clock)
b <= a;
而且你可以使用这种类型的编码风格,但不是强制性的,但为了便于调试和加强模拟,你可以尽可能减少开始结束块的使用
module XYZ
(
input wire CLK,
input wire Reset,
input wire nReset,
input wire [15:0] X,
input wire [15:0] A,
input wire T,
input wire B,
output reg M
);
reg P,N;
always @(posedge CLK, negedge nReset)
if (~nReset)begin
P <= #10 1;
N <= #10 1;
end else if (Reset) begin
P <= #10 1;
N <= #10 1;
end else begin
P <= #10 T ? 1 : ((C & ~M) ? 0: P);
N <= #10 B ? 1 : ((M & ~C) ? 0: N);
end
always @(posedge CLK, negedge nReset)
if (~nReset) M <= #10 0 ;
else if ( Reset) M <= #10 0 ;
else M <= #10 M ? ~(N & ~C): (P & C);
assign C = X > A;
endmodule