42. Instruction Decoder with Don’t-Care

Design a small instruction decoder that recognises opcodes with don’t-care bits.

Requirements

  • Module: opcode_decoder
  • Inputs: opcode[3:0]
  • Outputs: alu_op[3:0]

Behavior

  • If opcode[3:0] = 4'b1???:alu_op = ADD (4'b0001)
  • If opcode[3:0] = 4'b01??:alu_op = SUB (4'b0010)
  • Otherwise → alu_op = NOP (4'b0000)

Testbench Code

`timescale 1ns/1ps

module tb_opcode_decoder;
    // 1) Input
    reg  [3:0] opcode;

    // 2) DUT output
    wire [3:0] alu_op;

    // 3) Expected
    wire [3:0] expected_alu_op;

    // 4) Mismatch
    reg mismatch;
    wire mismatch_w = (alu_op !== expected_alu_op);

    integer TOTAL_TEST_CASES=0, TOTAL_PASSED_TEST_CASES=0, TOTAL_FAILED_TEST_CASES=0;
    integer VCD_MAX_CASES = 32;

    // DUT
    opcode_decoder dut(.opcode(opcode), .alu_op(alu_op));

    // Golden model (matches spec with don’t-cares)
    assign expected_alu_op =
        (opcode[3] == 1'b1)     ? 4'b0001 : // ADD group
        (opcode[3:2] == 2'b01) ? 4'b0010 : // SUB group
                                 4'b0000;  // NOP

    // VCD
    initial begin
        $dumpfile("tb_opcode_decoder.vcd");
        $dumpvars(0,
            tb_opcode_decoder.opcode,              // input
            tb_opcode_decoder.alu_op,              // output
            tb_opcode_decoder.expected_alu_op,     // expected
            tb_opcode_decoder.mismatch             // mismatch
        );
        $dumpon;
    end

    // Init
    initial begin
        opcode=0; mismatch=0;
        $display("opcode | alu_op | expected | mismatch");
        $display("-------------------------------------");
    end

    // Apply + check
    task apply_and_check;
        input [3:0] t_opcode;
        begin
            opcode = t_opcode;
            #1;
            mismatch = mismatch_w;

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

            $display(" %b  |  %b  |   %b   |   %0d",
                     opcode, alu_op, expected_alu_op, mismatch);

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

    // Stimulus
    initial begin
        // Directed ADD cases (1xxx)
        apply_and_check(4'b1000);
        apply_and_check(4'b1111);
        apply_and_check(4'b1010);

        // Directed SUB cases (01xx)
        apply_and_check(4'b0100);
        apply_and_check(4'b0111);

        // Directed NOP cases
        apply_and_check(4'b0000);
        apply_and_check(4'b0011);

        // Randomized tests (10 samples)
        repeat (10) apply_and_check($random);

        // Summary
        $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