以下 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;

在这种情况下会发生以下情况:

  1. r 将在稍后的模拟刻度中分配 in 的值,在评估了 always 块之后(请参阅 nba 调度区域)。

  2. 由于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