diff --git a/libraries/base/common/src/vhdl/common_str_pkg.vhd b/libraries/base/common/src/vhdl/common_str_pkg.vhd
index cda0f3672e1b164d7156a455166ae428c340b609..c6adcaad935043c1eabd4dc0a0b674ab3a0c524a 100644
--- a/libraries/base/common/src/vhdl/common_str_pkg.vhd
+++ b/libraries/base/common/src/vhdl/common_str_pkg.vhd
@@ -57,6 +57,7 @@ PACKAGE common_str_pkg IS
   FUNCTION real_to_str(re: REAL; width : INTEGER; digits : INTEGER) RETURN STRING;
 
   PROCEDURE print_str(str : STRING);
+  PROCEDURE print_str(str: STRING; enable: BOOLEAN);
 
   FUNCTION str_to_ascii_integer_arr(s: STRING) RETURN t_integer_arr;
   FUNCTION str_to_ascii_slv_8_arr(  s: STRING) RETURN t_slv_8_arr;
@@ -262,13 +263,21 @@ PACKAGE BODY common_str_pkg IS
   END;
 
   PROCEDURE print_str(str: STRING) IS
-  VARIABLE v_line: LINE;
+    VARIABLE v_line: LINE;
   BEGIN
     write(v_line, str);
     writeline(output, v_line);
     deallocate(v_line);
   END;
 
+  PROCEDURE print_str(str: STRING; enable: BOOLEAN) IS
+    VARIABLE v_line: LINE;
+  BEGIN
+    IF enable THEN
+      print_str(str);
+    END IF;
+  END;
+
   FUNCTION str_to_ascii_integer_arr(s: STRING) RETURN t_integer_arr IS
     VARIABLE r: t_integer_arr(0 TO s'RIGHT-1);
   BEGIN
diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index 3b1bff1f02a4186cb170dc23e7f7e42b99c69aea..34a2c49f89a64e30918443ee012c44e85d40f1d5 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -347,6 +347,7 @@ test_bench_files =
     
     tb/vhdl/tb_tb_tb_dp_backpressure.vhd
     tb/vhdl/tb_dp_offload_tx_v3.vhd
+    tb/vhdl/tb_tb_dp_offload_tx_v3.vhd
     tb/vhdl/tb_dp_offload_rx_filter.vhd
     tb/vhdl/tb_dp_selector_arr.vhd
     tb/vhdl/tb_mms_dp_scale.vhd
@@ -416,6 +417,7 @@ regression_test_vhdl =
     tb/vhdl/tb_tb_dp_xonoff.vhd
     tb/vhdl/tb_dp_selector_arr.vhd
     tb/vhdl/tb_mms_dp_scale.vhd
+    tb/vhdl/tb_tb_dp_offload_tx_v3.vhd
 
 [modelsim_project_file]
 
diff --git a/libraries/base/dp/src/vhdl/dp_offload_rx.vhd b/libraries/base/dp/src/vhdl/dp_offload_rx.vhd
index 9effa4c7f350bc97dcadd99b59682feabad782f9..3cb3907f1f9d858e6f140c819628fa5305ffff8f 100644
--- a/libraries/base/dp/src/vhdl/dp_offload_rx.vhd
+++ b/libraries/base/dp/src/vhdl/dp_offload_rx.vhd
@@ -19,6 +19,27 @@
 --
 -------------------------------------------------------------------------------
 
+-- Author: D. van der Schuur, E. Kooistra
+-- Purpose:
+-- . Split a user-defined header from a data block e.g. to from an Eth frame
+-- Description:
+-- . The dp_offload_tx_v3 --> dp_offload_rx form a pair.
+-- . The header and data block can be split at symbol level, to support a header
+--   that does not have an integer number of g_data_w. The header length is
+--   defined by c_nof_header_symbols.
+-- . The header contents can be monitored and is defined by g_hdr_field_arr.
+-- . The data block is output via src_out_arr. If the data block contains an
+--   integer number of g_data_w words, then src_out_arr.empty = 0.
+-- . Default the g_symbol_w = 0 which implies g_symbol_w = g_data_w.
+--   - If the header length is not an integer number of g_data_w, then
+--     g_symbol_w has to be set such that c_nof_symbols_per_data and
+--     c_nof_header_symbols are both integers. The g_symbol_w is then used
+--     to control the split.
+--   - If the data block length is not an integer number of g_data_w, then
+--     g_symbol_w defines the symbol width of the data and is used to
+--     control the snk_out_arr empty field.
+
+
 LIBRARY IEEE, common_lib, dp_lib;
 USE IEEE.STD_LOGIC_1164.ALL;
 USE IEEE.NUMERIC_STD.ALL;
@@ -31,6 +52,7 @@ ENTITY dp_offload_rx IS
   GENERIC (
     g_nof_streams   : NATURAL;
     g_data_w        : NATURAL;
+    g_symbol_w      : NATURAL := 0;   -- default 0 yields g_symbol_w = g_data_w
     g_hdr_field_arr : t_common_field_arr;
     g_remove_crc    : BOOLEAN := FALSE;
     g_crc_nof_words : NATURAL := 0
@@ -59,7 +81,9 @@ END dp_offload_rx;
 
 ARCHITECTURE str OF dp_offload_rx IS 
 
-  CONSTANT c_nof_header_words         : NATURAL := field_slv_len(g_hdr_field_arr) / g_data_w;
+  CONSTANT c_symbol_w                 : NATURAL := sel_a_b(g_symbol_w = 0, g_data_w, g_symbol_w);
+  CONSTANT c_nof_symbols_per_data     : NATURAL := g_data_w / g_symbol_w;
+  CONSTANT c_nof_header_symbols       : NATURAL := field_slv_len(g_hdr_field_arr) / c_symbol_w;
 
   CONSTANT c_field_sel                 : STD_LOGIC_VECTOR(g_hdr_field_arr'RANGE) := (OTHERS=>'0');-- Not used in sink mode but requires set range
 
@@ -92,8 +116,8 @@ BEGIN
     u_dp_split : ENTITY work.dp_split 
     GENERIC MAP (
       g_data_w        => g_data_w,
-      g_symbol_w      => g_data_w,
-      g_nof_symbols   => c_nof_header_words
+      g_symbol_w      => c_symbol_w,
+      g_nof_symbols   => c_nof_header_symbols
     )
     PORT MAP (
       rst         => dp_rst,
@@ -117,10 +141,12 @@ BEGIN
   gen_dp_field_blk : FOR i IN 0 TO g_nof_streams-1 GENERATE
     u_dp_field_blk : ENTITY work.dp_field_blk
     GENERIC MAP (
-      g_field_arr   => field_arr_set_mode(g_hdr_field_arr , "RO"),
-      g_field_sel   => c_field_sel,
-      g_snk_data_w  => c_dp_field_blk_snk_data_w, --g_data_w,
-      g_src_data_w  => c_dp_field_blk_src_data_w  --field_slv_in_len(field_arr_set_mode(g_hdr_field_arr , "RO"))
+      g_field_arr    => field_arr_set_mode(g_hdr_field_arr , "RO"),
+      g_field_sel    => c_field_sel,
+      g_snk_data_w   => c_dp_field_blk_snk_data_w,  --g_data_w,
+      g_src_data_w   => c_dp_field_blk_src_data_w,  --field_slv_in_len(field_arr_set_mode(g_hdr_field_arr , "RO"))
+      g_in_symbol_w  => c_symbol_w,
+      g_out_symbol_w => c_symbol_w
     )
     PORT MAP (
       dp_rst       => dp_rst,
@@ -152,7 +178,7 @@ BEGIN
     u_dp_tail_remove : ENTITY work.dp_tail_remove
     GENERIC MAP (
       g_data_w      => g_data_w,
-      g_symbol_w    => g_data_w,
+      g_symbol_w    => c_symbol_w,
       g_nof_symbols => sel_a_b(g_remove_crc, g_crc_nof_words, 0) 
     )
     PORT MAP (
diff --git a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd
index e841015d5418e980fad3d84ca0c347f4df7170f8..f72352cd6925c80356551b0c2fa3b6761b1f9877 100644
--- a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd
+++ b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd
@@ -19,21 +19,25 @@
 --
 -------------------------------------------------------------------------------
 
+-- Author: D. van der Schuur, E. Kooistra
 -- Purpose:
--- . Concatenate a user-defined header to a DP frame e.g. to create an Ethernet frame
+-- . Concatenate a user-defined header to a data block e.g. to create an Eth
+--   frame
 -- Description:
--- . The header contents can be controlled dynamically by data path or MM control (selected by g_hdr_field_sel)
--- . The header and data can be concatened at symbol level. The g_symbol_w defines the
---   resolution of the empty field. The g_data_w must be an integer multiple of the 
---   g_symbol_w. If the empty field is not used or if the empty field is always 0 then
---   set g_symbol_w = g_data_w.
--- . For example to concat header and data for an Ethernet frame use:
+-- . The dp_offload_tx_v3 --> dp_offload_rx form a pair.
+-- . The header contents can be controlled dynamically by data path or MM
+--   control (selected by g_hdr_field_sel)
+-- . The header and data can be concatened at symbol level. The g_symbol_w
+--   defines the resolution of the empty field. The g_data_w must be an
+--   integer multiple of the g_symbol_w. If the empty field is not used or
+--   if the empty field is always 0 then set g_symbol_w = g_data_w.
+-- . For example to concat header and data block for an Ethernet frame use:
 --   - g_data_w = 32 (1GbE) or 64 (10GbE)
---   - g_symbol_w = c_byte_w = 8 if either the header or the data can have an
---                  non-zero empty field, so when they are not a multiple of 4 bytes
---                  (= 32b) or 8 bytes (= 64b).
---     g_symbol_w = g_data_w if the empty field is always 0, so the number of bits in
---                  the header and data are an integer number of g_data_w.
+--   - g_symbol_w = c_byte_w = 8 if either the header or the data block can
+--          have an non-zero empty field, so when they are not a multiple of
+--          4 bytes (= 32b) or 8 bytes (= 64b).
+--     g_symbol_w = g_data_w if the empty field is always 0, so the number of
+--          bits in the header and data are an integer number of g_data_w.
 
 
 LIBRARY IEEE, common_lib, technology_lib, mm_lib;
@@ -50,7 +54,7 @@ ENTITY dp_offload_tx_v3 IS
     g_nof_streams    : NATURAL;
     g_data_w         : NATURAL;
     g_symbol_w       : NATURAL;
-    g_hdr_field_arr  : t_common_field_arr; -- User defined header fields
+    g_hdr_field_arr  : t_common_field_arr;  -- User defined header fields
     g_hdr_field_sel  : STD_LOGIC_VECTOR;    -- For each header field, select the source: 0=data path, 1=MM controlled
     g_pipeline_ready : BOOLEAN := FALSE
   ); 
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd b/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd
index 0481f2ff99f2ea88456c65a93dc800f136537c9b..70d6538309705161c9cd4870c762f448b08d57a2 100644
--- a/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd
+++ b/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd
@@ -24,12 +24,29 @@
 -- Description:
 --                 u_tx                     u_rx
 --                 ___________________      ___________________ 
---                |dp_offload_tx_v3|    |dp_offload_rx      |
+--                |dp_offload_tx_v3   |    |dp_offload_rx      |
 -- stimuli_src -->|                   |--->|                   |--> verify_snk
 --                | in            out | |  | in            out |
 --                |___________________| |  |___________________|
 --                                      |
 --                               link_offload_sosi
+--
+--   The verification of the header - data block boundary is controlled via
+--   g_symbol_w:
+--   . g_symbol_w = g_data_w : boundary at g_data_w
+--   . g_symbol_w < g_data_w : boundary at g_symbol_w, by reducing the number
+--     of the header dp_bsn field by 1 symbol. If the c_bsn_w <= 32 then the
+--     header MM interface only needs one MM word to read the header, so
+--     therefore there are two sizes of c_expected_tx_hdr_word_arr_* and
+--     c_expected_rx_hdr_word_arr_*.
+--
+-- Remarks:
+-- . The g_flow_control_verify has to be e_active, otherwise the tb fails,
+--   probably due to limitation in dp_offload_rx.vhd.
+-- . It appears that the tx_hdr_word read values are the MM write values, so
+--   read of value from logic fields (with MM override '0', e.g. dp_bsn,
+--   eth_src_mac) is not supported.
+--
 -- Usage:                                  
 -- > as 10
 -- > run -all
@@ -54,9 +71,10 @@ ENTITY tb_dp_offload_tx_v3 IS
     -- general
     g_flow_control_stimuli   : t_dp_flow_control_enum := e_pulse;  -- 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
+    g_print_en               : BOOLEAN := TRUE;
     -- specific
     g_data_w                 : NATURAL := 64;
-    g_nof_repeat             : NATURAL := 100;
+    g_symbol_w               : NATURAL := 32;
     g_pkt_len                : NATURAL := 240;
     g_pkt_gap                : NATURAL := 16
   );
@@ -68,6 +86,18 @@ ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS
   CONSTANT c_mm_clk_period : TIME := 1 ns;
   CONSTANT c_dp_clk_period : TIME := 5 ns;
 
+  -- Simulate header / payload boundary at g_data_w boundary or at g_symbol_w
+  -- boundary with one empty symbol, by adapting the size of the header dp_bsn
+  -- field:
+  -- . If g_symbol_w = g_data_w then boundary is at g_data_w, so empty is 0.
+  -- . If g_symbol_w < g_data_w then boundary is at last symbol, so empty is 1.
+  CONSTANT c_nof_symbols_per_data     : NATURAL := g_data_w / g_symbol_w;
+  CONSTANT c_nof_symbols_per_bsn      : NATURAL := c_dp_stream_bsn_w / g_symbol_w;  -- = 64 / g_symbol_w
+  CONSTANT c_bsn_w                    : NATURAL := sel_a_b(c_nof_symbols_per_data = 1,
+                                                           g_symbol_w *  c_nof_symbols_per_bsn,
+                                                           g_symbol_w * (c_nof_symbols_per_bsn - 1));
+  CONSTANT c_use_shortened_header     : BOOLEAN := c_bsn_w <= c_word_w;
+
   -- dp_stream_stimuli
   CONSTANT c_stimuli_pulse_active     : NATURAL := 3;
   CONSTANT c_stimuli_pulse_period     : NATURAL := 4;
@@ -87,48 +117,53 @@ ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS
   CONSTANT c_sync_period              : NATURAL := 5;
   CONSTANT c_sync_offset              : NATURAL := 2;
   CONSTANT c_bsn_init                 : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := TO_DP_BSN(0);
+  CONSTANT c_nof_sync                 : NATURAL := 3;
+  CONSTANT c_nof_packets              : NATURAL := c_sync_period * c_nof_sync;
 
   CONSTANT c_hdr_len                  : NATURAL := 7;
-  CONSTANT c_wait_last_evt            : NATURAL := 100 + g_nof_repeat * c_hdr_len;
+  CONSTANT c_wait_last_evt            : NATURAL := 100 + c_nof_packets * c_hdr_len;
 
   -----------------------------------------------------------------------------
   -- Tx offload
   -----------------------------------------------------------------------------
   -- From apertif_udp_offload_pkg.vhd:
-  CONSTANT c_udp_offload_nof_hdr_fields : NATURAL := 3+12+4+3; -- 22, 448b; 7 64b words
-  CONSTANT c_udp_offload_nof_hdr_words  : NATURAL := 26;       -- 23 single word + 3 double word = 26 32b words
+  CONSTANT c_udp_offload_nof_hdr_fields          : NATURAL := 3+12+4+3; -- 22, 448b; 7 64b words
+  CONSTANT c_udp_offload_nof_hdr_words_default   : NATURAL := 26;       -- 23 single word + 3 double word = 26 32b words
+  CONSTANT c_udp_offload_nof_hdr_words_shortened : NATURAL := c_udp_offload_nof_hdr_words_default - 1;
+  CONSTANT c_udp_offload_nof_hdr_words           : NATURAL := sel_a_b(c_use_shortened_header, c_udp_offload_nof_hdr_words_shortened, c_udp_offload_nof_hdr_words_default);
+
   -- 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) := ( -- index
-         ( field_name_pad("eth_dst_mac"            ), "RW", 48, field_default(x"001B214368AC") ),         -- 21
-         ( field_name_pad("eth_src_mac"            ), "RW", 48, field_default(x"0123456789AB") ),         -- 20
-         ( field_name_pad("eth_type"               ), "RW", 16, field_default(x"0800") ),                 -- 19
-         ( field_name_pad("ip_version"             ), "RW",  4, field_default(4) ),                       -- 18
-         ( field_name_pad("ip_header_length"       ), "RW",  4, field_default(5) ),                       -- 17
-         ( field_name_pad("ip_services"            ), "RW",  8, field_default(0) ),                       -- 16
-         ( field_name_pad("ip_total_length"        ), "RW", 16, field_default(1450) ),                    -- 15
-         ( field_name_pad("ip_identification"      ), "RW", 16, field_default(0) ),                       -- 14
-         ( field_name_pad("ip_flags"               ), "RW",  3, field_default(2) ),                       -- 13
-         ( field_name_pad("ip_fragment_offset"     ), "RW", 13, field_default(0) ),                       -- 12
-         ( field_name_pad("ip_time_to_live"        ), "RW",  8, field_default(127) ),                     -- 11
-         ( field_name_pad("ip_protocol"            ), "RW",  8, field_default(17) ),                      -- 10
-         ( field_name_pad("ip_header_checksum"     ), "RW", 16, field_default(29928) ),                   -- 9
-         ( field_name_pad("ip_src_addr"            ), "RW", 32, field_default(x"C0A80009") ),             -- 8
-         ( field_name_pad("ip_dst_addr"            ), "RW", 32, field_default(x"C0A80001") ),             -- 7
-         ( field_name_pad("udp_src_port"           ), "RW", 16, field_default(0) ),                       -- 6
-         ( field_name_pad("udp_dst_port"           ), "RW", 16, field_default(0) ),                       -- 5
-         ( field_name_pad("udp_total_length"       ), "RW", 16, field_default(1430) ),                    -- 4
-         ( field_name_pad("udp_checksum"           ), "RW", 16, field_default(0) ),                       -- 3
-         ( field_name_pad("dp_reserved"            ), "RW", 47, field_default(x"010203040506") ),         -- 2
-         ( field_name_pad("dp_sync"                ), "RW",  1, field_default(0) ),                       -- 1
-         ( field_name_pad("dp_bsn"                 ), "RW", 64, field_default(0) ) );                     -- 0
+         ( field_name_pad("eth_dst_mac"            ), "RW",      48, field_default(x"001B214368AC") ),         -- 21
+         ( field_name_pad("eth_src_mac"            ), "RW",      48, field_default(x"0123456789AB") ),         -- 20
+         ( field_name_pad("eth_type"               ), "RW",      16, field_default(x"0800") ),                 -- 19
+         ( field_name_pad("ip_version"             ), "RW",       4, field_default(4) ),                       -- 18
+         ( field_name_pad("ip_header_length"       ), "RW",       4, field_default(5) ),                       -- 17
+         ( field_name_pad("ip_services"            ), "RW",       8, field_default(0) ),                       -- 16
+         ( field_name_pad("ip_total_length"        ), "RW",      16, field_default(1450) ),                    -- 15
+         ( field_name_pad("ip_identification"      ), "RW",      16, field_default(0) ),                       -- 14
+         ( field_name_pad("ip_flags"               ), "RW",       3, field_default(2) ),                       -- 13
+         ( field_name_pad("ip_fragment_offset"     ), "RW",      13, field_default(0) ),                       -- 12
+         ( field_name_pad("ip_time_to_live"        ), "RW",       8, field_default(127) ),                     -- 11
+         ( field_name_pad("ip_protocol"            ), "RW",       8, field_default(17) ),                      -- 10
+         ( field_name_pad("ip_header_checksum"     ), "RW",      16, field_default(29928) ),                   -- 9
+         ( field_name_pad("ip_src_addr"            ), "RW",      32, field_default(x"C0A80009") ),             -- 8
+         ( field_name_pad("ip_dst_addr"            ), "RW",      32, field_default(x"C0A80001") ),             -- 7
+         ( field_name_pad("udp_src_port"           ), "RW",      16, field_default(0) ),                       -- 6
+         ( field_name_pad("udp_dst_port"           ), "RW",      16, field_default(0) ),                       -- 5
+         ( field_name_pad("udp_total_length"       ), "RW",      16, field_default(1430) ),                    -- 4
+         ( field_name_pad("udp_checksum"           ), "RW",      16, field_default(0) ),                       -- 3
+         ( field_name_pad("dp_reserved"            ), "RW",      47, field_default(x"010203040506") ),         -- 2
+         ( field_name_pad("dp_sync"                ), "RW",       1, field_default(0) ),                       -- 1
+         ( field_name_pad("dp_bsn"                 ), "RW", c_bsn_w, field_default(0) ) );                     -- 0
 
   -- TX: Corresponding storage of c_udp_offload_hdr_field_arr in MM register words
   -- . Note: It appears that the tx_hdr_word read values are the MM write values, so read of value from logic fields (with MM override '0', e.g. dp_bsn, eth_src_mac) is not supported.
-  CONSTANT c_expected_tx_hdr_word_arr : t_slv_32_arr(0 TO c_udp_offload_nof_hdr_words-1) := ( -- word address
+  CONSTANT c_expected_tx_hdr_word_arr_default : t_slv_32_arr(0 TO c_udp_offload_nof_hdr_words_default-1) := ( -- word address
                                                                              X"00000000",     -- 0   = dp_bsn[31:0]        -- readback is MM value, not the logic value
-                                                                             X"00000000",     -- 1   = dp_bsn[63:32]
+                                                                             X"00000000",     -- 1   = dp_bsn[c_bsn_w-1:32]
                                                                              X"00000000",     -- 2   = dp_sync
                                                                              X"03040506",     -- 3   = dp_reserved[31:0]
                                                                              X"00000102",     -- 4   = dp_reserved[47:32]
@@ -154,11 +189,38 @@ ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS
                                                                              X"214368AC",     -- 24  = eth_dst_mac[31:0]
                                                                              X"0000001B");    -- 25  = eth_dst_mac[47:32]
 
+  CONSTANT c_expected_tx_hdr_word_arr_shortened : t_slv_32_arr(0 TO c_udp_offload_nof_hdr_words_shortened-1) := ( -- word address
+                                                                             X"00000000",     -- 0   = dp_bsn[31:0]        -- readback is MM value, not the logic value
+                                                                             X"00000000",     -- 1   = dp_sync
+                                                                             X"03040506",     -- 2   = dp_reserved[31:0]
+                                                                             X"00000102",     -- 3   = dp_reserved[47:32]
+                                                                             X"00000000",     -- 4   = udp_checksum
+                                                                             X"00000596",     -- 5   = udp_total_length
+                                                                             X"00000000",     -- 6   = udp_dst_port
+                                                                             X"00000000",     -- 7   = udp_src_port        -- readback is MM value, not the logic value
+                                                                             X"C0A80001",     -- 8   = ip_dst_addr
+                                                                             X"C0A80009",     -- 9   = ip_src_addr
+                                                                             X"000074E8",     -- 10  = ip_header_checksum
+                                                                             X"00000011",     -- 11  = ip_protocol
+                                                                             X"0000007F",     -- 12  = ip_time_to_live
+                                                                             X"00000000",     -- 13  = ip_fragment_offset
+                                                                             X"00000002",     -- 14  = ip_flags
+                                                                             X"00000000",     -- 15  = ip_identification
+                                                                             X"000005AA",     -- 16  = ip_total_length
+                                                                             X"00000000",     -- 17  = ip_services
+                                                                             X"00000005",     -- 18  = ip_header_length
+                                                                             X"00000004",     -- 19  = ip_version
+                                                                             X"00000800",     -- 20  = eth_type[15:0]
+                                                                             X"456789AB",     -- 21  = eth_src_mac[31:0]   -- readback is MM value, not the logic value
+                                                                             X"00000123",     -- 22  = eth_src_mac[47:32]
+                                                                             X"214368AC",     -- 23  = eth_dst_mac[31:0]
+                                                                             X"0000001B");    -- 24  = eth_dst_mac[47:32]
+
   -- RX: Corresponding storage of c_udp_offload_hdr_field_arr in MM register words
-  CONSTANT c_expected_rx_hdr_word_arr : t_slv_32_arr(0 TO c_udp_offload_nof_hdr_words-1) := ( -- word address
-                                                                             X"0000000B",     -- 0   = dp_bsn[31:0]        -- dynamic value obtained from simulation
-                                                                             X"00000000",     -- 1   = dp_bsn[63:32]
-                                                                             X"00000000",     -- 2   = dp_sync             -- dynamic value obtained from simulation
+  CONSTANT c_expected_rx_hdr_word_arr_default : t_slv_32_arr(0 TO c_udp_offload_nof_hdr_words_default-1) := ( -- word address
+                                                                             X"00000002",     -- 0   = dp_bsn[31:0]        -- dynamic value obtained from simulation
+                                                                             X"00000000",     -- 1   = dp_bsn[c_bsn_w-1:32]
+                                                                             X"00000001",     -- 2   = dp_sync             -- dynamic value obtained from simulation
                                                                              X"03040506",     -- 3   = dp_reserved[31:0]
                                                                              X"00000102",     -- 4   = dp_reserved[47:32]
                                                                              X"00000000",     -- 5   = udp_checksum
@@ -183,6 +245,33 @@ ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS
                                                                              X"214368AC",     -- 24  = eth_dst_mac[31:0]
                                                                              X"0000001B");    -- 25  = eth_dst_mac[47:32]
 
+  CONSTANT c_expected_rx_hdr_word_arr_shortened : t_slv_32_arr(0 TO c_udp_offload_nof_hdr_words_shortened-1) := ( -- word address
+                                                                             X"00000002",     -- 0   = dp_bsn[31:0]        -- dynamic value obtained from simulation
+                                                                             X"00000001",     -- 1   = dp_sync             -- dynamic value obtained from simulation
+                                                                             X"03040506",     -- 2   = dp_reserved[31:0]
+                                                                             X"00000102",     -- 3   = dp_reserved[47:32]
+                                                                             X"00000000",     -- 4   = udp_checksum
+                                                                             X"00000596",     -- 5   = udp_total_length
+                                                                             X"00000000",     -- 6   = udp_dst_port
+                                                                             X"00000000",     -- 7   = udp_src_port
+                                                                             X"C0A80001",     -- 8   = ip_dst_addr
+                                                                             X"C0A80009",     -- 9   = ip_src_addr
+                                                                             X"000074E8",     -- 10  = ip_header_checksum
+                                                                             X"00000011",     -- 11  = ip_protocol
+                                                                             X"0000007F",     -- 12  = ip_time_to_live
+                                                                             X"00000000",     -- 13  = ip_fragment_offset
+                                                                             X"00000002",     -- 14  = ip_flags
+                                                                             X"00000000",     -- 15  = ip_identification
+                                                                             X"000005AA",     -- 16  = ip_total_length
+                                                                             X"00000000",     -- 17  = ip_services
+                                                                             X"00000005",     -- 18  = ip_header_length
+                                                                             X"00000004",     -- 19  = ip_version
+                                                                             X"00000800",     -- 20  = eth_type[15:0]
+                                                                             X"86080000",     -- 21  = eth_src_mac[31:0]   -- readback is the logic value x"00228608" & id_backplane = 0 & id_chip = 0 (c_NODE_ID = 0)
+                                                                             X"00000022",     -- 22  = eth_src_mac[47:32]
+                                                                             X"214368AC",     -- 23  = eth_dst_mac[31:0]
+                                                                             X"0000001B");    -- 24  = eth_dst_mac[47:32]
+
   -- From apertif_unb1_fn_beamformer_udp_offload.vhd:                                           221   111111111000   0000   000
   -- Override ('1') only the Ethernet fields so we can use MM defaults there.                   109   876543210987   6543   210
   CONSTANT c_hdr_field_ovr_init : STD_LOGIC_VECTOR(c_udp_offload_nof_hdr_fields-1 DOWNTO 0) := "101"&"111111111111"&"1111"&"100";
@@ -250,6 +339,7 @@ ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS
   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);
+  SIGNAL prev_verify_snk_in_data    : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0);
 
 BEGIN
 
@@ -279,7 +369,7 @@ BEGIN
     g_bsn_init       => c_bsn_init,
     -- specific
     g_in_dat_w       => g_data_w,
-    g_nof_repeat     => g_nof_repeat,
+    g_nof_repeat     => c_nof_packets,
     g_pkt_len        => g_pkt_len,
     g_pkt_gap        => g_pkt_gap,
     g_wait_last_evt  => c_wait_last_evt
@@ -403,13 +493,13 @@ BEGIN
   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); 
+  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(c_bsn_w-1 DOWNTO 0);
 
   u_tx : ENTITY work.dp_offload_tx_v3
   GENERIC MAP (
     g_nof_streams    => 1,
     g_data_w         => g_data_w,
-    g_symbol_w       => g_data_w,
+    g_symbol_w       => g_symbol_w,
     g_hdr_field_arr  => c_udp_offload_hdr_field_arr,
     g_hdr_field_sel  => c_hdr_field_ovr_init
   ) 
@@ -438,20 +528,23 @@ BEGIN
     VARIABLE v_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   BEGIN
     proc_common_wait_until_hi_lo(dp_clk, tx_offload_sosi_arr(0).sync);
-    proc_common_wait_until_hi_lo(dp_clk, tx_offload_sosi_arr(0).sync);
-    print_str("");
+    print_str("", g_print_en);
     FOR I IN 0 TO c_udp_offload_nof_hdr_words-1 LOOP
       proc_mem_mm_bus_rd(I, mm_clk, reg_dp_offload_tx_hdr_dat_mosi);
       proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
       v_word := reg_dp_offload_tx_hdr_dat_miso.rddata(31 DOWNTO 0);
       -- Log word in transcript window
-      print_str("tx_hdr_word(" & int_to_str(I) & ") = " & slv_to_hex(v_word));
+      print_str("tx_hdr_word(" & int_to_str(I) & ") = " & slv_to_hex(v_word), g_print_en);
       -- View word in wave window
       tx_hdr_word <= v_word;
       -- Verify expected word
-      ASSERT c_expected_tx_hdr_word_arr(I) = v_word REPORT "Unexpected tx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_tx_hdr_word_arr(I)) SEVERITY ERROR;
+      IF c_use_shortened_header THEN
+        ASSERT c_expected_tx_hdr_word_arr_shortened(I) = v_word REPORT "Unexpected tx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_tx_hdr_word_arr_shortened(I)) SEVERITY ERROR;
+      ELSE
+        ASSERT c_expected_tx_hdr_word_arr_default(I) = v_word REPORT "Unexpected tx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_tx_hdr_word_arr_default(I)) SEVERITY ERROR;
+      END IF;
     END LOOP;
-    print_str("");
+    print_str("", g_print_en);
     WAIT;
   END PROCESS;
 
@@ -481,6 +574,7 @@ BEGIN
   GENERIC MAP (
     g_nof_streams         => 1,
     g_data_w              => g_data_w,
+    g_symbol_w            => g_symbol_w,
     g_hdr_field_arr       => c_udp_offload_hdr_field_arr,
     g_remove_crc          => FALSE,
     g_crc_nof_words       => 0 
@@ -520,24 +614,69 @@ BEGIN
     VARIABLE v_word : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   BEGIN
     proc_common_wait_until_hi_lo(dp_clk, verify_snk_in.sync);
-    proc_common_wait_until_hi_lo(dp_clk, verify_snk_in.sync);
-    proc_common_wait_until_hi_lo(dp_clk, verify_snk_in.sync);
-    print_str("");
+    -- Check first packet after sync with dp_sync = 1
+    -- wait some latency until header fields of this sync packet are available via MM
+    proc_common_wait_some_cycles(dp_clk, 10);
+    print_str("", g_print_en);
     FOR I IN 0 TO c_udp_offload_nof_hdr_words-1 LOOP
       proc_mem_mm_bus_rd(I, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
       proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
       v_word := reg_dp_offload_rx_hdr_dat_miso.rddata(31 DOWNTO 0);
       -- Log word in transcript window
-      print_str("rx_hdr_word(" & int_to_str(I) & ") : " & slv_to_hex(v_word));
+      print_str("rx_hdr_word(" & int_to_str(I) & ") : " & slv_to_hex(v_word), g_print_en);
       -- View word in wave window
       rx_hdr_word <= v_word;
       -- Verify expected word
-      ASSERT c_expected_rx_hdr_word_arr(I) = v_word REPORT "Unexpected rx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_rx_hdr_word_arr(I)) SEVERITY ERROR;
+      IF c_use_shortened_header THEN
+        ASSERT v_word = c_expected_rx_hdr_word_arr_shortened(I) REPORT "Unexpected rx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_rx_hdr_word_arr_shortened(I)) SEVERITY ERROR;
+      ELSE
+        ASSERT v_word = c_expected_rx_hdr_word_arr_default(I) REPORT "Unexpected rx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_rx_hdr_word_arr_default(I)) SEVERITY ERROR;
+      END IF;
     END LOOP;
-    print_str("");
+    print_str("", g_print_en);
+
+    -- Check dp_bsn and dp_sync of second packet after sync with dp_sync = 0
+    proc_common_wait_until_hi_lo(dp_clk, verify_snk_in.sop);
+    -- wait some latency until header fields of this sync packet are available via MM
+    proc_common_wait_some_cycles(dp_clk, 10);
+    -- dp_bsn lo
+    proc_mem_mm_bus_rd(0, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
+    proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
+    v_word := reg_dp_offload_rx_hdr_dat_miso.rddata(31 DOWNTO 0);
+    rx_hdr_word <= v_word;  -- View word in wave window
+    IF c_use_shortened_header THEN
+      ASSERT v_word = INCR_UVEC(c_expected_rx_hdr_word_arr_shortened(0), 1) REPORT "Unexpected dp_bsn from MM" SEVERITY ERROR;
+    ELSE
+      ASSERT v_word = INCR_UVEC(c_expected_rx_hdr_word_arr_default(0), 1) REPORT "Unexpected dp_bsn from MM" SEVERITY ERROR;
+    END IF;
+    -- dp_sync
+    IF c_use_shortened_header THEN
+      proc_mem_mm_bus_rd(1, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
+    ELSE
+      proc_mem_mm_bus_rd(2, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
+    END IF;
+    proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
+    v_word := reg_dp_offload_rx_hdr_dat_miso.rddata(31 DOWNTO 0);
+    rx_hdr_word <= v_word;  -- View word in wave window
+    ASSERT v_word = TO_UVEC(0, 32) REPORT "Unexpected dp_sync from MM" SEVERITY ERROR;
+
     WAIT;
   END PROCESS;
 
+  p_verify_snk_in_data : PROCESS
+  BEGIN
+    -- Note: This verification overlaps with u_dp_stream_verify because that also verifies incrementing valid data.
+    WAIT UNTIL rising_edge(dp_clk);
+    prev_verify_snk_in_data <= verify_snk_in.data(g_data_w-1 DOWNTO 0);
+    IF verify_snk_in.sop = '1' THEN
+      ASSERT TO_UINT(verify_snk_in.data) MOD g_pkt_len = 0 REPORT "Wrong decoded data at sop." SEVERITY ERROR;
+    ELSIF verify_snk_in.eop = '1' THEN
+      ASSERT TO_UINT(verify_snk_in.data) MOD g_pkt_len = g_pkt_len - 1 REPORT "Wrong decoded data at eop." SEVERITY ERROR;
+    ELSIF verify_snk_in.valid = '1' THEN
+      ASSERT TO_UINT(verify_snk_in.data) = TO_UINT(prev_verify_snk_in_data) + 1 REPORT "Wrong decoded data at valid." SEVERITY ERROR;
+    END IF;
+  END PROCESS;
+
 
   ------------------------------------------------------------------------------
   -- Auxiliary
diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_offload_tx_v3.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_offload_tx_v3.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..f55d74d6584f394a5bbe5326a81c6eafd0abb84e
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_offload_tx_v3.vhd
@@ -0,0 +1,60 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2021
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+-- --------------------------------------------------------------------------
+--
+-- Author: E. Kooistra, Jan 2022
+-- Purpose: Regression multi tb for dp_offload_tx_v3 and dp_offload_rx
+-- Description:
+-- Usage:
+-- > as 5
+-- > run -all
+
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE work.tb_dp_pkg.ALL;   -- for t_dp_flow_control_enum
+
+ENTITY tb_tb_dp_offload_tx_v3 IS
+END tb_tb_dp_offload_tx_v3;
+
+
+ARCHITECTURE tb OF tb_tb_dp_offload_tx_v3 IS
+
+  SIGNAL tb_end : STD_LOGIC := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+
+BEGIN
+
+  -- -- general
+  -- g_flow_control_stimuli   : t_dp_flow_control_enum := e_pulse;  -- 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
+  -- g_print_en               : BOOLEAN := TRUE;
+  -- -- specific
+  -- g_data_w                 : NATURAL := 64;
+  -- g_symbol_w               : NATURAL := 16;
+  -- g_pkt_len                : NATURAL := 240;
+  -- g_pkt_gap                : NATURAL := 16
+
+  u_pls_act_data_w_64            : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_pulse,  e_active, FALSE, 64, 64, 240, 16);
+  u_pls_act_data_w_64_no_gap     : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_pulse,  e_active, FALSE, 64, 64, 240,  0);
+  u_rnd_act_data_w_64            : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_random, e_active, FALSE, 64, 64, 240, 16);
+  u_rnd_act_data_w_32            : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_random, e_active, FALSE, 32, 32, 240, 16);
+  --u_act_rnd_data_w               : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_active, e_random, FALSE, 64, 64, 240, 16);
+  u_rnd_act_data_64_symbol_16    : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_random, e_active, FALSE, 64, 16, 240, 16);
+  u_rnd_act_data_64_symbol_32    : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_random, e_active, FALSE, 64, 32, 240, 16);
+  u_rnd_act_data_32_symbol_8     : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_random, e_active, FALSE, 32,  8, 240, 16);
+  u_rnd_act_data_32_symbol_16    : ENTITY work.tb_dp_offload_tx_v3 GENERIC MAP (e_random, e_active, FALSE, 32, 16, 240, 16);
+
+END tb;