Electronic – Blocking vs Non Blocking Assignments

fpgasynthesissystem-verilogverilog

I have been having a really hard time understanding the difference between blocking and non-blocking assignments in Verilog. I mean, I understand the conceptual difference between the two, but I am really lost when it comes to implementation.

I referred to a number of sources, including this question, but all the explanations seem to explain the difference in terms of code (what happens to the sequence of execution of lines when using blocking vs non-blocking). My question is a little different.

While writing verilog code (since I am writing it to be synthesized on an FPGA), I always try to visualize what the synthesized circuit is going to look like, and that is where the problem begins :

1) I am not able to understand how the changing from blocking to non-blocking assignments would alter my synthesized circuit. For example :

    always @* begin

        number_of_incoming_data_bytes_next <= number_of_incoming_data_bytes_reg;
        generate_input_fifo_push_pulse_next <= generate_input_fifo_push_pulse;

        if(state_reg == idle) begin
            // mealey outputs
            count_next = 8'b0;

            if((rx_done_tick) && (rx_data_out == START_BYTE)) begin
                state_next = read_incoming_data_length;
                end else begin
                    state_next = idle;
                end

        end else if(state_reg == read_incoming_data_length) begin
            // mealey outputs
            count_next = 8'b0;

            if(rx_done_tick) begin
                number_of_incoming_data_bytes_reg <= rx_data_out;
                state_next = reading;
            end else begin
                state_next = read_incoming_data_length;
            end

        end else if(state_reg == reading) begin

            if(count_reg == number_of_incoming_data_bytes_reg) begin
                state_next = idle;
                // do something to indicate that all the reading is done
                // and to send all the data in the fifo
            end else begin
                if(rx_done_tick) begin
                    generate_input_fifo_push_pulse_next = ~ generate_input_fifo_push_pulse;
                    count_next = count_reg + 1;
                end else begin
                    count_next = count_reg;
                end
            end

        end else begin
            count_next = 8'b0;
            state_next = idle;
        end
    end

In the above code, how would the synthesized circuit change if I replaced all the blocking assignments by non-blocking

2) Understanding the difference between blocking and non-blocking statements when written sequentially is a bit simpler (and most answers to this question focus on this part), but how do blocking assignments affect behaviours when they are declared in separate conditional behaviours. For example :

Would it make a difference if I wrote this:

if(rx_done_tick) begin
    a = 10;
end else begin
    a = 8;
end

or if I wrote this :

if(rx_done_tick) begin
    a <= 10;
end else begin
    a <= 8;
end

I know that conditional statements synthesize to become multiplexers or priority structures, and so I feel that using either blocking or non-blocking statements should not make a difference, but I am not sure.

3) When writing testbenches, I the result of the simulation is very different when using blocking v/s non-blocking statements.
The behaviour is very different if I write :

initial begin
    #31 rx_data_out = 255;
    rx_done_tick = 1;
    #2 rx_done_tick = 0;
    #30 rx_data_out = 3;
    rx_done_tick = 1;
    #2 rx_done_tick = 0;
    #30 rx_data_out = 10;
    rx_done_tick = 1;
    #2 rx_done_tick = 0;
end

versus when I write this :

initial begin
    #31 rx_data_out <= 255;
    rx_done_tick <= 1;
    #2 rx_done_tick <= 0;
    #30 rx_data_out <= 3;
    rx_done_tick <= 1;
    #2 rx_done_tick <= 0;
    #30 rx_data_out <= 10;
    rx_done_tick <= 1;
    #2 rx_done_tick <= 0;
end

This is very confusing. In my practice, the rx_done_tick signal is going to be generated by a Flip Flop. So, I think that non-blocking statements should be used to represent this behaviour. Am I right ?

4) Finally, when to use blocking assignments and when not to use non-blocking statements ? I.e is it true that blocking statements should be used only in combinational behaviours , and non-blocking statements in sequential behaviours only? If yes or No, why ?

Best Answer

1) I am not able to understand how the changing from blocking to non-blocking

The example code posted was for a combinatorial block, changing all blocking (=) to non-blocking (<=) may affect simulation but will not affect synthesis. This results in a RTL to gate level mismatch. It is an incorrect place to use the non-blocking assignment, do not use it in a combinatorial section.

To summarise for the other question non-blocking simulates that data changing just after an event such as the posedge of a clock. This allows correct simulation of a flip-flop.

this implies for testbenches:

initial begin
    #31 rx_data_out = 255;

At time 31 the assignment happens.

initial begin
    #31 rx_data_out <= 255;

Just after time 31 the assignment happens. Try both in parallel with a

initial begin
  #31 $display(rx_data_out);
end 

For the first example you actually have a race condition both happen at the same time, you should get 255 printed out. For the second example you will always have x printed because the assignment happens just after the time 31 event, not on it.

non blocking can be useful for testbenches were you want to mimic data being driven by flip-flops, i.e. it changes just after the event. for example releasing a power on reset.

initial begin
  @(posedge clk);
  @(posedge clk);
  rst_n <= 1'b0;
end

Imagine we had a series of flip-flops (a,b,c) creating a delay line, they each have d input and q output.

if the assignments were chained with :

c = b = a

Data would rush through from a to c instantly. but if we have

c <= b <= a

we have a pipeline, and each flip-flop can hold its value.

Actual code:

always @(posedge clk) begin
  c = b;
  b = a;
  a = in;
end

versus:

always @(posedge clk) begin
  c <= b;
  b <= a;
  a <= in;
end

This is why for question 2 with only one assignment it does not matter. but if there are multiple assignments that rely on each other it really does matter because you're controlling if it is driven from a flip-flop (<=) or a block of combinatorial logic (=).

My rules of thumb: Use blocking (=) for combinatorial logic and non-blocking (<=) for sequential (flip-flops)