diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index f64fd1ecaa1314e1de75ace410648826c42109b7..118ac6f5a32916305b826e0ed8a6500509ade1d0 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -203,6 +203,7 @@ test_bench_files =
     tb/vhdl/tb_dp_mux.vhd
     tb/vhdl/tb2_dp_mux.vhd
     tb/vhdl/tb3_dp_mux.vhd
+    tb/vhdl/tb_dp_concat_field_blk.vhd
     tb/vhdl/tb_dp_packet.vhd
     tb/vhdl/tb_dp_packet_merge.vhd
     tb/vhdl/tb_dp_packetizing.vhd
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_concat_field_blk.vhd b/libraries/base/dp/tb/vhdl/tb_dp_concat_field_blk.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..ad87a38771c6fcea2ddd8c4d9a751b24e0eb8766
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_concat_field_blk.vhd
@@ -0,0 +1,398 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose:
+-- . Test bench for dp_concat_field_blk and dp_offload_rx
+-- Description:
+--                 u_tx                     u_rx
+--                 ___________________      ___________________ 
+--                |dp_concat_field_blk|    |dp_offload_rx      |
+-- stimuli_src -->|                   |--->|                   |--> verify_snk
+--                | in            out | |  | in            out |
+--                |___________________| |  |___________________|
+--                                      |
+--                               link_offload_sosi
+-- Usage:                                  
+-- > as 10
+-- > run -all
+--
+
+LIBRARY IEEE, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_field_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+
+ENTITY tb_dp_concat_field_blk IS
+  GENERIC (
+    -- general
+    g_flow_control_stimuli   : t_dp_flow_control_enum := e_active;  -- always e_active, e_random or e_pulse flow control
+    g_flow_control_verify    : t_dp_flow_control_enum := e_active;  -- always e_active, e_random or e_pulse flow control
+    -- specific
+    g_data_w                 : NATURAL := 64;
+    g_nof_repeat             : NATURAL := 13;
+    g_pkt_len                : NATURAL := 100;
+    g_pkt_gap                : NATURAL := 30
+  );
+END tb_dp_concat_field_blk;
+
+
+ARCHITECTURE tb OF tb_dp_concat_field_blk IS
+
+  CONSTANT c_mm_clk_period : TIME := 1 ns;
+  CONSTANT c_dp_clk_period : TIME := 5 ns;
+
+  -- dp_stream_stimuli
+  CONSTANT c_stimuli_pulse_active     : NATURAL := 3;
+  CONSTANT c_stimuli_pulse_period     : NATURAL := 7;
+
+  -- dp_stream_verify
+  CONSTANT c_verify_pulse_active      : NATURAL := 1;
+  CONSTANT c_verify_pulse_period      : NATURAL := 5;
+
+  CONSTANT c_data_max                 : UNSIGNED(g_data_w-1 DOWNTO 0) := (OTHERS=>'1');
+  CONSTANT c_dsp_max                  : UNSIGNED(g_data_w-1 DOWNTO 0) := (OTHERS=>'1');
+
+  --CONSTANT c_verify_snk_in_cnt_max    : t_dp_sosi_unsigned := c_dp_sosi_unsigned_rst;  -- default 0 is no wrap
+  CONSTANT c_verify_snk_in_cnt_max    : t_dp_sosi_unsigned := TO_DP_SOSI_UNSIGNED('0', '0', '0', '0', c_data_max, c_dsp_max, c_dsp_max, c_unsigned_0, c_unsigned_0, c_unsigned_0, c_unsigned_0);
+  CONSTANT c_verify_snk_in_cnt_gap    : t_dp_sosi_unsigned := c_dp_sosi_unsigned_ones; -- default only accept increment +1
+
+  CONSTANT c_expected_pkt_len         : NATURAL := g_pkt_len;
+  CONSTANT c_sync_period              : NATURAL := 5;
+  CONSTANT c_sync_offset              : NATURAL := 2;
+
+  -----------------------------------------------------------------------------
+  -- Tx offload
+  -----------------------------------------------------------------------------
+  -- From apertif_udp_offload_pkg.vhd:
+  CONSTANT c_udp_offload_nof_hdr_fields : NATURAL := 3+12+4+3; -- 448b; 7 64b words
+  -- Notes: 
+  -- . pre-calculated ip_header_checksum is valid only for UNB0, FN0 targeting IP 10.10.10.10
+  -- . udp_total_length = 176 beamlets * 64b / 8b = 1408B + 14 DP bytes + 8 UDP bytes = 1430B 
+  CONSTANT c_udp_offload_hdr_field_arr : t_common_field_arr(c_udp_offload_nof_hdr_fields-1 DOWNTO 0) := (
+         ( field_name_pad("eth_dst_mac"            ), "RW", 48, field_default(x"001B214368AC") ),
+         ( field_name_pad("eth_src_mac"            ), "RW", 48, field_default(0) ),
+         ( field_name_pad("eth_type"               ), "RW", 16, field_default(x"0800") ),
+         ( field_name_pad("ip_version"             ), "RW",  4, field_default(4) ),
+         ( field_name_pad("ip_header_length"       ), "RW",  4, field_default(5) ),
+         ( field_name_pad("ip_services"            ), "RW",  8, field_default(0) ),
+         ( field_name_pad("ip_total_length"        ), "RW", 16, field_default(1450) ), 
+         ( field_name_pad("ip_identification"      ), "RW", 16, field_default(0) ),
+         ( field_name_pad("ip_flags"               ), "RW",  3, field_default(2) ),
+         ( field_name_pad("ip_fragment_offset"     ), "RW", 13, field_default(0) ),
+         ( field_name_pad("ip_time_to_live"        ), "RW",  8, field_default(127) ),
+         ( field_name_pad("ip_protocol"            ), "RW",  8, field_default(17) ),
+         ( field_name_pad("ip_header_checksum"     ), "RW", 16, field_default(29928) ),
+         ( field_name_pad("ip_src_addr"            ), "RW", 32, field_default(x"C0A80009") ),
+         ( field_name_pad("ip_dst_addr"            ), "RW", 32, field_default(x"C0A80001") ),
+         ( field_name_pad("udp_src_port"           ), "RW", 16, field_default(0) ), 
+         ( field_name_pad("udp_dst_port"           ), "RW", 16, field_default(0) ), 
+         ( field_name_pad("udp_total_length"       ), "RW", 16, field_default(1430) ),
+         ( field_name_pad("udp_checksum"           ), "RW", 16, field_default(0) ),
+         ( field_name_pad("dp_reserved"            ), "RW", 47, field_default(0) ),
+         ( field_name_pad("dp_sync"                ), "RW",  1, field_default(0) ),
+         ( field_name_pad("dp_bsn"                 ), "RW", 64, field_default(0) ) );
+
+  -- From apertif_unb1_fn_beamformer_udp_offload.vhd:
+  -- Override ('1') only the Ethernet fields so we can use MM defaults there.
+  CONSTANT c_hdr_field_ovr_init : STD_LOGIC_VECTOR(c_udp_offload_nof_hdr_fields-1 DOWNTO 0) := "101"&"111111111111"&"1111"&"100";
+
+  CONSTANT c_NODE_ID                    : STD_LOGIC_VECTOR(7 DOWNTO 0) := TO_UVEC(0, 8);
+
+  SIGNAL id_backplane                   : STD_LOGIC_VECTOR(c_byte_w-1 DOWNTO 0);
+  SIGNAL id_chip                        : STD_LOGIC_VECTOR(c_byte_w-1 DOWNTO 0);
+
+  SIGNAL dp_offload_tx_snk_in_arr       : t_dp_sosi_arr(0 DOWNTO 0);
+  SIGNAL dp_offload_tx_snk_out_arr      : t_dp_siso_arr(0 DOWNTO 0);
+  
+  SIGNAL tx_hdr_fields_in_arr           : t_slv_1024_arr(0 DOWNTO 0);
+  
+  SIGNAL reg_dp_offload_tx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst;
+  SIGNAL reg_dp_offload_tx_hdr_dat_miso : t_mem_miso;
+
+  -----------------------------------------------------------------------------
+  -- Link
+  -----------------------------------------------------------------------------
+  
+  SIGNAL tx_offload_sosi_arr       : t_dp_sosi_arr(0 DOWNTO 0);
+  SIGNAL tx_offload_siso_arr       : t_dp_siso_arr(0 DOWNTO 0);
+
+  SIGNAL link_offload_sosi_arr     : t_dp_sosi_arr(0 DOWNTO 0);
+  SIGNAL link_offload_siso_arr     : t_dp_siso_arr(0 DOWNTO 0);
+
+  -----------------------------------------------------------------------------
+  -- Rx offload
+  -----------------------------------------------------------------------------
+  SIGNAL dp_offload_rx_src_out_arr      : t_dp_sosi_arr(0 DOWNTO 0);
+  SIGNAL dp_offload_rx_src_in_arr       : t_dp_siso_arr(0 DOWNTO 0);
+  
+  SIGNAL rx_hdr_fields_out_arr          : t_slv_1024_arr(0 DOWNTO 0);
+  
+  SIGNAL reg_dp_offload_rx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst;
+  SIGNAL reg_dp_offload_rx_hdr_dat_miso : t_mem_miso;
+
+  -----------------------------------------------------------------------------
+  -- Test
+  -----------------------------------------------------------------------------
+  SIGNAL mm_clk                     : STD_LOGIC := '1';
+  SIGNAL mm_rst                     : STD_LOGIC := '1';
+  SIGNAL dp_clk                     : STD_LOGIC := '1';
+  SIGNAL dp_rst                     : STD_LOGIC := '1';
+  SIGNAL tb_end                     : STD_LOGIC := '0';
+  
+  SIGNAL stimuli_src_in             : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL stimuli_src_out            : t_dp_sosi;
+  SIGNAL stimuli_src_out_data       : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0);
+
+  SIGNAL verify_snk_in_enable       : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+  SIGNAL last_snk_in                : t_dp_sosi;
+  SIGNAL last_snk_in_evt            : STD_LOGIC;
+  SIGNAL verify_last_snk_in_evt     : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+
+  SIGNAL verify_snk_out             : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL verify_snk_in              : t_dp_sosi;
+  SIGNAL verify_snk_in_data         : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0);
+
+BEGIN
+
+  ------------------------------------------------------------------------------
+  -- Clock & reset
+  ------------------------------------------------------------------------------
+  mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2;
+  mm_rst <= '1', '0' AFTER c_mm_clk_period*7;
+  dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2;
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*7;
+
+  ------------------------------------------------------------------------------
+  -- DATA GENERATION
+  ------------------------------------------------------------------------------
+
+  u_dp_stream_stimuli : ENTITY work.dp_stream_stimuli
+  GENERIC MAP (
+    g_instance_nr    => 0,                        -- only one stream so choose index 0
+    -- flow control
+    g_random_w       => 15,                       -- use different random width for stimuli and for verify to have different random sequences
+    g_pulse_active   => c_stimuli_pulse_active,
+    g_pulse_period   => c_stimuli_pulse_period,
+    g_flow_control   => g_flow_control_stimuli,   -- always active, random or pulse flow control
+    -- initializations
+    g_sync_period    => c_sync_period,
+    g_sync_offset    => c_sync_offset,
+    -- specific
+    g_in_dat_w       => g_data_w,
+    g_nof_repeat     => g_nof_repeat,
+    g_pkt_len        => g_pkt_len,
+    g_pkt_gap        => g_pkt_gap
+  )
+  PORT MAP (
+    rst                 => dp_rst,
+    clk                 => dp_clk,
+
+    -- Generate stimuli
+    src_in              => stimuli_src_in,
+    src_out             => stimuli_src_out,
+
+    -- End of stimuli
+    last_snk_in         => last_snk_in,      -- expected verify_snk_in after end of stimuli
+    last_snk_in_evt     => last_snk_in_evt,  -- trigger verify to verify the last_snk_in
+    tb_end              => tb_end            -- signal end of tb as far as this dp_stream_stimuli is concerned
+  );
+
+
+  ------------------------------------------------------------------------------
+  -- DATA VERIFICATION
+  ------------------------------------------------------------------------------
+
+  -- Select fields that need to be verified
+  -- . during the test
+  verify_snk_in_enable.sync    <= '1';
+  verify_snk_in_enable.bsn     <= '1';
+  verify_snk_in_enable.data    <= '1';
+  verify_snk_in_enable.re      <= '0';
+  verify_snk_in_enable.im      <= '0';
+  verify_snk_in_enable.valid   <= '1';
+  verify_snk_in_enable.sop     <= '1';
+  verify_snk_in_enable.eop     <= '1';
+  verify_snk_in_enable.empty   <= '0';
+  verify_snk_in_enable.channel <= '0';
+  verify_snk_in_enable.err     <= '0';
+
+  -- . after the test
+  verify_last_snk_in_evt.sync    <= last_snk_in_evt;
+  verify_last_snk_in_evt.bsn     <= '0';   -- in rx_hdr_fields_out_arr from dp_offload_rx output the bsn is only valid at sop
+  verify_last_snk_in_evt.data    <= last_snk_in_evt;
+  verify_last_snk_in_evt.re      <= '0';
+  verify_last_snk_in_evt.im      <= '0';
+  verify_last_snk_in_evt.valid   <= last_snk_in_evt;
+  verify_last_snk_in_evt.sop     <= last_snk_in_evt;
+  verify_last_snk_in_evt.eop     <= last_snk_in_evt;
+  verify_last_snk_in_evt.empty   <= '0';
+  verify_last_snk_in_evt.channel <= '0';
+  verify_last_snk_in_evt.err     <= '0';
+
+  u_dp_stream_verify : ENTITY work.dp_stream_verify
+  GENERIC MAP (
+    g_instance_nr    => 0,                        -- only one stream so choose index 0
+    -- flow control
+    g_random_w       => 14,                       -- use different random width for stimuli and for verify to have different random sequences
+    g_pulse_active   => c_verify_pulse_active,
+    g_pulse_period   => c_verify_pulse_period,
+    g_flow_control   => g_flow_control_verify,    -- always active, random or pulse flow control
+    -- initializations
+    g_sync_period    => c_sync_period,
+    g_sync_offset    => c_sync_offset,
+    g_snk_in_cnt_max => c_verify_snk_in_cnt_max,
+    g_snk_in_cnt_gap => c_verify_snk_in_cnt_gap,
+    -- specific
+    g_in_dat_w       => g_data_w,
+    g_pkt_len        => c_expected_pkt_len
+  )
+  PORT MAP (
+    rst                        => dp_rst,
+    clk                        => dp_clk,
+
+    -- Verify data
+    snk_out                    => verify_snk_out,
+    snk_in                     => verify_snk_in,
+
+    -- During stimuli
+    verify_snk_in_enable       => verify_snk_in_enable,  -- enable verify to verify that the verify_snk_in fields are incrementing
+
+    -- End of stimuli
+    expected_snk_in            => last_snk_in,            -- expected verify_snk_in after end of stimuli
+    verify_expected_snk_in_evt => verify_last_snk_in_evt  -- trigger verify to verify the last_snk_in
+  );
+
+  ------------------------------------------------------------------------------
+  -- DUT offload Tx
+  ------------------------------------------------------------------------------
+  dp_offload_tx_snk_in_arr(0) <= stimuli_src_out;
+  stimuli_src_in              <= dp_offload_tx_snk_out_arr(0);
+
+  -- Extract the chip and backplane numbers from c_NODE_ID
+  id_backplane <= RESIZE_UVEC(c_NODE_ID(7 DOWNTO 3), c_byte_w);
+  id_chip      <= RESIZE_UVEC(c_NODE_ID(2 DOWNTO 0), c_byte_w);
+
+  -- Wire the hardwired header fields to DP signals and c_NODE_ID
+  tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "eth_src_mac" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "eth_src_mac"     )) <= x"00228608" & id_backplane & id_chip;
+  tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "udp_src_port") DOWNTO field_lo(c_udp_offload_hdr_field_arr, "udp_src_port"    )) <= x"D0" & c_NODE_ID;
+  tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "udp_dst_port") DOWNTO field_lo(c_udp_offload_hdr_field_arr, "udp_dst_port"    )) <= x"D0" & c_NODE_ID;
+  tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "ip_src_addr" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "ip_src_addr"     )) <= x"0A63" & id_backplane & INCR_UVEC(id_chip, 1);
+                                                                                                               
+  tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_sync"     ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_sync"         )) <= slv(dp_offload_tx_snk_in_arr(0).sync);
+  tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_bsn"      ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_bsn"          )) <=     dp_offload_tx_snk_in_arr(0).bsn(63 DOWNTO 0); 
+
+  u_tx : ENTITY work.dp_concat_field_blk
+  GENERIC MAP (
+    g_nof_streams    => 1,
+    g_data_w         => g_data_w,
+    g_symbol_w       => g_data_w,
+    g_hdr_field_arr  => c_udp_offload_hdr_field_arr,
+    g_hdr_field_sel  => c_hdr_field_ovr_init
+  ) 
+  PORT MAP (
+    mm_rst                => mm_rst,
+    mm_clk                => mm_clk,
+    
+    dp_rst                => dp_rst,
+    dp_clk                => dp_clk,
+
+    reg_hdr_dat_mosi      => reg_dp_offload_tx_hdr_dat_mosi,
+    reg_hdr_dat_miso      => reg_dp_offload_tx_hdr_dat_miso,
+
+    snk_in_arr            => dp_offload_tx_snk_in_arr,
+    snk_out_arr           => dp_offload_tx_snk_out_arr,
+
+    src_out_arr           => tx_offload_sosi_arr,
+    src_in_arr            => tx_offload_siso_arr,
+
+    hdr_fields_in_arr     => tx_hdr_fields_in_arr
+  );
+
+  ------------------------------------------------------------------------------
+  -- Link
+  ------------------------------------------------------------------------------
+
+  p_link_offload : PROCESS(tx_offload_sosi_arr, link_offload_siso_arr)
+  BEGIN
+    link_offload_sosi_arr <= tx_offload_sosi_arr;
+    link_offload_sosi_arr(0).re <= (OTHERS=>'0');
+    link_offload_sosi_arr(0).im <= (OTHERS=>'0');
+    
+    tx_offload_siso_arr <= link_offload_siso_arr;
+  END PROCESS;
+  
+  ------------------------------------------------------------------------------
+  -- DUT offload Rx
+  ------------------------------------------------------------------------------
+
+  u_rx : ENTITY work.dp_offload_rx
+  GENERIC MAP (
+    g_nof_streams         => 1,
+    g_data_w              => g_data_w,
+    g_hdr_field_arr       => c_udp_offload_hdr_field_arr,
+    g_remove_crc          => FALSE,
+    g_crc_nof_words       => 0 
+  )
+  PORT MAP (
+    mm_rst                => mm_rst,
+    mm_clk                => mm_clk,
+    
+    dp_rst                => dp_rst,
+    dp_clk                => dp_clk,
+  
+    reg_hdr_dat_mosi      => reg_dp_offload_rx_hdr_dat_mosi,
+    reg_hdr_dat_miso      => reg_dp_offload_rx_hdr_dat_miso,
+  
+    snk_in_arr            => link_offload_sosi_arr,
+    snk_out_arr           => link_offload_siso_arr,
+               
+    src_out_arr           => dp_offload_rx_src_out_arr,
+    src_in_arr            => dp_offload_rx_src_in_arr,
+  
+    hdr_fields_out_arr    => rx_hdr_fields_out_arr
+  );
+  
+  p_restore_sync_bsn : PROCESS(dp_offload_rx_src_out_arr, rx_hdr_fields_out_arr)
+  BEGIN
+    verify_snk_in      <= dp_offload_rx_src_out_arr(0);
+    verify_snk_in.sync <=          sl(rx_hdr_fields_out_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_sync") DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_sync" )));
+    verify_snk_in.bsn  <= RESIZE_UVEC(rx_hdr_fields_out_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_bsn"  )), c_dp_stream_bsn_w);
+  END PROCESS;
+
+  dp_offload_rx_src_in_arr    <= (OTHERS=>c_dp_siso_rdy);
+  dp_offload_rx_src_in_arr(0) <= verify_snk_out;
+  
+  ------------------------------------------------------------------------------
+  -- Auxiliary
+  ------------------------------------------------------------------------------
+
+  -- Map to slv to ease monitoring in wave window
+  stimuli_src_out_data <= stimuli_src_out.data(g_data_w-1 DOWNTO 0);
+  verify_snk_in_data   <= verify_snk_in.data(g_data_w-1 DOWNTO 0);
+
+END tb;