Added timer, still wip
This commit is contained in:
45
sim/tb/tb_top_generic.v
Normal file
45
sim/tb/tb_top_generic.v
Normal file
@@ -0,0 +1,45 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_top_generic();
|
||||
reg aclk;
|
||||
reg aresetn;
|
||||
|
||||
wire led_green;
|
||||
wire led_red;
|
||||
wire [5:0] r2r;
|
||||
wire [7:0] LED;
|
||||
|
||||
// 100 MHz board input clock
|
||||
initial aclk = 1'b0;
|
||||
always #5 aclk = ~aclk;
|
||||
|
||||
// Hold reset low, then release
|
||||
initial begin
|
||||
aresetn = 1'b0;
|
||||
#200;
|
||||
aresetn = 1'b1;
|
||||
end
|
||||
|
||||
top_generic #(
|
||||
.sim(1)
|
||||
) dut (
|
||||
.aclk(aclk),
|
||||
.aresetn(aresetn),
|
||||
.led_green(led_green),
|
||||
.led_red(led_red),
|
||||
.r2r(r2r),
|
||||
.LED(LED)
|
||||
);
|
||||
|
||||
// Ensure firmware path resolves from repository root when simulating.
|
||||
defparam dut.mcu.memfile = "sw/sweep/sweep.hex";
|
||||
|
||||
initial begin
|
||||
$dumpfile("out.vcd");
|
||||
$dumpvars(0, tb_top_generic);
|
||||
|
||||
// Let firmware run for a while.
|
||||
#5_000_000;
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
157
sim/tb/tb_wb_timer.v
Normal file
157
sim/tb/tb_wb_timer.v
Normal file
@@ -0,0 +1,157 @@
|
||||
`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
|
||||
Reference in New Issue
Block a user