diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd index d1d166a6652a87dea6e7ecaf8980432e3f11685f..e3852bd36718fe5e2157207eedfae96682eaaf00 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd @@ -20,7 +20,7 @@ ------------------------------------------------------------------------------- -- --- Author: P. Donker, R van der Walle +-- Author: P. Donker, R van der Walle, E. Kooistra -- Purpose: -- . SDP statistics offload @@ -32,21 +32,23 @@ -- ------------------------------------------------------------------------------- -LIBRARY IEEE, common_lib, mm_lib, dp_lib; +LIBRARY IEEE, common_lib, mm_lib, dp_lib, ring_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 dp_lib.dp_stream_pkg.ALL; +USE ring_lib.ring_pkg.ALL; USE work.sdp_pkg.ALL; ENTITY sdp_statistics_offload IS GENERIC ( - g_statistics_type : STRING := "SST"; - g_offload_time : NATURAL := c_sdp_offload_time; - g_beamset_id : NATURAL := 0; - g_P_sq : NATURAL := c_sdp_P_sq -- use generic to support P_sq = 1 for one node and P_sq = c_sdp_P_sq for multiple nodes (with ring) + g_statistics_type : STRING := "SST"; + g_offload_time : NATURAL := c_sdp_offload_time; + g_beamset_id : NATURAL := 0; + g_P_sq : NATURAL := c_sdp_P_sq; -- use generic to support P_sq = 1 for one node and P_sq = c_sdp_P_sq for multiple nodes (with ring) + g_crosslets_direction : NATURAL := 1 -- > 0 for crosslet transport in positive direction (incrementing RN), else 0 for negative direction ); PORT ( -- Clocks and reset @@ -80,7 +82,6 @@ ENTITY sdp_statistics_offload IS ip_src_addr : IN STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0); gn_index : IN NATURAL; - sdp_info : IN t_sdp_info; subband_calibrated_flag : IN STD_LOGIC := '0'; nof_crosslets : IN STD_LOGIC_VECTOR(c_sdp_nof_crosslets_reg_w-1 DOWNTO 0) := (OTHERS => '0'); @@ -103,65 +104,64 @@ ARCHITECTURE str OF sdp_statistics_offload IS CONSTANT c_beamlet_id : NATURAL := g_beamset_id * c_sdp_S_sub_bf; - -- payload data - CONSTANT c_data_size : NATURAL := c_sdp_W_statistic_sz; -- = 2 - -- Note: - -- . c_nof_data_per_step = 2 for all g_statistics_type, but for different - -- reasons, because c_sdp_N_pol_bf = c_nof_complex = c_sdp_Q_fft = 2 - CONSTANT c_nof_data_per_step : NATURAL := sel_a_b(g_statistics_type="BST", c_sdp_N_pol_bf, - sel_a_b(g_statistics_type="XST", c_nof_complex, - c_sdp_Q_fft)); -- SST - CONSTANT c_step_size : NATURAL := sel_a_b(g_statistics_type="BST", c_data_size, - sel_a_b(g_statistics_type="XST", c_data_size, - c_data_size * c_nof_data_per_step)); -- SST - CONSTANT c_nof_data : NATURAL := c_nof_statistics_per_packet; - CONSTANT c_block_size : NATURAL := c_nof_data * c_step_size; + -- MM access settings per packet for u_dp_block_from_mm_dc + CONSTANT c_mm_data_size : NATURAL := func_sdp_get_stat_from_mm_data_size(g_statistics_type); + CONSTANT c_mm_step_size : NATURAL := func_sdp_get_stat_from_mm_step_size(g_statistics_type); + CONSTANT c_mm_nof_data : NATURAL := func_sdp_get_stat_from_mm_nof_data(g_statistics_type); -- offload control TYPE t_reg IS RECORD - block_count : NATURAL; + packet_count : NATURAL; start_address : NATURAL; start_pulse : STD_LOGIC; dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0); - data_id : STD_LOGIC_VECTOR(31 DOWNTO 0); - nof_cycles_dly : NATURAL; payload_err : STD_LOGIC; - interval_cnt : NATURAL; - integration_interval : NATURAL; - crosslet_count : NATURAL; - nof_crosslets : NATURAL; + in_sop_cnt : NATURAL; + integration_interval : NATURAL; + interleave_count : NATURAL RANGE 0 TO c_sdp_Q_fft; + crosslet_count : NATURAL RANGE 0 TO c_sdp_N_crosslets_max; + instance_count : NATURAL RANGE 0 TO c_sdp_P_sq; + instance_address : NATURAL; + nof_crosslets : NATURAL RANGE 0 TO c_sdp_N_crosslets_max; + crosslets_info_rec : t_sdp_crosslets_info; END RECORD; - CONSTANT c_reg_rst : t_reg := (0, 0, '0', (OTHERS => '0'), (OTHERS => '0'), 0, '0', 0, 0, 0, 0); - - TYPE t_selected_crosslet_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_sdp_crosslets_index_w-1 DOWNTO 0); + CONSTANT c_crosslets_info_rst : t_sdp_crosslets_info := (offset_arr => (OTHERS => 0), step => 0); + CONSTANT c_reg_rst : t_reg := (0, 0, '0', (OTHERS => '0'), '0', 0, 0, 0, 0, 0, 0, 0, c_crosslets_info_rst); SIGNAL r : t_reg; SIGNAL nxt_r : t_reg; - SIGNAL gn_index_reg : NATURAL; - SIGNAL rn_index_reg : NATURAL; - - SIGNAL trigger : STD_LOGIC := '0'; - SIGNAL done : STD_LOGIC := '0'; + SIGNAL gn_index_reg : NATURAL; -- index of this global node + SIGNAL pn_index : NATURAL; -- index of this node in antenna band + SIGNAL rn_index : NATURAL; -- index of this ring node + SIGNAL local_si_offset : NATURAL; -- index of first signal input on this node + SIGNAL remote_rn : NATURAL; -- index of remote ring node + SIGNAL remote_gn : NATURAL; -- index of remote global node + SIGNAL remote_pn : NATURAL; -- index of remote node in antenna band + SIGNAL remote_si_offset : NATURAL; -- index of first signal input on remote node + SIGNAL nof_cycles_dly : NATURAL; -- trigger_offload delay for this node + SIGNAL nof_packets : NATURAL; -- nof packets per integration interval + + SIGNAL data_id_rec : t_sdp_stat_data_id; + SIGNAL data_id_slv : STD_LOGIC_VECTOR(31 DOWNTO 0) := (OTHERS => '0'); + + SIGNAL trigger_en : STD_LOGIC := '0'; + SIGNAL trigger_offload : STD_LOGIC := '0'; + SIGNAL mm_done : STD_LOGIC := '0'; SIGNAL dp_block_from_mm_src_out : t_dp_sosi; SIGNAL dp_block_from_mm_src_in : t_dp_siso; SIGNAL dp_offload_snk_in : t_dp_sosi; SIGNAL dp_offload_snk_out : t_dp_siso; - SIGNAL dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0):= (OTHERS => '0'); SIGNAL bsn_at_sync : STD_LOGIC_VECTOR(63 DOWNTO 0) := (OTHERS => '0'); + SIGNAL dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0):= (OTHERS => '0'); - SIGNAL selected_crosslet_arr : t_selected_crosslet_arr(c_sdp_N_crosslets_max-1 DOWNTO 0); - BEGIN bsn_at_sync <= RESIZE_UVEC(in_sosi.bsn, 64) WHEN rising_edge(dp_clk) AND in_sosi.sync = '1'; - gen_sel_crosslets : FOR I IN 0 TO c_sdp_N_crosslets_max-1 GENERATE - selected_crosslet_arr(I) <= crosslets_info((I+1)*c_sdp_crosslets_index_w-1 DOWNTO I*c_sdp_crosslets_index_w); - END GENERATE; - + ------------------------------------------------------------------------------- -- Assemble offload header info, for data path fields that are selected by: -- c_sdp_stat_hdr_field_sel = "1"&"101"&"111011111001"&"0100"&"0100"&"000000010"&"1000000"&"0" @@ -207,7 +207,7 @@ BEGIN dp_header_info(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" )) <= SLV(subband_calibrated_flag); dp_header_info(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" )) <= TO_UVEC(gn_index, 5); dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_integration_interval" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_integration_interval" )) <= TO_UVEC(r.integration_interval, 24); - dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_data_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_data_id" )) <= r.data_id; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_data_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_data_id" )) <= data_id_slv; dp_header_info(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" )) <= TO_UVEC(c_nof_signal_inputs, 8); dp_header_info(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" )) <= TO_UVEC(c_sdp_nof_bytes_per_statistic, 8); dp_header_info(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" )) <= TO_UVEC(c_nof_statistics_per_packet, 16); @@ -223,81 +223,127 @@ BEGIN END IF; END PROCESS; - gn_index_reg <= gn_index WHEN rising_edge(dp_clk); - rn_index_reg <= gn_index - TO_UINT(sdp_info.O_rn) WHEN rising_edge(dp_clk); + -- Derive and pipeline dynamic parameters + gn_index_reg <= gn_index WHEN rising_edge(dp_clk); + pn_index <= func_sdp_gn_index_to_pn_index(gn_index) WHEN rising_edge(dp_clk); + rn_index <= gn_index - TO_UINT(sdp_info.O_rn) WHEN rising_edge(dp_clk); + local_si_offset <= pn_index * c_sdp_S_pn WHEN rising_edge(dp_clk); + nof_cycles_dly <= gn_index * g_offload_time WHEN rising_edge(dp_clk); + nof_packets <= func_sdp_get_stat_nof_packets(g_statistics_type, c_sdp_S_pn, g_P_sq, r.nof_crosslets) WHEN rising_edge(dp_clk); + + remote_rn <= func_nof_hops_to_source_rn(r.instance_count, rn_index, TO_UINT(sdp_info.N_rn), g_crosslets_direction); + remote_gn <= TO_UINT(sdp_info.O_rn) + remote_rn; + remote_pn <= func_sdp_gn_index_to_pn_index(remote_gn) WHEN rising_edge(dp_clk); + remote_si_offset <= remote_pn * c_sdp_S_pn WHEN rising_edge(dp_clk); + + -- Assign application header data_id for different statistic types, use + -- GENERATE to keep unused fields at 0. + gen_data_id_sst : IF g_statistics_type = "SST" GENERATE + data_id_rec.sst_signal_input_index <= r.packet_count + local_si_offset; + END GENERATE; + gen_data_id_bst : IF g_statistics_type = "BST" GENERATE + data_id_rec.bst_beamlet_index <= c_beamlet_id; + END GENERATE; + gen_data_id_xst : IF g_statistics_type = "XST" GENERATE + data_id_rec.xst_subband_index <= func_sdp_modulo_N_sub(r.crosslets_info_rec.offset_arr(r.crosslet_count)); + data_id_rec.xst_signal_input_A_index <= local_si_offset; + data_id_rec.xst_signal_input_B_index <= remote_si_offset; + END GENERATE; + + data_id_slv <= func_sdp_map_stat_data_id(g_statistics_type, data_id_rec); - p_control_packet_offload : PROCESS(r, gn_index_reg, in_sosi, trigger, done, dp_header_info, selected_crosslet_arr, nof_crosslets) - VARIABLE v: t_reg; + p_control_packet_offload : PROCESS(r, in_sosi, local_si_offset, trigger_offload, nof_crosslets, crosslets_info, nof_packets, mm_done, dp_header_info) + VARIABLE v : t_reg; + VARIABLE v_index : NATURAL; BEGIN v := r; - v.start_pulse := '0'; - v.nof_cycles_dly := gn_index_reg * g_offload_time; + v.start_pulse := '0'; - -- Count number of sop's in a sync interval and get payload errors and keep them till next sync. + -- Count number of sop in a sync interval and get payload errors and keep them till next sync. IF in_sosi.sync = '1' THEN - v.integration_interval := r.interval_cnt + 1; -- count = index + 1 - v.interval_cnt := 0; - v.payload_err := '0'; + v.integration_interval := r.in_sop_cnt + 1; -- count = index + 1 + v.in_sop_cnt := 0; + v.payload_err := '0'; ELSE IF in_sosi.eop = '1' THEN v.payload_err := r.payload_err OR in_sosi.err(0); END IF; IF in_sosi.sop = '1' THEN - v.interval_cnt := r.interval_cnt + 1; + v.in_sop_cnt := r.in_sop_cnt + 1; END IF; END IF; - -- assign sdp_data_id for different statistic types - v.data_id := x"00000000"; - IF g_statistics_type = "SST" THEN - v.data_id(7 DOWNTO 0) := TO_UVEC(r.block_count + c_sdp_S_pn * gn_index_reg, 8); - ELSIF g_statistics_type = "BST" THEN - v.data_id(15 DOWNTO 0) := TO_UVEC(c_beamlet_id, 16); - ELSIF g_statistics_type = "XST" THEN - v.data_id(24 DOWNTO 16) := RESIZE_UVEC(selected_crosslet_arr(r.crosslet_count), 9); - v.data_id(15 DOWNTO 8) := TO_UVEC(r.block_count * c_sdp_S_pn, 8); - v.data_id(7 DOWNTO 0) := TO_UVEC(r.block_count * c_sdp_S_pn, 8); -- RW TODO: define for P_sq > 1 + -- Capture nof_crosslets and crosslets_info at in_sosi.sync, to make sure + -- they do not change during packets offload. The trigger_offload occurs + -- after the nof_cycles_dly and the offload will have finished before the + -- next in_sosi.sync + IF in_sosi.sync = '1' THEN + v.nof_crosslets := TO_UINT(nof_crosslets); + v.crosslets_info_rec := func_sdp_map_crosslets_info(crosslets_info, TO_UINT(nof_crosslets)); END IF; -- Issue start_pulse per packet offload - IF trigger = '1' THEN - -- Use trigger to start first packet - v.start_pulse := '1'; - v.start_address := 0; - v.block_count := 0; - v.crosslet_count := 0; - v.nof_crosslets := TO_UINT(nof_crosslets); -- register nof_crosslets to make sure it does not change during packet output. - ELSIF done = '1' THEN - -- Use done to start next packets - IF r.block_count < c_nof_packets_max-1 THEN - IF g_statistics_type /= "XST" OR r.crosslet_count < r.nof_crosslets-1 THEN - -- For SST, BST and for XST nof_crosslets do: - IF r.block_count MOD c_nof_data_per_step = 0 THEN - v.start_address := r.block_count / c_nof_data_per_step * c_block_size; -- jump to first packet in next block - ELSE - v.start_address := r.start_address + c_data_size; -- step to next packet within block + IF trigger_offload = '1' THEN + -- Use trigger_offload to start first packet offload, all g_statistics_type start from start address 0 + v.start_pulse := '1'; + v.start_address := 0; + v.packet_count := 0; + v.interleave_count := 0; -- only used for SST + v.crosslet_count := 0; -- only used for XST + v.instance_count := 0; -- only used for XST + v.instance_address := 0; -- only used for XST + + ELSIF mm_done = '1' THEN + -- Use mm_done to start next packets offloads. + IF r.packet_count < nof_packets - 1 THEN + IF g_statistics_type = "SST" THEN + -- step step step step step step + -- start_address : 0, 2, 2048, 2050, 4096, 4098, 6144, 6146, 8192, 8194, 10240, 10242 + v.start_address := r.start_address + c_mm_data_size; -- default step to next packet in this step + v.interleave_count := r.interleave_count + 1; + IF r.interleave_count = c_sdp_Q_fft - 1 THEN + v.start_address := r.packet_count * c_sdp_N_sub * c_sdp_Q_fft * c_sdp_W_statistic_sz; -- jump to first packet for next step + v.interleave_count := 0; END IF; - v.start_pulse := '1'; - v.block_count := r.block_count + 1; + v.start_pulse := '1'; + v.packet_count := r.packet_count + 1; + + ELSIF g_statistics_type = "BST" THEN + NULL; -- there is only one BST packet, so no more packets to offload here. + + ELSIF g_statistics_type = "XST" THEN + -- start_address: + -- nof_crosslets: 0, 1, 2, 3, 4, 5, 6 + -- X_sq instance: + -- 0 0, 576, 1152, 1728, 2304, 2880, 3456 + -- 1 4096, 4672, 5248, 5824, 6400, 6976, 7552 + -- 2 8192, 8768, 9344, 9920, 10496, 11072, 11648 + -- 3 12288, 12864, 13440, 14016, 14592, 15168, 15744 + -- 4 16384, 16960, 17536, 18112, 18688, 19264, 19840 + -- 5 20480, 21056, 21632, 22208, 22784, 23360, 23936 + -- 6 24576, 25152, 25728, 26304, 26880, 27456, 28032 + -- 7 28672, 29248, 29824, 30400, 30976, 31552, 32128 + -- 8 32768, 33344, 33920, 34496, 35072, 35648, 36224 + v.start_address := r.start_address + c_sdp_X_sq * c_nof_complex * c_sdp_W_statistic_sz; -- continue with next packet in this instance v.crosslet_count := r.crosslet_count + 1; + IF r.crosslet_count = TO_UINT(nof_crosslets) - 1 THEN + v.start_address := r.instance_address + 2**c_sdp_ram_st_xsq_addr_w; -- jump to first packet in next instance + v.crosslet_count := 0; + v.instance_count := r.instance_count + 1; + v.instance_address := v.start_address; -- use v.start_address to avoid multipier needed in (r.instance_count + 1) * 2**c_sdp_ram_st_xsq_addr_w + END IF; + v.start_pulse := '1'; + v.packet_count := r.packet_count + 1; + ELSE - -- For XST after nof_crosslets do: - v.crosslet_count := 0; - -- skip block indices for unused XST blocks in this P_sq iteration by setting the block count to the next multiple of N_crosslets_max i.e. 7, 14, 21, etc. - v.block_count := r.block_count + 1 + (c_sdp_N_crosslets_max - r.nof_crosslets); + NULL; -- do nothing in case of unknown g_statistics_type END IF; - - ELSE - -- Prepare for next trigger interval. - v.start_address := 0; - v.block_count := 0; - v.crosslet_count := 0; END IF; END IF; - IF trigger = '1' OR done = '1' THEN - -- Release header info per packet offload + -- Release dp_header_info per packet offload + IF trigger_offload = '1' OR mm_done = '1' THEN v.dp_header_info := dp_header_info; END IF; nxt_r <= v; @@ -314,16 +360,17 @@ BEGIN reg_enable_mosi => reg_enable_mosi, reg_enable_miso => reg_enable_miso, - delay => r.nof_cycles_dly, + delay => nof_cycles_dly, trigger => in_sosi.sync, - trigger_dly => trigger + trigger_en => trigger_en, + trigger_dly => trigger_offload ); u_dp_block_from_mm_dc : ENTITY dp_lib.dp_block_from_mm_dc GENERIC MAP ( - g_data_size => c_data_size, - g_step_size => c_step_size, - g_nof_data => c_nof_data, + g_data_size => c_mm_data_size, + g_step_size => c_mm_step_size, + g_nof_data => c_mm_nof_data, g_reverse_word_order => TRUE -- default word order is MSB after LSB, we need to stream LSB after MSB. ) PORT MAP( @@ -333,7 +380,7 @@ BEGIN mm_clk => mm_clk, start_pulse => r.start_pulse, start_address => r.start_address, - done => done, + done => mm_done, mm_mosi => master_mosi, mm_miso => master_miso, out_sosi => dp_block_from_mm_src_out,