diff --git a/libraries/base/reorder/src/vhdl/reorder_pkg.vhd b/libraries/base/reorder/src/vhdl/reorder_pkg.vhd
index fb72f9233ac99fea559c3f26ce8f6b38e14efcf4..71439a5142d0f2f0115a1843362c391411e076cd 100644
--- a/libraries/base/reorder/src/vhdl/reorder_pkg.vhd
+++ b/libraries/base/reorder/src/vhdl/reorder_pkg.vhd
@@ -82,21 +82,54 @@ package reorder_pkg is
   -----------------------------------------------------------------------------
 
   -- Block and data counters to derive select_copi.address for transpose
-  -- reording between nof_blocks_per_packet and nof_data_per_block.
+  -- reordering between nof_blocks_per_packet and nof_data_per_block.
+  -- Optionally the data can consist of multiple words at consecutive
+  -- addresses. If data is one word, then word_cnt record field is not used.
   type t_reorder_transpose is record
     select_copi : t_mem_copi;
     addr        : natural;
     blk_cnt     : natural;
-    data_cnt    : natural;
+    blk_offset  : natural;
+    dat_cnt     : natural;
+    dat_offset  : natural;
+    word_cnt    : natural;
   end record;
 
-  constant c_reorder_transpose_rst : t_reorder_transpose := (c_mem_copi_rst, 0, 0, 0);
+  constant c_reorder_transpose_rst : t_reorder_transpose := (c_mem_copi_rst, 0, 0, 0, 0, 0, 0);
 
   -- Input packet has nof_ch = nof_data_per_block * nof_blocks_per_packet of
-  -- data per packet.
-  -- The transpose.select_copi.address order will yield transposed output,
-  -- with nof_blocks_per_packet data per block, and with nof_data_per_block
-  -- number of blocks per packet.
+  -- data per packet. The order of the words per nof_words_per_data is
+  -- preserved.
+
+  -- Transpose functions that operate on list of data indices
+  function func_reorder_transpose_indices(nof_blocks_per_packet : natural;
+                                          nof_data_per_block    : natural;
+                                          nof_words_per_data    : natural) return t_natural_arr;
+
+  function func_reorder_transpose_indices_impl(nof_blocks_per_packet : natural;
+                                               nof_data_per_block    : natural;
+                                               nof_words_per_data    : natural) return t_natural_arr;
+
+  -- Transpose functions that operate sequentially to determine the read
+  -- transpose.select_copi.address
+  -- . The transpose.select_copi.address order will yield transposed output,
+  --   with nof_blocks_per_packet data per block, and with nof_data_per_block
+  --   number of blocks per packet.
+  function func_reorder_transpose(nof_blocks_per_packet : natural;
+                                  nof_data_per_block    : natural;
+                                  nof_words_per_data    : natural;
+                                  transpose             : t_reorder_transpose)
+                                  return t_reorder_transpose;
+
+  -- Alternative implementation using a look up list:
+  -- func_reorder_transpose_look_up() = func_reorder_transpose()
+  function func_reorder_transpose_look_up(nof_blocks_per_packet : natural;
+                                          nof_data_per_block    : natural;
+                                          nof_words_per_data    : natural;
+                                          transpose             : t_reorder_transpose)
+                                          return t_reorder_transpose;
+
+  -- Variant with nof_words_per_data = 1
   function func_reorder_transpose(nof_blocks_per_packet : natural;
                                   nof_data_per_block    : natural;
                                   transpose             : t_reorder_transpose)
@@ -116,6 +149,8 @@ package reorder_pkg is
 
   constant c_reorder_identity_rst : t_reorder_identity := (c_mem_copi_rst, 0);
 
+  -- Identity function that operates sequentially to determine the read
+  -- identity.select_copi.address, which is an incrementing address range.
   function func_reorder_identity(nof_ch_per_packet : natural;
                                  identity          : t_reorder_identity)
                                  return t_reorder_identity;
@@ -124,15 +159,99 @@ end reorder_pkg;
 
 package body reorder_pkg is
 
+  -- Determine transpose index for input packet_index
+  -- . Similar function as func_sdp_bdo_transpose_packet() in tb_sdp_pkg.vhd.
+  -- . The transpose is between nof_blocks_per_packet and nof_data_per_block.
+  --   Doing transpose again with swapped nof_blocks_per_packet and
+  --   nof_data_per_block, yields original order.
+  -- . The order of the words per nof_words_per_data is preserved.
+  -- Example for:
+  --   . blk in range(nof_blocks_per_packet = 4)
+  --   . dat in range(nof_data_per_block = 488)
+  --   . wi in range(nof_words_per_data = 2)
+  --   input packet_index v_in:
+  --   . blk             0,            1,            2,            3
+  --   . dat    0, ... 487, 0,   ... 487, 0,   ... 487, 0,   ... 487
+  --   . wi   0,1, ... 0,1, 0,1, ... 0,1, 0,1, ... 0,1, 0,1, ... 0,1
+  --   . v_in   0, ... 975, 976, ...1951,1952, ...2927,2928, ...3903
+  --   return index v_out:
+  --   . wi                         0,1,0,1,0,1,0,1, ..., 0,1,0,1,0,1,0,1
+  --   . blk                          0,  1,  2,  3, ...,   0,  1,  2,  3
+  --   . dat                                      0, ...,             487
+  --   . v_out 0,1,  976, 977, 1952,1953, 2928,2929,
+  --           2,3,  978, 979, 1954,1955, 2930,2931,
+  --           ...,       ...,       ...,       ...,
+  --       972,973, 1948,1949, 2924,2925, 3900,3901,
+  --       974,775, 1950,1951, 2926,2927, 3902,3903
+  function func_reorder_transpose_indices(nof_blocks_per_packet : natural;
+                                          nof_data_per_block    : natural;
+                                          nof_words_per_data    : natural) return t_natural_arr is
+    constant c_nof_ch  : natural := nof_blocks_per_packet * nof_data_per_block * nof_words_per_data;
+    variable v_arr     : t_natural_arr(0 to c_nof_ch - 1);
+    variable v_in      : natural;
+    variable v_out     : natural;
+    variable v_ch      : natural := 0;
+  begin
+    -- Use outer loop blk and inner loop dat to have v_in = v_ch.
+    -- Use outer loop dat and inner loop blk to have v_out = v_ch.
+    -- For the return v_arr it does not matter which loop is the outer loop
+    -- or the inner loop. Choose to have v_out = v_ch, because then the
+    -- values in v_arr are calculated in output order, similar as if they
+    -- are output sequentially by reorder_col_select.
+    for dat in 0 to nof_data_per_block - 1 loop
+      for blk in 0 to nof_blocks_per_packet - 1 loop
+        for wi in 0 to nof_words_per_data - 1 loop
+          -- v_out is the transpose index for index v_in, so output value at
+          -- index v_out becomes input value at index v_in
+          v_in := (blk * nof_data_per_block + dat) * nof_words_per_data + wi;
+          v_out := (dat * nof_blocks_per_packet + blk) * nof_words_per_data + wi;
+          assert v_out = v_ch report "Wrong index in func_reorder_transpose_indices()" severity failure;
+          v_arr(v_out) := v_in;
+          v_ch := v_ch + 1;
+        end loop;
+      end loop;
+    end loop;
+    return v_arr;
+  end;
+
+  -- The func_reorder_transpose_indices_impl() yields the same as
+  -- func_reorder_transpose_indices(), except that it uses only
+  -- additions to calculate the indices, so no multiplications in
+  -- the loops.
+  function func_reorder_transpose_indices_impl(nof_blocks_per_packet : natural;
+                                               nof_data_per_block    : natural;
+                                               nof_words_per_data    : natural) return t_natural_arr is
+    constant c_nof_ch              : natural := nof_blocks_per_packet * nof_data_per_block * nof_words_per_data;
+    constant c_nof_words_per_block : natural := nof_words_per_data * nof_data_per_block;
+    variable v_blk_offset  : natural := 0;
+    variable v_dat_offset  : natural := 0;
+    variable v_arr     : t_natural_arr(0 to c_nof_ch - 1);
+    variable v_ch      : natural := 0;
+  begin
+    for dat in 0 to nof_data_per_block - 1 loop
+      for blk in 0 to nof_blocks_per_packet - 1 loop
+        for wi in 0 to nof_words_per_data - 1 loop
+          v_arr(v_ch) := v_blk_offset + v_dat_offset + wi;
+          v_ch := v_ch + 1;
+        end loop;
+        v_blk_offset := v_blk_offset + c_nof_words_per_block;
+      end loop;
+      v_blk_offset := 0;
+      v_dat_offset := v_dat_offset + nof_words_per_data;
+    end loop;
+    return v_arr;
+  end;
+
   -- A transpose process and an undo transpose process can both use
   -- func_reorder_transpose(), by swapping the transpose dimensions.
   -- For example, to get transposed output with:
   -- . g_nof_blocks_per_packet = 3 and
   -- . g_nof_data_per_block = 5
+  -- . g_nof_words_per_data = 1
   -- the p_comb_transpose selects:
   --
   --   v.blk_cnt:      0              1              2
-  --   v.data_cnt:     0  1  2  3  4  0  1  2  3  4  0  1  2  3  4
+  --   v.dat_cnt:      0  1  2  3  4  0  1  2  3  4  0  1  2  3  4
   --   ch:             0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
   --   data_in         0  1  2  3  4  5  6  7  8  9 10 11 12 13 14  -- in_sosi
   --   transpose:      0        3        6        9       12
@@ -148,7 +267,7 @@ package body reorder_pkg is
   -- the p_comb_undo_transpose selects:
   --
   --   v.blk_cnt:      0        1        2        3        4
-  --   v.data_cnt:     0  1  2  0  1  2  0  1  2  0  1  2  0  1  2
+  --   v.dat_cnt:      0  1  2  0  1  2  0  1  2  0  1  2  0  1  2
   --   ch:             0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
   --   data_in         0  3  6  9 12  1  4  7 10 13  2  5  8 11 14  -- transposed_sosi
   --   undo_transpose: 0              1              2
@@ -162,45 +281,102 @@ package body reorder_pkg is
   -- to restore the original order.
   function func_reorder_transpose(nof_blocks_per_packet : natural;
                                   nof_data_per_block    : natural;
+                                  nof_words_per_data    : natural;
                                   transpose             : t_reorder_transpose)
                                   return t_reorder_transpose is
+    constant c_nof_words_per_block : natural := nof_words_per_data * nof_data_per_block;
+
     variable v : t_reorder_transpose;
   begin
+    -- Implementation derived from func_reorder_transpose_indices_impl().
+    -- Instead of using incrementing v_ch and for-loops to return list of all
+    -- read indices, use sequential calls of this func_reorder_transpose()
+    -- to return next read address.
     v := transpose;
-    -- read at current address
+    -- Read at current address
     v.select_copi.address := TO_MEM_ADDRESS(v.addr);
     v.select_copi.rd := '1';
-    -- prepare next read address
-    if v.blk_cnt <= nof_blocks_per_packet - 1 then
-      if v.data_cnt < nof_data_per_block - 1 then
-        v.data_cnt := v.data_cnt + 1;
-        v.addr := v.addr + nof_blocks_per_packet;
-      else
-        v.data_cnt := 0;
+    -- Prepare next read address
+    -- . loop word_cnt
+    if v.word_cnt < nof_words_per_data - 1 then
+      v.word_cnt := v.word_cnt + 1;
+    else
+      -- . end loop word_cnt
+      v.word_cnt := 0;
+      -- . loop blk_cnt
+      if v.blk_cnt < nof_blocks_per_packet - 1 then
         v.blk_cnt := v.blk_cnt + 1;
-        if v.blk_cnt = nof_blocks_per_packet then
-          v.blk_cnt := 0;
+        v.blk_offset := v.blk_offset + c_nof_words_per_block;
+      else
+        -- . end loop blk_cnt
+        v.blk_cnt := 0;
+        v.blk_offset := 0;
+        -- . loop dat_cnt
+        if v.dat_cnt < nof_data_per_block - 1 then
+          v.dat_cnt := v.dat_cnt + 1;
+          v.dat_offset := v.dat_offset + nof_words_per_data;
+        else
+          -- . end loop dat_cnt
+          v.dat_cnt := 0;
+          v.dat_offset := 0;
         end if;
-        v.addr := v.blk_cnt;
       end if;
+    end if;
+    v.addr := v.blk_offset + v.dat_offset + v.word_cnt;
+    return v;
+  end;
+
+  function func_reorder_transpose_look_up(nof_blocks_per_packet : natural;
+                                          nof_data_per_block    : natural;
+                                          nof_words_per_data    : natural;
+                                          transpose             : t_reorder_transpose)
+                                          return t_reorder_transpose is
+    constant c_nof_ch       : natural := nof_blocks_per_packet * nof_data_per_block * nof_words_per_data;
+    constant c_look_up_list : t_natural_arr(0 to c_nof_ch - 1) :=
+      func_reorder_transpose_indices(nof_blocks_per_packet,
+                                     nof_data_per_block,
+                                     nof_words_per_data);
+    variable v : t_reorder_transpose;
+  begin
+    -- Equivalent implementation, so func_reorder_transpose_look_up() =
+    -- func_reorder_transpose()
+    v := transpose;
+    -- Read at current address
+    v.select_copi.address := TO_MEM_ADDRESS(v.addr);
+    v.select_copi.rd := '1';
+    -- Prepare next read address
+    -- . use word_cnt as incrementing ch index to count the sequential calls
+    --   of this func_reorder_transpose() to return next read address
+    if v.word_cnt < c_nof_ch - 1 then
+      v.word_cnt := v.word_cnt + 1;
     else
-      v.data_cnt := 0;
-      v.blk_cnt := 0;
-      v.addr := 0;
+      v.word_cnt := 0;
     end if;
+    v.addr := c_look_up_list(v.word_cnt);
     return v;
   end;
 
+  function func_reorder_transpose(nof_blocks_per_packet : natural;
+                                  nof_data_per_block    : natural;
+                                  transpose             : t_reorder_transpose)
+                                  return t_reorder_transpose is
+  begin
+    return func_reorder_transpose(nof_blocks_per_packet,
+                                  nof_data_per_block,
+                                  1,
+                                  transpose);
+  end;
+
   function func_reorder_identity(nof_ch_per_packet : natural;
                                  identity          : t_reorder_identity)
                                  return t_reorder_identity is
     variable v : t_reorder_identity;
   begin
     v := identity;
-    -- read at current address
+    -- Read at current address
     v.select_copi.address := TO_MEM_ADDRESS(v.addr);
     v.select_copi.rd := '1';
-     -- prepare next read address
+    -- Prepare next read address
     if v.addr < nof_ch_per_packet - 1 then
       v.addr := v.addr + 1;
     else
diff --git a/libraries/base/reorder/tb/vhdl/reorder_pkg_test.vhd b/libraries/base/reorder/tb/vhdl/reorder_pkg_test.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..a51252e77b80678d1466155eadf409a303bd5755
--- /dev/null
+++ b/libraries/base/reorder/tb/vhdl/reorder_pkg_test.vhd
@@ -0,0 +1,124 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- 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
+-- Purpose:
+--   Test bench to verify functions in reorder_pkg.vhd.
+-- Description:
+--
+-- Usage:
+-- > as 3
+-- > run -all
+-- * The tb is self stopping and self checking, tb_end will stop the simulation
+--   by stopping the clk and thus all toggling.
+
+library IEEE, common_lib, dp_lib;
+use IEEE.std_logic_1164.all;
+use common_lib.common_pkg.all;
+use common_lib.common_mem_pkg.all;
+use common_lib.tb_common_pkg.all;
+use dp_lib.dp_stream_pkg.all;
+use work.reorder_pkg.all;
+
+entity reorder_pkg_test is
+  generic(
+    g_nof_blocks_per_packet : natural := 4;
+    g_nof_data_per_block    : natural := 488;
+    g_nof_words_per_data    : natural := 1
+  );
+end reorder_pkg_test;
+
+
+architecture tb of reorder_pkg_test is
+
+  constant c_clk_period   : time := 10 ns;
+  constant c_nof_data     : natural := g_nof_blocks_per_packet * g_nof_data_per_block;
+
+  signal rst              : std_logic;
+  signal clk              : std_logic := '1';
+  signal tb_end           : std_logic := '0';
+
+  -- Verify default and alternative (lu = look up) implementation of r_transpose
+  signal r_transpose      : t_reorder_transpose := c_reorder_transpose_rst;
+  signal r_transpose_lu   : t_reorder_transpose := c_reorder_transpose_rst;
+  signal in_address       : natural := 0;
+  signal in_val           : std_logic := '0';
+  signal out_address      : natural;
+  signal out_address_lu   : natural;
+  signal out_val          : std_logic;
+  signal exp_address      : natural;
+
+  constant c_exp_addresses_arr : t_natural_arr := func_reorder_transpose_indices(g_nof_blocks_per_packet,
+                                                                                 g_nof_data_per_block,
+                                                                                 g_nof_words_per_data);
+
+  constant c_impl_addresses_arr : t_natural_arr := func_reorder_transpose_indices_impl(g_nof_blocks_per_packet,
+                                                                                       g_nof_data_per_block,
+                                                                                       g_nof_words_per_data);
+begin
+
+  assert c_exp_addresses_arr = c_impl_addresses_arr report "Wrong func_reorder_transpose_indices_impl()" severity failure;
+
+  clk <= (not clk) or tb_end after c_clk_period / 2;
+  rst <= '1', '0' after c_clk_period * 7;
+
+  p_stimuli : process
+  begin
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 5);
+
+    for I in 0 to c_nof_data - 1 loop
+      in_val <= '1';
+      in_address <= I;
+      r_transpose    <= func_reorder_transpose(
+        g_nof_blocks_per_packet, g_nof_data_per_block, g_nof_words_per_data, r_transpose);
+      r_transpose_lu <= func_reorder_transpose_look_up(
+        g_nof_blocks_per_packet, g_nof_data_per_block, g_nof_words_per_data, r_transpose_lu);
+      proc_common_wait_some_cycles(clk, 1);
+    end loop;
+    in_val <= '0';
+    r_transpose <= c_reorder_transpose_rst;
+    r_transpose_lu <= c_reorder_transpose_rst;
+
+    proc_common_wait_some_cycles(clk, 5);
+    tb_end <= '1';
+    wait;
+  end process;
+
+  out_address    <= TO_UINT(r_transpose.select_copi.address);
+  out_address_lu <= TO_UINT(r_transpose_lu.select_copi.address);
+  out_val        <= r_transpose.select_copi.rd;
+
+  exp_address <= c_exp_addresses_arr(in_address);
+
+  p_verify : process(clk)
+  begin
+    if rising_edge(clk) then
+      if in_val = '1' then
+        -- Only when valid expect that out_address = exp_address
+        assert out_address = exp_address report "Wrong transpose address" severity error;
+      end if;
+      -- Always expect that out_address_lu = out_address
+      assert out_address_lu = out_address report "Wrong transpose_lu address" severity error;
+    end if;
+  end process;
+
+end tb;
diff --git a/libraries/base/reorder/tb/vhdl/reorder_pkg_test_test.vhd b/libraries/base/reorder/tb/vhdl/reorder_pkg_test_test.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..e8aeb6583dcaa90dcc28494017ed232d43aae2f7
--- /dev/null
+++ b/libraries/base/reorder/tb/vhdl/reorder_pkg_test_test.vhd
@@ -0,0 +1,53 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- 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
+-- Purpose:
+--   Multi test bench to verify functions in reorder_pkg.vhd using instances
+--   of reorder_pkg_test.vhd.
+-- Description:
+--
+-- Usage:
+-- > as 3
+-- > run -all
+-- * The tb is self stopping and self checking, tb_end will stop the simulation
+--   by stopping the clk and thus all toggling.
+library IEEE;
+use IEEE.std_logic_1164.all;
+
+
+entity reorder_pkg_test_test is
+end reorder_pkg_test_test;
+
+
+architecture tb of reorder_pkg_test_test is
+
+  signal tb_end : std_logic := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+
+begin
+  -- g_nof_blocks_per_packet : natural := 4;
+  -- g_nof_data_per_block    : natural := 488;
+  -- g_nof_words_per_data    : natural := 1
+
+  u_4_488_1  : entity work.reorder_pkg_test generic map (4, 488, 1);
+  u_4_488_2  : entity work.reorder_pkg_test generic map (4, 488, 2);
+
+end tb;