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.
278 lines
12 KiB
Systemverilog
278 lines
12 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
|
|
module usb2_transaction_engine_tb;
|
|
logic clk_i = 1'b0;
|
|
logic rst_n_i = 1'b0;
|
|
usb2_pkg::usb2_role_e active_role_i = usb2_pkg::Usb2RoleHost;
|
|
logic [ 7:0][31:0] endpoint_cfg_i = '0;
|
|
logic work_valid_i = 1'b0;
|
|
logic work_ready_o;
|
|
logic [63:0] work_data_i = '0;
|
|
logic result_valid_o;
|
|
logic [63:0] result_data_o;
|
|
logic setup_valid_o;
|
|
logic [63:0] setup_data_o;
|
|
logic tx_request_valid_o;
|
|
logic tx_request_ready_i = 1'b1;
|
|
logic [ 3:0] tx_request_pid_o;
|
|
logic [10:0] tx_request_token_o;
|
|
logic [10:0] tx_request_length_o;
|
|
logic tx_payload_valid_o;
|
|
logic tx_payload_ready_i = 1'b1;
|
|
logic [ 7:0] tx_payload_data_o;
|
|
logic tx_done_i = 1'b0;
|
|
logic tx_error_i = 1'b0;
|
|
logic rx_payload_valid_i = 1'b0;
|
|
logic [ 7:0] rx_payload_data_i = '0;
|
|
logic rx_packet_done_i = 1'b0;
|
|
logic rx_packet_good_i = 1'b0;
|
|
logic [ 3:0] rx_packet_pid_i = '0;
|
|
logic store_rx_start_valid;
|
|
logic store_rx_start_ready;
|
|
logic [11:0] store_rx_base;
|
|
logic [14:0] store_rx_limit;
|
|
logic store_rx_valid;
|
|
logic store_rx_ready;
|
|
logic [ 7:0] store_rx_data;
|
|
logic store_rx_commit;
|
|
logic store_rx_cancel;
|
|
logic store_rx_done;
|
|
logic [14:0] store_rx_bytes;
|
|
logic store_rx_overflow;
|
|
logic store_tx_start_valid;
|
|
logic store_tx_start_ready;
|
|
logic [11:0] store_tx_base;
|
|
logic [14:0] store_tx_bytes;
|
|
logic store_tx_valid;
|
|
logic store_tx_ready;
|
|
logic [ 7:0] store_tx_data;
|
|
logic store_tx_done;
|
|
logic fill_start_valid_i = 1'b0;
|
|
logic fill_start_ready_o;
|
|
logic fill_valid_i = 1'b0;
|
|
logic fill_ready_o;
|
|
logic [31:0] fill_data_i = '0;
|
|
logic [ 3:0] fill_strb_i = '0;
|
|
logic fill_last_i = 1'b0;
|
|
logic fill_done_o;
|
|
logic fill_error_o;
|
|
logic busy_o;
|
|
logic retry_o;
|
|
logic protocol_error_o;
|
|
logic pending_tx_q = 1'b0;
|
|
logic pending_data_q = 1'b0;
|
|
logic data_consumed_q = 1'b0;
|
|
integer pid_count;
|
|
logic [ 3:0] observed_pid [0:3];
|
|
|
|
always #5 clk_i = ~clk_i;
|
|
|
|
always_ff @(posedge clk_i) begin
|
|
tx_done_i <= 1'b0;
|
|
rx_packet_done_i <= 1'b0;
|
|
rx_packet_good_i <= 1'b0;
|
|
if (!rst_n_i) begin
|
|
pending_tx_q <= 1'b0;
|
|
pending_data_q <= 1'b0;
|
|
data_consumed_q <= 1'b0;
|
|
pid_count <= 0;
|
|
end else begin
|
|
if (tx_request_valid_o && tx_request_ready_i) begin
|
|
observed_pid[pid_count] <= tx_request_pid_o;
|
|
pid_count <= pid_count + 1;
|
|
if (usb2_pkg::usb2_pid_is_data(tx_request_pid_o)) begin
|
|
pending_data_q <= 1'b1;
|
|
end else begin
|
|
pending_tx_q <= 1'b1;
|
|
end
|
|
end
|
|
if (pending_tx_q) begin
|
|
tx_done_i <= 1'b1;
|
|
pending_tx_q <= 1'b0;
|
|
end
|
|
if (pending_data_q && tx_payload_valid_o && tx_payload_ready_i &&
|
|
(tx_payload_data_o == 8'h55)) begin
|
|
data_consumed_q <= 1'b1;
|
|
end
|
|
if (pending_data_q && data_consumed_q) begin
|
|
tx_done_i <= 1'b1;
|
|
pending_data_q <= 1'b0;
|
|
data_consumed_q <= 1'b0;
|
|
end
|
|
if ((pid_count == 2) && !pending_data_q && !pending_tx_q && tx_done_i) begin
|
|
rx_packet_pid_i <= usb2_pkg::Usb2PidAck;
|
|
rx_packet_done_i <= 1'b1;
|
|
rx_packet_good_i <= 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
usb2_transaction_engine u_engine (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.active_role_i (active_role_i),
|
|
.device_addr_i (7'd0),
|
|
.endpoint_cfg_i (endpoint_cfg_i),
|
|
.timeout_i (32'd1000),
|
|
.work_valid_i (work_valid_i),
|
|
.work_ready_o (work_ready_o),
|
|
.work_data_i (work_data_i),
|
|
.result_valid_o (result_valid_o),
|
|
.result_ready_i (1'b1),
|
|
.result_data_o (result_data_o),
|
|
.setup_valid_o (setup_valid_o),
|
|
.setup_ready_i (1'b1),
|
|
.setup_data_o (setup_data_o),
|
|
.tx_request_valid_o (tx_request_valid_o),
|
|
.tx_request_ready_i (tx_request_ready_i),
|
|
.tx_request_pid_o (tx_request_pid_o),
|
|
.tx_request_token_o (tx_request_token_o),
|
|
.tx_request_length_o (tx_request_length_o),
|
|
.tx_payload_valid_o (tx_payload_valid_o),
|
|
.tx_payload_ready_i (tx_payload_ready_i),
|
|
.tx_payload_data_o (tx_payload_data_o),
|
|
.tx_done_i (tx_done_i),
|
|
.tx_error_i (tx_error_i),
|
|
.rx_payload_valid_i (rx_payload_valid_i),
|
|
.rx_payload_data_i (rx_payload_data_i),
|
|
.rx_packet_done_i (rx_packet_done_i),
|
|
.rx_packet_good_i (rx_packet_good_i),
|
|
.rx_packet_pid_i (rx_packet_pid_i),
|
|
.rx_token_addr_i (7'd0),
|
|
.rx_token_endpoint_i (4'd0),
|
|
.rx_payload_length_i (11'd0),
|
|
.store_rx_start_valid_o(store_rx_start_valid),
|
|
.store_rx_start_ready_i(store_rx_start_ready),
|
|
.store_rx_base_o (store_rx_base),
|
|
.store_rx_limit_o (store_rx_limit),
|
|
.store_rx_valid_o (store_rx_valid),
|
|
.store_rx_ready_i (store_rx_ready),
|
|
.store_rx_data_o (store_rx_data),
|
|
.store_rx_commit_o (store_rx_commit),
|
|
.store_rx_cancel_o (store_rx_cancel),
|
|
.store_rx_done_i (store_rx_done),
|
|
.store_rx_bytes_i (store_rx_bytes),
|
|
.store_rx_overflow_i (store_rx_overflow),
|
|
.store_tx_start_valid_o(store_tx_start_valid),
|
|
.store_tx_start_ready_i(store_tx_start_ready),
|
|
.store_tx_base_o (store_tx_base),
|
|
.store_tx_bytes_o (store_tx_bytes),
|
|
.store_tx_valid_i (store_tx_valid),
|
|
.store_tx_ready_o (store_tx_ready),
|
|
.store_tx_data_i (store_tx_data),
|
|
.store_tx_done_i (store_tx_done),
|
|
.busy_o (busy_o),
|
|
.retry_o (retry_o),
|
|
.protocol_error_o (protocol_error_o)
|
|
);
|
|
|
|
usb2_packet_store u_store (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.fill_start_valid_i (fill_start_valid_i),
|
|
.fill_start_ready_o (fill_start_ready_o),
|
|
.fill_base_i (12'd4),
|
|
.fill_bytes_i (15'd5),
|
|
.fill_valid_i (fill_valid_i),
|
|
.fill_ready_o (fill_ready_o),
|
|
.fill_data_i (fill_data_i),
|
|
.fill_strb_i (fill_strb_i),
|
|
.fill_last_i (fill_last_i),
|
|
.fill_done_o (fill_done_o),
|
|
.fill_error_o (fill_error_o),
|
|
.drain_start_valid_i(1'b0),
|
|
.drain_start_ready_o(),
|
|
.drain_base_i ('0),
|
|
.drain_bytes_i ('0),
|
|
.drain_valid_o (),
|
|
.drain_ready_i (1'b0),
|
|
.drain_data_o (),
|
|
.drain_strb_o (),
|
|
.drain_last_o (),
|
|
.drain_done_o (),
|
|
.rx_start_valid_i (store_rx_start_valid),
|
|
.rx_start_ready_o (store_rx_start_ready),
|
|
.rx_base_i (store_rx_base),
|
|
.rx_limit_i (store_rx_limit),
|
|
.rx_valid_i (store_rx_valid),
|
|
.rx_ready_o (store_rx_ready),
|
|
.rx_data_i (store_rx_data),
|
|
.rx_commit_i (store_rx_commit),
|
|
.rx_cancel_i (store_rx_cancel),
|
|
.rx_done_o (store_rx_done),
|
|
.rx_bytes_o (store_rx_bytes),
|
|
.rx_overflow_o (store_rx_overflow),
|
|
.tx_start_valid_i (store_tx_start_valid),
|
|
.tx_start_ready_o (store_tx_start_ready),
|
|
.tx_base_i (store_tx_base),
|
|
.tx_bytes_i (store_tx_bytes),
|
|
.tx_valid_o (store_tx_valid),
|
|
.tx_ready_i (store_tx_ready),
|
|
.tx_data_o (store_tx_data),
|
|
.tx_done_o (store_tx_done),
|
|
.busy_o (),
|
|
.ecc_corrected_o (),
|
|
.ecc_uncorrectable_o()
|
|
);
|
|
|
|
initial begin
|
|
repeat (4) @(posedge clk_i);
|
|
rst_n_i = 1'b1;
|
|
@(negedge clk_i);
|
|
fill_start_valid_i = 1'b1;
|
|
@(negedge clk_i);
|
|
fill_start_valid_i = 1'b0;
|
|
@(negedge clk_i);
|
|
fill_data_i = 32'h4433_2211;
|
|
fill_strb_i = 4'hF;
|
|
fill_last_i = 1'b0;
|
|
fill_valid_i = 1'b1;
|
|
@(negedge clk_i);
|
|
fill_data_i = 32'h0000_0055;
|
|
fill_strb_i = 4'h1;
|
|
fill_last_i = 1'b1;
|
|
@(negedge clk_i);
|
|
fill_valid_i = 1'b0;
|
|
wait (fill_done_o);
|
|
if (fill_error_o) $fatal(1, "protocol test prefill failed");
|
|
|
|
work_data_i = '0;
|
|
work_data_i[usb2_pkg::USB2_WORK_ROLE_LSB+:2] = usb2_pkg::Usb2RoleHost;
|
|
work_data_i[usb2_pkg::USB2_WORK_INDEX_LSB+:4] = 4'd3;
|
|
work_data_i[usb2_pkg::USB2_WORK_DIRECTION_IN] = 1'b0;
|
|
work_data_i[usb2_pkg::USB2_WORK_TYPE_LSB+:2] = usb2_pkg::Usb2TransferBulk;
|
|
work_data_i[usb2_pkg::USB2_WORK_ADDRESS_LSB+:7] = 7'd5;
|
|
work_data_i[usb2_pkg::USB2_WORK_ENDPOINT_LSB+:4] = 4'd2;
|
|
work_data_i[usb2_pkg::USB2_WORK_RAM_BASE_LSB+:12] = 12'd4;
|
|
work_data_i[usb2_pkg::USB2_WORK_LENGTH_LSB+:15] = 15'd5;
|
|
@(negedge clk_i);
|
|
work_valid_i = 1'b1;
|
|
@(negedge clk_i);
|
|
work_valid_i = 1'b0;
|
|
wait (result_valid_o);
|
|
if ((result_data_o[usb2_pkg::USB2_RESULT_CODE_LSB+:4] != usb2_pkg::Usb2ResultSuccess) ||
|
|
(result_data_o[usb2_pkg::USB2_RESULT_INDEX_LSB+:4] != 4'd3) || (pid_count != 2) ||
|
|
(observed_pid[0] != usb2_pkg::Usb2PidOut) ||
|
|
(observed_pid[1] != usb2_pkg::Usb2PidData0) || retry_o || protocol_error_o) begin
|
|
$fatal(1, "host OUT transaction failed result=%h pids=%h,%h", result_data_o, observed_pid[0],
|
|
observed_pid[1]);
|
|
end
|
|
wait (work_ready_o);
|
|
work_data_i[usb2_pkg::USB2_WORK_INDEX_LSB+:4] = 4'd4;
|
|
work_data_i[usb2_pkg::USB2_WORK_TYPE_LSB+:2] = usb2_pkg::Usb2TransferIsochronous;
|
|
@(negedge clk_i);
|
|
work_valid_i = 1'b1;
|
|
@(negedge clk_i);
|
|
work_valid_i = 1'b0;
|
|
wait (result_valid_o);
|
|
if ((result_data_o[usb2_pkg::USB2_RESULT_CODE_LSB+:4] != usb2_pkg::Usb2ResultSuccess) ||
|
|
(result_data_o[usb2_pkg::USB2_RESULT_INDEX_LSB+:4] != 4'd4) || (pid_count != 4) ||
|
|
(observed_pid[2] != usb2_pkg::Usb2PidOut) ||
|
|
(observed_pid[3] != usb2_pkg::Usb2PidData0) || retry_o || protocol_error_o) begin
|
|
$fatal(1, "host ISO OUT transaction waited for a handshake result=%h", result_data_o);
|
|
end
|
|
$display("USB2 transaction engine host OUT passed");
|
|
$finish;
|
|
end
|
|
endmodule
|