Testbench Code
`timescale 1ns/1ps
module tb_sipo4;
// Inputs
reg CLK;
reg RST;
reg serial_in;
// Output
wire [3:0] Q;
// DUT
sipo4 dut(.CLK(CLK), .RST(RST), .serial_in(serial_in), .Q(Q));
// Expected (golden model)
reg [3:0] expected_Q;
// Mismatch (4-state aware)
wire 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 printed_rows = 0;
integer printed_errs = 0;
// 50% duty-cycle free-running clock (10 time-unit period)
initial begin
CLK = 1'b0;
forever #5 CLK = ~CLK;
end
// Golden model mirrors DUT behavior
always @(posedge CLK or posedge RST) begin
if (RST)
expected_Q <= 4'b0000;
else
expected_Q <= {serial_in, expected_Q[3:1]};
end
// VCD: inputs -> outputs -> expected -> mismatch (start at #0)
initial begin
$dumpfile("tb_sipo4.vcd");
$dumpvars(0,
tb_sipo4.CLK,
tb_sipo4.RST,
tb_sipo4.serial_in,
tb_sipo4.Q,
tb_sipo4.expected_Q,
tb_sipo4.mismatch
);
$dumpon;
end
// Log one sampled row (after posedge)
task log_row;
begin
TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
if (!mismatch) begin
TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
if (printed_rows < VCD_MAX_CASES) begin
$display(" serial_in=%b | Q=0x%1h EXP=0x%1h | mismatch=%0d",
serial_in, Q, expected_Q, mismatch);
printed_rows = printed_rows + 1;
end
end else begin
TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;
if (printed_errs < ERROR_MAX_CASES) begin
$display("ERR: serial_in=%b => Q=0x%1h (exp 0x%1h)",
serial_in, Q, expected_Q);
printed_errs = printed_errs + 1;
end
end
if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
end
endtask
// Drive serial bit on negedge; sample/log after next posedge
task shift_bit;
input bit_val;
begin
@(negedge CLK);
serial_in = bit_val;
@(posedge CLK); #1; // allow scheduling to settle
log_row();
end
endtask
integer i;
initial begin
// Header
$display(" serial_in | Q | EXP | mismatch");
$display("--------------------------------");
// Bring to known state via async reset
RST = 1'b1; serial_in = 1'b0; expected_Q = 4'b0000;
@(posedge CLK); #1; log_row();
RST = 1'b0;
@(posedge CLK); #1; log_row();
// Directed sequence 1 (1,0,1,1)
shift_bit(1'b1);
shift_bit(1'b0);
shift_bit(1'b1);
shift_bit(1'b1);
// Directed sequence 2 (0,1,0,0)
shift_bit(1'b0);
shift_bit(1'b1);
shift_bit(1'b0);
shift_bit(1'b0);
// Random stress
for (i = 0; i < 12; i = i + 1)
shift_bit($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