mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- 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.
369 lines
12 KiB
Systemverilog
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
|