Testbench Code
`timescale 1ns/1ps
module tb_jk_ff_enable;
// 1) Inputs
reg CLK, EN, 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_enable dut(.CLK(CLK), .EN(EN), .J(J), .K(K), .Q(Q));
// Scoreboard: mirror DUT behavior at posedge CLK
always @(posedge CLK) begin
if (EN) 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
// EN=0 -> hold (no assignment)
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 — only Inputs -> Outputs -> Expected -> mismatch; start at #0
initial begin
$dumpfile("tb_jk_ff_enable.vcd");
$dumpvars(0,
tb_jk_ff_enable.CLK,
tb_jk_ff_enable.EN,
tb_jk_ff_enable.J,
tb_jk_ff_enable.K,
tb_jk_ff_enable.Q,
tb_jk_ff_enable.expected_Q,
tb_jk_ff_enable.mismatch
);
$dumpon;
end
// Drive inputs on negedge; check after next posedge
task drive_and_check;
input [127:0] name;
input en_v, j_v, k_v;
begin
@(negedge CLK);
EN = en_v; J = j_v; K = k_v;
@(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 EN=%b J=%b K=%b Q=%b expected_Q=%b t=%0t",
name, EN, J, K, 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 e, jv, kv;
reg curQ, nxtQ;
begin
curQ = expected_Q;
$display("Edge table (from current Q=%b):", curQ);
$display(" EN J K | EXP_Q_after_↑CLK");
$display("---------------------------");
for (e=0; e<2; e=e+1)
for (jv=0; jv<2; jv=jv+1)
for (kv=0; kv<2; kv=kv+1) begin
if (e==0) nxtQ = curQ;
else 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
end
$display(" %0d %0d %0d | %0d", e, jv, kv, nxtQ);
end
end
endtask
initial begin
// Start unknown like real silicon; first edge defines it
EN = 1'b0; J = 1'b0; K = 1'b0; expected_Q = 1'bx;
@(posedge CLK); #1;
// Directed
drive_and_check("disabled_hold" , 1'b0, 1'b1, 1'b1);
drive_and_check("reset" , 1'b1, 1'b0, 1'b1);
drive_and_check("set" , 1'b1, 1'b1, 1'b0);
drive_and_check("toggle" , 1'b1, 1'b1, 1'b1);
drive_and_check("hold_enabled" , 1'b1, 1'b0, 1'b0);
drive_and_check("toggle_ignored", 1'b0, 1'b1, 1'b1);
// Exhaustive two-step sequences over {EN,J,K}
for (i=0; i<8; i=i+1) begin
drive_and_check("prev_vec", i[2], i[1], i[0]);
for (j=0; j<8; j=j+1)
drive_and_check("next_vec", j[2], j[1], j[0]);
end
// Random stress
for (i=0; i<10; i=i+1)
drive_and_check("rand", $random, $random, $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