Testbench Code
`timescale 1ns/1ps
module tb_sr_latch_enable;
// 1) Inputs
reg EN, S, R;
// 2) Outputs
wire Q, Qn;
// 3) Expected outputs (prefixed "expected_")
reg expected_Q, expected_Qn;
// 4) Mismatch (HIGH when outputs != expected)
wire mismatch;
// DUT
sr_latch_enable dut(.EN(EN), .S(S), .R(R), .Q(Q), .Qn(Qn));
// Compare (4-state)
assign mismatch = ({Q, Qn} !== {expected_Q, expected_Qn});
// Complement invariant
wire not_compl = (Qn !== ~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;
// VCD — start at #0; dump only requested signals and order
initial begin
$dumpfile("tb_sr_latch_enable.vcd");
// Order: Inputs → Outputs → Expected → mismatch
$dumpvars(0,
tb_sr_latch_enable.EN,
tb_sr_latch_enable.S,
tb_sr_latch_enable.R,
tb_sr_latch_enable.Q,
tb_sr_latch_enable.Qn,
tb_sr_latch_enable.expected_Q,
tb_sr_latch_enable.expected_Qn,
tb_sr_latch_enable.mismatch
);
$dumpon; // begin dumping at #0
end
// Golden next-state (priority: reset > set > hold; hold when EN=0)
function [1:0] next_state;
input en_val, s_val, r_val;
input cur_Q, cur_Qn;
reg [1:0] nxt;
begin
nxt = {cur_Q, cur_Qn};
if (en_val) begin
if (s_val && r_val) nxt = 2'b01; // illegal -> reset
else if (!s_val && r_val) nxt = 2'b01; // reset
else if (s_val && !r_val) nxt = 2'b10; // set
// else: hold
end
// EN=0 → hold
next_state = nxt;
end
endfunction
// Named test executor (prints failures with inputs and expected outputs)
task apply_and_check;
input [127:0] tc_name;
input en_val, s_val, r_val;
reg [1:0] nxt;
begin
EN = en_val; S = s_val; R = r_val;
// Compute expected after inputs are applied
nxt = next_state(en_val, s_val, r_val, expected_Q, expected_Qn);
{expected_Q, expected_Qn} = nxt;
#1; // settle
TOTAL_TEST_CASES = TOTAL_TEST_CASES + 1;
// Count / print
if (!mismatch && !not_compl) 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) begin
$display("[FAIL] %0s EN=%b S=%b R=%b Q=%b Qn=%b expected_Q=%b expected_Qn=%b t=%0t",
tc_name, EN, S, R, Q, Qn, expected_Q, expected_Qn, $time);
end
end
// Limit VCD size to first VCD_MAX_CASES cases
if (TOTAL_TEST_CASES == VCD_MAX_CASES)
$dumpoff;
end
endtask
// Compact truth table (single-step from current state)
task print_truth_table;
reg curQ, curQn;
reg [1:0] nxt;
integer env, sv, rv;
begin
curQ = expected_Q;
curQn = expected_Qn;
$display("Truth table (from current state Q=%b/Qn=%b):", curQ, curQn);
$display(" EN S R | EXP_Q EXP_Qn");
$display("-----------------------");
for (env=0; env<2; env=env+1) begin
for (sv=0; sv<2; sv=sv+1) begin
for (rv=0; rv<2; rv=rv+1) begin
nxt = next_state(env[0], sv[0], rv[0], curQ, curQn);
$display(" %0d %0d %0d | %0d %0d", env, sv, rv, nxt[1], nxt[0]);
end
end
end
end
endtask
// Loop indices
integer i, j;
initial begin
// Establish a known reset state at t=0 (EN=1, R=1 → reset), then hold
EN=1'b1; S=1'b0; R=1'b1; {expected_Q, expected_Qn} = 2'b01; #1;
EN=1'b1; S=1'b0; R=1'b0; #1;
// Directed tests (meaningful names)
apply_and_check("set_when_en", 1'b1, 1'b1, 1'b0);
apply_and_check("hold_after_set_en", 1'b1, 1'b0, 1'b0);
apply_and_check("disable_then_ignore_set", 1'b0, 1'b1, 1'b0);
apply_and_check("re_enable_hold", 1'b1, 1'b0, 1'b0);
apply_and_check("reset_when_en", 1'b1, 1'b0, 1'b1);
apply_and_check("hold_after_reset_en", 1'b1, 1'b0, 1'b0);
apply_and_check("illegal_when_en_to_reset", 1'b1, 1'b1, 1'b1);
apply_and_check("final_hold", 1'b1, 1'b0, 1'b0);
// Exhaustive two-step transitions over {EN,S,R} (8 → 8 = 64 transitions)
for (i=0; i<8; i=i+1) begin
apply_and_check("prev_vec", i[2], i[1], i[0]);
for (j=0; j<8; j=j+1)
apply_and_check("next_vec", j[2], j[1], j[0]);
end
// Random stress
for (i=0; i<100; i=i+1)
apply_and_check("rand", $random, $random, $random);
// Small truth table (8 rows)
print_truth_table();
// Final 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