158 lines
3.9 KiB
Verilog
158 lines
3.9 KiB
Verilog
`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
|