diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index 3385ef085294734990746f48cb90267228449553..6e9f06dc39d1fc5fd18a50b36888de444246b87c 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -124,6 +124,9 @@ synth_files =
     src/vhdl/dp_src_out_timer.vhd
     src/vhdl/dp_sync_checker.vhd
     src/vhdl/mms_dp_sync_checker.vhd
+    src/vhdl/dp_folder.vhd
+    src/vhdl/dp_unfolder.vhd
+    src/vhdl/dp_switch.vhd
     tb/vhdl/dp_stream_player.vhd
     tb/vhdl/dp_sosi_recorder.vhd
     tb/vhdl/dp_stream_rec_play.vhd
@@ -187,7 +190,10 @@ test_bench_files =
     tb/vhdl/tb_dp_xonoff.vhd
     tb/vhdl/tb_mms_dp_xonoff.vhd
     tb/vhdl/tb_dp_sync_insert.vhd
-    
+    tb/vhdl/tb_dp_folder.vhd
+    tb/vhdl/tb_dp_switch.vhd
+
+
     tb/vhdl/tb_tb_dp_block_gen.vhd
     tb/vhdl/tb_tb_dp_bsn_align.vhd
     tb/vhdl/tb_tb_dp_concat.vhd
diff --git a/libraries/base/dp/src/vhdl/dp_folder.vhd b/libraries/base/dp/src/vhdl/dp_folder.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..98e6895f1bb42fba81f3537ee318502686c47278
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_folder.vhd
@@ -0,0 +1,238 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- 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/>.
+--
+--------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+
+-- Author:
+-- . Daniel van der Schuur
+-- Purpose:
+-- . Fold n input streams into n/2, n/2/2, n/2/2/2, .. output streams
+-- Description:
+-- . This component assumes the user has scheduled the input streams properly.
+--   . Input data that is to be folded onto one stream must not be valid at the same clock cycle
+-- . nof_outputs = ceil_div(g_nof_inputs, 2^(g_nof_folds)) for g_nof_folds>=0
+--   . Examples:
+--     . g_nof_inputs=10, g_nof_folds=0 -> nof_outputs=10
+--     . g_nof_inputs=10, g_nof_folds=1 -> nof_outputs= 5
+--     . g_nof_inputs=10, g_nof_folds=2 -> nof_outputs= 3
+--     . g_nof_inputs=10, g_nof_folds=3 -> nof_outputs= 2
+--     . g_nof_inputs=10, g_nof_folds=4 -> nof_outputs= 1
+--     . g_nof_inputs=10, g_nof_folds<0 -> nof_outputs= 1
+-- . This entity recursively instantiates (registered) stages of itself when folding streams multiple times.
+
+ENTITY dp_folder IS
+  GENERIC (
+    g_nof_inputs        : NATURAL;         -- Number of inputs to fold >0
+    g_nof_folds         : INTEGER := -1;   -- >0: Number of folds; 0: Wire out to in; <0: Fold until one output remains
+    g_output_block_size : NATURAL := 0;    -- >0: Create SOP/EOP tagged output blocks of this size. 0: Forward incoming SOP,EOP.
+    g_fwd_sync_bsn      : BOOLEAN := FALSE -- TRUE: forwards (stored) input Sync+BSN (from snk_in_arr(0)) to all output streams
+  );
+  PORT (
+    clk            : IN  STD_LOGIC;
+    rst            : IN  STD_LOGIC;
+
+    snk_in_arr     : IN  t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
+    src_out_arr    : OUT t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0)
+  );
+END dp_folder;
+
+ARCHITECTURE str OF dp_folder IS
+
+  COMPONENT dp_folder IS
+    GENERIC (
+      g_nof_inputs        : NATURAL;
+      g_nof_folds         : INTEGER := -1;
+      g_output_block_size : NATURAL := 0;   
+      g_fwd_sync_bsn      : BOOLEAN := FALSE
+    ); 
+    PORT (
+      rst            : IN  STD_LOGIC;
+      clk            : IN  STD_LOGIC;
+  
+      snk_in_arr     : IN  t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
+  
+      src_out_arr    : OUT t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0)
+    );
+  END COMPONENT;
+
+  CONSTANT c_nof_muxes : NATURAL := ceil_div(g_nof_inputs, 2);  -- Using ceil_div always yields an even number of mux inputs
+
+  SIGNAL mux_snk_in_arr      : t_dp_sosi_arr(2*c_nof_muxes-1 DOWNTO 0);
+  SIGNAL mux_snk_in_2arr_2   : t_dp_sosi_2arr_2(c_nof_muxes-1 DOWNTO 0);
+
+  SIGNAL mux_src_out_arr     : t_dp_sosi_arr(c_nof_muxes-1 DOWNTO 0);
+  SIGNAL nxt_mux_src_out_arr : t_dp_sosi_arr(c_nof_muxes-1 DOWNTO 0);
+
+  SIGNAL dp_folder_src_out_arr    : t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0);
+
+  SIGNAL dp_block_gen_snk_in_arr  : t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0);
+  SIGNAL dp_block_gen_src_out_arr : t_dp_sosi_arr(sel_a_b(g_nof_folds>=0, ceil_div(g_nof_inputs, ceil_pow2(g_nof_folds)), 1)-1 DOWNTO 0);
+
+BEGIN
+
+  gen_arch: IF g_nof_folds/=0 GENERATE
+    -----------------------------------------------------------------------------
+    -- Wire input array to mux_snk_in_arr to make sure we have an even number
+    -- of buses to work with in case of an odd number of inputs
+    -- . We want an even number of buses because we will wire up 2-input muxes
+    -----------------------------------------------------------------------------
+    gen_even_nof_buses: FOR i IN 0 TO g_nof_inputs-1 GENERATE   
+      mux_snk_in_arr(i) <= snk_in_arr(i);
+    END GENERATE;
+  
+    -----------------------------------------------------------------------------
+    -- Wire inputs to the 2-input muxes
+    -----------------------------------------------------------------------------
+    gen_mux_inputs_0: FOR i IN 0 TO c_nof_muxes-1 GENERATE
+      mux_snk_in_2arr_2(i)(0) <= mux_snk_in_arr(2*i);
+      mux_snk_in_2arr_2(i)(1) <= mux_snk_in_arr(2*i+1);
+    END GENERATE;
+  
+    -----------------------------------------------------------------------------
+    -- Simple 2-input mux logic
+    -----------------------------------------------------------------------------
+    p_mux : PROCESS(mux_snk_in_2arr_2)
+    BEGIN
+      FOR i IN 0 TO c_nof_muxes-1 LOOP
+        nxt_mux_src_out_arr(i) <= c_dp_sosi_rst;
+        IF mux_snk_in_2arr_2(i)(0).valid='1' THEN
+          nxt_mux_src_out_arr(i).data  <= mux_snk_in_2arr_2(i)(0).data;
+          nxt_mux_src_out_arr(i).re    <= mux_snk_in_2arr_2(i)(0).re;
+          nxt_mux_src_out_arr(i).im    <= mux_snk_in_2arr_2(i)(0).im;
+          nxt_mux_src_out_arr(i).valid <= '1';
+        ELSIF mux_snk_in_2arr_2(i)(1).valid='1' THEN
+          nxt_mux_src_out_arr(i).data  <= mux_snk_in_2arr_2(i)(1).data;
+          nxt_mux_src_out_arr(i).re    <= mux_snk_in_2arr_2(i)(1).re;
+          nxt_mux_src_out_arr(i).im    <= mux_snk_in_2arr_2(i)(1).im;
+          nxt_mux_src_out_arr(i).valid <= '1';
+        END IF;
+      END LOOP;
+    END PROCESS;
+ 
+    -- Registers
+    p_clk: PROCESS(clk, rst)
+    BEGIN
+      IF rst='1' THEN
+        mux_src_out_arr <= (OTHERS=>c_dp_sosi_rst);
+      ELSIF rising_edge(clk) THEN
+        mux_src_out_arr <= nxt_mux_src_out_arr;
+      END IF;
+    END PROCESS;
+
+    -----------------------------------------------------------------------------
+    -- Not done folding; add a stage.
+    -- . g_nof_folds <0 : user wants to fold all the way to one output
+    -- . g_nof_folds >0 : user wants to fold n times
+    -----------------------------------------------------------------------------
+    gen_dp_folder: IF (g_nof_folds<0 AND c_nof_muxes>1) OR g_nof_folds>1 GENERATE
+      u_dp_folder : dp_folder
+      GENERIC MAP (
+        g_nof_inputs        => c_nof_muxes,
+        g_nof_folds         => g_nof_folds-1,
+        g_output_block_size => g_output_block_size,
+        g_fwd_sync_bsn      => g_fwd_sync_bsn
+      )
+      PORT MAP (
+        rst         => rst,
+        clk         => clk,
+                    
+        snk_in_arr  => mux_src_out_arr,                   
+        src_out_arr => dp_folder_src_out_arr
+      );
+
+      src_out_arr <= dp_folder_src_out_arr;
+
+    END GENERATE;
+
+    -----------------------------------------------------------------------------
+    -- c_nof_muxes=1 or g_nof_folds=1, so this is the last stage.
+    -----------------------------------------------------------------------------
+    gen_src_out_arr: IF (g_nof_folds<0 AND c_nof_muxes=1) OR g_nof_folds=1 GENERATE
+      dp_block_gen_snk_in_arr <= mux_src_out_arr;
+
+      -----------------------------------------------------------------------------
+      -- Add SOP and EOP to the outputs
+      -----------------------------------------------------------------------------
+      gen_ctrl : IF g_output_block_size>0 GENERATE
+        gen_dp_block_gen : FOR i IN 0 TO c_nof_muxes-1 GENERATE
+          u_dp_block_gen : ENTITY work.dp_block_gen
+          GENERIC MAP (
+            g_use_src_in       => FALSE,
+            g_nof_data         => g_output_block_size,
+            g_preserve_sync    => TRUE,
+            g_preserve_bsn     => TRUE
+          )
+          PORT MAP(
+            rst        => rst,
+            clk        => clk,
+           
+            snk_in     => dp_block_gen_snk_in_arr(i),
+            src_out    => dp_block_gen_src_out_arr(i)
+          );    
+        END GENERATE;
+      END GENERATE;
+    
+      no_ctrl : IF g_output_block_size=0 GENERATE
+        dp_block_gen_src_out_arr <= dp_block_gen_snk_in_arr;
+      END GENERATE;
+    
+      -----------------------------------------------------------------------------
+      -- Re-add input sync + BSN to all output streams
+      -----------------------------------------------------------------------------
+      gen_sync_bsn : IF g_fwd_sync_bsn = TRUE GENERATE
+        gen_dp_fifo_info: FOR i IN 0 TO c_nof_muxes-1 GENERATE
+          u_dp_fifo_info : ENTITY work.dp_fifo_info
+          GENERIC MAP (
+            g_use_sync => TRUE,
+            g_use_bsn  => TRUE
+          )
+          PORT MAP (
+            rst          => rst,
+            clk          => clk,
+        
+            data_snk_in  => dp_block_gen_src_out_arr(i),  -- delayed snk_in data
+            info_snk_in  => snk_in_arr(0),                -- original snk_in info
+        
+            src_in       => c_dp_siso_rdy,
+            src_out      => src_out_arr(i)
+          );
+        END GENERATE;
+      END GENERATE;
+    
+      no_sync_bsn : IF g_fwd_sync_bsn = FALSE GENERATE
+        src_out_arr <= dp_block_gen_src_out_arr;
+      END GENERATE;
+    END GENERATE;  
+  END GENERATE;
+
+  -----------------------------------------------------------------------------
+  -- Wire output to input if g_nof_folds=0
+  -----------------------------------------------------------------------------
+  gen_wire_out_to_in: IF g_nof_folds=0 GENERATE
+    dp_block_gen_snk_in_arr <= snk_in_arr;
+  END GENERATE;
+
+END str;
+
diff --git a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
index 26945f2feace344b9a69c86d1d18d58413575e5e..c002b9efd71ad0faf2d61463a242cde38cdd87b8 100644
--- a/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
+++ b/libraries/base/dp/src/vhdl/dp_stream_pkg.vhd
@@ -75,7 +75,7 @@ PACKAGE dp_stream_pkg Is
     channel  : STD_LOGIC_VECTOR(c_dp_stream_channel_w-1 DOWNTO 0);
     err      : STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0);  -- name field 'err' to avoid the 'error' keyword
   END RECORD;
-  
+ 
   -- Initialise signal declarations with c_dp_stream_rst/rdy to ease the interpretation of slv fields with unused bits
   CONSTANT c_dp_siso_rst   : t_dp_siso := ('0', '0');
   CONSTANT c_dp_siso_x     : t_dp_siso := ('X', 'X');
@@ -329,7 +329,13 @@ PACKAGE dp_stream_pkg Is
   FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING                         ) RETURN t_dp_sosi_arr; 
   FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr;
  
-   
+  -- Concatenate the data from a SOSI array into a single SOSI stream (assumes streams are in sync)
+  FUNCTION func_dp_stream_concat(snk_in_arr : t_dp_sosi_arr; data_w : NATURAL) RETURN t_dp_sosi; -- Concat SOSI_ARR data into single SOSI
+  FUNCTION func_dp_stream_concat(src_in     : t_dp_siso; nof_streams : NATURAL) RETURN t_dp_siso_arr; -- Wire single SISO to SISO_ARR
+  -- Deconcatenate data from SOSI into SOSI array
+  FUNCTION func_dp_stream_deconcat(snk_in      : t_dp_sosi; nof_streams, data_w : NATURAL) RETURN t_dp_sosi_arr; -- Deconcat SOSI data
+  FUNCTION func_dp_stream_deconcat(src_out_arr : t_dp_siso_arr) RETURN t_dp_siso; -- Wire SISO_ARR(0) to single SISO 
+  
 END dp_stream_pkg;
 
 
@@ -1150,5 +1156,46 @@ PACKAGE BODY dp_stream_pkg IS
     RETURN v_dp;
   END;
 
+  -- Concatenate the data (and complex fields) from a SOSI array into a single SOSI stream (assumes streams are in sync)
+  FUNCTION func_dp_stream_concat(snk_in_arr : t_dp_sosi_arr; data_w : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE v_src_out      : t_dp_sosi := snk_in_arr(0);
+    VARIABLE v_compl_data_w : NATURAL   := data_w/2;
+  BEGIN
+    FOR i IN snk_in_arr'RANGE LOOP
+      v_src_out.data((i+1)*        data_w-1 DOWNTO i*        data_w) := snk_in_arr(i).data(      data_w-1 DOWNTO 0);
+      v_src_out.re(  (i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w) := snk_in_arr(i).re(v_compl_data_w-1 DOWNTO 0);
+      v_src_out.im(  (i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w) := snk_in_arr(i).im(v_compl_data_w-1 DOWNTO 0);
+    END LOOP;
+    RETURN v_src_out;
+  END;
+
+  FUNCTION func_dp_stream_concat(src_in : t_dp_siso; nof_streams : NATURAL) RETURN t_dp_siso_arr IS -- Wire single SISO to SISO_ARR
+    VARIABLE v_snk_out_arr : t_dp_siso_arr(nof_streams-1 DOWNTO 0);
+  BEGIN
+    FOR i IN v_snk_out_arr'RANGE LOOP
+      v_snk_out_arr(i) := src_in;
+    END LOOP;
+    RETURN v_snk_out_arr;
+  END;
+
+  -- Deconcatenate data from SOSI into SOSI array
+  FUNCTION func_dp_stream_deconcat(snk_in : t_dp_sosi; nof_streams, data_w : NATURAL) RETURN t_dp_sosi_arr IS
+    VARIABLE v_src_out_arr  : t_dp_sosi_arr(nof_streams-1 DOWNTO 0);
+    VARIABLE v_compl_data_w : NATURAL := data_w/2;
+  BEGIN
+    FOR i IN v_src_out_arr'RANGE LOOP
+      v_src_out_arr(i) := snk_in;
+      v_src_out_arr(i).data(        data_w-1 DOWNTO 0) := snk_in.data((i+1)*        data_w-1 DOWNTO i*        data_w);
+      v_src_out_arr(i).re(  v_compl_data_w-1 DOWNTO 0) := snk_in.re  ((i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w);
+      v_src_out_arr(i).im(  v_compl_data_w-1 DOWNTO 0) := snk_in.im  ((i+1)*v_compl_data_w-1 DOWNTO i*v_compl_data_w);
+    END LOOP;
+    RETURN v_src_out_arr;
+  END;
+
+  FUNCTION func_dp_stream_deconcat(src_out_arr : t_dp_siso_arr) RETURN t_dp_siso IS -- Wire SISO_ARR(0) to single SISO
+  BEGIN
+    RETURN src_out_arr(0);
+  END;
+
 END dp_stream_pkg;
 
diff --git a/libraries/base/dp/src/vhdl/dp_switch.vhd b/libraries/base/dp/src/vhdl/dp_switch.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..0f51fcfe7186816db8848d09b8b6b6fc29d0610c
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_switch.vhd
@@ -0,0 +1,149 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Author:
+-- . Daniel van der Schuur
+-- Purpose:
+-- . Switch one of g_nof_inputs input streams to the output.
+-- Description:
+-- . Respects frame boundaries (SOP..EOP).
+-- . This is basically an MM-controlled dp_mux (with g_mode=4).
+-- . There is always one input enabled. If undesired, add your own input and 
+--   assign c_dp_sosi_rst to it. Switching to that input will disable the output.
+-- Remark:
+-- . dp_mux requires a minimum invaled gap of 1 cycle to switch to a new input!
+--   . So this does not work for continuous streams!
+
+LIBRARY IEEE, common_lib, mm_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_field_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+
+ENTITY dp_switch IS
+  GENERIC (
+    g_nof_inputs      : NATURAL;          -- Number of inputs
+    g_default_enabled : NATURAL := 0;     -- This input number 0..g_nof_inputs-1 will be enabled by default
+    g_use_fifo        : BOOLEAN := FALSE; -- This and the generics below are forwarded to dp_mux only
+    g_bsn_w           : NATURAL := 16;
+    g_data_w          : NATURAL := 16;
+    g_empty_w         : NATURAL := 1;
+    g_in_channel_w    : NATURAL := 1;
+    g_error_w         : NATURAL := 1;
+    g_use_bsn         : BOOLEAN := FALSE;
+    g_use_empty       : BOOLEAN := FALSE;
+    g_use_in_channel  : BOOLEAN := FALSE;
+    g_use_error       : BOOLEAN := FALSE;
+    g_use_sync        : BOOLEAN := FALSE;
+    g_fifo_af_margin  : NATURAL := 4;  -- Nof words below max (full) at which fifo is considered almost full
+    g_fifo_size       : NATURAL := 1024;
+    g_fifo_fill       : NATURAL := 0
+  );
+  PORT (
+    dp_clk      : IN  STD_LOGIC;
+    dp_rst      : IN  STD_LOGIC;
+
+    mm_clk      : IN  STD_LOGIC;
+    mm_rst      : IN  STD_LOGIC;
+
+    snk_in_arr  : IN  t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
+    src_out     : OUT t_dp_sosi;
+
+    reg_mosi    : IN  t_mem_mosi;
+    reg_miso    : OUT t_mem_miso
+  );
+END dp_switch;
+
+
+ARCHITECTURE str OF dp_switch IS
+
+  CONSTANT c_field_arr : t_common_field_arr(0 DOWNTO 0) := (0=> ( field_name_pad("input_select"), "RW", ceil_log2(g_nof_inputs), field_default(g_default_enabled) ));
+
+  SIGNAL mm_fields_out       : STD_LOGIC_VECTOR(field_slv_out_len(c_field_arr)-1 DOWNTO 0);
+  SIGNAL dp_mux_sel_ctrl_req : NATURAL;
+  SIGNAL dp_mux_sel_ctrl     : NATURAL;
+
+BEGIN
+
+  ------------------------------------------------------------------------------
+  -- A single MM register contains input to select
+  ------------------------------------------------------------------------------
+  u_mm_fields: ENTITY mm_lib.mm_fields
+  GENERIC MAP(
+    g_field_arr => c_field_arr
+  )
+  PORT MAP (
+    mm_clk  => mm_clk,
+    mm_rst  => mm_rst,
+
+    mm_mosi => reg_mosi,
+    mm_miso => reg_miso,
+    
+    slv_clk => dp_clk,
+    slv_rst => dp_rst, 
+
+    slv_out => mm_fields_out
+  );
+
+  ------------------------------------------------------------------------------
+  -- Don't allow user to select a non-existent input
+  -- . If user requests non-existent input, the default input is forwarded instead.
+  ------------------------------------------------------------------------------
+  dp_mux_sel_ctrl_req <= TO_UINT(mm_fields_out(field_hi(c_field_arr, "input_select") DOWNTO field_lo(c_field_arr, "input_select")));
+  dp_mux_sel_ctrl <= dp_mux_sel_ctrl_req WHEN dp_mux_sel_ctrl_req<g_nof_inputs ELSE g_default_enabled;
+    
+  ------------------------------------------------------------------------------
+  -- DP mux forwards input based on dp_mux_sel_ctrl
+  ------------------------------------------------------------------------------
+  u_dp_mux : ENTITY work.dp_mux
+  GENERIC MAP (
+    g_mode            => 4, -- Use sel_ctrl
+    g_sel_ctrl_invert => TRUE, -- Invert the control as we're using DOWNTO ranged sosi_arrays.
+    g_nof_input       => g_nof_inputs,
+    g_use_fifo        => g_use_fifo,  
+    g_bsn_w           => g_bsn_w,  
+    g_data_w          => g_data_w,  
+    g_empty_w         => g_empty_w,  
+    g_in_channel_w    => g_in_channel_w,   
+    g_error_w         => g_error_w,  
+    g_use_bsn         => g_use_bsn,  
+    g_use_empty       => g_use_empty,  
+    g_use_in_channel  => g_use_in_channel,  
+    g_use_error       => g_use_error,  
+    g_use_sync        => g_use_sync,  
+    g_fifo_af_margin  => g_fifo_af_margin,  
+    g_fifo_size       => array_init(g_fifo_size, g_nof_inputs),
+    g_fifo_fill       => array_init(g_fifo_fill, g_nof_inputs)
+  )
+  PORT MAP (
+    clk         => dp_clk,
+    rst         => dp_rst,
+
+    sel_ctrl    => dp_mux_sel_ctrl,
+
+    snk_in_arr  => snk_in_arr,
+
+    src_out     => src_out,
+    src_in      => c_dp_siso_rdy
+  );  
+
+END str;
diff --git a/libraries/base/dp/src/vhdl/dp_unfolder.vhd b/libraries/base/dp/src/vhdl/dp_unfolder.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..e2d5343d0b0c1dbff8fed361acee9ea8814cbee8
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_unfolder.vhd
@@ -0,0 +1,251 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- 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/>.
+--
+--------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+
+-- Author:
+-- . Daniel van der Schuur
+-- Purpose:
+-- . Unfold n input streams into n*2, n*2*2, n*2*2*2, .. output streams
+-- Description:
+-- . Reversed operation of dp_folder.
+
+ENTITY dp_unfolder IS
+  GENERIC (
+    g_nof_inputs        : NATURAL;          -- Number of inputs
+    g_nof_unfolds       : NATURAL := 0;     -- Number of times to unfold
+    g_output_block_size : NATURAL := 0;     -- >0: Create SOP/EOP tagged output blocks of this size.
+    g_fwd_sync_bsn      : BOOLEAN := FALSE; -- TRUE: forwards (stored) input Sync+BSN (from snk_in_arr(0)) to all output streams
+    g_output_align      : BOOLEAN := TRUE   -- TRUE: Use pipeline stages to align the outputs
+  );
+  PORT (
+    rst            : IN  STD_LOGIC;
+    clk            : IN  STD_LOGIC;
+
+    snk_in_arr     : IN  t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
+
+    src_out_arr    : OUT t_dp_sosi_arr(g_nof_inputs*pow2(g_nof_unfolds)-1 DOWNTO 0)
+  );
+END dp_unfolder;
+
+ARCHITECTURE str OF dp_unfolder IS
+
+  COMPONENT dp_unfolder IS
+    GENERIC (
+      g_nof_inputs   : NATURAL;
+      g_nof_unfolds  : NATURAL := 0;
+      g_output_align : BOOLEAN := TRUE  
+    ); 
+    PORT (
+      rst            : IN  STD_LOGIC;
+      clk            : IN  STD_LOGIC;
+  
+      snk_in_arr     : IN  t_dp_sosi_arr(g_nof_inputs-1 DOWNTO 0);
+  
+      src_out_arr    : OUT t_dp_sosi_arr(g_nof_inputs*pow2(g_nof_unfolds)-1 DOWNTO 0)
+    );
+  END COMPONENT;
+
+  CONSTANT c_nof_demuxes : NATURAL := g_nof_inputs;
+  CONSTANT c_nof_outputs : NATURAL := g_nof_inputs*pow2(g_nof_unfolds);
+
+  SIGNAL output_sel_arr           : STD_LOGIC_VECTOR(c_nof_demuxes-1 DOWNTO 0);
+  SIGNAL nxt_output_sel_arr       : STD_LOGIC_VECTOR(c_nof_demuxes-1 DOWNTO 0);
+
+  SIGNAL demux_src_out_2arr_2     : t_dp_sosi_2arr_2(c_nof_demuxes-1 DOWNTO 0);
+  SIGNAL nxt_demux_src_out_2arr_2 : t_dp_sosi_2arr_2(c_nof_demuxes-1 DOWNTO 0);
+  SIGNAL demux_src_out_arr        : t_dp_sosi_arr(2*c_nof_demuxes-1 DOWNTO 0);
+
+  SIGNAL dp_pipeline_snk_in_arr   : t_dp_sosi_arr(c_nof_outputs-1 DOWNTO 0);
+
+  SIGNAL dp_block_gen_snk_in_arr  : t_dp_sosi_arr(c_nof_outputs-1 DOWNTO 0);
+  SIGNAL dp_block_gen_src_out_arr : t_dp_sosi_arr(c_nof_outputs-1 DOWNTO 0);
+
+BEGIN
+
+  gen_arch: IF g_nof_unfolds/=0 GENERATE
+    -----------------------------------------------------------------------------
+    -- Simple 2-output demux logic
+    -----------------------------------------------------------------------------
+    gen_demux_comb: FOR i IN 0 TO c_nof_demuxes-1 GENERATE
+      nxt_output_sel_arr(i) <= NOT output_sel_arr(i) WHEN snk_in_arr(i).valid='1' ELSE output_sel_arr(i);
+    END GENERATE;
+
+    p_demux : PROCESS(snk_in_arr, output_sel_arr)
+    BEGIN
+      FOR i IN 0 TO c_nof_demuxes-1 LOOP
+        nxt_demux_src_out_2arr_2(i)(0) <= c_dp_sosi_rst;
+        nxt_demux_src_out_2arr_2(i)(1) <= c_dp_sosi_rst;
+        IF snk_in_arr(i).valid='1' THEN
+          IF output_sel_arr(i)='0' THEN
+            nxt_demux_src_out_2arr_2(i)(0).data  <= snk_in_arr(i).data;
+            nxt_demux_src_out_2arr_2(i)(0).re    <= snk_in_arr(i).re;
+            nxt_demux_src_out_2arr_2(i)(0).im    <= snk_in_arr(i).im;
+            nxt_demux_src_out_2arr_2(i)(0).valid <= '1';
+          ELSE 
+            nxt_demux_src_out_2arr_2(i)(1).data  <= snk_in_arr(i).data;
+            nxt_demux_src_out_2arr_2(i)(1).re    <= snk_in_arr(i).re;
+            nxt_demux_src_out_2arr_2(i)(1).im    <= snk_in_arr(i).im;
+            nxt_demux_src_out_2arr_2(i)(1).valid <= '1';
+          END IF;
+        END IF;
+      END LOOP;
+    END PROCESS;
+
+    -- Registers
+    p_clk: PROCESS(clk, rst)
+    BEGIN
+      IF rst='1' THEN
+        demux_src_out_2arr_2 <= (OTHERS=>(OTHERS=>c_dp_sosi_rst));
+        output_sel_arr       <= (OTHERS=>'0');
+      ELSIF rising_edge(clk) THEN
+        demux_src_out_2arr_2 <= nxt_demux_src_out_2arr_2;
+        output_sel_arr       <= nxt_output_sel_arr;
+      END IF;
+    END PROCESS;
+
+    -----------------------------------------------------------------------------
+    -- Wire the 2D demux output array to 1D array to match entity I/O type
+    -----------------------------------------------------------------------------
+    gen_demux_inputs_0: FOR i IN 0 TO c_nof_demuxes-1 GENERATE
+       demux_src_out_arr(2*i)   <= demux_src_out_2arr_2(i)(0);
+       demux_src_out_arr(2*i+1) <= demux_src_out_2arr_2(i)(1);
+    END GENERATE;
+  
+    -----------------------------------------------------------------------------
+    -- g_nof_unfolds>1, so add an unfolder stage.
+    -----------------------------------------------------------------------------
+    gen_dp_unfolder: IF g_nof_unfolds>1 GENERATE
+      u_dp_unfolder : dp_unfolder
+      GENERIC MAP (
+        g_nof_inputs   => c_nof_demuxes*2, -- Next stage has all our demux outputs as inputs
+        g_nof_unfolds  => g_nof_unfolds-1,
+        g_output_align => g_output_align
+      )
+      PORT MAP (
+        rst         => rst,
+        clk         => clk,
+                    
+        snk_in_arr  => demux_src_out_arr,                   
+        src_out_arr => src_out_arr
+      );
+    END GENERATE;
+ 
+    -----------------------------------------------------------------------------
+    -- g_nof_unfolds=1, so this is the last stage. Wire up the outputs.
+    -----------------------------------------------------------------------------
+    gen_src_out_arr: IF g_nof_unfolds=1 GENERATE
+
+      gen_output_align : IF g_output_align=TRUE GENERATE
+        dp_pipeline_snk_in_arr <= demux_src_out_arr;
+  
+        -----------------------------------------------------------------------------
+        -- Pipeline to re-align the unfolder output
+        -----------------------------------------------------------------------------
+        gen_dp_pipeline : FOR i IN 0 TO c_nof_outputs-1 GENERATE
+          u_dp_pipeline : ENTITY dp_lib.dp_pipeline
+          GENERIC MAP (
+            g_pipeline => 0 + (pow2(g_nof_unfolds) - i REM pow2(g_nof_unfolds)-1)
+          )
+          PORT MAP (
+            rst         => rst,
+            clk         => clk,
+        
+            snk_in      => dp_pipeline_snk_in_arr(i),
+            src_out     => dp_block_gen_snk_in_arr(i)
+          );
+        END GENERATE; 
+      END GENERATE;
+
+      no_output_align : IF g_output_align=FALSE GENERATE
+        dp_block_gen_snk_in_arr <= demux_src_out_arr;
+      END GENERATE;
+
+      -----------------------------------------------------------------------------
+      -- Add SOP and EOP to the outputs
+      -----------------------------------------------------------------------------
+      gen_ctrl : IF g_output_block_size>0 GENERATE
+        gen_dp_block_gen : FOR i IN 0 TO c_nof_outputs-1 GENERATE
+          u_dp_block_gen : ENTITY work.dp_block_gen
+          GENERIC MAP (
+            g_use_src_in       => FALSE,
+            g_nof_data         => g_output_block_size,
+            g_preserve_sync    => TRUE,
+            g_preserve_bsn     => TRUE
+          )
+          PORT MAP(
+            rst        => rst,
+            clk        => clk,
+           
+            snk_in     => dp_block_gen_snk_in_arr(i),
+            src_out    => dp_block_gen_src_out_arr(i)
+          );    
+        END GENERATE;
+      END GENERATE;
+    
+      no_ctrl : IF g_output_block_size=0 GENERATE
+        dp_block_gen_src_out_arr <= dp_block_gen_snk_in_arr;
+      END GENERATE;
+    
+      -----------------------------------------------------------------------------
+      -- Re-add input sync + BSN to all output streams
+      -----------------------------------------------------------------------------
+      gen_sync_bsn : IF g_fwd_sync_bsn = TRUE GENERATE
+        gen_dp_fifo_info: FOR i IN 0 TO c_nof_outputs-1 GENERATE
+          u_dp_fifo_info : ENTITY work.dp_fifo_info
+          GENERIC MAP (
+            g_use_sync => TRUE,
+            g_use_bsn  => TRUE
+          )
+          PORT MAP (
+            rst          => rst,
+            clk          => clk,
+        
+            data_snk_in  => dp_block_gen_src_out_arr(i),  -- delayed snk_in data
+            info_snk_in  => snk_in_arr(0),                -- original snk_in info
+        
+            src_in       => c_dp_siso_rdy,
+            src_out      => src_out_arr(i)
+          );
+        END GENERATE;
+      END GENERATE;
+    
+      no_sync_bsn : IF g_fwd_sync_bsn = FALSE GENERATE
+        src_out_arr <= dp_block_gen_src_out_arr;
+      END GENERATE;
+    
+        END GENERATE;
+    
+      END GENERATE;
+
+  -----------------------------------------------------------------------------
+  -- Wire output to input if g_nof_unfolds=0
+  -----------------------------------------------------------------------------
+  gen_wire_out_to_in: IF g_nof_unfolds=0 GENERATE
+    dp_block_gen_snk_in_arr <= snk_in_arr;
+  END GENERATE;
+
+END str;
+
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_folder.vhd b/libraries/base/dp/tb/vhdl/tb_dp_folder.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..7963cb48e04f42d9116770836df5b880c044c1ab
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_folder.vhd
@@ -0,0 +1,129 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Author
+-- . Daniel van der Schuur
+-- Purpose
+-- . Verify stream through dp_unfolder->dp_folder stages
+
+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_mem_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_folder IS
+END tb_dp_folder;
+
+
+ARCHITECTURE tb OF tb_dp_folder IS
+
+  CONSTANT c_nof_inputs                  : NATURAL := 1;
+  CONSTANT c_nof_unfolds                 : NATURAL := 1; -- 5 folds = 1->2->4->8->16->32 unfolded streams
+  CONSTANT c_nof_unfolded_streams        : NATURAL := c_nof_inputs*pow2(c_nof_unfolds);
+
+  CONSTANT c_data_w                      : NATURAL := 32;
+  CONSTANT c_nof_packets                 : NATURAL := 10;
+  CONSTANT c_packet_len                  : NATURAL := 20;
+  CONSTANT c_packet_gap                  : NATURAL := 0;
+
+  CONSTANT c_clk_period                  : TIME := 5 ns;  -- 200 MHz
+  CONSTANT c_mm_clk_period               : TIME := 20 ns; --  50 MHz
+
+  SIGNAL clk                             : STD_LOGIC := '1';
+  SIGNAL rst                             : STD_LOGIC;
+
+  SIGNAL proc_dp_gen_block_data_in_en    : STD_LOGIC := '1';
+  SIGNAL proc_dp_gen_block_data_src_in   : t_dp_siso := c_dp_siso_rdy;
+
+  SIGNAL proc_dp_gen_block_data_src_out  : t_dp_sosi;
+
+  SIGNAL dp_unfolder_snk_in_arr          : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
+  SIGNAL dp_folder_snk_in_arr            : t_dp_sosi_arr(c_nof_unfolded_streams-1 DOWNTO 0);
+  SIGNAL dp_folder_src_out_arr           : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
+
+BEGIN
+
+  -----------------------------------------------------------------------------
+  -- Clock,reset generation
+  -----------------------------------------------------------------------------
+  clk <= NOT clk AFTER c_clk_period/2;
+  rst <= '1', '0'   AFTER c_clk_period*7;
+
+  -----------------------------------------------------------------------------
+  -- Generate packet stream
+  -----------------------------------------------------------------------------
+  p_generate_packets : PROCESS
+  BEGIN
+    proc_dp_gen_block_data_src_out <= c_dp_sosi_rst;
+
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 5);
+
+    FOR i IN 0 TO c_nof_packets-1 LOOP
+      -- Generate single packet
+      proc_dp_gen_block_data(c_data_w, 0, c_packet_len, 0, 0, '0', "0", clk, proc_dp_gen_block_data_in_en, proc_dp_gen_block_data_src_in, proc_dp_gen_block_data_src_out); 
+
+      -- Insert optional gap between the packets
+      proc_common_wait_some_cycles(clk, c_packet_gap);
+    END LOOP;
+    WAIT;
+  END PROCESS;
+
+  -----------------------------------------------------------------------------
+  -- Unfold the single stream into multiple streams, the fold it back into one again 
+  -----------------------------------------------------------------------------
+  dp_unfolder_snk_in_arr(0) <= proc_dp_gen_block_data_src_out;
+
+  u_dp_unfolder : ENTITY work.dp_unfolder
+  GENERIC MAP (
+    g_nof_inputs  => c_nof_inputs,
+    g_nof_unfolds => c_nof_unfolds,
+    g_output_align => FALSE -- We're going to fold these outputs again, so don't align them!
+  )
+  PORT MAP (
+    clk         => clk,
+    rst         => rst,
+                
+    snk_in_arr  => dp_unfolder_snk_in_arr,                   
+    src_out_arr => dp_folder_snk_in_arr
+  );
+
+  u_dp_folder : ENTITY work.dp_folder
+  GENERIC MAP (
+    g_nof_inputs => c_nof_unfolded_streams,
+    g_nof_folds  => -1 -- Fold until 1 output remains,
+--    g_output_block_size => c_packet_len
+  )
+  PORT MAP (
+    clk         => clk,
+    rst         => rst,
+                
+    snk_in_arr  => dp_folder_snk_in_arr,                   
+    src_out_arr => dp_folder_src_out_arr
+  );
+
+END tb;
+
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_switch.vhd b/libraries/base/dp/tb/vhdl/tb_dp_switch.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..0c772e3d0fd54f40511a0d349c866feb77595d0c
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_switch.vhd
@@ -0,0 +1,143 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2016
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Author
+-- . Daniel van der Schuur
+-- Purpose
+-- . Generate input streams for dp_switch, verify by eye in wave window.
+
+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_mem_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_switch IS
+END tb_dp_switch;
+
+
+ARCHITECTURE tb OF tb_dp_switch IS
+
+  CONSTANT c_nof_inputs                  : NATURAL := 3;
+  CONSTANT c_data_w                      : NATURAL := 32;
+  CONSTANT c_nof_packets                 : NATURAL := 10;
+  CONSTANT c_packet_len                  : NATURAL := 20;
+  CONSTANT c_packet_gap                  : NATURAL := 1; --NOTE: dp_mux requires a minimum gap of 1 to select a new input!
+
+  CONSTANT c_dp_clk_period               : TIME := 5 ns;  -- 200 MHz
+  CONSTANT c_mm_clk_period               : TIME := 20 ns; --  50 MHz
+
+  SIGNAL dp_clk                          : STD_LOGIC := '1';
+  SIGNAL dp_rst                          : STD_LOGIC;
+
+  SIGNAL mm_clk                          : STD_LOGIC := '1';
+  SIGNAL mm_rst                          : STD_LOGIC;
+
+  SIGNAL proc_dp_gen_block_data_in_en    : STD_LOGIC := '1';
+  SIGNAL proc_dp_gen_block_data_src_in   : t_dp_siso := c_dp_siso_rdy;
+
+  SIGNAL proc_dp_gen_block_data_src_out_arr : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
+
+  SIGNAL dp_switch_snk_in_arr            : t_dp_sosi_arr(c_nof_inputs-1 DOWNTO 0);
+  SIGNAL dp_switch_src_out               : t_dp_sosi;
+
+  SIGNAL reg_dp_switch_mosi              : t_mem_mosi := c_mem_mosi_rst;
+  SIGNAL reg_dp_switch_miso              : t_mem_miso;   
+
+BEGIN
+
+  -----------------------------------------------------------------------------
+  -- Clock,reset generation
+  -----------------------------------------------------------------------------
+  dp_clk <= NOT dp_clk AFTER c_dp_clk_period/2;
+  dp_rst <= '1', '0'   AFTER c_dp_clk_period*7;
+
+  mm_clk <= NOT mm_clk AFTER c_mm_clk_period/2;
+  mm_rst <= '1', '0'   AFTER c_mm_clk_period*7;
+
+  -----------------------------------------------------------------------------
+  -- Generate packet streams
+  -----------------------------------------------------------------------------
+  gen_generate_packets : FOR i IN 0 TO c_nof_inputs-1 GENERATE
+    p_generate_packets : PROCESS
+    BEGIN
+      proc_dp_gen_block_data_src_out_arr(i) <= c_dp_sosi_rst;
+  
+      proc_common_wait_until_low(dp_clk, dp_rst);
+      proc_common_wait_some_cycles(dp_clk, 5);
+  
+      FOR j IN 0 TO c_nof_packets-1 LOOP
+        -- Generate single packet
+        proc_dp_gen_block_data(c_data_w, i*1000, c_packet_len, 0, 0, '0', "0", dp_clk, proc_dp_gen_block_data_in_en, proc_dp_gen_block_data_src_in, proc_dp_gen_block_data_src_out_arr(i)); 
+  
+        -- Insert optional gap between the packets
+        proc_common_wait_some_cycles(dp_clk, c_packet_gap);
+      END LOOP;
+      WAIT;
+    END PROCESS;
+  END GENERATE;
+
+  -----------------------------------------------------------------------------
+  -- MM write different input selections
+  -----------------------------------------------------------------------------
+  p_generate_packets : PROCESS
+  BEGIN
+    reg_dp_switch_mosi <= c_mem_mosi_rst;
+    proc_common_wait_until_low(mm_clk, mm_rst);
+    proc_common_wait_some_cycles(mm_clk, 15);
+    proc_mem_mm_bus_wr(0, 1, mm_clk, reg_dp_switch_mosi);
+  WAIT;
+  END PROCESS;
+
+  -----------------------------------------------------------------------------
+  -- dp_switch forwards either stream 0 or stream 1
+  -- . Both inputs carry the same generated stream
+  -----------------------------------------------------------------------------
+  gen_dp_switch_snk_in_arr : FOR i IN 0 TO c_nof_inputs-1 GENERATE
+    dp_switch_snk_in_arr(i) <= proc_dp_gen_block_data_src_out_arr(i);
+  END GENERATE;
+
+  u_dp_switch : ENTITY work.dp_switch
+  GENERIC MAP (
+    g_nof_inputs      => c_nof_inputs,
+    g_default_enabled => 2 
+   )
+  PORT MAP (
+    dp_clk      => dp_clk,
+    dp_rst      => dp_rst,
+
+    mm_clk      => mm_clk,
+    mm_rst      => mm_rst,
+
+    snk_in_arr  => dp_switch_snk_in_arr,
+    src_out     => dp_switch_src_out,
+
+    reg_mosi    => reg_dp_switch_mosi,
+    reg_miso    => reg_dp_switch_miso
+  );
+
+END tb;
+