mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
- Introduced a new USB2 transaction engine testbench to validate the functionality of the USB2 transaction engine. - Updated clock and reset domain tests to include USB2 ULPI crossings. - Enhanced memory map tests to verify USB2 base addresses and performance offsets. - Modified pin map tests to ensure USB2 ULPI pins are correctly generated. - Updated SOC topology tests to account for USB2 peripherals and IRQ mappings. - Added static timing analysis constraints for USB2 clock domains. - Created dedicated USB2 tests for various components including packet RAM, descriptor validation, and transaction engine. - Implemented a register parity test to ensure ABI consistency between RTL and C header definitions.
217 lines
7.1 KiB
Systemverilog
217 lines
7.1 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
|
|
module usb2_dma_tb;
|
|
logic clk_i = 1'b0;
|
|
logic rst_n_i = 1'b0;
|
|
logic start_i = 1'b0;
|
|
logic abort_i = 1'b0;
|
|
logic memory_to_packet_i = 1'b1;
|
|
logic allow_short_i = 1'b0;
|
|
logic [31:0] desc_base_i = 32'd0;
|
|
logic [15:0] desc_limit_i = 16'd1;
|
|
logic [31:0] transfer_bytes_i = 32'd5;
|
|
logic packet_in_valid_i = 1'b0;
|
|
logic packet_in_ready_o;
|
|
logic [31:0] packet_in_data_i = '0;
|
|
logic [ 3:0] packet_in_strb_i = '0;
|
|
logic packet_in_last_i = 1'b0;
|
|
logic packet_out_valid_o;
|
|
logic packet_out_ready_i = 1'b1;
|
|
logic [31:0] packet_out_data_o;
|
|
logic [ 3:0] packet_out_strb_o;
|
|
logic packet_out_last_o;
|
|
logic busy_o;
|
|
logic done_o;
|
|
logic error_o;
|
|
logic [ 7:0] error_code_o;
|
|
logic [31:0] current_desc_o;
|
|
logic [31:0] next_desc_o;
|
|
logic [31:0] bytes_done_o;
|
|
logic [31:0] frame_o;
|
|
logic descriptor_irq_o;
|
|
logic abort_done_o;
|
|
integer output_count;
|
|
logic [31:0] output_data [0:1];
|
|
logic [ 3:0] output_strb [0:1];
|
|
logic output_last [0:1];
|
|
logic descriptor_irq_seen;
|
|
|
|
axi4_if #(
|
|
.ADDR_WIDTH(32),
|
|
.DATA_WIDTH(32),
|
|
.ID_WIDTH (1),
|
|
.USER_WIDTH(1)
|
|
) dma_axi4 (
|
|
.aclk (clk_i),
|
|
.aresetn(rst_n_i)
|
|
);
|
|
|
|
always #5 clk_i = ~clk_i;
|
|
|
|
always_ff @(posedge clk_i) begin
|
|
if (!rst_n_i) begin
|
|
output_count <= 0;
|
|
descriptor_irq_seen <= 1'b0;
|
|
end else begin
|
|
if (packet_out_valid_o && packet_out_ready_i) begin
|
|
output_data[output_count] <= packet_out_data_o;
|
|
output_strb[output_count] <= packet_out_strb_o;
|
|
output_last[output_count] <= packet_out_last_o;
|
|
output_count <= output_count + 1;
|
|
end
|
|
if (descriptor_irq_o) begin
|
|
descriptor_irq_seen <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
usb2_dma #(
|
|
.AddrWidth (32),
|
|
.DataWidth (32),
|
|
.MaxDescriptors(16)
|
|
) u_usb2_dma (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.start_i (start_i),
|
|
.abort_i (abort_i),
|
|
.memory_to_packet_i(memory_to_packet_i),
|
|
.allow_short_i (allow_short_i),
|
|
.desc_base_i (desc_base_i),
|
|
.desc_limit_i (desc_limit_i),
|
|
.transfer_bytes_i (transfer_bytes_i),
|
|
.packet_in_valid_i (packet_in_valid_i),
|
|
.packet_in_ready_o (packet_in_ready_o),
|
|
.packet_in_data_i (packet_in_data_i),
|
|
.packet_in_strb_i (packet_in_strb_i),
|
|
.packet_in_last_i (packet_in_last_i),
|
|
.packet_out_valid_o(packet_out_valid_o),
|
|
.packet_out_ready_i(packet_out_ready_i),
|
|
.packet_out_data_o (packet_out_data_o),
|
|
.packet_out_strb_o (packet_out_strb_o),
|
|
.packet_out_last_o (packet_out_last_o),
|
|
.busy_o (busy_o),
|
|
.done_o (done_o),
|
|
.error_o (error_o),
|
|
.error_code_o (error_code_o),
|
|
.current_desc_o (current_desc_o),
|
|
.next_desc_o (next_desc_o),
|
|
.bytes_done_o (bytes_done_o),
|
|
.frame_o (frame_o),
|
|
.descriptor_irq_o (descriptor_irq_o),
|
|
.abort_done_o (abort_done_o),
|
|
.dma_axi4 (dma_axi4)
|
|
);
|
|
|
|
sdio_axi_memory_responder #(
|
|
.DepthWords(16384)
|
|
) u_memory (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.axi4 (dma_axi4)
|
|
);
|
|
|
|
task automatic reset_dut;
|
|
begin
|
|
rst_n_i = 1'b0;
|
|
repeat (4) @(posedge clk_i);
|
|
rst_n_i = 1'b1;
|
|
@(posedge clk_i);
|
|
end
|
|
endtask
|
|
|
|
task automatic start_dma;
|
|
begin
|
|
@(negedge clk_i);
|
|
start_i = 1'b1;
|
|
@(negedge clk_i);
|
|
start_i = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
task automatic send_packet_word(input logic [31:0] data_i, input logic [3:0] strb_i,
|
|
input logic last_i);
|
|
begin
|
|
@(negedge clk_i);
|
|
packet_in_data_i = data_i;
|
|
packet_in_strb_i = strb_i;
|
|
packet_in_last_i = last_i;
|
|
packet_in_valid_i = 1'b1;
|
|
while (!packet_in_ready_o) @(negedge clk_i);
|
|
@(negedge clk_i);
|
|
packet_in_valid_i = 1'b0;
|
|
end
|
|
endtask
|
|
|
|
initial begin
|
|
u_memory.clear_memory();
|
|
reset_dut();
|
|
|
|
// Memory-to-packet transfer splits at 4 KiB and finishes with one valid byte.
|
|
u_memory.write_word(32'h0000_0000, 32'h0000_0FFC);
|
|
u_memory.write_word(32'h0000_0004, 32'd5);
|
|
u_memory.write_word(32'h0000_0008, 32'd0);
|
|
u_memory.write_word(32'h0000_000C, 32'h0000_000D);
|
|
u_memory.write_word(32'h0000_0010, 32'd0);
|
|
u_memory.write_word(32'h0000_0014, 32'd0);
|
|
u_memory.write_word(32'h0000_0018, 32'd0);
|
|
u_memory.write_word(32'h0000_001C, 32'd0);
|
|
u_memory.write_word(32'h0000_0FFC, 32'h4433_2211);
|
|
u_memory.write_word(32'h0000_1000, 32'h0000_0055);
|
|
memory_to_packet_i = 1'b1;
|
|
start_dma();
|
|
wait (done_o || error_o);
|
|
@(posedge clk_i);
|
|
if (error_o || (bytes_done_o != 32'd5) || (output_count != 2) ||
|
|
(output_data[0] != 32'h4433_2211) || (output_strb[0] != 4'hF) || output_last[0] ||
|
|
(output_data[1] != 32'h0000_0055) || (output_strb[1] != 4'h1) || !output_last[1] ||
|
|
(u_memory.read_burst_count != 3) || (u_memory.max_read_beats > 16) ||
|
|
(u_memory.read_word(
|
|
32'h0000_0010
|
|
) != 32'd5) || (u_memory.read_word(
|
|
32'h0000_0014
|
|
) != 32'h0001_0000) || (u_memory.read_word(
|
|
32'h0000_000C
|
|
) != 32'h0000_000C) || !descriptor_irq_seen) begin
|
|
$fatal(1, "memory-to-packet DMA failed err=%b code=%h bytes=%0d outputs=%0d", error_o,
|
|
error_code_o, bytes_done_o, output_count);
|
|
end
|
|
|
|
// Packet-to-memory transfer preserves tail strobes and commits OWN last.
|
|
reset_dut();
|
|
u_memory.write_word(32'h0000_0000, 32'h0000_0200);
|
|
u_memory.write_word(32'h0000_0004, 32'd5);
|
|
u_memory.write_word(32'h0000_0008, 32'd0);
|
|
u_memory.write_word(32'h0000_000C, 32'h0000_000D);
|
|
u_memory.write_word(32'h0000_0010, 32'd0);
|
|
u_memory.write_word(32'h0000_0014, 32'd0);
|
|
u_memory.write_word(32'h0000_0018, 32'd0);
|
|
u_memory.write_word(32'h0000_001C, 32'd0);
|
|
u_memory.write_word(32'h0000_0200, 32'd0);
|
|
u_memory.write_word(32'h0000_0204, 32'd0);
|
|
memory_to_packet_i = 1'b0;
|
|
start_dma();
|
|
send_packet_word(32'h8877_6655, 4'hF, 1'b0);
|
|
send_packet_word(32'h0000_0099, 4'h1, 1'b1);
|
|
wait (done_o || error_o);
|
|
@(posedge clk_i);
|
|
if (error_o || (bytes_done_o != 32'd5) || (u_memory.read_word(
|
|
32'h0000_0200
|
|
) != 32'h8877_6655) || (u_memory.read_word(
|
|
32'h0000_0204
|
|
) != 32'h0000_0099) || (u_memory.read_word(
|
|
32'h0000_0010
|
|
) != 32'd5) || (u_memory.read_word(
|
|
32'h0000_0014
|
|
) != 32'h0001_0000) || (u_memory.read_word(
|
|
32'h0000_000C
|
|
) != 32'h0000_000C) || !descriptor_irq_seen) begin
|
|
$fatal(1, "packet-to-memory DMA failed err=%b code=%h bytes=%0d data=%h tail=%h", error_o,
|
|
error_code_o, bytes_done_o, u_memory.read_word(32'h0000_0200), u_memory.read_word(
|
|
32'h0000_0204));
|
|
end
|
|
|
|
$display("USB2 descriptor DMA test passed");
|
|
$finish;
|
|
end
|
|
endmodule
|