diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd index 4db670eeaf24b1653ec13873b2b39d4e73a8ce94..ecf7c188d520a23fcb59490729641fc08fbee70b 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd @@ -20,7 +20,7 @@ ------------------------------------------------------------------------------- -- --- Author: R. van der Walle, E. Kooistra (payload error support) +-- Author: R. van der Walle, E. Kooistra -- Purpose: -- The beamformer data output (BDO) packetizes the beamlet data into UDP/IP packets. -- Description: see references @@ -47,6 +47,9 @@ use work.sdp_bdo_pkg.all; entity sdp_beamformer_output is generic ( g_beamset_id : natural := 0; + -- For g_nof_destinations_max > 1 the transpose is always used + -- For g_nof_destinations_max = 1 then the transpose is only used + -- when g_use_transpose = true, else the identity is used g_use_transpose : boolean := false; g_nof_destinations_max : natural := 1; g_sim_force_bsn_error : boolean := true @@ -85,24 +88,30 @@ entity sdp_beamformer_output is end sdp_beamformer_output; architecture str of sdp_beamformer_output is - constant c_data_w : natural := c_nof_complex * c_sdp_W_beamlet; -- 16b - constant c_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; -- call beamset 'id' and beamlet 'index' + constant c_data_w : natural := c_nof_complex * c_sdp_W_beamlet; -- 16b + constant c_beamset_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; -- call beamset 'id' and beamlet 'index' -- Use c_fifo_fill = c_fifo_size - margin so that FIFO does not get read out too soon. -- The dp_fifo_fill_eop takes care that the FIFO gets read out whenever there is an -- eop in the FIFO, so that no payload gets stuck in the FIFO. Thanks to the use of eop -- it possible to pass on blocks of variable length. - -- Make fifo size large enough for adding header, muxing c_sdp_N_beamsets beamsets and + -- Make c_fifo_size large enough for adding header, muxing c_sdp_N_beamsets beamsets and -- delaying output to be able to realign snk_in.err field from snk_in.eop to src_out.sop. - constant c_fifo_fill : natural := c_sdp_cep_payload_nof_longwords; -- 976 - constant c_fifo_size : natural := true_log_pow2(c_sdp_cep_payload_nof_longwords) * c_sdp_N_beamsets; -- 2048 - + constant c_nof_words_multi : natural := largest(func_sdp_bdo_nof_ch_per_packet_first_destinations_look_up_table(g_nof_destinations_max)); + constant c_nof_longwords_one : natural := c_sdp_cep_payload_nof_longwords; -- = 976 + constant c_nof_longwords_multi : natural := c_nof_words_multi / 2; + constant c_fifo_size_one : natural := true_log_pow2(c_nof_longwords_one) * c_sdp_N_beamsets; -- = 2048 + constant c_fifo_size_multi : natural := true_log_pow2(c_nof_longwords_multi) * c_sdp_N_beamsets; -- = 2048 + constant c_fifo_size : natural := sel_a_b(g_nof_destinations_max = 1, c_fifo_size_one, c_fifo_size_multi); + -- Rely on input eop instead of FIFO fill level, therefore set c_fifo_fill = + -- g_fifo_size - (g_fifo_af_margin + 2) as explained in dp_fifo_fill_eop + constant c_fifo_fill : natural := c_fifo_size - 6; -- Multi destination info (mdi) - constant c_nof_destinations_w : natural := ceil_log2(g_nof_destinations_max + 1); - constant c_mdi_slv_w : natural := c_nof_destinations_w * 2 + - c_sdp_bdo_reorder_nof_blocks_w + - c_sdp_nof_beamlets_per_block_w; + constant c_nof_destinations_w : natural := ceil_log2(g_nof_destinations_max + 1); + + constant c_beamlet_index_per_destination_mat : t_natural_matrix(1 to g_nof_destinations_max, 0 to g_nof_destinations_max - 1) := + func_sdp_bdo_beamlet_index_per_destination_look_up_matrix(g_nof_destinations_max); -- . field_sel = '0' for DP (dynamic), '1' for MM (fixed or programmable via MM of dp_offload_tx_v3) constant c_cep_hdr_field_sel : std_logic_vector(c_sdp_cep_nof_hdr_fields - 1 downto 0) := @@ -115,6 +124,7 @@ architecture str of sdp_beamformer_output is -- per beamlet and nof_beamlets_per_block dual pol beamlets per time slot. signal nof_blocks_per_packet : natural; signal nof_beamlets_per_block : natural; + signal beamlet_index : natural; signal snk_in_concat : t_dp_sosi; signal snk_in_concat_data : std_logic_vector(c_data_w - 1 downto 0); @@ -126,10 +136,10 @@ architecture str of sdp_beamformer_output is signal dp_packet_reorder_word : t_sdp_dual_pol_beamlet_in_word; signal dp_repack_longword_src_out : t_dp_sosi; signal dp_repack_longword : t_sdp_dual_pol_beamlet_in_longword; - signal dp_fifo_data_src_out : t_dp_sosi; - signal dp_fifo_data_src_in : t_dp_siso; - signal dp_pipeline_data_src_out : t_dp_sosi; - signal dp_pipeline_data_src_in : t_dp_siso; + signal dp_fifo_data_src_out : t_dp_sosi; + signal dp_fifo_data_src_in : t_dp_siso; + signal dp_pipeline_data_src_out : t_dp_sosi; + signal dp_pipeline_data_src_in : t_dp_siso; signal dp_offload_tx_src_out : t_dp_sosi; signal dp_offload_tx_src_in : t_dp_siso; signal ip_checksum_src_out : t_dp_sosi; @@ -137,32 +147,23 @@ architecture str of sdp_beamformer_output is signal dp_pipeline_ready_src_out : t_dp_sosi; signal dp_pipeline_ready_src_in : t_dp_siso; - signal dbg_bsn_offset : std_logic; - signal payload_err : std_logic_vector(0 downto 0); - signal station_info : std_logic_vector(15 downto 0) := (others => '0'); + signal dbg_force_bsn_error : std_logic := '0'; + signal payload_err : std_logic_vector(0 downto 0); + signal station_info : std_logic_vector(15 downto 0) := (others => '0'); -- Multiple destinations info (mdi) - signal multi_destinations_info : t_sdp_bdo_destinations_info; - signal mdi_hdr_eth_dst_mac : std_logic_vector(c_network_eth_mac_addr_w - 1 downto 0); - signal mdi_hdr_ip_dst_addr : std_logic_vector(c_network_ip_addr_w - 1 downto 0); - signal mdi_hdr_udp_dst_port : std_logic_vector(c_network_udp_port_w - 1 downto 0); - - -- . index for destination MAC/IP/UDP - signal mdi_destination_index : natural; - signal mdi_destination_index_slv : std_logic_vector(c_nof_destinations_w - 1 downto 0); - -- . header fields + signal multi_destinations_info : t_sdp_bdo_destinations_info; + signal s_DN : natural := 1; -- number of destinations + signal s_DI : natural := 0; -- destination index + signal mdi_eth_dst_mac : std_logic_vector(c_network_eth_mac_addr_w - 1 downto 0); + signal mdi_ip_dst_addr : std_logic_vector(c_network_ip_addr_w - 1 downto 0); + signal mdi_udp_dst_port : std_logic_vector(c_network_udp_port_w - 1 downto 0); + signal mdi_nof_blocks_per_packet : natural; - signal mdi_nof_blocks_per_packet_slv : std_logic_vector(c_sdp_bdo_reorder_nof_blocks_w - 1 downto 0); + signal mdi_nof_beamlets_per_block_first_destinations : natural; + signal mdi_nof_beamlets_per_block_last_destination : natural; signal mdi_nof_beamlets_per_block_per_destination : natural; - signal mdi_nof_beamlets_per_block_per_destination_slv : std_logic_vector(c_sdp_nof_beamlets_per_block_w - 1 downto 0); signal mdi_beamlet_index_per_destination : natural; - signal mdi_beamlet_index_per_destination_slv : std_logic_vector(c_nof_destinations_w - 1 downto 0); - signal mdi_fifo_in_slv : std_logic_vector(c_mdi_slv_w - 1 downto 0); - signal mdi_fifo_out_slv : std_logic_vector(c_mdi_slv_w - 1 downto 0); - signal mdi_hdr_destination_index : natural; - signal mdi_hdr_nof_blocks_per_packet : natural; - signal mdi_hdr_nof_beamlets_per_block_per_destination : natural; - signal mdi_hdr_beamlet_index_per_destination : natural; -- Default set all data path driven header fields to 0 signal dp_offload_tx_hdr_fields : std_logic_vector(1023 downto 0) := (others => '0'); @@ -193,7 +194,7 @@ begin -- tb_lofar2_unb2c_sdp_station_bf.vhd, this will cause two times payload -- errors, one when BSN goes wrong and one when BSN goes ok again. if g_sim_force_bsn_error = true then - dbg_bsn_offset <= '0'; + dbg_force_bsn_error <= '0'; if v_ref_time = 0 ns then if in_sosi.sop = '1' then -- Use start of input as reference time, rather than e.g. fixed 50 us, @@ -217,7 +218,7 @@ begin -- because the bsn is restored after first block, so the -- merged blocks do not have incrementing bsn -- . index >= 5 : bsn ok and payload_error = '0'. - dbg_bsn_offset <= '1'; + dbg_force_bsn_error <= '1'; snk_in_concat.bsn <= INCR_UVEC(in_sosi.bsn, 1); end if; end if; @@ -307,71 +308,46 @@ begin snk_in => dp_repack_beamlet_src_out, src_out => dp_packet_reorder_src_out, - -- Streaming data output info per destination index - destination_index => mdi_destination_index, - nof_blocks_per_packet => mdi_nof_blocks_per_packet, - nof_beamlets_per_block_per_destination => mdi_nof_beamlets_per_block_per_destination, - beamlet_index_per_destination => mdi_beamlet_index_per_destination + -- Streaming data output info dependent on DN = nof_destinations + nof_blocks_per_packet => mdi_nof_blocks_per_packet, + nof_beamlets_per_block_first_destinations => mdi_nof_beamlets_per_block_first_destinations, + nof_beamlets_per_block_last_destination => mdi_nof_beamlets_per_block_last_destination ); ----------------------------------------------------------------------------- - -- FIFO: to align multi destination info + -- Look up table values and and output info dependent on DN and DI ----------------------------------------------------------------------------- - mdi_destination_index_slv <= to_uvec(mdi_destination_index, c_nof_destinations_w); - mdi_nof_blocks_per_packet_slv <= to_uvec(mdi_nof_blocks_per_packet, c_sdp_bdo_reorder_nof_blocks_w); - mdi_nof_beamlets_per_block_per_destination_slv <= to_uvec(mdi_nof_beamlets_per_block_per_destination, c_sdp_nof_beamlets_per_block_w); - mdi_beamlet_index_per_destination_slv <= to_uvec(mdi_beamlet_index_per_destination, c_nof_destinations_w); - - -- Concat into slv - mdi_fifo_in_slv <= func_slv_concat(mdi_destination_index_slv, - mdi_nof_blocks_per_packet_slv, - mdi_nof_beamlets_per_block_per_destination_slv, - mdi_beamlet_index_per_destination_slv); - - -- Similar purpose as u_common_fifo_err, but from input sop to output sop. - u_common_fifo_mdi : entity common_lib.common_fifo_sc - generic map ( - g_dat_w => c_mdi_slv_w, - g_nof_words => c_sdp_N_beamsets + 2 - ) - port map ( - rst => dp_rst, - clk => dp_clk, - wr_dat => mdi_fifo_in_slv, - wr_req => dp_packet_reorder_src_out.sop, - rd_dat => mdi_fifo_out_slv, - rd_req => dp_fifo_data_src_out.sop - ); - - -- Extract from slv - mdi_hdr_destination_index <= to_uint(func_slv_extract(c_nof_destinations_w, - c_sdp_bdo_reorder_nof_blocks_w, - c_sdp_nof_beamlets_per_block_w, - c_nof_destinations_w, - mdi_fifo_out_slv, 0)); - mdi_hdr_nof_blocks_per_packet <= to_uint(func_slv_extract(c_nof_destinations_w, - c_sdp_bdo_reorder_nof_blocks_w, - c_sdp_nof_beamlets_per_block_w, - c_nof_destinations_w, - mdi_fifo_out_slv, 1)); - mdi_hdr_nof_beamlets_per_block_per_destination <= to_uint(func_slv_extract(c_nof_destinations_w, - c_sdp_bdo_reorder_nof_blocks_w, - c_sdp_nof_beamlets_per_block_w, - c_nof_destinations_w, - mdi_fifo_out_slv, 2)); - mdi_hdr_beamlet_index_per_destination <= to_uint(func_slv_extract(c_nof_destinations_w, - c_sdp_bdo_reorder_nof_blocks_w, - c_sdp_nof_beamlets_per_block_w, - c_nof_destinations_w, - mdi_fifo_out_slv, 3)); - - -- Select destination MAC/IP/UDP, pipeline to easing timing closure - p_pipeline : process(dp_clk) + -- Register output info dependent on DN and DI to ease timing closure + p_reg : process(dp_clk) + variable v_DN : natural; -- number of destinations + variable v_DI : natural; -- destination index begin if rising_edge(dp_clk) then - mdi_hdr_eth_dst_mac <= multi_destinations_info.eth_destination_mac_arr(mdi_hdr_destination_index); - mdi_hdr_ip_dst_addr <= multi_destinations_info.ip_destination_address_arr(mdi_hdr_destination_index); - mdi_hdr_udp_dst_port <= multi_destinations_info.udp_destination_port_arr(mdi_hdr_destination_index); + v_DN := multi_destinations_info.nof_destinations_act; + v_DI := to_uint(dp_fifo_data_src_out.channel); + + s_DN <= v_DN; + s_DI <= v_DI; + + -- Variable values that depend on DN set via MM and/or on current DI + -- from dp_packet_unmerged that is passed on via + -- dp_fifo_data_src_out.channel. + -- . Use s_DN to ease timing closure. Use v_DI to ensure that the mdi + -- values are valid at dp_pipeline_data_src_out.sop + mdi_eth_dst_mac <= multi_destinations_info.eth_destination_mac_arr(v_DI); + mdi_ip_dst_addr <= multi_destinations_info.ip_destination_address_arr(v_DI); + mdi_udp_dst_port <= multi_destinations_info.udp_destination_port_arr(v_DI); + + -- . Account for beamset offset in beamlet index + mdi_beamlet_index_per_destination <= c_beamset_beamlet_index + c_beamlet_index_per_destination_mat(s_DN, v_DI); + -- . In total there are S_sub_bf = 488 beamlets for nof_destinations. + -- The packet for last destination contains the same number of + -- beamlets as the first destinations, or less beamlets. + if v_DI < s_DN - 1 then + mdi_nof_beamlets_per_block_per_destination <= mdi_nof_beamlets_per_block_first_destinations; + else + mdi_nof_beamlets_per_block_per_destination <= mdi_nof_beamlets_per_block_last_destination; + end if; end if; end process; end generate; @@ -415,7 +391,9 @@ begin g_empty_w => c_byte_w, g_use_empty => true, g_use_bsn => true, + g_use_channel => true, g_bsn_w => 64, + g_channel_w => c_nof_destinations_w, g_use_sync => true, g_fifo_size => c_fifo_size, g_fifo_fill => c_fifo_fill, @@ -438,7 +416,7 @@ begin u_common_fifo_err : entity common_lib.common_fifo_sc generic map ( g_dat_w => 1, - g_nof_words => c_sdp_N_beamsets + 2 + g_nof_words => g_nof_destinations_max * c_sdp_N_beamsets + 2 ) port map ( rst => dp_rst, @@ -523,16 +501,20 @@ begin -- -- DP dp_bsn - p_assemble_offload_info : process(mdi_hdr_nof_blocks_per_packet, mdi_hdr_nof_beamlets_per_block_per_destination) + p_assemble_offload_info : process(mdi_nof_blocks_per_packet, + mdi_nof_beamlets_per_block_per_destination, + mdi_beamlet_index_per_destination) begin if g_nof_destinations_max = 1 then -- Use constant defaults for beamlet data output to one destination. nof_blocks_per_packet <= c_sdp_cep_nof_blocks_per_packet; -- = 4; nof_beamlets_per_block <= c_sdp_S_sub_bf; -- = 488 dual pol beamlets; + beamlet_index <= c_beamset_beamlet_index; else -- Use dynamic sizes for beamlet data output to multiple destination. - nof_blocks_per_packet <= mdi_hdr_nof_blocks_per_packet; - nof_beamlets_per_block <= mdi_hdr_nof_beamlets_per_block_per_destination; + nof_blocks_per_packet <= mdi_nof_blocks_per_packet; + nof_beamlets_per_block <= mdi_nof_beamlets_per_block_per_destination; + beamlet_index <= mdi_beamlet_index_per_destination; end if; end process; @@ -550,9 +532,9 @@ begin -- Use MM programmable destination MAC/IP/UDP from dp_offload_tx_v3 for one destination -- Use DP programmable destination MAC/IP/UDP from sdp_bdo_destinations_reg for multiple destinations - dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "eth_dst_mac" ) downto field_lo(c_sdp_cep_hdr_field_arr, "eth_dst_mac" )) <= mdi_hdr_eth_dst_mac; - dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "ip_dst_addr" ) downto field_lo(c_sdp_cep_hdr_field_arr, "ip_dst_addr" )) <= mdi_hdr_ip_dst_addr; - dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "udp_dst_port") downto field_lo(c_sdp_cep_hdr_field_arr, "udp_dst_port")) <= mdi_hdr_udp_dst_port; + dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "eth_dst_mac" ) downto field_lo(c_sdp_cep_hdr_field_arr, "eth_dst_mac" )) <= mdi_eth_dst_mac; + dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "ip_dst_addr" ) downto field_lo(c_sdp_cep_hdr_field_arr, "ip_dst_addr" )) <= mdi_ip_dst_addr; + dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "udp_dst_port") downto field_lo(c_sdp_cep_hdr_field_arr, "udp_dst_port")) <= mdi_udp_dst_port; dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_observation_id" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_observation_id" )) <= sdp_info.observation_id; dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_station_info" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_station_info" )) <= station_info; @@ -565,7 +547,7 @@ begin dp_offload_tx_hdr_fields(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" )) <= gn_id; dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_beamlet_scale" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_beamlet_scale" )) <= beamlet_scale; - dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_beamlet_index" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_beamlet_index" )) <= TO_UVEC(c_beamlet_index, c_halfword_w); + dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_beamlet_index" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_beamlet_index" )) <= TO_UVEC(beamlet_index, c_halfword_w); dp_offload_tx_hdr_fields(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" )) <= TO_UVEC(nof_blocks_per_packet, c_octet_w); dp_offload_tx_hdr_fields(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")) <= TO_UVEC(nof_beamlets_per_block, c_halfword_w); dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "sdp_block_period" ) downto field_lo(c_sdp_cep_hdr_field_arr, "sdp_block_period" )) <= sdp_info.block_period;