Files
retroSoC/tests/rtl/i2s_tb.sv
T
maksyuki 952b060a70 feat(tiny): integrate P6 shared IP and eight-channel DMA
Integrate RNG, CRC, WS2812, Crypto, I2S master and the SDIO private AXI owner on SAFE24. Preserve the 128 KiB main SRAM and six private Crypto macros, add product-specific DMA assignments and reject unsupported SDK operations.

Correct APB read strobes, I2S receive assembly and SDIO command timing, backpressure and descriptor retirement. Add pin-level workloads, source-bound evidence checks and publication/commercial consumer compatibility.

Validation of the final P6 worktree: 1726 pytest tests passed with one optional pypdf skip (exit 0, 4021.61 seconds; terminal session 36439). Both PDKs passed both RTL simulators, netlist boot and 38-macro binding checks. Shared formal, Mini compatibility and software/source quality gates passed.

Evidence remains attributed to the retained dirty-worktree snapshots based on b3b30a72cd under build/ics55-tiny-2026-10-12-11-50-2eb98c0e1fae/meta/tiny-r2-p6/. Timing is negative and warning observations are not promoted. This commit does not accept P6, qualify physical operation or enable P7.
2026-10-12 21:43:30 +08:00

171 lines
4.9 KiB
Systemverilog

`timescale 1ns / 1ps
`include "i2s_define.svh"
module i2s_tb;
logic clk_i = 1'b0;
logic clk_aud_i = 1'b0;
logic rst_n_i = 1'b0;
logic rst_aud_n_i = 1'b0;
logic dma_tx_stall;
logic dma_rx_stall;
logic [31:0] value;
int sclk_edges;
apb4_if apb4 (
.pclk (clk_i),
.presetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32),
.ID_WIDTH (1),
.DEST_WIDTH(1),
.USER_WIDTH(1)
) tx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
axi4_stream_if #(
.DATA_WIDTH(32),
.ID_WIDTH (1),
.DEST_WIDTH(1),
.USER_WIDTH(1)
) rx_axis (
.aclk (clk_i),
.aresetn(rst_n_i)
);
i2s_if i2s ();
assign i2s.adcdat_i = i2s.dacdat_o;
assign tx_axis.tvalid = 1'b0;
assign tx_axis.tdata = '0;
assign tx_axis.tkeep = '1;
assign tx_axis.tstrb = '1;
assign tx_axis.tlast = 1'b0;
assign tx_axis.tid = '0;
assign tx_axis.tdest = '0;
assign tx_axis.tuser = '0;
assign rx_axis.tready = 1'b1;
always #5 clk_i = ~clk_i;
always #8 clk_aud_i = ~clk_aud_i;
apb4_i2s u_dut (
.clk_i (clk_i),
.rst_n_i (rst_n_i),
.clk_aud_i (clk_aud_i),
.rst_aud_n_i (rst_aud_n_i),
.dma_tx_stall_o(dma_tx_stall),
.dma_rx_stall_o(dma_rx_stall),
.apb4 (apb4),
.tx_axis (tx_axis),
.rx_axis (rx_axis),
.i2s (i2s)
);
task automatic write(input logic [31:0] address, input logic [31:0] data);
begin
@(negedge clk_i);
apb4.paddr = address;
apb4.pwdata = data;
apb4.pstrb = 4'hF;
apb4.pwrite = 1'b1;
apb4.psel = 1'b1;
apb4.penable = 1'b0;
@(negedge clk_i);
apb4.penable = 1'b1;
while (!apb4.pready) @(negedge clk_i);
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.pstrb = '0;
end
endtask
task automatic read(input logic [31:0] address, 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);
data = apb4.prdata;
apb4.psel = 1'b0;
apb4.penable = 1'b0;
end
endtask
task automatic zero_strobe_rx_write;
logic [31:0] before_status, after_status;
read(32'h8, before_status);
if (before_status[2]) $fatal(1, "missing RX data for direction test");
@(negedge clk_i);
apb4.paddr = 32'h20;
apb4.pwdata = 0;
apb4.pstrb = 0;
apb4.pwrite = 1;
apb4.psel = 1;
apb4.penable = 0;
@(negedge clk_i);
apb4.penable = 1;
while (!apb4.pready) @(negedge clk_i);
if (!apb4.pslverr) $fatal(1, "zero-strobe write became an RX read");
apb4.psel = 0;
apb4.penable = 0;
apb4.pwrite = 0;
read(32'h8, after_status);
if (before_status[23:16] != after_status[23:16]) $fatal(1, "invalid write popped RX FIFO");
endtask
always @(posedge i2s.sclk_o) sclk_edges = sclk_edges + 1;
initial begin
apb4.psel = 1'b0;
apb4.paddr = '0;
apb4.pwdata = '0;
apb4.pstrb = '0;
sclk_edges = 0;
repeat (8) @(posedge clk_i);
rst_n_i = 1'b1;
rst_aud_n_i = 1'b1;
read(32'h0000_00f8, value);
if (value != 32'h0001_0000) $fatal(1, "bad I2S version %h", value);
read(32'h0000_00fc, value);
if (value != 32'h0030_0707) $fatal(1, "bad I2S capability %h", value);
read(32'h0000_0100, value);
if (!apb4.pslverr) $fatal(1, "invalid I2S access was accepted");
write(32'h0000_0000, 32'h0000_0001);
write(32'h0000_0010, 32'h0000_0001);
if (!apb4.pslverr) $fatal(1, "enabled FORMAT write was accepted");
write(32'h0000_0000, 32'h0000_0000);
write(32'h0000_0010, 32'h0000_0000);
write(32'h0000_0018, 32'h0020_0078);
write(32'h0000_0028, 32'h0000_0004);
write(32'h0000_0030, 32'h0000_0004);
read(32'h0000_0024, value);
if ((value & 32'h0000_0004) == 0) $fatal(1, "I2S interrupt test failed");
if (!i2s.irq_o) $fatal(1, "I2S IRQ was not raised");
write(32'h0000_0024, 32'h0000_000F);
write(32'h0000_001c, 32'hA5A5_5A5A);
write(32'h0000_0000, 32'h0000_0007);
repeat (4000) @(posedge clk_aud_i);
if (sclk_edges == 0) $fatal(1, "I2S SCLK did not toggle");
read(32'h0000_0008, value);
write(32'h0000_0000, 32'h0000_0000);
repeat (64) @(negedge clk_i);
zero_strobe_rx_write();
write(32'h0000_0000, 32'h0000_0008);
write(32'h0000_0000, 32'h0000_0009);
repeat (2000) @(posedge clk_aud_i);
write(32'h0000_0004, 32'h0000_0003);
repeat (200) @(posedge clk_i);
read(32'h0000_0008, value);
if ((value & 32'h0300_0000) != 0) $fatal(1, "I2S flush stayed busy %h", value);
$display("APB4 I2S controller test passed");
$finish;
end
endmodule