Testbench Code
`timescale 1ns/1ps
module tb_t_ff;
// 1) Inputs
reg CLK, T;
// 2) Output
wire Q;
// 3) Expected output (prefixed "expected_")
reg expected_Q;
// 4) Mismatch (HIGH when outputs != expected)
wire mismatch;
// DUT
t_ff dut(.CLK(CLK), .T(T), .Q(Q));
// Scoreboard mirrors DUT at posedge
always @(posedge CLK) begin
if (T) expected_Q <= ~expected_Q;
else expected_Q <= expected_Q;
end
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, j;
// Free-running clock (10 time-unit period)
initial begin
CLK = 1'b0;
forever #5 CLK = ~CLK;
end
// VCD — Inputs -> Outputs -> Expected -> mismatch; start at #0
initial begin
$dumpfile("tb_t_ff.vcd");
$dumpvars(0,
tb_t_ff.CLK,
tb_t_ff.T,
tb_t_ff.Q,
tb_t_ff.expected_Q,
tb_t_ff.mismatch
);
$dumpon;
end
// Seed the flop to avoid permanent X (no reset in DUT)
task seed_known_state;
begin
expected_Q = 1'b0;
force tb_t_ff.dut.Q = 1'b0; // seed DUT state
#1;
release tb_t_ff.dut.Q;
@(posedge CLK); #1; // re-sample a known state
end
endtask
// Drive T on negedge; check after next posedge
task drive_and_check;
input [127:0] name;
input t_val;
begin
@(negedge CLK);
T = t_val;
@(posedge CLK); #1;
TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
if (!mismatch) begin
TOTAL_PASSED_TEST_CASES = TOTAL_PASSED_TEST_CASES + 1;
end else begin
TOTAL_FAILED_TEST_CASES = TOTAL_FAILED_TEST_CASES + 1;
if (TOTAL_FAILED_TEST_CASES <= ERROR_MAX_CASES)
$display("[FAIL] %0s T=%b Q=%b expected_Q=%b t=%0t",
name, T, Q, expected_Q, $time);
end
if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
end
endtask
// Compact edge table (from current state)
task print_edge_table;
integer tv;
reg curQ, nxtQ;
begin
curQ = expected_Q;
$display(" T | EXP_Q_after_↑CLK");
$display("---------------------");
for (tv=0; tv<2; tv=tv+1) begin
nxtQ = (tv[0]) ? ~curQ : curQ;
$display(" %0d | %0d", tv[0], nxtQ);
end
end
endtask
initial begin
// Initialize inputs
T = 1'b0;
// Seed DUT/scoreboard to a known state (no reset in module)
seed_known_state();
// Directed
drive_and_check("hold" , 1'b0);
drive_and_check("toggle" , 1'b1);
drive_and_check("toggle2", 1'b1);
drive_and_check("hold2" , 1'b0);
// Two-step sequences
for (i=0; i<2; i=i+1) begin
drive_and_check("prev_edge", i[0]);
for (j=0; j<2; j=j+1)
drive_and_check("next_edge", j[0]);
end
// Random stress
for (i=0; i<10; i=i+1)
drive_and_check("rand", $random);
// Edge table
print_edge_table();
// Summary
$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