diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd index 6af6e86d5f1f80b1e405178bc72182fe7888db4f..e33f2166ab48f8e3c6b0c3ba91232a8b110323fb 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd @@ -110,15 +110,26 @@ end package sdp_bdo_pkg; package body sdp_bdo_pkg is function func_sdp_bdo_parse_nof_destinations(nof_destinations, c_nof_destinations_max : natural) return natural is + constant c_last_arr : t_natural_arr(1 to c_nof_destinations_max) := + func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table(c_nof_destinations_max); + variable v_DN : natural := 1; begin -- Parse input nof_destinations value if nof_destinations = 0 then - return 1; + v_DN := 1; -- force to at least 1 destination elsif nof_destinations > c_nof_destinations_max then - return c_nof_destinations_max; + v_DN := c_nof_destinations_max; else - return nof_destinations; + v_DN := nof_destinations; end if; + -- Check whether nof beamlet indices can be distributed over v_DN + -- destinations, else force to use one less destination, see + -- func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table() + -- description for further explanation. + if c_last_arr(v_DN) = 0 then + v_DN := v_DN - 1; + end if; + return v_DN; end func_sdp_bdo_parse_nof_destinations; function func_sdp_bdo_reorder_nof_blocks_look_up_table(c_nof_destinations_max : natural) return t_natural_arr is @@ -179,6 +190,7 @@ package body sdp_bdo_pkg is variable v_first_arr : t_natural_arr(1 to c_nof_destinations_max) := func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(c_nof_destinations_max); variable v_last_arr : t_natural_arr(1 to c_nof_destinations_max); + variable v_last : integer; begin -- Determine remaining nof_beamlets_per_block for the last destination -- with index DN, as function of number of destinations DN. @@ -188,17 +200,30 @@ package body sdp_bdo_pkg is -- DN = 1:16 --> v_first_arr = 488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31 -- DN = 1:16 --> v_last_arr = 488, 244, 162, 122, 96, 78, 68, 61, 48, 47, 38, 37, 32, 33, 26, 23 -- + -- DN = 17:32 --> v_first_arr = 29, 28, 26, 25, 24, 23, 22, 21, 20, 19, 19, 18, 17, 17, 16, 16 + -- DN = 17:32 --> v_last_arr = 24, 12, 20, 13, 8, 5, 4, 5, 8, 13, -6, 2, 12, -5, 8, -8 + -- 27, 30, 32 -- Remark: - -- . The v_last_arr(DN) may be < v_first_arr(DN) - 1, so the last - -- destination may contain much less beamlets than the others. In - -- combination with dp_packet_unmerge it is not feasible to distribute - -- the beamlets evenly over all destinations, using v_hi beamlets for - -- some first destinations and v_lo = v_hi - 1 for the remaining - -- destinations. This is because dp_packet_unmerge can only unmerge the - -- same packet length for N - 1 blocks and then unmerge the remaining - -- data in the last block until the eop. + -- . The v_last_arr(DN) <= v_first_arr(DN), because dp_packet_unmerge + -- can only unmerge the same packet length for N - 1 blocks and then + -- unmerge the remaining data in the last block until the input eop. + -- . The v_last_arr(DN) can be < v_first_arr(DN) - 1, so the last + -- destination then contains much less beamlets than the others. + -- . In combination with dp_packet_unmerge it is not feasible to + -- distribute the beamlets evenly over all destinations, using v_first + -- beamlets for some first destinations and v_first - 1 beamlets for + -- the remaining destinations. + -- . The v_last must be > 0. Therefor some number of destinations are + -- not possible in combination with c_sdp_S_sub_bf = 488. From the + -- v_last_arr it follows that DN = 27, 30 and 32 are not possible for + -- multiple destination BDO. for DN in 1 to c_nof_destinations_max loop - v_last_arr(DN) := c_sdp_S_sub_bf - (DN - 1) * v_first_arr(DN); + v_last := c_sdp_S_sub_bf - (DN - 1) * v_first_arr(DN); + if v_last > 0 then + v_last_arr(DN) := v_last; + else + v_last_arr(DN) := 0; -- force 0 to fit in natural + end if; end loop; return v_last_arr; end func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table; @@ -213,10 +238,17 @@ package body sdp_bdo_pkg is -- Determine nof_ch per packet for the first 1:DN-1 destinations, as -- function of number of destinations DN. -- The packet lengths follow from c_nof_blocks_arr * c_nof_beamlets_arr: + -- DN = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 -- . c_nof_blocks_arr = 4, 8, 12, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 -- . c_nof_beamlets_arr = 488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31 -- . v_len_arr = 1952,1952,1956,1952,1568,1312,1120, 976, 880, 784, 720, 656, 608, 560, 528, 496 -- . nof octets = 7808,7808,7824,7808,6272,5248,4480,3904,3520,3136,2880,2624,2432,2240,2112,1984 + -- + -- DN = 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 + -- . c_nof_blocks_arr = 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 + -- . c_nof_beamlets_arr = 29, 28, 26, 25, 24, 23, 22, 21, 20, 19, 19, 18, 17, 17, 16, 16 + -- . v_len_arr = 464, 448, 416, 400, 384, 368, 352, 336, 320, 304, 304, 288, 272, 272, 256, 256 + -- . nof octets = 1856,1792,1664,1600,1536,1472,1408,1344,1280,1216,1216,1152,1088,1088,1024,1024 for DN in 1 to c_nof_destinations_max loop v_len_arr(DN) := c_nof_blocks_arr(DN) * c_nof_beamlets_arr(DN); end loop; 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 c70d84b4f70aabd2229dc0ebe5f712608ddf8073..3e49d71d9e2bfd15898420676ecbb8c78875ef5f 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 @@ -47,8 +47,8 @@ entity tb_sdp_beamformer_output is g_nof_repeat : natural := 50; g_beamset_id : natural := 0; g_use_transpose : boolean := false; - g_nof_destinations_max : natural := 16; - g_nof_destinations : natural := 16 + g_nof_destinations_max : natural := 32; + g_nof_destinations : natural := 32 ); end tb_sdp_beamformer_output; @@ -56,6 +56,14 @@ architecture tb of tb_sdp_beamformer_output is constant c_dp_clk_period : time := 5 ns; -- 200 MHz constant c_mm_clk_period : time := 1 ns; -- fast MM clk to speed up simulation + -- Restrict generic values to within supported range + constant c_nof_destinations_max : natural := + sel_a_b(g_nof_destinations_max <= c_sdp_bdo_mm_nof_destinations_max, + g_nof_destinations_max, + c_sdp_bdo_mm_nof_destinations_max); + constant c_nof_destinations : natural := + func_sdp_bdo_parse_nof_destinations(g_nof_destinations, c_nof_destinations_max); + constant c_beamlet_mod : natural := 2**c_sdp_W_beamlet; constant c_init_re : natural := 0; constant c_init_im : natural := 1; @@ -76,14 +84,14 @@ architecture tb of tb_sdp_beamformer_output is 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_mdi_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_mdi_nof_blocks_per_packet : natural := c_mdi_reorder_nof_blocks_arr(g_nof_destinations); + constant c_mdi_reorder_nof_blocks_arr : t_natural_arr(1 to c_nof_destinations_max) := + func_sdp_bdo_reorder_nof_blocks_look_up_table(c_nof_destinations_max); + constant c_mdi_nof_blocks_per_packet : natural := c_mdi_reorder_nof_blocks_arr(c_nof_destinations); - constant c_mdi_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_mdi_nof_beamlets_per_block_first_destinations_arr : t_natural_arr(1 to c_nof_destinations_max) := + func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(c_nof_destinations_max); constant c_mdi_nof_beamlets_per_block_per_destination : natural := - c_mdi_nof_beamlets_per_block_first_destinations_arr(g_nof_destinations); + c_mdi_nof_beamlets_per_block_first_destinations_arr(c_nof_destinations); constant c_mdi_nof_beamlets_all_destinations : natural := c_mdi_nof_blocks_per_packet * c_sdp_S_sub_bf; @@ -115,6 +123,8 @@ architecture tb of tb_sdp_beamformer_output is signal hdr_dat_cipo : t_mem_cipo; signal reg_destinations_copi : t_mem_copi := c_mem_mosi_rst; signal reg_destinations_cipo : t_mem_cipo; + signal rd_nof_destinations : natural; + signal rd_nof_destinations_act : natural; signal reg_dp_xonoff_copi : t_mem_copi := c_mem_copi_rst; signal reg_dp_xonoff_cipo : t_mem_cipo; @@ -136,6 +146,12 @@ architecture tb of tb_sdp_beamformer_output is signal exp_beamlet_header : t_sdp_cep_header; signal exp_dp_bsn : natural; + -- Use equivalent 'mdi_' signal to avoid Warning: Nonresolved signal may have + -- multiple sources. This warning occurs e.g. for integer type when a signal + -- is assigned in different generate sections, even when these generate + -- sections are mutually exclusive. For e.g. std_logic this warning does not + -- occur, because std_logic type is resolved in case of multiple drivers. + signal mdi_exp_beamlet_header : t_sdp_cep_header; signal mdi_exp_beamlet_index : natural; signal mdi_exp_nof_beamlets_per_block : natural; @@ -158,15 +174,16 @@ architecture tb of tb_sdp_beamformer_output is signal rx_beamlet_arr_re : t_sdp_beamlet_part_arr; signal rx_beamlet_arr_im : t_sdp_beamlet_part_arr; signal rx_beamlet_cnt : natural; + signal rx_mdi_beamlet_cnt : natural; signal rx_beamlet_valid : std_logic; - -- g_nof_destinations = 1: [0 : 4 * 488 * 2 - 1] = [0 : 3903] + -- c_nof_destinations = 1: [0 : 4 * 488 * 2 - 1] = [0 : 3903] signal rx_packet_list_re : t_sdp_beamlet_packet_list; signal rx_packet_list_im : t_sdp_beamlet_packet_list; signal rx_beamlet_list_re : t_sdp_beamlet_packet_list; signal rx_beamlet_list_im : t_sdp_beamlet_packet_list; signal rx_beamlet_list_val : std_logic := '0'; - -- g_nof_destinations > 1: [0 : N * 488 * 2 - 1], where N = c_mdi_nof_blocks_per_packet + -- c_nof_destinations > 1: [0 : N * 488 * 2 - 1], where N = c_mdi_nof_blocks_per_packet signal rx_mdi_packet_list_re : t_slv_8_arr(0 to c_mdi_nof_beamlets_all_destinations * c_sdp_N_pol_bf - 1); signal rx_mdi_packet_list_im : t_slv_8_arr(0 to c_mdi_nof_beamlets_all_destinations * c_sdp_N_pol_bf - 1); signal rx_mdi_beamlet_list_re : t_slv_8_arr(0 to c_mdi_nof_beamlets_all_destinations * c_sdp_N_pol_bf - 1); @@ -177,6 +194,8 @@ architecture tb of tb_sdp_beamformer_output is -- to fit count in c_sdp_W_beamlet bits signal prev_re : natural := (c_init_re - 1 + c_beamlet_mod) mod c_beamlet_mod; signal prev_im : natural := (c_init_im - 1 + c_beamlet_mod) mod c_beamlet_mod; + signal mdi_prev_re : natural := (c_init_re - 1 + c_beamlet_mod) mod c_beamlet_mod; + signal mdi_prev_im : natural := (c_init_im - 1 + c_beamlet_mod) mod c_beamlet_mod; begin dp_rst <= '1', '0' after c_dp_clk_period * 7; dp_clk <= (not dp_clk) or tb_end after c_dp_clk_period / 2; @@ -194,20 +213,38 @@ begin -- 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); + v_offset := c_sdp_bdo_mm_nof_destinations_max * 4; + proc_mem_mm_bus_wr(v_offset + 0, 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 + -- . Read back nof_destinations + proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period, c_common_cross_clock_domain_latency * 2); + proc_mem_mm_bus_rd(v_offset + 0, mm_clk, reg_destinations_cipo, reg_destinations_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rd_nof_destinations <= to_uint(reg_destinations_cipo.rddata(c_word_w - 1 downto 0)); + proc_common_wait_some_cycles(mm_clk, 1); + assert rd_nof_destinations = g_nof_destinations report "Wrong MM readback nof_destinations" severity error; + + -- . Read nof_destinations_act, to check that g_nof_destinations is + -- forced to c_nof_destinations + proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period, c_common_cross_clock_domain_latency * 2); + proc_mem_mm_bus_rd(v_offset + 1, mm_clk, reg_destinations_cipo, reg_destinations_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rd_nof_destinations_act <= to_uint(reg_destinations_cipo.rddata(c_word_w - 1 downto 0)); + proc_common_wait_some_cycles(mm_clk, 1); + assert rd_nof_destinations_act = c_nof_destinations report "Wrong MM read nof_destinations_act" severity error; + + -- . Use same destination MAC/IP/UDP for all destinations, to ease rx_beamlet_header verification + -- and to have same c_exp_ip_header_checksum value for all c_nof_destinations. + for DI in 0 to c_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 + for DI in 0 to c_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 + for DI in 0 to c_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; @@ -273,7 +310,7 @@ begin generic map ( g_beamset_id => g_beamset_id, g_use_transpose => g_use_transpose, - g_nof_destinations_max => g_nof_destinations_max, + g_nof_destinations_max => c_nof_destinations_max, g_sim_force_bsn_error => false ) port map ( @@ -356,11 +393,11 @@ begin end process; -- Destination index (DI) - rx_DI <= rx_offload_sop_cnt mod g_nof_destinations; + rx_DI <= rx_offload_sop_cnt mod c_nof_destinations; rx_beamlet_header <= func_sdp_map_cep_header(rx_hdr_fields_raw); - gen_verify_one_destination : if g_nof_destinations_max = 1 generate + gen_verify_one_destination : if c_nof_destinations_max = 1 generate -- Wires rx_merge_sosi <= rx_offload_sosi; rx_beamlet_sosi <= rx_offload_sosi; @@ -452,18 +489,18 @@ begin end process; end generate; - gen_verify_multi_destinations : if g_nof_destinations_max > 1 generate + gen_verify_multi_destinations : if c_nof_destinations_max > 1 generate ----------------------------------------------------------------------------- -- Merge rx offload packet data ----------------------------------------------------------------------------- - -- Merge g_nof_destinations rx_offload_sosi packets into one rx_merge_sosi + -- Merge c_nof_destinations rx_offload_sosi packets into one rx_merge_sosi -- packet to: - -- - determine same expected BSN for all g_nof_destinations, + -- - determine same expected BSN for all c_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_nof_pkt => c_nof_destinations, g_bsn_increment => 1 ) port map( @@ -498,7 +535,7 @@ begin if rx_offload_sosi.sop = '1' then -- Default expect nof_beamlets_per_block for first destinations mdi_exp_nof_beamlets_per_block <= c_mdi_nof_beamlets_per_block_per_destination; - if rx_DI = g_nof_destinations - 1 then + if rx_DI = c_nof_destinations - 1 then -- Remaining nof_beamlets_per_block for last destination mdi_exp_nof_beamlets_per_block <= c_sdp_S_sub_bf - rx_DI * mdi_exp_nof_beamlets_per_block; end if; @@ -509,7 +546,7 @@ begin if rx_merge_sosi.sop = '1' then -- Expected BSN increments by c_mdi_nof_blocks_per_packet, after every merged packet, - -- because packets for all g_nof_destinations have same BSN. + -- because packets for all c_nof_destinations have same BSN. mdi_exp_dp_bsn <= c_init_bsn + rx_merge_sop_cnt * c_mdi_nof_blocks_per_packet; end if; @@ -532,7 +569,7 @@ begin proc_sdp_rx_beamlet_octets(c_mdi_nof_blocks_per_packet, dp_clk, rx_beamlet_sosi, - rx_beamlet_cnt, + rx_mdi_beamlet_cnt, rx_beamlet_valid, rx_beamlet_arr_re, rx_beamlet_arr_im, @@ -565,8 +602,8 @@ begin rx_mdi_beamlet_list_val <= '0'; -- Verify rx_beamlet_list -- . get last values from previous block - v_re := prev_re; - v_im := prev_im; + v_re := mdi_prev_re; + v_im := mdi_prev_im; for vI in 0 to c_N - 1 loop -- Verify incrementing beamlets v_re := (v_re + 1) mod c_beamlet_mod; @@ -575,8 +612,8 @@ begin assert to_uint(rx_mdi_beamlet_list_im(vI)) = v_im report "Wrong mdi im_beamlet." severity error; end loop; -- . hold last values for next block - prev_re <= v_re; - prev_im <= v_im; + mdi_prev_re <= v_re; + mdi_prev_im <= v_im; 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 41feb65aad8d76d0fd063048385e2688e847353b..7adf4c692ece6900d38921cb929a9406d43ae611 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 @@ -47,5 +47,16 @@ begin u_one_transpose : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 1, 1); -- Multiple BDO destinations + -- . prime number combination + u_multi_3_7 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 3, 7); + -- . use 1 destnation, when more are available + u_multi_1_16 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 1, 16); + -- . use all destinations that are available u_multi_16_16 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 16, 16); + -- . use prime number of destination from maximum available + u_multi_7_32 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 7, 32); + -- . use unfeasible number of destination, to check that it becomes 1 less + u_multi_32_32 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 32, 32); + -- . use maximum number of destinations + u_multi_31_32 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 31, 32); end tb;