diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_bf/tb_lofar2_unb2b_sdp_station_bf.vhd b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_bf/tb_lofar2_unb2b_sdp_station_bf.vhd index c8614845fb78c196b93ba64c9d0654c6e5567946..fc88e90a4a3bb1d561ce39a0571146b0799a99ec 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_bf/tb_lofar2_unb2b_sdp_station_bf.vhd +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_bf/tb_lofar2_unb2b_sdp_station_bf.vhd @@ -141,6 +141,7 @@ architecture tb of tb_lofar2_unb2b_sdp_station_bf is constant c_exp_beamlet_scale : natural := natural(g_beamlet_scale * real(c_sdp_unit_beamlet_scale)); -- c_sdp_unit_beamlet_scale = 2**15; constant c_exp_beamlet_index : natural := 0; -- depends on beamset bset * c_sdp_S_sub_bf + constant c_beamlet_index_mod : boolean := true; constant c_exp_sdp_info : t_sdp_info := ( TO_UVEC(3, 6), -- antenna_field_index @@ -1094,7 +1095,9 @@ begin -- Therefore accept any beamlet_index MOD c_sdp_S_sub_bf = 0 as correct -- in func_sdp_verify_cep_header(). if rx_beamlet_sosi.eop = '1' then - v_bool := func_sdp_verify_cep_header(rx_sdp_cep_header, exp_sdp_cep_header); + v_bool := func_sdp_verify_cep_header(rx_sdp_cep_header, + exp_sdp_cep_header, + c_beamlet_index_mod); end if; end process; diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station.vhd b/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station.vhd index d1081da37d29c20e329ab796f227ceff30d126bb..b293ea12e27dbbe5832679200f756b61de20950c 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station.vhd +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station.vhd @@ -804,20 +804,20 @@ begin ----------------------------------------------------------------------------- u_sdp_station : entity lofar2_sdp_lib.sdp_station generic map ( - g_sim => g_sim, - g_wpfb => g_wpfb, - g_wpfb_complex => g_wpfb_complex, - g_bsn_nof_clk_per_sync => g_bsn_nof_clk_per_sync, - g_scope_selected_subband => g_scope_selected_subband, - g_no_jesd => c_revision_select.no_jesd, - g_use_fsub => c_revision_select.use_fsub, - g_use_oversample => c_revision_select.use_oversample, - g_use_xsub => c_revision_select.use_xsub, - g_use_bf => c_revision_select.use_bf, - g_use_bdo_transpose => c_revision_select.use_bdo_transpose, - g_use_bdo_multiple_destinations => c_revision_select.use_bdo_multiple_destinations, - g_use_ring => c_revision_select.use_ring, - g_P_sq => c_revision_select.P_sq + g_sim => g_sim, + g_wpfb => g_wpfb, + g_wpfb_complex => g_wpfb_complex, + g_bsn_nof_clk_per_sync => g_bsn_nof_clk_per_sync, + g_scope_selected_subband => g_scope_selected_subband, + g_no_jesd => c_revision_select.no_jesd, + g_use_fsub => c_revision_select.use_fsub, + g_use_oversample => c_revision_select.use_oversample, + g_use_xsub => c_revision_select.use_xsub, + g_use_bf => c_revision_select.use_bf, + g_use_bdo_transpose => c_revision_select.use_bdo_transpose, + g_nof_bdo_destinations_max => c_revision_select.nof_bdo_destinations_max, + g_use_ring => c_revision_select.use_ring, + g_P_sq => c_revision_select.P_sq ) port map ( diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station_pkg.vhd b/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station_pkg.vhd index e65f35ec02f1047a436b00813f96f2f1ada738ec..f7da00a28564493a8e525870cb770b4ef89469cb 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station_pkg.vhd +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/src/vhdl/lofar2_unb2b_sdp_station_pkg.vhd @@ -31,31 +31,31 @@ package lofar2_unb2b_sdp_station_pkg is ----------------------------------------------------------------------------- type t_lofar2_unb2b_sdp_station_config is record - no_jesd : boolean; - use_fsub : boolean; - use_oversample : boolean; - use_bf : boolean; - use_bdo_transpose : boolean; - use_bdo_multiple_destinations : boolean; - use_xsub : boolean; - use_ring : boolean; - P_sq : natural; + no_jesd : boolean; + use_fsub : boolean; + use_oversample : boolean; + use_bf : boolean; + use_bdo_transpose : boolean; + nof_bdo_destinations_max : natural; -- <= c_sdp_bdo_mm_nof_destinations_max + use_xsub : boolean; + use_ring : boolean; + P_sq : natural; end record; - constant c_ait : t_lofar2_unb2b_sdp_station_config := (false, false, false, false, false, false, false, false, 0); - constant c_fsub : t_lofar2_unb2b_sdp_station_config := (false, true, false, false, false, false, false, false, 0); + constant c_ait : t_lofar2_unb2b_sdp_station_config := (false, false, false, false, false, 1, false, false, 0); + constant c_fsub : t_lofar2_unb2b_sdp_station_config := (false, true, false, false, false, 1, false, false, 0); -- use c_bf on one node also to simulate bdo transpose -- use c_bf_ring with ring also to simulate bdo identity - constant c_bf : t_lofar2_unb2b_sdp_station_config := (false, true, false, true, false, false, false, false, 0); - constant c_bf_ring : t_lofar2_unb2b_sdp_station_config := (false, true, false, true, false, false, false, true, 0); - constant c_xsub_one : t_lofar2_unb2b_sdp_station_config := (false, true, false, false, false, false, true, false, 1); - constant c_xsub_ring : t_lofar2_unb2b_sdp_station_config := (false, true, false, false, false, false, true, true, 9); + constant c_bf : t_lofar2_unb2b_sdp_station_config := (false, true, false, true, false, 1, false, false, 0); + constant c_bf_ring : t_lofar2_unb2b_sdp_station_config := (false, true, false, true, false, 1, false, true, 0); + constant c_xsub_one : t_lofar2_unb2b_sdp_station_config := (false, true, false, false, false, 1, true, false, 1); + constant c_xsub_ring : t_lofar2_unb2b_sdp_station_config := (false, true, false, false, false, 1, true, true, 9); -- use c_full_wg for SDP regression test on Arts-unb2b - constant c_full_wg : t_lofar2_unb2b_sdp_station_config := (true, true, false, true, true, false, true, true, 9); - constant c_full : t_lofar2_unb2b_sdp_station_config := (false, true, false, true, false, false, true, true, 9); - constant c_full_wg_os : t_lofar2_unb2b_sdp_station_config := (true, true, true, true, false, false, true, true, 9); + constant c_full_wg : t_lofar2_unb2b_sdp_station_config := (true, true, false, true, true, 1, true, true, 9); + constant c_full : t_lofar2_unb2b_sdp_station_config := (false, true, false, true, false, 1, true, true, 9); + constant c_full_wg_os : t_lofar2_unb2b_sdp_station_config := (true, true, true, true, false, 1, true, true, 9); -- use c_full_os for SDP on LTS-unb2b of Disturb2 - constant c_full_os : t_lofar2_unb2b_sdp_station_config := (false, true, true, true, false, false, true, true, 9); + constant c_full_os : t_lofar2_unb2b_sdp_station_config := (false, true, true, true, false, 1, true, true, 9); -- Function to select the revision configuration. function func_sel_revision_rec(g_design_name : string) return t_lofar2_unb2b_sdp_station_config; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd index 0e6167477ddb76d0a8d3921ad585908e4aa30fce..6d12a8748c603307877e1ff8b00d90efd6c72014 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd @@ -233,6 +233,7 @@ architecture tb of tb_lofar2_unb2c_sdp_station_bf is constant c_exp_beamlet_scale : natural := natural(g_beamlet_scale * real(c_sdp_unit_beamlet_scale)); -- c_sdp_unit_beamlet_scale = 2**15; constant c_exp_beamlet_index : natural := 0; -- depends on beamset bset * c_sdp_S_sub_bf + constant c_beamlet_index_mod : boolean := true; constant c_exp_sdp_info : t_sdp_info := ( TO_UVEC(3, 6), -- antenna_field_index @@ -1352,7 +1353,9 @@ begin -- Therefore accept any beamlet_index MOD c_sdp_S_sub_bf = 0 as correct -- in func_sdp_verify_cep_header(). if rx_beamlet_sosi.eop = '1' then - v_bool := func_sdp_verify_cep_header(rx_sdp_cep_header, exp_sdp_cep_header); + v_bool := func_sdp_verify_cep_header(rx_sdp_cep_header, + exp_sdp_cep_header, + c_beamlet_index_mod); end if; end process; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd index f4ada61682a5443c7be855ec9c9ad6a42fd86828..18702afb27646b839fa7bcb523075e7799bd1366 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd @@ -245,6 +245,7 @@ architecture tb of tb_lofar2_unb2c_sdp_station_bf_ring is constant c_exp_beamlet_scale : natural := natural(g_beamlet_scale * real(c_sdp_unit_beamlet_scale)); -- c_sdp_unit_beamlet_scale = 2**15; constant c_exp_beamlet_index : natural := 0; -- depends on beamset bset * c_sdp_S_sub_bf + constant c_beamlet_index_mod : boolean := true; constant c_exp_sdp_info : t_sdp_info := ( TO_UVEC(3, 6), -- antenna_field_index @@ -1443,7 +1444,9 @@ begin -- Therefore accept any beamlet_index MOD c_sdp_S_sub_bf = 0 as correct -- in func_sdp_verify_cep_header(). if rx_beamlet_sosi.eop = '1' then - v_bool := func_sdp_verify_cep_header(rx_sdp_cep_header, exp_sdp_cep_header); + v_bool := func_sdp_verify_cep_header(rx_sdp_cep_header, + exp_sdp_cep_header, + c_beamlet_index_mod); end if; end process; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station.vhd index 6862b4620fc00a9e665f8fe07edd96d13fd9737a..d9154faa443f87f2a84acb36e108a01eb2d24772 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station.vhd @@ -770,19 +770,19 @@ begin ----------------------------------------------------------------------------- u_sdp_station : entity lofar2_sdp_lib.sdp_station generic map ( - g_sim => g_sim, - g_wpfb => g_wpfb, - g_bsn_nof_clk_per_sync => g_bsn_nof_clk_per_sync, - g_scope_selected_subband => g_scope_selected_subband, - g_no_jesd => c_revision_select.no_jesd, - g_use_fsub => c_revision_select.use_fsub, - g_use_oversample => c_revision_select.use_oversample, - g_use_xsub => c_revision_select.use_xsub, - g_use_bf => c_revision_select.use_bf, - g_use_bdo_transpose => c_revision_select.use_bdo_transpose, - g_use_bdo_multiple_destinations => c_revision_select.use_bdo_multiple_destinations, - g_use_ring => c_revision_select.use_ring, - g_P_sq => c_revision_select.P_sq + g_sim => g_sim, + g_wpfb => g_wpfb, + g_bsn_nof_clk_per_sync => g_bsn_nof_clk_per_sync, + g_scope_selected_subband => g_scope_selected_subband, + g_no_jesd => c_revision_select.no_jesd, + g_use_fsub => c_revision_select.use_fsub, + g_use_oversample => c_revision_select.use_oversample, + g_use_xsub => c_revision_select.use_xsub, + g_use_bf => c_revision_select.use_bf, + g_use_bdo_transpose => c_revision_select.use_bdo_transpose, + g_nof_bdo_destinations_max => c_revision_select.nof_bdo_destinations_max, + g_use_ring => c_revision_select.use_ring, + g_P_sq => c_revision_select.P_sq ) port map ( diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd index 89fdb57b349264aec4d9125bb723b0abc2746532..177d5cfa3f656620bf33c69a72e92c8420474743 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd @@ -31,30 +31,30 @@ package lofar2_unb2c_sdp_station_pkg is ----------------------------------------------------------------------------- type t_lofar2_unb2c_sdp_station_config is record - no_jesd : boolean; - use_fsub : boolean; - use_oversample : boolean; - use_bf : boolean; - use_bdo_transpose : boolean; - use_bdo_multiple_destinations : boolean; - use_xsub : boolean; - use_ring : boolean; - P_sq : natural; + no_jesd : boolean; + use_fsub : boolean; + use_oversample : boolean; + use_bf : boolean; + use_bdo_transpose : boolean; + nof_bdo_destinations_max : natural; -- <= c_sdp_bdo_mm_nof_destinations_max + use_xsub : boolean; + use_ring : boolean; + P_sq : natural; end record; - constant c_ait : t_lofar2_unb2c_sdp_station_config := (false, false, false, false, false, false, false, false, 0); - constant c_fsub : t_lofar2_unb2c_sdp_station_config := (false, true, false, false, false, false, false, false, 0); + constant c_ait : t_lofar2_unb2c_sdp_station_config := (false, false, false, false, false, 1, false, false, 0); + constant c_fsub : t_lofar2_unb2c_sdp_station_config := (false, true, false, false, false, 1, false, false, 0); -- use c_bf on one node also to simulate bdo transpose -- use c_bf_ring with ring also to simulate bdo identity - constant c_bf : t_lofar2_unb2c_sdp_station_config := (false, true, false, true, true, false, false, false, 0); - constant c_bf_ring : t_lofar2_unb2c_sdp_station_config := (false, true, false, true, false, false, false, true, 0); - constant c_xsub_one : t_lofar2_unb2c_sdp_station_config := (false, true, false, false, false, false, true, false, 1); - constant c_xsub_ring : t_lofar2_unb2c_sdp_station_config := (false, true, false, false, false, false, true, true, 9); - constant c_full_wg : t_lofar2_unb2c_sdp_station_config := (true, true, false, true, true, false, true, true, 9); + constant c_bf : t_lofar2_unb2c_sdp_station_config := (false, true, false, true, true, 1, false, false, 0); + constant c_bf_ring : t_lofar2_unb2c_sdp_station_config := (false, true, false, true, false, 1, false, true, 0); + constant c_xsub_one : t_lofar2_unb2c_sdp_station_config := (false, true, false, false, false, 1, true, false, 1); + constant c_xsub_ring : t_lofar2_unb2c_sdp_station_config := (false, true, false, false, false, 1, true, true, 9); + constant c_full_wg : t_lofar2_unb2c_sdp_station_config := (true, true, false, true, true, 1, true, true, 9); -- Use c_full for LOFAR2 Station SDP operations - constant c_full : t_lofar2_unb2c_sdp_station_config := (false, true, false, true, true, false, true, true, 9); - constant c_full_wg_os : t_lofar2_unb2c_sdp_station_config := (true, true, true, true, true, false, true, true, 9); - constant c_full_os : t_lofar2_unb2c_sdp_station_config := (false, true, true, true, true, false, true, true, 9); + constant c_full : t_lofar2_unb2c_sdp_station_config := (false, true, false, true, true, 1, true, true, 9); + constant c_full_wg_os : t_lofar2_unb2c_sdp_station_config := (true, true, true, true, true, 1, true, true, 9); + constant c_full_os : t_lofar2_unb2c_sdp_station_config := (false, true, true, true, true, 1, true, true, 9); -- Function to select the revision configuration. function func_sel_revision_rec(g_design_name : string) return t_lofar2_unb2c_sdp_station_config; diff --git a/applications/lofar2/libraries/sdp/sdp.peripheral.yaml b/applications/lofar2/libraries/sdp/sdp.peripheral.yaml index 17b64c399c61a6e6aa3646a6b5497c1f86501d8f..3aebc0f87361b67dbb7c29fa4cd6e6d8e756efab 100644 --- a/applications/lofar2/libraries/sdp/sdp.peripheral.yaml +++ b/applications/lofar2/libraries/sdp/sdp.peripheral.yaml @@ -193,11 +193,10 @@ peripherals: - peripheral_name: sdp_bdo_destinations peripheral_description: "SDP beamlet data output (BDO) destinations." parameters: - # Parameters fixed in sdp_beamformer_output.vhd / sdp_pkg.vhd - - { name: N_destinations_max, value: 16 } - - { name: N_reorder_blocks_max, value: 16 } + # Parameters fixed in sdp_bdo_destinations_reg.vhd / sdp_pkg.vhd + - { name: N_destinations_max, value: 32 } mm_ports: - # MM port for sdp_beamformer_output.vhd / mm_fields.vhd + # MM port for sdp_bdo_destinations_reg.vhd / mm_fields.vhd - mm_port_name: REG_BDO_DESTINATIONS mm_port_type: REG mm_port_span: 16 * MM_BUS_SIZE @@ -207,15 +206,15 @@ peripherals: The number of destinations is 1 <= nof_destinations <= N_destinations_max. The actual nof_destinations is reported via nof_destinations_act. The actual number of blocks per packet depends on nof_destinations_act, and is reported - via nof_blocks_per_packet_act." + via nof_blocks_per_packet." fields: - - { field_name: eth_destination_mac, number_of_fields: N_destinations_max, mm_width: 32, user_width: 48, radix: uint64, access_mode: RW, address_offset: 0x0 } - - - { field_name: ip_destination_address, number_of_fields: N_destinations_max, mm_width: 32, access_mode: RW, address_offset: 0x80 } - - - { field_name: udp_destination_port, number_of_fields: N_destinations_max, mm_width: 16, access_mode: RW, address_offset: 0xC0 } - - - { field_name: nof_destinations, mm_width: 8, access_mode: RW, address_offset: 0x100 } - - - { field_name: nof_destinations_act, mm_width: 8, access_mode: RO, address_offset: 0x104 } - - - { field_name: nof_destinations_max, mm_width: 8, access_mode: RO, address_offset: 0x108 } - - - { field_name: nof_blocks_per_packet_act, mm_width: 8, access_mode: RO, address_offset: 0x10C } + - - { field_name: ip_destination_address, number_of_fields: N_destinations_max, mm_width: 32, access_mode: RW, address_offset: 0x100 } + - - { field_name: udp_destination_port, number_of_fields: N_destinations_max, mm_width: 16, access_mode: RW, address_offset: 0x180 } + - - { field_name: nof_destinations, mm_width: 8, access_mode: RW, address_offset: 0x200 } # = 512 = 128 * 4 + - - { field_name: nof_destinations_act, mm_width: 8, access_mode: RO, address_offset: 0x204 } # = 516 = 129 * 4 + - - { field_name: nof_destinations_max, mm_width: 8, access_mode: RO, address_offset: 0x208 } # = 520 = 130 * 4 + - - { field_name: nof_blocks_per_packet, mm_width: 8, access_mode: RO, address_offset: 0x20C } # = 524 = 131 * 4 - peripheral_name: sdp_beamformer_output_hdr_dat # pi_dp_offload_tx_hdr_dat_lofar2_beamformer_output.py diff --git a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd index 6a5a17961acb3510a95d385887ca5858ecead7e2..16bba9218c6b21e76bb1aeacfc4dfa45e66fee83 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_beamformer.vhd @@ -40,13 +40,13 @@ use work.sdp_pkg.all; entity node_sdp_beamformer is generic ( + -- Use no default, to force instance to set it g_sim : boolean := false; g_sim_sdp : t_sdp_sim := c_sdp_sim; - g_beamset_id : natural := 0; - g_use_bdo_transpose : boolean := false; - g_use_bdo_multiple_destinations : boolean := false; + g_beamset_id : natural; + g_use_bdo_transpose : boolean; + g_nof_bdo_destinations_max : natural; g_scope_selected_beamlet : natural := 0; - -- Use no default raw width, to force instance to set it g_subband_raw_dat_w : natural; -- default: c_sdp_W_subband; g_subband_raw_fraction_w : natural -- default: 0 ); @@ -256,9 +256,9 @@ begin --------------------------------------------------------------- u_sdp_beamformer_output : entity work.sdp_beamformer_output generic map( - g_beamset_id => g_beamset_id, - g_use_transpose => g_use_bdo_transpose, - g_use_multiple_destinations => g_use_bdo_multiple_destinations + g_beamset_id => g_beamset_id, + g_use_transpose => g_use_bdo_transpose, + g_nof_destinations_max => g_nof_bdo_destinations_max ) port map ( mm_rst => mm_rst, diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd index 89a9aa97d18a6133b9a7016dccac5be15253a145..8c5d010163da02bded46c30793f8c9a655ffdd0a 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd @@ -50,6 +50,9 @@ library IEEE, common_lib, mm_lib; use work.sdp_bdo_pkg.all; entity sdp_bdo_destinations_reg is + generic ( + g_nof_destinations_max : natural + ); port ( -- Clocks and reset mm_clk : in std_logic; @@ -67,11 +70,27 @@ end sdp_bdo_destinations_reg; architecture str of sdp_bdo_destinations_reg is constant c_field_arr : t_common_field_arr(c_sdp_bdo_destinations_info_nof_hdr_fields - 1 downto 0) := - ( (field_name_pad("nof_blocks_per_packet_act"), "RO", 8, field_default(c_sdp_cep_nof_blocks_per_packet)), - (field_name_pad("nof_destinations_max"), "RO", 8, field_default(1)), + ( (field_name_pad("nof_blocks_per_packet"), "RO", 8, field_default(c_sdp_cep_nof_blocks_per_packet)), + (field_name_pad("nof_destinations_max"), "RO", 8, field_default(g_nof_destinations_max)), (field_name_pad("nof_destinations_act"), "RO", 8, field_default(1)), (field_name_pad("nof_destinations"), "RW", 8, field_default(1)), + (field_name_pad("udp_destination_port_31"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_30"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_29"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_28"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_27"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_26"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_25"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_24"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_23"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_22"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_21"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_20"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_19"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_18"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_17"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_16"), "RW", 16, field_default(0)), (field_name_pad("udp_destination_port_15"), "RW", 16, field_default(0)), (field_name_pad("udp_destination_port_14"), "RW", 16, field_default(0)), (field_name_pad("udp_destination_port_13"), "RW", 16, field_default(0)), @@ -89,6 +108,22 @@ architecture str of sdp_bdo_destinations_reg is (field_name_pad("udp_destination_port_1"), "RW", 16, field_default(0)), (field_name_pad("udp_destination_port_0"), "RW", 16, field_default(0)), + (field_name_pad("ip_destination_address_31"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_30"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_29"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_28"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_27"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_26"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_25"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_24"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_23"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_22"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_21"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_20"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_19"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_18"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_17"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_16"), "RW", 32, field_default(0)), (field_name_pad("ip_destination_address_15"), "RW", 32, field_default(0)), (field_name_pad("ip_destination_address_14"), "RW", 32, field_default(0)), (field_name_pad("ip_destination_address_13"), "RW", 32, field_default(0)), @@ -106,6 +141,22 @@ architecture str of sdp_bdo_destinations_reg is (field_name_pad("ip_destination_address_1"), "RW", 32, field_default(0)), (field_name_pad("ip_destination_address_0"), "RW", 32, field_default(0)), + (field_name_pad("eth_destination_mac_31"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_30"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_29"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_28"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_27"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_26"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_25"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_24"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_23"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_22"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_21"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_20"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_19"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_18"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_17"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_16"), "RW", 48, field_default(0)), (field_name_pad("eth_destination_mac_15"), "RW", 48, field_default(0)), (field_name_pad("eth_destination_mac_14"), "RW", 48, field_default(0)), (field_name_pad("eth_destination_mac_13"), "RW", 48, field_default(0)), @@ -126,25 +177,33 @@ architecture str of sdp_bdo_destinations_reg is signal mm_fields_in : std_logic_vector(field_slv_in_len(c_field_arr) - 1 downto 0); signal mm_fields_out : std_logic_vector(field_slv_out_len(c_field_arr) - 1 downto 0); - signal destinations_info_rd : t_sdp_bdo_destinations_info; - signal destinations_info_wr : t_sdp_bdo_destinations_info; + signal destinations_info_rd : t_sdp_bdo_destinations_info := c_sdp_bdo_destinations_info_rst; + signal destinations_info_wr : t_sdp_bdo_destinations_info := c_sdp_bdo_destinations_info_rst; - signal nof_destinations_act : natural := 1; - signal nof_blocks_per_packet_act : natural := c_sdp_cep_nof_blocks_per_packet; + signal nof_destinations_act : natural := 1; + signal nof_blocks_per_packet : natural := c_sdp_cep_nof_blocks_per_packet; begin destinations_info <= destinations_info_rd; p_destinations_info_rd : process(destinations_info_wr, nof_destinations_act, - nof_blocks_per_packet_act) + nof_blocks_per_packet) begin - -- default write assign all fields - destinations_info_rd <= destinations_info_wr; + -- read/write fields + for DI in 0 to g_nof_destinations_max - 1 loop + -- Default only read/write connect the available fields. Leave unused + -- write fields open and read fields at rst value, so they will be + -- optimized away by synthesis. + destinations_info_rd.eth_destination_mac_arr(DI) <= destinations_info_wr.eth_destination_mac_arr(DI); + destinations_info_rd.ip_destination_address_arr(DI) <= destinations_info_wr.ip_destination_address_arr(DI); + destinations_info_rd.udp_destination_port_arr(DI) <= destinations_info_wr.udp_destination_port_arr(DI); + end loop; + destinations_info_rd.nof_destinations <= destinations_info_wr.nof_destinations; - -- overrule the read only fields - destinations_info_rd.nof_destinations_act <= nof_destinations_act; - destinations_info_rd.nof_destinations_max <= c_sdp_bdo_nof_destinations_max; - destinations_info_rd.nof_blocks_per_packet_act <= nof_blocks_per_packet_act; + -- read only fields + destinations_info_rd.nof_destinations_act <= nof_destinations_act; + destinations_info_rd.nof_destinations_max <= g_nof_destinations_max; + destinations_info_rd.nof_blocks_per_packet <= nof_blocks_per_packet; end process; u_mm_fields: entity mm_lib.mm_fields @@ -169,9 +228,9 @@ begin ); -- add "RO" fields to mm_fields - mm_fields_in(field_hi(c_field_arr, "nof_destinations_act") downto field_lo(c_field_arr, "nof_destinations_act")) <= to_uvec(destinations_info_rd.nof_destinations_act, 8); - mm_fields_in(field_hi(c_field_arr, "nof_destinations_max") downto field_lo(c_field_arr, "nof_destinations_max")) <= to_uvec(destinations_info_rd.nof_destinations_max, 8); - mm_fields_in(field_hi(c_field_arr, "nof_blocks_per_packet_act") downto field_lo(c_field_arr, "nof_blocks_per_packet_act")) <= to_uvec(destinations_info_rd.nof_blocks_per_packet_act, 8); + mm_fields_in(field_hi(c_field_arr, "nof_destinations_act") downto field_lo(c_field_arr, "nof_destinations_act")) <= to_uvec(destinations_info_rd.nof_destinations_act, 8); + mm_fields_in(field_hi(c_field_arr, "nof_destinations_max") downto field_lo(c_field_arr, "nof_destinations_max")) <= to_uvec(destinations_info_rd.nof_destinations_max, 8); + mm_fields_in(field_hi(c_field_arr, "nof_blocks_per_packet") downto field_lo(c_field_arr, "nof_blocks_per_packet")) <= to_uvec(destinations_info_rd.nof_blocks_per_packet, 8); -- get "RW" fields from mm_fields destinations_info_wr.eth_destination_mac_arr(0) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_0") downto field_lo(c_field_arr, "eth_destination_mac_0")); @@ -190,6 +249,22 @@ begin destinations_info_wr.eth_destination_mac_arr(13) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_13") downto field_lo(c_field_arr, "eth_destination_mac_13")); destinations_info_wr.eth_destination_mac_arr(14) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_14") downto field_lo(c_field_arr, "eth_destination_mac_14")); destinations_info_wr.eth_destination_mac_arr(15) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_15") downto field_lo(c_field_arr, "eth_destination_mac_15")); + destinations_info_wr.eth_destination_mac_arr(16) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_16") downto field_lo(c_field_arr, "eth_destination_mac_16")); + destinations_info_wr.eth_destination_mac_arr(17) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_17") downto field_lo(c_field_arr, "eth_destination_mac_17")); + destinations_info_wr.eth_destination_mac_arr(18) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_18") downto field_lo(c_field_arr, "eth_destination_mac_18")); + destinations_info_wr.eth_destination_mac_arr(19) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_19") downto field_lo(c_field_arr, "eth_destination_mac_19")); + destinations_info_wr.eth_destination_mac_arr(20) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_20") downto field_lo(c_field_arr, "eth_destination_mac_20")); + destinations_info_wr.eth_destination_mac_arr(21) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_21") downto field_lo(c_field_arr, "eth_destination_mac_21")); + destinations_info_wr.eth_destination_mac_arr(22) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_22") downto field_lo(c_field_arr, "eth_destination_mac_22")); + destinations_info_wr.eth_destination_mac_arr(23) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_23") downto field_lo(c_field_arr, "eth_destination_mac_23")); + destinations_info_wr.eth_destination_mac_arr(24) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_24") downto field_lo(c_field_arr, "eth_destination_mac_24")); + destinations_info_wr.eth_destination_mac_arr(25) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_25") downto field_lo(c_field_arr, "eth_destination_mac_25")); + destinations_info_wr.eth_destination_mac_arr(26) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_26") downto field_lo(c_field_arr, "eth_destination_mac_26")); + destinations_info_wr.eth_destination_mac_arr(27) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_27") downto field_lo(c_field_arr, "eth_destination_mac_27")); + destinations_info_wr.eth_destination_mac_arr(28) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_28") downto field_lo(c_field_arr, "eth_destination_mac_28")); + destinations_info_wr.eth_destination_mac_arr(29) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_29") downto field_lo(c_field_arr, "eth_destination_mac_29")); + destinations_info_wr.eth_destination_mac_arr(30) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_30") downto field_lo(c_field_arr, "eth_destination_mac_30")); + destinations_info_wr.eth_destination_mac_arr(31) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_31") downto field_lo(c_field_arr, "eth_destination_mac_31")); destinations_info_wr.ip_destination_address_arr(0) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_0") downto field_lo(c_field_arr, "ip_destination_address_0")); destinations_info_wr.ip_destination_address_arr(1) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_1") downto field_lo(c_field_arr, "ip_destination_address_1")); @@ -207,6 +282,22 @@ begin destinations_info_wr.ip_destination_address_arr(13) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_13") downto field_lo(c_field_arr, "ip_destination_address_13")); destinations_info_wr.ip_destination_address_arr(14) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_14") downto field_lo(c_field_arr, "ip_destination_address_14")); destinations_info_wr.ip_destination_address_arr(15) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_15") downto field_lo(c_field_arr, "ip_destination_address_15")); + destinations_info_wr.ip_destination_address_arr(16) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_16") downto field_lo(c_field_arr, "ip_destination_address_16")); + destinations_info_wr.ip_destination_address_arr(17) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_17") downto field_lo(c_field_arr, "ip_destination_address_17")); + destinations_info_wr.ip_destination_address_arr(18) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_18") downto field_lo(c_field_arr, "ip_destination_address_18")); + destinations_info_wr.ip_destination_address_arr(19) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_19") downto field_lo(c_field_arr, "ip_destination_address_19")); + destinations_info_wr.ip_destination_address_arr(20) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_20") downto field_lo(c_field_arr, "ip_destination_address_20")); + destinations_info_wr.ip_destination_address_arr(21) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_21") downto field_lo(c_field_arr, "ip_destination_address_21")); + destinations_info_wr.ip_destination_address_arr(22) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_22") downto field_lo(c_field_arr, "ip_destination_address_22")); + destinations_info_wr.ip_destination_address_arr(23) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_23") downto field_lo(c_field_arr, "ip_destination_address_23")); + destinations_info_wr.ip_destination_address_arr(24) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_24") downto field_lo(c_field_arr, "ip_destination_address_24")); + destinations_info_wr.ip_destination_address_arr(25) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_25") downto field_lo(c_field_arr, "ip_destination_address_25")); + destinations_info_wr.ip_destination_address_arr(26) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_26") downto field_lo(c_field_arr, "ip_destination_address_26")); + destinations_info_wr.ip_destination_address_arr(27) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_27") downto field_lo(c_field_arr, "ip_destination_address_27")); + destinations_info_wr.ip_destination_address_arr(28) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_28") downto field_lo(c_field_arr, "ip_destination_address_28")); + destinations_info_wr.ip_destination_address_arr(29) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_29") downto field_lo(c_field_arr, "ip_destination_address_29")); + destinations_info_wr.ip_destination_address_arr(30) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_30") downto field_lo(c_field_arr, "ip_destination_address_30")); + destinations_info_wr.ip_destination_address_arr(31) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_31") downto field_lo(c_field_arr, "ip_destination_address_31")); destinations_info_wr.udp_destination_port_arr(0) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_0") downto field_lo(c_field_arr, "udp_destination_port_0")); destinations_info_wr.udp_destination_port_arr(1) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_1") downto field_lo(c_field_arr, "udp_destination_port_1")); @@ -224,17 +315,33 @@ begin destinations_info_wr.udp_destination_port_arr(13) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_13") downto field_lo(c_field_arr, "udp_destination_port_13")); destinations_info_wr.udp_destination_port_arr(14) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_14") downto field_lo(c_field_arr, "udp_destination_port_14")); destinations_info_wr.udp_destination_port_arr(15) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_15") downto field_lo(c_field_arr, "udp_destination_port_15")); + destinations_info_wr.udp_destination_port_arr(16) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_16") downto field_lo(c_field_arr, "udp_destination_port_16")); + destinations_info_wr.udp_destination_port_arr(17) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_17") downto field_lo(c_field_arr, "udp_destination_port_17")); + destinations_info_wr.udp_destination_port_arr(18) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_18") downto field_lo(c_field_arr, "udp_destination_port_18")); + destinations_info_wr.udp_destination_port_arr(19) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_19") downto field_lo(c_field_arr, "udp_destination_port_19")); + destinations_info_wr.udp_destination_port_arr(20) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_20") downto field_lo(c_field_arr, "udp_destination_port_20")); + destinations_info_wr.udp_destination_port_arr(21) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_21") downto field_lo(c_field_arr, "udp_destination_port_21")); + destinations_info_wr.udp_destination_port_arr(22) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_22") downto field_lo(c_field_arr, "udp_destination_port_22")); + destinations_info_wr.udp_destination_port_arr(23) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_23") downto field_lo(c_field_arr, "udp_destination_port_23")); + destinations_info_wr.udp_destination_port_arr(24) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_24") downto field_lo(c_field_arr, "udp_destination_port_24")); + destinations_info_wr.udp_destination_port_arr(25) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_25") downto field_lo(c_field_arr, "udp_destination_port_25")); + destinations_info_wr.udp_destination_port_arr(26) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_26") downto field_lo(c_field_arr, "udp_destination_port_26")); + destinations_info_wr.udp_destination_port_arr(27) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_27") downto field_lo(c_field_arr, "udp_destination_port_27")); + destinations_info_wr.udp_destination_port_arr(28) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_28") downto field_lo(c_field_arr, "udp_destination_port_28")); + destinations_info_wr.udp_destination_port_arr(29) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_29") downto field_lo(c_field_arr, "udp_destination_port_29")); + destinations_info_wr.udp_destination_port_arr(30) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_30") downto field_lo(c_field_arr, "udp_destination_port_30")); + destinations_info_wr.udp_destination_port_arr(31) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_31") downto field_lo(c_field_arr, "udp_destination_port_31")); destinations_info_wr.nof_destinations <= to_uint(mm_fields_out(field_hi(c_field_arr, "nof_destinations") downto field_lo(c_field_arr, "nof_destinations"))); -- Register the read only actual values, to ease timing closure p_dp_clk : process(dp_clk) - constant c_nof_blocks_per_packet_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_bdo_nof_blocks_per_packet_look_up_table; + constant c_nof_blocks_per_packet_arr : t_natural_arr(1 to g_nof_destinations_max) := + func_sdp_bdo_reorder_nof_blocks_look_up_table(g_nof_destinations_max); begin if rising_edge(dp_clk) then - nof_destinations_act <= func_sdp_bdo_parse_nof_destinations(destinations_info_wr.nof_destinations); - nof_blocks_per_packet_act <= c_nof_blocks_per_packet_arr(nof_destinations_act); + nof_destinations_act <= func_sdp_bdo_parse_nof_destinations(destinations_info_wr.nof_destinations, g_nof_destinations_max); + nof_blocks_per_packet <= c_nof_blocks_per_packet_arr(nof_destinations_act); end if; end process; end str; diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_multiple_destinations.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_multiple_destinations.vhd index 33e2fc12e0ec47c425ba4980fb1c91ce752ca95c..ab82c282e39d20b888d25954b11cc0316355a005 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_multiple_destinations.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_multiple_destinations.vhd @@ -22,15 +22,32 @@ -- Purpose: -- Construct beamformer data output (BDO) payloads for multiple destinations. -- Description: --- * Get N_destinations from sdp_bdo_destinations_reg. --- * Merge, reorder and unmerge beamlet data for N_destinations > 1 from: --- (int8) [t] [N_blocks_per_packet][S_sub_bf / N_destinations] [N_pol_bf][N_complex] +-- * The nof_destinations_max determines how to MM control the beamlet packet +-- destination(s) MAC/IP/UDP: +-- . nof_destinations_max = 1 then use sdp_bdo_one_destination.vhd and +-- MM program the one destination MAC/IP/UDP from dp_offload_tx_v3. +-- . nof_destinations_max > 1 then use sdp_bdo_multiple_destinations.vhd and +-- MM program the one or more destination MAC/IP/UDP via +-- sdp_bdo_destinations_reg. +-- * Get nof_destinations from sdp_bdo_destinations_reg. The nof_destinations +-- is MM programmable between 1 and nof_destinations_max. The +-- nof_destinations must be in range 1:g_nof_destinations_max, then +-- nof_destinations_act = nof_destinations, as defined in +-- sdp_bdo_destinations_reg. +-- * The nof_blocks_per_packet is not MM programmable, but based on DN = +-- nof_destinations to ensure that the packet fits in a jumbo frame or +-- equal to c_sdp_bdo_reorder_nof_blocks_max to make maximum use of the +-- available reorder buffer size. +-- * Merge, reorder and unmerge beamlet data for nof_destinations > 1 from: +-- (int8) [t] [nof_blocks_per_packet][S_sub_bf / nof_destinations] [N_pol_bf][N_complex] -- to: --- (int8) [t] [S_sub_bf / N_destinations][N_blocks_per_packet] [N_pol_bf][N_complex] +-- (int8) [t] [S_sub_bf / nof_destinations][nof_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 --- . where N_destinations packets together transport the S_sub_bf beamlets. +-- . where nof_destinations packets together transport the S_sub_bf beamlets. +-- * Only support transposed beamlet data output, because each destination +-- must receive all blocks (= time samples) per beamlet. -- References: -- [1] https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Multiple+beamlet+output+destinations -- @@ -48,8 +65,8 @@ library IEEE, common_lib, dp_lib, reorder_lib; entity sdp_bdo_multiple_destinations is generic ( - g_beamset_id : natural := 0; - g_use_transpose : boolean := false + g_nof_destinations_max : natural := 1; + g_beamset_id : natural := 0 ); port ( mm_clk : in std_logic; @@ -58,66 +75,65 @@ entity sdp_bdo_multiple_destinations is dp_clk : in std_logic; dp_rst : in std_logic; + -- MM register reg_destinations_copi : in t_mem_copi; reg_destinations_cipo : out t_mem_cipo; destinations_info : out t_sdp_bdo_destinations_info; + -- Streaming data snk_in : in t_dp_sosi; - src_out : out t_dp_sosi + src_out : out t_dp_sosi; + + -- Streaming data output info dependent on DN = nof_destinations + nof_blocks_per_packet : out natural; + nof_beamlets_per_block_first_destinations : out natural; + nof_beamlets_per_block_last_destination : out natural ); end sdp_bdo_multiple_destinations; architecture str of sdp_bdo_multiple_destinations is - constant c_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; - - -- Reorder c_nof_ch = c_nof_ch_sel = c_nof_ch_in - constant c_reorder_nof_blocks_max : natural := c_sdp_bdo_reorder_nof_blocks_max; -- = 16 - constant c_reorder_nof_blocks_w : natural := ceil_log2(c_reorder_nof_blocks_max + 1); - constant c_reorder_nof_ch_max : natural := c_reorder_nof_blocks_max * - c_sdp_nof_beamlets_per_block * - c_sdp_nof_words_per_beamlet; -- = 7808 - - -- Look up table constants as function of N_destinations - constant c_m : natural := c_sdp_bdo_nof_destinations_max; -- 16 - constant c_nof_blocks_per_packet_arr : t_natural_arr(1 to c_m) := func_sdp_bdo_nof_blocks_per_packet_look_up_table; - constant c_reorder_nof_blocks_arr : t_natural_arr(1 to c_m) := func_sdp_bdo_reorder_nof_blocks_look_up_table; - constant c_reorder_nof_ch_arr : t_natural_arr(1 to c_m) := func_sdp_bdo_reorder_nof_ch_look_up_table; - constant c_nof_beamlets_per_block_first_destination_arr : t_natural_arr(1 to c_m) := func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table; - constant c_nof_beamlets_per_block_last_destination_arr : t_natural_arr(1 to c_m) := func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table; - constant c_nof_ch_per_packet_first_destination_arr : t_natural_arr(1 to c_m) := func_sdp_sdo_nof_ch_per_packet_first_destination_look_up_table; - constant c_nof_ch_per_packet_last_destination_arr : t_natural_arr(1 to c_m) := func_sdp_sdo_nof_ch_per_packet_last_destination_look_up_table; - - constant c_beamlet_index_per_destination_mat : t_natural_matrix(1 to c_m, 0 to c_m - 1) := - func_sdp_sdo_beamlet_index_per_destination_look_up_matrix; - - constant c_nof_ch_per_packet_max : natural := largest(c_nof_ch_per_packet_first_destination_arr); + constant c_beamset_beamlet_index : natural := g_beamset_id * c_sdp_S_sub_bf; + + -- Look up table constants as function of nof_destinations in range(g_nof_destinations_max) + constant c_m : natural := g_nof_destinations_max; + constant c_reorder_nof_blocks_arr : t_natural_arr(1 to c_m) := + func_sdp_bdo_reorder_nof_blocks_look_up_table(c_m); + constant c_reorder_nof_ch_arr : t_natural_arr(1 to c_m) := + func_sdp_bdo_reorder_nof_ch_look_up_table(c_m); + constant c_nof_beamlets_per_block_first_destinations_arr : t_natural_arr(1 to c_m) := + func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(c_m); + constant c_nof_beamlets_per_block_last_destination_arr : t_natural_arr(1 to c_m) := + func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table(c_m); + constant c_nof_ch_per_packet_first_destinations_arr : t_natural_arr(1 to c_m) := + func_sdp_bdo_nof_ch_per_packet_first_destinations_look_up_table(c_m); + constant c_nof_ch_per_packet_last_destination_arr : t_natural_arr(1 to c_m) := + func_sdp_bdo_nof_ch_per_packet_last_destination_look_up_table(c_m); + + constant c_nof_ch_per_packet_max : natural := largest(c_nof_ch_per_packet_first_destinations_arr); constant c_nof_ch_per_packet_w : natural := ceil_log2(c_nof_ch_per_packet_max + 1); - signal i_destinations_info : t_sdp_bdo_destinations_info; + -- Reorder all c_sdp_nof_beamlets_per_block = c_sdp_S_sub_bf = 488 beamlets + -- in buffer, such that they appear with first all blocks (= time samples) + -- for beamlet index 0 and last all blocks for beamlet index 477. + constant c_reorder_nof_beamlets_per_block : natural := c_sdp_nof_beamlets_per_block; + + signal i_destinations_info : t_sdp_bdo_destinations_info; + signal s_DN : natural range 1 to g_nof_destinations_max; -- number of destinations -- Dynamic merge, reorder, unmerge packet sizes - -- . default use values for N_destinations = 1 - signal nof_blocks_per_packet : natural := c_nof_blocks_per_packet_arr(1); - signal reorder_nof_blocks : natural := c_reorder_nof_blocks_arr(1); - signal reorder_nof_blocks_slv : std_logic_vector(c_reorder_nof_blocks_w - 1 downto 0); - signal reorder_nof_ch : natural := c_reorder_nof_ch_arr(1); - signal nof_beamlets_per_block_first_destination : natural := c_nof_beamlets_per_block_first_destination_arr(1); - signal nof_beamlets_per_block_last_destination : natural := c_nof_beamlets_per_block_last_destination_arr(1); - signal nof_beamlets_per_block : natural; - signal nof_ch_per_packet_first_destination : natural := c_nof_ch_per_packet_first_destination_arr(1); - signal nof_ch_per_packet_last_destination : natural := c_nof_ch_per_packet_last_destination_arr(1); - signal nof_ch_per_packet : natural; - signal nof_ch_per_packet_slv : std_logic_vector(c_nof_ch_per_packet_w - 1 downto 0); - - -- . default use values for N_destinations = 1 and destination index = 0 - signal beamlet_index_per_destination_bset_0 : natural := c_beamlet_index_per_destination_mat(1, 0); - signal beamlet_index_per_destination : natural := c_beamlet_index + c_beamlet_index_per_destination_mat(1, 0); + signal reorder_nof_blocks : natural; + signal reorder_nof_blocks_slv : std_logic_vector(c_sdp_bdo_reorder_nof_blocks_w - 1 downto 0); + signal reorder_nof_ch : natural; + signal nof_ch_per_packet_first_destinations : natural; + signal nof_ch_per_packet_first_destinations_slv : std_logic_vector(c_nof_ch_per_packet_w - 1 downto 0); + -- The nof_ch_per_packet_last_destination is used only for view in Wave + -- window, because dp_packet_unmerge automatically will output that number + -- of remaining number of ch for the last block. + signal nof_ch_per_packet_last_destination : natural; signal select_copi : t_mem_copi := c_mem_copi_rst; signal select_cipo : t_mem_cipo := c_mem_cipo_rst; - signal r_identity : t_reorder_identity; - signal d_identity : t_reorder_identity; signal r_transpose : t_reorder_transpose; signal d_transpose : t_reorder_transpose; @@ -129,14 +145,18 @@ architecture str of sdp_bdo_multiple_destinations is signal unmerge_src_out : t_dp_sosi; signal unmerge_word : t_sdp_dual_pol_beamlet_in_word; begin - src_out <= unmerge_src_out; destinations_info <= i_destinations_info; + nof_blocks_per_packet <= reorder_nof_blocks; + src_out <= unmerge_src_out; ----------------------------------------------------------------------------- -- Multiple destinations info register ----------------------------------------------------------------------------- -- Use dynamic sizes for beamlet data output to multiple destination. u_sdp_bdo_destinations_reg : entity work.sdp_bdo_destinations_reg + generic map ( + g_nof_destinations_max => g_nof_destinations_max + ) port map ( -- Clocks and reset mm_clk => mm_clk, @@ -153,40 +173,36 @@ begin ); ----------------------------------------------------------------------------- - -- Multiple destinations info look up values + -- Register look up table values dependent on DN to ease timing closure ----------------------------------------------------------------------------- - -- Pipeline values from look up tables to ease timing closure - p_pipeline : process(dp_clk) + 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 v_DN := i_destinations_info.nof_destinations_act; - nof_blocks_per_packet <= i_destinations_info.nof_blocks_per_packet_act; - reorder_nof_blocks <= c_reorder_nof_blocks_arr(v_DN); - reorder_nof_ch <= c_reorder_nof_ch_arr(v_DN); - nof_beamlets_per_block_first_destination <= c_nof_beamlets_per_block_first_destination_arr(v_DN); - nof_beamlets_per_block_last_destination <= c_nof_beamlets_per_block_last_destination_arr(v_DN); - v_DI := 0; - beamlet_index_per_destination_bset_0 <= c_beamlet_index_per_destination_mat(v_DN, v_DI); - beamlet_index_per_destination <= c_beamlet_index + beamlet_index_per_destination_bset_0; + + -- Semi constant values that depend on DN = nof_destinations_act set via MM + s_DN <= v_DN; + reorder_nof_blocks <= c_reorder_nof_blocks_arr(s_DN); + reorder_nof_ch <= c_reorder_nof_ch_arr(s_DN); + nof_beamlets_per_block_first_destinations <= c_nof_beamlets_per_block_first_destinations_arr(s_DN); + nof_beamlets_per_block_last_destination <= c_nof_beamlets_per_block_last_destination_arr(s_DN); + nof_ch_per_packet_first_destinations <= c_nof_ch_per_packet_first_destinations_arr(s_DN); + nof_ch_per_packet_last_destination <= c_nof_ch_per_packet_last_destination_arr(s_DN); end if; end process; - nof_beamlets_per_block <= nof_beamlets_per_block_first_destination; - nof_ch_per_packet <= nof_ch_per_packet_first_destination; - ----------------------------------------------------------------------------- -- dp_packet_merge ----------------------------------------------------------------------------- -- Use slv in port map to avoid vcom-1436: Actual expression (function call -- "TO_UVEC") of formal "nof_pkt" is not globally static. - reorder_nof_blocks_slv <= to_uvec(reorder_nof_blocks, c_reorder_nof_blocks_w); + reorder_nof_blocks_slv <= to_uvec(reorder_nof_blocks, c_sdp_bdo_reorder_nof_blocks_w); u_dp_packet_merge : entity dp_lib.dp_packet_merge generic map( g_use_ready => false, -- no flow control - g_nof_pkt => c_reorder_nof_blocks_max, + g_nof_pkt => c_sdp_bdo_reorder_nof_blocks_max, g_bsn_increment => 1 ) port map( @@ -206,13 +222,15 @@ begin ----------------------------------------------------------------------------- -- reorder_col_select -- . See tb_reorder_col_select_all.vhd for how to control col_select_copi / - -- cipo with p_reorder_identity or p_reorder_transpose. + -- cipo with p_reorder_transpose. + -- . Reorder nof_ch_sel = c_nof_ch_in = reorder_nof_ch, because the reorder + -- outputs all input. ----------------------------------------------------------------------------- u_reorder_col_select : entity reorder_lib.reorder_col_select generic map ( g_dsp_data_w => c_sdp_W_dual_pol_beamlet / c_nof_complex, -- = 32b / 2 - g_nof_ch_in => c_reorder_nof_ch_max, - g_nof_ch_sel => c_reorder_nof_ch_max, + g_nof_ch_in => c_sdp_bdo_reorder_nof_ch_max, + g_nof_ch_sel => c_sdp_bdo_reorder_nof_ch_max, g_use_complex => false ) port map ( @@ -245,37 +263,19 @@ begin p_dp_clk : process(dp_clk) begin if rising_edge(dp_clk) then - r_identity <= d_identity; r_transpose <= d_transpose; end if; end process; - -- Pass on beamlet data in original order or in transposed order - select_copi <= r_transpose.select_copi when g_use_transpose else r_identity.select_copi; - - p_reorder_identity : process(dp_rst, select_cipo, reorder_nof_ch, r_identity) - variable v : t_reorder_identity; - begin - if select_cipo.waitrequest = '0' then - -- Read from reorder_col_select page - v := func_reorder_identity(reorder_nof_ch, r_identity); - else - -- No read, new reorder_col_select page not available yet - v := c_reorder_identity_rst; - end if; - -- Synchronous reset - if dp_rst = '1' then - v := c_reorder_identity_rst; - end if; - d_identity <= v; - end process; + -- Pass on beamlet data in transposed order + select_copi <= r_transpose.select_copi; - p_reorder_transpose : process(dp_rst, select_cipo, nof_blocks_per_packet, nof_beamlets_per_block, r_transpose) + p_reorder_transpose : process(dp_rst, select_cipo, reorder_nof_blocks, r_transpose) variable v : t_reorder_transpose; begin if select_cipo.waitrequest = '0' then -- Read from reorder_col_select page - v := func_reorder_transpose(nof_blocks_per_packet, nof_beamlets_per_block, r_transpose); + v := func_reorder_transpose(reorder_nof_blocks, c_reorder_nof_beamlets_per_block, r_transpose); else -- No read, new reorder_col_select page not available yet v := c_reorder_transpose_rst; @@ -288,22 +288,22 @@ begin end process; ----------------------------------------------------------------------------- - -- dp_packet_unmerge for N_destinations + -- dp_packet_unmerge for nof_destinations ----------------------------------------------------------------------------- - nof_ch_per_packet_slv <= to_uvec(nof_ch_per_packet, c_nof_ch_per_packet_w); + nof_ch_per_packet_first_destinations_slv <= to_uvec(nof_ch_per_packet_first_destinations, c_nof_ch_per_packet_w); u_dp_packet_unmerge : entity dp_lib.dp_packet_unmerge generic map ( g_use_ready => false, -- no flow control - g_nof_pkt => c_reorder_nof_blocks_max, + g_nof_pkt => g_nof_destinations_max, g_pkt_len => c_nof_ch_per_packet_max, - g_bsn_increment => 1 + g_bsn_increment => 0 ) port map ( rst => dp_rst, clk => dp_clk, - pkt_len => nof_ch_per_packet_slv, + pkt_len => nof_ch_per_packet_first_destinations_slv, pkt_len_out => open, -- Valid at src_out.sop snk_in => reorder_src_out, diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_one_destination.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_one_destination.vhd index 989cfe606500eec2bce111870a7e13067d3a9def..4403f42f09f5178ce27b364f7df6218e73bd9adc 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_one_destination.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_one_destination.vhd @@ -46,7 +46,7 @@ library IEEE, common_lib, dp_lib, reorder_lib; entity sdp_bdo_one_destination is generic ( - g_use_transpose : boolean := false + g_use_transpose : boolean ); port ( dp_clk : in std_logic; 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 098d853c91e7c3dac21ceae9d02aaecf8c7e9680..e33f2166ab48f8e3c6b0c3ba91232a8b110323fb 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_pkg.vhd @@ -34,121 +34,145 @@ use work.sdp_pkg.all; package sdp_bdo_pkg is -- Beamlet data output (BDO) for multiple destinations - constant c_sdp_bdo_nof_destinations_max : natural := 16; - constant c_sdp_bdo_reorder_nof_blocks_max : natural := largest(16, c_sdp_cep_nof_blocks_per_packet); - constant c_sdp_bdo_destinations_info_nof_hdr_fields : natural := c_sdp_bdo_nof_destinations_max * 3 + 4; -- = 52 fields + -- Define the maximum number of destination to size the address span of the + -- MM register in sdp_bdo_destinations_reg. The actual nof_destinations_max + -- <= c_sdp_bdo_mm_nof_destinations_max is defined as revision constant, so + -- that it can differ per design revision. + constant c_sdp_bdo_mm_nof_destinations_max : natural := 32; + + -- Define the maximum number of blocks (= time samples per beamlet) here as + -- a package constant, because it can be the same for all design revisions. + -- The actual reorder_nof_blocks_max depends slightly on + -- nof_destinations_max, because the number of blocks has to fit in a jumbo + -- frame. Therefore func_sdp_bdo_reorder_nof_blocks_look_up_table() + -- determines the actual reorder_nof_blocks. + -- The nof_blocks_per_packet = reorder_nof_blocks. The beamlet packets will + -- have the same nof_blocks_per_packet for each destination, because the + -- blocks represent beamlet time samples that have to be kept together per + -- destination. The beamlets are distributed to the different destinations + -- based on their beamlet index as defined by + -- func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(). + -- The minimum value is c_sdp_cep_nof_blocks_per_packet = 4 to fill a jumbo + -- frame when nof_destinations = 1. + -- The maximum value is a balance between having sufficiently large packets + -- nof_destinations > 1 and how many block RAM resources are available for + -- the reordering. Therefore c_sdp_bdo_reorder_nof_blocks_max = 16 is a + -- suitable compromise value. + constant c_sdp_bdo_reorder_nof_blocks_max : natural := 16; + constant c_sdp_bdo_reorder_nof_blocks_w : natural := ceil_log2(c_sdp_bdo_reorder_nof_blocks_max + 1); + constant c_sdp_bdo_reorder_nof_ch_max : natural := c_sdp_bdo_reorder_nof_blocks_max * + c_sdp_nof_beamlets_per_block * + c_sdp_nof_words_per_beamlet; -- = 7808 + + -- 32 * 3 + 4 = 100 fields + constant c_sdp_bdo_destinations_info_nof_hdr_fields : natural := c_sdp_bdo_mm_nof_destinations_max * 3 + 4; type t_sdp_bdo_destinations_info is record - eth_destination_mac_arr : t_slv_48_arr(c_sdp_bdo_nof_destinations_max - 1 downto 0); - ip_destination_address_arr : t_slv_32_arr(c_sdp_bdo_nof_destinations_max - 1 downto 0); - udp_destination_port_arr : t_slv_16_arr(c_sdp_bdo_nof_destinations_max - 1 downto 0); + eth_destination_mac_arr : t_slv_48_arr(c_sdp_bdo_mm_nof_destinations_max - 1 downto 0); + ip_destination_address_arr : t_slv_32_arr(c_sdp_bdo_mm_nof_destinations_max - 1 downto 0); + udp_destination_port_arr : t_slv_16_arr(c_sdp_bdo_mm_nof_destinations_max - 1 downto 0); nof_destinations : natural; nof_destinations_act : natural; nof_destinations_max : natural; - nof_blocks_per_packet_act : natural; + nof_blocks_per_packet : natural; end record; - constant t_sdp_bdo_destinations_info_rst : t_sdp_bdo_destinations_info := + constant c_sdp_bdo_destinations_info_rst : t_sdp_bdo_destinations_info := ( (others => (others => '0')), (others => (others => '0')), (others => (others => '0')), 1, 1, - c_sdp_bdo_nof_destinations_max, + 1, c_sdp_cep_nof_blocks_per_packet); -- Parse user input to determine actual nof_destinations - function func_sdp_bdo_parse_nof_destinations(nof_destinations : natural) return natural; + function func_sdp_bdo_parse_nof_destinations(nof_destinations, c_nof_destinations_max : natural) return natural; -- Use functions that return look up tables to precalculate the values as -- constant arrays -- . One ch (channel) = one 32b word = one dual polarization beamlet (Xre, Xim, Yre, Yim) - -- . Look up table arrays for: t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) - function func_sdp_bdo_nof_blocks_per_packet_look_up_table return t_natural_arr; - function func_sdp_bdo_reorder_nof_blocks_look_up_table return t_natural_arr; - function func_sdp_bdo_reorder_nof_ch_look_up_table return t_natural_arr; - function func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table return t_natural_arr; - function func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table return t_natural_arr; - function func_sdp_sdo_nof_ch_per_packet_first_destination_look_up_table return t_natural_arr; - function func_sdp_sdo_nof_ch_per_packet_last_destination_look_up_table return t_natural_arr; + -- . Look up table arrays for: t_natural_arr(1 to c_nof_destinations_max) + function func_sdp_bdo_reorder_nof_blocks_look_up_table(c_nof_destinations_max : natural) return t_natural_arr; + function func_sdp_bdo_reorder_nof_ch_look_up_table(c_nof_destinations_max : natural) return t_natural_arr; + function func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(c_nof_destinations_max : natural) return t_natural_arr; + function func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table(c_nof_destinations_max : natural) return t_natural_arr; + function func_sdp_bdo_nof_ch_per_packet_first_destinations_look_up_table(c_nof_destinations_max : natural) return t_natural_arr; + function func_sdp_bdo_nof_ch_per_packet_last_destination_look_up_table(c_nof_destinations_max : natural) return t_natural_arr; -- Look up table matrix for: - -- t_natural_matrix(1 to c_sdp_bdo_nof_destinations_max, -- N_destinations - -- 0 to c_sdp_bdo_nof_destinations_max - 1) -- destination index - function func_sdp_sdo_beamlet_index_per_destination_look_up_matrix return t_natural_matrix; + -- t_natural_matrix(1 to c_nof_destinations_max, -- N_destinations + -- 0 to c_nof_destinations_max - 1) -- destination index + function func_sdp_bdo_beamlet_index_per_destination_look_up_matrix(c_nof_destinations_max : natural) return t_natural_matrix; end package sdp_bdo_pkg; package body sdp_bdo_pkg is - function func_sdp_bdo_parse_nof_destinations(nof_destinations : natural) return natural 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; - elsif nof_destinations > c_sdp_bdo_nof_destinations_max then - return c_sdp_bdo_nof_destinations_max; + v_DN := 1; -- force to at least 1 destination + elsif nof_destinations > c_nof_destinations_max then + 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_nof_blocks_per_packet_look_up_table return t_natural_arr is - variable v_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); + function func_sdp_bdo_reorder_nof_blocks_look_up_table(c_nof_destinations_max : natural) return t_natural_arr is + variable v_arr : t_natural_arr(1 to c_nof_destinations_max); begin - -- Determine nof_blocks_per_packet as function of number of destinations - -- DN. - -- . With 1 destination c_sdp_cep_nof_blocks_per_packet = 4 can fit in a - -- jumbo frame. + -- Determine reorder_nof_blocks = nof_blocks_per_packet as function of + -- c_sdp_bdo_reorder_nof_blocks_max and the number of destinations DN. + -- . With DN = 1 destination c_sdp_cep_nof_blocks_per_packet = 4 can fit + -- in a jumbo frame. -- . With DN destinations DN * c_sdp_cep_nof_blocks_per_packet can fit in - -- a jumbo frame, because the number of beamlets per destination reduces - -- by DN. + -- a jumbo frame, because the number of beamlet indices per destination + -- reduces by DN. -- DN = 1:16 --> 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64 - -- . In total there are maximum c_sdp_bdo_reorder_nof_blocks_max = 16 - -- blocks to distribute over DN destinations. - -- . Taking smallest yields the actual maximum number of blocks per packet - -- per destination, as function of number of destinations DN: + -- . In total there can be maximum c_sdp_bdo_reorder_nof_blocks_max = 16 + -- blocks per packet, due to the size of the reorder buffer. Taking + -- smallest yields the actual number of blocks per packet, as function + -- of number of destinations DN: -- DN = 1:16 --> 4, 8, 12, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 - for DN in 1 to c_sdp_bdo_nof_destinations_max loop - v_arr(DN) := smallest(c_sdp_bdo_reorder_nof_blocks_max, DN * c_sdp_cep_nof_blocks_per_packet); - end loop; - return v_arr; - end func_sdp_bdo_nof_blocks_per_packet_look_up_table; - - function func_sdp_bdo_reorder_nof_blocks_look_up_table return t_natural_arr is - constant c_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_bdo_nof_blocks_per_packet_look_up_table; - variable v_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); - begin - -- Determine reorder_nof_blocks as function of number of destinations DN. - -- . The number of blocks per destination is given by c_arr, so the number - -- of blocks that need to be merged for the reorder is DN * c_arr(DN): - -- DN = 1:16 --> 4, 16, 15, 16, 15, 12, 14, 16, 9, 10, 11, 12, 13, 14, 15, 16 - for DN in 1 to c_sdp_bdo_nof_destinations_max loop - v_arr(DN) := DN * c_arr(DN); + for DN in 1 to c_nof_destinations_max loop + v_arr(DN) := smallest(DN * c_sdp_cep_nof_blocks_per_packet, c_sdp_bdo_reorder_nof_blocks_max); end loop; return v_arr; end func_sdp_bdo_reorder_nof_blocks_look_up_table; - function func_sdp_bdo_reorder_nof_ch_look_up_table return t_natural_arr is - constant c_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_bdo_reorder_nof_blocks_look_up_table; - variable v_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); + function func_sdp_bdo_reorder_nof_ch_look_up_table(c_nof_destinations_max : natural) return t_natural_arr is + constant c_arr : t_natural_arr(1 to c_nof_destinations_max) := + func_sdp_bdo_reorder_nof_blocks_look_up_table(c_nof_destinations_max); + variable v_arr : t_natural_arr(1 to c_nof_destinations_max); begin -- Determine reorder nof_ch as function of number of destinations DN. - -- . The number of blocks to reorder is given by c_arr, so the number - -- of ch (channels = words) that need to be reordered is c_sdp_S_sub_bf - -- * c_arr(DN): - -- DN = 1:16 --> 1952, 7808, 7320, 7808, 7320, 5856, 6832, 7808 - -- 4392, 4880, 5368, 5856, 6344, 6832, 7320, 7808 - for DN in 1 to c_sdp_bdo_nof_destinations_max loop + -- . The number of blocks to reorder is given by c_arr, so the number of + -- ch (channels = words = dual pol, complex beamlets) that need to be + -- reordered is c_sdp_S_sub_bf * c_arr(DN): + -- DN = 1:16 --> 1952, 3904, 5856, 7808, 7808, 7808, 7808, 7808 + -- 7808, 7808, 7808, 7808, 7808, 7808, 7808, 7808 + for DN in 1 to c_nof_destinations_max loop v_arr(DN) := c_sdp_S_sub_bf * c_arr(DN); end loop; return v_arr; end func_sdp_bdo_reorder_nof_ch_look_up_table; - function func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table return t_natural_arr is - variable v_first_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); + function func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table(c_nof_destinations_max : natural) return t_natural_arr is + variable v_first_arr : t_natural_arr(1 to c_nof_destinations_max); begin -- Determine nof_beamlets_per_block for the first 1:DN-1 destinations, as -- function of number of destinations DN. @@ -156,67 +180,87 @@ package body sdp_bdo_pkg is -- distribute over DN destinations, so ceil(488 / DN) yields the number of -- blocks for the first 1:DN-1 destinations: -- DN = 1:16 --> v_first_arr = 488, 244, 163, 122, 98, 82, 70, 61, 55, 49, 45, 41, 38, 35, 33, 31 - for DN in 1 to c_sdp_bdo_nof_destinations_max loop + for DN in 1 to c_nof_destinations_max loop v_first_arr(DN) := ceil_div(c_sdp_S_sub_bf, DN); end loop; return v_first_arr; - end func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table; + end func_sdp_bdo_nof_beamlets_per_block_first_destinations_look_up_table; - function func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table return t_natural_arr is - variable v_first_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table; - variable v_last_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); + function func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table(c_nof_destinations_max : natural) return t_natural_arr 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 nof_beamlets_per_block for the last destination with index DN, - -- as function of number of destinations DN. + -- Determine remaining nof_beamlets_per_block for the last destination + -- with index DN, as function of number of destinations DN. -- . In total there are c_sdp_S_sub_bf = 488 dual polarization beamlets to -- distribute over DN destinations, so 488 - (DN-1) * ceil(488 / DN) -- beamlets remain for the last destination: -- 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 may be < v_first_arr - 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. - -- - for DN in 1 to c_sdp_bdo_nof_destinations_max loop - v_last_arr(DN) := c_sdp_S_sub_bf - (DN - 1) * v_first_arr(DN); + -- . 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 := 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_sdo_nof_beamlets_per_block_last_destination_look_up_table; + end func_sdp_bdo_nof_beamlets_per_block_last_destination_look_up_table; - function func_sdp_sdo_nof_ch_per_packet_first_destination_look_up_table return t_natural_arr is - constant c_nof_blocks_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_bdo_nof_blocks_per_packet_look_up_table; - constant c_nof_beamlets_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table; - variable v_len_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); + function func_sdp_bdo_nof_ch_per_packet_first_destinations_look_up_table(c_nof_destinations_max : natural) return t_natural_arr is + constant c_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_nof_beamlets_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_len_arr : t_natural_arr(1 to c_nof_destinations_max); begin -- 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 - for DN in 1 to c_sdp_bdo_nof_destinations_max loop + -- + -- 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; return v_len_arr; - end func_sdp_sdo_nof_ch_per_packet_first_destination_look_up_table; + end func_sdp_bdo_nof_ch_per_packet_first_destinations_look_up_table; - function func_sdp_sdo_nof_ch_per_packet_last_destination_look_up_table return t_natural_arr is - constant c_nof_blocks_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_bdo_nof_blocks_per_packet_look_up_table; - constant c_nof_beamlets_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_sdo_nof_beamlets_per_block_last_destination_look_up_table; - variable v_len_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max); + function func_sdp_bdo_nof_ch_per_packet_last_destination_look_up_table(c_nof_destinations_max : natural) return t_natural_arr is + constant c_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_nof_beamlets_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_len_arr : t_natural_arr(1 to c_nof_destinations_max); begin -- Determine nof_ch per packet for the first 1:DN-1 destinations, as -- function of number of destinations DN. @@ -225,22 +269,22 @@ package body sdp_bdo_pkg is -- . c_nof_beamlets_arr = 488, 244, 162, 122, 96, 78, 68, 61, 48, 47, 38, 37, 32, 33, 26, 23 -- . v_len_arr = 1952,1952,1944,1952,1536,1248,1088, 976, 768, 752, 608, 592, 512, 528, 416, 368 -- . nof octets = 7808,7808,7776,7808,6144,4992,4352,3904,3072,3008,2432,2368,2048,2112,1664,1472 - for DN in 1 to c_sdp_bdo_nof_destinations_max loop + 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; return v_len_arr; - end func_sdp_sdo_nof_ch_per_packet_last_destination_look_up_table; + end func_sdp_bdo_nof_ch_per_packet_last_destination_look_up_table; - function func_sdp_sdo_beamlet_index_per_destination_look_up_matrix return t_natural_matrix is - constant c_len_arr : t_natural_arr(1 to c_sdp_bdo_nof_destinations_max) := - func_sdp_sdo_nof_beamlets_per_block_first_destination_look_up_table; - variable v_index_mat : t_natural_matrix(1 to c_sdp_bdo_nof_destinations_max, - 0 to c_sdp_bdo_nof_destinations_max - 1); + function func_sdp_bdo_beamlet_index_per_destination_look_up_matrix(c_nof_destinations_max : natural) return t_natural_matrix is + constant c_len_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_index_mat : t_natural_matrix(1 to c_nof_destinations_max, + 0 to c_nof_destinations_max - 1); variable v_beamlet_index : natural; variable v_step : natural; begin -- Determine beamlet index of first beamlet in packet per destination with - -- index DN, as function of number of destinations DN. + -- index DI, as function of number of destinations DN. -- . Beamlet index for first destination starts at 0 -- . Beamlet index for the other destinations increments with number of -- beamlets per previous destination given by c_len_arr. @@ -280,10 +324,10 @@ package body sdp_bdo_pkg is -- v_beamlet_index += v_step -- print(lineStr) -- - for DN in 1 to c_sdp_bdo_nof_destinations_max loop + for DN in 1 to c_nof_destinations_max loop v_beamlet_index := 0; v_step := c_len_arr(DN); - for DI in 0 to c_sdp_bdo_nof_destinations_max - 1 loop + for DI in 0 to c_nof_destinations_max - 1 loop if v_beamlet_index < c_sdp_S_sub_bf then v_index_mat(DN, DI) := v_beamlet_index; end if; @@ -291,5 +335,5 @@ package body sdp_bdo_pkg is end loop; end loop; return v_index_mat; - end func_sdp_sdo_beamlet_index_per_destination_look_up_matrix; + end func_sdp_bdo_beamlet_index_per_destination_look_up_matrix; end sdp_bdo_pkg; 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 984d6a34d01effd1039a5b2250a05f9ca35c7bb1..f730e3020f1946aa6448e27340443a8283a005d9 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 @@ -46,10 +46,13 @@ use work.sdp_bdo_pkg.all; entity sdp_beamformer_output is generic ( - g_beamset_id : natural := 0; - g_use_transpose : boolean := false; - g_use_multiple_destinations : boolean := false; - g_sim_force_bsn_error : boolean := true + 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 ); port ( dp_clk : in std_logic; @@ -85,22 +88,35 @@ 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 - - -- field_sel = '0' for DP (dynamic), '1' for MM (fixed or programmable via MM of dp_offload_tx_v3) + 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_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) := - sel_a_b(g_use_multiple_destinations, func_sdp_cep_hdr_field_sel_dst('0'), - func_sdp_cep_hdr_field_sel_dst('1')); + sel_a_b(g_nof_destinations_max = 1, func_sdp_cep_hdr_field_sel_dst('1'), + func_sdp_cep_hdr_field_sel_dst('0')); -- BDO packet size control -- . One 32b word contains 1 dual pol beamlet of 4 octets (Xre, Xim, Yre, Yim). @@ -108,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); @@ -119,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_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; - signal dp_pipeline_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; @@ -130,15 +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 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); - -- Multiple destinations - signal destinations_info : t_sdp_bdo_destinations_info; - signal eth_dst_mac : std_logic_vector(c_network_eth_mac_addr_w - 1 downto 0); - signal ip_dst_addr : std_logic_vector(c_network_ip_addr_w - 1 downto 0); - signal udp_dst_port : std_logic_vector(c_network_udp_port_w - 1 downto 0); + signal mdi_nof_blocks_per_packet : natural; + 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_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'); @@ -169,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, @@ -193,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; @@ -229,7 +254,7 @@ begin -- [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)); - gen_one_destination : if g_use_multiple_destinations = false generate + gen_one_destination : if g_nof_destinations_max = 1 generate ----------------------------------------------------------------------------- -- Merge and reorder beamlet data for one destination from: -- (int8) [t] [N_blocks_per_packet][S_sub_bf] [N_pol_bf][N_complex] @@ -252,7 +277,7 @@ begin ); end generate; - gen_multiple_destinations : if g_use_multiple_destinations = true generate + gen_multiple_destinations : if g_nof_destinations_max > 1 generate ----------------------------------------------------------------------------- -- Merge, reorder and unmerge beamlet data for N_destinations >= 1 from: -- (int8) [t] [N_blocks_per_packet][S_sub_bf / N_destinations] [N_pol_bf][N_complex] @@ -265,8 +290,8 @@ begin ----------------------------------------------------------------------------- u_sdp_bdo_multiple_destinations : entity work.sdp_bdo_multiple_destinations generic map ( - g_beamset_id => g_beamset_id, - g_use_transpose => g_use_transpose + g_nof_destinations_max => g_nof_destinations_max, + g_beamset_id => g_beamset_id ) port map ( mm_clk => mm_clk, @@ -278,11 +303,55 @@ begin reg_destinations_copi => reg_destinations_copi, reg_destinations_cipo => reg_destinations_cipo, - destinations_info => destinations_info, + destinations_info => multi_destinations_info, snk_in => dp_repack_beamlet_src_out, - src_out => dp_packet_reorder_src_out + src_out => dp_packet_reorder_src_out, + + -- 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 ); + + ----------------------------------------------------------------------------- + -- Look up table values and and output info dependent on DN and DI + ----------------------------------------------------------------------------- + -- Register output info dependent on DN and DI to ease timing closure + p_reg : process(dp_clk) + variable v_DI : natural; -- destination index + begin + if rising_edge(dp_clk) then + -- Register number of destinations (DN) + s_DN <= multi_destinations_info.nof_destinations_act; + + -- Capture destination index (DI) from channel field, valid at sop + if dp_fifo_data_src_out.sop = '1' then + v_DI := to_uint(dp_fifo_data_src_out.channel); + s_DI <= v_DI; -- for view in Wave window + + -- 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 if; + end process; end generate; -- Debug signals for view in Wave window @@ -314,17 +383,19 @@ begin dp_repack_longword <= unpack_data(dp_repack_longword_src_out.data(c_longword_w - 1 downto 0)); ----------------------------------------------------------------------------- - -- FIFO + -- FIFO: to be able to insert header in u_dp_offload_tx_v3 ----------------------------------------------------------------------------- -- Pass on dp_repack_longword_src_out.err field not here, but via separate - -- u_common_fifo_sc_err. - u_dp_fifo_fill_eop_sc : entity dp_lib.dp_fifo_fill_eop_sc + -- u_common_fifo_err. + u_dp_fifo_data : entity dp_lib.dp_fifo_fill_eop_sc generic map ( g_data_w => c_longword_w, 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, @@ -334,16 +405,27 @@ begin clk => dp_clk, rst => dp_rst, snk_in => dp_repack_longword_src_out, - src_out => dp_fifo_fill_eop_src_out, - src_in => dp_fifo_fill_eop_src_in + src_out => dp_fifo_data_src_out, + src_in => dp_fifo_data_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. - u_common_fifo_sc_err : entity common_lib.common_fifo_sc + -- FIFO: to store and align payload error bit from eop to sop + -- . The payload error bit is set when dp_packet_merge detects an BSN + -- increment error. The dual page mechanism in reorder_col_select makes + -- that the sosi.err bit will be valid during the entire output packet, + -- so that it can be passed on at the sop via the application header. + -- For g_nof_destinations > 1 each destination packet will have its + -- payload error bit set as well, because dp_packet_unmerge applies the + -- input sosi.err at the sop to all unmerged output packets. + -- . 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_data 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. + -- . No need to account for g_nof_destinations_max > 1 in FIFO g_nof_words, + -- because the BDO packets are multiplexed round-robin with fair chance + -- per beamset by the dp_mux in sdp_station.vhd + u_common_fifo_err : entity common_lib.common_fifo_sc generic map ( g_dat_w => 1, g_nof_words => c_sdp_N_beamsets + 2 @@ -354,11 +436,11 @@ begin wr_dat => dp_repack_longword_src_out.err(0 downto 0), wr_req => dp_repack_longword_src_out.eop, rd_dat => payload_err, - rd_req => dp_fifo_fill_eop_src_out.sop + rd_req => dp_fifo_data_src_out.sop ); - -- Pipeline FIFO output to align payload_err at dp_pipeline_src_out.sop - u_pipeline : entity dp_lib.dp_pipeline + -- Pipeline dp_fifo_data_src_out to align payload_err at dp_pipeline_data_src_out.sop + u_pipeline_data : entity dp_lib.dp_pipeline generic map ( g_pipeline => 1 ) @@ -366,11 +448,11 @@ begin rst => dp_rst, clk => dp_clk, -- ST sink - snk_out => dp_fifo_fill_eop_src_in, - snk_in => dp_fifo_fill_eop_src_out, + snk_out => dp_fifo_data_src_in, + snk_in => dp_fifo_data_src_out, -- ST source - src_in => dp_pipeline_src_in, - src_out => dp_pipeline_src_out + src_in => dp_pipeline_data_src_in, + src_out => dp_pipeline_data_src_out ); ----------------------------------------------------------------------------- @@ -431,18 +513,20 @@ begin -- -- DP dp_bsn - p_assemble_offload_info : process(destinations_info) + 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_use_multiple_destinations = false then + 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 <= destinations_info.nof_blocks_per_packet_act; - nof_beamlets_per_block <= c_sdp_S_sub_bf; -- = 488 dual pol beamlets; - - -- TODO check channel field to set destination addresses in dp_offload_tx_hdr_fields + 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; @@ -460,9 +544,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" )) <= 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" )) <= 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")) <= 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; @@ -475,12 +559,12 @@ 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; - dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "dp_bsn" ) downto field_lo(c_sdp_cep_hdr_field_arr, "dp_bsn" )) <= dp_pipeline_src_out.bsn(63 downto 0); + dp_offload_tx_hdr_fields(field_hi(c_sdp_cep_hdr_field_arr, "dp_bsn" ) downto field_lo(c_sdp_cep_hdr_field_arr, "dp_bsn" )) <= dp_pipeline_data_src_out.bsn(63 downto 0); -- For viewing the header fields in wave window dp_offload_tx_header <= func_sdp_map_cep_header(dp_offload_tx_hdr_fields); @@ -507,8 +591,8 @@ begin reg_hdr_dat_mosi => reg_hdr_dat_mosi, reg_hdr_dat_miso => reg_hdr_dat_miso, - snk_in_arr(0) => dp_pipeline_src_out, - snk_out_arr(0) => dp_pipeline_src_in, + snk_in_arr(0) => dp_pipeline_data_src_out, + snk_out_arr(0) => dp_pipeline_data_src_in, src_out_arr(0) => dp_offload_tx_src_out, src_in_arr(0) => dp_offload_tx_src_in, diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd index a3a41fdb21d4451d8bdfd153c7623fb8f52bd654..6f3894ec9faecd12895f013d5075b4a5860456b2 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd @@ -140,6 +140,7 @@ package sdp_pkg is constant c_sdp_nof_words_per_beamlet : natural := 1; -- 1 dual pol, complex, 8bit beamlet (Xre, Xim, Yre, Yim) per 32b word constant c_sdp_nof_beamlets_per_longword : natural := 2; -- 2 dual pol, complex, 8bit beamlets fit in 1 64bit longword constant c_sdp_nof_beamlets_per_block : natural := c_sdp_S_sub_bf; -- number of dual pol beamlets per block + constant c_sdp_nof_beamlets_per_block_w : natural := ceil_log2(c_sdp_nof_beamlets_per_block + 1); -- . unit weights constant c_sdp_unit_sub_weight : natural := 2**c_sdp_W_sub_weight_fraction; -- 2**13, so range +-4.0 for 16 bit signed weight diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd index 77a525d30f18ad9a4bde74ff5f7873f98187d106..a40ee3c528fcc79c9be8e97a8172b2703f15834c 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_station.vhd @@ -54,22 +54,23 @@ use ring_lib.ring_pkg.all; entity sdp_station is generic ( - g_sim : boolean := false; -- Overridden by TB - g_sim_sdp : t_sdp_sim := c_sdp_sim; -- Used when g_sim = TRUE, otherwise use HW defaults - g_sim_sync_timeout : natural := 1024; - g_wpfb : t_wpfb := c_sdp_wpfb_subbands; - g_wpfb_complex : t_wpfb := c_sdp_wpfb_complex_subbands; - g_bsn_nof_clk_per_sync : natural := c_sdp_N_clk_per_sync; -- Default 200M, overide for short simulation - g_scope_selected_subband : natural := 0; - g_no_jesd : boolean := false; - g_use_fsub : boolean := true; - g_use_oversample : boolean := false; - g_use_xsub : boolean := true; - g_use_bf : boolean := true; - g_use_bdo_transpose : boolean := false; - g_use_bdo_multiple_destinations : boolean := false; - g_use_ring : boolean := true; - g_P_sq : natural := 1 + g_sim : boolean := false; -- Overridden by TB + g_sim_sdp : t_sdp_sim := c_sdp_sim; -- Used when g_sim = TRUE, otherwise use HW defaults + g_sim_sync_timeout : natural := 1024; + g_wpfb : t_wpfb := c_sdp_wpfb_subbands; + g_wpfb_complex : t_wpfb := c_sdp_wpfb_complex_subbands; + g_bsn_nof_clk_per_sync : natural := c_sdp_N_clk_per_sync; -- Default 200M, overide for short simulation + g_scope_selected_subband : natural := 0; + -- Use no default, to force instance to set it + g_no_jesd : boolean; + g_use_fsub : boolean; + g_use_oversample : boolean; + g_use_xsub : boolean; + g_use_bf : boolean; + g_use_bdo_transpose : boolean; + g_nof_bdo_destinations_max : natural; + g_use_ring : boolean; + g_P_sq : natural ); port ( -- System @@ -909,14 +910,14 @@ begin gen_bf : for beamset_id in 0 to c_sdp_N_beamsets - 1 generate u_bf : entity work.node_sdp_beamformer generic map( - g_sim => g_sim, - g_sim_sdp => g_sim_sdp, - g_beamset_id => beamset_id, - g_use_bdo_transpose => g_use_bdo_transpose, - g_use_bdo_multiple_destinations => g_use_bdo_multiple_destinations, - g_scope_selected_beamlet => g_scope_selected_subband, - g_subband_raw_dat_w => c_subband_raw_dat_w, - g_subband_raw_fraction_w => c_subband_raw_fraction_w + g_sim => g_sim, + g_sim_sdp => g_sim_sdp, + g_beamset_id => beamset_id, + g_use_bdo_transpose => g_use_bdo_transpose, + g_nof_bdo_destinations_max => g_nof_bdo_destinations_max, + g_scope_selected_beamlet => g_scope_selected_subband, + g_subband_raw_dat_w => c_subband_raw_dat_w, + g_subband_raw_fraction_w => c_subband_raw_fraction_w ) port map( dp_clk => dp_clk, 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 69a52466c91568dcba64d3f57a69f03f22648822..c63631e39f34e9252cd88cef8d4004ec457e68dd 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 @@ -29,7 +29,7 @@ -- > run -a ------------------------------------------------------------------------------- -library IEEE, common_lib, dp_lib; +library IEEE, common_lib, dp_lib, reorder_lib; use IEEE.std_logic_1164.all; use common_lib.common_pkg.all; use common_lib.common_mem_pkg.all; @@ -37,15 +37,19 @@ use common_lib.tb_common_pkg.all; use common_lib.tb_common_mem_pkg.all; use common_lib.common_network_layers_pkg.all; use dp_lib.dp_stream_pkg.all; +use reorder_lib.reorder_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 generic ( - g_nof_repeat : natural := 50; - g_beamset_id : natural := 0; - g_use_transpose : boolean := true; - g_use_multiple_destinations : boolean := false + g_nof_repeat : natural := 50; + g_beamset_id : natural := 1; + g_use_transpose : boolean := true; + g_nof_destinations_max : natural := 16; + g_nof_destinations : natural := 7; + g_sim_force_bsn_error : boolean := false -- not verified in this tb ); end tb_sdp_beamformer_output; @@ -53,6 +57,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; @@ -67,14 +79,27 @@ 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_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 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(c_nof_destinations); + + constant c_mdi_nof_beamlets_all_destinations : natural := c_mdi_nof_blocks_per_packet * c_sdp_S_sub_bf; + -- 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 @@ -87,6 +112,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; @@ -98,6 +124,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; @@ -115,31 +143,60 @@ 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_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; + signal mdi_exp_dp_bsn : natural; + + signal rx_offload_sosi : t_dp_sosi := c_dp_sosi_rst; + signal rx_offload_data : std_logic_vector(c_longword_w - 1 downto 0); -- 64 bit + 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; + signal rx_beamlet_data : std_logic_vector(c_longword_w - 1 downto 0); -- 64 bit -- [0 : 3] = X, Y, X, Y 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; - -- [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'; + -- 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'; + -- 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); + signal rx_mdi_beamlet_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_val : std_logic := '0'; + -- Use +c_beamlet_mod to ensure >= 0 to fit in natural, use mod c_beamlet_mod -- 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 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; @@ -148,29 +205,78 @@ 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); + if c_nof_destinations_max = 1 then + -------------------------------------------------------------------------- + -- BDO one destination fields in dp_offload_tx_v3 + -------------------------------------------------------------------------- + proc_mem_mm_bus_wr(41, to_uint(c_sdp_cep_eth_dst_mac(47 downto 32)), mm_clk, hdr_dat_cipo, hdr_dat_copi); + proc_mem_mm_bus_wr(40, to_sint(c_sdp_cep_eth_dst_mac(31 downto 0)), mm_clk, hdr_dat_cipo, hdr_dat_copi); + proc_mem_mm_bus_wr(25, to_sint(c_sdp_cep_ip_dst_addr), mm_clk, hdr_dat_cipo, hdr_dat_copi); + proc_mem_mm_bus_wr(23, to_uint(c_sdp_cep_udp_dst_port), mm_clk, hdr_dat_cipo, hdr_dat_copi); + else + ---------------------------------------------------------------------------- + -- BDO multiple destinations info in sdp_bdo_destinations_reg + ---------------------------------------------------------------------------- + -- . Set nof_destinations = g_nof_destinations + 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); + + -- . 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 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 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; + end if; + ---------------------------------------------------------------------------- - -- BDO header fields + -- BDO header src 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); proc_mem_mm_bus_wr(26, to_sint(c_cep_ip_src_addr), mm_clk, hdr_dat_cipo, hdr_dat_copi); proc_mem_mm_bus_wr(24, to_uint(c_cep_udp_src_port), mm_clk, hdr_dat_cipo, hdr_dat_copi); - proc_mem_mm_bus_wr(41, to_uint(c_sdp_cep_eth_dst_mac(47 downto 32)), mm_clk, hdr_dat_cipo, hdr_dat_copi); - proc_mem_mm_bus_wr(40, to_sint(c_sdp_cep_eth_dst_mac(31 downto 0)), mm_clk, hdr_dat_cipo, hdr_dat_copi); - proc_mem_mm_bus_wr(25, to_sint(c_sdp_cep_ip_dst_addr), mm_clk, hdr_dat_cipo, hdr_dat_copi); - proc_mem_mm_bus_wr(23, to_uint(c_sdp_cep_udp_dst_port), mm_clk, hdr_dat_cipo, hdr_dat_copi); ---------------------------------------------------------------------------- -- 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; @@ -195,7 +301,7 @@ begin g_wait_last_evt => 100 ) port map ( - rst => dp_rst, + rst => mm_init, clk => dp_clk, -- Generate stimuli @@ -212,8 +318,8 @@ begin generic map ( g_beamset_id => g_beamset_id, g_use_transpose => g_use_transpose, - g_use_multiple_destinations => g_use_multiple_destinations, - g_sim_force_bsn_error => false + g_nof_destinations_max => c_nof_destinations_max, + g_sim_force_bsn_error => g_sim_force_bsn_error ) port map ( mm_clk => mm_clk, @@ -269,7 +375,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 @@ -279,97 +385,243 @@ 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. - 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_dp_bsn); + -- Destination index (DI) + rx_DI <= rx_offload_sop_cnt mod c_nof_destinations; 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 c_nof_destinations_max = 1 generate + -- Wires + rx_merge_sosi <= rx_offload_sosi; + rx_beamlet_sosi <= rx_offload_sosi; + + --------------------------------------------------------------------------- + -- Verify one destination: beamlet header + --------------------------------------------------------------------------- + -- 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, + c_sdp_cep_nof_blocks_per_packet, + c_sdp_cep_nof_beamlets_per_block, + exp_dp_bsn); + + p_verify_one_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 one destination: 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_one_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 c_nof_destinations_max > 1 generate + ----------------------------------------------------------------------------- + -- Merge rx offload packet data + ----------------------------------------------------------------------------- + -- Merge c_nof_destinations rx_offload_sosi packets into one rx_merge_sosi + -- packet to: + -- - 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 => c_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 multiple destinations: beamlet header + --------------------------------------------------------------------------- + -- Prepare mdi_exp_beamlet_header before rx_offload_sosi.eop, so that + -- p_verify_beamlet_header can verify it at rx_offload_sosi.eop. + mdi_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, + mdi_exp_beamlet_index, + c_mdi_nof_blocks_per_packet, + mdi_exp_nof_beamlets_per_block, + mdi_exp_dp_bsn); + + p_verify_multi_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 + mdi_exp_nof_beamlets_per_block <= c_mdi_nof_beamlets_per_block_per_destination; + 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; + + -- Expected beamlet index increments by c_mdi_nof_beamlets_per_block_per_destination per destination index + mdi_exp_beamlet_index <= c_exp_beamlet_index + rx_DI * c_mdi_nof_beamlets_per_block_per_destination; + 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_prev_re : natural := prev_re; - variable v_prev_im : natural := prev_im; - 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 + 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 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; + + -- Verify header at eop + if rx_offload_sosi.eop = '1' then + v_bool := func_sdp_verify_cep_header(rx_beamlet_header, mdi_exp_beamlet_header); + end if; + end process; + + --------------------------------------------------------------------------- + -- Verify multiple destinations: beamlet data + --------------------------------------------------------------------------- + -- Wires + rx_beamlet_sosi <= rx_merge_sosi; + + -- To view the 64 bit 10GbE offload data more easily in the Wave window + rx_offload_data <= rx_offload_sosi.data(c_longword_w - 1 downto 0); + rx_beamlet_data <= rx_beamlet_sosi.data(c_longword_w - 1 downto 0); + + proc_sdp_rx_beamlet_octets(c_mdi_nof_blocks_per_packet, + dp_clk, + rx_beamlet_sosi, + rx_mdi_beamlet_cnt, + rx_beamlet_valid, + rx_beamlet_arr_re, + rx_beamlet_arr_im, + rx_mdi_packet_list_re, + rx_mdi_packet_list_im); + + p_verify_multi_rx_beamlet_list : process + -- Nof complex (= nof re = nof im = c_N) values in packet_list + constant c_N : natural := c_mdi_nof_beamlets_all_destinations * 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); -- 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 - for vI in 0 to c_N - 1 loop - -- Verify incrementing beamlets - v_prev_re := (v_prev_re + 1) mod c_beamlet_mod; - v_prev_im := (v_prev_im + 1) mod c_beamlet_mod; - assert to_uint(rx_beamlet_list_re(vI)) = v_prev_re report "Wrong re_beamlet." severity error; - assert to_uint(rx_beamlet_list_im(vI)) = v_prev_im report "Wrong im_beamlet." severity error; - end loop; - prev_re <= v_prev_re; - prev_im <= v_prev_im; - end process; + rx_mdi_beamlet_list_re <= func_reorder_transpose_packet(c_sdp_S_sub_bf, + c_mdi_nof_blocks_per_packet, + c_sdp_N_pol_bf, + rx_mdi_packet_list_re); + rx_mdi_beamlet_list_im <= func_reorder_transpose_packet(c_sdp_S_sub_bf, + c_mdi_nof_blocks_per_packet, + c_sdp_N_pol_bf, + rx_mdi_packet_list_im); + rx_mdi_beamlet_list_val <= '1'; + + -- Wait until rx_beamlet_list is valid + wait until rising_edge(dp_clk); + rx_mdi_beamlet_list_val <= '0'; + -- Verify rx_beamlet_list + -- . get last values from previous block + 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; + v_im := (v_im + 1) mod c_beamlet_mod; + assert to_uint(rx_mdi_beamlet_list_re(vI)) = v_re report "Wrong mdi re_beamlet." severity error; + 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 + 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_sdp_pkg.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd index 63ca0848374b7becbbf893c94cc36fdd8ba8a019..a6f9b19d3f5f044bee8c7b314f833dac4efd3275 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd @@ -62,24 +62,49 @@ package tb_sdp_pkg is ----------------------------------------------------------------------------- -- Beamlet output via 10GbE to CEP (= central processor) ----------------------------------------------------------------------------- - function func_sdp_compose_cep_header(ip_src_addr : std_logic_vector; - ip_header_checksum : natural; - sdp_info : t_sdp_info; -- app header - gn_index : natural; - payload_error : std_logic; - beamlet_scale : natural; - beamlet_index : natural; - dp_bsn : natural) return t_sdp_cep_header; - - function func_sdp_compose_cep_header(ip_header_checksum : natural; - sdp_info : t_sdp_info; -- app header - gn_index : natural; - payload_error : std_logic; - beamlet_scale : natural; - beamlet_index : natural; - dp_bsn : natural) return t_sdp_cep_header; - - function func_sdp_verify_cep_header(in_hdr, exp_hdr : t_sdp_cep_header) return boolean; + function func_sdp_compose_cep_header(ip_src_addr : std_logic_vector; + ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + nof_blocks_per_packet : natural; + nof_beamlets_per_block : natural; + dp_bsn : natural) return t_sdp_cep_header; + + function func_sdp_compose_cep_header(ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + nof_blocks_per_packet : natural; + nof_beamlets_per_block : natural; + dp_bsn : natural) return t_sdp_cep_header; + + function func_sdp_compose_cep_header(ip_src_addr : std_logic_vector; + ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + dp_bsn : natural) return t_sdp_cep_header; + + function func_sdp_compose_cep_header(ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + dp_bsn : natural) return t_sdp_cep_header; + + function func_sdp_verify_cep_header(in_hdr : t_sdp_cep_header; + exp_hdr : t_sdp_cep_header; + beamlet_index_mod : boolean) return boolean; + function func_sdp_verify_cep_header(in_hdr : t_sdp_cep_header; + exp_hdr : t_sdp_cep_header) return boolean; ----------------------------------------------------------------------------- -- Subband equalizer (ESub) @@ -109,8 +134,8 @@ package tb_sdp_pkg is ----------------------------------------------------------------------------- -- Beamlet output packet ----------------------------------------------------------------------------- - -- beamlet part index [0 : 3] of X, Y, X, Y in network longword: - -- - use separate array for re and for im: + -- beamlet complex part index [0 : 3] of X, Y, X, Y in network longword: + -- - use separate array for re part and for im part: -- . re[0 : 3] at 0, 2, 4, 6 in longword -- . im[0 : 3] at 1, 3, 5, 7 in longword subtype t_sdp_beamlet_part_arr is t_slv_8_arr(0 to c_sdp_nof_beamlets_per_longword * c_sdp_N_pol_bf - 1); @@ -127,6 +152,17 @@ package tb_sdp_pkg is function func_sdp_undo_transpose_beamlet_packet(packet_list : t_sdp_beamlet_packet_list) return t_sdp_beamlet_packet_list; -- Read beamlet packet octets per re and im parts + procedure proc_sdp_rx_beamlet_octets( + constant c_nof_blocks_per_packet : in natural; + signal clk : in std_logic; + signal rx_beamlet_sosi : in t_dp_sosi; + signal rx_beamlet_cnt : inout natural; + signal rx_beamlet_valid : out std_logic; + signal rx_beamlet_arr_re : out t_sdp_beamlet_part_arr; + signal rx_beamlet_arr_im : out t_sdp_beamlet_part_arr; + signal rx_packet_list_re : out t_slv_8_arr; + signal rx_packet_list_im : out t_slv_8_arr); + procedure proc_sdp_rx_beamlet_octets( signal clk : in std_logic; signal rx_beamlet_sosi : in t_dp_sosi; @@ -311,14 +347,16 @@ package body tb_sdp_pkg is return true; end func_sdp_verify_stat_header; - function func_sdp_compose_cep_header(ip_src_addr : std_logic_vector; - ip_header_checksum : natural; - sdp_info : t_sdp_info; -- app header - gn_index : natural; - payload_error : std_logic; - beamlet_scale : natural; - beamlet_index : natural; - dp_bsn : natural) return t_sdp_cep_header is + function func_sdp_compose_cep_header(ip_src_addr : std_logic_vector; + ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + nof_blocks_per_packet : natural; + nof_beamlets_per_block : natural; + dp_bsn : natural) return t_sdp_cep_header is -- Use sim default dst and src MAC, IP, UDP port from sdp_pkg.vhd and based on gn_index constant c_mac_15_0 : std_logic_vector(15 downto 0) := func_sdp_gn_index_to_mac_15_0(gn_index); variable v_hdr : t_sdp_cep_header; @@ -367,14 +405,60 @@ package body tb_sdp_pkg is v_hdr.app.sdp_reserved := TO_UVEC(0, 32); v_hdr.app.sdp_beamlet_scale := TO_UVEC(beamlet_scale, 16); v_hdr.app.sdp_beamlet_index := TO_UVEC(beamlet_index, 16); - v_hdr.app.sdp_nof_blocks_per_packet := TO_UVEC(c_sdp_cep_nof_blocks_per_packet, 8); - v_hdr.app.sdp_nof_beamlets_per_block := TO_UVEC(c_sdp_cep_nof_beamlets_per_block, 16); + v_hdr.app.sdp_nof_blocks_per_packet := TO_UVEC(nof_blocks_per_packet, 8); + v_hdr.app.sdp_nof_beamlets_per_block := TO_UVEC(nof_beamlets_per_block, 16); v_hdr.app.sdp_block_period := sdp_info.block_period; v_hdr.app.dp_bsn := TO_UVEC(dp_bsn, 64); return v_hdr; end func_sdp_compose_cep_header; + function func_sdp_compose_cep_header(ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + nof_blocks_per_packet : natural; + nof_beamlets_per_block : natural; + dp_bsn : natural) return t_sdp_cep_header is + -- Use sim default dst and src MAC, IP, UDP port from sdp_pkg.vhd and based on gn_index + constant c_ip_15_0 : std_logic_vector(15 downto 0) := func_sdp_gn_index_to_ip_15_0(gn_index); + constant c_ip_src_addr : std_logic_vector(31 downto 0) := c_sdp_cep_ip_src_addr_31_16 & c_ip_15_0; + begin + return func_sdp_compose_cep_header(c_ip_src_addr, + ip_header_checksum, + sdp_info, + gn_index, + payload_error, + beamlet_scale, + beamlet_index, + nof_blocks_per_packet, + nof_beamlets_per_block, + dp_bsn); + end func_sdp_compose_cep_header; + + function func_sdp_compose_cep_header(ip_src_addr : std_logic_vector; + ip_header_checksum : natural; + sdp_info : t_sdp_info; -- app header + gn_index : natural; + payload_error : std_logic; + beamlet_scale : natural; + beamlet_index : natural; + dp_bsn : natural) return t_sdp_cep_header is + begin + return func_sdp_compose_cep_header(ip_src_addr, + ip_header_checksum, + sdp_info, + gn_index, + payload_error, + beamlet_scale, + beamlet_index, + c_sdp_cep_nof_blocks_per_packet, + c_sdp_cep_nof_beamlets_per_block, + dp_bsn); + end func_sdp_compose_cep_header; + function func_sdp_compose_cep_header(ip_header_checksum : natural; sdp_info : t_sdp_info; -- app header gn_index : natural; @@ -393,10 +477,14 @@ package body tb_sdp_pkg is payload_error, beamlet_scale, beamlet_index, + c_sdp_cep_nof_blocks_per_packet, + c_sdp_cep_nof_beamlets_per_block, dp_bsn); end func_sdp_compose_cep_header; - function func_sdp_verify_cep_header(in_hdr, exp_hdr : t_sdp_cep_header) return boolean is + function func_sdp_verify_cep_header(in_hdr : t_sdp_cep_header; + exp_hdr : t_sdp_cep_header; + beamlet_index_mod : boolean) return boolean is variable v_beamlet_index : natural; begin -- eth header @@ -442,8 +530,11 @@ package body tb_sdp_pkg is assert in_hdr.app.sdp_reserved = exp_hdr.app.sdp_reserved report "Wrong beamlet app.sdp_reserved" severity ERROR; assert in_hdr.app.sdp_beamlet_scale = exp_hdr.app.sdp_beamlet_scale report "Wrong beamlet app.sdp_beamlet_scale" severity ERROR; - -- Treat beamlet_index modulo c_sdp_S_sub_bf, because the beamlet packets from different beamsets may arrive in arbitrary order - v_beamlet_index := TO_UINT(in_hdr.app.sdp_beamlet_index) mod c_sdp_S_sub_bf; + v_beamlet_index := TO_UINT(in_hdr.app.sdp_beamlet_index); + if beamlet_index_mod then + -- Treat beamlet_index modulo c_sdp_S_sub_bf, because the beamlet packets from different beamsets may arrive in arbitrary order + v_beamlet_index := v_beamlet_index mod c_sdp_S_sub_bf; + end if; assert v_beamlet_index = TO_UINT(exp_hdr.app.sdp_beamlet_index) report "Wrong beamlet app.sdp_beamlet_index" severity ERROR; assert in_hdr.app.sdp_nof_blocks_per_packet = exp_hdr.app.sdp_nof_blocks_per_packet report "Wrong beamlet app.sdp_nof_blocks_per_packet" severity ERROR; assert in_hdr.app.sdp_nof_beamlets_per_block = exp_hdr.app.sdp_nof_beamlets_per_block report "Wrong beamlet app.sdp_nof_beamlets_per_block" severity ERROR; @@ -453,6 +544,12 @@ package body tb_sdp_pkg is return true; end func_sdp_verify_cep_header; + function func_sdp_verify_cep_header(in_hdr : t_sdp_cep_header; + exp_hdr : t_sdp_cep_header) return boolean is + begin + return func_sdp_verify_cep_header(in_hdr, exp_hdr, false); + end func_sdp_verify_cep_header; + function func_sdp_subband_equalizer(sp_subband_ampl, sp_subband_phase, sp_esub_gain, sp_esub_phase, cross_subband_ampl, cross_subband_phase, cross_esub_gain, cross_esub_phase : real) return t_real_arr is -- 0:3 = ampl, phase, re, im @@ -557,21 +654,25 @@ package body tb_sdp_pkg is -- . Beamlets array is stored big endian in the data, so X.real index 0 first -- in MSByte of rx_beamlet_sosi.data. procedure proc_sdp_rx_beamlet_octets( - signal clk : in std_logic; - signal rx_beamlet_sosi : in t_dp_sosi; - signal rx_beamlet_cnt : inout natural; - signal rx_beamlet_valid : out std_logic; - signal rx_beamlet_arr_re : out t_sdp_beamlet_part_arr; - signal rx_beamlet_arr_im : out t_sdp_beamlet_part_arr; - signal rx_packet_list_re : out t_sdp_beamlet_packet_list; - signal rx_packet_list_im : out t_sdp_beamlet_packet_list) is + constant c_nof_blocks_per_packet : in natural; + signal clk : in std_logic; + signal rx_beamlet_sosi : in t_dp_sosi; + signal rx_beamlet_cnt : inout natural; + signal rx_beamlet_valid : out std_logic; + signal rx_beamlet_arr_re : out t_sdp_beamlet_part_arr; -- [0:3] + signal rx_beamlet_arr_im : out t_sdp_beamlet_part_arr; -- [0:3] + signal rx_packet_list_re : out t_slv_8_arr; -- [0:c_list_len - 1] + signal rx_packet_list_im : out t_slv_8_arr) is + constant c_nof_beamlets_per_packet : natural := c_nof_blocks_per_packet * c_sdp_cep_nof_beamlets_per_block; + constant c_nof_longwords_per_packet : natural := c_nof_beamlets_per_packet / c_sdp_nof_beamlets_per_longword; + constant c_list_len : natural := c_nof_beamlets_per_packet * c_sdp_N_pol_bf; begin rx_beamlet_cnt <= 0; rx_beamlet_valid <= '0'; -- Wait until start of a beamlet packet proc_common_wait_until_high(clk, rx_beamlet_sosi.sop); -- c_sdp_nof_beamlets_per_longword = 2 dual pol beamlets (= XY, XY) per 64b data word - for I in 0 to (c_sdp_cep_nof_beamlets_per_packet / c_sdp_nof_beamlets_per_longword) - 1 loop + for I in 0 to c_nof_longwords_per_packet - 1 loop proc_common_wait_until_high(clk, rx_beamlet_sosi.valid); rx_beamlet_valid <= '1'; -- Capture rx beamlets per longword in rx_beamlet_arr, for time series view in Wave window @@ -598,8 +699,29 @@ package body tb_sdp_pkg is -- contains no WAIT statement. wait until rising_edge(clk); rx_beamlet_valid <= '0'; - rx_beamlet_cnt <= (rx_beamlet_cnt + c_sdp_nof_beamlets_per_longword) mod c_sdp_cep_nof_beamlets_per_block; -- 4 blocks/packet + rx_beamlet_cnt <= (rx_beamlet_cnt + c_sdp_nof_beamlets_per_longword) mod c_sdp_cep_nof_beamlets_per_block; end loop; end proc_sdp_rx_beamlet_octets; + procedure proc_sdp_rx_beamlet_octets( + signal clk : in std_logic; + signal rx_beamlet_sosi : in t_dp_sosi; + signal rx_beamlet_cnt : inout natural; + signal rx_beamlet_valid : out std_logic; + signal rx_beamlet_arr_re : out t_sdp_beamlet_part_arr; + signal rx_beamlet_arr_im : out t_sdp_beamlet_part_arr; + signal rx_packet_list_re : out t_sdp_beamlet_packet_list; + signal rx_packet_list_im : out t_sdp_beamlet_packet_list) is + begin + proc_sdp_rx_beamlet_octets( + c_sdp_cep_nof_blocks_per_packet, -- 4 blocks/packet + 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); + end proc_sdp_rx_beamlet_octets; end tb_sdp_pkg; 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 881383bb6c521d754b60c6ed98b5761c77d57f1e..4f6652e9d9122117ba3cc823d696246877d71052 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 @@ -36,11 +36,30 @@ end tb_tb_sdp_beamformer_output; architecture tb of tb_tb_sdp_beamformer_output is signal tb_end : std_logic := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' begin - -- g_nof_repeat : natural := 10; - -- g_beamset_id : natural := 0; - -- g_use_transpose : boolean := false; - -- g_use_multiple_destinations : boolean := false + -- g_nof_repeat : natural := 10; + -- g_beamset_id : natural := 0; + -- g_use_transpose : boolean := false; + -- g_nof_destinations_max : natural := 1; + -- g_nof_destinations : natural := 1; + -- g_sim_force_bsn_error : boolean := false - u_one_identity : entity work.tb_sdp_beamformer_output generic map( 50, 0, false, false); - u_one_transpose : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, false); + -- One BDO destination + u_one_identity : entity work.tb_sdp_beamformer_output generic map( 50, 0, false, 1, 1, false); + u_one_transpose : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 1, 1, false); + u_one_transpose_bset_1 : entity work.tb_sdp_beamformer_output generic map( 50, 1, true, 1, 1, false); + + -- Multiple BDO destinations + -- . prime number combination + u_multi_7_3 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 7, 3, false); + u_multi_7_3_bset_1 : entity work.tb_sdp_beamformer_output generic map( 50, 1, true, 7, 3, false); + -- . use 1 destnation, when more are available + u_multi_16_1 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 16, 1, false); + -- . use all destinations that are available + u_multi_16_16 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 16, 16, false); + -- . use prime number of destination from maximum available + u_multi_32_7 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 32, 7, false); + -- . 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, false); + -- . use maximum number of destinations + u_multi_32_31 : entity work.tb_sdp_beamformer_output generic map( 50, 0, true, 32, 31, false); end tb; diff --git a/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd b/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd index 26c9f6656e7eab03f42af23ad26e6ce03b71d75e..8f706fe08b9b1afe5fab7b674ae91aedd939696d 100644 --- a/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd +++ b/libraries/base/dp/src/vhdl/dp_packet_unmerge.vhd @@ -162,7 +162,7 @@ begin if snk_in.sop = '1' then v.val_cnt := 0; elsif snk_in.valid = '1' then - if r.val_cnt < g_pkt_len - 1 then + if r.val_cnt < r.pkt_len - 1 then v.val_cnt := r.val_cnt + 1; else v.val_cnt := 0;