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 12d420d2eef731c1b2cff205bf4ebe1adebd95e9..bae0237fdecaa15af892cb4452808cf4e9c3eace 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd @@ -23,9 +23,11 @@ -- Author: R. van der Walle, E. Kooistra (payload error support) -- Purpose: -- The beamformer data output (BDO) packetizes the beamlet data into UDP/IP packets. --- Description: --- * https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Beamformer --- * https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Multiple+beamlet+output+destinations +-- Description: see references +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Beamformer +-- [2] https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Multiple+beamlet+output+destinations +-- [3] https://plm.astron.nl/polarion/#/project/LOFAR2System/wiki/L1%20Interface%20Control%20Documents/STAT%20to%20CEP%20ICD -- Remark: -- ------------------------------------------------------------------------------- @@ -94,6 +96,8 @@ architecture str of sdp_beamformer_output is constant c_nof_ch : natural := c_sdp_S_sub_bf * c_sdp_cep_nof_blocks_per_packet; -- Dynamic reorder block size control input + -- . The data consists of 1 word = 1 ch, because 1 word contains 1 dual pol + -- beamlet. -- . The input packet has nof_ch = nof_data_per_block * nof_blocks_per_packet -- of data per packet. -- . The transposed output packet will have blocks with nof_blocks_per_packet @@ -109,11 +113,18 @@ architecture str of sdp_beamformer_output is signal d_transpose : t_reorder_transpose; signal snk_in_concat : t_dp_sosi; + signal snk_in_concat_data : std_logic_vector(c_data_w - 1 downto 0); + signal snk_in_concat_re : std_logic_vector(c_sdp_W_beamlet - 1 downto 0); + signal snk_in_concat_im : std_logic_vector(c_sdp_W_beamlet - 1 downto 0); signal dp_repack_beamlet_src_out : t_dp_sosi; + signal dp_repack_beamlet_word : t_sdp_dual_pol_beamlet_in_word; signal dp_packet_merge_src_out : t_dp_sosi; + signal dp_packet_merge_word : t_sdp_dual_pol_beamlet_in_word; signal dp_packet_reorder_src_out : t_dp_sosi; + signal dp_packet_reorder_word : t_sdp_dual_pol_beamlet_in_word; signal reorder_busy : std_logic; signal dp_repack_longword_src_out : t_dp_sosi; + signal dp_repack_longword : t_sdp_dual_pol_beamlet_in_longword; signal dp_fifo_fill_eop_src_out : t_dp_sosi; signal dp_fifo_fill_eop_src_in : t_dp_siso; signal dp_pipeline_src_out : t_dp_sosi; @@ -135,55 +146,67 @@ architecture str of sdp_beamformer_output is begin - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- Input rewiring: concatenate input complex fields to data field -- . dp_repack_data works with data fields only - -- . send beamlet data big endian with X.re part first, then X.im, Y.re, Y.im - ------------------------------------------------------------------------------- + -- . send beamlet data big endian with X.re part first, then X.im, Y.re, + -- and Y.im, conform ICD STAT-CEP [3]. + ----------------------------------------------------------------------------- + + -- Debug signals for view in Wave window + snk_in_concat_data <= snk_in_concat.data(c_data_w - 1 downto 0); + snk_in_concat_re <= in_sosi.re(c_sdp_W_beamlet - 1 downto 0); + snk_in_concat_im <= in_sosi.re(c_sdp_W_beamlet - 1 downto 0); + p_snk_in_arr : process(in_sosi) variable v_ref_time : time := 0 ns; begin snk_in_concat <= in_sosi; - snk_in_concat.data(c_data_w - 1 downto 0) <= in_sosi.re(c_sdp_W_beamlet - 1 downto 0) & in_sosi.im(c_sdp_W_beamlet - 1 downto 0); + snk_in_concat.data(c_data_w - 1 downto 0) <= in_sosi.re(c_sdp_W_beamlet - 1 downto 0) & + in_sosi.im(c_sdp_W_beamlet - 1 downto 0); - ------------------------------------------------------------------------------- + --------------------------------------------------------------------------- -- synthesis translate_off - -- Force BSN error in simulation to verify payload error in 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. + -- Force BSN error in simulation to verify payload error in + -- 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. dbg_bsn_offset <= '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, to be - -- independent of how long it takes for the tb to deliver the first block. + -- Use start of input as reference time, rather than e.g. fixed 50 us, + -- to be independent of how long it takes for the tb to deliver the + -- first block. v_ref_time := NOW; - -- Offset the v_ref_time to the second block of the c_sdp_cep_nof_blocks_per_packet - -- = 4 blocks that will be merged. + -- Offset the v_ref_time to the second block of the + -- c_sdp_cep_nof_blocks_per_packet = 4 blocks that will be merged. v_ref_time := v_ref_time + c_sdp_block_period * 1 ns; end if; elsif NOW > v_ref_time + 1 * c_sdp_cep_nof_blocks_per_packet * c_sdp_block_period * 1 ns and NOW < v_ref_time + 4 * c_sdp_cep_nof_blocks_per_packet * c_sdp_block_period * 1 ns then - -- Disturb BSN to cause merged payload error. Expected results for the merged blocks: + -- Disturb BSN to cause merged payload error. Expected results for the + -- merged blocks: -- . index 0 : First merged block bsn ok and payload_error = '0'. - -- . index 1 : bsn still ok, but payload error = '1', due to bsn++ after first block - -- . index 2,3 : bsn wrong due to bsn++, but payload error = '0', because all 4 - -- merged blocks have incrementing bsn - -- . index 4 : bsn still wrong due to bsn++, and payload error = '1', because the bsn - -- is restored after first block, so the merged blocks do not have - -- incrementing bsn + -- . index 1 : bsn still ok, but payload error = '1', due to bsn++ + -- after first block + -- . index 2,3 : bsn wrong due to bsn++, but payload error = '0', + -- because all 4 merged blocks have incrementing bsn + -- . index 4 : bsn still wrong due to bsn++, and payload error = '1', + -- 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'; snk_in_concat.bsn <= INCR_UVEC(in_sosi.bsn, 1); end if; -- synthesis translate_on - ------------------------------------------------------------------------------- + --------------------------------------------------------------------------- end process; - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- dp_repack_data -- . Repack 16b -> 32b, to get dual polarization beamlets of N_pol_bf * -- N_complex * W_beamlet = 2 * 2 * 8 = 32b words -- . No need to flow control the source, because repack into wider words - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_dp_repack_data_beamlet : entity dp_lib.dp_repack_data generic map ( g_in_dat_w => c_data_w, -- = 16b @@ -202,9 +225,13 @@ begin src_in => c_dp_siso_rdy ); - ------------------------------------------------------------------------------- + -- Debug signals for view in Wave window + -- [0:3] = [Xre, Xim, Yre, Yim] + dp_repack_beamlet_word <= unpack_data(dp_repack_beamlet_src_out.data(c_sdp_W_dual_pol_beamlet - 1 downto 0)); + + ----------------------------------------------------------------------------- -- dp_packet_merge - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_dp_packet_merge : entity dp_lib.dp_packet_merge generic map( g_nof_pkt => c_sdp_cep_nof_blocks_per_packet, @@ -221,18 +248,23 @@ begin src_out => dp_packet_merge_src_out ); - ------------------------------------------------------------------------------- + -- Debug signals for view in Wave window + dp_packet_merge_word <= unpack_data(dp_packet_merge_src_out.data(c_sdp_W_dual_pol_beamlet - 1 downto 0)); + + ----------------------------------------------------------------------------- -- reorder_col_select -- . Reorder beamlet data from: - -- int8[t] [N_blocks_per_packet][S_sub_bf] [N_pol_bf][N_complex] + -- (int8) [t] [N_blocks_per_packet][S_sub_bf] [N_pol_bf][N_complex] -- to: - -- int8[t] [S_sub_bf][N_blocks_per_packet] [N_pol_bf][N_complex] + -- (int8) [t] [S_sub_bf][N_blocks_per_packet] [N_pol_bf][N_complex] -- + -- . where (int8) [N_pol_bf][N_complex] = c_sdp_W_dual_pol_beamlet = 32b + -- dual polarization beamlet word -- See tb_reorder_col_select_all.vhd for how to control col_select_copi/cipo. - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_reorder_col_select : entity reorder_lib.reorder_col_select generic map ( - g_dsp_data_w => c_sdp_W_dual_pol_beamlet, -- = 32b + g_dsp_data_w => c_sdp_W_dual_pol_beamlet / c_nof_complex, -- = 32b / 2 g_nof_ch_in => c_nof_ch, g_nof_ch_sel => c_nof_ch, g_use_complex => false @@ -260,6 +292,9 @@ begin output_sosi => dp_packet_reorder_src_out ); + -- Debug signals for view in Wave window + dp_packet_reorder_word <= unpack_data(dp_packet_reorder_src_out.data(c_sdp_W_dual_pol_beamlet - 1 downto 0)); + -- Use synchronous reset in d signals p_dp_clk_synchronous : process(dp_clk) begin @@ -307,15 +342,15 @@ begin d_transpose <= v; end process; - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- dp_repack_data -- . Repack 32b -> 64b, to get 64b longwords for network packet data -- . No need to flow control the source, because repack into wider words - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_dp_repack_data_longword : entity dp_lib.dp_repack_data generic map ( g_in_dat_w => c_sdp_W_dual_pol_beamlet, -- = 32b - g_in_nof_words => 2, -- = 2 + g_in_nof_words => c_sdp_nof_beamlets_per_longword, -- = 2 g_out_dat_w => c_longword_w, -- = 64b g_out_nof_words => 1 ) @@ -330,9 +365,11 @@ begin src_in => c_dp_siso_rdy ); - ------------------------------------------------------------------------------- + dp_repack_longword <= unpack_data(dp_repack_longword_src_out.data(c_longword_w - 1 downto 0)); + + ----------------------------------------------------------------------------- -- FIFO - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- Pass on dp_repack_longword_src_out.err field (from u_dp_packet_merge) via -- separate u_common_fifo_sc_err u_dp_fifo_fill_eop_sc : entity dp_lib.dp_fifo_fill_eop_sc @@ -355,11 +392,11 @@ begin src_in => dp_fifo_fill_eop_src_in ); - -- Simple fifo to store the payload error bit at eop of FIFO input to be used at sop of FIFO - -- output, so that payload_err can then be used in the packet header. - -- Typically the u_dp_fifo_fill_eop will store between 0 and c_sdp_N_beamsets = 2 packets. - -- Choose g_nof_words > c_sdp_N_beamsets to have some margin compared to c_fifo_size of the - -- data FIFO. + -- Simple fifo to store the payload error bit at eop of FIFO input to be used + -- at sop of FIFO output, so that payload_err can then be used in the packet + -- header. Typically the u_dp_fifo_fill_eop will store between 0 and + -- c_sdp_N_beamsets = 2 packets. Choose g_nof_words > c_sdp_N_beamsets to + -- have some margin compared to c_fifo_size of the data FIFO. u_common_fifo_sc_err : entity common_lib.common_fifo_sc generic map ( g_dat_w => 1, @@ -390,14 +427,15 @@ begin src_out => dp_pipeline_src_out ); - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- Assemble offload info - ------------------------------------------------------------------------------- - -- Whether the dp_offload_tx_hdr_fields value is actually used in the Tx header depends on c_sdp_cep_hdr_field_sel + ----------------------------------------------------------------------------- + -- Whether the dp_offload_tx_hdr_fields value is actually used in the Tx + -- header depends on c_sdp_cep_hdr_field_sel: -- . c_sdp_cep_hdr_field_sel = "111"&"111111111011"&"1110"&"1100"&"00000010"&"100110"&"0"; -- eth ip udp app - -- where 0 = data path, 1 = MM controlled. The '0' fields are assigned here via dp_offload_tx_hdr_fields. - -- in order: + -- where 0 = data path, 1 = MM controlled. The '0' fields are assigned here + -- via dp_offload_tx_hdr_fields. In order: -- access field -- MM eth_dst_mac -- MM eth_src_mac @@ -419,8 +457,9 @@ begin -- MM udp_src_port -- MM udp_dst_port -- MM udp_total_length - -- DP udp_checksum --> default fixed 0, so not used, not calculated here or in tr_10GbE - -- because would require store and forward + -- DP udp_checksum --> default fixed 0, so not used, not calculated + -- here or in tr_10GbE because would require + -- store and forward -- -- MM sdp_marker -- MM sdp_version_id @@ -446,10 +485,12 @@ begin -- -- DP dp_bsn - -- Use MM programmable source MAC/IP/UDP instead of source MAC/IP/UDP based on node ID. This is necessary because - -- beamlet packets from different stations must have different source MAC/IP/UDP. - -- Hence the eth_src_mac, udp_src_port and ip_src_addr are ignored, because c_sdp_cep_hdr_field_sel selects MM control, - -- but keep the code to be able to enable using them by just changing the selection bit. + -- Use MM programmable source MAC/IP/UDP instead of source MAC/IP/UDP based + -- on node ID. This is necessary because beamlet packets from different + -- stations must have different source MAC/IP/UDP. Hence the eth_src_mac, + -- udp_src_port and ip_src_addr are ignored, because c_sdp_cep_hdr_field_sel + -- selects MM control, but keep the code to be able to enable using them by + -- just changing the selection bit. station_info <= sdp_info.antenna_field_index & sdp_info.station_id; @@ -476,9 +517,9 @@ begin -- For viewing the header fields in wave window dp_offload_tx_header <= func_sdp_map_cep_header(dp_offload_tx_hdr_fields); - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- dp_offload_tx_v3 - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_dp_offload_tx_v3 : entity dp_lib.dp_offload_tx_v3 generic map ( g_nof_streams => 1, @@ -508,9 +549,9 @@ begin hdr_fields_out_arr(0) => hdr_fields_out ); - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- tr_10GbE_ip_checksum - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_tr_10GbE_ip_checksum : entity tr_10GbE_lib.tr_10GbE_ip_checksum port map ( rst => dp_rst, @@ -523,9 +564,9 @@ begin src_in => ip_checksum_src_in ); - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- dp_pipeline_ready to ease timing closure - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_dp_pipeline_ready : entity dp_lib.dp_pipeline_ready port map( rst => dp_rst, @@ -537,9 +578,9 @@ begin src_out => dp_pipeline_ready_src_out ); - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- -- mms_dp_xonoff - ------------------------------------------------------------------------------- + ----------------------------------------------------------------------------- u_mms_dp_xonoff : entity dp_lib.mms_dp_xonoff generic map( g_default_value => '0'