`timescale 1ns/1ps module tb_wb_timer(); localparam integer CLK_HALF_NS = 5; reg clk; reg rst; reg [31:0] i_wb_dat; wire [31:0] o_wb_dat; reg i_wb_we; reg i_wb_cyc; reg i_wb_stb; wire o_wb_ack; wire o_irq; integer errors; wb_countdown_timer #( .WIDTH(8), .DIVIDER(0) ) dut ( .i_clk (clk), .i_rst (rst), .o_irq (o_irq), .i_wb_dat(i_wb_dat), .o_wb_dat(o_wb_dat), .i_wb_we (i_wb_we), .i_wb_cyc(i_wb_cyc), .i_wb_stb(i_wb_stb), .o_wb_ack(o_wb_ack) ); always #CLK_HALF_NS clk = ~clk; task wb_write; input [31:0] data; begin @(negedge clk); i_wb_dat = data; i_wb_we = 1'b1; i_wb_cyc = 1'b1; i_wb_stb = 1'b1; #1; if (!o_wb_ack) begin $display("FAIL: WB write ACK not asserted when cyc/stb high"); errors = errors + 1; end @(negedge clk); i_wb_we = 1'b0; i_wb_cyc = 1'b0; i_wb_stb = 1'b0; end endtask task wb_read_check; input [31:0] expected; begin @(negedge clk); i_wb_we = 1'b0; i_wb_cyc = 1'b1; i_wb_stb = 1'b1; #1; if (!o_wb_ack) begin $display("FAIL: WB read ACK not asserted when cyc/stb high"); errors = errors + 1; end if (o_wb_dat !== expected) begin $display("FAIL: WB read mismatch. got=0x%08h expected=0x%08h", o_wb_dat, expected); errors = errors + 1; end @(negedge clk); i_wb_cyc = 1'b0; i_wb_stb = 1'b0; end endtask task wait_irq_with_timeout; input integer max_cycles; integer k; begin k = 0; while ((o_irq !== 1'b1) && (k < max_cycles)) begin @(posedge clk); k = k + 1; end if (o_irq !== 1'b1) begin $display("FAIL: IRQ did not assert within %0d cycles", max_cycles); errors = errors + 1; end end endtask initial begin $dumpfile("out.vcd"); $dumpvars; clk = 1'b0; rst = 1'b1; i_wb_dat = 32'd0; i_wb_we = 1'b0; i_wb_cyc = 1'b0; i_wb_stb = 1'b0; errors = 0; $display("---------------------------------------"); $display("Testbench: wb_countdown_timer"); $display("---------------------------------------"); repeat (3) @(posedge clk); rst = 1'b0; repeat (1) @(posedge clk); if (o_irq !== 1'b0) begin $display("FAIL: IRQ should be low after reset"); errors = errors + 1; end wb_read_check(32'd0); // Load timer and check readback at a deterministic point wb_write(32'd5); @(posedge clk); wb_read_check(32'd4); // Wait until expiration, then verify sticky IRQ behavior wait_irq_with_timeout(6); wb_read_check(32'd0); repeat (2) @(posedge clk); if (o_irq !== 1'b1) begin $display("FAIL: IRQ should remain sticky until next write"); errors = errors + 1; end // A new write must clear IRQ and restart the counter wb_write(32'd2); if (o_irq !== 1'b0) begin $display("FAIL: IRQ should clear on write"); errors = errors + 1; end wait_irq_with_timeout(3); if (errors == 0) $display("PASS: wb_timer basic functionality verified"); else $display("FAIL: wb_timer testbench found %0d error(s)", errors); $finish; end endmodule