Files
retroSoC/tests/rtl/ws2812_dma_tb.sv
T
maksyuki db9282aaf6 feat: add crypto accelerator support and related tests
- Modified DMA error testbench to include crypto input and output AXI4 stream interfaces.
- Updated DMA register testbench to integrate crypto AXI4 stream interfaces.
- Enhanced SOC IRQ topology test to account for new crypto IRQs.
- Added WS2812 DMA testbench modifications for crypto interfaces.
- Introduced new Python tests for crypto primitives (AES, SHA, RSA) and APB register paths.
- Implemented register parity tests to ensure synchronization between RTL and SDK constants.
- Expanded DMA tests to validate crypto streaming endpoints.
- Updated memory map tests to include crypto address definitions.
- Adjusted SOC topology tests to reflect changes in IRQ mappings and peripheral counts.
2026-08-21 07:29:00 +08:00

369 lines
12 KiB
Systemverilog

`timescale 1ns / 1ps
`include "ws2812_define.svh"
module ws2812_dma_tb;
localparam logic [31:0] SourceBase = 32'h4000_0000;
localparam logic [31:0] Ws2812Txdata = 32'h1000_8010;
localparam int BitCycles = 4;
localparam int T0hCycles = 1;
localparam int T1hCycles = 3;
localparam int ResetCycles = 5;
typedef enum logic [2:0] {
AxiIdle,
AxiReadResponse,
AxiWriteWait,
AxiWriteSetup,
AxiWriteAccess,
AxiWriteResponse
} axi_state_e;
logic clk_i = 1'b0;
logic rst_n_i = 1'b0;
logic dma_start = 1'b0;
logic [ 31:0] dma_cfg = '0;
logic [ 31:0] dma_src_addr = '0;
logic [ 31:0] dma_dst_addr = '0;
logic [ 31:0] dma_byte_count = '0;
logic [ 31:0] dma_request = '0;
logic [ 31:0] dma_burst = '0;
logic dma_done;
logic dma_error;
logic [ 3:0] dma_done_vector;
logic [ 3:0] dma_error_vector;
logic [127:0] dma_error_status_vector;
logic [127:0] dma_error_addr_vector;
logic host_active = 1'b1;
logic host_psel = 1'b0;
logic host_penable = 1'b0;
logic [ 31:0] host_addr = '0;
logic [ 31:0] host_wdata = '0;
logic [ 3:0] host_wstrb = '0;
axi_state_e axi_state_q = AxiIdle;
logic [ 31:0] axi_read_addr_q = '0;
integer dma_write_count = 0;
integer dma_backpressure_cycles = 0;
logic [ 23:0] pixels [0:5];
integer observed_pixel = 0;
integer observed_bit = 0;
integer observed_cycle = 0;
integer reset_low_cycles = 0;
dma_req_if req ();
axi4_if axi4 (
.aclk (clk_i),
.aresetn(rst_n_i)
);
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
);
ws2812_if ws2812 ();
axi4_stream_if i2s_tx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if i2s_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if dvp_rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if crypto_in_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if crypto_out_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
always #5 clk_i = ~clk_i;
initial begin
repeat (5000) @(posedge clk_i);
$fatal(1, "WS2812 DMA integration test timeout");
end
assign apb4.psel = host_active ? host_psel :
((axi_state_q == AxiWriteSetup) || (axi_state_q == AxiWriteAccess));
assign apb4.penable = host_active ? host_penable : (axi_state_q == AxiWriteAccess);
assign apb4.pwrite = 1'b1;
assign apb4.paddr = host_active ? host_addr : Ws2812Txdata;
assign apb4.pwdata = host_active ? host_wdata : axi4.wdata;
assign apb4.pstrb = host_active ? host_wstrb : axi4.wstrb;
assign apb4.pprot = '0;
assign axi4.arready = axi_state_q == AxiIdle;
assign axi4.rid = '0;
assign axi4.rdata = pixels[axi_read_addr_q[4:2]];
assign axi4.rresp = `AXI4_RESP_OKAY;
assign axi4.rlast = 1'b1;
assign axi4.ruser = '0;
assign axi4.rvalid = axi_state_q == AxiReadResponse;
assign axi4.awready = (axi_state_q == AxiIdle) && !axi4.arvalid;
assign axi4.wready = (axi_state_q == AxiWriteAccess) && apb4.pready;
assign axi4.bid = '0;
assign axi4.bresp = `AXI4_RESP_OKAY;
assign axi4.buser = '0;
assign axi4.bvalid = axi_state_q == AxiWriteResponse;
assign i2s_tx_axis.tready = 1'b0;
assign i2s_rx_axis.tdata = '0;
assign i2s_rx_axis.tkeep = '0;
assign i2s_rx_axis.tstrb = '0;
assign i2s_rx_axis.tlast = 1'b0;
assign i2s_rx_axis.tid = '0;
assign i2s_rx_axis.tdest = '0;
assign i2s_rx_axis.tuser = '0;
assign i2s_rx_axis.tvalid = 1'b0;
assign dvp_rx_axis.tdata = '0;
assign dvp_rx_axis.tkeep = '0;
assign dvp_rx_axis.tstrb = '0;
assign dvp_rx_axis.tlast = 1'b0;
assign dvp_rx_axis.tid = '0;
assign dvp_rx_axis.tdest = '0;
assign dvp_rx_axis.tuser = '0;
assign dvp_rx_axis.tvalid = 1'b0;
assign crypto_in_axis.tready = 1'b0;
assign crypto_out_axis.tdata = '0;
assign crypto_out_axis.tkeep = '0;
assign crypto_out_axis.tstrb = '0;
assign crypto_out_axis.tlast = 1'b0;
assign crypto_out_axis.tid = '0;
assign crypto_out_axis.tdest = '0;
assign crypto_out_axis.tuser = '0;
assign crypto_out_axis.tvalid = 1'b0;
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
axi_state_q <= AxiIdle;
axi_read_addr_q <= '0;
dma_write_count <= 0;
dma_backpressure_cycles <= 0;
end else begin
if (axi4.wvalid && !axi4.wready) begin
dma_backpressure_cycles <= dma_backpressure_cycles + 1;
end
unique case (axi_state_q)
AxiIdle: begin
if (axi4.arvalid && axi4.arready) begin
if ((axi4.arlen != 8'd0) || (axi4.araddr < (SourceBase + 32'd4)) ||
(axi4.araddr > (SourceBase + 32'd20))) begin
$fatal(1, "DMA issued an invalid WS2812 source read");
end
axi_read_addr_q <= axi4.araddr;
axi_state_q <= AxiReadResponse;
end else if (axi4.awvalid && axi4.awready) begin
if ((axi4.awlen != 8'd0) || (axi4.awaddr != Ws2812Txdata) ||
(axi4.awburst != `AXI4_BURST_TYPE_FIXED)) begin
$fatal(1, "fixed WS2812 destination was not a single AXI4 FIXED beat");
end
axi_state_q <= AxiWriteWait;
end
end
AxiReadResponse: begin
if (axi4.rvalid && axi4.rready) begin
axi_state_q <= AxiIdle;
end
end
AxiWriteWait: begin
if (axi4.wvalid) begin
axi_state_q <= AxiWriteSetup;
end
end
AxiWriteSetup: axi_state_q <= AxiWriteAccess;
AxiWriteAccess: begin
if (axi4.wvalid && axi4.wready) begin
if (!axi4.wlast) begin
$fatal(1, "single-beat WS2812 write did not assert WLAST");
end
dma_write_count <= dma_write_count + 1;
axi_state_q <= AxiWriteResponse;
end
end
AxiWriteResponse: begin
if (axi4.bvalid && axi4.bready) begin
axi_state_q <= AxiIdle;
end
end
default: axi_state_q <= AxiIdle;
endcase
end
end
dma_core #(
.NumChannels (4),
.MaxBurstBeats(16),
.FifoDepth (16)
) u_dma_core (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.global_reset_i (1'b0),
.global_error_clear_i (1'b0),
.ch_cfg_i ({96'd0, dma_cfg}),
.src_addr_i ({96'd0, dma_src_addr}),
.dst_addr_i ({96'd0, dma_dst_addr}),
.byte_count_i ({96'd0, dma_byte_count}),
.request_sel_i ({96'd0, dma_request}),
.burst_cfg_i ({96'd0, dma_burst}),
.start_i ({3'd0, dma_start}),
.suspend_i ('0),
.resume_i ('0),
.abort_i ('0),
.channel_reset_i ('0),
.event_clear_i ('0),
.busy_o (),
.suspended_o (),
.done_o (dma_done_vector),
.aborted_o (),
.error_o (dma_error_vector),
.stream_last_o (),
.event_status_o (),
.error_status_o (dma_error_status_vector),
.error_addr_o (dma_error_addr_vector),
.current_src_o (),
.current_dst_o (),
.remaining_o (),
.bytes_done_o (),
.stall_cycles_lo_o (),
.stall_cycles_hi_o (),
.first_error_valid_o (),
.first_error_channel_o(),
.first_error_status_o (),
.first_error_addr_hi_o(),
.request_status_o (),
.xpi_xfer_done_o (),
.req (req),
.axi4 (axi4),
.i2s_tx_axis (i2s_tx_axis),
.i2s_rx_axis (i2s_rx_axis),
.dvp_rx_axis (dvp_rx_axis),
.crypto_in_axis (crypto_in_axis),
.crypto_out_axis (crypto_out_axis)
);
assign dma_done = dma_done_vector[0];
assign dma_error = dma_error_vector[0];
apb4_ws2812 #(
.TxFifoDepth(4)
) u_ws2812 (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.apb4 (apb4),
.ws2812 (ws2812)
);
task automatic host_write(input logic [31:0] address, input logic [31:0] data);
begin
@(negedge clk_i);
host_addr = address;
host_wdata = data;
host_wstrb = 4'hF;
host_psel = 1'b1;
host_penable = 1'b0;
@(negedge clk_i);
host_penable = 1'b1;
while (!apb4.pready) @(negedge clk_i);
if (apb4.pslverr) $fatal(1, "WS2812 host write %h failed", address);
host_psel = 1'b0;
host_penable = 1'b0;
end
endtask
always @(posedge clk_i) begin
#1;
if (rst_n_i && u_ws2812.s_busy && !u_ws2812.s_reset_active) begin
integer high_cycles;
logic expected_data;
high_cycles = pixels[observed_pixel][23-observed_bit] ? T1hCycles : T0hCycles;
expected_data = observed_cycle < high_cycles;
if (ws2812.dat_o !== expected_data) begin
$fatal(1, "DMA waveform mismatch pixel=%0d bit=%0d cycle=%0d", observed_pixel,
observed_bit, observed_cycle);
end
observed_cycle = observed_cycle + 1;
if (observed_cycle == BitCycles) 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 (rst_n_i && u_ws2812.s_reset_active) begin
if (ws2812.dat_o !== 1'b0) begin
$fatal(1, "DMA frame reset interval drove the output high");
end
reset_low_cycles = reset_low_cycles + 1;
end
if (dma_error) begin
$fatal(1, "DMA failed during WS2812 transfer status=%h address=%h",
dma_error_status_vector[31:0], dma_error_addr_vector[31:0]);
end
end
initial begin
pixels[0] = 24'h800001;
pixels[1] = 24'h010203;
pixels[2] = 24'hA5A5A5;
pixels[3] = 24'h5A5A5A;
pixels[4] = 24'hFFFFFF;
pixels[5] = 24'h000000;
req.i2s_tx_proc = 1'b1;
req.i2s_rx_proc = 1'b1;
req.qspi_tx_proc = 1'b1;
req.qspi_rx_proc = 1'b1;
req.uart_tx_proc = 1'b1;
req.uart_rx_proc = 1'b1;
req.i2c0_tx_proc = 1'b1;
req.i2c0_rx_proc = 1'b1;
req.i2c1_tx_proc = 1'b1;
req.i2c1_rx_proc = 1'b1;
req.crypto_in_proc = 1'b1;
req.crypto_out_proc = 1'b1;
repeat (3) @(posedge clk_i);
rst_n_i = 1'b1;
host_write(`APB4_WS2812_BIT_CYCLES, BitCycles);
host_write(`APB4_WS2812_T0H_CYCLES, T0hCycles);
host_write(`APB4_WS2812_T1H_CYCLES, T1hCycles);
host_write(`APB4_WS2812_RESET_CYCLES, ResetCycles);
host_write(`APB4_WS2812_FIFO_WATERMARK, 3);
host_write(`APB4_WS2812_INTR_ENABLE, 1);
host_write(`APB4_WS2812_TXDATA, pixels[0]);
host_write(`APB4_WS2812_FRAME_WORDS, 6);
host_write(`APB4_WS2812_CTRL, 1);
host_active = 1'b0;
dma_cfg = {22'd0, 2'd1, 1'b0, 1'b1, 2'd2, 1'b0, 3'd0};
dma_src_addr = SourceBase + 32'd4;
dma_dst_addr = Ws2812Txdata;
dma_byte_count = 32'd20;
dma_request = 32'd0;
dma_burst = 32'd16;
@(negedge clk_i);
dma_start = 1'b1;
@(negedge clk_i);
dma_start = 1'b0;
wait (dma_done);
wait (!u_ws2812.s_busy);
@(posedge clk_i);
#1;
if ((dma_write_count != 5) || (dma_backpressure_cycles < 40) ||
(observed_pixel != 6) || (reset_low_cycles < ResetCycles) || !ws2812.irq_o) begin
$fatal(1, "DMA WS2812 result writes=%0d stalls=%0d pixels=%0d reset=%0d irq=%b",
dma_write_count, dma_backpressure_cycles, observed_pixel, reset_low_cycles,
ws2812.irq_o);
end
$display("WS2812 native AXI4 DMA backpressure integration test passed");
$finish;
end
endmodule