# Verilog 阻塞/非阻塞

# 阻塞赋值

阻塞赋值语句使用 = 赋值,并在程序块中一个接一个地执行。但是,这不会阻止执行在并行块中运行的语句。

module tb;
    reg [7:0] a, b, c, d, e;

    initial begin
        a = 8'hDA;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        b = 8'hF1;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        c = 8'h30;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    end

    initial begin
        d = 8'hAA;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
        e = 8'h55;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

请注意,有两个 initial 块在仿真开始时并行执行。语句在每个块中按顺序执行,两个块都在时间 0ns 完成。更具体地说,首先分配变量 a ,然后是 display 语句,然后是所有其他语句。这在输出中可见,其中变量 bc 在第一个显示语句中是 8'hxx 。这是因为在调用第一个 $display 时尚未执行变量 bc 的赋值。

仿真日志:

[0] a=0xda b=0xx c=0xx
[0] a=0xda b=0xf1 c=0xx
[0] a=0xda b=0xf1 c=0x30
[0] d=0xaa e=0xx
[0] d=0xaa e=0x55
1
2
3
4
5

在下一个示例中,我们将在同一组语句中添加一些延迟,以查看其行为方式。

module tb;
    reg [7:0] a, b, c, d, e;

    initial begin
        a = 8'hDA;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        #10 b = 8'hF1;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        c = 8'h30;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    end

    initial begin
        #5 d = 8'hAA;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
        #5 e = 8'h55;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

仿真日志:

[0] a=0xda b=0xx c=0xx
[5] d=0xaa e=0xx
[10] a=0xda b=0xf1 c=0xx
[10] a=0xda b=0xf1 c=0x30
[10] d=0xaa e=0x55
1
2
3
4
5

# 非阻塞赋值

非阻塞赋值允许在不阻塞执行后续语句的情况下调度赋值,并由 <= 符号指定。有趣的是,相同的符号在表达式中用作关系运算符,在非阻塞赋值的上下文中用作赋值运算符。如果我们采用上面的第一个示例,将所有 = 符号替换为非阻塞赋值运算符 <= ,我们将看到输出有所不同。

module tb;
    reg [7:0] a, b, c, d, e;

    initial begin
        a <= 8'hDA;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        b <= 8'hF1;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        c <= 8'h30;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    end

    initial begin
        d <= 8'hAA;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
        e <= 8'h55;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

看到所有的 $display 语句都打印了 x 。这种行为的原因在于非阻塞赋值的执行方式。捕获特定时间步的每个非阻塞语句的 RHS,并继续执行下一条语句。仅在时间步结束时将捕获的 RHS 值分配给 LHS 变量。

仿真日志:

[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] d=0xx e=0xx
[0] d=0xx e=0xx
1
2
3
4
5

因此,如果我们分解上述示例的执行流程,我们将得到如下所示的内容。

|__ Spawn Block1: initial
|      |___ Time #0ns : a <= 8'DA, is non-blocking so note value of RHS (8'hDA) and execute next step
|      |___ Time #0ns : $display() is blocking, so execute this statement: But a hasn't received new values so a=8'hx
|      |___ Time #0ns : b <= 8'F1, is non-blocking so note value of RHS (8'hF1) and execute next step
|      |___ Time #0ns : $display() is blocking, so execute this statement. But b hasn't received new values so b=8'hx
|      |___ Time #0ns : c <= 8'30, is non-blocking so note value of RHS (8'h30) and execute next step
|      |___ Time #0ns : $display() is blocking, so execute this statement. But c hasn't received new values so c=8'hx
|      |___ End of time-step and initial block, assign captured values into variables a, b, c
|
|__ Spawn Block2: initial
|      |___ Time #0ns : d <= 8'AA, is non-blocking so note value of RHS (8'hAA) and execute next step
|      |___ Time #0ns : $display() is blocking, so execute this statement: But d hasn't received new values so d=8'hx
|      |___ Time #0ns : e <= 8'55, is non-blocking so note value of RHS (8'h55) and execute next step
|      |___ Time #0ns : $display() is blocking, so execute this statement. But e hasn't received new values so e=8'hx
|      |___ End of time-step and initial block, assign captured values into variables d and e
|
|__ End of simulation at #0ns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

接下来,让我们使用第二个示例,将所有阻塞语句替换为非阻塞语句。

module tb;
    reg [7:0] a, b, c, d, e;

    initial begin
        a <= 8'hDA;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        #10 b <= 8'hF1;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
        c <= 8'h30;
        $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    end

    initial begin
        #5 d <= 8'hAA;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
        #5 e <= 8'h55;
        $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    end
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

我们再次可以看到输出与我们之前得到的不同。

[0] a=0xx b=0xx c=0xx
[5] d=0xx e=0xx
[10] a=0xda b=0xx c=0xx
[10] a=0xda b=0xx c=0xx
[10] d=0xaa e=0xx
1
2
3
4
5

如果我们分解执行流程,我们将得到如下所示的内容。

|__ Spawn Block1 at #0ns: initial
|      |___ Time #0ns : a <= 8'DA, is non-blocking so note value of RHS (8'hDA) and execute next step
|      |___ Time #0ns : $display() is blocking, so execute this statement: But a hasn't received new values so a=8'hx
|      |___ End of time-step : Assign captured value to variable a, and a is now 8'hDA
|      |___ Wait until time advances by 10 time-units to #10ns
|	
|      |___ Time #10ns : b <= 8'F1, is non-blocking so note value of RHS (8'hF1) and execute next step
|      |___ Time #10ns : $display() is blocking, so execute this statement. But b hasn't received new values so b=8'hx
|	   |___ Time #10ns : c <= 8'30, is non-blocking so note value of RHS (8'h30) and execute next step
|      |___ Time #10ns : $display() is blocking, so execute this statement. But c hasn't received new values so c=8'hx
|      |___ End of time-step and initial block, assign captured values into variables b, c
|	
|__ Spawn Block2 at #0ns: initial
|      |___ Wait until time advances by 5 time-units to #5ns
|	
|      |___ Time #5ns : d <= 8'AA, is non-blocking so note value of RHS (8'hAA) and execute next step
|      |___ Time #5ns : $display() is blocking, so execute this statement: But d hasn't received new values so d=8'hx
|      |___ End of time-step : Assign captured value to variable d, and d is now 8'hAA
|      |___ Wait until time advances by 5 time-units to #5ns
|	
|      |___ Time #10ns : e <= 8'55, is non-blocking so note value of RHS (8'h55) and execute next step
|      |___ Time #10ns : $display() is blocking, so execute this statement. But e hasn't received new values so e=8'hx
|      |___ End of time-step and initial block, assign captured values to variable e, and e is now 8'h55
|
|__ End of simulation at #10ns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
最后更新: 2022/10/6 01:12:51