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