Testbench Code
`timescale 1ns/1ps
module tb_jk_ff;
// 1) Inputs
reg CLK, J, K;
// 2) Outputs
wire Q;
// 3) Expected outputs (prefixed "expected_")
reg expected_Q;
// 4) Mismatch (HIGH when outputs != expected)
wire mismatch;
// DUT
jk_ff dut(.CLK(CLK), .J(J), .K(K), .Q(Q));
// Scoreboard: mirror DUT behavior at the capture edge
always @(posedge CLK) begin
case ({J, K})
2'b00: expected_Q <= expected_Q;
2'b01: expected_Q <= 1'b0;
2'b10: expected_Q <= 1'b1;
2'b11: expected_Q <= ~expected_Q;
endcase
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_jk_ff.vcd");
$dumpvars(0,
tb_jk_ff.CLK,
tb_jk_ff.J,
tb_jk_ff.K,
tb_jk_ff.Q,
tb_jk_ff.expected_Q,
tb_jk_ff.mismatch
);
$dumpon;
end
// Drive J,K on negedge; check after the next posedge
task drive_and_check;
input [127:0] name;
input j_val, k_val;
begin
@(negedge CLK);
J = j_val; K = k_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 J=%b K=%b Q=%b expected_Q=%b t=%0t",
name, J, K, Q, expected_Q, $time);
end
if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
end
endtask
// Small edge truth table from current state
task print_edge_table;
integer jv, kv;
reg curQ, nxtQ;
begin
curQ = expected_Q;
$display("Edge table (from current Q=%b):", curQ);
$display(" J K | EXP_Q_after_↑CLK");
$display("-----------------------");
for (jv=0; jv<2; jv=jv+1)
for (kv=0; kv<2; kv=kv+1) begin
case ({jv[0], kv[0]})
2'b00: nxtQ = curQ;
2'b01: nxtQ = 1'b0;
2'b10: nxtQ = 1'b1;
2'b11: nxtQ = ~curQ;
endcase
$display(" %0d %0d | %0d", jv, kv, nxtQ);
end
end
endtask
initial begin
// Start unknown like real silicon; first edge defines it
J = 1'b0; K = 1'b0; expected_Q = 1'bx;
@(posedge CLK); #1;
// Directed modes
drive_and_check("hold" , 1'b0, 1'b0);
drive_and_check("reset" , 1'b0, 1'b1);
drive_and_check("set" , 1'b1, 1'b0);
drive_and_check("toggle", 1'b1, 1'b1);
drive_and_check("toggle", 1'b1, 1'b1); // toggle again
// Exhaustive two-step sequences over {J,K}
for (i=0; i<4; i=i+1) begin
drive_and_check("prev_vec", i[1], i[0]);
for (j=0; j<4; j=j+1)
drive_and_check("next_vec", j[1], j[0]);
end
// Random stress
for (i=0; i<10; i=i+1)
drive_and_check("rand", $random, $random);
// Compact 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