mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- Added TCD head and count registers to DMA definition and register files. - Introduced CRC expected and result registers for enhanced error checking. - Updated DMA version to 2.0 to reflect new features. - Modified DMA testbench to validate new TCD and CRC functionalities. - Enhanced README and filelists to include new dependencies and configurations. - Updated formal verification and runtime tests to accommodate new DMA features.
270 lines
8.3 KiB
Systemverilog
270 lines
8.3 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
|
|
module dma_reg_tb;
|
|
logic clk_i = 1'b0;
|
|
logic rst_n_i = 1'b0;
|
|
logic irq_o;
|
|
logic xpi_done_o;
|
|
logic read_active_q = 1'b0;
|
|
logic write_active_q = 1'b0;
|
|
logic write_response_q = 1'b0;
|
|
logic allow_write_response = 1'b0;
|
|
|
|
dma_req_if req ();
|
|
apb4_if apb4 (
|
|
.pclk (clk_i),
|
|
.presetn(rst_n_i)
|
|
);
|
|
axi4_if axi4 (
|
|
.aclk (clk_i),
|
|
.aresetn(rst_n_i)
|
|
);
|
|
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;
|
|
|
|
assign axi4.arready = !read_active_q;
|
|
assign axi4.rid = '0;
|
|
assign axi4.rdata = 32'hC0DE_0001;
|
|
assign axi4.rresp = `AXI4_RESP_OKAY;
|
|
assign axi4.rlast = 1'b1;
|
|
assign axi4.ruser = '0;
|
|
assign axi4.rvalid = read_active_q;
|
|
assign axi4.awready = !write_active_q && !write_response_q;
|
|
assign axi4.wready = write_active_q;
|
|
assign axi4.bid = '0;
|
|
assign axi4.bresp = `AXI4_RESP_OKAY;
|
|
assign axi4.buser = '0;
|
|
assign axi4.bvalid = write_response_q && allow_write_response;
|
|
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
|
|
read_active_q <= 1'b0;
|
|
write_active_q <= 1'b0;
|
|
write_response_q <= 1'b0;
|
|
end else begin
|
|
if (axi4.arvalid && axi4.arready) begin
|
|
if (axi4.arlen != 8'd0) begin
|
|
$fatal(1, "register-directed transfer unexpectedly burst");
|
|
end
|
|
read_active_q <= 1'b1;
|
|
end
|
|
if (axi4.rvalid && axi4.rready) begin
|
|
read_active_q <= 1'b0;
|
|
end
|
|
if (axi4.awvalid && axi4.awready) begin
|
|
if (axi4.awlen != 8'd0) begin
|
|
$fatal(1, "register-directed transfer unexpectedly burst");
|
|
end
|
|
write_active_q <= 1'b1;
|
|
end
|
|
if (axi4.wvalid && axi4.wready) begin
|
|
if (!axi4.wlast || (axi4.wdata != 32'hC0DE_0001)) begin
|
|
$fatal(1, "DMA register transfer write data mismatch");
|
|
end
|
|
write_active_q <= 1'b0;
|
|
write_response_q <= 1'b1;
|
|
end
|
|
if (axi4.bvalid && axi4.bready) begin
|
|
write_response_q <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
apb4_dma u_apb4_dma (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.dma_xfer_done_o(xpi_done_o),
|
|
.irq_o (irq_o),
|
|
.hw_trg (req),
|
|
.apb4 (apb4),
|
|
.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)
|
|
);
|
|
|
|
task automatic apb_write(input logic [31:0] address, input logic [31:0] data,
|
|
input logic [3:0] strobe, input logic expected_error);
|
|
begin
|
|
@(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;
|
|
#1;
|
|
while (!apb4.pready) @(negedge clk_i);
|
|
if (apb4.pslverr != expected_error) begin
|
|
$fatal(1, "APB write %h PSLVERR=%b expected=%b", address, apb4.pslverr, expected_error);
|
|
end
|
|
@(negedge clk_i);
|
|
apb4.psel = 1'b0;
|
|
apb4.penable = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic apb_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;
|
|
#1;
|
|
while (!apb4.pready) @(negedge clk_i);
|
|
if (apb4.pslverr) begin
|
|
$fatal(1, "APB read %h unexpectedly failed", address);
|
|
end
|
|
data = apb4.prdata;
|
|
@(negedge clk_i);
|
|
apb4.psel = 1'b0;
|
|
apb4.penable = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
initial begin
|
|
logic [31:0] value;
|
|
|
|
apb4.paddr = '0;
|
|
apb4.pprot = '0;
|
|
apb4.psel = 1'b0;
|
|
apb4.penable = 1'b0;
|
|
apb4.pwrite = 1'b0;
|
|
apb4.pwdata = '0;
|
|
apb4.pstrb = '0;
|
|
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;
|
|
|
|
apb_read(32'h000, value);
|
|
if (value != 32'h444D_4134) begin
|
|
$fatal(1, "DMA IP identification mismatch");
|
|
end
|
|
apb_read(32'h004, value);
|
|
if (value != 32'h0002_0000) begin
|
|
$fatal(1, "DMA V2 version mismatch: %h", value);
|
|
end
|
|
apb_read(32'h008, value);
|
|
if ((value[0] != 1'b1) || (value[15:8] != 8'd4)) begin
|
|
$fatal(1, "DMA capability descriptor/channel mismatch: %h", value);
|
|
end
|
|
apb_write(32'h2C8, 32'h4000_8000, 4'hF, 1'b0);
|
|
apb_write(32'h2CC, 32'h0000_0001, 4'hF, 1'b0);
|
|
apb_write(32'h2D0, 32'h1234_5678, 4'hF, 1'b0);
|
|
apb_read(32'h2C8, value);
|
|
if (value != 32'h4000_8000) begin
|
|
$fatal(1, "DMA TCD head register mismatch: %h", value);
|
|
end
|
|
apb_read(32'h2D0, value);
|
|
if (value != 32'h1234_5678) begin
|
|
$fatal(1, "DMA CRC expected register mismatch: %h", value);
|
|
end
|
|
apb_write(32'h02c, 32'h1, 4'hF, 1'b1);
|
|
apb_write(32'h104, 32'h0000_0160, 4'h1, 1'b0);
|
|
apb_write(32'h108, 32'h4000_0000, 4'hF, 1'b0);
|
|
apb_write(32'h10c, 32'h4000_1000, 4'hF, 1'b0);
|
|
apb_write(32'h110, 32'h0000_0004, 4'hF, 1'b0);
|
|
apb_write(32'h114, 32'h0000_0000, 4'hF, 1'b0);
|
|
apb_write(32'h118, 32'h0000_0001, 4'hF, 1'b0);
|
|
apb_write(32'h11c, 32'h0000_0007, 4'hF, 1'b0);
|
|
apb_write(32'h018, 32'h0000_0001, 4'hF, 1'b0);
|
|
apb_write(32'h100, 32'h0000_0001, 4'h1, 1'b0);
|
|
|
|
wait (write_response_q);
|
|
apb_write(32'h110, 32'h0000_0008, 4'hF, 1'b1);
|
|
apb_write(32'h100, 32'h0000_0010, 4'h1, 1'b1);
|
|
apb_write(32'h00c, 32'h0000_0001, 4'h1, 1'b1);
|
|
apb_write(32'h100, 32'h0000_0001, 4'h2, 1'b1);
|
|
allow_write_response = 1'b1;
|
|
wait (!write_response_q);
|
|
repeat (2) @(posedge clk_i);
|
|
apb_read(32'h120, value);
|
|
if ((value & 32'h0000_0005) != 32'h0000_0004) begin
|
|
$fatal(1, "DMA status did not report a completed, idle transfer: %h", value);
|
|
end
|
|
apb_read(32'h124, value);
|
|
if (((value & 32'h1) == 32'd0) || !irq_o) begin
|
|
$fatal(1, "DMA done event did not assert the aggregate IRQ");
|
|
end
|
|
apb_write(32'h124, 32'h0000_0007, 4'h2, 1'b1);
|
|
if (!irq_o) begin
|
|
$fatal(1, "DMA event clear ignored unsupported PSTRB");
|
|
end
|
|
apb_write(32'h124, 32'h0000_0007, 4'h1, 1'b0);
|
|
repeat (1) @(posedge clk_i);
|
|
if (irq_o) begin
|
|
$fatal(1, "DMA W1C event clear did not lower the aggregate IRQ");
|
|
end
|
|
apb_write(32'h00c, 32'h0000_0001, 4'h1, 1'b0);
|
|
|
|
$display("DMA APB register and aggregate IRQ test passed");
|
|
$finish;
|
|
end
|
|
endmodule
|