Testbench Code
`timescale 1ns/1ps
module tb_sr_latch_nor;
// Inputs (1)
reg S, R;
// Outputs (2)
wire Q, Qn;
// Expected outputs (3) — prefixed "expected_"
reg expected_Q, expected_Qn;
// Mismatch (4) — HIGH when outputs != expected
wire mismatch;
// Instantiate DUT
sr_latch_nor dut(.S(S), .R(R), .Q(Q), .Qn(Qn));
// Mismatch definition (ordered compare, 4-state aware)
assign mismatch = ({Q, Qn} !== {expected_Q, expected_Qn});
// 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 selection counter
integer vcd_count = 0;
// Loop indices
integer i, j;
// VCD — start at #0; dump only selected signals in fixed order
initial begin
$dumpfile("tb_sr_latch_nor.vcd");
// Order: 1) Inputs 2) Outputs 3) Expected 4) Mismatch
$dumpvars(0,
tb_sr_latch_nor.S,
tb_sr_latch_nor.R,
tb_sr_latch_nor.Q,
tb_sr_latch_nor.Qn,
tb_sr_latch_nor.expected_Q,
tb_sr_latch_nor.expected_Qn,
tb_sr_latch_nor.mismatch
);
$dumpoff;
end
// Golden next-state function
function [1:0] next_state;
input s_val, r_val;
input cur_Q, cur_Qn;
reg [1:0] nxt;
begin
nxt = {cur_Q, cur_Qn};
if (s_val && r_val) nxt = 2'b01; // deterministic reset
else if (s_val && !r_val) nxt = 2'b10; // set
else if (!s_val && r_val) nxt = 2'b01; // reset
next_state = nxt;
end
endfunction
// Named test case executor
task apply_and_check;
input [127:0] tc_name;
input s_val, r_val;
reg [1:0] nxt;
begin
if (vcd_count < VCD_MAX_CASES) $dumpon;
S = s_val;
R = r_val;
nxt = next_state(s_val, r_val, expected_Q, expected_Qn);
{expected_Q, expected_Qn} = nxt;
#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) begin
$display("[FAIL] %0s S=%b R=%b Q=%b Qn=%b expected_Q=%b expected_Qn=%b t=%0t",
tc_name, S, R, Q, Qn, expected_Q, expected_Qn, $time);
end
end
if (vcd_count < VCD_MAX_CASES) begin
vcd_count = vcd_count + 1;
$dumpoff;
end
end
endtask
// Small “truth table” (single-step next-state from current state)
task print_truth_table;
reg curQ, curQn;
reg [1:0] nxt;
integer s, r;
begin
curQ = expected_Q;
curQn = expected_Qn;
$display("Truth table (from current state Q=%b/Qn=%b):", curQ, curQn);
$display(" S R | EXP_Q EXP_Qn");
$display("--------------------");
for (s=0; s<2; s=s+1) begin
for (r=0; r<2; r=r+1) begin
nxt = next_state(s[0], r[0], curQ, curQn);
$display(" %0d %0d | %0d %0d", s, r, nxt[1], nxt[0]);
end
end
end
endtask
initial begin
// Establish known state via Reset then Hold
{S, R} = 2'b01; {expected_Q, expected_Qn} = 2'b01; #1;
{S, R} = 2'b00; #1;
// Directed tests (meaningful names)
apply_and_check("set", 1'b1, 1'b0);
apply_and_check("hold_after_set", 1'b0, 1'b0);
apply_and_check("reset", 1'b0, 1'b1);
apply_and_check("hold_after_reset", 1'b0, 1'b0);
apply_and_check("illegal_to_reset", 1'b1, 1'b1);
apply_and_check("hold_after_illeg", 1'b0, 1'b0);
apply_and_check("set_again", 1'b1, 1'b0);
apply_and_check("final_hold", 1'b0, 1'b0);
// Exhaustive two-step transitions (16 total), named by vectors
for (i=0; i<4; i=i+1) begin
apply_and_check({"prev_", 8'h30+i[7:0]}, i[1], i[0]);
for (j=0; j<4; j=j+1) begin
apply_and_check({"next_", 8'h30+j[7:0]}, j[1], j[0]);
end
end
// Random stress (names “rand_XX”)
for (i=0; i<100; i=i+1) begin
apply_and_check({"rand_", i[7:0]}, $random, $random);
end
// Print compact truth table (small input space)
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