Blocking or non-blocking statement (= vs. <=)

Should i take by defacto that:

  1. all description of combinatorial logic should use the blocking assignment: =
  2. all description of sequential logic should be using non-blocking assignments: <=

i.e.


always_comb begin
a = b & c;
z = x & w;
end

always_ff @(posedge clk) begin
a <= b & c
z <= x & w;
end

or does the following would also result in any different synthesized circuit?


always_comb begin
a <= b & c;
z <= x & w;
end

always_ff @(posed clk) begin
a = b & c
z = x & w;
end

Thank you for your comments,

In reply to stefaniemcg:

Non-blocking assignments were created to help model sequential logic. They help distinguish between the old and new value of a signal. They should be avoided in combinatorial logic as they can create problems with simulation if there are multiple clock domains. It also creates a lot of unnecessary signal rippling. Synthesis tools don’t care.

For a sequential block, you can mix combinatorial and sequential logic in the same block. Which assignment type you choose makes a difference in synthesis/simulation when making an assignment before reading it in the same block.

always_ff @(posdege clk) begin
a = b & c;
z <= a & w; // same as b & c & w;
end
always_ff @(posdege clk) begin
a <= b & c;
z <= a & w; // uses previous cycle value of b & c.
end

You must use a non-blocking assignment when one process reads, and another process write to the same variable and they are both synchronized to the same clock.

Thank you @dave_59.

An extra question popped out:
In the case of functions and tasks what would the the right assignment?

To my understanding:

  • Functions are executed in a sequence, they are synthesized as combinatorial, and in execution time they are instantaneous (do not consume time).
  • Tasks on the other hand, are executed also in a sequence but can have timing controls, so they could be synthesized both sequential (if they wait for a clock) and combinatorial (if they wait for any other signal).

So, my guess is:

  1. all functions should always use blocking assignments: =, because of their sequence, combinatorial, and instantaneous nature
  2. all tasks should also always use the blocking assignments: =, because of their sequence execution nature

Are my understanding/guess correct?
or please clarify, :) thank you

In reply to stefaniemcg:

Your conclusions are mainly correct, but not for the reasons mentioned.

The body of code inside tasks and functions are inlined/expanded in the place where they are called for synthesis. After expansion, that code follows the same synthesis coding guidelines for blocking and nonblocking assignments in any procedural code block.

However, assignments to the function’s return value, and task/function output arguments must use blocking assignments because they get copied out upon returning from the task/function. If you used non-blocking assignment, the argument values will not have been updated before being copied out.