40. 3-Way Selector

Solution using default value to avoid latch:

module selector3 (
    input  [7:0] a,
    input  [7:0] b,
    input  [7:0] c,
    input  [1:0] sel,
    output reg [7:0] y
);
    always @* begin
        y = 8'h00; // default, avoids latchiong behaviour

        if (sel == 2'b00) begin
            y = a;
        end else if (sel == 2'b01) begin
            y = b;
        end else if (sel == 2'b10) begin
            y = c;
        end
    end
endmodule

Solution using else block to avoid latch:

module selector3 (
    input  [7:0] a,
    input  [7:0] b,
    input  [7:0] c,
    input  [1:0] sel,
    output reg [7:0] y
);
    always @* begin
        
        if (sel == 2'b00) begin
            y = a;
        end else if (sel == 2'b01) begin
            y = b;
        end else if (sel == 2'b10) begin
            y = c;
        end else begin
            y = 8'h00;
        end
    end
endmodule

💡Remember

  • Latch inference happens only if some input cases don’t assign outputs.
  • With if–else, always include default assignments or a final else.
  • With the ternary ?: operator, the default is explicit in the last : clause — naturally latch-free.
  • Both styles synthesize to the same mux hardware.

Testbench Code

`timescale 1ns/1ps

module tb_selector3;
    // -------- Inputs --------
    reg  [7:0] a, b, c;
    reg  [1:0] sel;

    // -------- DUT outputs --------
    wire [7:0] y;

    // -------- Expected --------
    wire [7:0] expected_y;

    // -------- Mismatch --------
    reg  mismatch;
    wire mismatch_w = (y !== expected_y);

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

    integer VCD_MAX_CASES = 32;

    // DUT
    selector3 dut(.a(a), .b(b), .c(c), .sel(sel), .y(y));

    // Golden model
    assign expected_y =
        (sel == 2'b00) ? a :
        (sel == 2'b01) ? b :
        (sel == 2'b10) ? c : 8'h00;

    // VCD setup
    initial begin
        $dumpfile("tb_selector3.vcd");
        $dumpvars(0,
            tb_selector3.a, tb_selector3.b, tb_selector3.c, tb_selector3.sel, // Inputs
            tb_selector3.y,                                                  // Output
            tb_selector3.expected_y,                                         // Expected
            tb_selector3.mismatch                                            // Mismatch
        );
        $dumpon;
    end

    initial begin
        a=0; b=0; c=0; sel=0;
        mismatch=0;
        $display("  a     b     c   sel |  DUT_y  | expected_y | mismatch");
        $display("-------------------------------------------------------");
    end

    task apply_and_check;
        input [7:0] ta, tb, tc;
        input [1:0] tsel;
        begin
            a = ta; b = tb; c = tc; sel = tsel;
            #1;
            mismatch = mismatch_w;

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

            $display("0x%02h 0x%02h 0x%02h  %b  | 0x%02h |   0x%02h   |   %0d",
                a, b, c, sel, y, expected_y, mismatch);

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

    initial begin
        // Full truth table over sel (fixed inputs)
        apply_and_check(8'h11,8'h22,8'h33,2'b00);
        apply_and_check(8'h11,8'h22,8'h33,2'b01);
        apply_and_check(8'h11,8'h22,8'h33,2'b10);
        apply_and_check(8'h11,8'h22,8'h33,2'b11);

        // Some randomized cases
        repeat (12) apply_and_check($random, $random, $random, $random % 4);

        // Logs
        $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");

        #2 $finish;
    end
endmodule