Skip to content
Snippets Groups Projects
eth_tester_pkg.vhd 14.9 KiB
Newer Older
-------------------------------------------------------------------------------
--
-- Copyright 2022
-- 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: E. Kooistra
Eric Kooistra's avatar
Eric Kooistra committed
-- Purpose: This package contains eth_tester specific constants and 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_pkg is

  CONSTANT c_eth_tester_bg_block_len_max   : NATURAL := c_network_eth_payload_jumbo_max;  -- 9000 octets
  CONSTANT c_eth_tester_rx_block_len_max   : NATURAL := c_network_eth_payload_jumbo_max + c_network_eth_crc_len;  -- 9004 octets
  CONSTANT c_eth_tester_eth_packet_len_max : NATURAL := c_network_eth_word_align_len + c_network_eth_frame_jumbo_max;   -- 9020 octets = 2 word align + 14 header + 9000 + 4 crc
  -- Support maximum (2**31-1)/200e6 = 10.7 s BG sync interval for sync timeout
  -- in BSN monitors, assuming st_clk at 200 MHz and with maximum NATURAL value
  -- of c_natural_high = 2**31 - 1.
  CONSTANT c_eth_tester_sync_timeout : NATURAL := c_natural_high;

  -- 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_eth_tester_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_eth_tester_nof_hdr_fields    : NATURAL := 1+3+12+4+4;
  CONSTANT c_eth_tester_hdr_field_sel     : STD_LOGIC_VECTOR(c_eth_tester_nof_hdr_fields-1 DOWNTO 0) := "1"&"101"&"111011111001"&"0100"&"0100";
  -- Default use destination MAC/IP/UDP = 0, so these have to be MM programmed
  -- before eth_tester packets can be send.
  CONSTANT c_eth_tester_hdr_field_arr : t_common_field_arr(c_eth_tester_nof_hdr_fields-1 DOWNTO 0) := (
      ( field_name_pad("word_align"                              ), "RW", 16, field_default(0) ),  -- Tx TSE IP will strip these 2 padding bytes
      ( field_name_pad("eth_dst_mac"                             ), "RW", 48, field_default(0) ),  -- c_eth_tester_eth_dst_mac
      ( 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("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_eth_tester_reg_hdr_dat_addr_w    : NATURAL := ceil_log2(field_nof_words(c_eth_tester_hdr_field_arr, c_word_w));  -- = 5
  CONSTANT c_eth_tester_reg_hdr_dat_addr_span : NATURAL := 2**c_eth_tester_reg_hdr_dat_addr_w;  -- = 32

  CONSTANT c_eth_tester_app_hdr_len  : NATURAL :=  12;  -- octets

  -- . MAC address 00:22:86:08:pp:qq = UNB_ETH_SRC_MAC_BASE in
  --   libraries/unb_osy/unbos_eth.h, pp = backplane ID, qq = node ID
  -- . IP address 10.99.xx.yy = g_base_ip in ctrl_unb2#_board.vhd used in
  --   libraries/unb_osy/unbos_eth.c, xx = backplane ID, yy = node ID + 1
  -- . UDP port 15:8 = E0, 7:0 = gn_id (= ID[7:0] = backplane[5:0] & node[1:0])
  CONSTANT c_eth_tester_eth_src_mac_47_16 : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00228608";
  CONSTANT c_eth_tester_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"0A63";
  CONSTANT c_eth_tester_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"E0";
  -- Default eth_tester UDP port for first stream via 1GbE.
  -- Do not use UDP port 0x1388 = 5000 for eth_tester, because port 5000 is
  -- used for M&C via 1GbE-I.
  CONSTANT c_eth_tester_udp_port : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(6001, 16);  -- 0x1771 = 6001
  TYPE t_eth_tester_app_header IS RECORD
    dp_length   : STD_LOGIC_VECTOR(15 DOWNTO 0);
    dp_reserved : STD_LOGIC_VECTOR(14 DOWNTO 0);
    dp_sync     : STD_LOGIC;
    dp_bsn      : STD_LOGIC_VECTOR(63 DOWNTO 0);
  END RECORD;

  TYPE t_eth_tester_header IS RECORD
    eth : t_network_eth_header;
    ip  : t_network_ip_header;
    udp : t_network_udp_header;
    app : t_eth_tester_app_header;
  END RECORD;

  -- Map global node index on UniBoard2 to node src MAC, IP and UDP port
  FUNCTION func_eth_tester_gn_index_to_mac_15_0(gn_index : NATURAL; eth_port_index : NATURAL) RETURN STD_LOGIC_VECTOR;
  FUNCTION func_eth_tester_gn_index_to_mac_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR;  -- default use 1GbE port I
  FUNCTION func_eth_tester_gn_index_to_ip_15_0(gn_index : NATURAL; eth_port_index : NATURAL) RETURN STD_LOGIC_VECTOR;
  FUNCTION func_eth_tester_gn_index_to_ip_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR;  -- default use 1GbE port I
  FUNCTION func_eth_tester_gn_index_to_udp_7_0(gn_index : NATURAL; eth_port_index : NATURAL) RETURN STD_LOGIC_VECTOR;
  FUNCTION func_eth_tester_gn_index_to_udp_7_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR;  -- default use 1GbE port I

  -- Map packet header fields to t_eth_tester_header record
  FUNCTION func_eth_tester_map_header(hdr_fields_raw : STD_LOGIC_VECTOR) RETURN t_eth_tester_header;

END eth_tester_pkg;


PACKAGE BODY eth_tester_pkg IS

  FUNCTION func_eth_tester_gn_index_to_mac_15_0(gn_index : NATURAL; eth_port_index : NATURAL) RETURN STD_LOGIC_VECTOR IS
    -- Assume gn_index < 256.
    -- Use default address for 1GbE II (eth_port_index = 0) and
    -- an address offset for 1GbE II (eth_port_index = 1)
    CONSTANT c_unb_nr    : NATURAL := gn_index / c_4;  -- 4 PN per Uniboard2
    CONSTANT c_node_nr   : NATURAL := gn_index MOD c_4;
    CONSTANT c_offset    : NATURAL := eth_port_index * c_4;
    CONSTANT c_mac_15_0  : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr + c_offset, 8);
  BEGIN
    RETURN c_mac_15_0;
  END func_eth_tester_gn_index_to_mac_15_0;

  FUNCTION func_eth_tester_gn_index_to_mac_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR IS
  BEGIN
    RETURN func_eth_tester_gn_index_to_mac_15_0(gn_index, 0);  -- default use 1GbE port I
  END func_eth_tester_gn_index_to_mac_15_0;


  FUNCTION func_eth_tester_gn_index_to_ip_15_0(gn_index : NATURAL; eth_port_index : NATURAL) RETURN STD_LOGIC_VECTOR IS
    -- Assume gn_index < 256.
    -- Use default address for 1GbE II (eth_port_index = 0) and
    -- an address offset for 1GbE II (eth_port_index = 1)
    CONSTANT c_unb_nr    : NATURAL := gn_index / c_4;  -- 4 PN per Uniboard2
    CONSTANT c_node_nr   : NATURAL := gn_index MOD c_4;
    CONSTANT c_offset    : NATURAL := eth_port_index * c_4;
    CONSTANT c_ip_15_0   : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(c_unb_nr, 8) & TO_UVEC(c_node_nr + 1 + c_offset, 8);  -- +1 to avoid IP = *.*.*.0
  BEGIN
    RETURN c_ip_15_0;
  END func_eth_tester_gn_index_to_ip_15_0;

  FUNCTION func_eth_tester_gn_index_to_ip_15_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR IS
  BEGIN
    RETURN func_eth_tester_gn_index_to_ip_15_0(gn_index, 0);  -- default use 1GbE port I
  END func_eth_tester_gn_index_to_ip_15_0;


  FUNCTION func_eth_tester_gn_index_to_udp_7_0(gn_index : NATURAL; eth_port_index : NATURAL) RETURN STD_LOGIC_VECTOR IS
    -- Assume gn_index < 128.
    -- Use default udp port for 1GbE I (eth_port_index = 0) and
    -- an increment udp port for 1GbE II (eth_port_index = 1)
    CONSTANT c_offset    : NATURAL := eth_port_index * c_128;  -- MSbit 7
    CONSTANT c_udp_7_0   : STD_LOGIC_VECTOR(7 DOWNTO 0) := TO_UVEC(gn_index + c_offset, 8);
  BEGIN
    RETURN c_udp_7_0;
  END func_eth_tester_gn_index_to_udp_7_0;

  FUNCTION func_eth_tester_gn_index_to_udp_7_0(gn_index : NATURAL) RETURN STD_LOGIC_VECTOR IS
  BEGIN
    RETURN func_eth_tester_gn_index_to_udp_7_0(gn_index, 0);  -- default use 1GbE port I
  END func_eth_tester_gn_index_to_udp_7_0;


  FUNCTION func_eth_tester_map_header(hdr_fields_raw : STD_LOGIC_VECTOR) RETURN t_eth_tester_header IS
    VARIABLE v : t_eth_tester_header;
  BEGIN
    -- eth header
    v.eth.dst_mac        := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "eth_dst_mac") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_dst_mac"));
    v.eth.src_mac        := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "eth_src_mac") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_src_mac"));
    v.eth.eth_type       := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "eth_type")    DOWNTO field_lo(c_eth_tester_hdr_field_arr, "eth_type"));

    -- ip header
    v.ip.version         := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_version")         DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_version"));
    v.ip.header_length   := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_header_length")   DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_header_length"));
    v.ip.services        := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_services")        DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_services"));
    v.ip.total_length    := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_total_length")    DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_total_length"));
    v.ip.identification  := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_identification")  DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_identification"));
    v.ip.flags           := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_flags")           DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_flags"));
    v.ip.fragment_offset := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_fragment_offset") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_fragment_offset"));
    v.ip.time_to_live    := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_time_to_live")    DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_time_to_live"));
    v.ip.protocol        := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_protocol")        DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_protocol"));
    v.ip.header_checksum := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_header_checksum") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_header_checksum"));
    v.ip.src_ip_addr     := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_src_addr")        DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_src_addr"));
    v.ip.dst_ip_addr     := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "ip_dst_addr")        DOWNTO field_lo(c_eth_tester_hdr_field_arr, "ip_dst_addr"));

    -- udp header
    v.udp.src_port       := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_src_port")     DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_src_port"));
    v.udp.dst_port       := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_dst_port")     DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_dst_port"));
    v.udp.total_length   := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_total_length") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_total_length"));
    v.udp.checksum       := hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "udp_checksum")     DOWNTO field_lo(c_eth_tester_hdr_field_arr, "udp_checksum"));

    -- app header
    v.app.dp_length      :=    hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_length")   DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_length"));
    v.app.dp_reserved    :=    hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_reserved") DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_reserved"));
    v.app.dp_sync        := sl(hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_sync")     DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_sync")));
    v.app.dp_bsn         :=    hdr_fields_raw(field_hi(c_eth_tester_hdr_field_arr, "dp_bsn")      DOWNTO field_lo(c_eth_tester_hdr_field_arr, "dp_bsn"));
    RETURN v;
  END func_eth_tester_map_header;

END eth_tester_pkg;