From bcee66efc44aafcd0c18e13b68a89346c59fdd14 Mon Sep 17 00:00:00 2001
From: Eric Kooistra <kooistra@astron.nl>
Date: Fri, 26 Nov 2021 10:30:40 +0100
Subject: [PATCH] Added t_sdp_sim. Add func_sdp_get_stat_*() functions to
 determine the header field parameters. Add t_sdp_network_stat_header and
 t_sdp_network_cep_header with extract functions.

---
 .../lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd | 400 ++++++++++++++++--
 1 file changed, 353 insertions(+), 47 deletions(-)

diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd
index 4dbd3fd7db..336551d932 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd
@@ -33,6 +33,7 @@ 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; 
@@ -117,17 +118,16 @@ PACKAGE sdp_pkg is
   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]
 
-  -- 
-  CONSTANT c_sdp_marker_sst : NATURAL := 83;  -- = 0x53 = 'S'
-  CONSTANT c_sdp_marker_bst : NATURAL := 66;  -- = 0x42 = 'B'
-  CONSTANT c_sdp_marker_xst : NATURAL := 88;  -- = 0x58 = 'X'
+  -- Default / tb values
+  CONSTANT c_sdp_beamlet_scale_default   : NATURAL := 2**15;
 
-  --CONSTANT c_sdp_offload_time : NATURAL := 13000;  -- from wave window 62855nS / 5nS = 12571 cycles.
-  CONSTANT c_sdp_offload_time : NATURAL := 600000;  
- 
+  -----------------------------------------------------------------------------
+  -- PFB
+  -----------------------------------------------------------------------------
 
-  -- In SDP c_nof_channels = 2**nof_chan = 1 and wb_factor = 1, 
+  -- 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 :=
@@ -143,13 +143,16 @@ PACKAGE sdp_pkg is
   -- . 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, 2, 195313, c_fft_pipeline, c_fft_pipeline, 
-   c_fil_ppf_pipeline);
+    (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, 2, 195313, c_fft_pipeline, c_fft_pipeline,
+    c_fil_ppf_pipeline);
+
+  -----------------------------------------------------------------------------
+  -- Statistics offload
+  -----------------------------------------------------------------------------
 
-  -- 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
@@ -157,22 +160,42 @@ PACKAGE sdp_pkg is
   -- 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
 
+  --CONSTANT c_sdp_offload_time : NATURAL := 13000;  -- from wave window 62855nS / 5nS = 12571 cycles.
+  CONSTANT c_sdp_offload_time : NATURAL := 600000;  -- L2SDP-452
+
+  -- packet lengths, see ICD SC-SDP
+  CONSTANT c_sdp_stat_app_header_len    : NATURAL := 32;
+
+  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;
+  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;
+  -- Note:
+  -- . For XST func_sdp_get_stat_nof_packets returns the maximum nof_packets.
+  --   The actual nof_packets for XST will depend on the MM programmable
+  --   nof_crosslets <= c_sdp_N_crosslets_max in sdp_statistics_offload.
+  FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING; S_pn, P_sq : NATURAL) RETURN NATURAL;
+  FUNCTION func_sdp_get_stat_nof_packets(g_statistics_type : STRING) RETURN NATURAL;
+
+  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_sst_udp_src_port_15_8  : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"D0";  -- TBC
-  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_cep_app_header_len  : NATURAL := 32;
-  CONSTANT c_sdp_stat_app_header_len : NATURAL := 32;
+  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
+  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_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"&"0101"&"0100"&"000000000"&"0000100"&"0";  -- 0=data path, 1=MM controlled TODO
---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_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"&"0101"&"0100"&"000000000"&"0000100"&"0";  -- 0=data path, 1=MM controlled TODO
+--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) ),
-      ( field_name_pad("eth_dst_mac"                             ), "RW", 48, field_default(x"001B217176B9") ), -- 001B217176B9 = DOP36-enp2s0 
+      ( 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") ),
 
@@ -187,15 +210,15 @@ PACKAGE sdp_pkg is
       ( 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(x"0A6300FE") ), -- 0A6300FE = DOP36-enp2s0 '10.99.0.254'
+      ( 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(5001) ), 
+      ( 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(5) ),
+      ( 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) ),
 
@@ -215,32 +238,86 @@ PACKAGE sdp_pkg is
       ( field_name_pad("sdp_nof_signal_inputs"                   ), "RW",  8, field_default(0) ),
       ( field_name_pad("sdp_nof_bytes_per_statistics"            ), "RW",  8, field_default(8) ),
       ( field_name_pad("sdp_nof_statistics_per_packet"           ), "RW", 16, field_default(0) ),
-      ( field_name_pad("sdp_block_period"                        ), "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));
-
-  -- 10GbE offload (cep = central processor)
+  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_statistics            : 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_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;
+
+  FUNCTION func_sdp_extract_stat_header(hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0)) RETURN t_sdp_stat_header;
+
+  -----------------------------------------------------------------------------
+  -- 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_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(x"00074306C700") ), -- 00074306C700=DOP36-eth0 
+      ( 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(7868) ), 
+      ( 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) ),
@@ -248,15 +325,15 @@ PACKAGE sdp_pkg is
       ( 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(x"C0A80001") ), -- C0A80001=DOP36-eth0 '192.168.0.1'
+      ( 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(5000) ), 
-      ( field_name_pad("udp_total_length"                   ), "RW", 16, field_default(7848) ), 
+      ( 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(x"62") ),
-      ( field_name_pad("sdp_version_id"                     ), "RW",  8, field_default(5) ),
+      ( 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) ),
 
@@ -270,19 +347,56 @@ PACKAGE sdp_pkg is
       ( 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(2**15) ),
+      ( 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(5120) ),
+      ( field_name_pad("sdp_block_period"                   ), "RW", 16, field_default(c_sdp_block_period) ),
 
       ( field_name_pad("dp_bsn"                             ), "RW", 64, field_default(0) ) 
   );
-  -- ST UDP offload MM address widths
-  CONSTANT c_sdp_reg_stat_enable_addr_w : NATURAL  := 1;  
+  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;
+
+  FUNCTION sdp_extract_cep_header(hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0)) RETURN t_sdp_cep_header;
+
+  -----------------------------------------------------------------------------
+  -- MM
+  -----------------------------------------------------------------------------
 
   -- 10GbE MM address widths
-  CONSTANT c_sdp_reg_hdr_dat_addr_w         : NATURAL := ceil_log2(c_sdp_N_beamsets) + ceil_log2(field_nof_words(c_sdp_cep_hdr_field_arr, c_word_w));
+  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;
 
@@ -294,7 +408,6 @@ PACKAGE sdp_pkg is
                                                          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; 
@@ -316,6 +429,9 @@ PACKAGE sdp_pkg is
   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);
@@ -364,11 +480,201 @@ PACKAGE sdp_pkg is
   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
+  END RECORD;
+
+  CONSTANT c_sdp_sim : t_sdp_sim := (1, 10);
 
 END PACKAGE sdp_pkg;
 
 PACKAGE BODY sdp_pkg IS
 
-  
-END sdp_pkg;
+  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_nof_statistics_per_packet(g_statistics_type : STRING) RETURN NATURAL IS
+  BEGIN
+    RETURN sel_a_b(g_statistics_type="BST", c_sdp_N_pol_bf * c_sdp_S_sub_bf,          -- = 976
+           sel_a_b(g_statistics_type="XST", c_sdp_S_pn * c_sdp_S_pn * 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_longword_sz + 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 : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN sel_a_b(g_statistics_type="BST", 1,
+           sel_a_b(g_statistics_type="XST", P_sq * c_sdp_N_crosslets_max,
+                                            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);
+  END func_sdp_get_stat_nof_packets;
+
+
+  FUNCTION func_sdp_extract_stat_header(hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0)) 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_statistics            := hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_bytes_per_statistics")  DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_bytes_per_statistics"));
+    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_extract_stat_header;
+
+
+  FUNCTION sdp_extract_cep_header(hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0)) 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 sdp_extract_cep_header;
 
+END sdp_pkg;
-- 
GitLab