Skip to content
Snippets Groups Projects
Commit 4b76d0b8 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Merge branch 'master' into L2SDP-964

parents 3da7b65b e83ed6b1
No related branches found
No related tags found
1 merge request!359Clarify g_nof_destinations_max design revision parameter and package constants...
Pipeline #59946 passed
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]
-------------------------------------------------------------------------------
--
-- 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:
-- Generates a RoCEv2 header (ETH + UDP + IP + RDMA). See [1].
-- Generics:
-- . g_use_immediate: When true, the immediate data field will be added to the
-- header.
-- . g_use_msg_cnt_as_immediate: When true, the message counter going from 0 to
-- "nof_msg" is used as immediate data. When false, the "immediate_data"
-- input port is used.
-- Signal inputs:
-- . immediate_data: Will be used as immediate data when
-- g_use_msg_cnt_as_immediate = False.
-- . block_len: Should be set to the length of the incoming data frame in octets.
-- . nof_packets_in_msg: Should be set to the desired amount of packets in a message.
-- . nof_msg: Should be set to the desired amount of messages, this determines the
-- address space aswell, see remarks.
-- . dma_len: The amount with which the address should increase every message,
-- this should be set to >= nof_packets_in_msg * block_len.
-- . start_address: The start address for the virtual_address field.
-- Remarks
-- . 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.
-- . The virtual_address is set automatically by increasing it with dma_len every
-- new message. The virtual address is reset to "start_address" when the number
-- of messages has reached "nof_msg". Then the cycle repeats.
-- . The PSN field (= Packet Sequence Number) is set to LSBs of the incoming BSN.
-- This can be used to check the order or detect missing packets at the receiver.
-- References:
-- . [1] https://support.astron.nl/confluence/x/3pKrB
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_first, s_middle, s_last);
type t_reg is record -- record to keep the registers organized.
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; -- Packet count (0 to nof_packets_in_msg).
msg_cnt : natural; -- message count (0 to nof_msg).
udp_total_length : natural;
ip_total_length : natural;
nof_packets_in_msg : natural;
end record;
constant c_reg_rst : t_reg := (s_first, (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);
-- State machine to derive RDMA header fields.
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
v.psn := resize_uvec(snk_in.bsn, c_word_w);
v.p_cnt := q.p_cnt + 1;
case q.state is
when s_first => -- wait to start a new message and set the first opcode.
v.p_cnt := 1;
if q.p_cnt >= v.nof_packets_in_msg then -- (re)set message counter and virtual address.
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 if;
if v.nof_packets_in_msg = 1 then -- set opcode to write_only.
v.opcode := c_rdma_packetiser_opcode_uc_write_only;
if g_use_immediate then -- set opcode to write_only with immediate data.
v.opcode := c_rdma_packetiser_opcode_uc_write_only_imm;
end if;
elsif v.nof_packets_in_msg = 2 then -- set opcode to write_first.
v.state := s_last; -- next state is last as there are only 2 packets.
v.opcode := c_rdma_packetiser_opcode_uc_write_first;
elsif v.nof_packets_in_msg > 2 then
v.state := s_middle;
v.opcode := c_rdma_packetiser_opcode_uc_write_first;
end if;
when s_middle => -- wait unitl the first packet is done and set next opcode.
v.opcode := c_rdma_packetiser_opcode_uc_write_middle;
if q.p_cnt >= v.nof_packets_in_msg - 2 then -- wait until last middle packet
v.state := s_last;
end if;
when s_last => -- next packet must be last packet, set opcode.
v.state := s_first;
v.opcode := c_rdma_packetiser_opcode_uc_write_last;
if g_use_immediate then -- set opcode to write_last with immediate data
v.opcode := c_rdma_packetiser_opcode_uc_write_last_imm;
end if;
end case;
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;
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;
-------------------------------------------------------------------------------
--
-- 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_packetiser specific constants and/or functions
-- Description: See [1] for RDMA explanation.
-- References:
-- . [1] https://support.astron.nl/confluence/x/3pKrB
-------------------------------------------------------------------------------
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) ), -- set by M&C
( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), -- set by M&C
( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), -- fixed
( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), -- fixed
( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), -- fixed
( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), -- fixed
( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- set by data path
( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), -- fixed
( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), -- fixed
( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), -- fixed
( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), -- fixed
( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), -- fixed
( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), -- set by data path
( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), -- set by M&C
( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- set by M&C
( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- set by data path
( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), -- fixed
( field_name_pad("bth_opcode" ), "RW", 8, field_default(x"FF") ), -- set by data path
( field_name_pad("bth_se" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_m" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_pad" ), "RW", 2, field_default(0) ), -- set by M&C
( field_name_pad("bth_tver" ), "RW", 4, field_default(0) ), -- set by M&C
( field_name_pad("bth_partition_key" ), "RW", 16, field_default(65535) ), -- set by M&C
( field_name_pad("bth_fres" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_bres" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_reserved_a" ), "RW", 6, field_default(0) ), -- fixed
( field_name_pad("bth_dest_qp" ), "RW", 16, field_default(0) ), -- set by M&C
( field_name_pad("bth_ack_req" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_reserved_b" ), "RW", 7, field_default(0) ), -- fixed
( field_name_pad("bth_psn" ), "RW", 32, field_default(0) ), -- set by data path
( field_name_pad("reth_virtual_address"), "RW", 64, field_default(0) ), -- set by data path
( field_name_pad("reth_r_key" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("reth_dma_length" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("immediate_data" ), "RW", 32, field_default(0) ) -- set by data path or M&C
);
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), so no immediate data ("no_imm").
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) ), -- set by M&C
( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), -- set by M&C
( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), -- fixed
( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), -- fixed
( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), -- fixed
( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), -- fixed
( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- set by data path
( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), -- fixed
( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), -- fixed
( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), -- fixed
( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), -- fixed
( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), -- fixed
( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), -- set by data path
( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), -- set by M&C
( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- set by M&C
( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- set by data path
( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), -- fixed
( field_name_pad("bth_opcode" ), "RW", 8, field_default(x"FF") ), -- set by data path
( field_name_pad("bth_se" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_m" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_pad" ), "RW", 2, field_default(0) ), -- set by M&C
( field_name_pad("bth_tver" ), "RW", 4, field_default(0) ), -- set by M&C
( field_name_pad("bth_partition_key" ), "RW", 16, field_default(65535) ), -- set by M&C
( field_name_pad("bth_fres" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_bres" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_reserved_a" ), "RW", 6, field_default(0) ), -- fixed
( field_name_pad("bth_dest_qp" ), "RW", 16, field_default(0) ), -- set by M&C
( field_name_pad("bth_ack_req" ), "RW", 1, field_default(0) ), -- set by M&C
( field_name_pad("bth_reserved_b" ), "RW", 7, field_default(0) ), -- fixed
( field_name_pad("bth_psn" ), "RW", 32, field_default(0) ), -- set by data path
( field_name_pad("reth_virtual_address"), "RW", 64, field_default(0) ), -- set by data path
( field_name_pad("reth_r_key" ), "RW", 32, field_default(0) ), -- set by M&C
( field_name_pad("reth_dma_length" ), "RW", 32, field_default(0) ) -- set by M&C
);
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"; -- without immediate
constant c_rdma_packetiser_opcode_uc_send_last_imm : std_logic_vector := "001" & "00011"; -- with immediate
constant c_rdma_packetiser_opcode_uc_send_only : std_logic_vector := "001" & "00100"; -- without immediate
constant c_rdma_packetiser_opcode_uc_send_only_imm : std_logic_vector := "001" & "00101"; -- with immediate
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"; -- without immediate
constant c_rdma_packetiser_opcode_uc_write_last_imm : std_logic_vector := "001" & "01001"; -- with immediate
constant c_rdma_packetiser_opcode_uc_write_only : std_logic_vector := "001" & "01010"; -- without immediate
constant c_rdma_packetiser_opcode_uc_write_only_imm : std_logic_vector := "001" & "01011"; -- with immediate
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;
-------------------------------------------------------------------------------
--
-- 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.
-- . The generics can be used to test specific conditions.
-- . g_use_immediate: When true, the DUT will use the optional immediate data
-- field.
-- . g_use_msg_cnt_as_immediate: When true, the DUT will use the message count
-- value as immediate data. When false, the DUT sets the immediate data to
-- the value of the immediate_data input port.
-- . g_nof_rep: number of packets the TB should generate.
-- . g_frame_len: length of the data frames that the TB should generate.
-- . g_start_address: 64 bit value to use as a start address for the DUT
-- . g_nof_packets_in_msg: The number of packets the DUT should put in one
-- RDMA message.
-- . g_nof_msg: Number of RDMA messages the DUT should create.
-------------------------------------------------------------------------------
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 := 60;
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 rx_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;
rx_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_verify_rdma_header : 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_imm;
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_imm;
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 rx_rdma_header = exp_rdma_header report "Wrong rx_rdma_header" severity error;
assert rx_rdma_header.ip.total_length = exp_rdma_header.ip.total_length report "Wrong rx_rdma_header.ip.total_length value" severity error;
assert rx_rdma_header.udp.total_length = exp_rdma_header.udp.total_length report "Wrong rx_rdma_header.udp.total_length value" severity error;
assert rx_rdma_header.bth.opcode = exp_rdma_header.bth.opcode report "Wrong rx_rdma_header.bth.opcode value" severity error;
assert rx_rdma_header.bth.psn = exp_rdma_header.bth.psn report "Wrong rx_rdma_header.bth.psn value" severity error;
assert rx_rdma_header.reth.virtual_address = exp_rdma_header.reth.virtual_address report "Wrong rx_rdma_header.reth.virtual_address value" severity error;
assert rx_rdma_header.reth.dma_length = exp_rdma_header.reth.dma_length report "Wrong rx_rdma_header.reth.dma_length value" severity error;
assert rx_rdma_header.immediate_data = exp_rdma_header.immediate_data report "Wrong rx_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;
-------------------------------------------------------------------------------
--
-- 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_imm_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_imm : entity work.tb_rdma_packetiser_assemble_header generic map( false, false, 30, 7, c_high_start_addr, 3, 2);
u_one : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 1, 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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment