diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd index 5512ee4aac84bb1d3d44c52ca0b82674514ed22c..0f8a3a8ef3292b6dc867f29ea8e3c4eb558b2bc3 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd @@ -20,7 +20,7 @@ ------------------------------------------------------------------------------- -- --- Author: R. van der Walle +-- Author: R. van der Walle, E. Kooistra -- Purpose: -- . This package contains sdp specific constants. -- Description: @@ -161,6 +161,7 @@ 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 + -- 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 @@ -169,22 +170,6 @@ PACKAGE sdp_pkg is 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_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; - -- 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, nof_crosslets : 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 @@ -283,6 +268,14 @@ PACKAGE sdp_pkg is 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; @@ -290,8 +283,6 @@ PACKAGE sdp_pkg is 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) ----------------------------------------------------------------------------- @@ -396,8 +387,6 @@ PACKAGE sdp_pkg is 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 ----------------------------------------------------------------------------- @@ -464,9 +453,6 @@ PACKAGE sdp_pkg is step : NATURAL; END RECORD; - FUNCTION func_extract_crosslets_info(info_slv : STD_LOGIC_VECTOR) RETURN t_sdp_crosslets_info; - FUNCTION func_construct_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN STD_LOGIC_VECTOR; - 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), @@ -480,7 +466,8 @@ PACKAGE sdp_pkg is 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_P_sq) + 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_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); @@ -506,10 +493,71 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_sim : t_sdp_sim := (1, 10); + ------------------------------------------------- + -- 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; + 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; nof_crosslets : NATURAL) RETURN t_sdp_crosslets_info; -- map only the used offsets + 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; nof_crosslets : NATURAL) RETURN STD_LOGIC_VECTOR; -- map only the used 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; nof_crosslets : NATURAL) RETURN t_sdp_crosslets_info; + 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_pn_w : NATURAL := ceil_log2(c_sdp_N_pn_max); -- = 4 + -- use sufficient bits to fit both PN index and GN index in v_index + CONSTANT c_w : NATURAL := ceil_log2(c_sdp_N_pn_max + gn_index); + CONSTANT c_index : STD_LOGIC_VECTOR(c_w-1 DOWNTO 0) := TO_UVEC(gn_index, c_w); + BEGIN + RETURN TO_UINT(c_index(c_pn_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' @@ -586,10 +634,10 @@ PACKAGE BODY sdp_pkg IS 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, nof_crosslets : NATURAL) RETURN NATURAL IS + 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 * nof_crosslets, + sel_a_b(g_statistics_type="XST", P_sq * N_crosslets, S_pn)); -- SST END func_sdp_get_stat_nof_packets; @@ -599,7 +647,7 @@ PACKAGE BODY sdp_pkg IS 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 + 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 @@ -658,10 +706,10 @@ PACKAGE BODY sdp_pkg IS 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; + END func_sdp_map_stat_header; - FUNCTION sdp_extract_cep_header(hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0)) RETURN t_sdp_cep_header IS + 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 @@ -713,27 +761,78 @@ PACKAGE BODY sdp_pkg IS 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 func_sdp_map_cep_header; - FUNCTION func_extract_crosslets_info(info_slv : STD_LOGIC_VECTOR) RETURN t_sdp_crosslets_info IS + 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; nof_crosslets : NATURAL) 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 + FOR I IN 0 TO nof_crosslets-1 LOOP -- map only used 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_extract_crosslets_info; + END func_sdp_map_crosslets_info; + + FUNCTION func_sdp_map_crosslets_info(info_slv : STD_LOGIC_VECTOR) RETURN t_sdp_crosslets_info IS + BEGIN + RETURN func_sdp_map_crosslets_info(info_slv, c_sdp_crosslets_info_nof_offsets); -- map all offsets + END func_sdp_map_crosslets_info; - FUNCTION func_construct_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN STD_LOGIC_VECTOR IS + FUNCTION func_sdp_map_crosslets_info(info_rec : t_sdp_crosslets_info; nof_crosslets : NATURAL) 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 + FOR I IN 0 TO nof_crosslets-1 LOOP -- map only used 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_construct_crosslets_info; + END func_sdp_map_crosslets_info; + + FUNCTION func_sdp_map_crosslets_info(info_rec : t_sdp_crosslets_info) RETURN STD_LOGIC_VECTOR IS + BEGIN + RETURN func_sdp_map_crosslets_info(info_rec, c_sdp_crosslets_info_nof_offsets); -- map all offsets + END func_sdp_map_crosslets_info; + + + FUNCTION func_sdp_step_crosslets_info(info_rec : t_sdp_crosslets_info; nof_crosslets : NATURAL) RETURN t_sdp_crosslets_info IS + VARIABLE v_info : t_sdp_crosslets_info := info_rec; + BEGIN + FOR I IN 0 TO nof_crosslets-1 LOOP -- step only the used 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;