From 3da7b65b7ff70a6da911618e580841bc4de23da9 Mon Sep 17 00:00:00 2001 From: Eric Kooistra <kooistra@astron.nl> Date: Tue, 3 Oct 2023 17:13:23 +0200 Subject: [PATCH] Verify beamlet header for multiple destinations. --- .../sdp/tb/vhdl/tb_sdp_beamformer_output.vhd | 304 ++++++++++++------ .../tb/vhdl/tb_tb_sdp_beamformer_output.vhd | 4 + 2 files changed, 214 insertions(+), 94 deletions(-) diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_output.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_output.vhd index 8f27b9b8b2..8516ea9ef8 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_output.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_output.vhd @@ -38,6 +38,7 @@ use common_lib.tb_common_mem_pkg.all; use common_lib.common_network_layers_pkg.all; use dp_lib.dp_stream_pkg.all; use work.sdp_pkg.all; +use work.sdp_bdo_pkg.all; use work.tb_sdp_pkg.all; entity tb_sdp_beamformer_output is @@ -68,14 +69,23 @@ architecture tb of tb_sdp_beamformer_output is constant c_gn_id_slv : std_logic_vector(c_sdp_W_gn_id - 1 downto 0) := to_uvec(c_gn_id, c_sdp_W_gn_id); constant c_id : std_logic_vector(7 downto 0) := to_uvec(c_gn_id, 8); - constant c_cep_eth_src_mac : std_logic_vector(47 downto 0) := c_sdp_cep_eth_src_mac_47_16 & func_sdp_gn_index_to_mac_15_0(c_gn_id); - constant c_cep_ip_src_addr : std_logic_vector(31 downto 0) := c_sdp_cep_ip_src_addr_31_16 & func_sdp_gn_index_to_ip_15_0(c_gn_id); + constant c_cep_eth_src_mac : std_logic_vector(47 downto 0) := c_sdp_cep_eth_src_mac_47_16 & + func_sdp_gn_index_to_mac_15_0(c_gn_id); + constant c_cep_ip_src_addr : std_logic_vector(31 downto 0) := c_sdp_cep_ip_src_addr_31_16 & + func_sdp_gn_index_to_ip_15_0(c_gn_id); constant c_cep_udp_src_port : std_logic_vector(15 downto 0) := c_sdp_cep_udp_src_port_15_8 & c_id; + constant c_reorder_nof_blocks_arr : t_natural_arr(1 to g_nof_destinations_max) := + func_sdp_bdo_reorder_nof_blocks_look_up_table(g_nof_destinations_max); + + constant c_nof_beamlets_per_block_first_destinations_arr : t_natural_arr(1 to g_nof_destinations_max) := + func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(g_nof_destinations_max); + constant c_nof_beamlets_per_block : natural := c_nof_beamlets_per_block_first_destinations_arr(g_nof_destinations); + -- Checksum value obtained from rx_sdp_cep_header.ip.header_checksum in wave window - constant c_exp_ip_header_checksum : natural := 16#5BDB#; - constant c_exp_payload_error : std_logic := '0'; - constant c_exp_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; + constant c_exp_ip_header_checksum : natural := 16#5BDB#; + constant c_exp_payload_error : std_logic := '0'; + constant c_exp_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; constant c_exp_sdp_info : t_sdp_info := (to_uvec(7, 6), -- antenna_field_index to_uvec(601, 10), -- station_id @@ -88,6 +98,7 @@ architecture tb of tb_sdp_beamformer_output is x"1400" -- block_period = 5120 ); + signal mm_init : std_logic := '1'; signal tb_end : std_logic := '0'; signal dp_clk : std_logic := '1'; signal dp_rst : std_logic; @@ -116,14 +127,24 @@ architecture tb of tb_sdp_beamformer_output is signal rx_hdr_fields_out : std_logic_vector(1023 downto 0); signal rx_hdr_fields_raw : std_logic_vector(1023 downto 0) := (others => '0'); signal rx_beamlet_header : t_sdp_cep_header; - signal exp_beamlet_header : t_sdp_cep_header; - signal exp_dp_bsn : natural; + + signal exp_beamlet_header : t_sdp_cep_header; + signal exp_beamlet_index : natural; + signal exp_nof_blocks_per_packet : natural; + signal exp_nof_beamlets_per_block : natural; + signal exp_dp_bsn : natural; + + signal rx_offload_sosi : t_dp_sosi := c_dp_sosi_rst; + signal rx_offload_sop_cnt : natural := 0; + signal rx_DI : natural := 0; + + -- rx merge + signal rx_merge_sosi : t_dp_sosi := c_dp_sosi_rst; + signal rx_merge_sop_cnt : natural := 0; -- Beamlets packets data signal rx_beamlet_data : std_logic_vector(c_longword_w - 1 downto 0); -- 64 bit signal rx_beamlet_sosi : t_dp_sosi := c_dp_sosi_rst; - signal rx_beamlet_sop_cnt : natural := 0; - signal rx_beamlet_eop_cnt : natural := 0; -- [0 : 3] = X, Y, X, Y signal rx_beamlet_arr_re : t_sdp_beamlet_part_arr; @@ -149,20 +170,36 @@ begin mm_clk <= (not mm_clk) or tb_end after c_mm_clk_period / 2; p_mm : process + variable v_offset : natural; begin proc_common_wait_until_low(dp_clk, mm_rst); proc_common_wait_some_cycles(mm_clk, 10); ---------------------------------------------------------------------------- - -- BDO nof destinations + -- BDO multiple destinations info in sdp_bdo_destinations_reg ---------------------------------------------------------------------------- + -- . Set nof_destinations = g_nof_destinations proc_mem_mm_bus_wr(128, g_nof_destinations, mm_clk, reg_destinations_cipo, reg_destinations_copi); + -- . Use same destination MAC/IP/UPD for all destinations, to ease rx_beamlet_header verification + -- and to have same c_exp_ip_header_checksum value for all g_nof_destinations. + for DI in 0 to g_nof_destinations - 1 loop + proc_mem_mm_bus_wr(DI * 2 + 1, to_uint(c_sdp_cep_eth_dst_mac(47 downto 32)), mm_clk, reg_destinations_cipo, reg_destinations_copi); + proc_mem_mm_bus_wr(DI * 2, to_sint(c_sdp_cep_eth_dst_mac(31 downto 0)), mm_clk, reg_destinations_cipo, reg_destinations_copi); + end loop; + v_offset := c_sdp_bdo_mm_nof_destinations_max * 2; + for DI in 0 to g_nof_destinations - 1 loop + proc_mem_mm_bus_wr(v_offset + DI, to_sint(c_sdp_cep_ip_dst_addr), mm_clk, reg_destinations_cipo, reg_destinations_copi); + end loop; + v_offset := c_sdp_bdo_mm_nof_destinations_max * 3; + for DI in 0 to g_nof_destinations - 1 loop + proc_mem_mm_bus_wr(v_offset + DI, to_uint(c_sdp_cep_udp_dst_port), mm_clk, reg_destinations_cipo, reg_destinations_copi); + end loop; + ---------------------------------------------------------------------------- - -- BDO header fields + -- BDO header src and single destination fields in dp_offload_tx_v3 ---------------------------------------------------------------------------- - -- . Use sim default dst and src MAC, IP, UDP port from sdp_pkg.vhd and - -- based on c_gn_id + -- . Use sim default dst and src MAC, IP, UDP port from sdp_pkg.vhd and based on c_gn_id -- . use signed to fit 32 b in integer proc_mem_mm_bus_wr(39, to_uint(c_cep_eth_src_mac(47 downto 32)), mm_clk, hdr_dat_cipo, hdr_dat_copi); proc_mem_mm_bus_wr(38, to_sint(c_cep_eth_src_mac(31 downto 0)), mm_clk, hdr_dat_cipo, hdr_dat_copi); @@ -177,6 +214,9 @@ begin -- Enable beamlet output (dp_xonoff) ---------------------------------------------------------------------------- proc_mem_mm_bus_wr(0, 1, mm_clk, reg_dp_xonoff_cipo, reg_dp_xonoff_copi); + + proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period, c_common_cross_clock_domain_latency * 2); + mm_init <= '0'; wait; end process; @@ -201,7 +241,7 @@ begin g_wait_last_evt => 100 ) port map ( - rst => dp_rst, + rst => mm_init, clk => dp_clk, -- Generate stimuli @@ -275,7 +315,7 @@ begin snk_in_arr(0) => bdo_sosi, snk_out_arr(0) => bdo_siso, - src_out_arr(0) => rx_beamlet_sosi, + src_out_arr(0) => rx_offload_sosi, hdr_fields_out_arr(0) => rx_hdr_fields_out, hdr_fields_raw_arr(0) => rx_hdr_fields_raw @@ -285,101 +325,177 @@ begin -- Beamlet offload packet header ----------------------------------------------------------------------------- - -- Counters to time expected cep_header fields per offload packet - p_test_counters : process(dp_clk) + -- Counters to time expected cep_header fields per rx_offload_sosi packet + p_rx_counters : process(dp_clk) begin if rising_edge(dp_clk) then - -- Count rx_beamlet_sosi packets - if rx_beamlet_sosi.sop = '1' then - rx_beamlet_sop_cnt <= rx_beamlet_sop_cnt + 1; -- early count + -- Count rx_offload_sosi packets, for fields per destination + if rx_offload_sosi.sop = '1' then + rx_offload_sop_cnt <= rx_offload_sop_cnt + 1; end if; - if rx_beamlet_sosi.eop = '1' then - rx_beamlet_eop_cnt <= rx_beamlet_eop_cnt + 1; -- after count + -- Count rx_merge_sosi packets, for BSN of all destinations + if rx_merge_sosi.sop = '1' then + rx_merge_sop_cnt <= rx_merge_sop_cnt + 1; end if; end if; end process; - -- Prepare exp_beamlet_header before rx_beamlet_sosi.eop, so that - -- p_verify_beamlet_header can verify it at rx_beamlet_sosi.eop. + -- Destination index (DI) + rx_DI <= rx_offload_sop_cnt mod g_nof_destinations; + + -- Prepare exp_beamlet_header before rx_offload_sosi.eop, so that + -- p_verify_beamlet_header can verify it at rx_offload_sosi.eop. exp_beamlet_header <= func_sdp_compose_cep_header(c_exp_ip_header_checksum, c_exp_sdp_info, c_gn_id, c_exp_payload_error, c_exp_beamlet_scale, - c_exp_beamlet_index, + exp_beamlet_index, + exp_nof_blocks_per_packet, + exp_nof_beamlets_per_block, exp_dp_bsn); rx_beamlet_header <= func_sdp_map_cep_header(rx_hdr_fields_raw); - p_verify_beamlet_header : process - variable v_bool : boolean; - begin - wait until rising_edge(dp_clk); - -- Prepare exp_sdp_cep_header at sop, so that it can be verified at eop - if rx_beamlet_sosi.sop = '1' then - -- Expected BSN increments by c_sdp_cep_nof_blocks_per_packet = 4 blocks - -- per packet - exp_dp_bsn <= c_init_bsn + rx_beamlet_sop_cnt * c_sdp_cep_nof_blocks_per_packet; - end if; + gen_verify_one_destination : if g_nof_destinations_max = 1 generate + -- Wires + rx_merge_sosi <= rx_offload_sosi; + rx_beamlet_sosi <= rx_offload_sosi; + + --------------------------------------------------------------------------- + -- Verify beamlet header + --------------------------------------------------------------------------- + exp_beamlet_index <= c_exp_beamlet_index; + exp_nof_blocks_per_packet <= c_sdp_cep_nof_blocks_per_packet; + exp_nof_beamlets_per_block <= c_sdp_cep_nof_beamlets_per_block; + + p_verify_beamlet_header : process + variable v_bool : boolean; + begin + wait until rising_edge(dp_clk); + -- Prepare exp_sdp_cep_header at sop, so that it can be verified at eop + if rx_offload_sosi.sop = '1' then + -- Expected BSN increments by c_sdp_cep_nof_blocks_per_packet = 4 blocks per packet + exp_dp_bsn <= c_init_bsn + rx_offload_sop_cnt * c_sdp_cep_nof_blocks_per_packet; + end if; - -- Verify header at eop - if rx_beamlet_sosi.eop = '1' then - v_bool := func_sdp_verify_cep_header(rx_beamlet_header, exp_beamlet_header); - end if; - end process; + -- Verify header at eop + if rx_offload_sosi.eop = '1' then + v_bool := func_sdp_verify_cep_header(rx_beamlet_header, exp_beamlet_header); + end if; + end process; + + ----------------------------------------------------------------------------- + -- Verify beamlet data + ----------------------------------------------------------------------------- + -- To view the 64 bit 10GbE offload data more easily in the Wave window + rx_beamlet_data <= rx_beamlet_sosi.data(c_longword_w - 1 downto 0); + + proc_sdp_rx_beamlet_octets(dp_clk, + rx_beamlet_sosi, + rx_beamlet_cnt, + rx_beamlet_valid, + rx_beamlet_arr_re, + rx_beamlet_arr_im, + rx_packet_list_re, + rx_packet_list_im); + + p_verify_rx_beamlet_list : process + -- Nof complex (= nof re = nof im = c_N) values in t_sdp_beamlet_packet_list + constant c_N : natural := c_sdp_cep_nof_beamlets_per_packet * c_sdp_N_pol_bf; + variable v_re : natural; + variable v_im : natural; + begin + -- Wait until end of a beamlet packet + -- . use at least one wait statement in process to avoid Modelsim warning: (vcom-1090) + wait until rising_edge(dp_clk); + proc_common_wait_until_hi_lo(dp_clk, rx_beamlet_sosi.eop); + if g_use_transpose then + -- Undo the beamlet output transpose, to have original beamlet order + rx_beamlet_list_re <= func_sdp_undo_transpose_beamlet_packet(rx_packet_list_re); + rx_beamlet_list_im <= func_sdp_undo_transpose_beamlet_packet(rx_packet_list_im); + else + -- Copy identity beamlet output order + rx_beamlet_list_re <= rx_packet_list_re; + rx_beamlet_list_im <= rx_packet_list_im; + end if; + rx_beamlet_list_val <= '1'; + + -- Wait until rx_beamlet_list is valid + wait until rising_edge(dp_clk); + rx_beamlet_list_val <= '0'; + -- Verify rx_beamlet_list + -- . get last values from previous block + v_re := prev_re; + v_im := prev_im; + for vI in 0 to c_N - 1 loop + -- Verify incrementing beamlets + v_re := (v_re + 1) mod c_beamlet_mod; + v_im := (v_im + 1) mod c_beamlet_mod; + assert to_uint(rx_beamlet_list_re(vI)) = v_re report "Wrong re_beamlet." severity error; + assert to_uint(rx_beamlet_list_im(vI)) = v_im report "Wrong im_beamlet." severity error; + end loop; + -- . hold last values for next block + prev_re <= v_re; + prev_im <= v_im; + end process; + end generate; + + gen_verify_multi_destinations : if g_nof_destinations_max > 1 generate + ----------------------------------------------------------------------------- + -- Merge rx offload packet data + ----------------------------------------------------------------------------- + -- Merge g_nof_destinations rx_offload_sosi packets into one rx_merge_sosi + -- packet to: + -- - determine same expected BSN for all g_nof_destinations, + -- - have all beamlet data for all beamlet indices in one packet. + u_dp_packet_merge : entity dp_lib.dp_packet_merge + generic map( + g_use_ready => false, -- no flow control + g_nof_pkt => g_nof_destinations, + g_bsn_increment => 1 + ) + port map( + rst => dp_rst, + clk => dp_clk, + + snk_in => rx_offload_sosi, + src_out => rx_merge_sosi + ); + + --------------------------------------------------------------------------- + -- Verify beamlet header + --------------------------------------------------------------------------- + exp_nof_blocks_per_packet <= c_reorder_nof_blocks_arr(g_nof_destinations_max); + + p_verify_beamlet_header : process + variable v_nof_beamlets : natural; + variable v_bool : boolean; + begin + wait until rising_edge(dp_clk); + -- Prepare exp_sdp_cep_header, so that it can be verified at rx_offload_sosi.eop + if rx_offload_sosi.sop = '1' then + -- Default expect nof_beamlets_per_block for first destinations + exp_nof_beamlets_per_block <= c_nof_beamlets_per_block; + if rx_DI = g_nof_destinations - 1 then + -- Remaining nof_beamlets_per_block for last destination + exp_nof_beamlets_per_block <= c_sdp_S_sub_bf - rx_DI * exp_nof_beamlets_per_block; + end if; + + -- Expected beamlet index increments by c_nof_beamlets_per_block per destination index + exp_beamlet_index <= rx_DI * c_nof_beamlets_per_block; + end if; - ----------------------------------------------------------------------------- - -- Beamlet offload packet data - ----------------------------------------------------------------------------- - -- To view the 64 bit 10GbE offload data more easily in the Wave window - rx_beamlet_data <= rx_beamlet_sosi.data(c_longword_w - 1 downto 0); - - proc_sdp_rx_beamlet_octets(dp_clk, - rx_beamlet_sosi, - rx_beamlet_cnt, - rx_beamlet_valid, - rx_beamlet_arr_re, - rx_beamlet_arr_im, - rx_packet_list_re, - rx_packet_list_im); - - p_verify_rx_beamlet_list : process - -- Nof complex (= nof re = nof im = c_N) values in t_sdp_beamlet_packet_list - constant c_N : natural := c_sdp_cep_nof_beamlets_per_packet * c_sdp_N_pol_bf; - variable v_re : natural; - variable v_im : natural; - begin - -- Wait until end of a beamlet packet - -- . use at least one wait statement in process to avoid Modelsim warning: (vcom-1090) - wait until rising_edge(dp_clk); - proc_common_wait_until_hi_lo(dp_clk, rx_beamlet_sosi.eop); - if g_use_transpose then - -- Undo the beamlet output transpose, to have original beamlet order - rx_beamlet_list_re <= func_sdp_undo_transpose_beamlet_packet(rx_packet_list_re); - rx_beamlet_list_im <= func_sdp_undo_transpose_beamlet_packet(rx_packet_list_im); - else - -- Copy identity beamlet output order - rx_beamlet_list_re <= rx_packet_list_re; - rx_beamlet_list_im <= rx_packet_list_im; - end if; - rx_beamlet_list_val <= '1'; - - -- Wait until rx_beamlet_list is valid - wait until rising_edge(dp_clk); - rx_beamlet_list_val <= '0'; - -- Verify rx_beamlet_list - -- . get last values from previous block - v_re := prev_re; - v_im := prev_im; - for vI in 0 to c_N - 1 loop - -- Verify incrementing beamlets - v_re := (v_re + 1) mod c_beamlet_mod; - v_im := (v_im + 1) mod c_beamlet_mod; - assert to_uint(rx_beamlet_list_re(vI)) = v_re report "Wrong re_beamlet." severity error; - assert to_uint(rx_beamlet_list_im(vI)) = v_im report "Wrong im_beamlet." severity error; - end loop; - -- . hold last values for next block - prev_re <= v_re; - prev_im <= v_im; - end process; + if rx_merge_sosi.sop = '1' then + -- Expected BSN increments by exp_nof_blocks_per_packet, after every merged packet + exp_dp_bsn <= c_init_bsn + rx_merge_sop_cnt * exp_nof_blocks_per_packet; + end if; + + -- Verify header at eop + if rx_offload_sosi.eop = '1' then + v_bool := func_sdp_verify_cep_header(rx_beamlet_header, exp_beamlet_header); + end if; + end process; + + end generate; end tb; diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_beamformer_output.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_beamformer_output.vhd index 60deb2ee5f..41feb65aad 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_beamformer_output.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_tb_sdp_beamformer_output.vhd @@ -42,6 +42,10 @@ begin -- g_nof_destinations_max : natural := 1; -- g_nof_destinations : natural := 1 + -- One BDO destination u_one_identity : entity work.tb_sdp_beamformer_output generic map( 50, 0, false, 1, 1); u_one_transpose : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 1, 1); + + -- Multiple BDO destinations + u_multi_16_16 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 16, 16); end tb; -- GitLab