mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- Updated test files to change instances of ribp_if to apb4_if in various test cases, ensuring consistency with the new APB4 interface. - Modified assertions and checks in tests to reflect the new APB4 naming conventions, including changes in expected output and input files. - Adjusted the test descriptions to accurately represent the APB4 functionality being tested, particularly in timer, UART, and GPIO tests. - Ensured that all relevant paths and file names in the tests are updated to point to the new APB4 implementations, maintaining the integrity of the test suite.
307 lines
9.8 KiB
Systemverilog
307 lines
9.8 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
|
|
`include "ws2812_define.svh"
|
|
|
|
module ws2812_tb;
|
|
localparam int FIFO_DEPTH = 4;
|
|
localparam int BIT_CYCLES = 4;
|
|
localparam int T0H_CYCLES = 1;
|
|
localparam int T1H_CYCLES = 3;
|
|
localparam int RESET_CYCLES = 5;
|
|
|
|
logic clk_i = 1'b0;
|
|
logic rst_n_i = 1'b0;
|
|
apb4_if apb4 (
|
|
.pclk (clk_i),
|
|
.presetn(rst_n_i)
|
|
);
|
|
ws2812_if ws2812 ();
|
|
|
|
logic monitor_enable = 1'b0;
|
|
logic [23:0] expected_pixels [0:7];
|
|
integer expected_pixel_count = 0;
|
|
integer observed_pixel = 0;
|
|
integer observed_bit = 0;
|
|
integer observed_cycle = 0;
|
|
integer expected_bit_cycles = BIT_CYCLES;
|
|
integer expected_t0h_cycles = T0H_CYCLES;
|
|
integer expected_t1h_cycles = T1H_CYCLES;
|
|
integer reset_low_cycles = 0;
|
|
integer test_stage = 0;
|
|
|
|
always #5 clk_i = ~clk_i;
|
|
|
|
initial begin
|
|
repeat (10000) @(posedge clk_i);
|
|
$fatal(1, "WS2812 test timeout at stage %0d state=%0d valid=%b ready=%b", test_stage,
|
|
u_dut.u_ws2812_core.s_state_q, apb4.psel, apb4.pready);
|
|
end
|
|
|
|
apb4_ws2812 #(
|
|
.TxFifoDepth(FIFO_DEPTH)
|
|
) u_dut (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.apb4 (apb4),
|
|
.ws2812 (ws2812)
|
|
);
|
|
|
|
task automatic apb4_write(input logic [31:0] address, input logic [31:0] data,
|
|
input logic [3:0] strobe, input logic expected_error,
|
|
output integer wait_cycles);
|
|
begin
|
|
wait_cycles = 0;
|
|
@(negedge clk_i);
|
|
apb4.paddr = address;
|
|
apb4.pwdata = data;
|
|
apb4.pstrb = strobe;
|
|
apb4.pwrite = 1'b1;
|
|
apb4.psel = 1'b1;
|
|
apb4.penable = 1'b0;
|
|
@(negedge clk_i);
|
|
apb4.penable = 1'b1;
|
|
while (!apb4.pready) begin
|
|
@(negedge clk_i);
|
|
wait_cycles = wait_cycles + 1;
|
|
end
|
|
if (apb4.pslverr !== expected_error) begin
|
|
$fatal(1, "write %h error=%b expected=%b", address, apb4.pslverr, expected_error);
|
|
end
|
|
apb4.psel = 1'b0;
|
|
apb4.penable = 1'b0;
|
|
apb4.pwrite = 1'b0;
|
|
apb4.pstrb = '0;
|
|
end
|
|
endtask
|
|
|
|
task automatic apb4_read(input logic [31:0] address, input logic expected_error,
|
|
output logic [31:0] data);
|
|
begin
|
|
@(negedge clk_i);
|
|
apb4.paddr = address;
|
|
apb4.pwdata = '0;
|
|
apb4.pstrb = '0;
|
|
apb4.pwrite = 1'b0;
|
|
apb4.psel = 1'b1;
|
|
apb4.penable = 1'b0;
|
|
@(negedge clk_i);
|
|
apb4.penable = 1'b1;
|
|
while (!apb4.pready) @(negedge clk_i);
|
|
if (apb4.pslverr !== expected_error) begin
|
|
$fatal(1, "read %h error=%b expected=%b", address, apb4.pslverr, expected_error);
|
|
end
|
|
data = apb4.prdata;
|
|
apb4.psel = 1'b0;
|
|
apb4.penable = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic write_ok(input logic [31:0] address, input logic [31:0] data);
|
|
integer ignored_wait;
|
|
begin
|
|
apb4_write(address, data, 4'hF, 1'b0, ignored_wait);
|
|
end
|
|
endtask
|
|
|
|
task automatic wait_until_idle;
|
|
logic [31:0] status;
|
|
begin
|
|
status = 32'h1;
|
|
while (status[`WS2812_STATUS_BUSY]) begin
|
|
apb4_read(`APB4_WS2812_STATUS, 1'b0, status);
|
|
end
|
|
end
|
|
endtask
|
|
|
|
task automatic configure_timing;
|
|
begin
|
|
write_ok(`APB4_WS2812_BIT_CYCLES, BIT_CYCLES);
|
|
write_ok(`APB4_WS2812_T0H_CYCLES, T0H_CYCLES);
|
|
write_ok(`APB4_WS2812_T1H_CYCLES, T1H_CYCLES);
|
|
write_ok(`APB4_WS2812_RESET_CYCLES, RESET_CYCLES);
|
|
write_ok(`APB4_WS2812_FIFO_WATERMARK, 3);
|
|
write_ok(`APB4_WS2812_INTR_ENABLE, 4'hF);
|
|
end
|
|
endtask
|
|
|
|
always @(posedge clk_i) begin
|
|
#1;
|
|
if (!rst_n_i && ws2812.dat_o !== 1'b0) begin
|
|
$fatal(1, "WS2812 output is not low during reset");
|
|
end
|
|
if (monitor_enable && u_dut.s_busy && !u_dut.s_reset_active) begin
|
|
integer high_cycles;
|
|
logic expected_data;
|
|
high_cycles = expected_pixels[observed_pixel][23-observed_bit] ? expected_t1h_cycles :
|
|
expected_t0h_cycles;
|
|
expected_data = observed_cycle < high_cycles;
|
|
if (ws2812.dat_o !== expected_data) begin
|
|
$fatal(1, "waveform mismatch pixel=%0d bit=%0d cycle=%0d", observed_pixel, observed_bit,
|
|
observed_cycle);
|
|
end
|
|
observed_cycle = observed_cycle + 1;
|
|
if (observed_cycle == expected_bit_cycles) begin
|
|
observed_cycle = 0;
|
|
observed_bit = observed_bit + 1;
|
|
if (observed_bit == 24) begin
|
|
observed_bit = 0;
|
|
observed_pixel = observed_pixel + 1;
|
|
end
|
|
end
|
|
end
|
|
if (monitor_enable && u_dut.s_reset_active) begin
|
|
if (ws2812.dat_o !== 1'b0) begin
|
|
$fatal(1, "WS2812 output is high during latch/reset");
|
|
end
|
|
reset_low_cycles = reset_low_cycles + 1;
|
|
end
|
|
end
|
|
|
|
task automatic begin_monitor(input integer pixel_count);
|
|
begin
|
|
observed_pixel = 0;
|
|
observed_bit = 0;
|
|
observed_cycle = 0;
|
|
reset_low_cycles = 0;
|
|
expected_pixel_count = pixel_count;
|
|
monitor_enable = 1'b1;
|
|
end
|
|
endtask
|
|
|
|
task automatic end_monitor(input logic expect_complete_frame);
|
|
begin
|
|
monitor_enable = 1'b0;
|
|
if (expect_complete_frame && observed_pixel != expected_pixel_count) begin
|
|
$fatal(1, "observed %0d pixels, expected %0d", observed_pixel, expected_pixel_count);
|
|
end
|
|
if (reset_low_cycles < RESET_CYCLES) begin
|
|
$fatal(1, "latch/reset low interval was only %0d cycles", reset_low_cycles);
|
|
end
|
|
end
|
|
endtask
|
|
|
|
initial begin
|
|
logic [31:0] value;
|
|
integer wait_cycles;
|
|
|
|
apb4.psel = 1'b0;
|
|
apb4.paddr = '0;
|
|
apb4.pwdata = '0;
|
|
apb4.pstrb = '0;
|
|
repeat (3) @(posedge clk_i);
|
|
rst_n_i = 1'b1;
|
|
|
|
test_stage = 1;
|
|
apb4_read(`APB4_WS2812_IP_INFO, 1'b0, value);
|
|
if (value !== 32'h1804_0100) begin
|
|
$fatal(1, "unexpected IP_INFO %h", value);
|
|
end
|
|
apb4_read(`APB4_WS2812_STATUS, 1'b0, value);
|
|
if (value[`WS2812_STATUS_CONFIG_VALID] || !value[`WS2812_STATUS_FIFO_EMPTY]) begin
|
|
$fatal(1, "unexpected reset status %h", value);
|
|
end
|
|
apb4_read(`APB4_WS2812_CTRL, 1'b1, value);
|
|
apb4_write(8'h02, 32'd1, 4'hF, 1'b1, wait_cycles);
|
|
apb4_read(32'h00000100, 1'b1, value);
|
|
apb4_write(`APB4_WS2812_TXDATA, 24'h112233, 4'h7, 1'b1, wait_cycles);
|
|
write_ok(`APB4_WS2812_TXDATA, 24'h112233);
|
|
write_ok(`APB4_WS2812_FRAME_WORDS, 1);
|
|
apb4_write(`APB4_WS2812_CTRL, 32'h1, 4'hF, 1'b1, wait_cycles);
|
|
apb4_read(`APB4_WS2812_ERROR_STATUS, 1'b0, value);
|
|
if (!value[`WS2812_ERROR_CONFIG]) begin
|
|
$fatal(1, "invalid timing did not set CONFIG error");
|
|
end
|
|
write_ok(`APB4_WS2812_ERROR_STATUS, 32'h7);
|
|
write_ok(`APB4_WS2812_CTRL, 32'h4);
|
|
|
|
configure_timing();
|
|
apb4_read(`APB4_WS2812_STATUS, 1'b0, value);
|
|
if (!value[`WS2812_STATUS_CONFIG_VALID]) begin
|
|
$fatal(1, "legal timing was not accepted");
|
|
end
|
|
|
|
test_stage = 2;
|
|
for (integer index = 0; index < FIFO_DEPTH; index = index + 1) begin
|
|
write_ok(`APB4_WS2812_TXDATA, index);
|
|
end
|
|
apb4_write(`APB4_WS2812_TXDATA, 32'h55, 4'hF, 1'b1, wait_cycles);
|
|
write_ok(`APB4_WS2812_CTRL, 32'h4);
|
|
write_ok(`APB4_WS2812_ERROR_STATUS, 32'h7);
|
|
write_ok(`APB4_WS2812_INTR_STATE, 32'hF);
|
|
|
|
test_stage = 3;
|
|
expected_pixels[0] = 24'h800001;
|
|
expected_pixels[1] = 24'h010203;
|
|
expected_pixels[2] = 24'hA5A5A5;
|
|
expected_pixels[3] = 24'h5A5A5A;
|
|
expected_pixels[4] = 24'hFFFFFF;
|
|
expected_pixels[5] = 24'h000000;
|
|
for (integer index = 0; index < FIFO_DEPTH; index = index + 1) begin
|
|
write_ok(`APB4_WS2812_TXDATA, expected_pixels[index]);
|
|
end
|
|
write_ok(`APB4_WS2812_FRAME_WORDS, 6);
|
|
begin_monitor(6);
|
|
write_ok(`APB4_WS2812_CTRL, 32'h1);
|
|
write_ok(`APB4_WS2812_TXDATA, expected_pixels[4]);
|
|
apb4_write(`APB4_WS2812_TXDATA, expected_pixels[5], 4'hF, 1'b0, wait_cycles);
|
|
if (wait_cycles < (BIT_CYCLES * 20)) begin
|
|
$fatal(1, "full FIFO write was not backpressured: %0d cycles", wait_cycles);
|
|
end
|
|
wait_until_idle();
|
|
end_monitor(1'b1);
|
|
apb4_read(`APB4_WS2812_INTR_STATE, 1'b0, value);
|
|
if ((value & 32'h3) != 32'h3 || !ws2812.irq_o) begin
|
|
$fatal(1, "done/low-watermark interrupt missing: %h", value);
|
|
end
|
|
write_ok(`APB4_WS2812_INTR_STATE, 32'hF);
|
|
if (ws2812.irq_o) begin
|
|
$fatal(1, "IRQ did not clear");
|
|
end
|
|
|
|
test_stage = 4;
|
|
expected_pixels[0] = 24'h123456;
|
|
write_ok(`APB4_WS2812_TXDATA, expected_pixels[0]);
|
|
write_ok(`APB4_WS2812_FRAME_WORDS, 2);
|
|
begin_monitor(1);
|
|
write_ok(`APB4_WS2812_CTRL, 32'h1);
|
|
wait_until_idle();
|
|
end_monitor(1'b1);
|
|
apb4_read(`APB4_WS2812_ERROR_STATUS, 1'b0, value);
|
|
if (!value[`WS2812_ERROR_UNDERFLOW]) begin
|
|
$fatal(1, "underflow was not reported");
|
|
end
|
|
apb4_read(`APB4_WS2812_FIFO_LEVEL, 1'b0, value);
|
|
if (value != 0) begin
|
|
$fatal(1, "underflow did not flush FIFO");
|
|
end
|
|
write_ok(`APB4_WS2812_ERROR_STATUS, 32'h7);
|
|
write_ok(`APB4_WS2812_INTR_STATE, 32'hF);
|
|
|
|
test_stage = 5;
|
|
expected_pixels[0] = 24'hABCDEF;
|
|
expected_pixels[1] = 24'h765432;
|
|
write_ok(`APB4_WS2812_TXDATA, expected_pixels[0]);
|
|
write_ok(`APB4_WS2812_TXDATA, expected_pixels[1]);
|
|
write_ok(`APB4_WS2812_FRAME_WORDS, 2);
|
|
begin_monitor(2);
|
|
write_ok(`APB4_WS2812_CTRL, 32'h1);
|
|
repeat (8) @(posedge clk_i);
|
|
write_ok(`APB4_WS2812_CTRL, 32'h2);
|
|
wait_until_idle();
|
|
end_monitor(1'b0);
|
|
apb4_read(`APB4_WS2812_INTR_STATE, 1'b0, value);
|
|
if (!value[`WS2812_INTR_ABORTED]) begin
|
|
$fatal(1, "abort completion was not reported");
|
|
end
|
|
|
|
write_ok(`APB4_WS2812_INTR_TEST, 32'h1);
|
|
if (!ws2812.irq_o) begin
|
|
$fatal(1, "interrupt test did not assert IRQ");
|
|
end
|
|
write_ok(`APB4_WS2812_INTR_STATE, 32'hF);
|
|
|
|
$display("WS2812 register, waveform, streaming, and error test passed");
|
|
$finish;
|
|
end
|
|
endmodule
|