Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
sdp_pkg.vhd 58.21 KiB
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- 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, E. Kooistra
-- Purpose: 
-- . This package contains sdp specific constants.
-- Description:
-- Remark:
-- . See Document: L3 SDP Decision: SDP Parameter definitions.
--   https://support.astron.nl/confluence/display/L2M/L3+SDP+Decision%3A+SDP+Parameter+definitions
-------------------------------------------------------------------------------
LIBRARY ieee, common_lib, rTwoSDF_lib, fft_lib, filter_lib, wpfb_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;
USE rTwoSDF_lib.rTwoSDFPkg.ALL;
USE fft_lib.fft_pkg.ALL; 
USE filter_lib.fil_pkg.ALL; 
USE wpfb_lib.wpfb_pkg.ALL;

PACKAGE sdp_pkg is
  -------------------------------------------------
  -- SDP info record as defined in:
  --  LOFAR2-9258-SDP info per antenna band 
  -------------------------------------------------
  TYPE t_sdp_info IS RECORD
    station_id              : STD_LOGIC_VECTOR(15 DOWNTO 0);
    antenna_band_index      : STD_LOGIC;
    observation_id          : STD_LOGIC_VECTOR(31 DOWNTO 0); 
    nyquist_zone_index      : STD_LOGIC_VECTOR(1 DOWNTO 0);   
    f_adc                   : STD_LOGIC;     
    fsub_type               : STD_LOGIC;  
    beam_repositioning_flag : STD_LOGIC; 
    O_si                    : STD_LOGIC_VECTOR(7 DOWNTO 0);    
    N_si                    : STD_LOGIC_VECTOR(7 DOWNTO 0);    
    O_rn                    : STD_LOGIC_VECTOR(7 DOWNTO 0);    
    N_rn                    : STD_LOGIC_VECTOR(7 DOWNTO 0);   
    block_period            : STD_LOGIC_VECTOR(15 DOWNTO 0);      
  END RECORD;   

  CONSTANT c_sdp_info_rst : t_sdp_info := 
      ( (OTHERS => '0'), '0', (OTHERS => '0'), (OTHERS => '0'),
        '0', '0', '0',
        (OTHERS => '0'), (OTHERS => '0'), (OTHERS => '0'), (OTHERS => '0'),
        (OTHERS => '0') );  

  -------------------------------------------------
  -- SDP specific parameters as defined in:
  --  L3 SDP Decision: SDP Parameter definitions 
  CONSTANT c_sdp_f_adc_MHz                 : NATURAL := 200;
  CONSTANT c_sdp_N_beamsets                : NATURAL := 2;
  CONSTANT c_sdp_N_crosslets_max           : NATURAL := 7;
  CONSTANT c_sdp_N_fft                     : NATURAL := 1024;
  CONSTANT c_sdp_N_pn_lb                   : NATURAL := 16;
  CONSTANT c_sdp_N_pn_max                  : NATURAL := 16;  -- gn 0:31 --> pn 0:15, pn 0:15 per antenna band
  CONSTANT c_sdp_N_pol                     : NATURAL := 2;
  CONSTANT c_sdp_N_pol_bf                  : NATURAL := 2;
  CONSTANT c_sdp_N_ring_lanes_max          : NATURAL := 8;
  CONSTANT c_sdp_N_sub                     : NATURAL := 512;
  CONSTANT c_sdp_N_sync_rcu                : NATURAL := 1;
  CONSTANT c_sdp_N_taps                    : NATURAL := 16;
  CONSTANT c_sdp_P_sq                      : NATURAL := 9;
  CONSTANT c_sdp_Q_fft                     : NATURAL := 2;
  CONSTANT c_sdp_S_pn                      : NATURAL := 12;
  CONSTANT c_sdp_S_rcu                     : NATURAL := 3;
  CONSTANT c_sdp_S_sub_bf                  : NATURAL := 488;
  CONSTANT c_sdp_V_ring_pkt_len_max        : NATURAL := 48; -- for 16 nodes
  CONSTANT c_sdp_V_sample_delay            : NATURAL := 4096;
  CONSTANT c_sdp_V_si_db                   : NATURAL := 1024;
  CONSTANT c_sdp_V_si_db_large             : NATURAL := 131072;
  CONSTANT c_sdp_V_si_histogram            : NATURAL := 512;
  CONSTANT c_sdp_W_adc                     : NATURAL := 14;
  CONSTANT c_sdp_W_adc_jesd                : NATURAL := 16;
  CONSTANT c_sdp_W_fir_coef                : NATURAL := 16;
  CONSTANT c_sdp_W_subband                 : NATURAL := 18;
  CONSTANT c_sdp_W_crosslet                : NATURAL := 16;
  CONSTANT c_sdp_W_beamlet_sum             : NATURAL := 18;
  CONSTANT c_sdp_W_beamlet                 : NATURAL := 8;
  CONSTANT c_sdp_W_gn_id                   : NATURAL := 5;
  CONSTANT c_sdp_W_statistic               : NATURAL := 64;
  CONSTANT c_sdp_W_statistic_sz            : NATURAL := 2;   -- = c_sdp_W_statistic / c_word_w
  CONSTANT c_sdp_W_sub_weight              : NATURAL := 16;  -- = w in s(w, p), s = signed
  CONSTANT c_sdp_W_sub_weight_fraction     : NATURAL := 13;  -- = p in s(w, p)
  CONSTANT c_sdp_W_sub_weight_magnitude    : NATURAL := c_sdp_W_sub_weight - c_sdp_W_sub_weight_fraction - 1;  -- = 2
  CONSTANT c_sdp_W_beamlet_scale           : NATURAL := 16;  -- = w in u(w, p), u = unsigned
  CONSTANT c_sdp_W_beamlet_scale_fraction  : NATURAL := 15;  -- = p in u(w, p)
  CONSTANT c_sdp_W_beamlet_scale_magnitude : NATURAL := c_sdp_W_beamlet_scale - c_sdp_W_beamlet_scale_fraction;  -- = 1
  CONSTANT c_sdp_W_bf_weight               : NATURAL := 16;  -- = w in s(w, p), s = signed
  CONSTANT c_sdp_W_bf_weight_fraction      : NATURAL := 14;  -- = p in s(w, p)
  CONSTANT c_sdp_W_bf_weight_magnitude     : NATURAL := c_sdp_W_bf_weight - c_sdp_W_bf_weight_fraction - 1;  -- = 1

  -- Derived constants
  CONSTANT c_sdp_FS_adc          : NATURAL := 2**(c_sdp_W_adc - 1); -- full scale FS corresponds to amplitude 1.0
  CONSTANT c_sdp_N_clk_per_sync  : NATURAL := c_sdp_f_adc_MHz*10**6;  -- Default 200M clock cycles per second
  CONSTANT c_sdp_N_sync_jesd     : NATURAL := c_sdp_S_pn * c_sdp_N_sync_rcu / c_sdp_S_rcu; -- = 4, nof JESD IP sync outputs per PN
  CONSTANT c_sdp_P_pfb           : NATURAL := c_sdp_S_pn / c_sdp_Q_fft;
  CONSTANT c_sdp_T_adc           : TIME    := (10**6 / c_sdp_f_adc_MHz) * 1 ps;
  CONSTANT c_sdp_T_sub           : TIME    := c_sdp_N_fft * c_sdp_T_adc;
  CONSTANT c_sdp_W_bf_product    : NATURAL := c_sdp_W_subband + c_sdp_W_bf_weight -1;
  CONSTANT c_sdp_X_sq            : NATURAL := c_sdp_S_pn * c_sdp_S_pn;
  CONSTANT c_sdp_block_period    : NATURAL := c_sdp_N_fft * 1000 / c_sdp_f_adc_MHz;  -- = 5120 [ns]

  -- Default / tb values
  CONSTANT c_sdp_beamlet_scale_default   : NATURAL := 2**15;

  -----------------------------------------------------------------------------
  -- PFB
  -----------------------------------------------------------------------------

  -- In SDP c_nof_channels = 2**nof_chan = 1 and wb_factor = 1,
  -- therefore these parameters are not explicitly used in calculation of derived constants
  -- LTS 2020_11_23:
  --CONSTANT c_sdp_wpfb_subbands : t_wpfb :=
  -- (1, c_sdp_N_fft, 0, c_sdp_P_pfb,
  -- c_sdp_N_taps, 1, c_sdp_W_adc, 16, c_sdp_W_fir_coef,
  -- true, false, true, 16, c_sdp_W_subband, 1, 18, 2, 
  -- true, 54, 2, 195313, c_fft_pipeline, c_fft_pipeline, 
  -- c_fil_ppf_pipeline);
  -- LTS 2021-02-03, changes based on results from u_wpfb_stage22 in tb_tb_verify_pfb_wg.vhd:
  -- . fil_backoff_w = 0 (was 1)
  -- . fil_out_dat_w = fft_in_dat_w = 17 (was 16)
  -- . g_fft_out_gain_w = 0 (was 1)
  -- . g_fft_stage_dat_w = 22 (was 18)
  -- . g_fft_guard_w = 1 (was 2)
  CONSTANT c_sdp_wpfb_subbands : t_wpfb :=
    (1, c_sdp_N_fft, 0, c_sdp_P_pfb,
    c_sdp_N_taps, 0, c_sdp_W_adc, 17, c_sdp_W_fir_coef,
    true, false, true, 17, c_sdp_W_subband, 0, 22, 1,
    true, 54, c_sdp_W_statistic_sz, 195313, c_fft_pipeline, c_fft_pipeline,
    c_fil_ppf_pipeline);

  -----------------------------------------------------------------------------
  -- Statistics offload
  -----------------------------------------------------------------------------

  -- The statistics offload uses the same 1GbE port as the NiosII for M&C. The 1GbE addresses defined in SW and here in FW.
  -- See NiosII code:
  --   https://git.astron.nl/desp/hdl/-/blob/master/libraries/unb_osy/unbos_eth.h
  --   https://git.astron.nl/desp/hdl/-/blob/master/libraries/unb_osy/unbos_eth.c
  -- and g_base_ip = x"0A63" in:
  --   https://git.astron.nl/desp/hdl/-/blob/master/boards/uniboard2b/libraries/unb2b_board/src/vhdl/ctrl_unb2b_board.vhd

  -- Can use same offload time for all statistics, because 1GbE mux will combine them
  --CONSTANT c_sdp_offload_time : NATURAL := 13000;  -- from wave window 62855nS / 5nS = 12571 cycles.
  CONSTANT c_sdp_offload_time : NATURAL := 600000;  -- see L2SDP-452

  -- packet lengths, see ICD SC-SDP
  CONSTANT c_sdp_nof_bytes_per_statistic : NATURAL := 8;  -- c_sdp_W_statistic_sz * c_word_sz = 2 * 4 = 8

  CONSTANT c_sdp_stat_app_header_len    : NATURAL := 32;

  CONSTANT c_sdp_stat_eth_dst_mac       : STD_LOGIC_VECTOR(47 DOWNTO 0) := x"001B217176B9";  -- 001B217176B9 = DOP36-enp2s0
  CONSTANT c_sdp_stat_eth_src_mac_47_16 : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00228608";  -- 00:22:86:08:pp:qq
  CONSTANT c_sdp_stat_ip_dst_addr       : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"0A6300FE";  -- 0A6300FE = '10.99.0.254' = DOP36-enp2s0
  CONSTANT c_sdp_stat_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"0A63";    -- 10.99.xx.yy
  CONSTANT c_sdp_stat_udp_dst_port      : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(5001, 16);
  CONSTANT c_sdp_sst_udp_src_port_15_8  : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D0";  -- TBC, 7:0 = gn_id (= ID[7:0] = backplane[5:0] & node[1:0])
  CONSTANT c_sdp_bst_udp_src_port_15_8  : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D1";  -- TBC
  CONSTANT c_sdp_xst_udp_src_port_15_8  : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D2";  -- TBC

  CONSTANT c_sdp_stat_version_id        : NATURAL := 5;
  CONSTANT c_sdp_stat_nof_hdr_fields    : NATURAL := 1+3+12+4+20+1; -- 608b; 19 32b words
  CONSTANT c_sdp_stat_hdr_field_sel     : STD_LOGIC_VECTOR(c_sdp_stat_nof_hdr_fields-1 DOWNTO 0) := "1"&"101"&"111011111001"&"0100"&"0100"&"000000010"&"1000000"&"0";  -- 0=data path, 1=MM controlled
--CONSTANT c_sdp_stat_hdr_field_sel     : STD_LOGIC_VECTOR(c_sdp_stat_nof_hdr_fields-1 DOWNTO 0) := "1"&"101"&"111011111001"&"0101"&"0100"&"000000000"&"0000100"&"0";  -- 0=data path, 1=MM controlled TODO (26 nov 2021)
--CONSTANT c_sdp_stat_hdr_field_sel     : STD_LOGIC_VECTOR(c_sdp_stat_nof_hdr_fields-1 DOWNTO 0) := "0"&"100"&"000000010001"&"0100"&"0100"&"000000010"&"1000000"&"0";  -- 0=data path, 1=MM controlled TODO

  CONSTANT c_sdp_stat_hdr_field_arr : t_common_field_arr(c_sdp_stat_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(c_sdp_stat_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) ), 
      ( 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(c_sdp_stat_ip_dst_addr) ),

      ( field_name_pad("udp_src_port"                            ), "RW", 16, field_default(0) ), 
      ( field_name_pad("udp_dst_port"                            ), "RW", 16, field_default(c_sdp_stat_udp_dst_port) ),
      ( field_name_pad("udp_total_length"                        ), "RW", 16, field_default(0) ), 
      ( field_name_pad("udp_checksum"                            ), "RW", 16, field_default(0) ),

      ( field_name_pad("sdp_marker"                              ), "RW",  8, field_default(0) ),
      ( field_name_pad("sdp_version_id"                          ), "RW",  8, field_default(c_sdp_stat_version_id) ),
      ( field_name_pad("sdp_observation_id"                      ), "RW", 32, field_default(0) ),
      ( field_name_pad("sdp_station_id"                          ), "RW", 16, field_default(0) ),

      ( field_name_pad("sdp_source_info_antenna_band_id"         ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_nyquist_zone_id"         ), "RW",  2, field_default(0) ),
      ( field_name_pad("sdp_source_info_f_adc"                   ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_fsub_type"               ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_payload_error"           ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_beam_repositioning_flag" ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_subband_calibrated_flag" ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_reserved"                ), "RW",  3, field_default(0) ),
      ( field_name_pad("sdp_source_info_gn_id"                   ), "RW",  5, field_default(0) ),

      ( field_name_pad("sdp_reserved"                            ), "RW",  8, field_default(0) ),
      ( field_name_pad("sdp_integration_interval"                ), "RW", 24, field_default(0) ),
      ( field_name_pad("sdp_data_id"                             ), "RW", 32, field_default(0) ),
      ( field_name_pad("sdp_nof_signal_inputs"                   ), "RW",  8, field_default(0) ),
      ( field_name_pad("sdp_nof_bytes_per_statistic"             ), "RW",  8, field_default(c_sdp_nof_bytes_per_statistic) ),
      ( field_name_pad("sdp_nof_statistics_per_packet"           ), "RW", 16, field_default(0) ),
      ( field_name_pad("sdp_block_period"                        ), "RW", 16, field_default(c_sdp_block_period) ),

      ( field_name_pad("dp_bsn"                                  ), "RW", 64, field_default(0) )
  );
  CONSTANT c_sdp_reg_stat_hdr_dat_addr_w : NATURAL := ceil_log2(field_nof_words(c_sdp_stat_hdr_field_arr, c_word_w));

  TYPE t_sdp_network_stat_header IS RECORD
    sdp_marker                              : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_version_id                          : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_observation_id                      : STD_LOGIC_VECTOR(31 DOWNTO 0);
    sdp_station_id                          : STD_LOGIC_VECTOR(15 DOWNTO 0);

    sdp_source_info_antenna_band_id         : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_nyquist_zone_id         : STD_LOGIC_VECTOR( 1 DOWNTO 0);
    sdp_source_info_f_adc                   : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_fsub_type               : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_payload_error           : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_beam_repositioning_flag : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_subband_calibrated_flag : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_reserved                : STD_LOGIC_VECTOR( 2 DOWNTO 0);
    sdp_source_info_gn_id                   : STD_LOGIC_VECTOR( 4 DOWNTO 0);

    sdp_reserved                            : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_integration_interval                : STD_LOGIC_VECTOR(23 DOWNTO 0);
    sdp_data_id                             : STD_LOGIC_VECTOR(31 DOWNTO 0);
    sdp_data_id_sst_signal_input_index      : STD_LOGIC_VECTOR( 7 DOWNTO  0);  -- sdp_data_id sub field
    sdp_data_id_bst_beamlet_index           : STD_LOGIC_VECTOR(15 DOWNTO  0);  -- sdp_data_id sub field
    sdp_data_id_xst_subband_index           : STD_LOGIC_VECTOR(24 DOWNTO 16);  -- sdp_data_id sub field
    sdp_data_id_xst_signal_input_A_index    : STD_LOGIC_VECTOR(15 DOWNTO  8);  -- sdp_data_id sub field
    sdp_data_id_xst_signal_input_B_index    : STD_LOGIC_VECTOR( 7 DOWNTO  0);  -- sdp_data_id sub field
    sdp_nof_signal_inputs                   : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_nof_bytes_per_statistic             : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_nof_statistics_per_packet           : STD_LOGIC_VECTOR(15 DOWNTO 0);
    sdp_block_period                        : STD_LOGIC_VECTOR(15 DOWNTO 0);

    dp_bsn                                  : STD_LOGIC_VECTOR(63 DOWNTO 0);
  END RECORD;

  TYPE t_sdp_stat_data_id IS RECORD
    sst_signal_input_index      : NATURAL RANGE 0 TO 2**8 - 1;   -- < 192 = c_sdp_N_pn_max * c_sdp_S_pn
    bst_beamlet_index           : NATURAL RANGE 0 TO 2**16 - 1;  -- < 976 = c_sdp_N_beamsets * c_sdp_S_sub_bf
    xst_subband_index           : NATURAL RANGE 0 TO 2**9 - 1;   -- < 512 = c_sdp_N_sub
    xst_signal_input_A_index    : NATURAL RANGE 0 TO 2**8 - 1;   -- < 192 = c_sdp_N_pn_max * c_sdp_S_pn
    xst_signal_input_B_index    : NATURAL RANGE 0 TO 2**8 - 1;   -- < 192 = c_sdp_N_pn_max * c_sdp_S_pn
  END RECORD;

  TYPE t_sdp_stat_header IS RECORD
    eth : t_network_eth_header;
    ip  : t_network_ip_header;
    udp : t_network_udp_header;
    app : t_sdp_network_stat_header;
  END RECORD;

  -----------------------------------------------------------------------------
  -- Beamlet output via 10GbE to CEP (= central processor)
  -----------------------------------------------------------------------------
  CONSTANT c_sdp_marker_beamlets : NATURAL := 98;  -- = x"62" = 'b'

  CONSTANT c_sdp_cep_eth_dst_mac       : STD_LOGIC_VECTOR(47 DOWNTO 0) := x"00074306C700"; -- 00074306C700 = DOP36-eth0
  CONSTANT c_sdp_cep_eth_src_mac_47_16 : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00228608";  -- 47:16, 15:8 = backplane, 7:0 = node
  CONSTANT c_sdp_cep_ip_dst_addr       : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"C0A80001";  -- C0A80001 = '192.168.0.1' = DOP36-eth0
  CONSTANT c_sdp_cep_ip_src_addr_31_16 : STD_LOGIC_VECTOR(15 DOWNTO 0) := x"C0A8";      -- 31:16, 15:8 = backplane, 7:0 = node + 1 = 192.168.xx.yy
  CONSTANT c_sdp_cep_ip_total_length   : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(7868, 16);  -- see ICD STAT-CEP
  CONSTANT c_sdp_cep_udp_total_length  : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(7848, 16);  -- see ICD STAT-CEP
  CONSTANT c_sdp_cep_udp_dst_port      : STD_LOGIC_VECTOR(15 DOWNTO 0) := TO_UVEC(5000, 16);
  CONSTANT c_sdp_cep_udp_src_port_15_8 : STD_LOGIC_VECTOR( 7 DOWNTO 0) := x"D0";        -- 15:8, 7:0 = gn_id (= ID[7:0] = backplane[5:0] & node[1:0])

  CONSTANT c_sdp_cep_app_header_len    : NATURAL := 32;

  CONSTANT c_sdp_cep_version_id             : NATURAL := 5;
  CONSTANT c_sdp_cep_nof_blocks_per_packet  : NATURAL := 4;
  CONSTANT c_sdp_cep_nof_beamlets_per_block : NATURAL := c_sdp_S_sub_bf; -- number of dual pol beamlets (c_sdp_N_pol_bf = 2)

  CONSTANT c_sdp_cep_nof_hdr_fields : NATURAL := 3+12+4+18+1; -- 592b; 9.25 64b words
  CONSTANT c_sdp_cep_hdr_field_sel  : STD_LOGIC_VECTOR(c_sdp_cep_nof_hdr_fields-1 DOWNTO 0) := "101"&"111111111001"&"0111"&"1100"&"00000010"&"000110"&"0";  -- 0=data path, 1=MM controlled TODO
--CONSTANT c_sdp_cep_hdr_field_sel  : STD_LOGIC_VECTOR(c_sdp_cep_nof_hdr_fields-1 DOWNTO 0) := "100"&"000000010001"&"0100"&"0100"&"00000000"&"101000"&"0";  -- 0=data path, 1=MM controlled TODO

  CONSTANT c_sdp_cep_hdr_field_arr : t_common_field_arr(c_sdp_cep_nof_hdr_fields-1 DOWNTO 0) := ( 
      ( field_name_pad("eth_dst_mac"                        ), "RW", 48, field_default(c_sdp_cep_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(c_sdp_cep_ip_total_length) ),
      ( 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(c_sdp_cep_ip_dst_addr) ),

      ( field_name_pad("udp_src_port"                       ), "RW", 16, field_default(0) ), 
      ( field_name_pad("udp_dst_port"                       ), "RW", 16, field_default(c_sdp_cep_udp_dst_port) ),
      ( field_name_pad("udp_total_length"                   ), "RW", 16, field_default(c_sdp_cep_udp_total_length) ),
      ( field_name_pad("udp_checksum"                       ), "RW", 16, field_default(0) ),

      ( field_name_pad("sdp_marker"                         ), "RW",  8, field_default(c_sdp_marker_beamlets) ),
      ( field_name_pad("sdp_version_id"                     ), "RW",  8, field_default(c_sdp_cep_version_id) ),
      ( field_name_pad("sdp_observation_id"                 ), "RW", 32, field_default(0) ),
      ( field_name_pad("sdp_station_id"                     ), "RW", 16, field_default(0) ),

      ( field_name_pad("sdp_source_info_antenna_band_id"    ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_nyquist_zone_id"    ), "RW",  2, field_default(0) ),
      ( field_name_pad("sdp_source_info_f_adc"              ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_fsub_type"          ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_payload_error"      ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_repositioning_flag" ), "RW",  1, field_default(0) ),
      ( field_name_pad("sdp_source_info_beamlet_width"      ), "RW",  4, field_default(c_sdp_W_beamlet) ),
      ( field_name_pad("sdp_source_info_gn_id"              ), "RW",  5, field_default(0) ),

      ( field_name_pad("sdp_reserved"                       ), "RW", 40, field_default(0) ),
      ( field_name_pad("sdp_beamlet_scale"                  ), "RW", 16, field_default(c_sdp_beamlet_scale_default) ),
      ( field_name_pad("sdp_beamlet_id"                     ), "RW", 16, field_default(0) ),
      ( field_name_pad("sdp_nof_blocks_per_packet"          ), "RW",  8, field_default(c_sdp_cep_nof_blocks_per_packet) ),
      ( field_name_pad("sdp_nof_beamlets_per_block"         ), "RW", 16, field_default(c_sdp_cep_nof_beamlets_per_block) ),
      ( field_name_pad("sdp_block_period"                   ), "RW", 16, field_default(c_sdp_block_period) ),

      ( field_name_pad("dp_bsn"                             ), "RW", 64, field_default(0) ) 
  );
  CONSTANT c_sdp_reg_cep_hdr_dat_addr_w : NATURAL := ceil_log2(field_nof_words(c_sdp_cep_hdr_field_arr, c_word_w));

  TYPE t_sdp_network_cep_header IS RECORD
    sdp_marker                              : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_version_id                          : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_observation_id                      : STD_LOGIC_VECTOR(31 DOWNTO 0);
    sdp_station_id                          : STD_LOGIC_VECTOR(15 DOWNTO 0);

    sdp_source_info_antenna_band_id         : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_nyquist_zone_id         : STD_LOGIC_VECTOR( 1 DOWNTO 0);
    sdp_source_info_f_adc                   : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_fsub_type               : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_payload_error           : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_repositioning_flag      : STD_LOGIC_VECTOR( 0 DOWNTO 0);
    sdp_source_info_beamlet_width           : STD_LOGIC_VECTOR( 3 DOWNTO 0);
    sdp_source_info_gn_id                   : STD_LOGIC_VECTOR( 4 DOWNTO 0);

    sdp_reserved                            : STD_LOGIC_VECTOR(39 DOWNTO 0);
    sdp_beamlet_scale                       : STD_LOGIC_VECTOR(15 DOWNTO 0);
    sdp_beamlet_id                          : STD_LOGIC_VECTOR(15 DOWNTO 0);
    sdp_nof_blocks_per_packet               : STD_LOGIC_VECTOR( 7 DOWNTO 0);
    sdp_nof_beamlets_per_block              : STD_LOGIC_VECTOR(15 DOWNTO 0);
    sdp_block_period                        : STD_LOGIC_VECTOR(15 DOWNTO 0);

    dp_bsn                                  : STD_LOGIC_VECTOR(63 DOWNTO 0);
  END RECORD;

  TYPE t_sdp_cep_header IS RECORD
    eth : t_network_eth_header;
    ip  : t_network_ip_header;
    udp : t_network_udp_header;
    app : t_sdp_network_cep_header;
  END RECORD;

  -----------------------------------------------------------------------------
  -- MM
  -----------------------------------------------------------------------------

  -- 10GbE MM address widths
  CONSTANT c_sdp_reg_bf_hdr_dat_addr_w      : NATURAL := ceil_log2(c_sdp_N_beamsets) + c_sdp_reg_cep_hdr_dat_addr_w;
  CONSTANT c_sdp_reg_nw_10GbE_mac_addr_w    : NATURAL := 13;
  CONSTANT c_sdp_reg_nw_10GbE_eth10g_addr_w : NATURAL := 1;

  -- JESD204
  CONSTANT c_sdp_jesd204b_freq             : STRING := "200MHz";
  CONSTANT c_sdp_jesd204b_mm_jesd_ctrl_reg : t_c_mem := (latency  => 1,
                                                         adr_w    => 1,
                                                         dat_w    => c_word_w,
                                                         nof_dat  => 1,
                                                         init_sl  => '0');

  -- AIT MM address widths
  CONSTANT c_sdp_jesd204b_addr_w               : NATURAL := ceil_log2(c_sdp_S_pn) + 8; 
  CONSTANT c_sdp_jesd_ctrl_addr_w              : NATURAL := 1; 
  CONSTANT c_sdp_reg_bsn_monitor_input_addr_w  : NATURAL := 8;
  CONSTANT c_sdp_reg_wg_addr_w                 : NATURAL := ceil_log2(c_sdp_S_pn) + 2; 
  CONSTANT c_sdp_ram_wg_addr_w                 : NATURAL := ceil_log2(c_sdp_S_pn) + 10; 
  CONSTANT c_sdp_reg_dp_shiftram_addr_w        : NATURAL := ceil_log2(c_sdp_S_pn) + 1; 
  CONSTANT c_sdp_reg_bsn_source_v2_addr_w      : NATURAL := 3;
  CONSTANT c_sdp_reg_bsn_scheduler_addr_w      : NATURAL := 1;
  CONSTANT c_sdp_ram_diag_data_buf_bsn_addr_w  : NATURAL := ceil_log2(c_sdp_S_pn) + ceil_log2(c_sdp_V_si_db_large); -- Dimension DB address range for largest DB, so that both the large and the default small DB fit.
  CONSTANT c_sdp_reg_diag_data_buf_bsn_addr_w  : NATURAL := ceil_log2(c_sdp_S_pn) + 1;  
  CONSTANT c_sdp_ram_st_histogram_addr_w       : NATURAL := ceil_log2(c_sdp_S_pn) + ceil_log2(c_sdp_V_si_histogram); 
  CONSTANT c_sdp_reg_aduh_monitor_addr_w       : NATURAL := ceil_log2(c_sdp_S_pn) + 2;
  -- FSUB MM address widths
  CONSTANT c_sdp_ram_fil_coefs_addr_w       : NATURAL := ceil_log2(c_sdp_N_fft * c_sdp_N_taps);
  CONSTANT c_sdp_ram_st_sst_addr_w          : NATURAL := ceil_log2(c_sdp_P_pfb * c_sdp_N_sub * c_sdp_Q_fft * c_sdp_W_statistic_sz);
  CONSTANT c_sdp_reg_si_addr_w              : NATURAL := 1; --enable/disable
  CONSTANT c_sdp_ram_equalizer_gains_addr_w : NATURAL := ceil_log2(c_sdp_P_pfb*c_sdp_N_sub*c_sdp_Q_fft);
  CONSTANT c_sdp_reg_dp_selector_addr_w     : NATURAL := 1; --Select input 0 or 1.

  -- STAT UDP offload MM address widths
  CONSTANT c_sdp_reg_stat_enable_addr_w     : NATURAL  := 1;

  -- BF MM address widths
  CONSTANT c_sdp_reg_sdp_info_addr_w        : NATURAL := 4;  
  CONSTANT c_sdp_ram_ss_ss_wide_addr_w      : NATURAL := ceil_log2(c_sdp_N_beamsets) + ceil_log2(c_sdp_P_pfb * c_sdp_S_sub_bf * c_sdp_Q_fft);
  CONSTANT c_sdp_ram_bf_weights_addr_w      : NATURAL := ceil_log2(c_sdp_N_beamsets) + ceil_log2(c_sdp_N_pol_bf * c_sdp_P_pfb * c_sdp_S_sub_bf * c_sdp_Q_fft);
  CONSTANT c_sdp_reg_bf_scale_addr_w        : NATURAL := ceil_log2(c_sdp_N_beamsets) + 1;  
  CONSTANT c_sdp_reg_dp_xonoff_addr_w       : NATURAL := ceil_log2(c_sdp_N_beamsets) + 1;
  CONSTANT c_sdp_ram_st_bst_addr_w          : NATURAL := ceil_log2(c_sdp_N_beamsets) + ceil_log2(c_sdp_S_sub_bf * c_sdp_N_pol_bf * c_sdp_W_statistic_sz);
  CONSTANT c_sdp_reg_stat_enable_bst_addr_w : NATURAL := ceil_log2(c_sdp_N_beamsets) + c_sdp_reg_stat_enable_addr_w;
  CONSTANT c_sdp_reg_stat_hdr_dat_bst_addr_w: NATURAL := ceil_log2(c_sdp_N_beamsets) + c_sdp_reg_stat_hdr_dat_addr_w;

  -- XSUB
  CONSTANT c_sdp_crosslets_index_w          : NATURAL := ceil_log2(c_sdp_N_sub);
  CONSTANT c_sdp_mm_reg_crosslets_info : t_c_mem := (latency  => 1,
                                                     adr_w    => 4,
                                                     dat_w    => c_sdp_crosslets_index_w,  
                                                     nof_dat  => 16,        -- 15 offsets + 1 step
                                                     init_sl  => '0');
  CONSTANT c_sdp_crosslets_info_reg_w       : NATURAL := c_sdp_mm_reg_crosslets_info.nof_dat*c_sdp_mm_reg_crosslets_info.dat_w;
  CONSTANT c_sdp_crosslets_info_nof_offsets : NATURAL := c_sdp_mm_reg_crosslets_info.nof_dat - 1;

  TYPE t_sdp_crosslets_info IS RECORD
    offset_arr : t_natural_arr(0 TO c_sdp_crosslets_info_nof_offsets-1);
    step       : NATURAL;
  END RECORD;

  CONSTANT c_sdp_mm_reg_nof_crosslets  : t_c_mem := (latency  => 1,
                                                     adr_w    => 1,
                                                     dat_w    => ceil_log2(c_sdp_N_crosslets_max+1),  
                                                     nof_dat  => 1,
                                                     init_sl  => '0'); -- Default = 1
  CONSTANT c_sdp_nof_crosslets_reg_w : NATURAL := c_sdp_mm_reg_nof_crosslets.nof_dat*c_sdp_mm_reg_nof_crosslets.dat_w;

  CONSTANT c_sdp_xst_nof_clk_per_sync_min : NATURAL := c_sdp_N_clk_per_sync / 10; -- 0.1 second

  -- XSUB MM address widths
  CONSTANT c_sdp_reg_crosslets_info_addr_w          : NATURAL := c_sdp_mm_reg_crosslets_info.adr_w;
  CONSTANT c_sdp_reg_nof_crosslets_addr_w           : NATURAL := c_sdp_mm_reg_nof_crosslets.adr_w;
  CONSTANT c_sdp_reg_bsn_sync_scheduler_xsub_addr_w : NATURAL := 4; 
  CONSTANT c_sdp_ram_st_xsq_addr_w                  : NATURAL := ceil_log2(c_sdp_N_crosslets_max * c_sdp_X_sq * c_nof_complex * c_sdp_W_statistic_sz);
  CONSTANT c_sdp_ram_st_xsq_arr_addr_w              : NATURAL := ceil_log2(c_sdp_P_sq) + c_sdp_ram_st_xsq_addr_w;

  -- RING MM address widths
  CONSTANT c_sdp_reg_bsn_monitor_v2_ring_rx_addr_w        : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + ceil_log2(c_sdp_N_pn_max) + ceil_Log2(7); 
  CONSTANT c_sdp_reg_bsn_monitor_v2_ring_tx_addr_w        : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + ceil_log2(c_sdp_N_pn_max) + ceil_Log2(7); 
  CONSTANT c_sdp_reg_ring_lane_info_addr_w                : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + 1; 
  CONSTANT c_sdp_reg_dp_xonoff_lane_addr_w                : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + 1; 
  CONSTANT c_sdp_reg_dp_xonoff_local_addr_w               : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + 1; 
  CONSTANT c_sdp_reg_dp_block_validate_err_addr_w         : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + 4; 
  CONSTANT c_sdp_reg_dp_block_validate_bsn_at_sync_addr_w : NATURAL := ceil_log2(c_sdp_N_ring_lanes_max) + 2; 
  CONSTANT c_sdp_reg_ring_info_addr_w                     : NATURAL := 2; 
  CONSTANT c_sdp_reg_tr_10GbE_mac_addr_w                  : NATURAL := 13; 
  CONSTANT c_sdp_reg_tr_10GbE_eth10g_addr_w               : NATURAL := 1; 
  CONSTANT c_sdp_reg_diag_bg_addr_w                       : NATURAL := 3;
  CONSTANT c_sdp_ram_diag_bg_addr_w                       : NATURAL := 7;

  -------------------------------------------------
  -- SDP simulation constants record, to use instead of HW default when g_sim = TRUE
  -------------------------------------------------
  TYPE t_sdp_sim IS RECORD
    xst_nof_clk_per_sync_min : NATURAL;
    offload_time             : NATURAL;  -- select > 0 and gn_index > 0 to see effect of offload_time on statistics offload
    sync_timeout             : NATURAL;
    unb_nr                   : NATURAL;
    node_nr                  : NATURAL;
  END RECORD;

  CONSTANT c_sdp_sim : t_sdp_sim := (1, 10, 3*1024, 0, 0);

  -------------------------------------------------
  -- SDP functions
  -------------------------------------------------

  FUNCTION func_sdp_gn_index_to_pn_index(gn_index : NATURAL) RETURN NATURAL;
  FUNCTION func_sdp_modulo_N_sub(sub_index : NATURAL) RETURN NATURAL;

  FUNCTION func_sdp_get_stat_marker(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_nof_signal_inputs(g_statistics_type : STRING) RETURN NATURAL;

  -- nof_statistics_per_packet = mm_nof_data * mm_data_size / c_sdp_W_statistic_sz
  FUNCTION func_sdp_get_stat_from_mm_data_size(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_from_mm_step_size(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_from_mm_nof_data(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_nof_statistics_per_packet(g_statistics_type : STRING) RETURN NATURAL;

  FUNCTION func_sdp_get_stat_app_total_length(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_udp_total_length(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_ip_total_length(g_statistics_type : STRING) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING; S_pn, P_sq, N_crosslets : NATURAL) RETURN NATURAL;
  FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING) RETURN NATURAL;  -- use c_sdp_S_pn, c_sdp_P_sq, c_sdp_N_crosslets_max

  FUNCTION func_sdp_map_stat_header(hdr_fields_raw : STD_LOGIC_VECTOR) RETURN t_sdp_stat_header;
  FUNCTION func_sdp_map_cep_header(hdr_fields_raw : STD_LOGIC_VECTOR) RETURN t_sdp_cep_header;

  FUNCTION func_sdp_map_stat_data_id(g_statistics_type : STRING; data_id_slv : STD_LOGIC_VECTOR) RETURN t_sdp_stat_data_id;
  FUNCTION func_sdp_map_stat_data_id(g_statistics_type : STRING; data_id_rec : t_sdp_stat_data_id) RETURN STD_LOGIC_VECTOR;

  FUNCTION func_sdp_map_crosslets_info(info_slv : STD_LOGIC_VECTOR) RETURN t_sdp_crosslets_info;  -- map all c_sdp_N_crosslets_max offsets
  FUNCTION func_sdp_map_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN STD_LOGIC_VECTOR;  -- map all c_sdp_N_crosslets_max offsets
  FUNCTION func_sdp_step_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN t_sdp_crosslets_info;  -- step all c_sdp_N_crosslets_max offsets

END PACKAGE sdp_pkg;

PACKAGE BODY sdp_pkg IS

  FUNCTION func_sdp_gn_index_to_pn_index(gn_index : NATURAL) RETURN NATURAL IS
    -- Determine PN index that starts at 0 per antenna band.
    -- For LOFAR2 SDP there are two antenna bands: LB and HB. The LB starts at
    -- GN index = 0 and has c_sdp_N_pn_lb = c_sdp_N_pn_max = 16 nodes. The HB
    -- starts at c_sdp_N_pn_max. Assume every antenna_band starts at a GN:
    --
    --   pn_index = gn_index MOD c_sdp_N_pn_max
    --
    -- The fact that c_sdp_N_pn_max = 16 implies that instead of implementing
    -- MOD it is possible to do:
    --
    --   pn_index = gn_index[3:0], because log2(16) = 4
    CONSTANT c_w  : NATURAL := ceil_log2(c_sdp_N_pn_max);  -- = 4

    VARIABLE v_index : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := TO_UVEC(gn_index, c_word_w);
  BEGIN
    RETURN TO_UINT(v_index(c_w-1 DOWNTO 0));
  END func_sdp_gn_index_to_pn_index;

  FUNCTION func_sdp_modulo_N_sub(sub_index : NATURAL) RETURN NATURAL IS
  BEGIN
    ASSERT sub_index < 2 * c_sdp_N_sub REPORT "func_sdp_modulo_N_sub: sub_index too large" SEVERITY FAILURE;
    IF sub_index < c_sdp_N_sub-1 THEN
      RETURN sub_index;
    ELSE
      RETURN sub_index - c_sdp_N_sub;
    END IF;
  END func_sdp_modulo_N_sub;

  FUNCTION func_sdp_get_stat_marker(g_statistics_type : STRING) RETURN NATURAL IS
    CONSTANT c_marker_sst : NATURAL := 83;  -- = 0x53 = 'S'
    CONSTANT c_marker_bst : NATURAL := 66;  -- = 0x42 = 'B'
    CONSTANT c_marker_xst : NATURAL := 88;  -- = 0x58 = 'X'
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", c_marker_bst,
           sel_a_b(g_statistics_type="XST", c_marker_xst,
                                            c_marker_sst));  -- SST
  END func_sdp_get_stat_marker;

  FUNCTION func_sdp_get_stat_nof_signal_inputs(g_statistics_type : STRING) RETURN NATURAL IS
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", 0,  -- not applicable for BST, so use 0,
           sel_a_b(g_statistics_type="XST", c_sdp_S_pn,
                                            1));  -- SST
  END func_sdp_get_stat_nof_signal_inputs;

  FUNCTION func_sdp_get_stat_from_mm_data_size(g_statistics_type : STRING) RETURN NATURAL IS
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", c_sdp_N_pol_bf * c_sdp_W_statistic_sz,   -- = 4
           sel_a_b(g_statistics_type="XST", c_nof_complex  * c_sdp_W_statistic_sz,   -- = 4
                                                             c_sdp_W_statistic_sz)); -- = 2, SST
  END func_sdp_get_stat_from_mm_data_size;

  FUNCTION func_sdp_get_stat_from_mm_step_size(g_statistics_type : STRING) RETURN NATURAL IS
    CONSTANT c_data_size : NATURAL := func_sdp_get_stat_from_mm_data_size(g_statistics_type);
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", c_data_size,                  -- = 4
           sel_a_b(g_statistics_type="XST", c_data_size,                  -- = 4
                                            c_data_size * c_sdp_Q_fft));  -- = 4, SST
  END func_sdp_get_stat_from_mm_step_size;

  FUNCTION func_sdp_get_stat_from_mm_nof_data(g_statistics_type : STRING) RETURN NATURAL IS
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", c_sdp_S_sub_bf,  -- = 488
           sel_a_b(g_statistics_type="XST", c_sdp_X_sq,      -- = 144
                                            c_sdp_N_sub));   -- = 512, SST
  END func_sdp_get_stat_from_mm_nof_data;

  -- nof_statistics_per_packet = mm_nof_data * mm_data_size / c_sdp_W_statistic_sz
  FUNCTION func_sdp_get_stat_nof_statistics_per_packet(g_statistics_type : STRING) RETURN NATURAL IS
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", c_sdp_S_sub_bf * c_sdp_N_pol_bf,  -- = 976
           sel_a_b(g_statistics_type="XST", c_sdp_X_sq * c_nof_complex,       -- = 288
                                            c_sdp_N_sub));                    -- = 512, SST
  END func_sdp_get_stat_nof_statistics_per_packet;

  FUNCTION func_sdp_get_stat_app_total_length(g_statistics_type : STRING) RETURN NATURAL IS
    CONSTANT c_nof_statistics_per_packet : NATURAL := func_sdp_get_stat_nof_statistics_per_packet(g_statistics_type);
  BEGIN
    -- RETURN:
    -- . SST : 4128 (= 4096 + 32)
    -- . BST : 7840 (= 7808 + 32)
    -- . XST : 2336 (= 2304 + 32)
    RETURN c_nof_statistics_per_packet * c_sdp_nof_bytes_per_statistic + c_sdp_stat_app_header_len;
  END func_sdp_get_stat_app_total_length;

  FUNCTION func_sdp_get_stat_udp_total_length(g_statistics_type : STRING) RETURN NATURAL IS
    CONSTANT c_sdp_app_total_length : NATURAL := func_sdp_get_stat_app_total_length(g_statistics_type);
  BEGIN
    -- RETURN:
    -- . SST : 4136 (= 4128 + 8)
    -- . BST : 7848 (= 7840 + 8)
    -- . XST : 2344 (= 2336 + 8)
    RETURN c_sdp_app_total_length + c_network_udp_header_len;
  END func_sdp_get_stat_udp_total_length;
  FUNCTION func_sdp_get_stat_ip_total_length(g_statistics_type : STRING) RETURN NATURAL IS
    CONSTANT c_sdp_udp_total_length : NATURAL := func_sdp_get_stat_udp_total_length(g_statistics_type);
  BEGIN
    -- RETURN:
    -- . SST : 4156 (= 4136 + 20)
    -- . BST : 7868 (= 7848 + 20)
    -- . XST : 2364 (= 2344 + 20)
    RETURN c_sdp_udp_total_length + c_network_ip_header_len;
  END func_sdp_get_stat_ip_total_length;

  FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING; S_pn, P_sq, N_crosslets : NATURAL) RETURN NATURAL IS
  BEGIN
    RETURN sel_a_b(g_statistics_type="BST", 1,
           sel_a_b(g_statistics_type="XST", P_sq * N_crosslets,
                                            S_pn));  -- SST
  END func_sdp_get_stat_nof_packets;

  FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING) RETURN NATURAL IS
  BEGIN
    RETURN func_sdp_get_stat_nof_packets(g_statistics_type, c_sdp_S_pn, c_sdp_P_sq, c_sdp_N_crosslets_max);
  END func_sdp_get_stat_nof_packets;


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

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

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

    -- app header
    v.app.sdp_marker                              := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_marker")         DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_marker"));
    v.app.sdp_version_id                          := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_version_id")     DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_version_id"));
    v.app.sdp_observation_id                      := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_observation_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_observation_id"));
    v.app.sdp_station_id                          := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_station_id")     DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_station_id"));

    v.app.sdp_source_info_antenna_band_id         := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_antenna_band_id")         DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_antenna_band_id"));
    v.app.sdp_source_info_nyquist_zone_id         := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_nyquist_zone_id")         DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_nyquist_zone_id"));
    v.app.sdp_source_info_f_adc                   := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_f_adc")                   DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_f_adc"));
    v.app.sdp_source_info_fsub_type               := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_fsub_type")               DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_fsub_type"));
    v.app.sdp_source_info_payload_error           := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_payload_error")           DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_payload_error"));
    v.app.sdp_source_info_beam_repositioning_flag := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_beam_repositioning_flag") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_beam_repositioning_flag"));
    v.app.sdp_source_info_subband_calibrated_flag := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_subband_calibrated_flag") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_subband_calibrated_flag"));
    v.app.sdp_source_info_reserved                := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_reserved")                DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_reserved"));
    v.app.sdp_source_info_gn_id                   := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_gn_id")                   DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_gn_id"));

    v.app.sdp_reserved                            := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_reserved")                  DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_reserved"));
    v.app.sdp_integration_interval                := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_integration_interval")      DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_integration_interval"));
    v.app.sdp_data_id                             := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_data_id")                   DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_data_id"));
    v.app.sdp_data_id_sst_signal_input_index      := v.app.sdp_data_id( 7 DOWNTO  0);
    v.app.sdp_data_id_bst_beamlet_index           := v.app.sdp_data_id(15 DOWNTO  0);
    v.app.sdp_data_id_xst_subband_index           := v.app.sdp_data_id(24 DOWNTO 16);
    v.app.sdp_data_id_xst_signal_input_A_index    := v.app.sdp_data_id(15 DOWNTO  8);
    v.app.sdp_data_id_xst_signal_input_B_index    := v.app.sdp_data_id( 7 DOWNTO  0);
    v.app.sdp_nof_signal_inputs                   := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_signal_inputs")         DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_signal_inputs"));
    v.app.sdp_nof_bytes_per_statistic             := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_bytes_per_statistic")   DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_bytes_per_statistic"));
    v.app.sdp_nof_statistics_per_packet           := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_statistics_per_packet") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_statistics_per_packet"));
    v.app.sdp_block_period                        := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_block_period")              DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_block_period"));

    v.app.dp_bsn                                  := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "dp_bsn") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "dp_bsn"));
    RETURN v;
  END func_sdp_map_stat_header;


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

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

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

    -- app header
    v.app.sdp_marker                         := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_marker")         DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_marker"));
    v.app.sdp_version_id                     := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_version_id")     DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_version_id"));
    v.app.sdp_observation_id                 := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_observation_id") DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_observation_id"));
    v.app.sdp_station_id                     := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_station_id")     DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_station_id"));

    v.app.sdp_source_info_antenna_band_id    := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_antenna_band_id")    DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_antenna_band_id"));
    v.app.sdp_source_info_nyquist_zone_id    := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_nyquist_zone_id")    DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_nyquist_zone_id"));
    v.app.sdp_source_info_f_adc              := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_f_adc")              DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_f_adc"));
    v.app.sdp_source_info_fsub_type          := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_fsub_type")          DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_fsub_type"));
    v.app.sdp_source_info_payload_error      := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_payload_error")      DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_payload_error"));
    v.app.sdp_source_info_repositioning_flag := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_repositioning_flag") DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_repositioning_flag"));
    v.app.sdp_source_info_beamlet_width      := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_beamlet_width")      DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_beamlet_width"));
    v.app.sdp_source_info_gn_id              := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_source_info_gn_id")              DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_source_info_gn_id"));

    v.app.sdp_reserved                       := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_reserved")               DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_reserved"));
    v.app.sdp_beamlet_scale                  := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_beamlet_scale")          DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_beamlet_scale"));
    v.app.sdp_beamlet_id                     := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_beamlet_id")             DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_beamlet_id"));
    v.app.sdp_nof_blocks_per_packet          := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_nof_blocks_per_packet")  DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_nof_blocks_per_packet"));
    v.app.sdp_nof_beamlets_per_block         := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_nof_beamlets_per_block") DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_nof_beamlets_per_block"));
    v.app.sdp_block_period                   := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "sdp_block_period")           DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "sdp_block_period"));

    v.app.dp_bsn                             := hdr_fields_raw(field_hi(c_sdp_cep_hdr_field_arr, "dp_bsn") DOWNTO field_lo(c_sdp_cep_hdr_field_arr, "dp_bsn"));
    RETURN v;
  END func_sdp_map_cep_header;

  FUNCTION func_sdp_map_stat_data_id(g_statistics_type : STRING; data_id_slv : STD_LOGIC_VECTOR) RETURN t_sdp_stat_data_id IS
    VARIABLE v_rec : t_sdp_stat_data_id;
  BEGIN
    IF g_statistics_type = "SST" THEN
      v_rec.sst_signal_input_index := TO_UINT(data_id_slv(7 DOWNTO 0));
    ELSIF g_statistics_type = "BST" THEN
      v_rec.bst_beamlet_index := TO_UINT(data_id_slv(15 DOWNTO 0));
    ELSIF g_statistics_type = "XST" THEN
      v_rec.xst_subband_index := TO_UINT(data_id_slv(24 DOWNTO 16));
      v_rec.xst_signal_input_A_index := TO_UINT(data_id_slv(15 DOWNTO 8));
      v_rec.xst_signal_input_B_index := TO_UINT(data_id_slv(7 DOWNTO 0));
    END IF;
    RETURN v_rec;
  END func_sdp_map_stat_data_id;

  FUNCTION func_sdp_map_stat_data_id(g_statistics_type : STRING; data_id_rec : t_sdp_stat_data_id) RETURN STD_LOGIC_VECTOR IS
    VARIABLE v_slv : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"00000000";
  BEGIN
    IF g_statistics_type = "SST" THEN
      v_slv(7 DOWNTO 0) := TO_UVEC(data_id_rec.sst_signal_input_index, 8);
    ELSIF g_statistics_type = "BST" THEN
      v_slv(15 DOWNTO 0) := TO_UVEC(data_id_rec.bst_beamlet_index, 16);
    ELSIF g_statistics_type = "XST" THEN
      v_slv(24 DOWNTO 16) := TO_UVEC(data_id_rec.xst_subband_index, 9);
      v_slv(15 DOWNTO 8) := TO_UVEC(data_id_rec.xst_signal_input_A_index, 8);
      v_slv(7 DOWNTO 0) := TO_UVEC(data_id_rec.xst_signal_input_B_index, 8);
    END IF;
    RETURN v_slv;
  END func_sdp_map_stat_data_id;


  FUNCTION func_sdp_map_crosslets_info(info_slv : STD_LOGIC_VECTOR) RETURN t_sdp_crosslets_info IS
    VARIABLE v_info : t_sdp_crosslets_info;
  BEGIN
    FOR I IN 0 TO c_sdp_crosslets_info_nof_offsets-1 LOOP  -- map al offsets
      v_info.offset_arr(I) := TO_UINT(info_slv((I+1)*c_sdp_crosslets_index_w-1 DOWNTO I*c_sdp_crosslets_index_w));
    END LOOP;
    v_info.step := TO_UINT(info_slv(c_sdp_crosslets_info_reg_w-1 DOWNTO c_sdp_crosslets_info_reg_w - c_sdp_crosslets_index_w));
    RETURN v_info;
  END func_sdp_map_crosslets_info;

  FUNCTION func_sdp_map_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN STD_LOGIC_VECTOR IS
    VARIABLE v_info : STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0);
  BEGIN
    FOR I IN 0 TO c_sdp_crosslets_info_nof_offsets-1 LOOP  -- map all offsets
      v_info((I+1)*c_sdp_crosslets_index_w-1 DOWNTO I*c_sdp_crosslets_index_w) := TO_UVEC(info_rec.offset_arr(I), c_sdp_crosslets_index_w);
    END LOOP;
    v_info(c_sdp_crosslets_info_reg_w-1 DOWNTO c_sdp_crosslets_info_reg_w - c_sdp_crosslets_index_w) := TO_UVEC(info_rec.step, c_sdp_crosslets_index_w);
    RETURN v_info;
  END func_sdp_map_crosslets_info;


  FUNCTION func_sdp_step_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN t_sdp_crosslets_info IS
    VARIABLE v_info : t_sdp_crosslets_info := info_rec;
  BEGIN
    FOR I IN 0 TO c_sdp_crosslets_info_nof_offsets-1 LOOP  -- step all offsets
      v_info.offset_arr(I) := v_info.offset_arr(I) + v_info.step;
    END LOOP;
    RETURN v_info;
  END func_sdp_step_crosslets_info;

END sdp_pkg;