33. Assignment - Blocking vs Non-Blocking

module nb_blocking_order (
    input  clk,
    input  b,
    output reg c_block,
    output reg c_nblk
);
    reg a1, a2;

    initial begin
        a1 = 1'b0; a2 = 1'b0;
        c_block = 1'b0; c_nblk = 1'b0;
    end

    always @(posedge clk) begin
        // Flow 1: both blocking -> c_block sees NEW b immediately
        a1      = b;
        c_block = a1;

        // Flow 2: NBA then blocking -> c_nblk sees OLD a2 this edge
        a2     <= b;  // schedules update for end of timestep
        c_nblk =  a2; // reads old a2 now
    end
endmodule

💡Remember

  • Blocking = executes now, in order; later statements see the new value.
  • Non-blocking <= takes a snapshot now but updates at the end of the timestep.
  • Reordering doesn’t help: even if you write c_nblk = a2; a2 <= b;, c_nblk still sees old a2 this edge.
  • The effect here:
    • c_block = this cycle’s b
    • c_nblk = previous cycle’s b
  • Golden rule: = in combinational, <= in sequential. Avoid driving the same reg from different always blocks or mixing =/<= across blocks.

Testbench Code

`timescale 1ns/1ps

module tb_nb_blocking_order;
    // 1) Inputs
    reg clk;
    reg b;

    // 2) DUT outputs
    wire c_block;
    wire c_nblk;

    // 3) Expected (prefixed expected_)
    reg expected_c_block;
    reg expected_c_nblk;

    // 4) Mismatch (HIGH on fail)
    wire mismatch_block = (c_block !== expected_c_block);
    wire mismatch_nblk  = (c_nblk  !== expected_c_nblk);
    wire mismatch       = mismatch_block | mismatch_nblk;

    // Counters
    integer TOTAL_TEST_CASES        = 0;
    integer TOTAL_PASSED_TEST_CASES = 0;
    integer TOTAL_FAILED_TEST_CASES = 0;

    // VCD limit
    integer VCD_MAX_CASES = 32;

    // DUT
    nb_blocking_order dut(.clk(clk), .b(b), .c_block(c_block), .c_nblk(c_nblk));

    // VCD dump (Inputs -> Outputs -> Expected -> Mismatch)
    initial begin
        $dumpfile("tb_nb_blocking_order.vcd");
        $dumpvars(0,
            tb_nb_blocking_order.clk, tb_nb_blocking_order.b,                  // Inputs
            tb_nb_blocking_order.c_block, tb_nb_blocking_order.c_nblk,         // Outputs
            tb_nb_blocking_order.expected_c_block, tb_nb_blocking_order.expected_c_nblk, // Expected
            tb_nb_blocking_order.mismatch                                      // Mismatch
        );
        $dumpon; // start at t=0
    end

    // Clock
    localparam T = 10;
    initial clk = 0;
    always #(T/2) clk = ~clk;

    // Keep a 1-cycle history of b for expected model
    reg prev_b;

    initial begin
        b = 0; prev_b = 0;
        expected_c_block = 0; expected_c_nblk = 0;

        $display(" time | clk b | c_block c_nblk | exp_block exp_nblk | mismatch");
        $display("---------------------------------------------------------------");

        // apply 12 edges (≤ 20 printed rows overall)
        drive_and_check(0);
        drive_and_check(1);
        drive_and_check(1);
        drive_and_check(0);
        drive_and_check(1);
        drive_and_check(0);
        drive_and_check(1);
        drive_and_check(0);
        drive_and_check(1);
        drive_and_check(0);
        drive_and_check(1);
        drive_and_check(0);

        $display("---------------------------------------------------------------");
        $display("TOTAL_TEST_CASES=%0d", TOTAL_TEST_CASES);
        $display("TOTAL_PASSED_TEST_CASES=%0d", TOTAL_PASSED_TEST_CASES);
        $display("TOTAL_FAILED_TEST_CASES=%0d", TOTAL_FAILED_TEST_CASES);
        $display("ALL_TEST_CASES_PASSED=%s",
                 (TOTAL_FAILED_TEST_CASES==0) ? "true" : "false");

        #(T) $finish;
    end

    // Drive next b on negedge; check at following posedge
    task drive_and_check;
        input next_b;
        begin
            @(negedge clk);
            b = next_b;

            @(posedge clk);
            // Compute expected FIRST at the sampling edge
            expected_c_block = b;        // blocking chain ⇒ current b
            expected_c_nblk  = prev_b;   // NBA+blocking chain ⇒ previous b
            prev_b           = b;        // update history for next edge

            #1; // let DUT NBAs settle

            TOTAL_TEST_CASES++;
            if (!mismatch) TOTAL_PASSED_TEST_CASES++; else TOTAL_FAILED_TEST_CASES++;

            $display("%4t |  %0d   %0d |    %0d      %0d  |     %0d        %0d  |    %0d",
                     $time, clk, b, c_block, c_nblk,
                     expected_c_block, expected_c_nblk, mismatch);

            if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
        end
    endtask
endmodule