Skip to content
Snippets Groups Projects

initial commit of rdma_packetiser library

Merged Reinier van der Walle requested to merge HPR-129 into master
All threads resolved!
5 files
+ 756
0
Compare changes
  • Side-by-side
  • Inline
Files
5
-------------------------------------------------------------------------------
--
-- 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;
Loading