diff --git a/applications/rdma_demo/libraries/eth_tester_200g/hdllib.cfg b/applications/rdma_demo/libraries/eth_tester_200g/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..fe2717bbb8790ed0e4ee240566958d0b2d636693 --- /dev/null +++ b/applications/rdma_demo/libraries/eth_tester_200g/hdllib.cfg @@ -0,0 +1,20 @@ +hdl_lib_name = eth_tester_200g +hdl_library_clause_name = eth_tester_200g_lib +hdl_lib_uses_synth = common dp eth +hdl_lib_uses_sim = diag technology tech_tse +hdl_lib_technology = + +synth_files = + src/vhdl/eth_tester_200g_pkg.vhd + src/vhdl/eth_tester_200g.vhd + +test_bench_files = + tb/vhdl/tb_eth_tester_200g.vhd + +regression_test_vhdl = + + +[modelsim_project_file] + +[quartus_project_file] + diff --git a/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g.vhd b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9c83af4c58457be7465f5226897c41d57e9a33a0 --- /dev/null +++ b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g.vhd @@ -0,0 +1,379 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Provide AXI-4-stream interfaces + standard avalon MM interfaces for +-- eth_tester.vhd such that it can be used to create a Vivado IP block. +-- Description: +-- . The rdma_generator_eth_tester_wrapper uses axi4_stream_dp_bridge to convert the dp +-- sosi/siso interfaces of the eth_tester into AXI4-Stream interfaces. +-- . In order for this component to be suitable as a Vivado IP, the ports are +-- exclusively STD_LOGIC(_VECTOR) where the widths are hard-coded as demanded +-- by the Vivado IP creator (only supports VHDL-93). +-- Remark +-- . Avalon is used for all MM interfaces, which can be bridged to AXI4-Lite in +-- vivado using the AXI AMM Bridge IP. + +library IEEE, common_lib, dp_lib, axi4_lib, eth_lib; +use IEEE.std_logic_1164.all; +use common_lib.common_pkg.all; +use common_lib.common_mem_pkg.all; +use common_lib.common_network_layers_pkg.all; +use dp_lib.dp_stream_pkg.all; +use dp_lib.dp_components_pkg.all; +use axi4_lib.axi4_stream_pkg.all; +use eth_lib.eth_pkg.all; +use eth_lib.eth_tester_pkg.all; +use work.rdma_generator_pkg.all; + +entity rdma_generator_eth_tester_wrapper is + port ( + -- Clocks and reset + mm_clk : in std_logic; + st_clk : in std_logic; + st_pps : in std_logic; + aresetn : in std_logic; + -- UDP transmit interface + eth_src_mac : in std_logic_vector(6 * 8 - 1 downto 0); + ip_src_addr : in std_logic_vector(4 * 8 - 1 downto 0); + udp_src_port : in std_logic_vector(2 * 8 - 1 downto 0); + + tx_fifo_rd_emp_arr : out std_logic_vector(0 downto 0); + + -- tx_udp + -- Source In and Sink Out + tx_udp_tready : in std_logic; + + -- Source Out and Sink In + tx_udp_tvalid : out std_logic; + tx_udp_tdata : out std_logic_vector(512 - 1 downto 0); + tx_udp_tstrb : out std_logic_vector(512 / 8 - 1 downto 0); + tx_udp_tkeep : out std_logic_vector(512 / 8 - 1 downto 0); + tx_udp_tlast : out std_logic; + tx_udp_tid : out std_logic_vector(4 - 1 downto 0); + tx_udp_tdest : out std_logic_vector(32 - 1 downto 0); + tx_udp_tuser : out std_logic_vector(70 - 1 downto 0); + + -- rx_udp + -- Source In and Sink Out + rx_udp_tready : out std_logic; + + -- Source Out and Sink In + rx_udp_tvalid : in std_logic; + rx_udp_tdata : in std_logic_vector(512 - 1 downto 0); + rx_udp_tstrb : in std_logic_vector(512 / 8 - 1 downto 0); + rx_udp_tkeep : in std_logic_vector(512 / 8 - 1 downto 0); + rx_udp_tlast : in std_logic; + rx_udp_tid : in std_logic_vector(4 - 1 downto 0); + rx_udp_tdest : in std_logic_vector(32 - 1 downto 0); + rx_udp_tuser : in std_logic_vector(70 - 1 downto 0); + + -- reg_bg_ctrl + reg_bg_ctrl_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_bg_ctrl_avs_read : in std_logic; + reg_bg_ctrl_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_bg_ctrl_avs_readdatavalid : out std_logic; + reg_bg_ctrl_avs_waitrequest : out std_logic; + reg_bg_ctrl_avs_write : in std_logic; + reg_bg_ctrl_avs_writedata : in std_logic_vector(32 - 1 downto 0); + + -- reg_hdr_dat + reg_hdr_dat_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_hdr_dat_avs_read : in std_logic; + reg_hdr_dat_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_hdr_dat_avs_readdatavalid : out std_logic; + reg_hdr_dat_avs_waitrequest : out std_logic; + reg_hdr_dat_avs_write : in std_logic; + reg_hdr_dat_avs_writedata : in std_logic_vector(32 - 1 downto 0); + + -- reg_bsn_monitor_v2_tx + reg_bsn_monitor_v2_tx_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_bsn_monitor_v2_tx_avs_read : in std_logic; + reg_bsn_monitor_v2_tx_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_bsn_monitor_v2_tx_avs_readdatavalid : out std_logic; + reg_bsn_monitor_v2_tx_avs_waitrequest : out std_logic; + reg_bsn_monitor_v2_tx_avs_write : in std_logic; + reg_bsn_monitor_v2_tx_avs_writedata : in std_logic_vector(32 - 1 downto 0); + + -- reg_strobe_total_count_tx + reg_strobe_total_count_tx_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_strobe_total_count_tx_avs_read : in std_logic; + reg_strobe_total_count_tx_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_strobe_total_count_tx_avs_readdatavalid : out std_logic; + reg_strobe_total_count_tx_avs_waitrequest : out std_logic; + reg_strobe_total_count_tx_avs_write : in std_logic; + reg_strobe_total_count_tx_avs_writedata : in std_logic_vector(32 - 1 downto 0); + + -- reg_dp_split + reg_dp_split_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_dp_split_avs_read : in std_logic; + reg_dp_split_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_dp_split_avs_readdatavalid : out std_logic; + reg_dp_split_avs_waitrequest : out std_logic; + reg_dp_split_avs_write : in std_logic; + reg_dp_split_avs_writedata : in std_logic_vector(32 - 1 downto 0); + + -- reg_bsn_monitor_v2_rx + reg_bsn_monitor_v2_rx_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_bsn_monitor_v2_rx_avs_read : in std_logic; + reg_bsn_monitor_v2_rx_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_bsn_monitor_v2_rx_avs_readdatavalid : out std_logic; + reg_bsn_monitor_v2_rx_avs_waitrequest : out std_logic; + reg_bsn_monitor_v2_rx_avs_write : in std_logic; + reg_bsn_monitor_v2_rx_avs_writedata : in std_logic_vector(32 - 1 downto 0); + + -- reg_strobe_total_count_rx + reg_strobe_total_count_rx_avs_address : in std_logic_vector(32 - 1 downto 0); + reg_strobe_total_count_rx_avs_read : in std_logic; + reg_strobe_total_count_rx_avs_readdata : out std_logic_vector(32 - 1 downto 0); + reg_strobe_total_count_rx_avs_readdatavalid : out std_logic; + reg_strobe_total_count_rx_avs_waitrequest : out std_logic; + reg_strobe_total_count_rx_avs_write : in std_logic; + reg_strobe_total_count_rx_avs_writedata : in std_logic_vector(32 - 1 downto 0) + + ); +end rdma_generator_eth_tester_wrapper; + +architecture str of rdma_generator_eth_tester_wrapper is + constant c_nof_byte : natural := c_rdma_generator_nof_octet_output_100gbe; + + signal rx_udp_sosi_arr : t_dp_sosi_arr(0 downto 0) := (others => c_dp_sosi_rst); + signal rx_udp_siso_arr : t_dp_siso_arr(0 downto 0) := (others => c_dp_siso_rdy); + signal tx_udp_sosi_arr : t_dp_sosi_arr(0 downto 0) := (others => c_dp_sosi_rst); + signal tx_udp_siso_arr : t_dp_siso_arr(0 downto 0) := (others => c_dp_siso_rdy); + + signal rx_udp_axi4_sosi : t_axi4_sosi := c_axi4_sosi_rst; + signal rx_udp_axi4_siso : t_axi4_siso := c_axi4_siso_rst; + signal tx_udp_axi4_sosi : t_axi4_sosi := c_axi4_sosi_rst; + signal tx_udp_axi4_siso : t_axi4_siso := c_axi4_siso_rst; + + signal reg_bg_ctrl_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bg_ctrl_cipo : t_mem_cipo; + signal reg_hdr_dat_copi : t_mem_copi := c_mem_copi_rst; + signal reg_hdr_dat_cipo : t_mem_cipo; + signal reg_bsn_monitor_v2_tx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_monitor_v2_tx_cipo : t_mem_cipo; + signal reg_strobe_total_count_tx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_strobe_total_count_tx_cipo : t_mem_cipo; + signal reg_dp_split_copi : t_mem_copi := c_mem_copi_rst; + signal reg_dp_split_cipo : t_mem_cipo; + + signal reg_bsn_monitor_v2_rx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_monitor_v2_rx_cipo : t_mem_cipo; + signal reg_strobe_total_count_rx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_strobe_total_count_rx_cipo : t_mem_cipo; + + signal mm_rst : std_logic := '0'; + signal st_rst : std_logic := '0'; +begin + u_eth_tester : entity eth_lib.eth_tester + generic map ( + g_nof_octet_generate => c_rdma_generator_nof_octet_generate_100gbe, + g_nof_octet_output => c_rdma_generator_nof_octet_output_100gbe, + g_use_eth_header => false, + g_use_ip_udp_header => false, + g_use_dp_header => true, + g_hdr_field_arr => c_rdma_generator_dp_hdr_field_arr, + g_hdr_field_sel => c_rdma_generator_dp_hdr_field_sel, + g_remove_crc => false + ) + port map ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + st_pps => st_pps, + + -- UDP transmit interface + eth_src_mac => eth_src_mac, + ip_src_addr => ip_src_addr, + udp_src_port => udp_src_port, + + tx_fifo_rd_emp_arr => tx_fifo_rd_emp_arr, + + tx_udp_sosi_arr => tx_udp_sosi_arr, + tx_udp_siso_arr => tx_udp_siso_arr, + + -- UDP receive interface + rx_udp_sosi_arr => rx_udp_sosi_arr, + + -- Memory Mapped Slaves (one per stream) + reg_bg_ctrl_copi => reg_bg_ctrl_copi, + reg_bg_ctrl_cipo => reg_bg_ctrl_cipo, + reg_hdr_dat_copi => reg_hdr_dat_copi, + reg_hdr_dat_cipo => reg_hdr_dat_cipo, + reg_bsn_monitor_v2_tx_copi => reg_bsn_monitor_v2_tx_copi, + reg_bsn_monitor_v2_tx_cipo => reg_bsn_monitor_v2_tx_cipo, + reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi, + reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo, + reg_dp_split_copi => reg_dp_split_copi, + reg_dp_split_cipo => reg_dp_split_cipo, + + reg_bsn_monitor_v2_rx_copi => reg_bsn_monitor_v2_rx_copi, + reg_bsn_monitor_v2_rx_cipo => reg_bsn_monitor_v2_rx_cipo, + reg_strobe_total_count_rx_copi => reg_strobe_total_count_rx_copi, + reg_strobe_total_count_rx_cipo => reg_strobe_total_count_rx_cipo + ); + + -- DP to AXI4 + u_axi4_tx_udp : entity axi4_lib.axi4_stream_dp_bridge + generic map ( + g_axi4_rl => 0, + g_dp_rl => 1, + g_active_low_rst => true + ) + port map ( + in_clk => st_clk, + in_rst => aresetn, + + dp_rst => st_rst, + + dp_in_sosi => tx_udp_sosi_arr(0), + dp_in_siso => tx_udp_siso_arr(0), + + axi4_out_sosi => tx_udp_axi4_sosi, + axi4_out_siso => tx_udp_axi4_siso + ); + + u_axi4_rx_udp : entity axi4_lib.axi4_stream_dp_bridge + generic map ( + g_axi4_rl => 0, + g_dp_rl => 1, + g_active_low_rst => true + ) + port map ( + in_clk => st_clk, + in_rst => aresetn, + + axi4_in_sosi => rx_udp_axi4_sosi, + axi4_in_siso => rx_udp_axi4_siso, + + dp_out_sosi => rx_udp_sosi_arr(0), + dp_out_siso => rx_udp_siso_arr(0) + ); + + -- Wire Records to IN/OUT ports. + -- tx_udp + tx_udp_axi4_siso.tready <= tx_udp_tready; + + tx_udp_tvalid <= tx_udp_axi4_sosi.tvalid; + tx_udp_tstrb <= tx_udp_axi4_sosi.tstrb; + tx_udp_tlast <= tx_udp_axi4_sosi.tlast; + tx_udp_tid <= tx_udp_axi4_sosi.tid; + tx_udp_tdest <= tx_udp_axi4_sosi.tdest; + tx_udp_tuser <= tx_udp_axi4_sosi.tuser; + -- reverse order of bytes + gen_tx_data : for I in 0 to c_nof_byte - 1 generate + tx_udp_tdata( (I + 1) * c_octet_w - 1 downto I * c_octet_w) <= tx_udp_axi4_sosi.tdata((c_nof_byte - I) * c_octet_w - 1 downto (c_nof_byte - 1 - I) * c_octet_w); + tx_udp_tkeep(I) <= tx_udp_axi4_sosi.tkeep(c_nof_byte - 1 - I); + end generate; + + -- rx_udp + rx_udp_tready <= rx_udp_axi4_siso.tready; + + rx_udp_axi4_sosi.tvalid <= rx_udp_tvalid; + rx_udp_axi4_sosi.tstrb <= rx_udp_tstrb; + rx_udp_axi4_sosi.tlast <= rx_udp_tlast; + rx_udp_axi4_sosi.tid <= rx_udp_tid; + rx_udp_axi4_sosi.tdest <= rx_udp_tdest; + rx_udp_axi4_sosi.tuser <= rx_udp_tuser; + -- reverse order of bytes + gen_rx_data : for I in 0 to c_nof_byte - 1 generate + rx_udp_axi4_sosi.tdata( (I + 1) * c_octet_w - 1 downto I * c_octet_w) <= rx_udp_tdata((c_nof_byte - I) * c_octet_w - 1 downto (c_nof_byte - 1 - I) * c_octet_w); + rx_udp_axi4_sosi.tkeep(I) <= rx_udp_tkeep(c_nof_byte - 1 - I); + end generate; + + -- reg_bg_ctrl + -- copi + reg_bg_ctrl_copi.address <= reg_bg_ctrl_avs_address; + reg_bg_ctrl_copi.wrdata <= RESIZE_UVEC(reg_bg_ctrl_avs_writedata, c_mem_data_w); + reg_bg_ctrl_copi.wr <= reg_bg_ctrl_avs_write; + reg_bg_ctrl_copi.rd <= reg_bg_ctrl_avs_read; + -- cipo + reg_bg_ctrl_avs_readdata <= RESIZE_UVEC_32(reg_bg_ctrl_cipo.rddata); + reg_bg_ctrl_avs_readdatavalid <= reg_bg_ctrl_cipo.rdval; + reg_bg_ctrl_avs_waitrequest <= reg_bg_ctrl_cipo.waitrequest; + + -- reg_hdr_dat + -- copi + reg_hdr_dat_copi.address <= reg_hdr_dat_avs_address; + reg_hdr_dat_copi.wrdata <= RESIZE_UVEC(reg_hdr_dat_avs_writedata, c_mem_data_w); + reg_hdr_dat_copi.wr <= reg_hdr_dat_avs_write; + reg_hdr_dat_copi.rd <= reg_hdr_dat_avs_read; + -- cipo + reg_hdr_dat_avs_readdata <= RESIZE_UVEC_32(reg_hdr_dat_cipo.rddata); + reg_hdr_dat_avs_readdatavalid <= reg_hdr_dat_cipo.rdval; + reg_hdr_dat_avs_waitrequest <= reg_hdr_dat_cipo.waitrequest; + + -- reg_bsn_monitor_v2_tx + -- copi + reg_bsn_monitor_v2_tx_copi.address <= reg_bsn_monitor_v2_tx_avs_address; + reg_bsn_monitor_v2_tx_copi.wrdata <= RESIZE_UVEC(reg_bsn_monitor_v2_tx_avs_writedata, c_mem_data_w); + reg_bsn_monitor_v2_tx_copi.wr <= reg_bsn_monitor_v2_tx_avs_write; + reg_bsn_monitor_v2_tx_copi.rd <= reg_bsn_monitor_v2_tx_avs_read; + -- cipo + reg_bsn_monitor_v2_tx_avs_readdata <= RESIZE_UVEC_32(reg_bsn_monitor_v2_tx_cipo.rddata); + reg_bsn_monitor_v2_tx_avs_readdatavalid <= reg_bsn_monitor_v2_tx_cipo.rdval; + reg_bsn_monitor_v2_tx_avs_waitrequest <= reg_bsn_monitor_v2_tx_cipo.waitrequest; + + -- reg_strobe_total_count_tx + -- copi + reg_strobe_total_count_tx_copi.address <= reg_strobe_total_count_tx_avs_address; + reg_strobe_total_count_tx_copi.wrdata <= RESIZE_UVEC(reg_strobe_total_count_tx_avs_writedata, c_mem_data_w); + reg_strobe_total_count_tx_copi.wr <= reg_strobe_total_count_tx_avs_write; + reg_strobe_total_count_tx_copi.rd <= reg_strobe_total_count_tx_avs_read; + -- cipo + reg_strobe_total_count_tx_avs_readdata <= RESIZE_UVEC_32(reg_strobe_total_count_tx_cipo.rddata); + reg_strobe_total_count_tx_avs_readdatavalid <= reg_strobe_total_count_tx_cipo.rdval; + reg_strobe_total_count_tx_avs_waitrequest <= reg_strobe_total_count_tx_cipo.waitrequest; + + -- reg_dp_split + -- copi + reg_dp_split_copi.address <= reg_dp_split_avs_address; + reg_dp_split_copi.wrdata <= RESIZE_UVEC(reg_dp_split_avs_writedata, c_mem_data_w); + reg_dp_split_copi.wr <= reg_dp_split_avs_write; + reg_dp_split_copi.rd <= reg_dp_split_avs_read; + -- cipo + reg_dp_split_avs_readdata <= RESIZE_UVEC_32(reg_dp_split_cipo.rddata); + reg_dp_split_avs_readdatavalid <= reg_dp_split_cipo.rdval; + reg_dp_split_avs_waitrequest <= reg_dp_split_cipo.waitrequest; + + -- reg_bsn_monitor_v2_rx + -- copi + reg_bsn_monitor_v2_rx_copi.address <= reg_bsn_monitor_v2_rx_avs_address; + reg_bsn_monitor_v2_rx_copi.wrdata <= RESIZE_UVEC(reg_bsn_monitor_v2_rx_avs_writedata, c_mem_data_w); + reg_bsn_monitor_v2_rx_copi.wr <= reg_bsn_monitor_v2_rx_avs_write; + reg_bsn_monitor_v2_rx_copi.rd <= reg_bsn_monitor_v2_rx_avs_read; + -- cipo + reg_bsn_monitor_v2_rx_avs_readdata <= RESIZE_UVEC_32(reg_bsn_monitor_v2_rx_cipo.rddata); + reg_bsn_monitor_v2_rx_avs_readdatavalid <= reg_bsn_monitor_v2_rx_cipo.rdval; + reg_bsn_monitor_v2_rx_avs_waitrequest <= reg_bsn_monitor_v2_rx_cipo.waitrequest; + + -- reg_strobe_total_count_rx + -- copi + reg_strobe_total_count_rx_copi.address <= reg_strobe_total_count_rx_avs_address; + reg_strobe_total_count_rx_copi.wrdata <= RESIZE_UVEC(reg_strobe_total_count_rx_avs_writedata, c_mem_data_w); + reg_strobe_total_count_rx_copi.wr <= reg_strobe_total_count_rx_avs_write; + reg_strobe_total_count_rx_copi.rd <= reg_strobe_total_count_rx_avs_read; + -- cipo + reg_strobe_total_count_rx_avs_readdata <= RESIZE_UVEC_32(reg_strobe_total_count_rx_cipo.rddata); + reg_strobe_total_count_rx_avs_readdatavalid <= reg_strobe_total_count_rx_cipo.rdval; + reg_strobe_total_count_rx_avs_waitrequest <= reg_strobe_total_count_rx_cipo.waitrequest; +end str; diff --git a/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g_pkg.vhd b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..bdc161635035a5ff5f76920b983c9c15c2505db1 --- /dev/null +++ b/applications/rdma_demo/libraries/eth_tester_200g/src/vhdl/eth_tester_200g_pkg.vhd @@ -0,0 +1,120 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- +-- +-- Author: R. vd Walle +-- Purpose: This package contains rdma_generator specific constants and/or functions +-- Description: +-- +library IEEE, common_lib; +use IEEE.std_logic_1164.all; +use common_lib.common_pkg.all; +use common_lib.common_mem_pkg.all; +use common_lib.common_field_pkg.all; +use common_lib.common_network_layers_pkg.all; + +package eth_tester_200g_pkg is + constant c_rdma_generator_nof_octet_generate_100gbe : natural := 64; + constant c_rdma_generator_nof_octet_output_100gbe : natural := 64; + + -- hdr_field_sel bit selects where the hdr_field value is set: + -- . 0 = data path controlled, value is set in data path, so field_default() + -- is not used. + -- . 1 = MM controlled, value is set via MM or by the field_default(), so any + -- data path setting in eth_tester.vhd is not used. + -- Remarks: + -- . For constant values it is convenient to use MM controlled, because then + -- the field_default() is used that can be set here in + -- c_rdma_generator_hdr_field_arr. + -- . For reserved values it is convenient to use MM controlled, because then + -- in future they could still be changed via MM without having to recompile + -- the FW. + -- . Typically only use data path controlled if the value has to be set + -- dynamically, so dependent on the state of the FW. + -- . If a data path controlled field is not set in the FW, then it defaults + -- to 0 by declaring hdr_fields_in_arr with all 0. Hence e.g. udp_checksum + -- = 0 can be achieve via data path and default hdr_fields_in_arr = 0 or + -- via MM controlled and field_default(0). + constant c_rdma_generator_dp_nof_hdr_fields : natural := 4; + constant c_rdma_generator_dp_hdr_field_sel : std_logic_vector(c_rdma_generator_dp_nof_hdr_fields - 1 downto 0) := "0100"; + + constant c_rdma_generator_dp_hdr_field_arr : t_common_field_arr(c_rdma_generator_dp_nof_hdr_fields - 1 downto 0) := ( + ( field_name_pad("dp_length" ), "RW", 16, field_default(0) ), + ( field_name_pad("dp_reserved"), "RW", 15, field_default(0) ), + ( field_name_pad("dp_sync" ), "RW", 1, field_default(0) ), + ( field_name_pad("dp_bsn" ), "RW", 64, field_default(0) ) + ); + constant c_rdma_generator_dp_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_generator_dp_hdr_field_arr, c_word_w)); + constant c_rdma_generator_dp_reg_hdr_dat_addr_span : natural := 2**c_rdma_generator_dp_reg_hdr_dat_addr_w; + + constant c_rdma_generator_dp_app_hdr_len : natural := 12; -- octets + + -- RoCEv2 header for RDMA write operation (excluding ETH, IP, UDP) + -- Base Transport Header (BTH) + RDMA Extended Transport Header (RETH) + Immediate Data + constant c_rdma_generator_roce_nof_hdr_fields : natural := 12 + 4 + 13 + 3 + 1; + constant c_rdma_generator_roce_hdr_field_sel : std_logic_vector(c_rdma_generator_roce_nof_hdr_fields - 1 downto 0) := "111011111001" & "0100" & "1111111111111" & "111" & "1"; + + constant c_rdma_generator_roce_hdr_field_arr : t_common_field_arr(c_rdma_generator_roce_nof_hdr_fields - 1 downto 0) := ( + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- depends on BG block size, so set by data path + ( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + ( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), + ( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- c_eth_tester_ip_dst_addr + + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- c_eth_tester_udp_dst_port + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- depends on BG block size, so set by data path + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + + ( field_name_pad("bth_opcode" ), "RW", 8, field_default(0) ), + ( field_name_pad("bth_se" ), "RW", 1, field_default(0) ), + ( field_name_pad("bth_m" ), "RW", 1, field_default(0) ), + ( field_name_pad("bth_pad" ), "RW", 2, field_default(0) ), + ( field_name_pad("bth_tver" ), "RW", 4, field_default(0) ), + ( field_name_pad("bth_partition_key" ), "RW", 16, field_default(0) ), + ( field_name_pad("bth_fres" ), "RW", 1, field_default(0) ), + ( field_name_pad("bth_bres" ), "RW", 1, field_default(0) ), + ( field_name_pad("bth_reserved_a" ), "RW", 6, field_default(0) ), + ( field_name_pad("bth_dest_qp" ), "RW", 16, field_default(0) ), + ( field_name_pad("bth_ack_req" ), "RW", 1, field_default(0) ), + ( field_name_pad("bth_reserved_b" ), "RW", 7, field_default(0) ), + ( field_name_pad("bth_psn" ), "RW", 32, field_default(0) ), + + ( field_name_pad("reth_virtual_address"), "RW", 64, field_default(0) ), + ( field_name_pad("reth_r_key" ), "RW", 32, field_default(0) ), + ( field_name_pad("reth_dma_length" ), "RW", 32, field_default(0) ), + + ( field_name_pad("immediate_data" ), "RW", 32, field_default(0) ) + ); + constant c_rdma_generator_roce_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_generator_roce_hdr_field_arr, c_word_w)); + constant c_rdma_generator_roce_reg_hdr_dat_addr_span : natural := 2**c_rdma_generator_roce_reg_hdr_dat_addr_w; + + constant c_rdma_generator_roce_hdr_len : natural := 32; -- octets + constant c_rdma_generator_roce_icrc_len : natural := 4; -- octets +end eth_tester_200g_pkg; + +package body eth_tester_200g_pkg is +end eth_tester_200g_pkg; diff --git a/applications/rdma_demo/libraries/eth_tester_200g/tb/vhdl/tb_eth_tester_200g.vhd b/applications/rdma_demo/libraries/eth_tester_200g/tb/vhdl/tb_eth_tester_200g.vhd new file mode 100644 index 0000000000000000000000000000000000000000..eae40bfd2f37ef56750f74de571b0c95608e60f3 --- /dev/null +++ b/applications/rdma_demo/libraries/eth_tester_200g/tb/vhdl/tb_eth_tester_200g.vhd @@ -0,0 +1,524 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- +-- Author: R. vd Walle +-- Purpose: Test bench for rdma_generator_roce_tester using high bandwidth generic +-- configuration, e.g. g_nof_octet_output = 64 and g_nof_octet_generate = 64. +-- Description: Similar to the 1GbE testbench [1] for the eth tester but using generic +-- values for usage with high bandwidth, e.g. 10 / 100 GbE. +-- The g_nof_streams >= 1 are tested independently, using g_bg_ctrl_first for +-- BG in stream 0 and g_bg_ctrl_others for all other streams. +-- +-- Usage: +-- > as 8 +-- # * E.g. view sosi/data signals in dut/gen_streams/u_rx and u_tx +-- > run -a +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + +library IEEE, common_lib, dp_lib, diag_lib, technology_lib, tech_tse_lib, eth_lib; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use common_lib.common_pkg.all; +use common_lib.common_mem_pkg.all; +use common_lib.common_str_pkg.all; +use common_lib.tb_common_pkg.all; +use common_lib.tb_common_mem_pkg.all; +use common_lib.common_network_layers_pkg.all; +use dp_lib.dp_stream_pkg.all; +use dp_lib.dp_components_pkg.all; +use diag_lib.diag_pkg.all; +use eth_lib.eth_pkg.all; +use eth_lib.eth_tester_pkg.all; +use eth_lib.tb_eth_tester_pkg.all; +use technology_lib.technology_select_pkg.all; +use tech_tse_lib.tech_tse_pkg.all; +use tech_tse_lib.tb_tech_tse_pkg.all; + +entity tb_rdma_generator is + generic ( + g_tb_index : natural := 0; -- use to incremental delay logging from tb instances in tb_tb + g_nof_sync : natural := 2; -- number of BG sync intervals to set c_run_time + g_nof_streams : natural := 1; + g_nof_octet_output : natural := 64; -- maximum = 96 bytes as max dp.data field = 768 bits. + g_nof_octet_generate : natural := 64; + + -- t_diag_block_gen_integer = + -- sl: enable + -- sl: enable_sync + -- nat: samples_per_packet + -- nat: blocks_per_sync + -- nat: gapsize + -- nat: mem_low_adrs + -- nat: mem_high_adrs + -- nat: bsn_init + + -- for first stream + g_bg_ctrl_first : t_diag_block_gen_integer := ('1', '1', 500, 3, 200, 0, c_diag_bg_mem_max_adr, 0); + -- for other streams + g_bg_ctrl_others : t_diag_block_gen_integer := ('1', '1', 300, 3, 10, 0, c_diag_bg_mem_max_adr, 0) + ); + port ( + tb_end : out std_logic + ); +end tb_rdma_generator; + +architecture tb of tb_rdma_generator is + -- use to distinguish logging from tb instances in tb_tb + constant c_tb_str : string := "tb-" & natural'image(g_tb_index) & " : "; + + constant mm_clk_period : time := 10 ns; -- 100 MHz + constant c_nof_st_clk_per_s : natural := 200 * 10**6; + constant st_clk_period : time := (10**9 / c_nof_st_clk_per_s) * 1 ns; -- 5 ns, 200 MHz + + constant c_bg_block_len_first : natural := ceil_div(g_bg_ctrl_first.samples_per_packet, g_nof_octet_generate); + constant c_bg_block_len_others : natural := ceil_div(g_bg_ctrl_others.samples_per_packet, g_nof_octet_generate); + constant c_bg_block_len_max : natural := largest(c_bg_block_len_first, c_bg_block_len_others); + + constant c_bg_slot_len_first : natural := c_bg_block_len_first + g_bg_ctrl_first.gapsize; + constant c_bg_slot_len_others : natural := c_bg_block_len_others + g_bg_ctrl_others.gapsize; + constant c_bg_slot_len_max : natural := largest(c_bg_slot_len_first, c_bg_slot_len_others); + + constant c_eth_packet_len_first : natural := func_eth_tester_eth_packet_length(c_bg_block_len_first); + constant c_eth_packet_len_others : natural := func_eth_tester_eth_packet_length(c_bg_block_len_others); + + -- Use REAL to avoid NATURAL overflow in bps calculation + + constant c_bg_nof_bps_first : real := real(c_bg_block_len_first * c_octet_w) * real(c_nof_st_clk_per_s) / real(c_bg_slot_len_first); + constant c_bg_nof_bps_others : real := real(c_bg_block_len_others * c_octet_w) * real(c_nof_st_clk_per_s) / real(c_bg_slot_len_others); + constant c_bg_nof_bps_total : real := c_bg_nof_bps_first + real(g_nof_streams - 1) * c_bg_nof_bps_others; + + constant c_bg_sync_period_first : natural := c_bg_slot_len_first * g_bg_ctrl_first.blocks_per_sync; + constant c_bg_sync_period_others : natural := c_bg_slot_len_others * g_bg_ctrl_others.blocks_per_sync; + constant c_bg_sync_period_max : natural := largest(c_bg_sync_period_first, c_bg_sync_period_others); + + constant c_run_time : natural := g_nof_sync * c_bg_sync_period_max; + constant c_nof_sync_first : natural := c_run_time / c_bg_sync_period_first; + constant c_nof_sync_others : natural := c_run_time / c_bg_sync_period_others; + + -- Expected Tx --> Rx latency values obtained from a tb run + constant c_tx_exp_latency : natural := 0; + constant c_rx_exp_latency_en : boolean := c_bg_block_len_max >= 50; + constant c_rx_exp_latency_st : natural := 19; + + -- CRC is added by Tx TSE IP and removed by dp_offload_rx when g_remove_crc = + -- g_loopback_eth = TRUE. Therefore internally only application payload + -- (= block_len) octets are counted. + constant c_nof_valid_per_packet_first : natural := c_bg_block_len_first; + constant c_nof_valid_per_packet_others : natural := c_bg_block_len_others; + + constant c_total_count_nof_valid_per_sync_first : natural := g_bg_ctrl_first.blocks_per_sync * c_nof_valid_per_packet_first; + constant c_total_count_nof_valid_per_sync_others : natural := g_bg_ctrl_others.blocks_per_sync * c_nof_valid_per_packet_others; + + constant c_mon_nof_sop_first : natural := g_bg_ctrl_first.blocks_per_sync; + constant c_mon_nof_sop_others : natural := g_bg_ctrl_others.blocks_per_sync; + constant c_mon_nof_valid_first_tx : natural := c_mon_nof_sop_first * ceil_div(c_bg_block_len_first * g_nof_octet_generate, g_nof_octet_output); + constant c_mon_nof_valid_first_rx : natural := c_mon_nof_sop_first * c_nof_valid_per_packet_first; + constant c_mon_nof_valid_others_tx : natural := c_mon_nof_sop_others * ceil_div(c_bg_block_len_others * g_nof_octet_generate, g_nof_octet_output); + constant c_mon_nof_valid_others_rx : natural := c_mon_nof_sop_others * c_nof_valid_per_packet_others; + + -- Use sim default src MAC, IP, UDP port from eth_tester_pkg.vhd and based on c_gn_index + constant c_gn_index : natural := 17; -- global node index + constant c_gn_eth_src_mac : std_logic_vector(c_network_eth_mac_addr_w - 1 downto 0) := c_eth_tester_eth_src_mac_47_16 & func_eth_tester_gn_index_to_mac_15_0(c_gn_index); + constant c_gn_ip_src_addr : std_logic_vector(c_network_ip_addr_w - 1 downto 0) := c_eth_tester_ip_src_addr_31_16 & func_eth_tester_gn_index_to_ip_15_0(c_gn_index); + constant c_gn_udp_src_port : std_logic_vector(c_network_udp_port_w - 1 downto 0) := c_eth_tester_udp_src_port_15_8 & TO_UVEC(c_gn_index, 8); + + -- Clocks and reset + signal mm_rst : std_logic := '1'; + signal mm_clk : std_logic := '1'; + signal st_rst : std_logic := '1'; + signal st_clk : std_logic := '1'; + signal st_pps : std_logic := '0'; + signal stimuli_end : std_logic := '0'; + signal i_tb_end : std_logic := '0'; + + -- Use same bg_ctrl for all others streams, this provides sufficient test coverage + signal bg_ctrl_arr : t_diag_block_gen_integer_arr(g_nof_streams - 1 downto 0); + + signal tx_fifo_rd_emp_arr : std_logic_vector(g_nof_streams - 1 downto 0); + + -- ETH UDP data path interface + signal tx_udp_sosi_arr : t_dp_sosi_arr(g_nof_streams - 1 downto 0); + signal tx_udp_siso_arr : t_dp_siso_arr(g_nof_streams - 1 downto 0) := (others => c_dp_siso_rdy); + signal rx_udp_sosi_arr : t_dp_sosi_arr(g_nof_streams - 1 downto 0); + + -- MM interface + -- . Tx + signal reg_bg_ctrl_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bg_ctrl_cipo : t_mem_cipo; + signal reg_hdr_dat_copi : t_mem_copi := c_mem_copi_rst; + signal reg_hdr_dat_cipo : t_mem_cipo; + signal reg_bsn_monitor_v2_tx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_monitor_v2_tx_cipo : t_mem_cipo; + signal reg_strobe_total_count_tx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_strobe_total_count_tx_cipo : t_mem_cipo; + signal reg_dp_split_copi : t_mem_copi := c_mem_copi_rst; + signal reg_dp_split_cipo : t_mem_cipo; + -- . Rx + signal reg_bsn_monitor_v2_rx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_monitor_v2_rx_cipo : t_mem_cipo; + signal reg_strobe_total_count_rx_copi : t_mem_copi := c_mem_copi_rst; + signal reg_strobe_total_count_rx_cipo : t_mem_cipo; + + -- . reg_strobe_total_count + signal tx_total_count_nof_packet_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal rx_total_count_nof_packet_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal exp_total_count_nof_packet_arr : t_natural_arr(g_nof_streams - 1 downto 0); -- same for both tx and rx + + signal rx_total_count_nof_valid_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal rx_exp_total_count_nof_valid_arr : t_natural_arr(g_nof_streams - 1 downto 0); + + signal rx_total_count_nof_corrupted_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal rx_exp_total_count_nof_corrupted_arr : t_natural_arr(g_nof_streams - 1 downto 0); + + -- . reg_bsn_monitor_v2 + signal tx_mon_nof_sop_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal tx_mon_nof_valid_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal tx_mon_latency_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal rx_mon_nof_sop_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal rx_mon_nof_valid_arr : t_natural_arr(g_nof_streams - 1 downto 0); + signal rx_mon_latency_arr : t_natural_arr(g_nof_streams - 1 downto 0); + + -- View in Wave window + signal dbg_c_run_time : natural := c_run_time; + signal dbg_c_mon_nof_sop_first : natural := c_mon_nof_sop_first; + signal dbg_c_mon_nof_sop_others : natural := c_mon_nof_sop_others; + signal dbg_c_mon_nof_valid_first_tx : natural := c_mon_nof_valid_first_tx; + signal dbg_c_mon_nof_valid_first_rx : natural := c_mon_nof_valid_first_rx; + signal dbg_c_mon_nof_valid_others_tx : natural := c_mon_nof_valid_others_tx; + signal dbg_c_mon_nof_valid_others_rx : natural := c_mon_nof_valid_others_rx; +begin + tb_end <= i_tb_end; + + mm_clk <= (not mm_clk) or i_tb_end after mm_clk_period / 2; + st_clk <= (not st_clk) or i_tb_end after st_clk_period / 2; + mm_rst <= '1', '0' after mm_clk_period * 5; + st_rst <= '1', '0' after st_clk_period * 5; + + -- Using + --SIGNAL exp_total_count_nof_packet_arr : t_natural_arr(g_nof_streams-1 DOWNTO 0); + -- (g_nof_streams-1 DOWNTO 1 => g_nof_sync * g_bg_ctrl_others.blocks_per_sync, + -- 0 => g_nof_sync * g_bg_ctrl_first.blocks_per_sync); + -- yields verror 1074, verror 1048, therefor use p_init instead, and + -- therefor use bg_ctrl_arr instead of c_bg_ctrl_arr. + p_init : process + begin + bg_ctrl_arr <= (others => g_bg_ctrl_others); + bg_ctrl_arr(0) <= g_bg_ctrl_first; + + exp_total_count_nof_packet_arr <= (others => c_nof_sync_others * g_bg_ctrl_others.blocks_per_sync); + exp_total_count_nof_packet_arr(0) <= c_nof_sync_first * g_bg_ctrl_first.blocks_per_sync; + + rx_exp_total_count_nof_valid_arr <= (others => c_nof_sync_others * c_total_count_nof_valid_per_sync_others); + rx_exp_total_count_nof_valid_arr(0) <= c_nof_sync_first * c_total_count_nof_valid_per_sync_first; + + rx_exp_total_count_nof_corrupted_arr <= (others => 0); -- default no Rx errors + wait; + end process; + + ----------------------------------------------------------------------------- + -- MM control and monitoring + ----------------------------------------------------------------------------- + p_mm : process + variable v_value : natural; + variable v_offset : natural; + variable v_udp_dst_port : natural; + begin + i_tb_end <= '0'; + + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 10); + + --------------------------------------------------------------------------- + -- Rx UDP offload port + --------------------------------------------------------------------------- + v_udp_dst_port := TO_UINT(c_eth_tester_udp_dst_port); + + for I in g_nof_streams - 1 downto 0 loop + v_offset := I * c_eth_tester_reg_hdr_dat_addr_span; + -- Set destination MAC/IP/UDP port in tx header, increment udp_dst_port per stream + -- The MM addresses follow from byte address_offset // 4 in eth.peripheral.yaml + proc_mem_mm_bus_wr(v_offset + 16#7#, v_udp_dst_port + I, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + -- use signed to fit 32 b in INTEGER + proc_mem_mm_bus_wr(v_offset + 16#10#, TO_SINT(c_eth_tester_ip_dst_addr), + mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + proc_mem_mm_bus_wr(v_offset + 16#18#, TO_SINT(c_eth_tester_eth_dst_mac(31 downto 0)), + mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + proc_mem_mm_bus_wr(v_offset + 16#19#, TO_UINT(c_eth_tester_eth_dst_mac(47 downto 32)), + mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + end loop; + + --------------------------------------------------------------------------- + -- Stimuli + --------------------------------------------------------------------------- + for I in g_nof_streams - 1 downto 0 loop + v_offset := I * c_diag_bg_reg_adr_span; + -- Set number of octets per packet for dp_split + proc_mem_mm_bus_wr(I * 2, bg_ctrl_arr(I).samples_per_packet, mm_clk, reg_dp_split_copi); + + -- Prepare the BG + proc_mem_mm_bus_wr(v_offset + 1, ceil_div(bg_ctrl_arr(I).samples_per_packet, g_nof_octet_generate), + mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 2, bg_ctrl_arr(I).blocks_per_sync, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 3, bg_ctrl_arr(I).gapsize, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 4, bg_ctrl_arr(I).mem_low_adrs, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 5, bg_ctrl_arr(I).mem_high_adrs, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(v_offset + 6, bg_ctrl_arr(I).bsn_init, mm_clk, reg_bg_ctrl_copi); -- low part + proc_mem_mm_bus_wr(v_offset + 7, 0, mm_clk, reg_bg_ctrl_copi); -- high part + -- Enable the BG at st_pps pulse. + proc_mem_mm_bus_wr(v_offset + 0, 3, mm_clk, reg_bg_ctrl_copi); + end loop; + proc_common_wait_some_cycles(mm_clk, 10); + -- Issue an st_pps pulse to start the enabled BG + proc_common_gen_pulse(st_clk, st_pps); + + -- Run test + proc_common_wait_some_cycles(st_clk, c_run_time); + + -- Disable the BG + for I in g_nof_streams - 1 downto 0 loop + v_offset := I * c_diag_bg_reg_adr_span; + -- Disable the other BG + proc_mem_mm_bus_wr(v_offset + 0, 0, mm_clk, reg_bg_ctrl_copi); + end loop; + + -- Wait until Tx FIFOs have emptied for all streams + while unsigned(tx_fifo_rd_emp_arr(g_nof_streams - 1 downto 0)) /= 2**g_nof_streams - 1 loop + proc_common_wait_some_cycles(st_clk, 1); + end loop; + proc_common_wait_some_cycles(st_clk, c_bg_sync_period_max); + stimuli_end <= '1'; + + -- Delay logging between different tb instances + proc_common_wait_some_cycles(st_clk, g_tb_index * 100); + + -- Print logging + print_str(""); -- log empty line between tb results + for I in g_nof_streams - 1 downto 0 loop + if I = 0 then + print_str(c_tb_str & + "ETH bit rate (" & natural'image(I) & ") :" & + " c_bg_nof_bps_first = " & real'image(c_bg_nof_bps_first) & " bps"); + else + print_str(c_tb_str & + "ETH bit rate (" & natural'image(I) & ") :" & + " c_bg_nof_bps_others = " & real'image(c_bg_nof_bps_others) & " bps"); + end if; + end loop; + if g_nof_streams > 1 then + print_str(c_tb_str & + "ETH bit rate total :" & + " c_bg_nof_bps_total = " & real'image(c_bg_nof_bps_total) & " bps"); + end if; + + ------------------------------------------------------------------------- + -- Verification: Total counts + ------------------------------------------------------------------------- + for I in g_nof_streams - 1 downto 0 loop + -- . read low part, ignore high part (= 0) of two word total counts + v_offset := I * c_dp_strobe_total_count_reg_adr_span; + -- Tx total nof packets + proc_mem_mm_bus_rd(v_offset + 0, mm_clk, reg_strobe_total_count_tx_cipo, reg_strobe_total_count_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_total_count_nof_packet_arr(I) <= TO_UINT(reg_strobe_total_count_tx_cipo.rddata(c_word_w - 1 downto 0)); + -- Rx total nof packets + proc_mem_mm_bus_rd(v_offset + 0, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_packet_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w - 1 downto 0)); + -- Rx total nof valids + proc_mem_mm_bus_rd(v_offset + 2, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_valid_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w - 1 downto 0)); + -- Rx total nof corrupted + proc_mem_mm_bus_rd(v_offset + 4, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_corrupted_arr(I) <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w - 1 downto 0)); + proc_common_wait_some_cycles(mm_clk, 1); + + -- Print logging + print_str(c_tb_str & + "Tx total counts monitor(" & natural'image(I) & ") :" & + " nof_packet = " & natural'image(tx_total_count_nof_packet_arr(I))); + + print_str(c_tb_str & + "Rx total counts monitor(" & natural'image(I) & ") :" & + " nof_packet = " & natural'image(rx_total_count_nof_packet_arr(I)) & + ", nof_valid = " & natural'image(rx_total_count_nof_valid_arr(I)) & + ", nof_corrupted = " & natural'image(rx_total_count_nof_corrupted_arr(I))); + + -- Verify, only log when wrong + if c_bg_nof_bps_total < 10.0**9 then + assert tx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) + report c_tb_str & + "Wrong Tx total nof packets count(" & natural'image(I) & + "), Tx count = " & natural'image(tx_total_count_nof_packet_arr(I)) & + " /= " & natural'image(exp_total_count_nof_packet_arr(I)) & + " = Expected count" + severity ERROR; + + assert rx_total_count_nof_packet_arr(I) = exp_total_count_nof_packet_arr(I) + report c_tb_str & + "Wrong Rx total nof packets count(" & natural'image(I) & + "), Rx count = " & natural'image(rx_total_count_nof_packet_arr(I)) & + " /= " & natural'image(exp_total_count_nof_packet_arr(I)) & + " = Expected count" + severity ERROR; + + assert rx_total_count_nof_valid_arr(I) = rx_exp_total_count_nof_valid_arr(I) + report c_tb_str & + "Wrong Rx total nof valids count(" & natural'image(I) & + "), Rx count = " & natural'image(rx_total_count_nof_valid_arr(I)) & + " /= " & natural'image(rx_exp_total_count_nof_valid_arr(I)) & + " = Expected count" + severity ERROR; + + assert rx_total_count_nof_corrupted_arr(I) = rx_exp_total_count_nof_corrupted_arr(I) + report c_tb_str & + "Wrong Rx total nof corrupted count(" & natural'image(I) & + "), Rx count = " & natural'image(rx_total_count_nof_corrupted_arr(I)) & + " /= " & natural'image(rx_exp_total_count_nof_corrupted_arr(I)) & + " = Expected count" + severity ERROR; + else + -- Verify that Tx total nof packets = Rx total nof packets, also when + -- BG experiences siso.xon block level flow control, to stay below + -- 1 Gbps of the 1GbE link rate. + assert tx_total_count_nof_packet_arr(I) = rx_total_count_nof_packet_arr(I) + report c_tb_str & + "Wrong Tx-Rx total nof packets count(" & natural'image(I) & + "), Tx count = " & natural'image(tx_total_count_nof_packet_arr(I)) & + " /= " & natural'image(rx_total_count_nof_packet_arr(I)) & + " = Rx count" + severity ERROR; + end if; + end loop; + + ------------------------------------------------------------------------- + -- Verification: BSN monitors (yield same values in every sync interval) + ------------------------------------------------------------------------- + for I in g_nof_streams - 1 downto 0 loop + v_offset := I * c_dp_bsn_monitor_v2_reg_adr_span; + -- 3 = nof_sop + -- 4 = nof_valid + -- 6 = latency + -- . Tx + proc_mem_mm_bus_rd(v_offset + 3, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_nof_sop_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w - 1 downto 0)); + proc_mem_mm_bus_rd(v_offset + 4, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_nof_valid_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w - 1 downto 0)); + proc_mem_mm_bus_rd(v_offset + 6, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_latency_arr(I) <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w - 1 downto 0)); + + -- Print logging + print_str(c_tb_str & + "Tx BSN monitor(" & natural'image(I) & ") :" & + " nof_sop = " & natural'image(tx_mon_nof_sop_arr(I)) & + ", nof_valid = " & natural'image(tx_mon_nof_valid_arr(I)) & + ", latency = " & natural'image(tx_mon_latency_arr(I))); + + if c_bg_nof_bps_total < 10.0**9 then + -- Verify BSN monitors only when the BG sync interval is stable, so + -- the ETH data rate < 1 Gbps and no BG block flow control. + -- Verify, only log when wrong + if I = 0 then + assert tx_mon_nof_sop_arr(I) = c_mon_nof_sop_first + report c_tb_str & "Wrong tx nof_sop for stream (" & natural'image(I) & ")" + severity ERROR; + assert tx_mon_nof_valid_arr(I) = c_mon_nof_valid_first_tx + report c_tb_str & "Wrong tx nof_valid for stream (" & natural'image(I) & ")" + severity ERROR; + else + assert tx_mon_nof_sop_arr(I) = c_mon_nof_sop_others + report c_tb_str & "Wrong tx nof_sop for stream (" & natural'image(I) & ")" + severity ERROR; + assert tx_mon_nof_valid_arr(I) = c_mon_nof_valid_others_tx + report c_tb_str & "Wrong tx nof_valid for stream (" & natural'image(I) & ")" + severity ERROR; + end if; + assert tx_mon_latency_arr(I) = c_tx_exp_latency + report c_tb_str & "Wrong tx latency for stream (" & natural'image(I) & ")" + severity ERROR; + + -- For short block lengths the Rx latency appears to become less, the + -- exact Rx latency is therefore hard to predetermine. The actual + -- latency is not critical, therefore it is sufficient to only very + -- the latency when it is more or less fixed. + if c_rx_exp_latency_en then + assert almost_equal(rx_mon_latency_arr(I), c_rx_exp_latency_st, 10) + report c_tb_str & "Wrong rx latency using st interface (" & natural'image(I) & ")" + severity ERROR; + end if; + end if; + end loop; + + ------------------------------------------------------------------------- + -- End of test + ------------------------------------------------------------------------- + proc_common_wait_some_cycles(mm_clk, 100); + i_tb_end <= '1'; + wait; + end process; + + dut : entity work.rdma_generator_roce_tester + port map ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + st_pps => st_pps, + + -- UDP transmit interface + eth_src_mac => c_gn_eth_src_mac, + ip_src_addr => c_gn_ip_src_addr, + udp_src_port => c_gn_udp_src_port, + tx_fifo_rd_emp_arr => tx_fifo_rd_emp_arr, + + tx_udp_sosi_arr => tx_udp_sosi_arr, + tx_udp_siso_arr => tx_udp_siso_arr, + + -- UDP receive interface + rx_udp_sosi_arr => rx_udp_sosi_arr, + + -- Memory Mapped Slaves (one per stream) + -- . Tx + reg_bg_ctrl_copi => reg_bg_ctrl_copi, + reg_bg_ctrl_cipo => reg_bg_ctrl_cipo, + reg_hdr_dat_copi => reg_hdr_dat_copi, + reg_hdr_dat_cipo => reg_hdr_dat_cipo, + reg_bsn_monitor_v2_tx_copi => reg_bsn_monitor_v2_tx_copi, + reg_bsn_monitor_v2_tx_cipo => reg_bsn_monitor_v2_tx_cipo, + reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi, + reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo, + reg_dp_split_copi => reg_dp_split_copi, + reg_dp_split_cipo => reg_dp_split_cipo, + -- . Rx + reg_bsn_monitor_v2_rx_copi => reg_bsn_monitor_v2_rx_copi, + reg_bsn_monitor_v2_rx_cipo => reg_bsn_monitor_v2_rx_cipo, + reg_strobe_total_count_rx_copi => reg_strobe_total_count_rx_copi, + reg_strobe_total_count_rx_cipo => reg_strobe_total_count_rx_cipo + ); + + -- Loop back at streaming sosi level + rx_udp_sosi_arr <= tx_udp_sosi_arr; +end tb;