Testbench Code
`timescale 1ns/1ps
module tb_t_ff_async_pr;
// 1) Inputs
reg CLK, RST, PRE, T;
// 2) Outputs
wire Q;
// 3) Expected outputs (prefixed "expected_")
reg expected_Q;
// 4) Mismatch (HIGH when outputs != expected)
wire mismatch;
// DUT
t_ff_async_pr dut(.CLK(CLK), .RST(RST), .PRE(PRE), .T(T), .Q(Q));
// Scoreboard: mirror DUT exactly (async + sync)
always @(posedge CLK or posedge RST or posedge PRE) begin
if (RST) expected_Q <= 1'b0;
else if (PRE) expected_Q <= 1'b1;
else if (T) expected_Q <= ~expected_Q;
else expected_Q <= expected_Q;
end
// 4-state 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, 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_t_ff_async_pr.vcd");
$dumpvars(0,
tb_t_ff_async_pr.CLK,
tb_t_ff_async_pr.RST,
tb_t_ff_async_pr.PRE,
tb_t_ff_async_pr.T,
tb_t_ff_async_pr.Q,
tb_t_ff_async_pr.expected_Q,
tb_t_ff_async_pr.mismatch
);
$dumpon;
end
task log_case;
begin
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] RST=%b PRE=%b T=%b Q=%b expected_Q=%b t=%0t",
RST, PRE, T, Q, expected_Q, $time);
end
if (TOTAL_TEST_CASES == VCD_MAX_CASES) $dumpoff;
end
endtask
// Asynchronous controls (assert/deassert at arbitrary times)
task async_assert_reset; begin RST = 1'b1; PRE = 1'b0; #1; log_case(); end endtask
task async_release_reset; begin RST = 1'b0; #1; log_case(); end endtask
task async_assert_preset; begin PRE = 1'b1; RST = 1'b0; #1; log_case(); end endtask
task async_release_preset;begin PRE = 1'b0; #1; log_case(); end endtask
// Synchronous capture: drive T on negedge, check after posedge
task capture_cycle;
input t_val;
begin
@(negedge CLK);
T = t_val;
@(posedge CLK); #1;
log_case();
end
endtask
initial begin
// Start with unknown like real silicon; first async event defines it
RST = 1'b0; PRE = 1'b0; T = 1'b0; expected_Q = 1'bx;
@(negedge CLK);
// Bring to known state and exercise behavior
async_assert_reset(); // Q -> 0 immediately
async_release_reset();
capture_cycle(1'b1); // toggle to 1
async_assert_preset(); // force 1 immediately
async_release_preset();
capture_cycle(1'b1); // toggle to 0
// Simultaneous asserts: reset must dominate preset
RST = 1'b0; PRE = 1'b0; #1;
RST = 1'b1; PRE = 1'b1; #1; // both high -> Q must be 0
log_case();
async_release_reset(); // keep PRE=1
async_release_preset();
// More captures
capture_cycle(1'b0); // hold
capture_cycle(1'b1); // toggle
// Exhaustive two-step over {RST,PRE,T} with RST/PRE low for captures
RST = 1'b0; PRE = 1'b0;
for (i=0; i<2; i=i+1) begin
capture_cycle(i[0]);
for (j=0; j<2; j=j+1)
capture_cycle(j[0]);
end
// Randomized sequences mixing async and sync behavior
for (i=0; i<6; i=i+1) begin
if ($random) async_assert_reset(); else async_release_reset();
if ($random) async_assert_preset(); else async_release_preset();
capture_cycle($random);
end
// 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