All submissions

4-bit Bidirectional Shift Register

Solving Approach

How do you plan to solve it?

 

Code

module shift_reg_bidirectional (
    input        CLK,
    input        RST,
    input        DIR,
    input        serial_in,
    output reg [3:0] Q
);
    // Write your code here
    
always @(posedge CLK or RST) begin

    if(RST) Q=4'b0000;

    else begin

        if(DIR) begin
            Q<={Q[2:0],serial_in};
        end

        else begin
            Q<={serial_in, Q[3:1]};
        end
    end

end    
endmodule

 

Testbench Code

`timescale 1ns/1ps

module tb_shift_reg_bidirectional;
    // 1) Inputs
    reg CLK, RST, DIR, serial_in;
    // 2) Outputs
    wire [3:0] Q;
    // 3) Expected outputs (prefixed "expected_")
    reg  [3:0] expected_Q;
    // 4) Mismatch (HIGH when outputs != expected)
    wire mismatch;

    // DUT
    shift_reg_bidirectional dut(.CLK(CLK), .RST(RST), .DIR(DIR), .serial_in(serial_in), .Q(Q));

    // Free-running 50% duty-cycle clock (10 time-unit period)
    initial begin
        CLK = 1'b0;
        forever #5 CLK = ~CLK;
    end

    // Scoreboard mirrors DUT (async reset + edge shift)
    always @(posedge CLK or posedge RST) begin
        if (RST)
            expected_Q <= 4'b0000;
        else if (DIR)
            expected_Q <= {expected_Q[2:0], serial_in};
        else
            expected_Q <= {serial_in, expected_Q[3:1]};
    end

    // 4-state aware compare
    assign mismatch = (Q !== expected_Q);

    // Counters / limits
    integer TOTAL_TEST_CASES        = 0;
    integer TOTAL_PASSED_TEST_CASES = 0;
    integer TOTAL_FAILED_TEST_CASES = 0;
    integer VCD_MAX_CASES           = 32;
    integer ERROR_MAX_CASES         = 32;

    integer i;

    // VCD — order: Inputs -> Outputs -> Expected -> mismatch; start at #0
    initial begin
        $dumpfile("tb_shift_reg_bidirectional.vcd");
        $dumpvars(0,
            tb_shift_reg_bidirectional.CLK,
            tb_shift_reg_bidirectional.RST,
            tb_shift_reg_bidirectional.DIR,
            tb_shift_reg_bidirectional.serial_in,
            tb_shift_reg_bidirectional.Q,
            tb_shift_reg_bidirectional.expected_Q,
            tb_shift_reg_bidirectional.mismatch
        );
        $dumpon;
    end

    // Log one test result and cap VCD rows
    task log_case;
    begin
        TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
        if (!mismatch) begin
            TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
            if (TOTAL_TEST_CASES <= VCD_MAX_CASES)
                $display(" DIR=%b serial_in=%b | Q=0x%1h EXP=0x%1h | mismatch=%0d",
                         DIR, serial_in, Q, expected_Q, mismatch);
        end else begin
            TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;
            if (TOTAL_FAILED_TEST_CASES <= ERROR_MAX_CASES)
                $display("ERR: DIR=%b serial_in=%b => Q=0x%1h (exp 0x%1h)",
                         DIR, serial_in, Q, expected_Q);
        end
        if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
    end
    endtask

    // Async reset pulse
    task async_reset;
    begin
        RST = 1'b1;
        @(posedge CLK); #1; log_case(); // scoreboard/DUT both jump to 0 immediately; sample next edge
        RST = 1'b0;
        @(posedge CLK); #1; log_case();
    end
    endtask

    // One capture: drive on negedge, sample after next posedge
    task shift_step;
        input dir_v;
        input sin_v;
    begin
        @(negedge CLK);
        DIR = dir_v;
        serial_in = sin_v;
        @(posedge CLK); #1; log_case();
    end
    endtask

    initial begin
        // Known start via reset
        DIR = 1'b0; serial_in = 1'b0; expected_Q = 4'hx; RST = 1'b0;
        async_reset();

        // Directed sequence
        shift_step(1'b1, 1'b1); // left insert 1
        shift_step(1'b1, 1'b0); // left insert 0
        shift_step(1'b0, 1'b1); // right insert 1
        shift_step(1'b0, 1'b1); // right insert 1

        // Randomized mix
        for (i = 0; i < 12; i = i + 1)
            shift_step($random, $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