2
\$\begingroup\$

I am having a very difficult time to understand the logic behind the naming of "Blocking" and "Non-blocking" statements in Verilog.

By definition, Blocking assignment evaluates and assigns values immediate. Whereas, Non-blocking assignment deferred until all right-hand sides have been evaluated (See reference)

Here I have created two test modules to verify this definition in Vivado 2022:

// module to test non-blocking
module NonBlockingTest(D, Clk, Qa, Qb, Qc);
 input D, Clk;
 output reg Qa, Qb, Qc;
 
 always @(posedge Clk)
 begin
 Qa <= D;
 Qb <= Qa;
 Qc <= Qb; 
 end
endmodule
// module to test blocking
module BlockingTest(D, Clk, Qd, Qe, Qf);
 input D, Clk;
 output reg Qd, Qe, Qf;
 
 always @(posedge Clk)
 begin
 Qd = D;
 Qe = Qd;
 Qf = Qe; 
 end
endmodule

And here is the test bench:

module NonBlockingTest_TB();
 reg D, Clk;
 wire Qa, Qb, Qc;
 NonBlockingTest DUT_NonBlocking(D, Clk, Qa, Qb, Qc);
 BlockingTest DUT_Blocking(D, Clk, Qd, Qe, Qf);
 
 initial
 begin
 Clk = 0;
 D = 1;
 #50;
 Clk = 1;
 #50;
 Clk = 0;
 #50;
 Clk = 1;
 #50;
 Clk = 0;
 #50;
 Clk = 1;
 #50;
 Clk = 0;
 end
 
endmodule

The result is not what I expected: enter image description here Qa, Qb, Qc come from non-blocking assignment, yet they are executed sequentially.

Qd, Qe, Qf come from blocking assignment, yet they are executed at simultaneously.

From the meaning of the English word itself, it appears that "=" is the non-blocking assignment, while "<=" is the blocking assignment.

Am I interpreting the word 'blocking' incorrectly?

asked Mar 22, 2024 at 3:42
\$\endgroup\$
4
  • \$\begingroup\$ I think it is nicely written. But there's a few subtle bits. One is that simulation \$\ne\$ synthesis. And the sheet starts out mentioning simulation and then heads over and shows a possible synthesis to make their point. Slide 4, right side: when clk goes hi, q1 gets assigned in. But inside that block, to assign q2 to the value of q1 all synthesis needs to do is just wire the two together. Etc. So one latch. Left side: in this case, synthesis knows it has to collect up all three values first and move things over all at the same time with clk. That means 3 latches. \$\endgroup\$ Commented Mar 22, 2024 at 4:30
  • \$\begingroup\$ this may help chipverify.com/verilog/verilog-blocking-non-blocking-statements \$\endgroup\$ Commented Mar 22, 2024 at 14:28
  • 1
    \$\begingroup\$ a way to remember ... non blocking is two words and the symbol contains two characters <= \$\endgroup\$ Commented Mar 22, 2024 at 14:31
  • \$\begingroup\$ @jsotola Except nonblocking is one word according to the IEEE. \$\endgroup\$ Commented Mar 23, 2024 at 0:57

4 Answers 4

2
\$\begingroup\$

It might help by referring to the following diagram in page 5 of the reference that you provided.

enter image description here

For blocking, you see x = a & b is evaluated after a changes from 1 to 0. And then y = x | c is evaluated after x = a & b has been evaluated. It is blocking in that sense.

For non-blocking, you see x = a & b is evaluated, but not immediately assigned (is deferred). Notice that y = x | c appears to be evaluated without waiting for x = a & b result; otherwise y would have been 0 instead of 1 because x = 0. It is non-blocking in that sense.

To understand your result, below is the table showing the update progression for BlockingTest:

Clock Cycle D Qd Qe Qf Evaluation
0 1 1 0 0 Qd = D
0 1 1 1 0 Qe = Qd
0 1 1 1 1 Qf = Qe
1 1 1 1 1 Qd = D
1 1 1 1 1 Qe = Qd
1 1 1 1 1 Qf = Qe
2 1 1 1 1 Qd = D
2 1 1 1 1 Qe = Qd
2 1 1 1 1 Qf = Qe

By the end of the clock cycle 0, you see Qd, Qe, and Qf have taken the value of D=1. This is because Qe waits for Qd to be assigned with the value 'D=1' before it itself being updated. Similarly, Qf waits for Qe to be assigned with the value 'Qd=1' before it itself being updated.

The following table shows the update progression for NonBlockingTest:

Clock Cycle D Qa Qb Qc Qa' Qb' Qc' Evaluation
0 1 1 0 0 0 0 0 Qa <= D
0 1 1 0 0 0 0 0 Qb <= Qa'
0 1 1 0 0 0 0 0 Qc <= Qb'
1 1 1 0 0 1 0 0 Qa <= D
1 1 1 1 0 1 0 0 Qb <= Qa'
1 1 1 1 0 1 0 0 Qc <= Qb'
2 1 1 1 0 1 1 0 Qa <= D
2 1 1 1 0 1 1 0 Qb <= Qa'
2 1 1 1 1 1 1 0 Qc <= Qb'

where Qa', Qb', and Qc' are the immediate previous values of Qa, Qb, and Qc, respectively. In each clock cycle, each variable is assigned with the immediate previous values of the variables on the RHS of the expressions because in non-blocking code, the evaluations do not wait for the others to complete. Hence it takes a number of clock cycles before every variable settles on the final values of 1's.

answered Mar 22, 2024 at 6:06
\$\endgroup\$
3
  • \$\begingroup\$ Thank you for creating the two tables. They really help illustrating the differences. \$\endgroup\$ Commented Mar 23, 2024 at 3:46
  • \$\begingroup\$ For the NonBlocking Table, did you mean to use '<=' instead of '='? Like 'Qa <= D'? \$\endgroup\$ Commented Mar 23, 2024 at 3:55
  • \$\begingroup\$ Yes, correct. I have amended it. \$\endgroup\$ Commented Mar 23, 2024 at 8:55
2
\$\begingroup\$

The term "blocking" was originally intended just to describe the potential to suspend a process. A clarifying description of this terminology was just added to the Annex P Glossary in the IEEE 1800-2023 SystemVerilog LRM:

blocking statement: A construct having the potential to suspend a process. This potential is determined through lexical analysis of the source syntax alone, not by execution semantics. For example, the statement wait(1) is considered a blocking statement even though evaluation of the expression '1' will be true at execution. All statements with procedural event controls (see 9.4) become blocking statements. A task enable is also a blocking statement because the task may itself contain a blocking statement. The task caller is not required to recursively investigate the task body.

A blocking assignment (see 10.4.1) is only considered a blocking statement when the syntax contains an optional intra-assignment delay. Without the delay, a blocking assignment is not a blocking statement. A nonblocking assignment (see 10.4.2) is never a blocking statement.

I would suggest never using a blocking assignment with an inter-assignment delay, and simply calling it a procedural assignment.

answered Mar 22, 2024 at 14:51
\$\endgroup\$
1
\$\begingroup\$

Qa, Qb, Qc come from non-blocking assignment, yet they are executed one after another,

You're seeing Qb has its value changed on the 2nd clock edge and calling that "executing one after the other". This is not correct.

When we say the assignment is non-blocking, what it means is that on the first clock edge, all three of the assignment statements execute. But because the first assignment is non-blocking, the right-hand-side of the second assignment uses the "old" values of its signals. The process isn't "blocked" to wait for the first assignment to happen before the r.h.s. of the second assignment is evaluated. So since Qa is initially X, Qb is assigned X (the same value it had before) on this edge.

Only on the second clock edge will the Qb assignment see that Qa has changed to 1 and get that value.

answered Mar 22, 2024 at 15:46
\$\endgroup\$
1
  • \$\begingroup\$ I suppose for Qd, Qe, Qf, the process waits for all three assignment completes before "clocking in", hence, we are observing all three outputs go high on 1st clock's rising edge. It makes sense now. \$\endgroup\$ Commented Mar 23, 2024 at 3:44
1
\$\begingroup\$

Non-blocking statements have the following meaning:

always @(posedge Clk)
begin
 Qa_after_end <= D_before_begin;
 Qb_after_end <= Qa_before_begin;
 Qc_after_end <= Qb_begin_begin; 
end

In effect, D, Qa, Qb, Qc form a shift register. The assignments are all executed in parallel, after the block end. This is borne out in the simulation results.

enter image description here

always @(posedge Clk)
begin
 Qd_below_this_line = D_above_this_line;
 Qe_below_this_line = Qd_above_this_line;
 Qf_below_this_line = Qe_above_this_line; 
end

Qd, Qe, and Qf all take on the value of D, because the assignments are executed sequentially within the block. But note that this all happens within the same clock cycle, and takes zero time. The sequence of assignments only establishes how the values propagate. The above block simplifies to:

always @(posedge Clk)
begin
 Qd_below_this_line = D_above_this_line;
 Qe_below_this_line = Qd_above_this_line = D_above_this_line;
 Qf_below_this_line = Qe_above_this_line = D_above_this_line;
end

Now, since the ultimate value referred to on the right side of the assignment (D) is never same as the destination on the left, the "above this line" and "below this line" distinctions are not necessary anymore, and the block is equivalent to:

always @(posedge Clk)
begin
 Qd = D;
 Qe = D;
 Qf = D;
end

And, as you can see in the simulation results, after the positive edge of the clock, Qd, Qe and Qf do indeed all take the value of D.

enter image description here

answered Mar 22, 2024 at 20:34
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.