From 5f5878fcf52a3c7cbd991e5bbf04785609366f19 Mon Sep 17 00:00:00 2001 From: Reinier van der Walle <walle@astron.nl> Date: Mon, 2 Oct 2023 16:30:12 +0200 Subject: [PATCH] initial commit of rdma_packetiser library --- .../libraries/rdma_packetiser/hdllib.cfg | 22 ++ .../vhdl/rdma_packetiser_assemble_header.vhd | 186 ++++++++++++ .../src/vhdl/rdma_packetiser_pkg.vhd | 271 ++++++++++++++++++ .../tb_rdma_packetiser_assemble_header.vhd | 199 +++++++++++++ .../tb_tb_rdma_packetiser_assemble_header.vhd | 62 ++++ 5 files changed, 740 insertions(+) create mode 100644 applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg create mode 100644 applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd create mode 100644 applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd create mode 100644 applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd create mode 100644 applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd diff --git a/applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg b/applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg new file mode 100644 index 0000000000..c449e83d95 --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg @@ -0,0 +1,22 @@ +hdl_lib_name = rdma_packetiser +hdl_library_clause_name = rdma_packetiser_lib +hdl_lib_uses_synth = common dp eth +hdl_lib_uses_sim = diag technology +hdl_lib_technology = + +synth_files = + src/vhdl/rdma_packetiser_pkg.vhd + src/vhdl/rdma_packetiser_assemble_header.vhd + +test_bench_files = + tb/vhdl/tb_rdma_packetiser_assemble_header.vhd + tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd + +regression_test_vhdl = + tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd + + +[modelsim_project_file] + +[quartus_project_file] + diff --git a/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd new file mode 100644 index 0000000000..3695122448 --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd @@ -0,0 +1,186 @@ +------------------------------------------------------------------------------- +-- +-- 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: Assembles the RDMA header at snk_in.sop +-- Description: +-- The hdr_fields_slv output is set one st_clk cycle after snk_in.sop and will +-- contain the RoCEv2 (RDMA over Converged Ethernet v2) header information for +-- the corresponding data frame. +-- Remark +-- . The incoming data frame on snk_in should consist of at least 2 clock cycles. +-- i.e. two consecutive 1 cycle frames (sop + eop on the same clock cycle) +-- without a gap inbetween is not supported. + +library IEEE, common_lib, dp_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_network_layers_pkg.all; +use common_lib.common_field_pkg.all; +use dp_lib.dp_stream_pkg.all; +use dp_lib.dp_components_pkg.all; +use eth_lib.eth_pkg.all; +use eth_lib.eth_tester_pkg.all; +use work.rdma_packetiser_pkg.all; + +entity rdma_packetiser_assemble_header is + generic ( + g_use_immediate : boolean := true; + g_use_msg_cnt_as_immediate : boolean := true + ); + port ( + -- Clocks and reset + st_clk : in std_logic; + st_rst : in std_logic; + + snk_in : in t_dp_sosi := c_dp_sosi_rst; + + hdr_fields_slv : out std_logic_vector(1023 downto 0) := (others => '0'); + + immediate_data : in std_logic_vector(c_rdma_packetiser_roce_imm_len * c_octet_w - 1 downto 0) := (others => '0'); + block_len : in std_logic_vector(c_halfword_w - 1 downto 0); -- in octets + nof_packets_in_msg : in std_logic_vector(c_word_w - 1 downto 0); + nof_msg : in std_logic_vector(c_word_w - 1 downto 0); + dma_len : in std_logic_vector(c_word_w - 1 downto 0); -- = block_len * nof_packets_in_msg + start_address : in std_logic_vector(c_longword_w - 1 downto 0) + + ); +end rdma_packetiser_assemble_header; + +architecture str of rdma_packetiser_assemble_header is + constant c_hdr_field_arr : t_common_field_arr := sel_a_b(g_use_immediate, c_rdma_packetiser_roce_hdr_field_arr, c_rdma_packetiser_roce_no_imm_hdr_field_arr); + constant c_app_hdr_length : natural := sel_a_b(g_use_immediate, c_rdma_packetiser_roce_hdr_len, c_rdma_packetiser_roce_no_imm_hdr_len); + constant c_udp_app_hdr_length : natural := c_network_udp_header_len + c_app_hdr_length; + constant c_ip_udp_app_hdr_length : natural := c_network_ip_header_len + c_udp_app_hdr_length; + + type t_state is (s_idle, s_first, s_middle, s_last); + type t_reg is record + state : t_state; + opcode : std_logic_vector(c_byte_w - 1 downto 0); + immediate_data : std_logic_vector(c_rdma_packetiser_roce_imm_len * c_octet_w - 1 downto 0); + psn : std_logic_vector(c_word_w - 1 downto 0); + virtual_address : unsigned(c_longword_w - 1 downto 0); + dma_len : unsigned(c_word_w - 1 downto 0); + p_cnt : natural; + msg_cnt : natural; + udp_total_length : natural; + ip_total_length : natural; + nof_packets_in_msg : natural; + end record; + + constant c_reg_rst : t_reg := (s_idle, (others => '1'), (others => '0'), (others => '0'), (others => '0'), (others => '0'), 0, 0, 0, 0, 0); + signal d, q : t_reg; +begin + + q <= d when rising_edge(st_clk); + + p_comb : process(st_rst, q, snk_in, nof_packets_in_msg, start_address, nof_msg, immediate_data, dma_len, block_len) + variable v : t_reg; + begin + v := q; + if snk_in.sop = '1' then -- set on sop + v.psn := resize_uvec(snk_in.bsn, c_word_w); + end if; + if v.msg_cnt = 0 then -- set on new message + v.virtual_address := unsigned(start_address); + v.dma_len := unsigned(dma_len); + v.udp_total_length := c_udp_app_hdr_length + to_uint(block_len) + c_rdma_packetiser_roce_icrc_len; + v.ip_total_length := c_ip_udp_app_hdr_length + to_uint(block_len) + c_rdma_packetiser_roce_icrc_len; + v.nof_packets_in_msg := to_uint(nof_packets_in_msg); + v.immediate_data := immediate_data; + end if; + + case q.state is + when s_idle => + if snk_in.sop = '1' and v.nof_packets_in_msg > 1 then + v.state := s_first; + v.opcode := c_rdma_packetiser_opcode_uc_write_first; + v.p_cnt := 1; + elsif snk_in.sop = '1' and v.nof_packets_in_msg = 1 then + v.state := s_last; + v.opcode := c_rdma_packetiser_opcode_uc_write_only; + if g_use_immediate then + v.opcode := c_rdma_packetiser_opcode_uc_write_only_im; + end if; + end if; + + when s_first => + if snk_in.sop = '1' and v.nof_packets_in_msg > 2 then + v.state := s_middle; + v.opcode := c_rdma_packetiser_opcode_uc_write_middle; + v.p_cnt := q.p_cnt + 1; + elsif snk_in.sop = '1' and v.nof_packets_in_msg = 2 then + v.state := s_last; + v.opcode := c_rdma_packetiser_opcode_uc_write_last; + v.p_cnt := q.p_cnt + 1; + if g_use_immediate then + v.opcode := c_rdma_packetiser_opcode_uc_write_last_im; + end if; + end if; + + when s_middle => + if snk_in.sop = '1' and q.p_cnt >= v.nof_packets_in_msg - 1 then + v.state := s_last; + v.opcode := c_rdma_packetiser_opcode_uc_write_last; + v.p_cnt := q.p_cnt + 1; + if g_use_immediate then + v.opcode := c_rdma_packetiser_opcode_uc_write_last_im; + end if; + elsif snk_in.sop = '1' then + v.p_cnt := q.p_cnt + 1; + end if; + + when s_last => + v.state := s_idle; + v.p_cnt := 0; + if q.msg_cnt >= to_uint(nof_msg) - 1 then + v.msg_cnt := 0; + else + v.msg_cnt := q.msg_cnt + 1; + v.virtual_address := q.virtual_address + q.dma_len; + end if; + + end case; + + if st_rst = '1' then + v := c_reg_rst; + end if; + + d <= v; + end process; + + hdr_fields_slv(field_hi(c_hdr_field_arr, "ip_total_length" ) downto field_lo(c_hdr_field_arr, "ip_total_length" )) <= TO_UVEC(q.ip_total_length, 16); + hdr_fields_slv(field_hi(c_hdr_field_arr, "udp_total_length" ) downto field_lo(c_hdr_field_arr, "udp_total_length" )) <= TO_UVEC(q.udp_total_length, 16); + hdr_fields_slv(field_hi(c_hdr_field_arr, "bth_opcode" ) downto field_lo(c_hdr_field_arr, "bth_opcode" )) <= q.opcode; + hdr_fields_slv(field_hi(c_hdr_field_arr, "bth_psn" ) downto field_lo(c_hdr_field_arr, "bth_psn" )) <= q.psn; + hdr_fields_slv(field_hi(c_hdr_field_arr, "reth_virtual_address") downto field_lo(c_hdr_field_arr, "reth_virtual_address")) <= std_logic_vector(q.virtual_address); + hdr_fields_slv(field_hi(c_hdr_field_arr, "reth_dma_length" ) downto field_lo(c_hdr_field_arr, "reth_dma_length" )) <= std_logic_vector(q.dma_len); + + gen_use_immediate : if g_use_immediate generate + gen_use_msg_cnt : if g_use_msg_cnt_as_immediate generate + hdr_fields_slv(field_hi(c_hdr_field_arr, "immediate_data") downto field_lo(c_hdr_field_arr, "immediate_data")) <= TO_UVEC(q.msg_cnt, 32); + end generate; + gen_use_no_msg_cnt : if not g_use_msg_cnt_as_immediate generate + hdr_fields_slv(field_hi(c_hdr_field_arr, "immediate_data") downto field_lo(c_hdr_field_arr, "immediate_data")) <= q.immediate_data; + end generate; + end generate; + +end str; diff --git a/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd new file mode 100644 index 0000000000..cea6fea409 --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd @@ -0,0 +1,271 @@ +------------------------------------------------------------------------------- +-- +-- 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 rdma_packetiser_pkg is + + type t_rdma_packetiser_bth_header is record + opcode : std_logic_vector( 7 downto 0); + se : std_logic_vector( 0 downto 0); + m : std_logic_vector( 0 downto 0); + pad : std_logic_vector( 1 downto 0); + tver : std_logic_vector( 3 downto 0); + partition_key : std_logic_vector(15 downto 0); + fres : std_logic_vector( 0 downto 0); + bres : std_logic_vector( 0 downto 0); + reserved_a : std_logic_vector( 5 downto 0); + dest_qp : std_logic_vector(15 downto 0); + ack_req : std_logic_vector( 0 downto 0); + reserved_b : std_logic_vector( 6 downto 0); + psn : std_logic_vector(31 downto 0); + end record; + + type t_rdma_packetiser_reth_header is record + virtual_address : std_logic_vector(63 downto 0); + r_key : std_logic_vector(31 downto 0); + dma_length : std_logic_vector(31 downto 0); + end record; + + type t_rdma_packetiser_roce_header is record + eth : t_network_eth_header; + ip : t_network_ip_header; + udp : t_network_udp_header; + bth : t_rdma_packetiser_bth_header; + reth : t_rdma_packetiser_reth_header; + immediate_data : std_logic_vector(31 downto 0); + end record; + + constant c_rdma_packetiser_nof_octet_generate_100gbe : natural := 64; + constant c_rdma_packetiser_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_packetiser_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). + + -- RoCEv2 header for RDMA operation with immediate data + -- ETH + IP + UDP + Base Transport Header (BTH) + RDMA Extended Transport Header (RETH) + Immediate Data + constant c_rdma_packetiser_roce_nof_hdr_fields : natural := 3 + 12 + 4 + 13 + 3 + 1; + constant c_rdma_packetiser_roce_hdr_field_sel : std_logic_vector(c_rdma_packetiser_roce_nof_hdr_fields - 1 downto 0) := "111" & "111011111001" & "0100" & "1111111111111" & "111" & "1"; + + constant c_rdma_packetiser_roce_hdr_field_arr : t_common_field_arr(c_rdma_packetiser_roce_nof_hdr_fields - 1 downto 0) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + + ( 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(x"FF") ), + ( 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(65535) ), + ( 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_packetiser_roce_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_packetiser_roce_hdr_field_arr, c_word_w)); + constant c_rdma_packetiser_roce_reg_hdr_dat_addr_span : natural := 2**c_rdma_packetiser_roce_reg_hdr_dat_addr_w; + + -- RoCEv2 header for RDMA operation without immediate data + -- ETH + IP + UDP + Base Transport Header (BTH) + RDMA Extended Transport Header (RETH) + constant c_rdma_packetiser_roce_no_imm_nof_hdr_fields : natural := 3 + 12 + 4 + 13 + 3; + constant c_rdma_packetiser_roce_no_imm_hdr_field_sel : std_logic_vector(c_rdma_packetiser_roce_no_imm_nof_hdr_fields - 1 downto 0) := "111" & "111011111001" & "0100" & "1111111111111" & "111"; + + constant c_rdma_packetiser_roce_no_imm_hdr_field_arr : t_common_field_arr(c_rdma_packetiser_roce_no_imm_nof_hdr_fields - 1 downto 0) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + + ( 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(x"FF") ), + ( 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(65535) ), + ( 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) ) + ); + constant c_rdma_packetiser_roce_reg_no_imm_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_packetiser_roce_no_imm_hdr_field_arr, c_word_w)); + constant c_rdma_packetiser_roce_reg_no_imm_hdr_dat_addr_span : natural := 2**c_rdma_packetiser_roce_reg_no_imm_hdr_dat_addr_w; + + constant c_rdma_packetiser_roce_hdr_len : natural := 32; -- octets + constant c_rdma_packetiser_roce_imm_len : natural := 4; -- octets + constant c_rdma_packetiser_roce_icrc_len : natural := 4; -- octets + constant c_rdma_packetiser_roce_no_imm_hdr_len : natural := c_rdma_packetiser_roce_hdr_len - c_rdma_packetiser_roce_imm_len; + + constant c_rdma_packetiser_opcode_uc_send_first : std_logic_vector := "001" & "00000"; + constant c_rdma_packetiser_opcode_uc_send_middle : std_logic_vector := "001" & "00001"; + constant c_rdma_packetiser_opcode_uc_send_last : std_logic_vector := "001" & "00010"; + constant c_rdma_packetiser_opcode_uc_send_last_im : std_logic_vector := "001" & "00011"; + constant c_rdma_packetiser_opcode_uc_send_only : std_logic_vector := "001" & "00100"; + constant c_rdma_packetiser_opcode_uc_send_only_im : std_logic_vector := "001" & "00101"; + constant c_rdma_packetiser_opcode_uc_write_first : std_logic_vector := "001" & "00110"; + constant c_rdma_packetiser_opcode_uc_write_middle : std_logic_vector := "001" & "00111"; + constant c_rdma_packetiser_opcode_uc_write_last : std_logic_vector := "001" & "01000"; + constant c_rdma_packetiser_opcode_uc_write_last_im : std_logic_vector := "001" & "01001"; + constant c_rdma_packetiser_opcode_uc_write_only : std_logic_vector := "001" & "01010"; + constant c_rdma_packetiser_opcode_uc_write_only_im : std_logic_vector := "001" & "01011"; + + function func_rdma_packetiser_map_header(hdr_fields_raw : std_logic_vector; use_immediate : boolean) return t_rdma_packetiser_roce_header; + +end rdma_packetiser_pkg; + +package body rdma_packetiser_pkg is + + function func_rdma_packetiser_map_header(hdr_fields_raw : std_logic_vector; use_immediate : boolean) return t_rdma_packetiser_roce_header is + variable v : t_rdma_packetiser_roce_header; + constant c_hdr_field_arr : t_common_field_arr := sel_a_b(use_immediate, c_rdma_packetiser_roce_hdr_field_arr, c_rdma_packetiser_roce_no_imm_hdr_field_arr); + begin + -- eth header + v.eth.dst_mac := hdr_fields_raw(field_hi(c_hdr_field_arr, "eth_dst_mac") downto field_lo(c_hdr_field_arr, "eth_dst_mac")); + v.eth.src_mac := hdr_fields_raw(field_hi(c_hdr_field_arr, "eth_src_mac") downto field_lo(c_hdr_field_arr, "eth_src_mac")); + v.eth.eth_type := hdr_fields_raw(field_hi(c_hdr_field_arr, "eth_type") downto field_lo(c_hdr_field_arr, "eth_type")); + + -- ip header + v.ip.version := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_version") downto field_lo(c_hdr_field_arr, "ip_version")); + v.ip.header_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_header_length") downto field_lo(c_hdr_field_arr, "ip_header_length")); + v.ip.services := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_services") downto field_lo(c_hdr_field_arr, "ip_services")); + v.ip.total_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_total_length") downto field_lo(c_hdr_field_arr, "ip_total_length")); + v.ip.identification := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_identification") downto field_lo(c_hdr_field_arr, "ip_identification")); + v.ip.flags := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_flags") downto field_lo(c_hdr_field_arr, "ip_flags")); + v.ip.fragment_offset := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_fragment_offset") downto field_lo(c_hdr_field_arr, "ip_fragment_offset")); + v.ip.time_to_live := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_time_to_live") downto field_lo(c_hdr_field_arr, "ip_time_to_live")); + v.ip.protocol := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_protocol") downto field_lo(c_hdr_field_arr, "ip_protocol")); + v.ip.header_checksum := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_header_checksum") downto field_lo(c_hdr_field_arr, "ip_header_checksum")); + v.ip.src_ip_addr := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_src_addr") downto field_lo(c_hdr_field_arr, "ip_src_addr")); + v.ip.dst_ip_addr := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_dst_addr") downto field_lo(c_hdr_field_arr, "ip_dst_addr")); + + -- udp header + v.udp.src_port := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_src_port") downto field_lo(c_hdr_field_arr, "udp_src_port")); + v.udp.dst_port := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_dst_port") downto field_lo(c_hdr_field_arr, "udp_dst_port")); + v.udp.total_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_total_length") downto field_lo(c_hdr_field_arr, "udp_total_length")); + v.udp.checksum := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_checksum") downto field_lo(c_hdr_field_arr, "udp_checksum")); + + -- bth header + v.bth.opcode := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_opcode") downto field_lo(c_hdr_field_arr, "bth_opcode")); + v.bth.se := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_se") downto field_lo(c_hdr_field_arr, "bth_se")); + v.bth.m := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_m") downto field_lo(c_hdr_field_arr, "bth_m")); + v.bth.pad := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_pad") downto field_lo(c_hdr_field_arr, "bth_pad")); + v.bth.tver := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_tver") downto field_lo(c_hdr_field_arr, "bth_tver")); + v.bth.partition_key := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_partition_key") downto field_lo(c_hdr_field_arr, "bth_partition_key")); + v.bth.fres := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_fres") downto field_lo(c_hdr_field_arr, "bth_fres")); + v.bth.bres := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_bres") downto field_lo(c_hdr_field_arr, "bth_bres")); + v.bth.reserved_a := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_reserved_a") downto field_lo(c_hdr_field_arr, "bth_reserved_a")); + v.bth.dest_qp := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_dest_qp") downto field_lo(c_hdr_field_arr, "bth_dest_qp")); + v.bth.ack_req := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_ack_req") downto field_lo(c_hdr_field_arr, "bth_ack_req")); + v.bth.reserved_b := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_reserved_b") downto field_lo(c_hdr_field_arr, "bth_reserved_b")); + v.bth.psn := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_psn") downto field_lo(c_hdr_field_arr, "bth_psn")); + + -- reth header + v.reth.virtual_address := hdr_fields_raw(field_hi(c_hdr_field_arr, "reth_virtual_address") downto field_lo(c_hdr_field_arr, "reth_virtual_address")); + v.reth.r_key := hdr_fields_raw(field_hi(c_hdr_field_arr, "reth_r_key") downto field_lo(c_hdr_field_arr, "reth_r_key")); + v.reth.dma_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "reth_dma_length") downto field_lo(c_hdr_field_arr, "reth_dma_length")); + + --immediate data + v.immediate_data := (others => '0'); + if use_immediate then + v.immediate_data := hdr_fields_raw(field_hi(c_hdr_field_arr, "immediate_data") downto field_lo(c_hdr_field_arr, "immediate_data")); + end if; + + return v; + end func_rdma_packetiser_map_header; + + + +end rdma_packetiser_pkg; diff --git a/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd new file mode 100644 index 0000000000..84fc97af8b --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd @@ -0,0 +1,199 @@ +------------------------------------------------------------------------------- +-- +-- 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_packetiser_assemble_header +-- Description: +-- . Generates DP data using proc_dp_gen_block_data that streams into DUT. +-- . Verifies the resulting header field array comming from the DUT by +-- comparing to expected values. +-- Remark: +-- . +------------------------------------------------------------------------------- + +library IEEE, common_lib, dp_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_network_layers_pkg.all; +use common_lib.tb_common_pkg.all; +use common_lib.tb_common_mem_pkg.all; +use dp_lib.tb_dp_pkg.all; +use dp_lib.dp_stream_pkg.all; +use work.rdma_packetiser_pkg.all; + +entity tb_rdma_packetiser_assemble_header is + generic ( + g_use_immediate : boolean := true; + g_use_msg_cnt_as_immediate : boolean := true; + g_nof_rep : natural := 15; + g_frame_len : natural := 15; + g_start_address : unsigned(c_longword_w - 1 downto 0) := (others => '0'); + g_nof_packets_in_msg : natural := 4; + g_nof_msg : natural := 3 + ); +end tb_rdma_packetiser_assemble_header; + +architecture tb of tb_rdma_packetiser_assemble_header is + constant c_dp_clk_period : time := 5 ns; -- 200 MHz + constant c_data_w : natural := c_word_w; + constant c_data_init : natural := 13; + constant c_hdr_fields_slv_rst : std_logic_vector(1023 downto 0) := (others => '0'); + constant c_rdma_hdr_len : natural := c_rdma_packetiser_roce_icrc_len + sel_a_b(g_use_immediate, + c_rdma_packetiser_roce_hdr_len, c_rdma_packetiser_roce_no_imm_hdr_len); + constant c_block_len : natural := g_frame_len * (c_data_w / c_octet_w); + constant c_dma_len : natural := c_block_len * g_nof_packets_in_msg; + + signal tb_end : std_logic := '0'; + + signal dp_clk : std_logic := '1'; + signal dp_rst : std_logic; + + signal immediate_data : std_logic_vector(c_word_w - 1 downto 0) := X"89ABCDEF"; + signal block_len : std_logic_vector(c_halfword_w - 1 downto 0) := TO_UVEC(c_block_len, c_halfword_w); + signal nof_packets_in_msg : std_logic_vector(c_word_w - 1 downto 0) := TO_UVEC(g_nof_packets_in_msg, c_word_w); + signal nof_msg : std_logic_vector(c_word_w - 1 downto 0) := TO_UVEC(g_nof_msg, c_word_w); + signal dma_len : std_logic_vector(c_word_w - 1 downto 0) := TO_UVEC(c_dma_len, c_word_w); + signal start_address : std_logic_vector(c_longword_w - 1 downto 0) := std_logic_vector(g_start_address); + + signal hdr_fields_slv : std_logic_vector(1023 downto 0) := (others => '0'); + signal rdma_header : t_rdma_packetiser_roce_header; + signal exp_rdma_header : t_rdma_packetiser_roce_header := func_rdma_packetiser_map_header(c_hdr_fields_slv_rst, g_use_immediate); + signal in_en : std_logic := '0'; + + signal snk_in : t_dp_sosi := c_dp_sosi_rst; + signal snk_out : t_dp_siso := c_dp_siso_rdy; + + +begin + dp_rst <= '1', '0' after c_dp_clk_period * 7; + dp_clk <= (not dp_clk) or tb_end after c_dp_clk_period / 2; + + rdma_header <= func_rdma_packetiser_map_header(hdr_fields_slv, g_use_immediate ); + + p_dp_stimuli : process + begin + + -- dp stimuli + proc_common_wait_until_low(dp_clk, dp_rst); + proc_common_wait_some_cycles(dp_clk, 100); + in_en <= '1'; + for rep in 0 to g_nof_rep - 1 loop + proc_dp_gen_block_data(1, true, c_data_w, c_data_w, c_data_init, 0, 0, g_frame_len, 0, 0, '0', TO_DP_BSN(rep), dp_clk, in_en, snk_out, snk_in); + end loop; + proc_common_wait_some_cycles(dp_clk, 100); + in_en <= '0'; + wait; + end process; + + -- check if values in rdma_packetiser_assemble_header match with expected values + p_rdma_packetiser_assemble_header_stimuli : process + variable v_exp_ip_total_length : natural; + variable v_exp_udp_total_length : natural; + variable v_exp_bth_opcode : std_logic_vector(c_byte_w - 1 downto 0); + variable v_exp_bth_psn : natural; + variable v_exp_reth_virtual_address : unsigned(c_longword_w - 1 downto 0); + variable v_exp_reth_dma_length : natural; + variable v_exp_immediate_data : std_logic_vector(c_word_w - 1 downto 0); + variable v_p, v_m : natural := 0; + begin + for rep in 0 to g_nof_rep - 1 loop + proc_common_wait_until_high(dp_clk, snk_in.sop); -- wait for sop + + v_exp_ip_total_length := c_network_ip_header_len + c_network_udp_header_len + c_rdma_hdr_len + to_uint(block_len); + v_exp_udp_total_length := c_network_udp_header_len + c_rdma_hdr_len + to_uint(block_len); + v_exp_bth_psn := v_p; + v_exp_reth_virtual_address := g_start_address + to_unsigned((v_m mod g_nof_msg) * c_dma_len, c_longword_w); + v_exp_reth_dma_length := c_dma_len; + v_exp_immediate_data := sel_a_b(g_use_immediate, + sel_a_b(g_use_msg_cnt_as_immediate, to_uvec((v_m mod g_nof_msg), c_word_w), immediate_data), to_uvec(0, c_word_w)); + + -- determine expected opcode + if v_p mod g_nof_packets_in_msg = 0 then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_first; + if g_nof_packets_in_msg = 1 and g_use_immediate then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_only_im; + elsif g_nof_packets_in_msg = 1 then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_only; + end if; + elsif v_p mod g_nof_packets_in_msg = g_nof_packets_in_msg - 1 then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_last; + if g_use_immediate then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_last_im; + end if; + else + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_middle; + end if; + + -- increase counters + v_p := v_p + 1; + v_m := v_p / g_nof_packets_in_msg; + + -- assign expected values to signal to view in wave window. + exp_rdma_header.ip.total_length <= to_uvec(v_exp_ip_total_length, c_halfword_w); + exp_rdma_header.udp.total_length <= to_uvec(v_exp_udp_total_length, c_halfword_w ); + exp_rdma_header.bth.opcode <= v_exp_bth_opcode; + exp_rdma_header.bth.psn <= to_uvec(v_exp_bth_psn, c_word_w); + exp_rdma_header.reth.virtual_address <= std_logic_vector(v_exp_reth_virtual_address); + exp_rdma_header.reth.dma_length <= to_uvec(v_exp_reth_dma_length, c_word_w); + exp_rdma_header.immediate_data <= v_exp_immediate_data; + proc_common_wait_some_cycles(dp_clk, 1); + + -- assert when header is not as expected. + assert TO_UINT(rdma_header.ip.total_length) = v_exp_ip_total_length report "Wrong rdma_header.ip.total_length value" severity error; + assert TO_UINT(rdma_header.udp.total_length) = v_exp_udp_total_length report "Wrong rdma_header.udp.total_length value" severity error; + assert rdma_header.bth.opcode = v_exp_bth_opcode report "Wrong rdma_header.bth.opcode value" severity error; + assert TO_UINT(rdma_header.bth.psn) = v_exp_bth_psn report "Wrong rdma_header.bth.psn value" severity error; + assert unsigned(rdma_header.reth.virtual_address) = v_exp_reth_virtual_address report "Wrong rdma_header.reth.virtual_address value" severity error; + assert TO_UINT(rdma_header.reth.dma_length) = v_exp_reth_dma_length report "Wrong rdma_header.reth.dma_length value" severity error; + assert rdma_header.immediate_data = v_exp_immediate_data report "Wrong rdma_header.immediate_data value" severity error; + + end loop; + + proc_common_wait_some_cycles(dp_clk, 100); + tb_end <= '1'; + wait; + end process; + + u_dut: entity work.rdma_packetiser_assemble_header + generic map ( + g_use_immediate => g_use_immediate, + g_use_msg_cnt_as_immediate => g_use_msg_cnt_as_immediate + ) + port map ( + st_clk => dp_clk, + st_rst => dp_rst, + + snk_in => snk_in, + hdr_fields_slv => hdr_fields_slv, + + immediate_data => immediate_data, + block_len => block_len, + nof_packets_in_msg => nof_packets_in_msg, + nof_msg => nof_msg, + dma_len => dma_len, + start_address => start_address + ); +end tb; diff --git a/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd new file mode 100644 index 0000000000..b956b27c12 --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd @@ -0,0 +1,62 @@ +------------------------------------------------------------------------------- +-- +-- 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: Verify multiple variations of tb_rdma_packetiser_assemble_header +-- Description: +-- Usage: +-- > as 3 +-- > run -all +------------------------------------------------------------------------------- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity tb_tb_rdma_packetiser_assemble_header is +end tb_tb_rdma_packetiser_assemble_header; + +architecture tb of tb_tb_rdma_packetiser_assemble_header is + constant c_low_start_addr : unsigned(63 downto 0) := X"000000000000BCDF"; -- arbitrary low start address + constant c_high_start_addr : unsigned(63 downto 0) := X"CBA9876543210000"; -- arbitrary high start address + signal tb_end : std_logic := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' +begin + +-- All generics of TB +-- g_use_immediate : boolean := true; +-- g_use_msg_cnt_as_immediate : boolean := true; +-- g_nof_rep : natural := 15; +-- g_frame_len : natural := 15; +-- g_start_address : unsigned(c_longword_w - 1 downto 0) := (others => '0'); +-- g_nof_packets_in_msg : natural := 4; +-- g_nof_msg : natural := 3 + + u_lo_addr : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_low_start_addr, 4, 5); + u_hi_addr : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_high_start_addr, 4, 5); + u_no_mid : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_high_start_addr, 2, 5); + u_wr_only : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_high_start_addr, 1, 5); + u_large : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 10, 2000, c_low_start_addr, 3, 1); + u_no_im_cnt : entity work.tb_rdma_packetiser_assemble_header generic map( false, true, 100, 15, c_low_start_addr, 4, 10); + u_no_cnt : entity work.tb_rdma_packetiser_assemble_header generic map( true, false, 20, 15, c_low_start_addr, 4, 5); + u_no_im : entity work.tb_rdma_packetiser_assemble_header generic map( false, false, 30, 7, c_high_start_addr, 3, 2); + u_two : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 2, c_low_start_addr, 1, 5); + u_many : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 6000, 3, c_low_start_addr, 5, 1000); +end tb; -- GitLab