// tb_hello.v -- self-checking testbench for hello.v. // // A deliberately small half period (4 clocks) keeps the run short; the checker then proves that the // LED toggles exactly every 4 clocks and stays low while reset is asserted. Sampling happens on the // falling edge, after the design's non-blocking updates have settled, so the count cannot race. `timescale 1ns/1ps `default_nettype none module tb_hello; localparam integer HALF = 4; reg clk = 1'b0; reg rst_n = 1'b0; wire led; integer cycles = 0; integer toggles = 0; integer last_toggle = 0; integer errors = 0; reg led_q = 1'b0; hello #(.CLK_HZ(8), .BLINK_HZ(1)) dut ( // 8 Hz / (2*1 Hz) -> HALF = 4 clocks .clk(clk), .rst_n(rst_n), .led(led) ); always #5 clk = ~clk; always @(negedge clk) begin if (rst_n) begin cycles = cycles + 1; if (led !== led_q) begin if (toggles > 0 && (cycles - last_toggle) != HALF) begin $display("[TB] ERROR: toggled after %0d cycles, expected %0d", cycles - last_toggle, HALF); errors = errors + 1; end toggles = toggles + 1; last_toggle = cycles; end end led_q = led; end initial begin $dumpfile("tb_hello.vcd"); $dumpvars(0, tb_hello); repeat (3) @(posedge clk); if (led !== 1'b0) begin $display("[TB] ERROR: led is not low during reset"); errors = errors + 1; end rst_n = 1'b1; repeat (HALF * 8) @(posedge clk); if (errors == 0 && toggles >= 4) begin $display("[TB] %0d toggles observed, interval = %0d cycles -> PASS", toggles, HALF); end else begin $display("[TB] FAIL: %0d errors, %0d toggles", errors, toggles); end $finish; end endmodule `default_nettype wire