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;