diff --git a/cores/base/common/common_components/common_switch.vhd b/cores/base/common/common_components/common_switch.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..553c2353278f4ad9f98e8f53b2b3f45b4ce27388
--- /dev/null
+++ b/cores/base/common/common_components/common_switch.vhd
@@ -0,0 +1,103 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2009
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose : Switch output high or low
+-- Description:
+-- . The output goes high when switch_high='1' and low when switch_low='1'.
+-- . If g_or_high is true then the output follows the switch_high immediately,
+--   else it goes high in the next clk cycle.
+-- . If g_and_low is true then the output follows the switch_low immediately,
+--   else it goes low in the next clk cycle.
+--   The g_priority_lo defines which input has priority when switch_high and
+--   switch_low are active simultaneously.
+
+LIBRARY ieee;
+USE ieee.std_logic_1164.ALL;
+
+ENTITY common_switch IS
+  GENERIC (
+    g_rst_level    : STD_LOGIC := '0';  -- Defines the output level at reset.
+    g_priority_lo  : BOOLEAN := TRUE;   -- When TRUE then input switch_low has priority, else switch_high. Don't care when switch_high and switch_low are pulses that do not occur simultaneously.
+    g_or_high      : BOOLEAN := FALSE;  -- When TRUE and priority hi then the registered switch_level is OR-ed with the input switch_high to get out_level, else out_level is the registered switch_level
+    g_and_low      : BOOLEAN := FALSE   -- When TRUE and priority lo then the registered switch_level is AND-ed with the input switch_low to get out_level, else out_level is the registered switch_level
+  );
+  PORT (
+    rst         : IN  STD_LOGIC;
+    clk         : IN  STD_LOGIC;
+    clken       : IN  STD_LOGIC := '1';
+    switch_high : IN  STD_LOGIC;    -- A pulse on switch_high makes the out_level go high
+    switch_low  : IN  STD_LOGIC;    -- A pulse on switch_low makes the out_level go low
+    out_level   : OUT STD_LOGIC
+  );
+END;
+
+ARCHITECTURE rtl OF common_switch IS
+  
+  SIGNAL switch_level         : STD_LOGIC := g_rst_level;
+  SIGNAL nxt_switch_level     : STD_LOGIC;
+  
+BEGIN
+
+  gen_wire : IF g_or_high=FALSE AND g_and_low=FALSE GENERATE
+    out_level <= switch_level;
+  END GENERATE;
+  
+  gen_or : IF g_or_high=TRUE AND g_and_low=FALSE GENERATE
+    out_level <= switch_level OR switch_high;
+  END GENERATE;
+
+  gen_and : IF g_or_high=FALSE AND g_and_low=TRUE GENERATE
+    out_level <= switch_level AND (NOT switch_low);
+  END GENERATE;
+  
+  gen_or_and : IF g_or_high=TRUE AND g_and_low=TRUE GENERATE
+    out_level <= (switch_level OR switch_high) AND (NOT switch_low);
+  END GENERATE;
+  
+  p_reg : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      switch_level <= g_rst_level;
+    ELSIF rising_edge(clk) THEN
+      IF clken='1' THEN
+        switch_level <= nxt_switch_level;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  p_switch_level : PROCESS(switch_level, switch_low, switch_high)
+  BEGIN
+    nxt_switch_level <= switch_level;
+    IF g_priority_lo=TRUE THEN
+      IF switch_low='1' THEN
+        nxt_switch_level <= '0';
+      ELSIF switch_high='1' THEN
+        nxt_switch_level <= '1';
+      END IF;
+    ELSE
+      IF switch_high='1' THEN
+        nxt_switch_level <= '1';
+      ELSIF switch_low='1' THEN
+        nxt_switch_level <= '0';
+      END IF;
+    END IF;
+  END PROCESS;
+END rtl;
diff --git a/cores/base/common/common_components/hdllib.cfg b/cores/base/common/common_components/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..9b7bc1bb2357ab86146944d31ce18045f5161faa
--- /dev/null
+++ b/cores/base/common/common_components/hdllib.cfg
@@ -0,0 +1,18 @@
+hdl_lib_name = common_components
+hdl_library_clause_name = common_components_lib
+hdl_lib_uses_synth = 
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    common_switch.vhd
+ 
+test_bench_files = 
+
+regression_test_vhdl = 
+    
+[modelsim_project_file]
+modelsim_copy_files =
+
+[quartus_project_file]
+
diff --git a/cores/base/common/common_pkg/common_lfsr_sequences_pkg.vhd b/cores/base/common/common_pkg/common_lfsr_sequences_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..eb45149411f8e8148d523ef2b7a78f1159d64ce6
--- /dev/null
+++ b/cores/base/common/common_pkg/common_lfsr_sequences_pkg.vhd
@@ -0,0 +1,193 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2009
+-- 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/>.
+--
+--------------------------------------------------------------------------------
+ 
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE work.common_pkg.ALL;
+
+PACKAGE common_lfsr_sequences_pkg IS
+
+  CONSTANT c_common_lfsr_max_nof_feedbacks : NATURAL := 6;
+  CONSTANT c_common_lfsr_first             : NATURAL := 1;  -- also support n = 1 and 2 in addition to n >= 3
+  
+  TYPE t_FEEDBACKS IS ARRAY (c_common_lfsr_max_nof_feedbacks-1 DOWNTO 0) OF NATURAL;
+  TYPE t_SEQUENCES IS ARRAY (NATURAL RANGE <>) OF t_FEEDBACKS;
+
+  -- XNOR feedbacks for n = 1:
+  --   (0,0,0,0,0, 0) yields repeat <1>
+  --   (0,0,0,0,0, 1) yields repeat <0, 1>
+  
+  -- XNOR feedbacks for n = 2:
+  --   (0,0,0,0, 0, 1) yields repeat <1, 2>
+  --   (0,0,0,0, 0, 2) yields repeat <0, 1, 3, 2>
+  --   (0,0,0,0, 2, 1) yields repeat <0, 1, 2>
+  
+  -- XNOR feedbacks from outputs for n = 3 .. 72 from Xilinx xapp052.pdf (that lists feedbacks for in total 168 sequences)
+  CONSTANT c_common_lfsr_sequences : t_SEQUENCES := ((0,0,0,0,0,               1),   -- 1 : <0, 1>
+                                                     (0,0,0,0,              0, 2),   -- 2 : <0, 1, 3, 2>
+                                                     (0,0,0,0,              3, 2),   -- 3
+                                                     (0,0,0,0,              4, 3),   -- 4
+                                                     (0,0,0,0,              5, 3),   -- 5
+                                                     (0,0,0,0,              6, 5),   -- 6
+                                                     (0,0,0,0,              7, 6),   -- 7
+                                                     (0,0,            8, 6, 5, 4),   -- 8
+                                                     (0,0,0,0,              9, 5),   -- 9
+                                                     (0,0,0,0,             10, 7),   -- 10
+                                                     (0,0,0,0,             11, 9),   -- 11
+                                                     (0,0,           12, 6, 4, 1),   -- 12
+                                                     (0,0,           13, 4, 3, 1),   -- 13
+                                                     (0,0,           14, 5, 3, 1),   -- 14
+                                                     (0,0,0,0,       15,14      ),   -- 15
+                                                     (0,0,           16,15,13, 4),   -- 16
+                                                     (0,0,0,0,       17,14      ),   -- 17
+                                                     (0,0,0,0,       18,11      ),   -- 18
+                                                     (0,0,           19, 6, 2, 1),   -- 19
+                                                     (0,0,0,0,       20,17      ),   -- 20
+                                                     (0,0,0,0,       21,19      ),   -- 21
+                                                     (0,0,0,0,       22,21      ),   -- 22
+                                                     (0,0,0,0,       23,18      ),   -- 23
+                                                     (0,0,           24,23,22,17),   -- 24
+                                                     (0,0,0,0,       25,22      ),   -- 25
+                                                     (0,0,           26, 6, 2, 1),   -- 26
+                                                     (0,0,           27, 5, 2, 1),   -- 27
+                                                     (0,0,0,0,       28,25      ),   -- 28
+                                                     (0,0,0,0,       29,27      ),   -- 29
+                                                     (0,0,           30, 6, 4, 1),   -- 30
+                                                     (0,0,0,0,       31,28      ),   -- 31
+                                                     (0,0,           32,22, 2, 1),   -- 32
+                                                     (0,0,0,0,       33,20      ),   -- 33
+                                                     (0,0,           34,27, 2, 1),   -- 34
+                                                     (0,0,0,0,       35,33      ),   -- 35
+                                                     (0,0,0,0,       36,25      ),   -- 36
+                                                     (         37, 5, 4, 3, 2, 1),   -- 37
+                                                     (0,0,           38, 6, 5, 1),   -- 38
+                                                     (0,0,0,0,       39,35      ),   -- 39
+                                                     (0,0,           40,38,21,19),   -- 40
+                                                     (0,0,0,0,       41,38      ),   -- 41
+                                                     (0,0,           42,41,20,19),   -- 42
+                                                     (0,0,           43,42,38,37),   -- 43
+                                                     (0,0,           44,43,18,17),   -- 44
+                                                     (0,0,           45,44,42,41),   -- 45
+                                                     (0,0,           46,45,26,25),   -- 46
+                                                     (0,0,0,0,       47,42      ),   -- 47
+                                                     (0,0,           48,47,21,20),   -- 48
+                                                     (0,0,0,0,       49,40      ),   -- 49
+                                                     (0,0,           50,49,24,23),   -- 50
+                                                     (0,0,           51,50,36,35),   -- 51
+                                                     (0,0,0,0,       52,49      ),   -- 52
+                                                     (0,0,           53,52,38,37),   -- 53
+                                                     (0,0,           54,53,18,17),   -- 54
+                                                     (0,0,0,0,       55,31      ),   -- 55
+                                                     (0,0,           56,55,35,34),   -- 56
+                                                     (0,0,0,0,       57,50      ),   -- 57
+                                                     (0,0,0,0,       58,39      ),   -- 58
+                                                     (0,0,           59,58,38,37),   -- 59
+                                                     (0,0,0,0,       60,59      ),   -- 60
+                                                     (0,0,           61,60,46,45),   -- 61
+                                                     (0,0,           62,61, 6, 5),   -- 62
+                                                     (0,0,0,0,       63,62      ),   -- 63
+                                                     (0,0,           64,63,61,60),   -- 64
+                                                     (0,0,0,0,       65,47      ),   -- 65
+                                                     (0,0,           66,65,57,56),   -- 66
+                                                     (0,0,           67,66,58,57),   -- 67
+                                                     (0,0,0,0,       68,59      ),   -- 68
+                                                     (0,0,           69,67,42,40),   -- 69
+                                                     (0,0,           70,69,55,54),   -- 70
+                                                     (0,0,0,0,       71,65      ),   -- 71
+                                                     (0,0,           72,66,25,19));  -- 72
+                                                   
+  
+  -- Procedure for calculating the next PSRG and COUNTER sequence value
+  PROCEDURE common_lfsr_nxt_seq(CONSTANT c_lfsr_nr : IN  NATURAL;
+                                CONSTANT g_incr    : IN  INTEGER;
+                                         in_en     : IN  STD_LOGIC;
+                                         in_req    : IN  STD_LOGIC;
+                                         in_dat    : IN  STD_LOGIC_VECTOR;
+                                         prsg      : IN  STD_LOGIC_VECTOR;
+                                         cntr      : IN  STD_LOGIC_VECTOR;
+                                SIGNAL   nxt_prsg  : OUT STD_LOGIC_VECTOR;
+                                SIGNAL   nxt_cntr  : OUT STD_LOGIC_VECTOR);
+                               
+  -- Use lfsr part of common_lfsr_nxt_seq to make a random bit generator function
+  -- . width of lfsr selects the LFSR sequence
+  -- . initialized lfsr with (OTHERS=>'0')
+  -- . use lfsr(lfsr'HIGH) as random bit
+  FUNCTION func_common_random(lfsr : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  
+END common_lfsr_sequences_pkg;
+
+
+PACKAGE BODY common_lfsr_sequences_pkg IS
+
+  PROCEDURE common_lfsr_nxt_seq(CONSTANT c_lfsr_nr : IN  NATURAL;
+                                CONSTANT g_incr    : IN  INTEGER;
+                                         in_en     : IN  STD_LOGIC;
+                                         in_req    : IN  STD_LOGIC;
+                                         in_dat    : IN  STD_LOGIC_VECTOR;
+                                         prsg      : IN  STD_LOGIC_VECTOR;
+                                         cntr      : IN  STD_LOGIC_VECTOR;
+                                SIGNAL   nxt_prsg  : OUT STD_LOGIC_VECTOR;
+                                SIGNAL   nxt_cntr  : OUT STD_LOGIC_VECTOR) IS
+    VARIABLE v_feedback : STD_LOGIC;
+  BEGIN
+    nxt_prsg <= prsg;
+    nxt_cntr <= cntr;
+    IF in_en='0' THEN     -- init reference value
+      nxt_prsg <= in_dat;
+      nxt_cntr <= in_dat;
+    ELSIF in_req='1' THEN   -- next reference value
+      -- PRSG shift
+      nxt_prsg    <= prsg(prsg'HIGH-1 DOWNTO 0) & '0';
+      -- PRSG feedback
+      v_feedback := '0';
+      FOR I IN c_common_lfsr_max_nof_feedbacks-1 DOWNTO 0 LOOP
+        IF c_common_lfsr_sequences(c_lfsr_nr)(I) /= 0 THEN
+          v_feedback := v_feedback XOR prsg(c_common_lfsr_sequences(c_lfsr_nr)(I)-1);
+        END IF;
+      END LOOP;
+      nxt_prsg(0) <= NOT v_feedback;
+
+      -- COUNTER
+      nxt_cntr <= INCR_UVEC(cntr, g_incr);
+    END IF;
+  END common_lfsr_nxt_seq;
+
+  FUNCTION func_common_random(lfsr : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_lfsr_nr  : NATURAL := lfsr'LENGTH - c_common_lfsr_first;
+    VARIABLE v_nxt_lfsr : STD_LOGIC_VECTOR(lfsr'RANGE);
+    VARIABLE v_feedback : STD_LOGIC;
+  BEGIN
+    -- shift
+    v_nxt_lfsr := lfsr(lfsr'HIGH-1 DOWNTO 0) & '0';
+    -- feedback
+    v_feedback := '0';
+    FOR I IN c_common_lfsr_max_nof_feedbacks-1 DOWNTO 0 LOOP
+      IF c_common_lfsr_sequences(c_lfsr_nr)(I) /= 0 THEN
+        v_feedback := v_feedback XOR lfsr(c_common_lfsr_sequences(c_lfsr_nr)(I)-1);
+      END IF;
+    END LOOP;
+    v_nxt_lfsr(0) := NOT v_feedback;
+    RETURN v_nxt_lfsr;
+  END func_common_random;
+  
+END common_lfsr_sequences_pkg;
diff --git a/cores/base/common/common_pkg/common_pkg.vhd b/cores/base/common/common_pkg/common_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..9782ee21f5885d5fa7ae412122d754e1661be518
--- /dev/null
+++ b/cores/base/common/common_pkg/common_pkg.vhd
@@ -0,0 +1,2294 @@
+
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2009
+-- 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;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE IEEE.MATH_REAL.ALL;
+
+PACKAGE common_pkg IS
+
+  -- CONSTANT DECLARATIONS ----------------------------------------------------
+
+  -- some integers
+  CONSTANT c_0                    : NATURAL := 0;
+  CONSTANT c_zero                 : NATURAL := 0;
+  CONSTANT c_1                    : NATURAL := 1;
+  CONSTANT c_one                  : NATURAL := 1;
+  CONSTANT c_2                    : NATURAL := 2;
+  CONSTANT c_4                    : NATURAL := 4;
+  CONSTANT c_quad                 : NATURAL := 4;
+  CONSTANT c_8                    : NATURAL := 8;
+  CONSTANT c_16                   : NATURAL := 16;
+  CONSTANT c_32                   : NATURAL := 32;
+  CONSTANT c_64                   : NATURAL := 64;
+  CONSTANT c_128                  : NATURAL := 128;
+  CONSTANT c_256                  : NATURAL := 256;
+  
+  -- widths and sizes
+  CONSTANT c_halfword_sz          : NATURAL := 2;
+  CONSTANT c_word_sz              : NATURAL := 4;
+  CONSTANT c_longword_sz          : NATURAL := 8;
+  CONSTANT c_nibble_w             : NATURAL := 4;
+  CONSTANT c_byte_w               : NATURAL := 8;
+  CONSTANT c_octet_w              : NATURAL := 8;
+  CONSTANT c_halfword_w           : NATURAL := c_byte_w*c_halfword_sz;
+  CONSTANT c_word_w               : NATURAL := c_byte_w*c_word_sz;
+  CONSTANT c_integer_w            : NATURAL := 32;              -- unfortunately VHDL integer type is limited to 32 bit values
+  CONSTANT c_natural_w            : NATURAL := c_integer_w-1;   -- unfortunately VHDL natural type is limited to 31 bit values (0 and the positive subset of the VHDL integer type0
+  CONSTANT c_longword_w           : NATURAL := c_byte_w*c_longword_sz;
+  
+  -- logic
+  CONSTANT c_sl0                  : STD_LOGIC := '0';
+  CONSTANT c_sl1                  : STD_LOGIC := '1';
+  CONSTANT c_unsigned_0           : UNSIGNED(0 DOWNTO 0) := TO_UNSIGNED(0,1);
+  CONSTANT c_unsigned_1           : UNSIGNED(0 DOWNTO 0) := TO_UNSIGNED(1,1);
+  CONSTANT c_signed_0             : SIGNED(1 DOWNTO 0) := TO_SIGNED(0,2);
+  CONSTANT c_signed_1             : SIGNED(1 DOWNTO 0) := TO_SIGNED(1,2);
+  CONSTANT c_slv0                 : STD_LOGIC_VECTOR(255 DOWNTO 0) := (OTHERS=>'0');
+  CONSTANT c_slv1                 : STD_LOGIC_VECTOR(255 DOWNTO 0) := (OTHERS=>'1');
+  CONSTANT c_word_01              : STD_LOGIC_VECTOR(31 DOWNTO 0) := "01010101010101010101010101010101";
+  CONSTANT c_word_10              : STD_LOGIC_VECTOR(31 DOWNTO 0) := "10101010101010101010101010101010";
+  CONSTANT c_slv01                : STD_LOGIC_VECTOR(255 DOWNTO 0) := c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01 & c_word_01;
+  CONSTANT c_slv10                : STD_LOGIC_VECTOR(255 DOWNTO 0) := c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10 & c_word_10;
+
+  -- math
+  CONSTANT c_nof_complex          : NATURAL := 2;   -- Real and imaginary part of complex number
+  CONSTANT c_sign_w               : NATURAL := 1;   -- Sign bit, can be used to skip one of the double sign bits of a product
+  CONSTANT c_sum_of_prod_w        : NATURAL := 1;   -- Bit growth for sum of 2 products, can be used in case complex multiply has normalized real and imag inputs instead of normalized amplitude inputs
+      
+  -- FF, block RAM, FIFO
+  CONSTANT c_meta_delay_len       : NATURAL := 3;   -- default nof flipflops (FF) in meta stability recovery delay line (e.g. for clock domain crossing)
+  CONSTANT c_meta_fifo_depth      : NATURAL := 16;  -- default use 16 word deep FIFO to cross clock domain, typically > 2*c_meta_delay_len or >~ 8 is enough
+
+  CONSTANT c_bram_m9k_nof_bits    : NATURAL := 1024*9;  -- size of 1 Altera M9K block RAM in bits
+  CONSTANT c_bram_m9k_max_w       : NATURAL := 36;      -- maximum width of 1 Altera M9K block RAM, so the size is then 256 words of 36 bits
+  CONSTANT c_bram_m9k_fifo_depth  : NATURAL := c_bram_m9k_nof_bits/c_bram_m9k_max_w;  -- using a smaller FIFO depth than this leaves part of the RAM unused
+  
+  CONSTANT c_fifo_afull_margin    : NATURAL := 4;       -- default or minimal FIFO almost full margin
+  
+  -- DSP
+  CONSTANT c_dsp_mult_w           : NATURAL := 18;   -- Width of the embedded multipliers in Stratix IV
+  
+  -- TYPE DECLARATIONS --------------------------------------------------------
+  TYPE t_boolean_arr     IS ARRAY (INTEGER RANGE <>) OF BOOLEAN;   -- INTEGER left index starts default at -2**31
+  TYPE t_integer_arr     IS ARRAY (INTEGER RANGE <>) OF INTEGER;   -- INTEGER left index starts default at -2**31
+  TYPE t_natural_arr     IS ARRAY (INTEGER RANGE <>) OF NATURAL;   -- INTEGER left index starts default at -2**31
+  TYPE t_nat_boolean_arr IS ARRAY (NATURAL RANGE <>) OF BOOLEAN;   -- NATURAL left index starts default at 0
+  TYPE t_nat_integer_arr IS ARRAY (NATURAL RANGE <>) OF INTEGER;   -- NATURAL left index starts default at 0
+  TYPE t_nat_natural_arr IS ARRAY (NATURAL RANGE <>) OF NATURAL;   -- NATURAL left index starts default at 0
+  TYPE t_sl_arr          IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC;
+  TYPE t_slv_1_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(0 DOWNTO 0);
+  TYPE t_slv_2_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(1 DOWNTO 0);
+  TYPE t_slv_4_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(3 DOWNTO 0);
+  TYPE t_slv_8_arr       IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
+  TYPE t_slv_12_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(11 DOWNTO 0);
+  TYPE t_slv_16_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(15 DOWNTO 0);
+  TYPE t_slv_18_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(17 DOWNTO 0);
+  TYPE t_slv_24_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(23 DOWNTO 0);
+  TYPE t_slv_32_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(31 DOWNTO 0);
+  TYPE t_slv_44_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(43 DOWNTO 0);
+  TYPE t_slv_48_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(47 DOWNTO 0);
+  TYPE t_slv_64_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(63 DOWNTO 0);
+  TYPE t_slv_128_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(127 DOWNTO 0);
+  TYPE t_slv_256_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(255 DOWNTO 0);
+  TYPE t_slv_512_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(511 DOWNTO 0);
+  TYPE t_slv_1024_arr    IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(1023 DOWNTO 0);
+ 
+  CONSTANT c_boolean_arr     : t_boolean_arr     := (TRUE, FALSE);  -- array all possible values that can be iterated over
+  CONSTANT c_nat_boolean_arr : t_nat_boolean_arr := (TRUE, FALSE);  -- array all possible values that can be iterated over
+ 
+  TYPE t_integer_matrix IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF INTEGER;
+  TYPE t_boolean_matrix IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF BOOLEAN;
+  TYPE t_sl_matrix      IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC;
+  TYPE t_slv_8_matrix   IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
+  TYPE t_slv_16_matrix  IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(15 DOWNTO 0);
+  TYPE t_slv_32_matrix  IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(31 DOWNTO 0);
+  TYPE t_slv_64_matrix  IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF STD_LOGIC_VECTOR(63 DOWNTO 0);
+
+  TYPE t_natural_2arr_2 IS ARRAY (INTEGER RANGE <>) OF t_natural_arr(1 DOWNTO 0);
+
+  -- STRUCTURE DECLARATIONS ---------------------------------------------------
+  
+  -- Clock and Reset
+  --
+  -- . rst   = Reset. Can be used asynchronously to take effect immediately
+  --           when used before the clk'EVENT section. May also be used as
+  --           synchronous reset using it as first condition in the clk'EVENT
+  --           section. As synchronous reset it requires clock activity to take
+  --           effect. A synchronous rst may or may not depend on clken,
+  --           however typically rst should take priority over clken.
+  -- . clk   = Clock. Used in clk'EVENT line via rising_edge(clk) or sometimes
+  --           as falling_edge(clk).
+  -- . clken = Clock Enable. Used for the whole clk'EVENT section.
+  TYPE t_sys_rce IS RECORD
+    rst   : STD_LOGIC;
+    clk   : STD_LOGIC;
+    clken : STD_LOGIC;  -- := '1';
+  END RECORD;
+  
+  TYPE t_sys_ce IS RECORD
+    clk   : STD_LOGIC;
+    clken : STD_LOGIC;  -- := '1';
+  END RECORD;
+
+    
+  -- FUNCTION DECLARATIONS ----------------------------------------------------
+  
+  -- All functions assume [high downto low] input ranges
+  
+  FUNCTION pow2(n : NATURAL) RETURN NATURAL;  -- = 2**n
+  FUNCTION ceil_pow2(n : INTEGER) RETURN NATURAL;  -- = 2**n, returns 1 for n<0
+
+  FUNCTION true_log2(n : NATURAL) RETURN NATURAL;  -- true_log2(n) = log2(n)
+  FUNCTION ceil_log2(n : NATURAL) RETURN NATURAL;  -- ceil_log2(n) = log2(n), but force ceil_log2(1) = 1
+ 
+  FUNCTION floor_log10(n : NATURAL) RETURN NATURAL;
+
+  FUNCTION is_pow2(n : NATURAL) RETURN BOOLEAN;        -- return TRUE when n is a power of 2, so 0, 1, 2, 4, 8, 16, ...
+  FUNCTION true_log_pow2(n : NATURAL) RETURN NATURAL;  -- 2**true_log2(n), return power of 2 that is >= n
+  
+  FUNCTION ratio( n, d : NATURAL) RETURN NATURAL;  -- return n/d when n MOD d = 0 else return 0, so ratio * d = n only when integer ratio > 0
+  FUNCTION ratio2(n, m : NATURAL) RETURN NATURAL;  -- return integer ratio of n/m or m/n, whichever is the largest
+ 
+  FUNCTION ceil_div(   n, d : NATURAL)  RETURN NATURAL;   -- ceil_div    = n/d + (n MOD d)/=0
+  FUNCTION ceil_value( n, d : NATURAL)  RETURN NATURAL;   -- ceil_value  = ceil_div(n, d) * d
+  FUNCTION floor_value(n, d : NATURAL)  RETURN NATURAL;   -- floor_value = (n/d) * d
+  FUNCTION ceil_div(   n : UNSIGNED; d: NATURAL) RETURN UNSIGNED;
+  FUNCTION ceil_value( n : UNSIGNED; d: NATURAL) RETURN UNSIGNED;
+  FUNCTION floor_value(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED;
+  
+  FUNCTION slv(n: IN STD_LOGIC)        RETURN STD_LOGIC_VECTOR;  -- standard logic to 1 element standard logic vector
+  FUNCTION sl( n: IN STD_LOGIC_VECTOR) RETURN STD_LOGIC;         -- 1 element standard logic vector to standard logic
+  
+  FUNCTION to_natural_arr(n : t_integer_arr; to_zero : BOOLEAN) RETURN t_natural_arr;  -- if to_zero=TRUE then negative numbers are forced to zero, otherwise they will give a compile range error
+  FUNCTION to_natural_arr(n : t_nat_natural_arr)                RETURN t_natural_arr;
+  FUNCTION to_integer_arr(n : t_natural_arr)                    RETURN t_integer_arr;
+  FUNCTION to_integer_arr(n : t_nat_natural_arr)                RETURN t_integer_arr;
+  FUNCTION to_slv_32_arr( n : t_integer_arr)                    RETURN t_slv_32_arr;
+  FUNCTION to_slv_32_arr( n : t_natural_arr)                    RETURN t_slv_32_arr;
+  
+  FUNCTION vector_tree(slv : STD_LOGIC_VECTOR; operation : STRING) RETURN STD_LOGIC;  -- Core operation tree function for vector "AND", "OR", "XOR"
+  FUNCTION vector_and(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- '1' when all slv bits are '1' else '0'
+  FUNCTION vector_or( slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- '0' when all slv bits are '0' else '1'
+  FUNCTION vector_xor(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- '1' when the slv has an odd number of '1' bits else '0'
+  FUNCTION vector_one_hot(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- Returns slv when it contains one hot bit, else returns 0.
+  
+  FUNCTION andv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- alias of vector_and
+  FUNCTION orv( slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- alias of vector_or
+  FUNCTION xorv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC;  -- alias of vector_xor
+  
+  FUNCTION matrix_and(mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC;  -- '1' when all matrix bits are '1' else '0'
+  FUNCTION matrix_or( mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC;  -- '0' when all matrix bits are '0' else '1'
+  
+  FUNCTION smallest(n, m    : INTEGER)       RETURN INTEGER;
+  FUNCTION smallest(n, m, l : INTEGER)       RETURN INTEGER;
+  FUNCTION smallest(n       : t_natural_arr) RETURN NATURAL;
+
+  FUNCTION largest(n, m : INTEGER)       RETURN INTEGER;
+  FUNCTION largest(n    : t_natural_arr) RETURN NATURAL;
+  
+  FUNCTION func_sum(    n : t_natural_arr)     RETURN NATURAL;      -- sum     of all elements in array
+  FUNCTION func_sum(    n : t_nat_natural_arr) RETURN NATURAL;
+  FUNCTION func_product(n : t_natural_arr)     RETURN NATURAL;      -- product of all elements in array
+  FUNCTION func_product(n : t_nat_natural_arr) RETURN NATURAL;
+  
+  FUNCTION "+" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise sum
+  FUNCTION "+" (L   : t_natural_arr; R : INTEGER)  RETURN t_natural_arr;  -- element wise sum
+  FUNCTION "+" (L   : INTEGER; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise sum
+  
+  FUNCTION "-" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise subtract
+  FUNCTION "-" (L, R: t_natural_arr)               RETURN t_integer_arr;  -- element wise subtract, support negative result
+  FUNCTION "-" (L   : t_natural_arr; R : INTEGER)  RETURN t_natural_arr;  -- element wise subtract
+  FUNCTION "-" (L   : INTEGER; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise subtract
+  
+  FUNCTION "*" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise product
+  FUNCTION "*" (L   : t_natural_arr; R : NATURAL)  RETURN t_natural_arr;  -- element wise product
+  FUNCTION "*" (L   : NATURAL; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise product
+  
+  FUNCTION "/" (L, R: t_natural_arr)               RETURN t_natural_arr;  -- element wise division
+  FUNCTION "/" (L   : t_natural_arr; R : POSITIVE) RETURN t_natural_arr;  -- element wise division
+  FUNCTION "/" (L   : NATURAL; R : t_natural_arr)  RETURN t_natural_arr;  -- element wise division
+  
+  FUNCTION is_true(a : STD_LOGIC) RETURN BOOLEAN;
+  FUNCTION is_true(a : STD_LOGIC) RETURN NATURAL;
+  FUNCTION is_true(a : BOOLEAN)   RETURN STD_LOGIC;
+  FUNCTION is_true(a : BOOLEAN)   RETURN NATURAL;
+  FUNCTION is_true(a : INTEGER)   RETURN BOOLEAN;    -- also covers NATURAL because it is a subtype of INTEGER
+  FUNCTION is_true(a : INTEGER)   RETURN STD_LOGIC;  -- also covers NATURAL because it is a subtype of INTEGER
+  
+  FUNCTION sel_a_b(sel,           a, b : BOOLEAN)           RETURN BOOLEAN;
+  FUNCTION sel_a_b(sel,           a, b : INTEGER)           RETURN INTEGER;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : INTEGER)           RETURN INTEGER;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : REAL)              RETURN REAL;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC)         RETURN STD_LOGIC;
+  FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC)         RETURN STD_LOGIC;
+  FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC_VECTOR)  RETURN STD_LOGIC_VECTOR;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC_VECTOR)  RETURN STD_LOGIC_VECTOR;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : SIGNED)            RETURN SIGNED;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : UNSIGNED)          RETURN UNSIGNED;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_integer_arr)     RETURN t_integer_arr;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_natural_arr)     RETURN t_natural_arr;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_integer_arr) RETURN t_nat_integer_arr;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_natural_arr) RETURN t_nat_natural_arr;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : STRING)            RETURN STRING;
+  FUNCTION sel_a_b(sel : INTEGER; a, b : STRING)            RETURN STRING;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : TIME)              RETURN TIME;
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : SEVERITY_LEVEL)    RETURN SEVERITY_LEVEL;
+  
+  -- sel_n() index sel = 0, 1, 2, ... will return a, b, c, ...
+  FUNCTION sel_n(sel : NATURAL; a, b, c                      : BOOLEAN) RETURN BOOLEAN;  --  3
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : BOOLEAN) RETURN BOOLEAN;  --  4
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : BOOLEAN) RETURN BOOLEAN;  --  5
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : BOOLEAN) RETURN BOOLEAN;  --  6
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : BOOLEAN) RETURN BOOLEAN;  --  7
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : BOOLEAN) RETURN BOOLEAN;  --  8
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : BOOLEAN) RETURN BOOLEAN;  --  9
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : BOOLEAN) RETURN BOOLEAN;  -- 10
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c                      : INTEGER) RETURN INTEGER;  --  3
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : INTEGER) RETURN INTEGER;  --  4
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : INTEGER) RETURN INTEGER;  --  5
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : INTEGER) RETURN INTEGER;  --  6
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : INTEGER) RETURN INTEGER;  --  7
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : INTEGER) RETURN INTEGER;  --  8
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : INTEGER) RETURN INTEGER;  --  9
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : INTEGER) RETURN INTEGER;  -- 10
+  
+  FUNCTION sel_n(sel : NATURAL; a, b                         : STRING) RETURN STRING;    --  2
+  FUNCTION sel_n(sel : NATURAL; a, b, c                      : STRING) RETURN STRING;    --  3
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : STRING) RETURN STRING;    --  4
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : STRING) RETURN STRING;    --  5
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : STRING) RETURN STRING;    --  6
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : STRING) RETURN STRING;    --  7
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : STRING) RETURN STRING;    --  8
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : STRING) RETURN STRING;    --  9
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : STRING) RETURN STRING;    -- 10
+  
+  FUNCTION array_init(init : STD_LOGIC; nof              : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init a unconstrained array of size 1
+  FUNCTION array_init(init,             nof              : NATURAL) RETURN t_natural_arr;     -- useful to init a unconstrained array of size 1
+  FUNCTION array_init(init,             nof              : NATURAL) RETURN t_nat_natural_arr; -- useful to init a unconstrained array of size 1
+  FUNCTION array_init(init,             nof, incr        : NATURAL) RETURN t_natural_arr;     -- useful to init an array with incrementing numbers
+  FUNCTION array_init(init,             nof, incr        : NATURAL) RETURN t_nat_natural_arr;
+  FUNCTION array_init(init,             nof, incr        : INTEGER) RETURN t_slv_16_arr;
+  FUNCTION array_init(init,             nof, incr        : INTEGER) RETURN t_slv_32_arr;
+  FUNCTION array_init(init,             nof, width       : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init an unconstrained std_logic_vector with repetitive content
+  FUNCTION array_init(init,             nof, width, incr : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init an unconstrained std_logic_vector with incrementing content
+  FUNCTION array_sinit(init : INTEGER;   nof, width       : NATURAL) RETURN STD_LOGIC_VECTOR;  -- useful to init an unconstrained std_logic_vector with repetitive content
+  
+  FUNCTION init_slv_64_matrix(nof_a, nof_b, k : INTEGER) RETURN t_slv_64_matrix;  -- initialize all elements in t_slv_64_matrix to value k
+  
+  -- Concatenate two or more STD_LOGIC_VECTORs into a single STD_LOGIC_VECTOR or extract one of them from a concatenated STD_LOGIC_VECTOR
+  FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a, b, c, d, e, f, g : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e, use_f        : BOOLEAN; a, b, c, d, e, f    : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d, use_e               : BOOLEAN; a, b, c, d, e       : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_concat(  use_a, use_b, use_c, use_d                      : BOOLEAN; a, b, c, d          : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_concat(  use_a, use_b, use_c                             : BOOLEAN; a, b, c             : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_concat(  use_a, use_b                                    : BOOLEAN; a, b                : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL) RETURN NATURAL;
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f        : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w      : NATURAL) RETURN NATURAL;
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e               : BOOLEAN; a_w, b_w, c_w, d_w, e_w           : NATURAL) RETURN NATURAL;
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d                      : BOOLEAN; a_w, b_w, c_w, d_w                : NATURAL) RETURN NATURAL;
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c                             : BOOLEAN; a_w, b_w, c_w                     : NATURAL) RETURN NATURAL;
+  FUNCTION func_slv_concat_w(use_a, use_b                                    : BOOLEAN; a_w, b_w                          : NATURAL) RETURN NATURAL;
+  FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e, use_f        : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w      : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_extract( use_a, use_b, use_c, use_d, use_e               : BOOLEAN; a_w, b_w, c_w, d_w, e_w           : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_extract( use_a, use_b, use_c, use_d                      : BOOLEAN; a_w, b_w, c_w, d_w                : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_extract( use_a, use_b, use_c                             : BOOLEAN; a_w, b_w, c_w                     : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_slv_extract( use_a, use_b                                    : BOOLEAN; a_w, b_w                          : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR;
+  
+  FUNCTION TO_UINT(vec : STD_LOGIC_VECTOR) RETURN NATURAL;  -- beware: NATURAL'HIGH = 2**31-1, not 2*32-1, use TO_SINT to avoid warning
+  FUNCTION TO_SINT(vec : STD_LOGIC_VECTOR) RETURN INTEGER;
+  
+  FUNCTION TO_UVEC(dec, w : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION TO_SVEC(dec, w : INTEGER) RETURN STD_LOGIC_VECTOR;
+  
+  FUNCTION TO_SVEC_32(dec : INTEGER) RETURN STD_LOGIC_VECTOR;  -- = TO_SVEC() with w=32 for t_slv_32_arr slv elements
+    
+-- The RESIZE for SIGNED in IEEE.NUMERIC_STD extends the sign bit or it keeps the sign bit and LS part. This
+  -- behaviour of preserving the sign bit is less suitable for DSP and not necessary in general. A more
+  -- appropriate approach is to ignore the MSbit sign and just keep the LS part. For too large values this 
+  -- means that the result gets wrapped, but that is fine for default behaviour, because that is also what
+  -- happens for RESIZE of UNSIGNED. Therefor this is what the RESIZE_NUM for SIGNED and the RESIZE_SVEC do
+  -- and better not use RESIZE for SIGNED anymore.
+  FUNCTION RESIZE_NUM( u   : UNSIGNED;         w : NATURAL) RETURN UNSIGNED;          -- left extend with '0' or keep LS part (same as RESIZE for UNSIGNED)
+  FUNCTION RESIZE_NUM( s   : SIGNED;           w : NATURAL) RETURN SIGNED;            -- extend sign bit or keep LS part
+  FUNCTION RESIZE_UVEC(sl  : STD_LOGIC;        w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- left extend with '0' into slv
+  FUNCTION RESIZE_UVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- left extend with '0' or keep LS part
+  FUNCTION RESIZE_SVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- extend sign bit or keep LS part
+  FUNCTION RESIZE_UINT(u   : INTEGER;          w : NATURAL) RETURN INTEGER;           -- left extend with '0' or keep LS part
+  FUNCTION RESIZE_SINT(s   : INTEGER;          w : NATURAL) RETURN INTEGER;           -- extend sign bit or keep LS part
+  
+  FUNCTION RESIZE_UVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- = RESIZE_UVEC() with w=32 for t_slv_32_arr slv elements
+  FUNCTION RESIZE_SVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- = RESIZE_SVEC() with w=32 for t_slv_32_arr slv elements
+  
+  FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER)  RETURN STD_LOGIC_VECTOR;
+  FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : UNSIGNED) RETURN STD_LOGIC_VECTOR; 
+  FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER)  RETURN STD_LOGIC_VECTOR;
+  FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : SIGNED)   RETURN STD_LOGIC_VECTOR; 
+                                                                                                                   -- Used in common_add_sub.vhd
+  FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec + r_vec, treat slv operands as signed,   slv output width is res_w
+  FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec - r_vec, treat slv operands as signed,   slv output width is res_w
+  FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec + r_vec, treat slv operands as unsigned, slv output width is res_w
+  FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- l_vec - r_vec, treat slv operands as unsigned, slv output width is res_w
+  
+  FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec + r_vec, treat slv operands as signed,   slv output width is l_vec'LENGTH
+  FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec - r_vec, treat slv operands as signed,   slv output width is l_vec'LENGTH
+  FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec + r_vec, treat slv operands as unsigned, slv output width is l_vec'LENGTH
+  FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;                   -- l_vec - r_vec, treat slv operands as unsigned, slv output width is l_vec'LENGTH
+  
+  FUNCTION COMPLEX_MULT_REAL(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER;  -- Calculate real part of complex multiplication: a_re*b_re - a_im*b_im 
+  FUNCTION COMPLEX_MULT_IMAG(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER;  -- Calculate imag part of complex multiplication: a_im*b_re + a_re*b_im 
+  
+  FUNCTION SHIFT_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR;  -- < 0 shift left, > 0 shift right
+  FUNCTION SHIFT_SVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR;  -- < 0 shift left, > 0 shift right
+  
+  FUNCTION offset_binary(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  
+  FUNCTION truncate(                vec : STD_LOGIC_VECTOR; n              : NATURAL) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec, so result has width vec'LENGTH-n
+  FUNCTION truncate_and_resize_uvec(vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec and then resize to width w
+  FUNCTION truncate_and_resize_svec(vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
+  FUNCTION scale(                   vec : STD_LOGIC_VECTOR; n:               NATURAL) RETURN STD_LOGIC_VECTOR;  -- add n '0' LSBits to vec
+  FUNCTION scale_and_resize_uvec(   vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- add n '0' LSBits to vec and then resize to width w
+  FUNCTION scale_and_resize_svec(   vec : STD_LOGIC_VECTOR; n,           w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
+  FUNCTION truncate_or_resize_uvec( vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- when b=TRUE then truncate to width w, else resize to width w
+  FUNCTION truncate_or_resize_svec( vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
+  
+  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n, and clip to avoid wrap
+  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n
+  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem but round up to +infinity (s_round_up = u_round)
+  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- idem but round up to +infinity (s_round_up = u_round)
+  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
+  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
+
+  FUNCTION hton(a : STD_LOGIC_VECTOR; w, sz : NATURAL) RETURN STD_LOGIC_VECTOR;  -- convert endianity from host to network, sz in symbols of width w
+  FUNCTION hton(a : STD_LOGIC_VECTOR;    sz : NATURAL) RETURN STD_LOGIC_VECTOR;  -- convert endianity from host to network, sz in bytes
+  FUNCTION hton(a : STD_LOGIC_VECTOR                 ) RETURN STD_LOGIC_VECTOR;  -- convert endianity from host to network, for all bytes in a
+  FUNCTION ntoh(a : STD_LOGIC_VECTOR;    sz : NATURAL) RETURN STD_LOGIC_VECTOR;  -- convert endianity from network to host, sz in bytes, ntoh() = hton()
+  FUNCTION ntoh(a : STD_LOGIC_VECTOR                 ) RETURN STD_LOGIC_VECTOR;  -- convert endianity from network to host, for all bytes in a, ntoh() = hton()
+  
+  FUNCTION flip(a : STD_LOGIC_VECTOR)  RETURN STD_LOGIC_VECTOR;  -- bit flip a vector, map a[h:0] to [0:h]
+  FUNCTION flip(a, w : NATURAL)        RETURN NATURAL;           -- bit flip a vector, map a[h:0] to [0:h], h = w-1
+  FUNCTION flip(a : t_slv_32_arr)      RETURN t_slv_32_arr;
+  FUNCTION flip(a : t_integer_arr)     RETURN t_integer_arr;
+  FUNCTION flip(a : t_natural_arr)     RETURN t_natural_arr;
+  FUNCTION flip(a : t_nat_natural_arr) RETURN t_nat_natural_arr;
+  
+  FUNCTION transpose(a : STD_LOGIC_VECTOR; row, col : NATURAL) RETURN STD_LOGIC_VECTOR;  -- transpose a vector, map a[i*row+j] to output index [j*col+i]
+  FUNCTION transpose(a,                    row, col : NATURAL) RETURN NATURAL;           -- transpose index a = [i*row+j] to output index [j*col+i]
+
+  FUNCTION split_w(input_w: NATURAL; min_out_w: NATURAL; max_out_w: NATURAL) RETURN NATURAL;
+
+  FUNCTION pad(str: STRING; width: NATURAL; pad_char: CHARACTER) RETURN STRING;
+
+  FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING;
+  FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL; pad_char: CHARACTER) RETURN STRING;
+  FUNCTION slice_dn(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING;
+
+  FUNCTION nat_arr_to_concat_slv(nat_arr: t_natural_arr; nof_elements: NATURAL) RETURN STD_LOGIC_VECTOR;
+
+  ------------------------------------------------------------------------------
+  -- Component specific functions
+  ------------------------------------------------------------------------------
+
+  -- common_fifo_*  
+  PROCEDURE proc_common_fifo_asserts (CONSTANT c_fifo_name   : IN STRING;
+                                      CONSTANT c_note_is_ful : IN BOOLEAN;
+                                      CONSTANT c_fail_rd_emp : IN BOOLEAN;
+                                      SIGNAL   wr_rst        : IN STD_LOGIC;
+                                      SIGNAL   wr_clk        : IN STD_LOGIC;
+                                      SIGNAL   wr_full       : IN STD_LOGIC;
+                                      SIGNAL   wr_en         : IN STD_LOGIC;
+                                      SIGNAL   rd_clk        : IN STD_LOGIC;
+                                      SIGNAL   rd_empty      : IN STD_LOGIC;
+                                      SIGNAL   rd_en         : IN STD_LOGIC);
+  
+  -- common_fanout_tree  
+  FUNCTION func_common_fanout_tree_pipelining(c_nof_stages, c_nof_output_per_cell, c_nof_output : NATURAL;
+                                              c_cell_pipeline_factor_arr, c_cell_pipeline_arr : t_natural_arr) RETURN t_natural_arr;
+  
+  -- common_reorder_symbol 
+  FUNCTION func_common_reorder2_is_there(I, J : NATURAL) RETURN BOOLEAN;
+  FUNCTION func_common_reorder2_is_active(I, J, N : NATURAL) RETURN BOOLEAN;
+  FUNCTION func_common_reorder2_get_select_index(I, J, N : NATURAL) RETURN INTEGER;
+  FUNCTION func_common_reorder2_get_select(I, J, N : NATURAL; select_arr : t_natural_arr) RETURN NATURAL;
+  FUNCTION func_common_reorder2_inverse_select(N : NATURAL; select_arr : t_natural_arr) RETURN t_natural_arr;
+  
+  -- Generate faster sample SCLK from digital DCLK for sim only
+  PROCEDURE proc_common_dclk_generate_sclk(CONSTANT Pfactor : IN    POSITIVE;
+                                           SIGNAL   dclk    : IN    STD_LOGIC;
+                                           SIGNAL   sclk    : INOUT STD_LOGIC);
+  
+END common_pkg;
+
+PACKAGE BODY common_pkg IS
+
+  FUNCTION pow2(n : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN 2**n;
+  END;
+
+  FUNCTION ceil_pow2(n : INTEGER) RETURN NATURAL IS
+  -- Also allows negative exponents and rounds up before returning the value
+  BEGIN
+    RETURN natural(integer(ceil(2**real(n))));
+  END;
+  
+  FUNCTION true_log2(n : NATURAL) RETURN NATURAL IS
+  -- Purpose: For calculating extra vector width of existing vector
+  -- Description: Return mathematical ceil(log2(n))
+  --   n    log2()
+  --   0 -> -oo  --> FAILURE
+  --   1 ->  0
+  --   2 ->  1
+  --   3 ->  2
+  --   4 ->  2
+  --   5 ->  3
+  --   6 ->  3
+  --   7 ->  3
+  --   8 ->  3
+  --   9 ->  4
+  --   etc, up to n = NATURAL'HIGH = 2**31-1
+  BEGIN
+    RETURN natural(integer(ceil(log2(real(n)))));
+  END;
+  
+  FUNCTION ceil_log2(n : NATURAL) RETURN NATURAL IS
+  -- Purpose: For calculating vector width of new vector 
+  -- Description:
+  --   Same as true_log2() except ceil_log2(1) = 1, which is needed to support
+  --   the vector width width for 1 address, to avoid NULL array for single
+  --   word register address.
+  --   If n = 0, return 0 so we get a NULL array when using 
+  --   STD_LOGIC_VECTOR(ceil_log2(g_addr_w)-1 DOWNTO 0), instead of an error.
+  BEGIN
+    IF n = 0 THEN
+      RETURN 0;  -- Get NULL array
+    ELSIF n = 1 THEN
+      RETURN 1;  -- avoid NULL array
+    ELSE
+      RETURN true_log2(n);
+    END IF;
+  END;
+
+  FUNCTION floor_log10(n : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN natural(integer(floor(log10(real(n)))));
+  END;
+  
+  FUNCTION is_pow2(n : NATURAL) RETURN BOOLEAN IS
+  BEGIN
+    RETURN n=2**true_log2(n);
+  END;
+  
+  FUNCTION true_log_pow2(n : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN 2**true_log2(n);
+  END;
+  
+  FUNCTION ratio(n, d : NATURAL) RETURN NATURAL IS
+  BEGIN
+    IF n MOD d = 0 THEN
+      RETURN n/d;
+    ELSE
+      RETURN 0;
+    END IF;
+  END;
+  
+  FUNCTION ratio2(n, m : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN largest(ratio(n,m), ratio(m,n));
+  END;
+  
+  FUNCTION ceil_div(n, d : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN n/d + sel_a_b(n MOD d = 0, 0, 1);
+  END;
+  
+  FUNCTION ceil_value(n, d : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN ceil_div(n, d) * d;
+  END;
+  
+  FUNCTION floor_value(n, d : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN (n / d) * d;
+  END;
+  
+  FUNCTION ceil_div(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED IS
+  BEGIN
+    RETURN n/d + sel_a_b(n MOD d = 0, 0, 1);  -- "/" returns same width as n
+  END;
+  
+  FUNCTION ceil_value(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED IS
+    CONSTANT w : NATURAL := n'LENGTH;
+    VARIABLE p : UNSIGNED(2*w-1 DOWNTO 0);
+  BEGIN
+    p := ceil_div(n, d) * d;
+    RETURN p(w-1 DOWNTO 0);  -- return same width as n
+  END;
+  
+  FUNCTION floor_value(n : UNSIGNED; d: NATURAL) RETURN UNSIGNED IS
+    CONSTANT w : NATURAL := n'LENGTH;
+    VARIABLE p : UNSIGNED(2*w-1 DOWNTO 0);
+  BEGIN
+    p := (n / d) * d;
+    RETURN p(w-1 DOWNTO 0);  -- return same width as n
+  END;
+  
+  FUNCTION slv(n: IN STD_LOGIC) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE r : STD_LOGIC_VECTOR(0 DOWNTO 0);
+  BEGIN
+    r(0) := n;
+    RETURN r;
+  END;
+  
+  FUNCTION sl(n: IN STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+    VARIABLE r : STD_LOGIC;
+  BEGIN
+    r := n(n'LOW);
+    RETURN r;
+  END;
+  
+  FUNCTION to_natural_arr(n : t_integer_arr; to_zero : BOOLEAN) RETURN t_natural_arr IS
+    VARIABLE vN : t_integer_arr(n'LENGTH-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := n;
+    FOR I IN vN'RANGE LOOP
+      IF to_zero=FALSE THEN
+        vR(I) := vN(I);
+      ELSE
+        vR(I) := 0;
+        IF vN(I)>0 THEN
+          vR(I) := vN(I);
+        END IF;
+      END IF;
+    END LOOP;
+    RETURN vR;
+  END;
+  
+  FUNCTION to_natural_arr(n : t_nat_natural_arr) RETURN t_natural_arr IS
+    VARIABLE vN : t_nat_natural_arr(n'LENGTH-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := n;
+    FOR I IN vN'RANGE LOOP
+      vR(I) := vN(I);
+    END LOOP;
+    RETURN vR;
+  END;
+  
+  FUNCTION to_integer_arr(n : t_natural_arr) RETURN t_integer_arr IS
+    VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+    VARIABLE vR : t_integer_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := n;
+    FOR I IN vN'RANGE LOOP
+      vR(I) := vN(I);
+    END LOOP;
+    RETURN vR;
+  END;
+  
+  FUNCTION to_integer_arr(n : t_nat_natural_arr) RETURN t_integer_arr IS
+    VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := to_natural_arr(n);
+    RETURN to_integer_arr(vN);
+  END;
+  
+  FUNCTION to_slv_32_arr(n : t_integer_arr) RETURN t_slv_32_arr IS
+    VARIABLE vN : t_integer_arr(n'LENGTH-1 DOWNTO 0);
+    VARIABLE vR : t_slv_32_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := n;
+    FOR I IN vN'RANGE LOOP
+      vR(I) := TO_SVEC(vN(I), 32);
+    END LOOP;
+    RETURN vR;
+  END;
+  
+  FUNCTION to_slv_32_arr(n : t_natural_arr) RETURN t_slv_32_arr IS
+    VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+    VARIABLE vR : t_slv_32_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := n;
+    FOR I IN vN'RANGE LOOP
+      vR(I) := TO_UVEC(vN(I), 32);
+    END LOOP;
+    RETURN vR;
+  END;
+  
+  FUNCTION vector_tree(slv : STD_LOGIC_VECTOR; operation : STRING) RETURN STD_LOGIC IS
+    -- Linear loop to determine result takes combinatorial delay that is proportional to slv'LENGTH:
+    --   FOR I IN slv'RANGE LOOP
+    --     v_result := v_result OPERATION slv(I);
+    --   END LOOP;
+    --   RETURN v_result;
+    -- Instead use binary tree to determine result with smallest combinatorial delay that depends on log2(slv'LENGTH)
+    CONSTANT c_slv_w      : NATURAL := slv'LENGTH;
+    CONSTANT c_nof_stages : NATURAL := ceil_log2(c_slv_w);
+    CONSTANT c_w          : NATURAL := 2**c_nof_stages;  -- extend the input slv to a vector with length power of 2 to ease using binary tree
+    TYPE t_stage_arr IS ARRAY (-1 TO c_nof_stages-1) OF STD_LOGIC_VECTOR(c_w-1 DOWNTO 0);
+    VARIABLE v_stage_arr  : t_stage_arr;
+    VARIABLE v_result     : STD_LOGIC := '0';
+  BEGIN
+    -- default any unused, the stage results will be kept in the LSBits and the last result in bit 0
+    IF    operation="AND" THEN v_stage_arr := (OTHERS=>(OTHERS=>'1'));
+    ELSIF operation="OR"  THEN v_stage_arr := (OTHERS=>(OTHERS=>'0'));
+    ELSIF operation="XOR" THEN v_stage_arr := (OTHERS=>(OTHERS=>'0'));
+    ELSE
+      ASSERT TRUE REPORT "common_pkg: Unsupported vector_tree operation" SEVERITY FAILURE;
+    END IF;
+    v_stage_arr(-1)(c_slv_w-1 DOWNTO 0) := slv;  -- any unused input c_w : c_slv_w bits have void default value
+    FOR J IN 0 TO c_nof_stages-1 LOOP
+      FOR I IN 0 TO c_w/(2**(J+1))-1 LOOP
+        IF    operation="AND" THEN v_stage_arr(J)(I) := v_stage_arr(J-1)(2*I) AND v_stage_arr(J-1)(2*I+1);
+        ELSIF operation="OR"  THEN v_stage_arr(J)(I) := v_stage_arr(J-1)(2*I) OR  v_stage_arr(J-1)(2*I+1);
+        ELSIF operation="XOR" THEN v_stage_arr(J)(I) := v_stage_arr(J-1)(2*I) XOR v_stage_arr(J-1)(2*I+1);
+        END IF;
+      END LOOP;
+    END LOOP;
+    RETURN v_stage_arr(c_nof_stages-1)(0);
+  END;  
+  
+  FUNCTION vector_and(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+  BEGIN
+    RETURN vector_tree(slv, "AND");
+  END;
+  
+  FUNCTION vector_or(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+  BEGIN
+    RETURN vector_tree(slv, "OR");
+  END;
+
+  FUNCTION vector_xor(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+  BEGIN
+    RETURN vector_tree(slv, "XOR");
+  END;
+
+  FUNCTION vector_one_hot(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_one_hot : BOOLEAN := FALSE;
+    VARIABLE v_zeros   : STD_LOGIC_VECTOR(slv'RANGE) := (OTHERS=>'0');
+  BEGIN
+    FOR i IN slv'RANGE LOOP
+      IF slv(i) = '1' THEN
+        IF NOT(v_one_hot) THEN
+          -- No hot bits found so far
+          v_one_hot := TRUE;
+        ELSE
+          -- This is the second hot bit found; return zeros.
+          RETURN v_zeros;
+        END IF;
+      END IF;
+    END LOOP;
+    -- No or a single hot bit found in slv; return slv.
+    RETURN slv;
+  END;
+  
+  FUNCTION andv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+  BEGIN
+    RETURN vector_tree(slv, "AND");
+  END;
+  
+  FUNCTION orv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+  BEGIN
+    RETURN vector_tree(slv, "OR");
+  END;
+  
+  FUNCTION xorv(slv : STD_LOGIC_VECTOR) RETURN STD_LOGIC IS
+  BEGIN
+    RETURN vector_tree(slv, "XOR");
+  END;
+  
+  FUNCTION matrix_and(mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC IS
+    VARIABLE v_mat    : t_sl_matrix(0 TO wi-1, 0 TO wj-1) := mat;  -- map to fixed range
+    VARIABLE v_result : STD_LOGIC := '1';
+  BEGIN
+    FOR I IN 0 TO wi-1 LOOP
+      FOR J IN 0 TO wj-1 LOOP
+        v_result := v_result AND v_mat(I,J);
+      END LOOP;
+    END LOOP;
+    RETURN v_result;
+  END;
+  
+  FUNCTION matrix_or(mat : t_sl_matrix; wi, wj : NATURAL) RETURN STD_LOGIC IS
+    VARIABLE v_mat    : t_sl_matrix(0 TO wi-1, 0 TO wj-1) := mat;  -- map to fixed range
+    VARIABLE v_result : STD_LOGIC := '0';
+  BEGIN
+    FOR I IN 0 TO wi-1 LOOP
+      FOR J IN 0 TO wj-1 LOOP
+        v_result := v_result OR v_mat(I,J);
+      END LOOP;
+    END LOOP;
+    RETURN v_result;
+  END;
+  
+  FUNCTION smallest(n, m : INTEGER) RETURN INTEGER IS
+  BEGIN
+    IF n < m THEN
+      RETURN n;
+    ELSE
+      RETURN m;
+    END IF;
+  END;
+  
+  FUNCTION smallest(n, m, l : INTEGER) RETURN INTEGER IS
+    VARIABLE v : NATURAL;
+  BEGIN
+                  v := n;
+    IF v > m THEN v := m; END IF;
+    IF v > l THEN v := l; END IF;
+    RETURN v;
+  END;
+
+  FUNCTION smallest(n : t_natural_arr) RETURN NATURAL IS
+    VARIABLE m : NATURAL := 0;
+  BEGIN
+    FOR I IN n'RANGE LOOP
+      IF n(I) < m THEN
+        m := n(I);
+      END IF;
+    END LOOP;
+    RETURN m;
+  END;
+  
+  FUNCTION largest(n, m : INTEGER) RETURN INTEGER IS
+  BEGIN
+    IF n > m THEN
+      RETURN n;
+    ELSE
+      RETURN m;
+    END IF;
+  END;
+  
+  FUNCTION largest(n : t_natural_arr) RETURN NATURAL IS
+    VARIABLE m : NATURAL := 0;
+  BEGIN
+    FOR I IN n'RANGE LOOP
+      IF n(I) > m THEN
+        m := n(I);
+      END IF;
+    END LOOP;
+    RETURN m;
+  END;
+  
+  FUNCTION func_sum(n : t_natural_arr) RETURN NATURAL IS
+    VARIABLE vS : NATURAL;
+  BEGIN
+    vS := 0;
+    FOR I IN n'RANGE LOOP
+      vS := vS + n(I);
+    END LOOP;
+    RETURN vS;
+  END;
+  
+  FUNCTION func_sum(n : t_nat_natural_arr) RETURN NATURAL IS
+    VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := to_natural_arr(n);
+    RETURN func_sum(vN);
+  END;
+  
+  FUNCTION func_product(n : t_natural_arr) RETURN NATURAL IS
+    VARIABLE vP : NATURAL;
+  BEGIN
+    vP := 1;
+    FOR I IN n'RANGE LOOP
+      vP := vP * n(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION func_product(n : t_nat_natural_arr) RETURN NATURAL IS
+    VARIABLE vN : t_natural_arr(n'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vN := to_natural_arr(n);
+    RETURN func_product(vN);
+  END;
+  
+  FUNCTION "+" (L, R: t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    vR := R;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) + vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "+" (L: t_natural_arr; R : INTEGER) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) + R;
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "+" (L: INTEGER; R : t_natural_arr) RETURN t_natural_arr IS
+  BEGIN
+    RETURN R + L;
+  END;
+  
+  FUNCTION "-" (L, R: t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    vR := R;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) - vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "-" (L, R: t_natural_arr) RETURN t_integer_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_integer_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    vR := R;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) - vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "-" (L: t_natural_arr; R : INTEGER) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) - R;
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "-" (L: INTEGER; R : t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := R'LENGTH;
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vR := R;
+    FOR I IN vR'RANGE LOOP
+      vP(I) := L - vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "*" (L, R: t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    vR := R;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) * vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "*" (L: t_natural_arr; R : NATURAL) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) * R;
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "*" (L: NATURAL; R : t_natural_arr) RETURN t_natural_arr IS
+  BEGIN
+    RETURN R * L;
+  END;
+  
+  FUNCTION "/" (L, R: t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    vR := R;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) / vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "/" (L: t_natural_arr; R : POSITIVE) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := L'LENGTH;
+    VARIABLE vL : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vL := L;
+    FOR I IN vL'RANGE LOOP
+      vP(I) := vL(I) / R;
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION "/" (L: NATURAL; R : t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT w  : NATURAL := R'LENGTH;
+    VARIABLE vR : t_natural_arr(w-1 DOWNTO 0);
+    VARIABLE vP : t_natural_arr(w-1 DOWNTO 0);
+  BEGIN
+    vR := R;
+    FOR I IN vR'RANGE LOOP
+      vP(I) := L / vR(I);
+    END LOOP;
+    RETURN vP;
+  END;
+  
+  FUNCTION is_true(a : STD_LOGIC) RETURN BOOLEAN   IS BEGIN IF a='1'  THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END;
+  FUNCTION is_true(a : STD_LOGIC) RETURN NATURAL   IS BEGIN IF a='1'  THEN RETURN 1;    ELSE RETURN 0;     END IF; END;
+  FUNCTION is_true(a : BOOLEAN)   RETURN STD_LOGIC IS BEGIN IF a=TRUE THEN RETURN '1';  ELSE RETURN '0';   END IF; END;  
+  FUNCTION is_true(a : BOOLEAN)   RETURN NATURAL   IS BEGIN IF a=TRUE THEN RETURN 1;    ELSE RETURN 0;     END IF; END;  
+  FUNCTION is_true(a : INTEGER)   RETURN BOOLEAN   IS BEGIN IF a/=0   THEN RETURN TRUE; ELSE RETURN FALSE; END IF; END;
+  FUNCTION is_true(a : INTEGER)   RETURN STD_LOGIC IS BEGIN IF a/=0   THEN RETURN '1';  ELSE RETURN '0';   END IF; END;
+  
+  FUNCTION sel_a_b(sel, a, b : INTEGER) RETURN INTEGER IS
+  BEGIN
+    IF sel /= 0 THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+
+  FUNCTION sel_a_b(sel, a, b : BOOLEAN) RETURN BOOLEAN IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : INTEGER) RETURN INTEGER IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : REAL) RETURN REAL IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC) RETURN STD_LOGIC IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC) RETURN STD_LOGIC IS
+  BEGIN
+    IF sel /= 0 THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : INTEGER; a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    IF sel /= 0 THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : SIGNED) RETURN SIGNED IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : UNSIGNED) RETURN UNSIGNED IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_integer_arr) RETURN t_integer_arr IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_natural_arr) RETURN t_natural_arr IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_integer_arr) RETURN t_nat_integer_arr IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : t_nat_natural_arr) RETURN t_nat_natural_arr IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : STRING) RETURN STRING IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : INTEGER; a, b : STRING) RETURN STRING IS
+  BEGIN
+    IF sel /= 0 THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : TIME) RETURN TIME IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+
+  FUNCTION sel_a_b(sel : BOOLEAN; a, b : SEVERITY_LEVEL) RETURN SEVERITY_LEVEL IS
+  BEGIN
+    IF sel = TRUE THEN
+      RETURN a;
+    ELSE
+      RETURN b;
+    END IF;
+  END;
+  
+  -- sel_n : boolean
+  FUNCTION sel_n(sel : NATURAL; a, b, c : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g, h);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g, h, i);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : BOOLEAN) RETURN BOOLEAN IS
+    CONSTANT c_arr : t_nat_boolean_arr := (a, b, c, d, e, f, g, h, i, j);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  -- sel_n : integer
+  FUNCTION sel_n(sel : NATURAL; a, b, c : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g, h);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g, h, i);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : INTEGER) RETURN INTEGER IS
+    CONSTANT c_arr : t_nat_integer_arr := (a, b, c, d, e, f, g, h, i, j);
+  BEGIN
+    RETURN c_arr(sel);
+  END;
+  
+  -- sel_n : string
+  FUNCTION sel_n(sel : NATURAL; a, b                         : STRING) RETURN STRING IS BEGIN IF sel=0 THEN RETURN            a                         ; ELSE RETURN b; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c                      : STRING) RETURN STRING IS BEGIN IF sel<2 THEN RETURN sel_n(sel, a, b                     ); ELSE RETURN c; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d                   : STRING) RETURN STRING IS BEGIN IF sel<3 THEN RETURN sel_n(sel, a, b, c                  ); ELSE RETURN d; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e                : STRING) RETURN STRING IS BEGIN IF sel<4 THEN RETURN sel_n(sel, a, b, c, d               ); ELSE RETURN e; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f             : STRING) RETURN STRING IS BEGIN IF sel<5 THEN RETURN sel_n(sel, a, b, c, d, e            ); ELSE RETURN f; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g          : STRING) RETURN STRING IS BEGIN IF sel<6 THEN RETURN sel_n(sel, a, b, c, d, e, f         ); ELSE RETURN g; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h       : STRING) RETURN STRING IS BEGIN IF sel<7 THEN RETURN sel_n(sel, a, b, c, d, e, f, g      ); ELSE RETURN h; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i    : STRING) RETURN STRING IS BEGIN IF sel<8 THEN RETURN sel_n(sel, a, b, c, d, e, f, g, h   ); ELSE RETURN i; END IF; END;
+  FUNCTION sel_n(sel : NATURAL; a, b, c, d, e, f, g, h, i, j : STRING) RETURN STRING IS BEGIN IF sel<9 THEN RETURN sel_n(sel, a, b, c, d, e, f, g, h, i); ELSE RETURN j; END IF; END;
+  
+  FUNCTION array_init(init : STD_LOGIC; nof : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_arr : STD_LOGIC_VECTOR(0 TO nof-1);
+  BEGIN
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := init;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_init(init, nof : NATURAL) RETURN t_natural_arr IS
+    VARIABLE v_arr : t_natural_arr(0 TO nof-1);
+  BEGIN
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := init;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_init(init, nof : NATURAL) RETURN t_nat_natural_arr IS
+    VARIABLE v_arr : t_nat_natural_arr(0 TO nof-1);
+  BEGIN
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := init;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_init(init, nof, incr : NATURAL) RETURN t_natural_arr IS
+    VARIABLE v_arr : t_natural_arr(0 TO nof-1);
+    VARIABLE v_i   : NATURAL;
+  BEGIN
+    v_i := 0;
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := init + v_i * incr;
+      v_i := v_i + 1;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_init(init, nof, incr : NATURAL) RETURN t_nat_natural_arr IS
+    VARIABLE v_arr : t_nat_natural_arr(0 TO nof-1);
+    VARIABLE v_i   : NATURAL;
+  BEGIN
+    v_i := 0;
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := init + v_i * incr;
+      v_i := v_i + 1;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_init(init, nof, incr : INTEGER) RETURN t_slv_16_arr IS
+    VARIABLE v_arr : t_slv_16_arr(0 TO nof-1);
+    VARIABLE v_i   : NATURAL;
+  BEGIN
+    v_i := 0;
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := TO_SVEC(init + v_i * incr, 16);
+      v_i := v_i + 1;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_init(init, nof, incr : INTEGER) RETURN t_slv_32_arr IS
+    VARIABLE v_arr : t_slv_32_arr(0 TO nof-1);
+    VARIABLE v_i   : NATURAL;
+  BEGIN
+    v_i := 0;
+    FOR I IN v_arr'RANGE LOOP
+      v_arr(I) := TO_SVEC(init + v_i * incr, 32);
+      v_i := v_i + 1;
+    END LOOP;
+    RETURN v_arr;
+  END;
+
+  FUNCTION array_init(init, nof, width : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_arr : STD_LOGIC_VECTOR(nof*width-1 DOWNTO 0);
+  BEGIN
+    FOR I IN 0 TO nof-1 LOOP
+      v_arr(width*(I+1)-1 DOWNTO width*I) := TO_UVEC(init, width);
+    END LOOP;
+    RETURN v_arr;
+  END;
+
+  FUNCTION array_init(init, nof, width, incr : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_arr : STD_LOGIC_VECTOR(nof*width-1 DOWNTO 0);
+    VARIABLE v_i   : NATURAL;
+  BEGIN
+    v_i := 0;
+    FOR I IN 0 TO nof-1 LOOP
+      v_arr(width*(I+1)-1 DOWNTO width*I) := TO_UVEC(init + v_i * incr, width);
+      v_i := v_i + 1;
+    END LOOP;
+    RETURN v_arr;
+  END;
+  
+  FUNCTION array_sinit(init :INTEGER; nof, width : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_arr : STD_LOGIC_VECTOR(nof*width-1 DOWNTO 0);
+  BEGIN
+    FOR I IN 0 TO nof-1 LOOP
+      v_arr(width*(I+1)-1 DOWNTO width*I) := TO_SVEC(init, width);
+    END LOOP;
+    RETURN v_arr;
+  END;
+
+  FUNCTION init_slv_64_matrix(nof_a, nof_b, k : INTEGER) RETURN t_slv_64_matrix IS
+    VARIABLE v_mat : t_slv_64_matrix(nof_a-1 DOWNTO 0, nof_b-1 DOWNTO 0);
+  BEGIN
+    FOR I IN 0 TO nof_a-1 LOOP
+      FOR J IN 0 TO nof_b-1 LOOP
+        v_mat(I,J) := TO_SVEC(k, 64);
+      END LOOP;
+    END LOOP;
+    RETURN v_mat;
+  END;
+  
+  
+  -- Support concatenation of up to 7 slv into 1 slv
+  FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a, b, c, d, e, f, g : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_max_w : NATURAL := a'LENGTH + b'LENGTH + c'LENGTH + d'LENGTH + e'LENGTH + f'LENGTH + g'LENGTH;
+    VARIABLE v_res   : STD_LOGIC_VECTOR(c_max_w-1 DOWNTO 0) := (OTHERS=>'0');
+    VARIABLE v_len   : NATURAL := 0;
+  BEGIN
+    IF use_a = TRUE THEN v_res(a'LENGTH-1 + v_len DOWNTO v_len) := a; v_len := v_len + a'LENGTH; END IF;
+    IF use_b = TRUE THEN v_res(b'LENGTH-1 + v_len DOWNTO v_len) := b; v_len := v_len + b'LENGTH; END IF;
+    IF use_c = TRUE THEN v_res(c'LENGTH-1 + v_len DOWNTO v_len) := c; v_len := v_len + c'LENGTH; END IF;
+    IF use_d = TRUE THEN v_res(d'LENGTH-1 + v_len DOWNTO v_len) := d; v_len := v_len + d'LENGTH; END IF;
+    IF use_e = TRUE THEN v_res(e'LENGTH-1 + v_len DOWNTO v_len) := e; v_len := v_len + e'LENGTH; END IF;
+    IF use_f = TRUE THEN v_res(f'LENGTH-1 + v_len DOWNTO v_len) := f; v_len := v_len + f'LENGTH; END IF;
+    IF use_g = TRUE THEN v_res(g'LENGTH-1 + v_len DOWNTO v_len) := g; v_len := v_len + g'LENGTH; END IF;
+    RETURN v_res(v_len-1 DOWNTO 0);
+  END func_slv_concat;
+  
+  FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f : BOOLEAN; a, b, c, d, e, f : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_concat(use_a, use_b, use_c, use_d, use_e, use_f, FALSE, a, b, c, d, e, f, "0");
+  END func_slv_concat;
+  
+  FUNCTION func_slv_concat(use_a, use_b, use_c, use_d, use_e : BOOLEAN; a, b, c, d, e : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_concat(use_a, use_b, use_c, use_d, use_e, FALSE, FALSE, a, b, c, d, e, "0", "0");
+  END func_slv_concat;
+  
+  FUNCTION func_slv_concat(use_a, use_b, use_c, use_d : BOOLEAN; a, b, c, d : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_concat(use_a, use_b, use_c, use_d, FALSE, FALSE, FALSE, a, b, c, d, "0", "0", "0");
+  END func_slv_concat;
+  
+  FUNCTION func_slv_concat(use_a, use_b, use_c : BOOLEAN; a, b, c : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_concat(use_a, use_b, use_c, FALSE, FALSE, FALSE, FALSE, a, b, c, "0", "0", "0", "0");
+  END func_slv_concat;
+  
+  FUNCTION func_slv_concat(use_a, use_b : BOOLEAN; a, b : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_concat(use_a, use_b, FALSE, FALSE, FALSE, FALSE, FALSE, a, b, "0", "0", "0", "0", "0");
+  END func_slv_concat;
+  
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL) RETURN NATURAL IS
+    VARIABLE v_len : NATURAL := 0;
+  BEGIN
+    IF use_a = TRUE THEN v_len := v_len + a_w; END IF;
+    IF use_b = TRUE THEN v_len := v_len + b_w; END IF;
+    IF use_c = TRUE THEN v_len := v_len + c_w; END IF;
+    IF use_d = TRUE THEN v_len := v_len + d_w; END IF;
+    IF use_e = TRUE THEN v_len := v_len + e_w; END IF;
+    IF use_f = TRUE THEN v_len := v_len + f_w; END IF;
+    IF use_g = TRUE THEN v_len := v_len + g_w; END IF;
+    RETURN v_len;
+  END func_slv_concat_w;
+  
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, use_f, FALSE, a_w, b_w, c_w, d_w, e_w, f_w, 0);
+  END func_slv_concat_w;
+  
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d, use_e : BOOLEAN; a_w, b_w, c_w, d_w, e_w : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, use_e, FALSE, FALSE, a_w, b_w, c_w, d_w, e_w, 0, 0);
+  END func_slv_concat_w;
+  
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c, use_d : BOOLEAN; a_w, b_w, c_w, d_w : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN func_slv_concat_w(use_a, use_b, use_c, use_d, FALSE, FALSE, FALSE, a_w, b_w, c_w, d_w, 0, 0, 0);
+  END func_slv_concat_w;
+  
+  FUNCTION func_slv_concat_w(use_a, use_b, use_c : BOOLEAN; a_w, b_w, c_w : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN func_slv_concat_w(use_a, use_b, use_c, FALSE, FALSE, FALSE, FALSE, a_w, b_w, c_w, 0, 0, 0, 0);
+  END func_slv_concat_w;
+  
+  FUNCTION func_slv_concat_w(use_a, use_b : BOOLEAN; a_w, b_w : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN func_slv_concat_w(use_a, use_b, FALSE, FALSE, FALSE, FALSE, FALSE, a_w, b_w, 0, 0, 0, 0, 0);
+  END func_slv_concat_w;
+  
+  -- extract slv
+  FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f, use_g : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w, g_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_w  : NATURAL := 0;
+    VARIABLE v_lo : NATURAL := 0;
+  BEGIN
+    -- if the selected slv is not used in vec, then return dummy, else return the selected slv from vec
+    CASE sel IS
+      WHEN 0 =>
+        IF use_a = TRUE THEN v_w := a_w; ELSE RETURN c_slv0(a_w-1 DOWNTO 0); END IF;
+      WHEN 1 =>
+        IF use_b = TRUE THEN v_w := b_w; ELSE RETURN c_slv0(b_w-1 DOWNTO 0); END IF;
+        IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
+      WHEN 2 =>
+        IF use_c = TRUE THEN v_w := c_w; ELSE RETURN c_slv0(c_w-1 DOWNTO 0); END IF;
+        IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
+        IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
+      WHEN 3 =>
+        IF use_d = TRUE THEN v_w := d_w; ELSE RETURN c_slv0(d_w-1 DOWNTO 0); END IF;
+        IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
+        IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
+        IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
+      WHEN 4 =>
+        IF use_e = TRUE THEN v_w := e_w; ELSE RETURN c_slv0(e_w-1 DOWNTO 0); END IF;
+        IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
+        IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
+        IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
+        IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
+      WHEN 5 =>
+        IF use_f = TRUE THEN v_w := f_w; ELSE RETURN c_slv0(f_w-1 DOWNTO 0); END IF;
+        IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
+        IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
+        IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
+        IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
+        IF use_e = TRUE THEN v_lo := v_lo + e_w; END IF;
+      WHEN 6 =>
+        IF use_g = TRUE THEN v_w := g_w; ELSE RETURN c_slv0(g_w-1 DOWNTO 0); END IF;
+        IF use_a = TRUE THEN v_lo := v_lo + a_w; END IF;
+        IF use_b = TRUE THEN v_lo := v_lo + b_w; END IF;
+        IF use_c = TRUE THEN v_lo := v_lo + c_w; END IF;
+        IF use_d = TRUE THEN v_lo := v_lo + d_w; END IF;
+        IF use_e = TRUE THEN v_lo := v_lo + e_w; END IF;
+        IF use_f = TRUE THEN v_lo := v_lo + f_w; END IF;
+      WHEN OTHERS => REPORT "Unknown common_pkg func_slv_extract argument" SEVERITY FAILURE;
+    END CASE;
+    RETURN vec(v_w-1 + v_lo DOWNTO v_lo);  -- extracted slv
+  END func_slv_extract;
+  
+  FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f : BOOLEAN; a_w, b_w, c_w, d_w, e_w, f_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_extract(use_a, use_b, use_c, use_d, use_e, use_f, FALSE, a_w, b_w, c_w, d_w, e_w, f_w, 0, vec, sel);
+  END func_slv_extract;
+  
+  FUNCTION func_slv_extract(use_a, use_b, use_c, use_d, use_e : BOOLEAN; a_w, b_w, c_w, d_w, e_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_extract(use_a, use_b, use_c, use_d, use_e, FALSE, FALSE, a_w, b_w, c_w, d_w, e_w, 0, 0, vec, sel);
+  END func_slv_extract;
+  
+  FUNCTION func_slv_extract(use_a, use_b, use_c, use_d : BOOLEAN; a_w, b_w, c_w, d_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_extract(use_a, use_b, use_c, use_d, FALSE, FALSE, FALSE, a_w, b_w, c_w, d_w, 0, 0, 0, vec, sel);
+  END func_slv_extract;
+  
+  FUNCTION func_slv_extract(use_a, use_b, use_c : BOOLEAN; a_w, b_w, c_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_extract(use_a, use_b, use_c, FALSE, FALSE, FALSE, FALSE, a_w, b_w, c_w, 0, 0, 0, 0, vec, sel);
+  END func_slv_extract;
+  
+  FUNCTION func_slv_extract(use_a, use_b : BOOLEAN; a_w, b_w : NATURAL; vec : STD_LOGIC_VECTOR; sel : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN func_slv_extract(use_a, use_b, FALSE, FALSE, FALSE, FALSE, FALSE, a_w, b_w, 0, 0, 0, 0, 0, vec, sel);
+  END func_slv_extract;
+  
+  
+  FUNCTION TO_UINT(vec : STD_LOGIC_VECTOR) RETURN NATURAL IS
+  BEGIN
+    RETURN TO_INTEGER(UNSIGNED(vec));
+  END;
+  
+  FUNCTION TO_SINT(vec : STD_LOGIC_VECTOR) RETURN INTEGER IS
+  BEGIN
+    RETURN TO_INTEGER(SIGNED(vec));
+  END;
+  
+  FUNCTION TO_UVEC(dec, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(TO_UNSIGNED(dec, w));
+  END;
+
+  FUNCTION TO_SVEC(dec, w : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(TO_SIGNED(dec, w));
+  END;
+  
+  FUNCTION TO_SVEC_32(dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN TO_SVEC(dec, 32);
+  END;
+
+  FUNCTION RESIZE_NUM(u : UNSIGNED; w : NATURAL) RETURN UNSIGNED IS
+  BEGIN
+    -- left extend with '0' or keep LS part (same as RESIZE for UNSIGNED)
+    RETURN RESIZE(u, w);
+  END;
+  
+  FUNCTION RESIZE_NUM(s : SIGNED; w : NATURAL) RETURN SIGNED IS
+  BEGIN
+    -- extend sign bit or keep LS part
+    IF w>s'LENGTH THEN
+      RETURN RESIZE(s, w);                    -- extend sign bit
+    ELSE
+      RETURN SIGNED(RESIZE(UNSIGNED(s), w));  -- keep LSbits (= vec[w-1:0])
+    END IF;
+  END;
+  
+  FUNCTION RESIZE_UVEC(sl : STD_LOGIC; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_slv0 : STD_LOGIC_VECTOR(w-1 DOWNTO 1) := (OTHERS=>'0');
+  BEGIN
+    RETURN v_slv0 & sl;
+  END;
+  
+  FUNCTION RESIZE_UVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(vec), w));
+  END;
+
+  FUNCTION RESIZE_SVEC(vec : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(RESIZE_NUM(SIGNED(vec), w));
+  END;
+  
+  FUNCTION RESIZE_UINT(u : INTEGER; w : NATURAL) RETURN INTEGER IS
+    VARIABLE v : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  BEGIN
+    v := TO_UVEC(u, c_word_w);
+    RETURN TO_UINT(v(w-1 DOWNTO 0));
+  END;
+  
+  FUNCTION RESIZE_SINT(s : INTEGER; w : NATURAL) RETURN INTEGER IS
+    VARIABLE v : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  BEGIN
+    v := TO_SVEC(s, c_word_w);
+    RETURN TO_SINT(v(w-1 DOWNTO 0));
+  END;
+  
+  FUNCTION RESIZE_UVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(vec, 32);
+  END;
+  
+  FUNCTION RESIZE_SVEC_32(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_SVEC(vec, 32);
+  END;
+  
+  FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_dec : INTEGER;
+  BEGIN
+    IF dec < 0 THEN
+      v_dec := -dec;
+      RETURN STD_LOGIC_VECTOR(UNSIGNED(vec) - v_dec);  -- uses function "-" (L : UNSIGNED, R : NATURAL), there is no function + with R : INTEGER argument
+    ELSE
+      v_dec := dec;
+      RETURN STD_LOGIC_VECTOR(UNSIGNED(vec) + v_dec);  -- uses function "+" (L : UNSIGNED, R : NATURAL)
+    END IF;
+  END;
+
+  FUNCTION INCR_UVEC(vec : STD_LOGIC_VECTOR; dec : UNSIGNED) RETURN STD_LOGIC_VECTOR IS   
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(UNSIGNED(vec) + dec);
+  END;
+  
+  FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : INTEGER) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_dec : INTEGER;
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(SIGNED(vec) + v_dec);  -- uses function "+" (L : SIGNED, R : INTEGER)
+  END;
+
+  FUNCTION INCR_SVEC(vec : STD_LOGIC_VECTOR; dec : SIGNED) RETURN STD_LOGIC_VECTOR IS   
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(SIGNED(vec) + dec);
+  END;
+  
+  FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(RESIZE_NUM(SIGNED(l_vec), res_w) + SIGNED(r_vec));
+  END;
+  
+  FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(RESIZE_NUM(SIGNED(l_vec), res_w) - SIGNED(r_vec));
+  END;
+  
+  FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(l_vec), res_w) + UNSIGNED(r_vec));
+  END;
+  
+  FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR; res_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN STD_LOGIC_VECTOR(RESIZE_NUM(UNSIGNED(l_vec), res_w) - UNSIGNED(r_vec));
+  END;
+  
+  
+  FUNCTION ADD_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN ADD_SVEC(l_vec, r_vec, l_vec'LENGTH);
+  END;
+  
+  FUNCTION SUB_SVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN SUB_SVEC(l_vec, r_vec, l_vec'LENGTH);
+  END;
+  
+  FUNCTION ADD_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN ADD_UVEC(l_vec, r_vec, l_vec'LENGTH);
+  END;
+  
+  FUNCTION SUB_UVEC(l_vec : STD_LOGIC_VECTOR; r_vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN SUB_UVEC(l_vec, r_vec, l_vec'LENGTH);
+  END;
+  
+  FUNCTION COMPLEX_MULT_REAL(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER IS   
+  BEGIN
+    RETURN (a_re*b_re - a_im*b_im); 
+  END;
+  
+  FUNCTION COMPLEX_MULT_IMAG(a_re, a_im, b_re, b_im : INTEGER) RETURN INTEGER IS
+  BEGIN
+    RETURN (a_im*b_re + a_re*b_im);
+  END;
+  
+  FUNCTION SHIFT_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    IF shift < 0 THEN
+      RETURN STD_LOGIC_VECTOR(SHIFT_LEFT(UNSIGNED(vec), -shift));  -- fill zeros from right
+    ELSE
+      RETURN STD_LOGIC_VECTOR(SHIFT_RIGHT(UNSIGNED(vec), shift));  -- fill zeros from left
+    END IF;
+  END;
+  
+  FUNCTION SHIFT_SVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    IF shift < 0 THEN
+      RETURN STD_LOGIC_VECTOR(SHIFT_LEFT(SIGNED(vec), -shift));  -- same as SHIFT_LEFT for UNSIGNED
+    ELSE
+      RETURN STD_LOGIC_VECTOR(SHIFT_RIGHT(SIGNED(vec), shift));  -- extend sign
+    END IF;
+  END;
+
+  --
+  -- offset_binary() : maps offset binary to or from two-complement binary.
+  --
+  --   National ADC08DC1020     offset binary     two-complement binary
+  --   + full scale =  127.5 :  11111111 = 255     127 = 01111111
+  --     ...                                  
+  --   +            =   +0.5 :  10000000 = 128       0 = 00000000
+  --   0
+  --   -            =   -0.5 :  01111111 = 127      -1 = 11111111
+  --     ...                                  
+  --   - full scale = -127.5 :  00000000 =   0    -128 = 10000000
+  --
+  -- To map between the offset binary and two complement binary involves
+  -- adding 128 to the binary value or equivalently inverting the sign bit.
+  -- The offset_binary() mapping can be done and undone both ways.
+  -- The offset_binary() mapping to two-complement binary yields a DC offset
+  -- of -0.5 Lsb.
+  FUNCTION offset_binary(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_res : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;
+  BEGIN
+   v_res(v_res'HIGH) := NOT v_res(v_res'HIGH);  -- invert MSbit to get to from offset binary to two's complement, or vice versa
+   RETURN v_res;
+  END;
+  
+  FUNCTION truncate(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
+    CONSTANT c_trunc_w : NATURAL := c_vec_w-n;
+    VARIABLE v_vec     : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0) := vec;
+    VARIABLE v_res     : STD_LOGIC_VECTOR(c_trunc_w-1 DOWNTO 0);
+  BEGIN
+   v_res := v_vec(c_vec_w-1 DOWNTO n);  -- keep MS part
+   RETURN v_res;
+  END;
+
+  FUNCTION truncate_and_resize_uvec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
+    CONSTANT c_trunc_w : NATURAL := c_vec_w-n;
+    VARIABLE v_trunc   : STD_LOGIC_VECTOR(c_trunc_w-1 DOWNTO 0);
+    VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
+  BEGIN
+    v_trunc := truncate(vec, n);       -- first keep MS part
+    v_res := RESIZE_UVEC(v_trunc, w);  -- then keep LS part or left extend with '0'
+    RETURN v_res;
+  END;
+  
+  FUNCTION truncate_and_resize_svec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
+    CONSTANT c_trunc_w : NATURAL := c_vec_w-n;
+    VARIABLE v_trunc   : STD_LOGIC_VECTOR(c_trunc_w-1 DOWNTO 0);
+    VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
+  BEGIN
+    v_trunc := truncate(vec, n);       -- first keep MS part
+    v_res := RESIZE_SVEC(v_trunc, w);  -- then keep sign bit and LS part or left extend sign bit
+    RETURN v_res;
+  END;
+  
+  FUNCTION scale(vec : STD_LOGIC_VECTOR; n: NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
+    CONSTANT c_scale_w : NATURAL := c_vec_w+n;
+    VARIABLE v_res     : STD_LOGIC_VECTOR(c_scale_w-1 DOWNTO 0) := (OTHERS=>'0');
+  BEGIN
+    v_res(c_scale_w-1 DOWNTO n) := vec;  -- scale by adding n zero bits at the right
+    RETURN v_res;
+  END;
+  
+  FUNCTION scale_and_resize_uvec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
+    CONSTANT c_scale_w : NATURAL := c_vec_w+n;
+    VARIABLE v_scale   : STD_LOGIC_VECTOR(c_scale_w-1 DOWNTO 0) := (OTHERS=>'0');
+    VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
+  BEGIN
+    v_scale(c_scale_w-1 DOWNTO n) := vec;  -- first scale by adding n zero bits at the right
+    v_res := RESIZE_UVEC(v_scale, w);      -- then keep LS part or left extend with '0'
+    RETURN v_res;
+  END;
+  
+  FUNCTION scale_and_resize_svec(vec : STD_LOGIC_VECTOR; n, w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w   : NATURAL := vec'LENGTH;
+    CONSTANT c_scale_w : NATURAL := c_vec_w+n;
+    VARIABLE v_scale   : STD_LOGIC_VECTOR(c_scale_w-1 DOWNTO 0) := (OTHERS=>'0');
+    VARIABLE v_res     : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
+  BEGIN
+    v_scale(c_scale_w-1 DOWNTO n) := vec;  -- first scale by adding n zero bits at the right
+    v_res := RESIZE_SVEC(v_scale, w);      -- then keep LS part or left extend sign bit
+    RETURN v_res;
+  END;
+  
+  FUNCTION truncate_or_resize_uvec(vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w : NATURAL := vec'LENGTH;
+    VARIABLE c_n     : INTEGER := c_vec_w-w;
+    VARIABLE v_res   : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
+  BEGIN
+    IF b=TRUE AND c_n>0 THEN
+      v_res := truncate_and_resize_uvec(vec, c_n, w);
+    ELSE
+      v_res := RESIZE_UVEC(vec, w);
+    END IF;
+    RETURN v_res;
+  END;
+  
+  FUNCTION truncate_or_resize_svec(vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_vec_w : NATURAL := vec'LENGTH;
+    VARIABLE c_n     : INTEGER := c_vec_w-w;
+    VARIABLE v_res   : STD_LOGIC_VECTOR(w-1 DOWNTO 0);
+  BEGIN
+    IF b=TRUE AND c_n>0 THEN
+      v_res := truncate_and_resize_svec(vec, c_n, w);
+    ELSE
+      v_res := RESIZE_SVEC(vec, w);
+    END IF;
+    RETURN v_res;
+  END;
+  
+  
+  -- Functions s_round, s_round_up and u_round:
+  --
+  -- . The returned output width is input width - n.
+  -- . If n=0 then the return value is the same as the input value so only
+  --   wires (NOP, no operation).
+  -- . Both have the same implementation but different c_max and c_clip values.
+  -- . Round up for unsigned so +2.5 becomes 3
+  -- . Round away from zero for signed so round up for positive and round down for negative, so +2.5 becomes 3 and -2.5 becomes -3.
+  -- . Round away from zero is also used by round() in Matlab, Python, TCL
+  -- . Rounding up implies adding 0.5 and then truncation, use clip = TRUE to
+  --   clip the potential overflow due to adding 0.5 to +max.
+  -- . For negative values overflow due to rounding can not occur, because c_half-1 >= 0 for n>0
+  -- . If the input comes from a product and is rounded to the input width then
+  --   clip can safely be FALSE, because e.g. for unsigned 4b*4b=8b->4b the
+  --   maximum product is 15*15=225 <= 255-8, and for signed 4b*4b=8b->4b the
+  --   maximum product is -8*-8=+64 <= 127-8, so wrapping due to rounding
+  --   overflow will never occur.
+
+  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
+    -- Use SIGNED to avoid NATURAL (32 bit range) overflow error
+    CONSTANT c_in_w  : NATURAL := vec'LENGTH;
+    CONSTANT c_out_w : NATURAL := vec'LENGTH - n;
+    CONSTANT c_one   : SIGNED(c_in_w-1 DOWNTO 0) := TO_SIGNED(1, c_in_w);
+    CONSTANT c_half  : SIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                            -- = 2**(n-1)
+    CONSTANT c_max   : SIGNED(c_in_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_in_w-2 DOWNTO 0)) - c_half;  -- = 2**(c_in_w-1)-1 - c_half  
+    CONSTANT c_clip  : SIGNED(c_out_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_out_w-2 DOWNTO 0));         -- = 2**(c_out_w-1)-1
+    VARIABLE v_in    : SIGNED(c_in_w-1 DOWNTO 0);
+    VARIABLE v_out   : SIGNED(c_out_w-1 DOWNTO 0);
+  BEGIN
+    v_in := SIGNED(vec);
+    IF n > 0 THEN
+      IF clip = TRUE AND v_in > c_max THEN
+        v_out := c_clip;                                              -- Round clip to maximum positive to avoid wrap to negative
+      ELSE
+        IF vec(vec'HIGH)='0' THEN
+          v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half + 0, n), c_out_w);  -- Round up for positive
+        ELSE
+          v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half - 1, n), c_out_w);  -- Round down for negative
+        END IF;
+      END IF;
+    ELSE
+      v_out := RESIZE_NUM(v_in, c_out_w);                             -- NOP
+    END IF;
+    RETURN STD_LOGIC_VECTOR(v_out);
+  END;
+
+  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN s_round(vec, n, FALSE);  -- no round clip
+  END;
+  
+  -- An alternative is to always round up, also for negative numbers (i.e. s_round_up = u_round).
+  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN u_round(vec, n, clip);
+  END;
+  
+  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN u_round(vec, n, FALSE);  -- no round clip
+  END;
+  
+  -- Unsigned numbers are round up (almost same as s_round, but without the else on negative vec)
+  FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN ) RETURN STD_LOGIC_VECTOR IS
+    -- Use UNSIGNED to avoid NATURAL (32 bit range) overflow error
+    CONSTANT c_in_w  : NATURAL := vec'LENGTH;
+    CONSTANT c_out_w : NATURAL := vec'LENGTH - n;
+    CONSTANT c_one   : UNSIGNED(c_in_w-1 DOWNTO 0) := TO_UNSIGNED(1, c_in_w);
+    CONSTANT c_half  : UNSIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                        -- = 2**(n-1)
+    CONSTANT c_max   : UNSIGNED(c_in_w-1 DOWNTO 0) := UNSIGNED(c_slv1(c_in_w-1 DOWNTO 0)) - c_half;  -- = 2**c_in_w-1 - c_half  
+    CONSTANT c_clip  : UNSIGNED(c_out_w-1 DOWNTO 0) := UNSIGNED(c_slv1(c_out_w-1 DOWNTO 0));         -- = 2**c_out_w-1
+    VARIABLE v_in    : UNSIGNED(c_in_w-1 DOWNTO 0);
+    VARIABLE v_out   : UNSIGNED(c_out_w-1 DOWNTO 0);
+  BEGIN
+    v_in := UNSIGNED(vec);
+    IF n > 0 THEN
+      IF clip = TRUE AND v_in > c_max THEN
+        v_out := c_clip;                                              -- Round clip to +max to avoid wrap to 0
+      ELSE
+        v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half, n), c_out_w);  -- Round up
+      END IF;
+    ELSE
+      v_out := RESIZE_NUM(v_in, c_out_w);                             -- NOP
+    END IF;
+    RETURN STD_LOGIC_VECTOR(v_out);
+  END;
+
+  FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN u_round(vec, n, FALSE);  -- no round clip
+  END;
+  
+  
+  FUNCTION hton(a : STD_LOGIC_VECTOR; w, sz : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_a : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;  -- map a to range [h:0]
+    VARIABLE v_b : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;  -- default b = a
+    VARIABLE vL  : NATURAL;
+    VARIABLE vK  : NATURAL;
+  BEGIN
+    -- Note:
+    -- . if sz = 1          then v_b = v_a
+    -- . if a'LENGTH > sz*w then v_b(a'LENGTH:sz*w) = v_a(a'LENGTH:sz*w)
+    FOR vL IN 0 TO sz-1 LOOP
+      vK := sz-1 - vL;
+      v_b((vL+1)*w-1 DOWNTO vL*w) := v_a((vK+1)*w-1 DOWNTO vK*w);
+    END LOOP;
+    RETURN v_b;
+  END FUNCTION;
+  
+  FUNCTION hton(a : STD_LOGIC_VECTOR; sz : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN hton(a, c_byte_w, sz);  -- symbol width w = c_byte_w = 8
+  END FUNCTION;
+  
+  FUNCTION hton(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_sz : NATURAL := a'LENGTH/ c_byte_w;
+  BEGIN
+    RETURN hton(a, c_byte_w, c_sz);  -- symbol width w = c_byte_w = 8
+  END FUNCTION;
+  
+  FUNCTION ntoh(a : STD_LOGIC_VECTOR; sz : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN hton(a, sz);  -- i.e. ntoh() = hton()
+  END FUNCTION;
+  
+  FUNCTION ntoh(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN hton(a);  -- i.e. ntoh() = hton()
+  END FUNCTION;
+  
+  FUNCTION flip(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_a : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0) := a;
+    VARIABLE v_b : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0);
+  BEGIN
+    FOR I IN v_a'RANGE LOOP
+      v_b(a'LENGTH-1-I) := v_a(I);
+    END LOOP;
+    RETURN v_b;
+  END;
+  
+  FUNCTION flip(a, w : NATURAL) RETURN NATURAL IS
+  BEGIN
+    RETURN TO_UINT(flip(TO_UVEC(a, w)));
+  END;
+  
+  FUNCTION flip(a : t_slv_32_arr) RETURN t_slv_32_arr IS
+    VARIABLE v_a : t_slv_32_arr(a'LENGTH-1 DOWNTO 0) := a;
+    VARIABLE v_b : t_slv_32_arr(a'LENGTH-1 DOWNTO 0);
+  BEGIN
+    FOR I IN v_a'RANGE LOOP
+      v_b(a'LENGTH-1-I) := v_a(I);
+    END LOOP;
+    RETURN v_b;
+  END;
+  
+  FUNCTION flip(a : t_integer_arr) RETURN t_integer_arr IS
+    VARIABLE v_a : t_integer_arr(a'LENGTH-1 DOWNTO 0) := a;
+    VARIABLE v_b : t_integer_arr(a'LENGTH-1 DOWNTO 0);
+  BEGIN
+    FOR I IN v_a'RANGE LOOP
+      v_b(a'LENGTH-1-I) := v_a(I);
+    END LOOP;
+    RETURN v_b;
+  END;
+
+  FUNCTION flip(a : t_natural_arr) RETURN t_natural_arr IS
+    VARIABLE v_a : t_natural_arr(a'LENGTH-1 DOWNTO 0) := a;
+    VARIABLE v_b : t_natural_arr(a'LENGTH-1 DOWNTO 0);
+  BEGIN
+    FOR I IN v_a'RANGE LOOP
+      v_b(a'LENGTH-1-I) := v_a(I);
+    END LOOP;
+    RETURN v_b;
+  END;
+  
+  FUNCTION flip(a : t_nat_natural_arr) RETURN t_nat_natural_arr IS
+    VARIABLE v_a : t_nat_natural_arr(a'LENGTH-1 DOWNTO 0) := a;
+    VARIABLE v_b : t_nat_natural_arr(a'LENGTH-1 DOWNTO 0);
+  BEGIN
+    FOR I IN v_a'RANGE LOOP
+      v_b(a'LENGTH-1-I) := v_a(I);
+    END LOOP;
+    RETURN v_b;
+  END;
+    
+  FUNCTION transpose(a : STD_LOGIC_VECTOR; row, col : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE vIn  : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0);
+    VARIABLE vOut : STD_LOGIC_VECTOR(a'LENGTH-1 DOWNTO 0);
+  BEGIN
+    vIn  := a;    -- map input vector to h:0 range
+    vOut := vIn;  -- default leave any unused MSbits the same
+    FOR J IN 0 TO row-1 LOOP
+      FOR I IN 0 TO col-1 LOOP
+        vOut(J*col + I) := vIn(I*row + J);  -- transpose vector, map input index [i*row+j] to output index [j*col+i]
+      END LOOP;
+    END LOOP;
+    RETURN vOut;
+  END FUNCTION;
+  
+  FUNCTION transpose(a, row, col : NATURAL) RETURN NATURAL IS  -- transpose index a = [i*row+j] to output index [j*col+i]
+    VARIABLE vI  : NATURAL;
+    VARIABLE vJ  : NATURAL;
+  BEGIN
+    vI := a / row;
+    vJ := a MOD row;
+    RETURN vJ * col + vI;
+  END;
+ 
+  FUNCTION split_w(input_w: NATURAL; min_out_w: NATURAL; max_out_w: NATURAL) RETURN NATURAL IS -- Calculate input_w in multiples as close as possible to max_out_w
+    -- Examples: split_w(256, 8, 32) = 32;  split_w(16, 8, 32) = 16; split_w(72, 8, 32) = 18;    -- Input_w must be multiple of 2.
+    VARIABLE r: NATURAL;
+  BEGIN
+    r := input_w;
+    FOR i IN 1 TO ceil_log2(input_w) LOOP -- Useless to divide the number beyond this       
+      IF r <= max_out_w AND r >= min_out_w THEN
+        RETURN r;
+      ELSIF i = ceil_log2(input_w) THEN -- last iteration
+        RETURN 0; -- Indicates wrong values were used
+      END IF;
+      r := r / 2;
+    END LOOP;
+  END;
+
+  FUNCTION pad(str: STRING; width: NATURAL; pad_char: CHARACTER) RETURN STRING IS
+    VARIABLE v_str : STRING(1 TO width) := (OTHERS => pad_char);
+  BEGIN
+    v_str(width-str'LENGTH+1 TO width) := str;
+    RETURN v_str;
+  END;
+
+  FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING IS
+  BEGIN
+    RETURN str(i*width+1 TO (i+1)*width);
+  END;
+
+  -- If the input value is not a multiple of the desired width, the return value is padded with
+  -- the passed pad value. E.g. if input='10' and desired width is 4, return value is '0010'.
+  FUNCTION slice_up(str: STRING; width: NATURAL; i: NATURAL; pad_char: CHARACTER) RETURN STRING IS
+    VARIABLE padded_str : STRING(1 TO width) := (OTHERS=>'0');
+  BEGIN
+    padded_str := pad(str(i*width+1 TO (i+1)*width), width, '0');
+    RETURN padded_str;
+  END;
+
+  FUNCTION slice_dn(str: STRING; width: NATURAL; i: NATURAL) RETURN STRING IS
+  BEGIN
+    RETURN str((i+1)*width-1 DOWNTO i*width);
+  END;
+
+ 
+  FUNCTION nat_arr_to_concat_slv(nat_arr: t_natural_arr; nof_elements: NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_concat_slv : STD_LOGIC_VECTOR(nof_elements*32-1 DOWNTO 0) := (OTHERS=>'0');
+  BEGIN
+    FOR i IN 0 TO nof_elements-1 LOOP
+      v_concat_slv(i*32+32-1 DOWNTO i*32) :=  TO_UVEC(nat_arr(i), 32);
+    END LOOP;
+    RETURN v_concat_slv;
+  END;
+
+  
+  ------------------------------------------------------------------------------
+  -- common_fifo_*  
+  ------------------------------------------------------------------------------
+  
+  PROCEDURE proc_common_fifo_asserts (CONSTANT c_fifo_name   : IN STRING;
+                                      CONSTANT c_note_is_ful : IN BOOLEAN;
+                                      CONSTANT c_fail_rd_emp : IN BOOLEAN;
+                                      SIGNAL   wr_rst        : IN STD_LOGIC;
+                                      SIGNAL   wr_clk        : IN STD_LOGIC;
+                                      SIGNAL   wr_full       : IN STD_LOGIC;
+                                      SIGNAL   wr_en         : IN STD_LOGIC;
+                                      SIGNAL   rd_clk        : IN STD_LOGIC;
+                                      SIGNAL   rd_empty      : IN STD_LOGIC;
+                                      SIGNAL   rd_en         : IN STD_LOGIC) IS
+  BEGIN
+    -- c_fail_rd_emp : when TRUE report FAILURE when read from an empty FIFO, important when FIFO rd_val is not used
+    -- c_note_is_ful : when TRUE report NOTE when FIFO goes full, to note that operation is on the limit
+    -- FIFO overflow is always reported as FAILURE
+
+    -- The FIFO wr_full goes high at reset to indicate that it can not be written and it goes low a few cycles after reset.
+    -- Therefore only check on wr_full going high when wr_rst='0'.
+    
+    --synthesis translate_off
+    ASSERT NOT(c_fail_rd_emp=TRUE AND rising_edge(rd_clk)  AND rd_empty='1' AND rd_en='1')  REPORT c_fifo_name & " : read from empty fifo occurred!" SEVERITY FAILURE;
+    ASSERT NOT(c_note_is_ful=TRUE AND rising_edge(wr_full) AND wr_rst='0')                  REPORT c_fifo_name & " : fifo is full now"               SEVERITY NOTE;
+    ASSERT NOT(                       rising_edge(wr_clk)  AND wr_full='1'  AND wr_en='1')  REPORT c_fifo_name & " : fifo overflow occurred!"        SEVERITY FAILURE;
+    --synthesis translate_on
+  END PROCEDURE proc_common_fifo_asserts;
+  
+  
+  ------------------------------------------------------------------------------
+  -- common_fanout_tree 
+  ------------------------------------------------------------------------------
+  
+  FUNCTION func_common_fanout_tree_pipelining(c_nof_stages, c_nof_output_per_cell, c_nof_output : NATURAL;
+                                              c_cell_pipeline_factor_arr, c_cell_pipeline_arr : t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT k_cell_pipeline_factor_arr : t_natural_arr(c_nof_stages-1 DOWNTO 0) := c_cell_pipeline_factor_arr;
+    CONSTANT k_cell_pipeline_arr        : t_natural_arr(c_nof_output_per_cell-1 DOWNTO 0) := c_cell_pipeline_arr;
+    VARIABLE v_stage_pipeline_arr       : t_natural_arr(c_nof_output-1 DOWNTO 0) := (OTHERS=>0);
+    VARIABLE v_prev_stage_pipeline_arr  : t_natural_arr(c_nof_output-1 DOWNTO 0) := (OTHERS=>0);
+  BEGIN
+    loop_stage : FOR j IN 0 TO c_nof_stages-1 LOOP
+      v_prev_stage_pipeline_arr := v_stage_pipeline_arr;
+      loop_cell : FOR i IN 0 TO c_nof_output_per_cell**j-1 LOOP
+        v_stage_pipeline_arr((i+1)*c_nof_output_per_cell-1 DOWNTO i*c_nof_output_per_cell) := v_prev_stage_pipeline_arr(i) + (k_cell_pipeline_factor_arr(j) * k_cell_pipeline_arr);
+      END LOOP;
+    END LOOP;
+    RETURN v_stage_pipeline_arr; 
+  END FUNCTION func_common_fanout_tree_pipelining;
+  
+  
+  ------------------------------------------------------------------------------
+  -- common_reorder_symbol 
+  ------------------------------------------------------------------------------
+  
+  -- Determine whether the stage I and row J index refer to any (active or redundant) 2-input reorder cell instantiation
+  FUNCTION func_common_reorder2_is_there(I, J : NATURAL) RETURN BOOLEAN IS
+    VARIABLE v_odd  : BOOLEAN;
+    VARIABLE v_even : BOOLEAN;
+  BEGIN
+    v_odd  := (I MOD 2 = 1) AND (J MOD 2 = 1);  -- for odd  stage at each odd  row
+    v_even := (I MOD 2 = 0) AND (J MOD 2 = 0);  -- for even stage at each even row
+    RETURN v_odd OR v_even;
+  END func_common_reorder2_is_there;
+  
+  -- Determine whether the stage I and row J index refer to an active 2-input reorder cell instantiation in a reorder network with N stages
+  FUNCTION func_common_reorder2_is_active(I, J, N : NATURAL) RETURN BOOLEAN IS
+    VARIABLE v_inst : BOOLEAN;
+    VARIABLE v_act  : BOOLEAN;
+  BEGIN
+    v_inst := func_common_reorder2_is_there(I, J);
+    v_act  := (I > 0) AND (I <= N) AND (J > 0) AND (J < N);
+    RETURN v_inst AND v_act;
+  END func_common_reorder2_is_active;
+  
+  -- Get the index K in the select setting array for the reorder2 cell on stage I and row J in a reorder network with N stages
+  FUNCTION func_common_reorder2_get_select_index(I, J, N : NATURAL) RETURN INTEGER IS
+    CONSTANT c_nof_reorder2_per_odd_stage  : NATURAL := N/2;
+    CONSTANT c_nof_reorder2_per_even_stage : NATURAL := (N-1)/2;
+    VARIABLE v_nof_odd_stages  : NATURAL;
+    VARIABLE v_nof_even_stages : NATURAL;
+    VARIABLE v_offset          : NATURAL;
+    VARIABLE v_K               : INTEGER;
+  BEGIN
+    -- for I, J that do not refer to an reorder cell instance for -1 as dummy return value.
+    -- for the redundant two port reorder cells at the border rows for -1 to indicate that the cell should pass on the input.
+    v_K := -1;
+    IF func_common_reorder2_is_active(I, J, N) THEN
+      -- for the active two port reorder cells use the setting at index v_K from the select setting array
+      v_nof_odd_stages  :=  I/2;
+      v_nof_even_stages := (I-1)/2;
+      v_offset          := (J-1)/2;  -- suits both odd stage and even stage
+      v_K := v_nof_odd_stages * c_nof_reorder2_per_odd_stage + v_nof_even_stages * c_nof_reorder2_per_even_stage + v_offset;
+    END IF;
+    RETURN v_K;
+  END func_common_reorder2_get_select_index;
+  
+  -- Get the select setting for the reorder2 cell on stage I and row J in a reorder network with N stages
+  FUNCTION func_common_reorder2_get_select(I, J, N : NATURAL; select_arr : t_natural_arr) RETURN NATURAL IS
+    CONSTANT c_nof_select : NATURAL := select_arr'LENGTH;
+    CONSTANT c_select_arr : t_natural_arr(c_nof_select-1 DOWNTO 0) := select_arr;  -- force range downto 0
+    VARIABLE v_sel        : NATURAL;
+    VARIABLE v_K          : INTEGER;
+  BEGIN
+    v_sel := 0;
+    v_K := func_common_reorder2_get_select_index(I, J, N);
+    IF v_K>=0 THEN
+      v_sel := c_select_arr(v_K);
+    END IF;
+    RETURN v_sel;
+  END func_common_reorder2_get_select;
+  
+  -- Determine the inverse of a reorder network by using two reorder networks in series
+  FUNCTION func_common_reorder2_inverse_select(N : NATURAL; select_arr : t_natural_arr) RETURN t_natural_arr IS
+    CONSTANT c_nof_select      : NATURAL := select_arr'LENGTH;
+    CONSTANT c_select_arr      : t_natural_arr(c_nof_select-1 DOWNTO 0) := select_arr;  -- force range downto 0
+    VARIABLE v_sel             : NATURAL;
+    VARIABLE v_Ki              : INTEGER;
+    VARIABLE v_Ii              : NATURAL;
+    VARIABLE v_inverse_arr     : t_natural_arr(2*c_nof_select-1 DOWNTO 0) := (OTHERS=>0);  -- default set identity for the reorder2 cells in both reorder instances
+  BEGIN
+    -- the inverse select consists of inverse_in reorder and inverse_out reorder in series
+    IF N MOD 2 = 1 THEN
+      -- N is odd so only need to fill in the inverse_in reorder, the inverse_out reorder remains at default pass on
+      FOR I IN 1 TO N LOOP
+        FOR J IN 0 TO N-1 LOOP
+          -- get the DUT setting
+          v_sel := func_common_reorder2_get_select(I, J, N, c_select_arr);
+          -- map DUT I to inverse v_Ii stage index and determine the index for the inverse setting
+          v_Ii := 1+N-I;
+          v_Ki := func_common_reorder2_get_select_index(v_Ii, J, N);
+          IF v_Ki>=0 THEN
+            v_inverse_arr(v_Ki) := v_sel;
+          END IF;
+        END LOOP;
+      END LOOP;
+    ELSE
+      -- N is even so only use stage 1 of the inverse_out reorder, the other stages remain at default pass on
+      FOR K IN 0 TO N/2-1 LOOP
+         v_Ki := c_nof_select + K;  -- stage 1 of the inverse_out reorder
+         v_inverse_arr(v_Ki) := c_select_arr(K);
+      END LOOP;
+      -- N is even so leave stage 1 of the inverse_in reorder at default pass on, and do inverse the other stages
+      FOR I IN 2 TO N LOOP
+        FOR J IN 0 TO N-1 LOOP
+          -- get the DUT setting
+          v_sel := func_common_reorder2_get_select(I, J, N, c_select_arr);
+          -- map DUT I to inverse v_Ii stage index and determine the index for the inverse setting
+          v_Ii := 2+N-I;
+          v_Ki := func_common_reorder2_get_select_index(v_Ii, J, N);
+          IF v_Ki>=0 THEN
+            v_inverse_arr(v_Ki) := v_sel;
+          END IF;
+        END LOOP;
+      END LOOP;
+    END IF;
+    RETURN v_inverse_arr;
+  END func_common_reorder2_inverse_select;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate faster sample SCLK from digital DCLK for sim only
+  -- Description:
+  --   The SCLK kan be used to serialize Pfactor >= 1 symbols per word and then 
+  --   view them in a scope component that is use internally in the design.
+  --   The scope component is only instantiated for simulation, to view the
+  --   serialized symbols, typically with decimal radix and analogue format.
+  --   The scope component will not be synthesized, because the SCLK can not
+  --   be synthesized.
+  --   
+  --   Pfactor = 4
+  --            _______         _______         _______         _______
+  --   DCLK ___|       |_______|       |_______|       |_______|       |_______
+  --        ___________________   _   _   _   _   _   _   _   _   _   _   _   _
+  --   SCLK                    |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
+  --
+  --   The rising edges of SCLK occur after the rising edge of DCLK, to ensure
+  --   that they all apply to the same wide data word that was clocked by the
+  --   rising edge of the DCLK.
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_dclk_generate_sclk(CONSTANT Pfactor : IN    POSITIVE;
+                                           SIGNAL   dclk    : IN    STD_LOGIC;
+                                           SIGNAL   sclk    : INOUT STD_LOGIC) IS
+    VARIABLE v_dperiod : TIME;
+    VARIABLE v_speriod : TIME;
+  BEGIN
+    SCLK <= '1';
+    -- Measure DCLK period
+    WAIT UNTIL rising_edge(DCLK);
+    v_dperiod := NOW;
+    WAIT UNTIL rising_edge(DCLK);
+    v_dperiod := NOW - v_dperiod;
+    v_speriod := v_dperiod / Pfactor;
+    -- Generate Pfactor SCLK periods per DCLK period
+    WHILE TRUE LOOP
+      -- Realign at every DCLK
+      WAIT UNTIL rising_edge(DCLK);
+      -- Create Pfactor SCLK periods within this DCLK period
+      SCLK <= '0';
+      IF Pfactor>1 THEN
+        FOR I IN 0 TO 2*Pfactor-1-2 LOOP
+          WAIT FOR v_speriod/2;
+          SCLK <= NOT SCLK;
+        END LOOP;
+      END IF;
+      WAIT FOR v_speriod/2;
+      SCLK <= '1';
+      -- Wait for next DCLK
+    END LOOP;
+    WAIT;
+  END proc_common_dclk_generate_sclk;
+  
+END common_pkg;
+
diff --git a/cores/base/common/common_pkg/common_str_pkg.vhd b/cores/base/common/common_pkg/common_str_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..54e51b4d03a8384238a94bb0490ad9675fd6d807
--- /dev/null
+++ b/cores/base/common/common_pkg/common_str_pkg.vhd
@@ -0,0 +1,282 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2012
+-- 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;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE STD.TEXTIO.ALL;
+USE IEEE.STD_LOGIC_TEXTIO.ALL;
+USE work.common_pkg.ALL;
+
+PACKAGE common_str_pkg IS
+
+  TYPE t_str_4_arr IS ARRAY (INTEGER RANGE <>) OF STRING(1 TO 4);
+
+  FUNCTION nof_digits(number: NATURAL) RETURN NATURAL;
+  FUNCTION nof_digits_int(number: INTEGER) RETURN NATURAL;
+
+  FUNCTION time_to_str(in_time : TIME) RETURN STRING;
+  FUNCTION str_to_time(in_str : STRING) RETURN TIME;
+  FUNCTION slv_to_str(slv : STD_LOGIC_VECTOR) RETURN STRING;
+  FUNCTION str_to_hex(str : STRING) RETURN STRING;
+  FUNCTION slv_to_hex(slv : STD_LOGIC_VECTOR) RETURN STRING;
+  FUNCTION hex_to_slv(str : STRING) RETURN STD_LOGIC_VECTOR;
+
+  Function hex_nibble_to_slv(c: character) return std_logic_vector;
+
+  FUNCTION int_to_str(int: INTEGER) RETURN STRING;
+  FUNCTION real_to_str(re: REAL; width : INTEGER; digits : INTEGER) RETURN STRING;
+
+  PROCEDURE print_str(str : STRING);
+
+  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;
+  FUNCTION str_to_ascii_slv_32_arr( s: STRING) RETURN t_slv_32_arr;
+  FUNCTION str_to_ascii_slv_32_arr( s: STRING; arr_size : NATURAL) RETURN t_slv_32_arr;
+
+END common_str_pkg;
+
+PACKAGE BODY common_str_pkg IS
+
+  FUNCTION nof_digits(number: NATURAL) RETURN NATURAL IS
+  -- Returns number of digits in a natural number. Only used in string processing, so defined here.
+  -- log10(0) is not allowed so:
+  -- . nof_digits(0) = 1
+  -- We're adding 1 so:
+  -- . nof_digits(1) = 1
+  -- . nof_digits(9) = 1
+  -- . nof_digits(10) = 2
+  BEGIN
+    IF number>0 THEN
+      RETURN floor_log10(number)+1;
+    ELSE 
+      RETURN 1;
+    END IF;
+  END;
+
+  FUNCTION nof_digits_int(number: INTEGER) RETURN NATURAL IS
+  -- Returns number of digits in a natural number. Only used in string processing, so defined here.
+  -- log10(0) is not allowed so:
+  -- . nof_digits(0) = 1
+  -- We're adding 1 so:
+  -- . nof_digits(1) = 1
+  -- . nof_digits(9) = 1
+  -- . nof_digits(10) = 2
+  -- . nof_digits(1) = 2
+  BEGIN
+    IF number=0 THEN
+      RETURN 1;
+    ELSE  
+      IF number > 0 THEN
+        RETURN floor_log10(number)+1;
+      ELSE
+        RETURN floor_log10(-1*number)+2;
+      END IF;
+    END IF;
+  END;
+
+  FUNCTION time_to_str(in_time : TIME) RETURN STRING IS
+    CONSTANT c_max_len_time : NATURAL := 20;
+  	VARIABLE v_line         : LINE;
+  	VARIABLE v_str          : STRING(1 TO c_max_len_time):= (OTHERS => ' '); 
+  BEGIN
+    write(v_line, in_time);
+  	v_str(v_line.ALL'RANGE) := v_line.ALL;
+  	deallocate(v_line);
+  	RETURN v_str;
+  END;
+
+  FUNCTION str_to_time(in_str : STRING) RETURN TIME IS
+  BEGIN
+    RETURN TIME'VALUE(in_str);
+  END;
+
+  FUNCTION slv_to_str(slv : STD_LOGIC_VECTOR) RETURN STRING IS
+    VARIABLE v_line : LINE;  
+    VARIABLE v_str  : STRING(1 TO slv'LENGTH) := (OTHERS => ' ');
+  BEGIN
+     write(v_line, slv);
+     v_str(v_line.ALL'RANGE) := v_line.ALL;
+     deallocate(v_line);
+     RETURN v_str;
+  END;
+
+  FUNCTION str_to_hex(str : STRING) RETURN STRING IS
+    CONSTANT c_nof_nibbles : NATURAL := ceil_div(str'LENGTH, c_nibble_w);
+    VARIABLE v_nibble_arr  : t_str_4_arr(0 TO c_nof_nibbles-1) := (OTHERS=>(OTHERS=>'0'));
+    VARIABLE v_hex         : STRING(1 TO c_nof_nibbles) := (OTHERS => '0');
+  BEGIN
+    FOR i IN 0 TO v_hex'RIGHT-1 LOOP
+      v_nibble_arr(i) := slice_up(str, c_nibble_w, i, '0'); 
+
+      CASE v_nibble_arr(i) IS
+        WHEN "0000" => v_hex(i+1) := '0';
+        WHEN "0001" => v_hex(i+1) := '1'; 
+        WHEN "0010" => v_hex(i+1) := '2';
+        WHEN "0011" => v_hex(i+1) := '3';
+        WHEN "0100" => v_hex(i+1) := '4';
+        WHEN "0101" => v_hex(i+1) := '5';
+        WHEN "0110" => v_hex(i+1) := '6';
+        WHEN "0111" => v_hex(i+1) := '7';
+        WHEN "1000" => v_hex(i+1) := '8';
+        WHEN "1001" => v_hex(i+1) := '9';
+        WHEN "1010" => v_hex(i+1) := 'A';
+        WHEN "1011" => v_hex(i+1) := 'B';
+        WHEN "1100" => v_hex(i+1) := 'C';
+        WHEN "1101" => v_hex(i+1) := 'D';
+        WHEN "1110" => v_hex(i+1) := 'E';
+        WHEN "1111" => v_hex(i+1) := 'F';
+        WHEN OTHERS => v_hex(i+1) := 'X';
+      END CASE; 
+    END LOOP;
+    RETURN v_hex; 
+  END;
+
+  FUNCTION slv_to_hex(slv :STD_LOGIC_VECTOR) RETURN STRING IS 
+  BEGIN 
+    RETURN str_to_hex(slv_to_str(slv));
+  END;
+
+  FUNCTION hex_to_slv(str: STRING) RETURN STD_LOGIC_VECTOR IS
+  CONSTANT c_length : NATURAL := str'LENGTH;
+  VARIABLE v_str    : STRING(1 TO str'LENGTH) := str; -- Keep local copy of str to prevent range mismatch
+  VARIABLE v_result : STD_LOGIC_VECTOR(c_length * 4 - 1 DOWNTO 0);
+  BEGIN 
+   FOR i IN c_length DOWNTO 1 LOOP
+       v_result(3 +(c_length - i)*4  DOWNTO (c_length-i)*4) := hex_nibble_to_slv(v_str(i));
+   END LOOP;
+   RETURN v_result;
+  END;
+
+  FUNCTION hex_nibble_to_slv(c: CHARACTER) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_result : STD_LOGIC_VECTOR(3 DOWNTO 0);
+  BEGIN
+    CASE c IS
+      WHEN '0' => v_result :=  "0000";
+      WHEN '1' => v_result :=  "0001";
+      WHEN '2' => v_result :=  "0010";
+      WHEN '3' => v_result :=  "0011";
+      WHEN '4' => v_result :=  "0100";
+      WHEN '5' => v_result :=  "0101";
+      WHEN '6' => v_result :=  "0110";
+      WHEN '7' => v_result :=  "0111";
+      WHEN '8' => v_result :=  "1000";
+      WHEN '9' => v_result :=  "1001";
+      WHEN 'A' => v_result :=  "1010";
+      WHEN 'B' => v_result :=  "1011";
+      WHEN 'C' => v_result :=  "1100";
+      WHEN 'D' => v_result :=  "1101";
+      WHEN 'E' => v_result :=  "1110";
+      WHEN 'F' => v_result :=  "1111";
+      WHEN 'a' => v_result :=  "1010";
+      WHEN 'b' => v_result :=  "1011";
+      WHEN 'c' => v_result :=  "1100";
+      WHEN 'd' => v_result :=  "1101";
+      WHEN 'e' => v_result :=  "1110";
+      WHEN 'f' => v_result :=  "1111";
+      WHEN 'x' => v_result :=  "XXXX";
+      WHEN 'X' => v_result :=  "XXXX";
+      WHEN 'z' => v_result :=  "ZZZZ";
+      WHEN 'Z' => v_result :=  "ZZZZ";
+        
+	    WHEN OTHERS => v_result := "0000";
+     END CASE;
+   RETURN v_result;
+  END hex_nibble_to_slv;
+
+  FUNCTION int_to_str(int: INTEGER) RETURN STRING IS
+--    CONSTANT c_max_len_int : NATURAL := 20;
+    VARIABLE v_line: LINE;
+    VARIABLE v_str: STRING(1 TO nof_digits_int(int)):= (OTHERS => ' ');
+  BEGIN 
+    STD.TEXTIO.WRITE(v_line, int);
+    v_str(v_line.ALL'RANGE) := v_line.ALL;
+    deallocate(v_line);
+    RETURN v_str;        
+  END;
+
+  FUNCTION real_to_str(re: REAL; width : INTEGER; digits : INTEGER) RETURN STRING IS
+    VARIABLE v_line: LINE;
+    VARIABLE v_str: STRING(1 TO width):= (OTHERS => ' ');
+  BEGIN 
+    STD.TEXTIO.WRITE(v_line, re, right, width, digits);
+    v_str(v_line.ALL'RANGE) := v_line.ALL;
+    deallocate(v_line);
+    RETURN v_str;        
+  END;
+
+  PROCEDURE print_str(str: STRING) IS
+  VARIABLE v_line: LINE;
+  BEGIN
+    write(v_line, str);
+    writeline(output, v_line);
+    deallocate(v_line);
+  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
+    FOR i IN s'RANGE LOOP
+      r(i-1) := CHARACTER'POS(s(i));
+    END LOOP;
+    RETURN r;
+  END;
+
+  FUNCTION str_to_ascii_slv_8_arr(s: STRING) RETURN t_slv_8_arr IS
+    VARIABLE r: t_slv_8_arr(0 TO s'RIGHT-1);
+  BEGIN
+    FOR i IN s'RANGE LOOP
+      r(i-1) := TO_UVEC(str_to_ascii_integer_arr(s)(i-1), 8);
+    END LOOP;
+    RETURN r;
+  END;
+
+  -- Returns minimum array size required to fit the string
+  FUNCTION str_to_ascii_slv_32_arr(s: STRING) RETURN t_slv_32_arr IS
+    CONSTANT c_slv_8: t_slv_8_arr(0 TO s'RIGHT-1) := str_to_ascii_slv_8_arr(s);
+    CONSTANT c_bytes_per_word : NATURAL := 4;
+    -- Initialize all elements to (OTHERS=>'0') so any unused bytes become a NULL character
+    VARIABLE r: t_slv_32_arr(0 TO ceil_div(s'RIGHT * c_byte_w, c_word_w)-1) := (OTHERS=>(OTHERS=>'0'));
+  BEGIN
+    FOR word IN r'RANGE  LOOP --0, 1
+      FOR byte IN 0 TO c_bytes_per_word-1 LOOP -- 0,1,2,3
+        IF byte+c_bytes_per_word*word<=c_slv_8'RIGHT THEN
+          r(word)(byte*c_byte_w+c_byte_w-1 DOWNTO byte*c_byte_w) := c_slv_8(byte+c_bytes_per_word*word); 
+        END IF;
+      END LOOP;
+    END LOOP;
+
+    RETURN r;
+  END;
+
+  -- Overloaded version to match array size to arr_size
+  FUNCTION str_to_ascii_slv_32_arr(s: STRING; arr_size: NATURAL) RETURN t_slv_32_arr IS
+    CONSTANT slv_32: t_slv_32_arr(0 TO ceil_div(s'RIGHT * c_byte_w, c_word_w)-1) := str_to_ascii_slv_32_arr(s);   
+    VARIABLE r: t_slv_32_arr(0 TO arr_size-1) := (OTHERS=>(OTHERS=>'0'));
+  BEGIN
+    FOR word IN slv_32'RANGE  LOOP
+      r(word) := slv_32(word);
+    END LOOP;
+    RETURN r;
+  END;
+
+END common_str_pkg;
+
diff --git a/cores/base/common/common_pkg/hdllib.cfg b/cores/base/common/common_pkg/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..f6768a9929395c39a4348540ac0a859cafb71f78
--- /dev/null
+++ b/cores/base/common/common_pkg/hdllib.cfg
@@ -0,0 +1,21 @@
+hdl_lib_name = common_pkg
+hdl_library_clause_name = common_pkg_lib
+hdl_lib_uses_synth = 
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    common_pkg.vhd
+    common_str_pkg.vhd
+    common_lfsr_sequences_pkg.vhd
+    tb_common_pkg.vhd
+
+test_bench_files = 
+
+regression_test_vhdl = 
+    
+[modelsim_project_file]
+modelsim_copy_files =
+
+[quartus_project_file]
+
diff --git a/cores/base/common/common_pkg/tb_common_pkg.vhd b/cores/base/common/common_pkg/tb_common_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..7e87a3ffb399f71d02e7349b757b0ba4ef972091
--- /dev/null
+++ b/cores/base/common/common_pkg/tb_common_pkg.vhd
@@ -0,0 +1,1358 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE std.textio.ALL;             -- for boolean, integer file IO
+USE IEEE.std_logic_textio.ALL;  -- for std_logic, std_logic_vector file IO
+USE work.common_pkg.ALL;  
+
+
+PACKAGE tb_common_pkg IS
+
+  PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
+                                                c_nof_cycles : IN  NATURAL);
+                                                
+  PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
+                                                c_nof_cycles : IN  REAL);
+                                                
+  PROCEDURE proc_common_wait_some_cycles(SIGNAL clk_in       : IN  STD_LOGIC;
+                                         SIGNAL clk_out      : IN  STD_LOGIC;
+                                                c_nof_cycles : IN  NATURAL);
+      
+  PROCEDURE proc_common_wait_some_pulses(SIGNAL clk          : IN  STD_LOGIC;
+                                         SIGNAL pulse        : IN  STD_LOGIC;
+                                                c_nof_pulses : IN  NATURAL);
+                                                
+  PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
+                                       SIGNAL level  : IN  STD_LOGIC);
+                                                
+  PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
+                                       SIGNAL level  : IN  INTEGER);
+                                                
+  PROCEDURE proc_common_wait_until_evt(CONSTANT c_timeout : IN  NATURAL;
+                                       SIGNAL   clk       : IN  STD_LOGIC;
+                                       SIGNAL   level     : IN  STD_LOGIC);
+                                        
+  PROCEDURE proc_common_wait_until_high(CONSTANT c_timeout : IN  NATURAL;
+                                        SIGNAL   clk       : IN  STD_LOGIC;
+                                        SIGNAL   level     : IN  STD_LOGIC);
+                                        
+  PROCEDURE proc_common_wait_until_high(SIGNAL clk    : IN  STD_LOGIC;
+                                        SIGNAL level  : IN  STD_LOGIC);
+                                                
+  PROCEDURE proc_common_wait_until_low(CONSTANT c_timeout : IN  NATURAL;
+                                       SIGNAL   clk       : IN  STD_LOGIC;
+                                       SIGNAL   level     : IN  STD_LOGIC);
+                                       
+  PROCEDURE proc_common_wait_until_low(SIGNAL clk    : IN  STD_LOGIC;
+                                       SIGNAL level  : IN  STD_LOGIC);
+                                         
+  PROCEDURE proc_common_wait_until_hi_lo(CONSTANT c_timeout : IN  NATURAL;
+                                         SIGNAL   clk       : IN  STD_LOGIC;
+                                         SIGNAL   level     : IN  STD_LOGIC);
+                                         
+  PROCEDURE proc_common_wait_until_hi_lo(SIGNAL clk    : IN  STD_LOGIC;
+                                         SIGNAL level  : IN  STD_LOGIC);
+                                         
+  PROCEDURE proc_common_wait_until_lo_hi(CONSTANT c_timeout : IN  NATURAL;
+                                         SIGNAL   clk       : IN  STD_LOGIC;
+                                         SIGNAL   level     : IN  STD_LOGIC);
+                                         
+  PROCEDURE proc_common_wait_until_lo_hi(SIGNAL clk    : IN  STD_LOGIC;
+                                         SIGNAL level  : IN  STD_LOGIC);
+                                         
+  PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
+                                         SIGNAL clk       : IN  STD_LOGIC;
+                                         SIGNAL level     : IN  INTEGER);
+                                         
+  PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
+                                         SIGNAL clk       : IN  STD_LOGIC;
+                                         SIGNAL level     : IN  STD_LOGIC_VECTOR);
+                                         
+  PROCEDURE proc_common_wait_until_value(CONSTANT c_timeout : IN  NATURAL;
+                                         CONSTANT c_value   : IN  INTEGER;
+                                         SIGNAL clk         : IN  STD_LOGIC;
+                                         SIGNAL level       : IN  STD_LOGIC_VECTOR);
+
+  -- Wait until absolute simulation time NOW = c_time
+  PROCEDURE proc_common_wait_until_time(SIGNAL clk      : IN  STD_LOGIC;
+                                        CONSTANT c_time : IN  TIME);
+                                       
+  -- Exit simulation on timeout failure                                         
+  PROCEDURE proc_common_timeout_failure(CONSTANT c_timeout : IN TIME;
+                                        SIGNAL tb_end      : IN STD_LOGIC);
+
+                                       
+  -- Stop simulation using severity FAILURE when g_tb_end=TRUE, else for use in multi tb report as severity NOTE
+  PROCEDURE proc_common_stop_simulation(SIGNAL tb_end : IN STD_LOGIC);
+
+  PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
+                                        CONSTANT g_latency : IN NATURAL;   -- latency between tb_done and tb_)end
+                                        SIGNAL clk         : IN STD_LOGIC;
+                                        SIGNAL tb_done     : IN STD_LOGIC;
+                                        SIGNAL tb_end      : OUT STD_LOGIC);
+
+  PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
+                                        SIGNAL clk         : IN STD_LOGIC;
+                                        SIGNAL tb_done     : IN STD_LOGIC;
+                                        SIGNAL tb_end      : OUT STD_LOGIC);
+                                       
+  -- Handle stream ready signal, only support ready latency c_rl = 0 or 1.
+  PROCEDURE proc_common_ready_latency(CONSTANT c_rl      : IN  NATURAL;
+                                      SIGNAL   clk       : IN  STD_LOGIC;
+                                      SIGNAL   enable    : IN  STD_LOGIC;  -- when '1' then active output when ready
+                                      SIGNAL   ready     : IN  STD_LOGIC;
+                                      SIGNAL   out_valid : OUT STD_LOGIC);
+                                      
+                                  
+  -- Generate a single active, inactive pulse
+  PROCEDURE proc_common_gen_pulse(CONSTANT c_active : IN  NATURAL;    -- pulse active for nof clk
+                                  CONSTANT c_period : IN  NATURAL;    -- pulse period for nof clk
+                                  CONSTANT c_level  : IN  STD_LOGIC;  -- pulse level when active
+                                  SIGNAL   clk      : IN  STD_LOGIC;
+                                  SIGNAL   pulse    : OUT STD_LOGIC);
+                                  
+  -- Pulse forever after rst was released
+  PROCEDURE proc_common_gen_pulse(CONSTANT c_active : IN  NATURAL;    -- pulse active for nof clk
+                                  CONSTANT c_period : IN  NATURAL;    -- pulse period for nof clk
+                                  CONSTANT c_level  : IN  STD_LOGIC;  -- pulse level when active
+                                  SIGNAL   rst      : IN  STD_LOGIC;
+                                  SIGNAL   clk      : IN  STD_LOGIC;
+                                  SIGNAL   pulse    : OUT STD_LOGIC);
+                                       
+  -- Generate a single '1', '0' pulse
+  PROCEDURE proc_common_gen_pulse(SIGNAL clk   : IN  STD_LOGIC;
+                                  SIGNAL pulse : OUT STD_LOGIC);
+                                  
+  -- Generate a periodic pulse with arbitrary duty cycle
+  PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_delay     : IN  NATURAL;    -- delay pulse for nof_clk after enable
+                                       CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
+                                       CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
+                                       CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
+                                       SIGNAL   rst         : IN  STD_LOGIC;
+                                       SIGNAL   clk         : IN  STD_LOGIC;
+                                       SIGNAL   enable      : IN  STD_LOGIC;  -- once enabled, the pulse remains enabled
+                                       SIGNAL   pulse       : OUT STD_LOGIC);
+                                       
+  PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
+                                       CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
+                                       CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
+                                       SIGNAL   rst         : IN  STD_LOGIC;
+                                       SIGNAL   clk         : IN  STD_LOGIC;
+                                       SIGNAL   enable      : IN  STD_LOGIC;  -- once enabled, the pulse remains enabled
+                                       SIGNAL   pulse       : OUT STD_LOGIC);
+                                       
+  -- Generate counter data with valid and arbitrary increment or fixed increment=1
+  PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
+                                 CONSTANT c_init      : IN  INTEGER;
+                                 CONSTANT c_incr      : IN  INTEGER;
+                                 SIGNAL   rst         : IN  STD_LOGIC;
+                                 SIGNAL   clk         : IN  STD_LOGIC;
+                                 SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
+                                 SIGNAL   ready       : IN  STD_LOGIC;
+                                 SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
+                                 SIGNAL   out_valid   : OUT STD_LOGIC);
+                                 
+  PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
+                                 CONSTANT c_init      : IN  INTEGER;
+                                 SIGNAL   rst         : IN  STD_LOGIC;
+                                 SIGNAL   clk         : IN  STD_LOGIC;
+                                 SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
+                                 SIGNAL   ready       : IN  STD_LOGIC;
+                                 SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
+                                 SIGNAL   out_valid   : OUT STD_LOGIC);
+                                 
+  -- Generate frame control
+  PROCEDURE proc_common_sop(SIGNAL clk     : IN  STD_LOGIC;
+                            SIGNAL in_val  : OUT STD_LOGIC;
+                            SIGNAL in_sop  : OUT STD_LOGIC);
+                            
+  PROCEDURE proc_common_eop(SIGNAL clk     : IN  STD_LOGIC;
+                            SIGNAL in_val  : OUT STD_LOGIC;
+                            SIGNAL in_eop  : OUT STD_LOGIC);
+                            
+  PROCEDURE proc_common_val(CONSTANT c_val_len : IN NATURAL;
+                            SIGNAL   clk       : IN  STD_LOGIC;
+                            SIGNAL   in_val    : OUT STD_LOGIC);
+                            
+  PROCEDURE proc_common_val_duty(CONSTANT c_hi_len  : IN NATURAL;
+                                 CONSTANT c_lo_len  : IN NATURAL;
+                                 SIGNAL   clk       : IN  STD_LOGIC;
+                                 SIGNAL   in_val    : OUT STD_LOGIC);
+                                 
+  PROCEDURE proc_common_eop_flush(CONSTANT c_flush_len : IN NATURAL;
+                                  SIGNAL   clk         : IN  STD_LOGIC;
+                                  SIGNAL   in_val      : OUT STD_LOGIC;
+                                  SIGNAL   in_eop      : OUT STD_LOGIC);
+                                       
+  -- Verify the DUT output incrementing data, only support ready latency c_rl = 0 or 1.
+  PROCEDURE proc_common_verify_data(CONSTANT c_rl            : IN    NATURAL;
+                                    SIGNAL   clk             : IN    STD_LOGIC;
+                                    SIGNAL   verify_en       : IN    STD_LOGIC;
+                                    SIGNAL   ready           : IN    STD_LOGIC;
+                                    SIGNAL   out_valid       : IN    STD_LOGIC;
+                                    SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                    SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                    
+  -- Verify the DUT output valid for ready latency, only support ready latency c_rl = 0 or 1.
+  PROCEDURE proc_common_verify_valid(CONSTANT c_rl        : IN    NATURAL;
+                                     SIGNAL   clk         : IN    STD_LOGIC;
+                                     SIGNAL   verify_en   : IN    STD_LOGIC;
+                                     SIGNAL   ready       : IN    STD_LOGIC;
+                                     SIGNAL   prev_ready  : INOUT STD_LOGIC;
+                                     SIGNAL   out_valid   : IN    STD_LOGIC);
+                                     
+  -- Verify the DUT input to output latency for SL ctrl signals
+  PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "valid", "sop", "eop"
+                                       CONSTANT c_latency     : IN    NATURAL;
+                                       SIGNAL   clk           : IN    STD_LOGIC;
+                                       SIGNAL   verify_en     : IN    STD_LOGIC;
+                                       SIGNAL   in_ctrl       : IN    STD_LOGIC;
+                                       SIGNAL   pipe_ctrl_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:c_latency]
+                                       SIGNAL   out_ctrl      : IN    STD_LOGIC);
+                                       
+  -- Verify the DUT input to output latency for SLV data signals
+  PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "data"
+                                       CONSTANT c_latency     : IN    NATURAL;
+                                       SIGNAL   clk           : IN    STD_LOGIC;
+                                       SIGNAL   verify_en     : IN    STD_LOGIC;
+                                       SIGNAL   in_data       : IN    STD_LOGIC_VECTOR;
+                                       SIGNAL   pipe_data_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:(1 + c_latency)*c_data_w-1]
+                                       SIGNAL   out_data      : IN    STD_LOGIC_VECTOR);
+                                       
+  -- Verify the expected value, e.g. to check that a test has ran at all
+  PROCEDURE proc_common_verify_value(CONSTANT mode : IN NATURAL;
+                                     SIGNAL   clk  : IN STD_LOGIC;
+                                     SIGNAL   en   : IN STD_LOGIC;
+                                     SIGNAL   exp  : IN STD_LOGIC_VECTOR;  
+                                     SIGNAL   res  : IN STD_LOGIC_VECTOR);
+  -- open, read line, close file
+  PROCEDURE proc_common_open_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                  FILE in_file : TEXT; 
+                                  file_name    : IN STRING;
+                                  file_mode    : IN FILE_OPEN_KIND);
+  
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      read_value_0 : OUT INTEGER);
+  
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      read_value_0 : OUT INTEGER;
+                                      read_value_1 : OUT INTEGER);
+  
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      value_array  : OUT t_integer_arr;
+                                      nof_reads    : IN  INTEGER);
+                                  
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      read_slv     : OUT STD_LOGIC_VECTOR);
+                                  
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;                  
+                                      res_string   : OUT STRING);
+  
+  PROCEDURE proc_common_close_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                   FILE in_file : TEXT);
+
+  -- read entire file
+  PROCEDURE proc_common_read_integer_file(file_name              : IN  STRING;
+                                          nof_header_lines       : NATURAL;
+                                          nof_row                : NATURAL;
+                                          nof_col                : NATURAL;
+                                          SIGNAL return_array    : OUT t_integer_arr);
+                                  
+  PROCEDURE proc_common_read_mif_file(file_name           : IN  STRING;
+                                      SIGNAL return_array : OUT t_integer_arr);
+  
+  -- Complex multiply function with conjugate option for input b
+  FUNCTION func_complex_multiply(in_ar, in_ai, in_br, in_bi : STD_LOGIC_VECTOR; conjugate_b : BOOLEAN; str : STRING; g_out_dat_w : NATURAL) RETURN STD_LOGIC_VECTOR;
+  
+  FUNCTION func_decstring_to_integer(in_string: STRING) RETURN INTEGER;     
+  
+  FUNCTION func_hexstring_to_integer(in_string: STRING) RETURN INTEGER;     
+  
+  FUNCTION func_find_char_in_string(in_string: STRING; find_char: CHARACTER) RETURN INTEGER;
+  
+  FUNCTION func_find_string_in_string(in_string: STRING; find_string: STRING) RETURN BOOLEAN;
+  
+END tb_common_pkg;
+
+
+PACKAGE BODY tb_common_pkg IS
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Wait some clock cycles
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
+                                                c_nof_cycles : IN  NATURAL) IS
+  BEGIN
+    FOR I IN 0 TO c_nof_cycles-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+  END proc_common_wait_some_cycles;
+  
+  PROCEDURE proc_common_wait_some_cycles(SIGNAL clk          : IN  STD_LOGIC;
+                                                c_nof_cycles : IN  REAL) IS
+  BEGIN
+    proc_common_wait_some_cycles(clk, NATURAL(c_nof_cycles));
+  END proc_common_wait_some_cycles;
+  
+  PROCEDURE proc_common_wait_some_cycles(SIGNAL clk_in       : IN  STD_LOGIC;
+                                         SIGNAL clk_out      : IN  STD_LOGIC;
+                                                c_nof_cycles : IN  NATURAL) IS
+  BEGIN
+    proc_common_wait_some_cycles(clk_in, c_nof_cycles);
+    proc_common_wait_some_cycles(clk_out, c_nof_cycles);
+  END proc_common_wait_some_cycles;
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Wait some pulses
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_wait_some_pulses(SIGNAL clk          : IN  STD_LOGIC;
+                                         SIGNAL pulse        : IN  STD_LOGIC;
+                                                c_nof_pulses : IN  NATURAL) IS
+  BEGIN
+    FOR I IN 0 TO c_nof_pulses-1 LOOP
+      proc_common_wait_until_hi_lo(clk, pulse);
+    END LOOP;
+  END proc_common_wait_some_pulses;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Wait until the level input event
+  -- PROCEDURE: Wait until the level input is high
+  -- PROCEDURE: Wait until the level input is low
+  -- PROCEDURE: Wait until the       input is equal to c_value
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
+                                       SIGNAL level  : IN  STD_LOGIC) IS
+    VARIABLE v_level : STD_LOGIC := level;
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    WHILE v_level=level LOOP
+      v_level := level;
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_common_wait_until_evt;
+  
+  PROCEDURE proc_common_wait_until_evt(SIGNAL clk    : IN  STD_LOGIC;
+                                       SIGNAL level  : IN  INTEGER) IS
+    VARIABLE v_level : INTEGER := level;
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    WHILE v_level=level LOOP
+      v_level := level;
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_common_wait_until_evt;
+  
+  PROCEDURE proc_common_wait_until_evt(CONSTANT c_timeout : IN  NATURAL;
+                                       SIGNAL   clk       : IN  STD_LOGIC;
+                                       SIGNAL   level     : IN  STD_LOGIC) IS
+    VARIABLE v_level : STD_LOGIC := level;
+    VARIABLE v_I     : NATURAL := 0;
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    WHILE v_level=level LOOP
+      v_level := level;
+      WAIT UNTIL rising_edge(clk);
+      v_I := v_I + 1;
+      IF v_I>=c_timeout-1 THEN
+        REPORT "COMMON : level evt timeout" SEVERITY ERROR;
+        EXIT;
+      END IF;
+    END LOOP;
+  END proc_common_wait_until_evt;
+  
+  PROCEDURE proc_common_wait_until_high(SIGNAL clk    : IN  STD_LOGIC;
+                                        SIGNAL level  : IN  STD_LOGIC) IS
+  BEGIN
+    IF level/='1' THEN
+      WAIT UNTIL rising_edge(clk) AND level='1';
+    END IF;
+  END proc_common_wait_until_high;
+  
+  PROCEDURE proc_common_wait_until_high(CONSTANT c_timeout : IN  NATURAL;
+                                        SIGNAL   clk       : IN  STD_LOGIC;
+                                        SIGNAL   level     : IN  STD_LOGIC) IS
+  BEGIN
+    FOR I IN 0 TO c_timeout-1 LOOP
+      IF level='1' THEN
+        EXIT;
+      ELSE
+        IF I=c_timeout-1 THEN
+          REPORT "COMMON : level high timeout" SEVERITY ERROR;
+        END IF;
+        WAIT UNTIL rising_edge(clk);
+      END IF;
+    END LOOP;
+  END proc_common_wait_until_high;
+  
+  PROCEDURE proc_common_wait_until_low(SIGNAL clk    : IN  STD_LOGIC;
+                                       SIGNAL level  : IN  STD_LOGIC) IS
+  BEGIN
+    IF level/='0' THEN
+      WAIT UNTIL rising_edge(clk) AND level='0';
+    END IF;
+  END proc_common_wait_until_low;
+  
+  PROCEDURE proc_common_wait_until_low(CONSTANT c_timeout : IN  NATURAL;
+                                       SIGNAL   clk       : IN  STD_LOGIC;
+                                       SIGNAL   level     : IN  STD_LOGIC) IS
+  BEGIN
+    FOR I IN 0 TO c_timeout-1 LOOP
+      IF level='0' THEN
+        EXIT;
+      ELSE
+        IF I=c_timeout-1 THEN
+          REPORT "COMMON : level low timeout" SEVERITY ERROR;
+        END IF;
+        WAIT UNTIL rising_edge(clk);
+      END IF;
+    END LOOP;
+  END proc_common_wait_until_low;
+  
+  PROCEDURE proc_common_wait_until_hi_lo(SIGNAL clk    : IN  STD_LOGIC;
+                                         SIGNAL level  : IN  STD_LOGIC) IS
+  BEGIN
+    IF level/='1' THEN
+      proc_common_wait_until_high(clk, level);
+    END IF;
+    proc_common_wait_until_low(clk, level);
+  END proc_common_wait_until_hi_lo;
+  
+  PROCEDURE proc_common_wait_until_hi_lo(CONSTANT c_timeout : IN  NATURAL;
+                                         SIGNAL   clk       : IN  STD_LOGIC;
+                                         SIGNAL   level     : IN  STD_LOGIC) IS
+  BEGIN
+    IF level/='1' THEN
+      proc_common_wait_until_high(c_timeout, clk, level);
+    END IF;
+    proc_common_wait_until_low(c_timeout, clk, level);
+  END proc_common_wait_until_hi_lo;
+  
+  PROCEDURE proc_common_wait_until_lo_hi(SIGNAL clk    : IN  STD_LOGIC;
+                                         SIGNAL level  : IN  STD_LOGIC) IS
+  BEGIN
+    IF level/='0' THEN
+      proc_common_wait_until_low(clk, level);
+    END IF;
+    proc_common_wait_until_high(clk, level);
+  END proc_common_wait_until_lo_hi;
+  
+  PROCEDURE proc_common_wait_until_lo_hi(CONSTANT c_timeout : IN  NATURAL;
+                                         SIGNAL   clk       : IN  STD_LOGIC;
+                                         SIGNAL   level     : IN  STD_LOGIC) IS
+  BEGIN
+    IF level/='0' THEN
+      proc_common_wait_until_low(c_timeout, clk, level);
+    END IF;
+    proc_common_wait_until_high(c_timeout, clk, level);
+  END proc_common_wait_until_lo_hi;
+  
+  PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
+                                         SIGNAL clk       : IN  STD_LOGIC;
+                                         SIGNAL level     : IN  INTEGER) IS
+  BEGIN
+    WHILE level/=c_value LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_common_wait_until_value;
+  
+  PROCEDURE proc_common_wait_until_value(CONSTANT c_value : IN  INTEGER;
+                                         SIGNAL clk       : IN  STD_LOGIC;
+                                         SIGNAL level     : IN  STD_LOGIC_VECTOR) IS
+  BEGIN
+    WHILE SIGNED(level)/=c_value LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_common_wait_until_value;
+  
+  PROCEDURE proc_common_wait_until_value(CONSTANT c_timeout : IN  NATURAL;
+                                         CONSTANT c_value   : IN  INTEGER;
+                                         SIGNAL clk         : IN  STD_LOGIC;
+                                         SIGNAL level       : IN  STD_LOGIC_VECTOR) IS
+  BEGIN
+    FOR I IN 0 TO c_timeout-1 LOOP
+      IF SIGNED(level)=c_value THEN
+        EXIT;
+      ELSE
+        IF I=c_timeout-1 THEN
+          REPORT "COMMON : level value timeout" SEVERITY ERROR;
+        END IF;
+        WAIT UNTIL rising_edge(clk);
+      END IF;
+    END LOOP;
+  END proc_common_wait_until_value;
+  
+  PROCEDURE proc_common_wait_until_time(SIGNAL clk      : IN  STD_LOGIC;
+                                        CONSTANT c_time : IN  TIME) IS
+  BEGIN
+    WHILE NOW < c_time LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END PROCEDURE;                                        
+ 
+  PROCEDURE proc_common_timeout_failure(CONSTANT c_timeout : IN TIME;
+                                        SIGNAL tb_end      : IN STD_LOGIC) IS
+  BEGIN
+    WHILE tb_end='0' LOOP
+      ASSERT NOW < c_timeout REPORT "Test bench timeout." SEVERITY FAILURE;
+      WAIT FOR 1 us;
+    END LOOP;
+  END PROCEDURE;
+
+  PROCEDURE proc_common_stop_simulation(SIGNAL tb_end : IN STD_LOGIC) IS
+  BEGIN
+    WAIT UNTIL tb_end='1';
+    -- For modelsim_regression_test_vhdl.py:
+    -- The tb_end will stop the test verification bases on error or failure. The wait is necessary to
+    -- stop the simulation using failure, without causing the test to fail.
+    WAIT FOR 1 ns;
+    REPORT "Tb simulation finished." SEVERITY FAILURE;
+    WAIT;
+  END PROCEDURE;
+  
+  PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
+                                        CONSTANT g_latency : IN NATURAL;
+                                        SIGNAL clk         : IN STD_LOGIC;
+                                        SIGNAL tb_done     : IN STD_LOGIC;
+                                        SIGNAL tb_end      : OUT STD_LOGIC) IS
+  BEGIN
+    -- Wait until simulation indicates done
+    proc_common_wait_until_high(clk, tb_done);
+    
+    -- Wait some more cycles
+    proc_common_wait_some_cycles(clk, g_latency);
+    
+    -- Stop the simulation or only report NOTE
+    tb_end <= '1';
+    -- For modelsim_regression_test_vhdl.py:
+    -- The tb_end will stop the test verification bases on error or failure. The wait is necessary to
+    -- stop the simulation using failure, without causing the test to fail.
+    WAIT FOR 1 ns;
+    IF g_tb_end=FALSE THEN
+      REPORT "Tb Simulation finished." SEVERITY NOTE;
+    ELSE
+      REPORT "Tb Simulation finished." SEVERITY FAILURE;
+    END IF;
+    WAIT;
+  END PROCEDURE;
+
+  PROCEDURE proc_common_stop_simulation(CONSTANT g_tb_end  : IN BOOLEAN;
+                                        SIGNAL clk         : IN STD_LOGIC;
+                                        SIGNAL tb_done     : IN STD_LOGIC;
+                                        SIGNAL tb_end      : OUT STD_LOGIC) IS
+  BEGIN
+    proc_common_stop_simulation(g_tb_end, 0, clk, tb_done, tb_end);
+  END PROCEDURE;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Handle stream ready signal for data valid
+  -- . output active when ready='1' and enable='1'
+  -- . only support ready latency c_rl = 0 or 1
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_ready_latency(CONSTANT c_rl      : IN  NATURAL;
+                                      SIGNAL   clk       : IN  STD_LOGIC;
+                                      SIGNAL   enable    : IN  STD_LOGIC;
+                                      SIGNAL   ready     : IN  STD_LOGIC;
+                                      SIGNAL   out_valid : OUT STD_LOGIC) IS
+  BEGIN
+    -- skip ready cycles until enable='1'
+    out_valid <= '0';
+    WHILE enable='0' LOOP
+      IF c_rl=0 THEN
+        WAIT UNTIL rising_edge(clk);
+        WHILE ready /= '1' LOOP
+          WAIT UNTIL rising_edge(clk);
+        END LOOP;
+      END IF;
+      IF c_rl=1 THEN
+        WHILE ready /= '1' LOOP
+          WAIT UNTIL rising_edge(clk);
+        END LOOP;
+        WAIT UNTIL rising_edge(clk);
+      END IF;
+    END LOOP;
+    -- active output when ready
+    IF c_rl=0 THEN
+      out_valid <= '1';
+      WAIT UNTIL rising_edge(clk);
+      WHILE ready /= '1' LOOP
+        WAIT UNTIL rising_edge(clk);
+      END LOOP;
+    END IF;
+    IF c_rl=1 THEN
+      WHILE ready /= '1' LOOP
+        out_valid <= '0';
+        WAIT UNTIL rising_edge(clk);
+      END LOOP;
+      out_valid <= '1';
+      WAIT UNTIL rising_edge(clk);
+    END IF;
+  END proc_common_ready_latency;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate a single active, inactive pulse
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_gen_pulse(CONSTANT c_active  : IN  NATURAL;    -- pulse active for nof clk
+                                  CONSTANT c_period  : IN  NATURAL;    -- pulse period for nof clk
+                                  CONSTANT c_level   : IN  STD_LOGIC;  -- pulse level when active
+                                  SIGNAL   clk       : IN  STD_LOGIC;
+                                  SIGNAL   pulse     : OUT STD_LOGIC) IS
+    VARIABLE v_cnt : NATURAL RANGE 0 TO c_period := 0;
+  BEGIN
+    WHILE v_cnt<c_period LOOP
+      IF v_cnt<c_active THEN
+        pulse <= c_level;
+      ELSE
+        pulse <= NOT c_level;    
+      END IF;
+      v_cnt := v_cnt+1;
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_common_gen_pulse;
+  
+  -- Pulse forever after rst was released
+  PROCEDURE proc_common_gen_pulse(CONSTANT c_active  : IN  NATURAL;    -- pulse active for nof clk
+                                  CONSTANT c_period  : IN  NATURAL;    -- pulse period for nof clk
+                                  CONSTANT c_level   : IN  STD_LOGIC;  -- pulse level when active
+                                  SIGNAL   rst       : IN  STD_LOGIC;
+                                  SIGNAL   clk       : IN  STD_LOGIC;
+                                  SIGNAL   pulse     : OUT STD_LOGIC) IS
+    VARIABLE v_cnt : NATURAL RANGE 0 TO c_period := 0;
+  BEGIN
+    pulse <= NOT c_level;
+    IF rst='0' THEN
+      WAIT UNTIL rising_edge(clk);
+      WHILE TRUE LOOP
+        proc_common_gen_pulse(c_active, c_period, c_level, clk, pulse);
+      END LOOP;
+    END IF;
+  END proc_common_gen_pulse;
+  
+  -- pulse '1', '0'
+  PROCEDURE proc_common_gen_pulse(SIGNAL clk   : IN  STD_LOGIC;
+                                  SIGNAL pulse : OUT STD_LOGIC) IS
+  BEGIN
+    proc_common_gen_pulse(1, 2, '1', clk, pulse);
+  END proc_common_gen_pulse;
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate a periodic pulse with arbitrary duty cycle
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_delay     : IN  NATURAL;    -- delay pulse for nof_clk after enable
+                                       CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
+                                       CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
+                                       CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
+                                       SIGNAL   rst         : IN  STD_LOGIC;
+                                       SIGNAL   clk         : IN  STD_LOGIC;
+                                       SIGNAL   enable      : IN  STD_LOGIC;
+                                       SIGNAL   pulse       : OUT STD_LOGIC) IS
+    VARIABLE v_cnt : NATURAL RANGE 0 TO c_period-1 := 0;
+  BEGIN
+    pulse <= NOT c_level;
+    IF rst='0' THEN
+      proc_common_wait_until_high(clk, enable);    -- if enabled then continue immediately else wait here
+      proc_common_wait_some_cycles(clk, c_delay);  -- apply initial c_delay. Once enabled, the pulse remains enabled
+      WHILE TRUE LOOP
+        WAIT UNTIL rising_edge(clk);
+        IF v_cnt<c_active THEN
+          pulse <= c_level;
+        ELSE
+          pulse <= NOT c_level;    
+        END IF;
+        IF v_cnt<c_period-1 THEN
+          v_cnt := v_cnt+1;
+        ELSE
+          v_cnt := 0;
+        END IF;
+      END LOOP;
+    END IF;
+  END proc_common_gen_duty_pulse;
+  
+  PROCEDURE proc_common_gen_duty_pulse(CONSTANT c_active    : IN  NATURAL;    -- pulse active for nof clk
+                                       CONSTANT c_period    : IN  NATURAL;    -- pulse period for nof clk
+                                       CONSTANT c_level     : IN  STD_LOGIC;  -- pulse level when active
+                                       SIGNAL   rst         : IN  STD_LOGIC;
+                                       SIGNAL   clk         : IN  STD_LOGIC;
+                                       SIGNAL   enable      : IN  STD_LOGIC;
+                                       SIGNAL   pulse       : OUT STD_LOGIC) IS
+  BEGIN
+    proc_common_gen_duty_pulse(0, c_active, c_period, c_level, rst, clk, enable, pulse);
+  END proc_common_gen_duty_pulse;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate counter data with valid
+  -- . Output counter data dependent on enable and ready
+  ------------------------------------------------------------------------------
+  -- arbitrary c_incr
+  PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
+                                 CONSTANT c_init      : IN  INTEGER;
+                                 CONSTANT c_incr      : IN  INTEGER;
+                                 SIGNAL   rst         : IN  STD_LOGIC;
+                                 SIGNAL   clk         : IN  STD_LOGIC;
+                                 SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
+                                 SIGNAL   ready       : IN  STD_LOGIC;
+                                 SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
+                                 SIGNAL   out_valid   : OUT STD_LOGIC) IS
+    CONSTANT c_data_w  : NATURAL := out_data'LENGTH;
+    VARIABLE v_data    : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= TO_SVEC(c_init, c_data_w);
+  BEGIN
+    out_valid <= '0';
+    out_data  <= v_data;
+    IF rst='0' THEN
+      WAIT UNTIL rising_edge(clk);
+      WHILE TRUE LOOP
+        out_data <= v_data;
+        proc_common_ready_latency(c_rl, clk, enable, ready, out_valid);
+        v_data := INCR_UVEC(v_data, c_incr);
+      END LOOP;
+    END IF;
+  END proc_common_gen_data;
+  
+  -- c_incr = 1
+  PROCEDURE proc_common_gen_data(CONSTANT c_rl        : IN  NATURAL;    -- 0, 1 are supported by proc_common_ready_latency()
+                                 CONSTANT c_init      : IN  INTEGER;
+                                 SIGNAL   rst         : IN  STD_LOGIC;
+                                 SIGNAL   clk         : IN  STD_LOGIC;
+                                 SIGNAL   enable      : IN  STD_LOGIC;  -- when '0' then no valid output even when ready='1'
+                                 SIGNAL   ready       : IN  STD_LOGIC;
+                                 SIGNAL   out_data    : OUT STD_LOGIC_VECTOR;
+                                 SIGNAL   out_valid   : OUT STD_LOGIC) IS
+  BEGIN
+    proc_common_gen_data(c_rl, c_init, 1, rst, clk, enable, ready, out_data, out_valid);
+  END proc_common_gen_data;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate frame control
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_sop(SIGNAL clk     : IN  STD_LOGIC;
+                            SIGNAL in_val  : OUT STD_LOGIC;
+                            SIGNAL in_sop  : OUT STD_LOGIC) IS
+  BEGIN
+    in_val <= '1';
+    in_sop <= '1';
+    proc_common_wait_some_cycles(clk, 1);
+    in_sop <= '0';
+  END proc_common_sop;
+    
+  PROCEDURE proc_common_eop(SIGNAL clk     : IN  STD_LOGIC;
+                            SIGNAL in_val  : OUT STD_LOGIC;
+                            SIGNAL in_eop  : OUT STD_LOGIC) IS
+  BEGIN
+    in_val <= '1';
+    in_eop <= '1';
+    proc_common_wait_some_cycles(clk, 1);
+    in_val <= '0';
+    in_eop <= '0';
+  END proc_common_eop;
+  
+  PROCEDURE proc_common_val(CONSTANT c_val_len : IN NATURAL;
+                            SIGNAL   clk       : IN  STD_LOGIC;
+                            SIGNAL   in_val    : OUT STD_LOGIC) IS
+  BEGIN
+    in_val <= '1';
+    proc_common_wait_some_cycles(clk, c_val_len);
+    in_val <= '0';
+  END proc_common_val;
+  
+  PROCEDURE proc_common_val_duty(CONSTANT c_hi_len  : IN NATURAL;
+                                 CONSTANT c_lo_len  : IN NATURAL;
+                                 SIGNAL   clk       : IN  STD_LOGIC;
+                                 SIGNAL   in_val    : OUT STD_LOGIC) IS
+  BEGIN
+    in_val <= '1';
+    proc_common_wait_some_cycles(clk, c_hi_len);
+    in_val <= '0';
+    proc_common_wait_some_cycles(clk, c_lo_len);
+  END proc_common_val_duty;
+  
+  PROCEDURE proc_common_eop_flush(CONSTANT c_flush_len : IN NATURAL;
+                                  SIGNAL   clk         : IN  STD_LOGIC;
+                                  SIGNAL   in_val      : OUT STD_LOGIC;
+                                  SIGNAL   in_eop      : OUT STD_LOGIC) IS
+  BEGIN
+    -- . eop
+    proc_common_eop(clk, in_val, in_eop);
+    -- . flush after in_eop to empty the shift register
+    proc_common_wait_some_cycles(clk, c_flush_len);
+  END proc_common_eop_flush;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify incrementing data
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_verify_data(CONSTANT c_rl            : IN    NATURAL;
+                                    SIGNAL   clk             : IN    STD_LOGIC;
+                                    SIGNAL   verify_en       : IN    STD_LOGIC;
+                                    SIGNAL   ready           : IN    STD_LOGIC;
+                                    SIGNAL   out_valid       : IN    STD_LOGIC;
+                                    SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                    SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+    VARIABLE v_exp_data : STD_LOGIC_VECTOR(out_data'RANGE);
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- out_valid must be active, because only the out_data will it differ from the previous out_data
+      IF out_valid='1' THEN
+        -- for ready_latency = 1 out_valid indicates new data
+        -- for ready_latency = 0 out_valid only indicates new data when it is confirmed by ready
+        IF c_rl=1 OR (c_rl=0 AND ready='1') THEN
+          prev_out_data <= out_data;
+          v_exp_data := INCR_UVEC(prev_out_data, 1);  -- increment first then compare to also support increment wrap around
+          IF verify_en='1' AND UNSIGNED(out_data) /= UNSIGNED(v_exp_data) THEN
+            REPORT "COMMON : Wrong out_data count" SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_verify_data;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output valid
+  -- . only support ready latency c_rl = 0 or 1
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_verify_valid(CONSTANT c_rl        : IN    NATURAL;
+                                     SIGNAL   clk         : IN    STD_LOGIC;
+                                     SIGNAL   verify_en   : IN    STD_LOGIC;
+                                     SIGNAL   ready       : IN    STD_LOGIC;
+                                     SIGNAL   prev_ready  : INOUT STD_LOGIC;
+                                     SIGNAL   out_valid   : IN    STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- for ready latency c_rl = 1 out_valid may only be asserted after ready
+      -- for ready latency c_rl = 0 out_valid may always be asserted
+      prev_ready <= '0';
+      IF c_rl=1 THEN
+        prev_ready <= ready;
+        IF verify_en='1' AND out_valid='1' THEN
+          IF prev_ready/='1' THEN
+            REPORT "COMMON : Wrong ready latency between ready and out_valid" SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_verify_valid;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT input to output latency
+  ------------------------------------------------------------------------------
+  -- for SL ctrl
+  PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "valid", "sop", "eop"
+                                       CONSTANT c_latency     : IN    NATURAL;
+                                       SIGNAL   clk           : IN    STD_LOGIC;
+                                       SIGNAL   verify_en     : IN    STD_LOGIC;
+                                       SIGNAL   in_ctrl       : IN    STD_LOGIC;
+                                       SIGNAL   pipe_ctrl_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:c_latency]
+                                       SIGNAL   out_ctrl      : IN    STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      pipe_ctrl_vec <= in_ctrl & pipe_ctrl_vec(0 TO c_latency-1);  -- note: pipe_ctrl_vec(c_latency) is a dummy place holder to avoid [0:-1] range
+      IF verify_en='1' THEN
+        IF c_latency=0 THEN
+          IF in_ctrl/=out_ctrl THEN
+            REPORT "COMMON : Wrong zero latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
+          END IF;
+        ELSE
+          IF pipe_ctrl_vec(c_latency-1)/=out_ctrl THEN
+            REPORT "COMMON : Wrong latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_verify_latency;
+  
+  
+  -- for SLV data
+  PROCEDURE proc_common_verify_latency(CONSTANT c_str         : IN    STRING;   -- e.g. "data"
+                                       CONSTANT c_latency     : IN    NATURAL;
+                                       SIGNAL   clk           : IN    STD_LOGIC;
+                                       SIGNAL   verify_en     : IN    STD_LOGIC;
+                                       SIGNAL   in_data       : IN    STD_LOGIC_VECTOR;
+                                       SIGNAL   pipe_data_vec : INOUT STD_LOGIC_VECTOR;  -- range [0:(1 + c_latency)*c_data_w-1]
+                                       SIGNAL   out_data      : IN    STD_LOGIC_VECTOR) IS
+    CONSTANT c_data_w     : NATURAL := in_data'LENGTH;
+    CONSTANT c_data_vec_w : NATURAL := pipe_data_vec'LENGTH;  -- = (1 + c_latency) * c_data_w
+  BEGIN
+    IF rising_edge(clk) THEN
+      pipe_data_vec <= in_data & pipe_data_vec(0 TO c_data_vec_w-c_data_w-1);  -- note: pipe_data_vec(c_latency) is a dummy place holder to avoid [0:-1] range
+      IF verify_en='1' THEN
+        IF c_latency=0 THEN
+          IF UNSIGNED(in_data)/=UNSIGNED(out_data) THEN
+            REPORT "COMMON : Wrong zero latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
+          END IF;
+        ELSE
+          IF UNSIGNED(pipe_data_vec(c_data_vec_w-c_data_w-c_data_w TO c_data_vec_w-c_data_w-1))/=UNSIGNED(out_data) THEN
+            REPORT "COMMON : Wrong latency between input " & c_str & " and output " & c_str SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_verify_latency;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the expected value
+  -- . e.g. to check that a test has ran at all
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_verify_value(CONSTANT mode : IN NATURAL;
+                                     SIGNAL   clk  : IN STD_LOGIC;
+                                     SIGNAL   en   : IN STD_LOGIC;
+                                     SIGNAL   exp  : IN STD_LOGIC_VECTOR;  
+                                     SIGNAL   res  : IN STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF en='1' THEN
+        IF mode = 0 AND UNSIGNED(res) /= UNSIGNED(exp) THEN
+          REPORT "COMMON : Wrong result value" SEVERITY ERROR;             -- == (equal)
+        END IF;
+        IF mode = 1 AND UNSIGNED(res) < UNSIGNED(exp) THEN
+          REPORT "COMMON : Wrong result value too small" SEVERITY ERROR;   -- >= (at least)
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_verify_value;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Opens a file for access and reports fail or success of opening. 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_open_file( file_status  : INOUT FILE_OPEN_STATUS;
+                                   FILE in_file : TEXT; 
+                                   file_name    : IN    STRING;
+                                   file_mode    : IN    FILE_OPEN_KIND) IS
+  BEGIN
+    IF file_status=OPEN_OK THEN
+      file_close(in_file);
+    END IF;
+    file_open (file_status, in_file, file_name, file_mode);
+    IF file_status=OPEN_OK THEN
+      REPORT "COMMON : File opened " SEVERITY NOTE;
+    ELSE
+      REPORT "COMMON : Unable to open file " SEVERITY FAILURE;
+    END IF;
+  END proc_common_open_file;
+
+ ------------------------------------------------------------------------------
+  -- PROCEDURE: Reads an integer from a file. 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      read_value_0 : OUT INTEGER) IS
+     VARIABLE v_line : LINE;    
+     VARIABLE v_good : BOOLEAN; 
+  BEGIN
+    IF file_status/=OPEN_OK THEN
+      REPORT "COMMON : File is not opened " SEVERITY FAILURE;
+    ELSE
+      IF ENDFILE(in_file) THEN
+        REPORT "COMMON : end of file " SEVERITY NOTE;
+      ELSE
+        READLINE(in_file, v_line);
+        READ(v_line, read_value_0, v_good);         
+        IF v_good = FALSE THEN 
+          REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_readline_file;
+ 
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Reads two integers from two columns in a file. 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      read_value_0 : OUT INTEGER;  
+                                      read_value_1 : OUT INTEGER) IS 
+     VARIABLE v_line : LINE;    
+     VARIABLE v_good : BOOLEAN; 
+  BEGIN
+    IF file_status/=OPEN_OK THEN
+      REPORT "COMMON : File is not opened " SEVERITY FAILURE;
+    ELSE
+      IF ENDFILE(in_file) THEN
+        REPORT "COMMON : end of file " SEVERITY NOTE;
+      ELSE
+        READLINE(in_file, v_line);
+        READ(v_line, read_value_0, v_good);         
+        IF v_good = FALSE THEN 
+          REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
+        END IF;
+        READ(v_line, read_value_1, v_good);         
+        IF v_good = FALSE THEN 
+          REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_readline_file;
+
+------------------------------------------------------------------------------
+  -- PROCEDURE: Reads an array of integer from a file. 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      value_array  : OUT t_integer_arr;  
+                                      nof_reads    : IN  INTEGER) IS 
+     VARIABLE v_line : LINE;    
+     VARIABLE v_good : BOOLEAN; 
+  BEGIN
+    IF file_status/=OPEN_OK THEN
+      REPORT "COMMON : File is not opened " SEVERITY FAILURE;
+    ELSE
+      IF ENDFILE(in_file) THEN
+        REPORT "COMMON : end of file " SEVERITY NOTE;
+      ELSE
+        READLINE(in_file, v_line);
+        FOR I IN 0 TO nof_reads - 1 LOOP 
+          READ(v_line, value_array(I), v_good);         
+          IF v_good = FALSE THEN 
+            REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
+          END IF;
+        END LOOP;
+      END IF;
+    END IF;
+  END proc_common_readline_file;
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Reads an std_logic_vector from a file
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;
+                                      read_slv     : OUT STD_LOGIC_VECTOR) IS
+     VARIABLE v_line : LINE;    
+     VARIABLE v_good : BOOLEAN; 
+  BEGIN
+    IF file_status/=OPEN_OK THEN
+      REPORT "COMMON : File is not opened " SEVERITY FAILURE;
+    ELSE
+      IF ENDFILE(in_file) THEN
+        REPORT "COMMON : end of file " SEVERITY NOTE;
+      ELSE
+        READLINE(in_file, v_line);
+        READ(v_line, read_slv, v_good);         
+        IF v_good = FALSE THEN 
+          REPORT "COMMON : Read from line unsuccessful " SEVERITY FAILURE;
+        END IF;
+      END IF;
+    END IF;
+  END proc_common_readline_file;
+ 
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Reads a string of any length from a file pointer. 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_readline_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                      FILE in_file : TEXT;                  
+                                      res_string   : OUT STRING) IS
+    VARIABLE v_line    : LINE;
+    VARIABLE v_char    : CHARACTER;
+    VARIABLE is_string : BOOLEAN;
+  BEGIN
+    IF file_status/=OPEN_OK THEN
+      REPORT "COMMON : File is not opened " SEVERITY FAILURE;
+    ELSE
+      IF ENDFILE(in_file) THEN
+        REPORT "COMMON : end of file " SEVERITY NOTE;
+      ELSE
+        readline(in_file, v_line);
+        -- clear the contents of the result string
+        FOR I IN res_string'RANGE LOOP
+            res_string(I) := ' ';
+        END LOOP;   
+        -- read all characters of the line, up to the length  
+        -- of the results string
+        FOR I IN res_string'RANGE LOOP
+           read(v_line, v_char, is_string);
+           IF NOT is_string THEN -- found end of line
+              EXIT;
+           END IF;   
+           res_string(I) := v_char;
+        END LOOP; 
+      END IF;
+    END IF;
+  END proc_common_readline_file;
+  
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Closes a file. 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_close_file(file_status  : INOUT FILE_OPEN_STATUS;
+                                   FILE in_file : TEXT) IS
+  BEGIN
+    IF file_status/=OPEN_OK THEN
+      REPORT "COMMON : File was not opened " SEVERITY WARNING;
+    END IF;
+    FILE_CLOSE(in_file);
+    REPORT "COMMON : File closed " SEVERITY NOTE;
+  END proc_common_close_file;     
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Reads the integer data from nof_rows with nof_col values per
+  --            row from a file and returns it row by row in an array of
+  --            integers.
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_read_integer_file(file_name              : IN  STRING;
+                                          nof_header_lines       : NATURAL;
+                                          nof_row                : NATURAL;
+                                          nof_col                : NATURAL;
+                                          SIGNAL return_array    : OUT t_integer_arr) IS
+    VARIABLE v_file_status : FILE_OPEN_STATUS;                                  
+    FILE     v_in_file     : TEXT;  
+    VARIABLE v_input_line  : LINE;   
+    VARIABLE v_string      : STRING(1 TO 80);
+    VARIABLE v_row_arr     : t_integer_arr(0 TO nof_col-1);
+  BEGIN
+    IF file_name/="UNUSED" AND file_name/="unused" THEN
+      -- Open the file for reading
+      proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); 
+      -- Read and skip the header
+      FOR J IN 0 TO nof_header_lines-1  LOOP
+        proc_common_readline_file(v_file_status, v_in_file, v_string); 
+      END LOOP;
+      FOR J IN 0 TO nof_row-1  LOOP
+        proc_common_readline_file(v_file_status, v_in_file, v_row_arr, nof_col);
+        FOR I IN 0 TO nof_col-1 LOOP
+          return_array(J*nof_col + I) <= v_row_arr(I);  -- use loop to be independent of t_integer_arr downto or to range
+        END LOOP;
+        IF ENDFILE(v_in_file) THEN
+          IF J/=nof_row-1 THEN
+            REPORT "COMMON : Unexpected end of file" SEVERITY FAILURE;
+          END IF;
+          EXIT;
+        END IF;
+      END LOOP;
+      -- Close the file 
+      proc_common_close_file(v_file_status, v_in_file);
+    ELSE
+      return_array <= (return_array'RANGE=>0);
+    END IF;
+  END proc_common_read_integer_file;
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Reads the data column from a .mif file and returns it in an 
+  --            array of integers
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_common_read_mif_file(        file_name    : IN  STRING;
+                                       SIGNAL return_array : OUT t_integer_arr) IS
+    VARIABLE v_file_status : FILE_OPEN_STATUS;                                  
+    FILE     v_in_file     : TEXT;  
+    VARIABLE v_input_line  : LINE;   
+    VARIABLE v_string      : STRING(1 TO 80); 
+    VARIABLE v_mem_width   : NATURAL := 0;        
+    VARIABLE v_mem_depth   : NATURAL := 0; 
+    VARIABLE v_up_bound    : NATURAL := 0; 
+    VARIABLE v_low_bound   : NATURAL := 0; 
+    VARIABLE v_end_header  : BOOLEAN := FALSE;
+    VARIABLE v_char        : CHARACTER;
+  BEGIN
+    -- Open the .mif file for reading
+    proc_common_open_file(v_file_status, v_in_file, file_name, READ_MODE); 
+    -- Read the header.
+    WHILE NOT v_end_header LOOP
+      proc_common_readline_file(v_file_status, v_in_file, v_string); 
+      IF(func_find_string_in_string(v_string, "WIDTH=")) THEN                              -- check for "WIDTH=" 
+        v_up_bound  := func_find_char_in_string(v_string, ';');
+        v_low_bound := func_find_char_in_string(v_string, '=');
+        v_mem_width := func_decstring_to_integer(v_string(v_low_bound+1 TO v_up_bound-1)); 
+      ELSIF(func_find_string_in_string(v_string, "DEPTH=")) THEN                           -- check for "DEPTH=" 
+        v_up_bound  := func_find_char_in_string(v_string, ';');
+        v_low_bound := func_find_char_in_string(v_string, '=');                      
+        v_mem_depth := func_decstring_to_integer(v_string(v_low_bound+1 TO v_up_bound-1)); 
+      ELSIF(func_find_string_in_string(v_string, "CONTENT BEGIN")) THEN                  
+        v_end_header := TRUE; 
+      END IF;  
+    END LOOP;
+    -- Read the data           
+    FOR I IN 0 TO v_mem_depth-1  LOOP
+      proc_common_readline_file(v_file_status, v_in_file, v_string);                 -- Read the next line from the file. 
+      v_low_bound     := func_find_char_in_string(v_string, ':');   -- Find the left position of the string that contains the data field
+      v_up_bound      := func_find_char_in_string(v_string, ';');   -- Find the right position of the string that contains the data field           
+      return_array(I) <= func_hexstring_to_integer(v_string(v_low_bound+1 TO v_up_bound-1));
+    END LOOP; 
+    -- Close the file 
+    proc_common_close_file(v_file_status, v_in_file);             
+  END proc_common_read_mif_file;
+
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Complex multiply with conjugate option for input b
+  ------------------------------------------------------------------------------
+  FUNCTION func_complex_multiply(in_ar, in_ai, in_br, in_bi : STD_LOGIC_VECTOR; conjugate_b : BOOLEAN; str : STRING; g_out_dat_w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    -- Function: Signed complex multiply
+    --   p = a * b       when g_conjugate_b = FALSE
+    --     = (ar + j ai) * (br + j bi)
+    --     =  ar*br - ai*bi + j ( ar*bi + ai*br)
+    --
+    --   p = a * conj(b) when g_conjugate_b = TRUE
+    --     = (ar + j ai) * (br - j bi)
+    --     =  ar*br + ai*bi + j (-ar*bi + ai*br)
+    -- From mti_numeric_std.vhd follows:
+    -- . SIGNED * --> output width = 2 * input width
+    -- . SIGNED + --> output width = largest(input width)
+    CONSTANT c_in_w      : NATURAL := in_ar'LENGTH;  -- all input have same width
+    CONSTANT c_res_w     : NATURAL := 2*c_in_w+1;    -- *2 for multiply, +1 for sum of two products
+    VARIABLE v_ar        : SIGNED(c_in_w-1 DOWNTO 0);
+    VARIABLE v_ai        : SIGNED(c_in_w-1 DOWNTO 0);
+    VARIABLE v_br        : SIGNED(c_in_w-1 DOWNTO 0);
+    VARIABLE v_bi        : SIGNED(c_in_w-1 DOWNTO 0);
+    VARIABLE v_result_re : SIGNED(c_res_w-1 DOWNTO 0);
+    VARIABLE v_result_im : SIGNED(c_res_w-1 DOWNTO 0);
+  BEGIN
+    -- Calculate expected result
+    v_ar := RESIZE_NUM(SIGNED(in_ar), c_in_w);
+    v_ai := RESIZE_NUM(SIGNED(in_ai), c_in_w);
+    v_br := RESIZE_NUM(SIGNED(in_br), c_in_w);
+    v_bi := RESIZE_NUM(SIGNED(in_bi), c_in_w);
+    IF conjugate_b=FALSE THEN
+      v_result_re := RESIZE_NUM(v_ar*v_br, c_res_w) - v_ai*v_bi;
+      v_result_im := RESIZE_NUM(v_ar*v_bi, c_res_w) + v_ai*v_br;
+    ELSE
+      v_result_re := RESIZE_NUM(v_ar*v_br, c_res_w) + v_ai*v_bi;
+      v_result_im := RESIZE_NUM(v_ai*v_br, c_res_w) - v_ar*v_bi;
+    END IF;
+    -- Note that for the product needs as many bits as the sum of the input widths. However the
+    -- sign bit is then only needed for the case that both inputs have the largest negative
+    -- values, only then the MSBits will be "01". For all other inputs the MSbits will always
+    -- be "00" for positive numbers or "11" for negative numbers. MSbits "10" can not occur.
+    -- For largest negative inputs the complex multiply result becomes:
+    --
+    --   3b inputs                --> 6b products     --> c_res_w = 7b
+    --     -4 *   -4 +   -4 *   -4 =     +16 +     +16 =      +64       -- most negative valued inputs
+    --   b100 * b100 + b100 * b100 = b010000 + b010000 = b0100000
+    --
+    --   --> if g_out_dat_w = 6b then
+    --       a) IEEE unsigned resizing skips   the MSbits so b0100000 = +64 becomes b_100000 = -64
+    --       b) IEEE signed resizing preserves the MSbit  so b0100000 = +64 becomes b0_00000 = 0
+    --       c) detect MSbits = "01" to clip max positive to get                    _b011111 = +63
+    -- Option a) seems to map best on the FPGA hardware multiplier IP.
+    IF str="RE" THEN
+      RETURN STD_LOGIC_VECTOR(RESIZE_NUM(v_result_re, g_out_dat_w));  -- conform option a)
+    ELSE
+      RETURN STD_LOGIC_VECTOR(RESIZE_NUM(v_result_im, g_out_dat_w));  -- conform option a)
+    END IF;
+  END;  
+  
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Converts the decimal value represented in a string to an integer value. 
+  ------------------------------------------------------------------------------
+  FUNCTION func_decstring_to_integer(in_string: STRING) RETURN INTEGER IS
+    CONSTANT c_nof_digits : NATURAL := in_string'LENGTH;   -- Define the length of the string
+    VARIABLE v_char       : CHARACTER;
+    VARIABLE v_weight     : INTEGER := 1; 
+    VARIABLE v_return_int : INTEGER := 0;
+  BEGIN
+    -- Walk through the string character by character. 
+    FOR I IN c_nof_digits-1 DOWNTO 0 LOOP         
+      v_char := in_string(I+in_string'LOW);
+      CASE v_char IS
+         WHEN '0' => v_return_int := v_return_int + 0*v_weight;
+         WHEN '1' => v_return_int := v_return_int + 1*v_weight;
+         WHEN '2' => v_return_int := v_return_int + 2*v_weight;
+         WHEN '3' => v_return_int := v_return_int + 3*v_weight;
+         WHEN '4' => v_return_int := v_return_int + 4*v_weight;
+         WHEN '5' => v_return_int := v_return_int + 5*v_weight;
+         WHEN '6' => v_return_int := v_return_int + 6*v_weight;
+         WHEN '7' => v_return_int := v_return_int + 7*v_weight;
+         WHEN '8' => v_return_int := v_return_int + 8*v_weight;
+         WHEN '9' => v_return_int := v_return_int + 9*v_weight;
+         WHEN OTHERS => NULL;
+      END CASE; 
+      IF (v_char /= ' ') THEN      -- Only increment the weight when the character is NOT a spacebar. 
+        v_weight := v_weight*10;   -- Addapt the weight for the next decimal digit.
+      END IF;
+    END LOOP;
+    RETURN(v_return_int);
+  END FUNCTION func_decstring_to_integer;  
+
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Converts the hexadecimal value represented in a string to an integer value. 
+  ------------------------------------------------------------------------------
+  FUNCTION func_hexstring_to_integer(in_string: STRING) RETURN INTEGER IS
+    CONSTANT c_nof_digits : NATURAL := in_string'LENGTH;  -- Define the length of the string
+    VARIABLE v_char       : CHARACTER;
+    VARIABLE v_weight     : INTEGER := 1; 
+    VARIABLE v_return_int : INTEGER := 0;
+  BEGIN     
+    -- Walk through the string character by character. 
+    FOR I IN c_nof_digits-1 DOWNTO 0 LOOP
+      v_char := in_string(I+in_string'LOW);
+      CASE v_char IS
+         WHEN '0' => v_return_int := v_return_int + 0*v_weight;
+         WHEN '1' => v_return_int := v_return_int + 1*v_weight;
+         WHEN '2' => v_return_int := v_return_int + 2*v_weight;
+         WHEN '3' => v_return_int := v_return_int + 3*v_weight;
+         WHEN '4' => v_return_int := v_return_int + 4*v_weight;
+         WHEN '5' => v_return_int := v_return_int + 5*v_weight;
+         WHEN '6' => v_return_int := v_return_int + 6*v_weight;
+         WHEN '7' => v_return_int := v_return_int + 7*v_weight;
+         WHEN '8' => v_return_int := v_return_int + 8*v_weight;
+         WHEN '9' => v_return_int := v_return_int + 9*v_weight;
+         WHEN 'A' | 'a' => v_return_int := v_return_int + 10*v_weight;
+         WHEN 'B' | 'b' => v_return_int := v_return_int + 11*v_weight;
+         WHEN 'C' | 'c' => v_return_int := v_return_int + 12*v_weight;
+         WHEN 'D' | 'd' => v_return_int := v_return_int + 13*v_weight;
+         WHEN 'E' | 'e' => v_return_int := v_return_int + 14*v_weight;
+         WHEN 'F' | 'f' => v_return_int := v_return_int + 15*v_weight;
+         WHEN OTHERS => NULL;
+      END CASE; 
+      IF (v_char /= ' ') THEN     -- Only increment the weight when the character is NOT a spacebar. 
+        v_weight := v_weight*16;  -- Addapt the weight for the next hexadecimal digit.                   
+      END IF; 
+    END LOOP;
+    RETURN(v_return_int);
+  END FUNCTION func_hexstring_to_integer;  
+
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Finds the first instance of a given character in a string 
+  --           and returns its position. 
+  ------------------------------------------------------------------------------
+  FUNCTION func_find_char_in_string(in_string: STRING; find_char: CHARACTER) RETURN INTEGER IS
+    VARIABLE v_char_position : INTEGER := 0;
+  BEGIN
+    FOR I IN 1 TO in_string'LENGTH LOOP
+      IF(in_string(I) = find_char) THEN
+        v_char_position := I;
+      END IF;
+    END LOOP;  
+    RETURN(v_char_position); 
+  END FUNCTION func_find_char_in_string;
+  
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Checks if a string(find_string) is part of a larger string(in_string).
+  --           The result is returned as a BOOLEAN. 
+  ------------------------------------------------------------------------------
+  FUNCTION func_find_string_in_string(in_string: STRING; find_string: STRING) RETURN BOOLEAN IS
+    CONSTANT c_in_length     : NATURAL := in_string'LENGTH;   -- Define the length of the string to search in
+    CONSTANT c_find_length   : NATURAL := find_string'LENGTH; -- Define the length of the string to be find
+    VARIABLE v_found_it      : BOOLEAN := FALSE;
+  BEGIN
+    FOR I IN 1 TO c_in_length-c_find_length LOOP
+      IF(in_string(I TO (I+c_find_length-1)) = find_string) THEN
+        v_found_it := TRUE;
+      END IF;
+    END LOOP;  
+    RETURN(v_found_it); 
+  END FUNCTION func_find_string_in_string;
+
+END tb_common_pkg;
+
diff --git a/cores/base/dp/dp_components/dp_hold_ctrl.vhd b/cores/base/dp/dp_components/dp_hold_ctrl.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..fa36f9310c02a57584afb31b854c896430b33a9e
--- /dev/null
+++ b/cores/base/dp/dp_components/dp_hold_ctrl.vhd
@@ -0,0 +1,70 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_components_lib;
+USE IEEE.std_logic_1164.all;
+
+-- Purpose:
+--   Hold hld_ctrl active until next ready high when in_ctrl is active while
+--   ready went low
+-- Description:
+--   When ready goes low there may still arrive one new valid data. The control
+--   information for this data can then be held with this component. When ready
+--   goes high again the held data can then be output and the hld_ctrl is 
+--   released. After that the subsequent data output can come directly from the
+--   up stream source, until ready goes low again.
+-- Remarks:
+-- . Ready latency RL = 1
+-- . The in_ctrl is typically in_valid, in_sop or in_eop
+-- . Typically used together with dp_hold_data
+
+ENTITY dp_hold_ctrl IS
+  PORT (
+    rst      : IN  STD_LOGIC;
+    clk      : IN  STD_LOGIC;
+    ready    : IN  STD_LOGIC;
+    in_ctrl  : IN  STD_LOGIC;
+    hld_ctrl : OUT STD_LOGIC
+  );
+END dp_hold_ctrl;
+
+
+ARCHITECTURE rtl OF dp_hold_ctrl IS
+  
+  SIGNAL hi_ctrl : STD_LOGIC;
+  SIGNAL lo_ctrl : STD_LOGIC;
+
+BEGIN
+
+  hi_ctrl <=     in_ctrl AND NOT ready;  -- capture
+  lo_ctrl <= NOT in_ctrl AND     ready;  -- release
+  
+  u_hld_ctrl : ENTITY common_components_lib.common_switch
+  PORT MAP (
+    rst         => rst,
+    clk         => clk,
+    switch_high => hi_ctrl,
+    switch_low  => lo_ctrl,
+    out_level   => hld_ctrl
+  );
+  
+END rtl;
diff --git a/cores/base/dp/dp_components/dp_hold_input.vhd b/cores/base/dp/dp_components/dp_hold_input.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..81ab370cfc135e4089c9fe9f7c74759d13285801
--- /dev/null
+++ b/cores/base/dp/dp_components/dp_hold_input.vhd
@@ -0,0 +1,157 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, dp_pkg_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Purpose:
+--   Hold the sink input
+-- Description:
+--   This dp_hold_input provides the necessary input logic to hold the input
+--   data and control to easily register the source output. Compared to
+--   dp_pipeling the dp_hold_input is the same except for the output register
+--   stage. In this way dp_hold_input can be used in a more complicated stream
+--   component where the output is not always the same as the input.
+--   The snk_in.valid and hold_in.valid are never high at the same time.
+--   If src_in.ready goes low while snk_in.valid is high then this snk_in.valid
+--   is held in hold_in.valid and the corresponding snk_in.data will get held
+--   in the external src_out_reg.data. When src_in.ready goes high again then
+--   the held data becomes valid via src_out_reg.valid and hold_in.valid goes
+--   low. Due to the RL=1 the next cycle the snk_in.valid from the sink may go
+--   high. The next_src_out control signals are equal to pend_src_out AND
+--   src_in.ready, so they can directly be assigned to src_out_reg.data if the
+--   snk_in.data needs to be passed on.
+--   The internal pend_src_out control signals are available outside, in
+--   addition to the next_src_out control signals, to support external control
+--   independent of src_in.ready. Use pend_scr_out instead of next_src_out
+--   to avoid combinatorial loop when src_in.ready depends on next_src_out.
+--   The pend_src_out signals are used to implement show ahead behaviour like
+--   with RL=0, but for RL=1. The input can then be stopped based on the snk_in
+--   data and later on continued again without losing this snk_in data, because
+--   it was held as described above.
+-- Remarks:
+-- . Ready latency = 1
+-- . Without flow control so when src_in.ready = '1' fixed, then dp_hold_input
+--   becomes void because the dp_hold_ctrl output then remains '0'.
+
+ENTITY dp_hold_input IS
+  PORT (
+    rst              : IN  STD_LOGIC;
+    clk              : IN  STD_LOGIC;
+    -- ST sink
+    snk_out          : OUT t_dp_siso;
+    snk_in           : IN  t_dp_sosi;
+    -- ST source
+    src_in           : IN  t_dp_siso;
+    next_src_out     : OUT t_dp_sosi;
+    pend_src_out     : OUT t_dp_sosi;  -- the SOSI data fields are the same as for next_src_out
+    src_out_reg      : IN  t_dp_sosi   -- uses only the SOSI data fields
+  );
+END dp_hold_input;
+
+
+ARCHITECTURE rtl OF dp_hold_input IS
+  
+  SIGNAL i_pend_src_out : t_dp_sosi;
+  SIGNAL hold_in        : t_dp_sosi;  -- uses only the SOSI ctrl fields
+  
+BEGIN
+
+  pend_src_out <= i_pend_src_out;
+
+  -- SISO:
+  snk_out <= src_in;  --  No change in ready latency, pass on xon frame level flow control
+  
+  -- SOSI:
+  -- Take care of active snk_in.valid, snk_in.sync, snk_in.sop and snk_in.eop
+  -- when src_in.ready went low. If hold_in.valid would not be used for
+  -- pend_src_out.valid and next_src_out.valid, then the pipeline would still
+  -- work, but the valid snk_in.data that came when src_in.ready went low,
+  -- will then only get pushed out on the next valid snk_in.valid. Whereas
+  -- hold_in.valid ensures that it will get pushed out as soon as src_in.ready
+  -- goes high again. This is typically necessary in case of packetized data
+  -- where the eop of one packet should not have to wait for the valid (sop)
+  -- of a next packet to get pushed out.
+  
+  u_hold_val : ENTITY work.dp_hold_ctrl
+  PORT MAP (
+    rst      => rst,
+    clk      => clk,
+    ready    => src_in.ready,
+    in_ctrl  => snk_in.valid,
+    hld_ctrl => hold_in.valid
+  );
+  
+  u_hold_sync : ENTITY work.dp_hold_ctrl
+  PORT MAP (
+    rst      => rst,
+    clk      => clk,
+    ready    => src_in.ready,
+    in_ctrl  => snk_in.sync,
+    hld_ctrl => hold_in.sync
+  );
+  
+  u_hold_sop : ENTITY work.dp_hold_ctrl
+  PORT MAP (
+    rst      => rst,
+    clk      => clk,
+    ready    => src_in.ready,
+    in_ctrl  => snk_in.sop,
+    hld_ctrl => hold_in.sop
+  );
+  
+  u_hold_eop : ENTITY work.dp_hold_ctrl
+  PORT MAP (
+    rst      => rst,
+    clk      => clk,
+    ready    => src_in.ready,
+    in_ctrl  => snk_in.eop,
+    hld_ctrl => hold_in.eop
+  );
+  
+  p_pend_src_out : PROCESS(snk_in, src_out_reg, hold_in)
+  BEGIN
+    -- Pend data
+    IF snk_in.valid='1' THEN
+      i_pend_src_out <= snk_in;       -- Input data
+    ELSE
+      i_pend_src_out <= src_out_reg;  -- Hold data
+    END IF;
+    i_pend_src_out.valid <= snk_in.valid OR hold_in.valid;
+    i_pend_src_out.sync  <= snk_in.sync  OR hold_in.sync;
+    i_pend_src_out.sop   <= snk_in.sop   OR hold_in.sop;
+    i_pend_src_out.eop   <= snk_in.eop   OR hold_in.eop;
+  END PROCESS;
+  
+  p_next_src_out : PROCESS(i_pend_src_out, src_in)
+  BEGIN
+    -- Next data
+    next_src_out       <= i_pend_src_out;
+    -- Next control
+    next_src_out.valid <= i_pend_src_out.valid AND src_in.ready;
+    next_src_out.sync  <= i_pend_src_out.sync  AND src_in.ready;
+    next_src_out.sop   <= i_pend_src_out.sop   AND src_in.ready;
+    next_src_out.eop   <= i_pend_src_out.eop   AND src_in.ready;
+  END PROCESS;
+    
+END rtl;
diff --git a/cores/base/dp/dp_components/dp_latency_adapter.vhd b/cores/base/dp/dp_components/dp_latency_adapter.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..9fcca836dd9b256c160e26b5535a0e61b3a6b419
--- /dev/null
+++ b/cores/base/dp/dp_components/dp_latency_adapter.vhd
@@ -0,0 +1,260 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Purpose:
+--   Adapt the g_in_latency input ready to the g_out_latency output latency.
+--   A typical application is to use this latency adapter to provide a read
+--   ahead interface to a default FIFO with e.g. read latency 1 or 2.
+-- Description:
+--   If g_in_latency > g_out_latency then the input latency is first adapted
+--   to zero latency by means of a latency FIFO. After that a delay line for
+--   src_in.ready yields the g_out_latency output latency.
+--   If g_in_latency < g_out_latency, then a delay line for src_in.ready yields
+--   the g_out_latency output latency.
+--   The sync input is also passed on, only if it occurs during valid. The
+--   constant c_pass_sync_during_not_valid is defined to preserve the
+--   corresponding section of code for passing the sync also during not valid.
+-- Remark:
+-- . The snk_out.ready is derived combinatorially from the src_in.ready. If for
+--   timing performance it is needed to register snk_out.ready, then this can
+--   be done by first increasing the ready latency using this adapter with
+--   g_in_latency = g_out_latency + 1, followed by a second adapter to reach
+--   the required output ready latency latency.
+
+ENTITY dp_latency_adapter IS
+  GENERIC (
+    g_in_latency   : NATURAL := 3;
+    g_out_latency  : NATURAL := 1
+  );
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- Monitor internal FIFO filling
+    fifo_usedw   : OUT STD_LOGIC_VECTOR(ceil_log2(2+g_in_latency)-1 DOWNTO 0);  -- see description of c_fifo_size, c_usedw_w for explanation of why +2
+    fifo_ful     : OUT STD_LOGIC;
+    fifo_emp     : OUT STD_LOGIC;
+    -- ST sink
+    snk_out      : OUT t_dp_siso;
+    snk_in       : IN  t_dp_sosi;
+    -- ST source
+    src_in       : IN  t_dp_siso;
+    src_out      : OUT t_dp_sosi
+  );
+END dp_latency_adapter;
+
+
+ARCHITECTURE rtl OF dp_latency_adapter IS
+
+  -- The difference between the input ready latency and the output ready latency
+  CONSTANT c_diff_latency               : INTEGER := g_out_latency - g_in_latency;
+  
+  -- Define constant to preserve the corresponding section of code, but default keep it at FALSE
+  CONSTANT c_pass_sync_during_not_valid : BOOLEAN := FALSE;
+  
+  -- Use g_in_latency+1 words for the FIFO data array, to go to zero latency
+  CONSTANT c_high           : NATURAL := g_in_latency;
+  CONSTANT c_fifo_size      : NATURAL := g_in_latency+1;            -- +1 because RL=0 also requires a word
+  CONSTANT c_usedw_w        : NATURAL := ceil_log2(c_fifo_size+1);  -- +1 because to store value 2**n requires n+1 bits
+
+  SIGNAL fifo_reg           : t_dp_sosi_arr(c_high DOWNTO 0);
+  SIGNAL nxt_fifo_reg       : t_dp_sosi_arr(c_high DOWNTO 0);
+  SIGNAL fifo_reg_valid     : STD_LOGIC_VECTOR(c_high DOWNTO 0);    -- debug signal for Wave window
+  
+  SIGNAL nxt_fifo_usedw     : STD_LOGIC_VECTOR(c_usedw_w-1 DOWNTO 0);
+  SIGNAL nxt_fifo_ful       : STD_LOGIC;
+  SIGNAL nxt_fifo_emp       : STD_LOGIC;
+
+  SIGNAL ff_siso            : t_dp_siso;  -- SISO ready
+  SIGNAL ff_sosi            : t_dp_sosi;  -- SOSI
+  
+  SIGNAL i_snk_out          : t_dp_siso := c_dp_siso_rdy;
+  
+BEGIN
+
+  -- Use i_snk_out with defaults to force unused snk_out bits and fields to '0'
+  snk_out <= i_snk_out;
+  
+  gen_wires : IF c_diff_latency = 0 GENERATE  -- g_out_latency = g_in_latency
+    i_snk_out <= src_in;  -- SISO
+    src_out   <= snk_in;  -- SOSI
+  END GENERATE gen_wires;
+
+
+  no_fifo : IF c_diff_latency > 0 GENERATE  -- g_out_latency > g_in_latency
+    -- Go from g_in_latency to required larger g_out_latency
+    u_latency : ENTITY work.dp_latency_increase
+    GENERIC MAP (
+      g_in_latency   => g_in_latency,
+      g_incr_latency => c_diff_latency
+    )
+    PORT MAP (
+      rst       => rst,
+      clk       => clk,
+      -- ST sink
+      snk_out   => i_snk_out,
+      snk_in    => snk_in,
+      -- ST source
+      src_in    => src_in,
+      src_out   => src_out
+    );
+  END GENERATE no_fifo;
+  
+  
+  gen_fifo : IF c_diff_latency < 0 GENERATE  -- g_out_latency < g_in_latency
+    -- Register [0] contains the FIFO output with zero ready latency
+    ff_sosi <= fifo_reg(0);
+  
+    p_clk_fifo : PROCESS(rst, clk)
+    BEGIN
+      IF rst='1' THEN
+        fifo_reg   <= (OTHERS=>c_dp_sosi_rst);
+        fifo_usedw <= (OTHERS=>'0');
+        fifo_ful   <= '0';
+        fifo_emp   <= '1';
+      ELSIF rising_edge(clk) THEN
+        fifo_reg   <= nxt_fifo_reg;
+        fifo_usedw <= nxt_fifo_usedw;
+        fifo_ful   <= nxt_fifo_ful;
+        fifo_emp   <= nxt_fifo_emp;
+      END IF;
+    END PROCESS;
+    
+    -- Pass on frame level flow control
+    i_snk_out.xon <= src_in.xon;
+    
+    p_snk_out_ready : PROCESS(fifo_reg, ff_siso, snk_in)
+    BEGIN
+      i_snk_out.ready <= '0';
+      IF ff_siso.ready='1' THEN
+        -- Default snk_out ready when the source is ready.
+        i_snk_out.ready <= '1';
+      ELSE
+        -- Extra snk_out ready to look ahead for src_in RL = 0.
+        -- The fifo_reg[h:0] size is g_in_latency+1 number of SOSI values.
+        -- . The fifo_reg[h:1] provide free space for h=g_in_latency nof data
+        --   when snk_out.ready is pulled low, because then there can still
+        --   arrive g_in_latency nof new data with snk_in.valid asserted.
+        -- . The [0] is the registered output SOSI value with RL=0. Therefore
+        --   fifo_reg[0] can still accept a new input when ff_siso.ready is
+        --   low. If this assignment is omitted then the functionallity is
+        --   still OK, but the throughtput sligthly reduces.
+        IF fifo_reg(0).valid='0' THEN
+          i_snk_out.ready <= '1';
+        ELSIF fifo_reg(1).valid='0' THEN
+          i_snk_out.ready <= NOT(snk_in.valid);
+        END IF;
+      END IF;
+    END PROCESS;
+  
+    p_fifo_reg : PROCESS(fifo_reg, ff_siso, snk_in)
+    BEGIN
+      -- Keep or shift the fifo_reg dependent on ff_siso.ready, no need to explicitly check fifo_reg().valid
+      nxt_fifo_reg <= fifo_reg;
+      IF ff_siso.ready='1' THEN
+        nxt_fifo_reg(c_high-1 DOWNTO 0) <= fifo_reg(c_high DOWNTO 1);
+        nxt_fifo_reg(c_high).valid <= '0';
+        nxt_fifo_reg(c_high).sync  <= '0';
+        nxt_fifo_reg(c_high).sop   <= '0';
+        nxt_fifo_reg(c_high).eop   <= '0';
+        -- Forcing the nxt_fifo_reg[h] control fields to '0' is robust, but not
+        -- strictly necessary, because the control fields in fifo_reg[h] will
+        -- have been set to '0' already earlier due to the snk_in when
+        -- ff_siso.ready was '0'.
+      END IF;
+  
+      -- Put input data at the first available location dependent on ff_siso.ready, no need to explicitly check snk_in.valid
+      IF fifo_reg(0).valid='0' THEN
+        nxt_fifo_reg(0) <= snk_in;               -- fifo_reg is empty
+      ELSE
+        -- The fifo_reg is not empty, so filled to some extend
+        FOR I IN 1 TO c_high LOOP
+          IF fifo_reg(I).valid='0' THEN
+            IF ff_siso.ready='0' THEN
+              nxt_fifo_reg(I)   <= snk_in;
+            ELSE
+              nxt_fifo_reg(I-1) <= snk_in;
+            END IF;
+            EXIT;
+          END IF;
+        END LOOP;
+        
+        -- Default the input sync during input data valid is only passed on with the valid input data.
+        -- When c_pass_sync_during_not_valid is enabled then the input sync during input data not valid is passed on via the head fifo_reg(0) if the fifo_reg is empty.
+        IF c_pass_sync_during_not_valid=TRUE AND snk_in.sync='1' AND snk_in.valid='0' THEN
+          -- Otherwise for input sync during input data not valid we need to insert the input sync at the last location with valid data independent of ff_siso.ready, to avoid that it gets lost.
+          -- For streams that do not use the sync this logic will be void and optimize away by synthesis, because then snk_in.sync = '0' fixed.
+          IF fifo_reg(c_high).valid='1' THEN     -- fifo_reg is full
+            nxt_fifo_reg(c_high).sync <= '1';    -- insert input sync
+          ELSE
+            FOR I IN c_high-1 DOWNTO 0 LOOP      -- fifo_reg is filled to some extend, so not full and not empty
+              IF fifo_reg(I).valid='1' THEN
+                nxt_fifo_reg(I+1).sync <= '0';   -- overrule default sync assignment
+                nxt_fifo_reg(I).sync   <= '1';   -- insert input sync
+                EXIT;
+              END IF;
+            END LOOP;
+          END IF;
+        END IF;
+      END IF;
+    END PROCESS;
+    
+    p_fifo_usedw : PROCESS(nxt_fifo_reg)
+    BEGIN
+      nxt_fifo_usedw <= (OTHERS=>'0');
+      FOR I IN c_high DOWNTO 0 LOOP
+        IF nxt_fifo_reg(I).valid='1' THEN
+          nxt_fifo_usedw <= TO_UVEC(I+1, c_usedw_w);
+          EXIT;
+        END IF;
+      END LOOP;
+    END PROCESS;
+    
+    fifo_reg_valid <= func_dp_stream_arr_get(fifo_reg, "VALID");
+    
+    nxt_fifo_ful <= '1' WHEN TO_UINT(nxt_fifo_usedw)>=c_high+1 ELSE '0';  -- using >= or = is equivalent here
+    nxt_fifo_emp <= '1' WHEN TO_UINT(nxt_fifo_usedw) =0        ELSE '0';
+    
+    -- Go from 0 FIFO latency to required g_out_latency (only wires when g_out_latency=0)
+    u_latency : ENTITY work.dp_latency_increase
+    GENERIC MAP (
+      g_in_latency   => 0,
+      g_incr_latency => g_out_latency
+    )
+    PORT MAP (
+      rst       => rst,
+      clk       => clk,
+      -- ST sink
+      snk_out   => ff_siso,
+      snk_in    => ff_sosi,
+      -- ST source
+      src_in    => src_in,
+      src_out   => src_out
+    );
+  END GENERATE gen_fifo;
+
+END rtl;
diff --git a/cores/base/dp/dp_components/dp_latency_increase.vhd b/cores/base/dp/dp_components/dp_latency_increase.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..2ddc1cfe38489449f18a9e1a4a60c0b674bd9ce6
--- /dev/null
+++ b/cores/base/dp/dp_components/dp_latency_increase.vhd
@@ -0,0 +1,117 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Purpose:
+--   Typically used in dp_latency_adapter.
+-- Description:
+--   Increase the output ready latency by g_incr_latency compared to the input
+--   ready latency g_in_latency. Hence the output latency becomes g_in_latency
+--   + g_incr_latency.
+-- Remark:
+-- . The SOSI data stream signals (i.e. data, empty, channel, err) are passed
+--   on as wires.
+-- . The out_sync, out_val, out_sop and out_eop are internally AND with the
+--   delayed src_in.ready, this is only truely necessary if the input ready
+--   latency is 0, but it does not harm to do it also when the input ready
+--   latency > 0. However to easy achieving P&R timing it is better to not have
+--   unnessary logic in the combinatorial path of out_sync, out_val, out_sop
+--   and out_eop, therefore the AND with reg_val is only generated when
+--   g_in_latency=0.
+
+ENTITY dp_latency_increase IS
+  GENERIC (
+    g_in_latency   : NATURAL := 0;  -- >= 0
+    g_incr_latency : NATURAL := 2   -- >= 0
+  );
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- ST sink
+    snk_out      : OUT t_dp_siso;
+    snk_in       : IN  t_dp_sosi;
+    -- ST source
+    src_in       : IN  t_dp_siso;
+    src_out      : OUT t_dp_sosi
+  );
+END dp_latency_increase;
+
+
+ARCHITECTURE rtl OF dp_latency_increase IS
+
+  CONSTANT c_out_latency : NATURAL := g_in_latency + g_incr_latency;
+  
+  SIGNAL reg_ready : STD_LOGIC_VECTOR(c_out_latency DOWNTO 0);
+  SIGNAL reg_val   : STD_LOGIC;
+  
+  SIGNAL i_snk_out : t_dp_siso := c_dp_siso_rdy;
+  
+BEGIN
+
+  -- Use i_snk_out with defaults to force unused snk_out bits and fields to '0'
+  snk_out <= i_snk_out;
+
+  -- Support wires only for g_incr_latency=0
+  no_latency : IF g_incr_latency=0 GENERATE
+    i_snk_out <= src_in;  -- SISO
+    src_out   <= snk_in;  -- SOSI
+  END GENERATE no_latency;
+  
+  gen_latency : IF g_incr_latency>0 GENERATE
+    -- SISO
+    reg_ready(0) <= src_in.ready;  -- use reg_ready(0) to combinatorially store src_in.ready
+    p_clk : PROCESS(rst, clk)
+    BEGIN
+      IF rst='1' THEN
+        reg_ready(c_out_latency DOWNTO 1) <= (OTHERS=>'0');
+      ELSIF rising_edge(clk) THEN
+        reg_ready(c_out_latency DOWNTO 1) <= reg_ready(c_out_latency-1 DOWNTO 0);
+      END IF;
+    END PROCESS;
+    
+    i_snk_out.xon   <= src_in.xon;                 -- Pass on frame level flow control
+    i_snk_out.ready <= reg_ready(g_incr_latency);  -- Adjust ready latency
+    
+    -- SOSI
+    gen_out : IF g_in_latency/=0 GENERATE
+      src_out <= snk_in;
+    END GENERATE;
+    gen_zero_out : IF g_in_latency=0 GENERATE
+      reg_val <= reg_ready(c_out_latency);
+    
+      p_src_out : PROCESS(snk_in, reg_val)
+      BEGIN
+        src_out       <= snk_in;
+        src_out.sync  <= snk_in.sync  AND reg_val;
+        src_out.valid <= snk_in.valid AND reg_val;
+        src_out.sop   <= snk_in.sop   AND reg_val;
+        src_out.eop   <= snk_in.eop   AND reg_val;
+      END PROCESS;
+    END GENERATE;
+  END GENERATE gen_latency;
+  
+END rtl;
diff --git a/cores/base/dp/dp_components/hdllib.cfg b/cores/base/dp/dp_components/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..28b973ab8d93d763520924ea3e1a4c7c0394dbc8
--- /dev/null
+++ b/cores/base/dp/dp_components/hdllib.cfg
@@ -0,0 +1,22 @@
+hdl_lib_name = dp_components
+hdl_library_clause_name = dp_components_lib
+hdl_lib_uses_synth = common_pkg common_components dp_pkg
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    dp_latency_increase.vhd
+    dp_latency_adapter.vhd
+    dp_hold_ctrl.vhd
+    dp_hold_input.vhd
+   
+test_bench_files = 
+    tb_dp_latency_adapter.vhd
+
+regression_test_vhdl = 
+    tb_dp_latency_adapter.vhd
+    
+[modelsim_project_file]
+
+
+[quartus_project_file]
diff --git a/cores/base/dp/dp_components/tb_dp_latency_adapter.vhd b/cores/base/dp/dp_components/tb_dp_latency_adapter.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..b4b1633b68030f936d48417f5225bee3bb166d72
--- /dev/null
+++ b/cores/base/dp/dp_components/tb_dp_latency_adapter.vhd
@@ -0,0 +1,254 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_latency_adapter IS
+END tb_dp_latency_adapter;
+
+
+ARCHITECTURE tb OF tb_dp_latency_adapter IS
+
+  -- See tb_dp_pkg.vhd for explanation and run time
+  
+  SUBTYPE t_dut_range  IS INTEGER RANGE -1 to INTEGER'HIGH; 
+
+  TYPE t_dut_natural_arr  IS ARRAY (t_dut_range RANGE <>) OF NATURAL;
+  TYPE t_dut_data_arr     IS ARRAY (t_dut_range RANGE <>) OF STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  TYPE t_dut_logic_arr    IS ARRAY (t_dut_range RANGE <>) OF STD_LOGIC;  -- can not use STD_LOGIC_VECTOR because of integer range 
+  
+  -- TX ready latency to DUT chain
+  CONSTANT c_tx_latency     : NATURAL := 3;
+  CONSTANT c_tx_void        : NATURAL := sel_a_b(c_tx_latency, 1, 0);  -- used to avoid empty range VHDL warnings when c_tx_latency=0
+  
+  CONSTANT c_tx_offset_sop  : NATURAL := 3;
+  CONSTANT c_tx_period_sop  : NATURAL := 7;              -- sop in data valid cycle 3,  10,  17, ...
+  CONSTANT c_tx_offset_eop  : NATURAL := 5;              -- eop in data valid cycle   5,  12,  19, ...
+  CONSTANT c_tx_period_eop  : NATURAL := c_tx_period_sop;
+  CONSTANT c_tx_offset_sync : NATURAL := 3;                  -- sync in data valid cycle 3, 20, 37, ...
+  CONSTANT c_tx_period_sync : NATURAL := 17;
+  
+  -- The TB supports using 1 or more dp_latency_adapter Devices Under Test in a chain. DUT 0 is the first DUT and it
+  -- gets the tx_data from this test bench, which has index -1. Each next DUT gets its input from the previous DUT,
+  -- hence the ready latency between DUTs should be the same.
+  -- The output latency of the previous must equal the input latency of the next DUT, hence it is sufficient to define
+  -- only the DUT output latencies.
+  --CONSTANT c_dut_latency    : t_dut_natural_arr := (c_tx_latency, 3);  -- verify single dp_latency_adapter with only wires
+  --CONSTANT c_dut_latency    : t_dut_natural_arr := (c_tx_latency, 4);  -- verify single dp_latency_adapter with latency increase
+  --CONSTANT c_dut_latency    : t_dut_natural_arr := (c_tx_latency, 1);  -- verify single dp_latency_adapter with latency decrease
+  CONSTANT c_dut_latency    : t_dut_natural_arr := (c_tx_latency, 1, 2, 0, 5, 5, 2, 1, 0, 7);
+  
+  -- The nof dut latencies in the c_dut_latency array automatically also defines the nof DUTs c_nof_dut.
+  CONSTANT c_nof_dut        : NATURAL := c_dut_latency'HIGH+1;
+  
+  -- RX ready latency from DUT chain
+  CONSTANT c_rx_latency     : NATURAL := c_dut_latency(c_nof_dut-1);
+  
+  CONSTANT c_verify_en_wait : NATURAL := 10+c_nof_dut*2;  -- wait some cycles before asserting verify enable
+  
+  CONSTANT c_empty_offset   : NATURAL := 1;
+  CONSTANT c_channel_offset : NATURAL := 2;
+  
+  CONSTANT c_random_w       : NATURAL := 19;
+  
+  SIGNAL tb_end         : STD_LOGIC := '0';
+  SIGNAL clk            : STD_LOGIC := '0';
+  SIGNAL rst            : STD_LOGIC;
+  SIGNAL sync           : STD_LOGIC;
+  SIGNAL lfsr1          : STD_LOGIC_VECTOR(c_random_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL lfsr2          : STD_LOGIC_VECTOR(c_random_w   DOWNTO 0) := (OTHERS=>'0');
+  
+  SIGNAL cnt_dat        : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL cnt_val        : STD_LOGIC;
+  SIGNAL cnt_en         : STD_LOGIC;
+  
+  SIGNAL tx_data        : t_dp_data_arr(0 TO c_tx_latency + c_tx_void);
+  SIGNAL tx_val         : STD_LOGIC_VECTOR(0 TO c_tx_latency + c_tx_void);
+  
+  SIGNAL in_ready       : STD_LOGIC;
+  SIGNAL in_data        : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL in_sync        : STD_LOGIC;
+  SIGNAL in_val         : STD_LOGIC;
+  SIGNAL in_sop         : STD_LOGIC;
+  SIGNAL in_eop         : STD_LOGIC;
+  
+  -- DUT index -1 = in_data
+  SIGNAL dut_ready      : t_dut_logic_arr(-1 TO c_nof_dut-1);  -- SISO
+  SIGNAL dut_data       : t_dut_data_arr(-1 TO c_nof_dut-1);   -- SOSI
+  SIGNAL dut_empty      : t_dut_data_arr(-1 TO c_nof_dut-1) := (OTHERS=>(OTHERS=>'0'));
+  SIGNAL dut_channel    : t_dut_data_arr(-1 TO c_nof_dut-1) := (OTHERS=>(OTHERS=>'0'));
+  SIGNAL dut_sync       : t_dut_logic_arr(-1 TO c_nof_dut-1);
+  SIGNAL dut_val        : t_dut_logic_arr(-1 TO c_nof_dut-1);
+  SIGNAL dut_sop        : t_dut_logic_arr(-1 TO c_nof_dut-1);
+  SIGNAL dut_eop        : t_dut_logic_arr(-1 TO c_nof_dut-1);
+  -- DUT index c_nof_dut-1 = out_data
+  SIGNAL dut_siso       : t_dp_siso_arr(-1 TO c_nof_dut-1);
+  SIGNAL dut_sosi       : t_dp_sosi_arr(-1 TO c_nof_dut-1) := (OTHERS=>c_dp_sosi_rst);
+  
+  SIGNAL out_ready      : STD_LOGIC;
+  SIGNAL prev_out_ready : STD_LOGIC_VECTOR(0 TO c_rx_latency);
+  SIGNAL out_data       : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL out_empty      : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL out_channel    : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL out_sync       : STD_LOGIC;
+  SIGNAL out_val        : STD_LOGIC;
+  SIGNAL out_sop        : STD_LOGIC;
+  SIGNAL out_eop        : STD_LOGIC;
+  SIGNAL hold_out_sop   : STD_LOGIC;
+  SIGNAL prev_out_data  : STD_LOGIC_VECTOR(out_data'RANGE);
+  
+  SIGNAL state          : t_dp_state_enum;
+  
+  SIGNAL verify_en      : STD_LOGIC;
+  SIGNAL verify_done    : STD_LOGIC;
+  
+  SIGNAL exp_data       : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0) := TO_UVEC(19555, c_dp_data_w);
+  
+BEGIN
+
+  -- Use intervals marked by sync to start a new test named by state.
+  --
+  -- Under all circumstances the out_data should not mis or duplicate a count
+  -- while out_val is asserted as checked by p_verify.
+  -- The throughput must remain 100%, with only some increase in latency. This
+  -- can be checked manually by checking that cnt_val does not toggle when the
+  -- out_ready is asserted continuously. E.g. check that the out_data value 
+  -- is sufficiently high given the number of sync intervals that have passed.
+  --
+  -- Stimuli to verify the dp_latency_adapter DUT:
+  --
+  -- * Use various ready latency combinations in c_dut_latency:
+  --   .     c_in_latency > c_out_latency = 0
+  --   .     c_in_latency > c_out_latency > 0
+  --   .     c_in_latency = c_out_latency = 0
+  --   .     c_in_latency = c_out_latency > 0
+  --   . 0 = c_in_latency < c_out_latency
+  --   . 0 < c_in_latency < c_out_latency
+  --
+  -- * Manipulate the stimuli in:
+  --   . p_cnt_en    : cnt_en not always active when in_ready is asserted
+  --   . p_out_ready : out_ready not always active
+
+  clk <= NOT clk OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+  
+  -- Sync interval
+  proc_dp_sync_interval(clk, sync);
+  
+  -- Input data
+  cnt_val <= in_ready AND cnt_en;
+  
+  proc_dp_cnt_dat(rst, clk, cnt_val, cnt_dat);
+  proc_dp_tx_data(c_tx_latency, rst, clk, cnt_val, cnt_dat, tx_data, tx_val, in_data, in_val);
+  proc_dp_tx_ctrl(c_tx_offset_sync, c_tx_period_sync, in_data, in_val, in_sync);
+  proc_dp_tx_ctrl(c_tx_offset_sop, c_tx_period_sop, in_data, in_val, in_sop);
+  proc_dp_tx_ctrl(c_tx_offset_eop, c_tx_period_eop, in_data, in_val, in_eop);
+  
+  -- Stimuli control
+  proc_dp_count_en(rst, clk, sync, lfsr1, state, verify_done, tb_end, cnt_en);
+  proc_dp_out_ready(rst, clk, sync, lfsr2, out_ready);
+  
+  -- Output verify
+  proc_dp_verify_en(c_verify_en_wait, rst, clk, sync, verify_en);
+  proc_dp_verify_data("out_data", c_rx_latency, clk, verify_en, out_ready, out_val, out_data, prev_out_data);
+  proc_dp_verify_valid(c_rx_latency, clk, verify_en, out_ready, prev_out_ready, out_val);
+  proc_dp_verify_ctrl(c_tx_offset_sync, c_tx_period_sync, "sync", clk, verify_en, out_data, out_val, out_sync);
+  proc_dp_verify_ctrl(c_tx_offset_sop, c_tx_period_sop, "sop", clk, verify_en, out_data, out_val, out_sop);
+  proc_dp_verify_ctrl(c_tx_offset_eop, c_tx_period_eop, "eop", clk, verify_en, out_data, out_val, out_eop);
+  proc_dp_verify_sop_and_eop(c_rx_latency, FALSE, clk, out_val, out_val, out_sop, out_eop, hold_out_sop);  -- Verify that sop and eop come in pairs, no check on valid between eop and sop
+  proc_dp_verify_other_sosi("empty", INCR_UVEC(out_data, c_empty_offset), clk, verify_en, out_empty);
+  proc_dp_verify_other_sosi("channel", INCR_UVEC(out_data, c_channel_offset), clk, verify_en, out_channel);
+
+  -- Check that the test has ran at all
+  proc_dp_verify_value(e_equal, clk, verify_done, exp_data, out_data);
+  
+  ------------------------------------------------------------------------------
+  -- Chain of 1 or more dp_latency_adapter DUTs
+  --
+  -- . Note this also models a series of streaming modules in a data path
+  --
+  ------------------------------------------------------------------------------
+  
+  -- Map the test bench tx counter data to the input of the chain
+  in_ready        <= dut_ready(-1);
+  dut_data(-1)    <=           in_data;
+  dut_empty(-1)   <= INCR_UVEC(in_data, c_empty_offset);
+  dut_channel(-1) <= INCR_UVEC(in_data, c_channel_offset);
+  dut_sync(-1)    <= in_sync;
+  dut_val(-1)     <= in_val;
+  dut_sop(-1)     <= in_sop;
+  dut_eop(-1)     <= in_eop;
+  
+  -- map sl, slv to record
+  dut_ready(-1) <= dut_siso(-1).ready;                           -- SISO
+  dut_sosi(-1).data(c_dp_data_w-1 DOWNTO 0) <= dut_data(-1);     -- SOSI
+  dut_sosi(-1).empty                        <= dut_empty(-1)(c_dp_empty_w-1 DOWNTO 0);
+  dut_sosi(-1).channel                      <= dut_channel(-1)(c_dp_channel_w-1 DOWNTO 0);
+  dut_sosi(-1).sync                         <= dut_sync(-1);
+  dut_sosi(-1).valid                        <= dut_val(-1);
+  dut_sosi(-1).sop                          <= dut_sop(-1);
+  dut_sosi(-1).eop                          <= dut_eop(-1);
+    
+  gen_chain : FOR I IN 0 TO c_nof_dut-1 GENERATE
+    dut : ENTITY work.dp_latency_adapter
+    GENERIC MAP (
+      g_in_latency  => c_dut_latency(I-1),
+      g_out_latency => c_dut_latency(I)
+    )
+    PORT MAP (
+      rst       => rst,
+      clk       => clk,
+      -- ST sink
+      snk_out   => dut_siso(I-1),
+      snk_in    => dut_sosi(I-1),
+      -- ST source
+      src_in    => dut_siso(I),
+      src_out   => dut_sosi(I)
+    );
+  END GENERATE;
+
+  -- map record to sl, slv
+  dut_siso(c_nof_dut-1).ready <= dut_ready(c_nof_dut-1);                                                      -- SISO
+  dut_data(c_nof_dut-1)                               <= dut_sosi(c_nof_dut-1).data(c_dp_data_w-1 DOWNTO 0);  -- SOSI
+  dut_empty(c_nof_dut-1)(c_dp_empty_w-1 DOWNTO 0)     <= dut_sosi(c_nof_dut-1).empty;
+  dut_channel(c_nof_dut-1)(c_dp_channel_w-1 DOWNTO 0) <= dut_sosi(c_nof_dut-1).channel;
+  dut_sync(c_nof_dut-1)                               <= dut_sosi(c_nof_dut-1).sync;
+  dut_val(c_nof_dut-1)                                <= dut_sosi(c_nof_dut-1).valid;
+  dut_sop(c_nof_dut-1)                                <= dut_sosi(c_nof_dut-1).sop;
+  dut_eop(c_nof_dut-1)                                <= dut_sosi(c_nof_dut-1).eop;
+  
+  -- Map the output of the DUT chain to the test bench output data
+  dut_ready(c_nof_dut-1) <= out_ready;
+  out_data               <= dut_data(c_nof_dut-1);
+  out_empty              <= dut_empty(c_nof_dut-1);
+  out_channel            <= dut_channel(c_nof_dut-1);
+  out_sync               <= dut_sync(c_nof_dut-1);
+  out_val                <= dut_val(c_nof_dut-1);
+  out_sop                <= dut_sop(c_nof_dut-1);
+  out_eop                <= dut_eop(c_nof_dut-1);
+    
+END tb;
diff --git a/cores/base/dp/dp_counter/dp_counter.vhd b/cores/base/dp/dp_counter/dp_counter.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..6e92fe1af263e3fd51c38223b00c3a44318db97a
--- /dev/null
+++ b/cores/base/dp/dp_counter/dp_counter.vhd
@@ -0,0 +1,213 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2017
+-- 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:
+-- . Pipeline wrapper around dp_counter_func
+-- Description:
+-- . See dp_counter_func.
+-- . dp_counter_func contains only functional logic (no pipelining).
+-- . This wrapper adds pipelining for the source side outputs (g_pipeline_src_out)
+--   and source side inputs (g_pipeline_src_in).
+-- Usage:
+-- . When g_nof_counters = 1 then dp_counter can reshape the block sizes in a
+--   sync intervals, as is done in dp_block_reshape.vhd
+-- . When g_nof_counters = 2 then dp_counter can reshape the block sizes and the
+--   sync interval, as is done in dp_block_reshape_sync.vhd
+-- . When g_nof_counters > 1 then the dp_counter count_src_out_arr provides the 
+--   block indices for an array of data. The g_nof_counters then defines the 
+--   dimension of the array within a sync interval. For example:
+--
+--     a[N][M][P] with N=3, M=5, p=10 will have N*M*P = 150 valid per sync interval. 
+--
+--   The dp_counter can then provide for each valid in the sync interval the
+--   corresponding array index (n, m, p), using:
+--
+--     g_nof_counters = 3
+--     g_range_start  = (0, 0,  0)
+--     g_range_stop   = (3, 5, 10)
+--     g_range_step   = (1, 1,  1)
+--
+-- Remarks:
+-- . Unfortunately it is not possible to use a generic in the definition of another generic. Therefore the
+--   g_range_* generics are defined as unconstraint.
+-- . When dp_counter is instanciated the length of the g_range_* generics must at least fit g_nof_counters.
+--   In theory count_src_out_arr could be declared as unconstraint and then g_nof_counters could be derived
+--   from the length of count_src_out_arr, but it is more clear to explitely to declare g_nof_counters.
+--
+--   31-05-2018 J Hargreaves added count_offset_in_arr input
+--     This signal can be used to apply an offset to the start count
+--   USAGE
+--     Do not connect the signal if it is not needed: It will consume extra resources
+--     It only works when g_range_step(i) is 1
+--     It only works when g_range_start(i) + count_offset_in_arr(i) < g_range_stop(i)
+--     Any other useage will break counters >= stage i
+
+LIBRARY IEEE, dp_pipeline_lib, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_counter IS
+  GENERIC (
+    g_nof_counters     : NATURAL := 1;
+    g_range_start      : t_nat_natural_arr;  -- range must fit (g_nof_counters-1 DOWNTO 0)
+    g_range_stop       : t_nat_natural_arr;  -- range must fit (g_nof_counters-1 DOWNTO 0)
+    g_range_step       : t_nat_natural_arr;  -- range must fit (g_nof_counters-1 DOWNTO 0)
+    g_pipeline_src_out : NATURAL := 1;       -- Pipeline source outputs (data,valid,sop,eop etc)
+    g_pipeline_src_in  : NATURAL := 0        -- Pipeline source inputs (ready,xon). This will also pipeline src_out.
+  );
+  PORT (                                                    
+    clk         : IN  STD_LOGIC;
+    rst         : IN  STD_LOGIC;
+
+    snk_in      : IN  t_dp_sosi;
+    snk_out     : OUT t_dp_siso;
+
+    src_out     : OUT t_dp_sosi;
+    src_in      : IN  t_dp_siso := c_dp_siso_rdy;
+
+    count_offset_in_arr : IN  t_nat_natural_arr(g_nof_counters-1 DOWNTO 0) := (OTHERS=>0);  
+    count_src_out_arr : OUT t_dp_sosi_arr(g_nof_counters-1 DOWNTO 0)
+  );
+END dp_counter;
+
+
+ARCHITECTURE wrap OF dp_counter IS
+
+  -- force downto range for unconstraint g_range generics
+  CONSTANT c_range_len             : NATURAL := g_range_start'LENGTH;  -- g_nof_counters must be <= c_range_len
+  CONSTANT c_range_start           : t_nat_natural_arr(c_range_len-1 DOWNTO 0) := g_range_start;
+  CONSTANT c_range_stop            : t_nat_natural_arr(c_range_len-1 DOWNTO 0) := g_range_stop;
+  CONSTANT c_range_step            : t_nat_natural_arr(c_range_len-1 DOWNTO 0) := g_range_step;
+
+  CONSTANT c_use_dp_pipeline       : BOOLEAN := (g_pipeline_src_out>0 AND g_pipeline_src_in=0);
+  CONSTANT c_use_dp_pipeline_ready : BOOLEAN := (g_pipeline_src_in>0);
+
+  SIGNAL dp_counter_func_src_out_arr : t_dp_sosi_arr(g_nof_counters-1 DOWNTO 0);
+
+BEGIN
+
+  ------------------------------------------------------------------------------
+  -- dp_counter_func
+  ------------------------------------------------------------------------------ 
+  u_dp_counter_func : ENTITY work.dp_counter_func
+  GENERIC MAP (
+    g_nof_counters => g_nof_counters,
+    g_range_start  => c_range_start,
+    g_range_stop   => c_range_stop,
+    g_range_step   => c_range_step
+  )
+  PORT MAP (
+    rst       => rst,
+    clk       => clk,
+
+    count_en  => snk_in.valid,
+
+    count_offset_in_arr => count_offset_in_arr,
+    count_src_out_arr   => dp_counter_func_src_out_arr
+  );
+  
+  ------------------------------------------------------------------------------
+  -- dp_pipeline
+  ------------------------------------------------------------------------------
+  gen_dp_pipeline : IF c_use_dp_pipeline = TRUE GENERATE
+    u_dp_pipeline_snk_in : ENTITY dp_pipeline_lib.dp_pipeline
+    GENERIC MAP (
+      g_pipeline => g_pipeline_src_out
+    )
+    PORT MAP (
+      clk         => clk,
+      rst         => rst,
+  
+      snk_in      => snk_in,
+      snk_out     => snk_out,
+  
+      src_out     => src_out,
+      src_in      => src_in
+    );
+
+    gen_dp_pipeline_count_src_out_arr : FOR i IN 0 TO g_nof_counters-1 GENERATE
+      u_dp_pipeline_count_src_out_arr : ENTITY dp_pipeline_lib.dp_pipeline
+      GENERIC MAP (
+        g_pipeline => g_pipeline_src_out
+      )
+      PORT MAP (
+        clk     => clk,
+        rst     => rst,
+    
+        snk_in  => dp_counter_func_src_out_arr(i),
+    
+        src_out => count_src_out_arr(i),
+        src_in  => src_in
+      );
+    END GENERATE;
+  END GENERATE;
+
+  ------------------------------------------------------------------------------
+  -- dp_pipeline_ready
+  ------------------------------------------------------------------------------
+  gen_dp_pipeline_ready : IF c_use_dp_pipeline_ready = TRUE GENERATE
+    u_dp_pipeline_ready : ENTITY dp_pipeline_lib.dp_pipeline_ready
+    GENERIC MAP (
+      g_in_latency   => 1
+    )
+    PORT MAP (
+      clk          => clk,
+      rst          => rst,
+  
+      snk_in       => snk_in,
+      snk_out      => snk_out,
+  
+      src_out      => src_out,
+      src_in       => src_in
+    );
+
+    gen_dp_pipeline_ready_count_src_out_arr : FOR i IN 0 TO g_nof_counters-1 GENERATE
+      u_dp_pipeline_ready_count_src_out_arr : ENTITY dp_pipeline_lib.dp_pipeline_ready
+      GENERIC MAP (
+        g_in_latency => 1
+      )
+      PORT MAP (
+        clk     => clk,
+        rst     => rst,
+    
+        snk_in  => dp_counter_func_src_out_arr(i),
+    
+        src_out => count_src_out_arr(i),
+        src_in  => src_in
+      );
+    END GENERATE;
+  END GENERATE;  
+
+  ------------------------------------------------------------------------------
+  -- No pipelining
+  ------------------------------------------------------------------------------
+  no_dp_pipeline : IF c_use_dp_pipeline=FALSE AND c_use_dp_pipeline_ready=FALSE GENERATE
+    src_out <= snk_in;
+    snk_out <= src_in;
+    
+    count_src_out_arr <= dp_counter_func_src_out_arr;
+  END GENERATE;
+
+END wrap;
diff --git a/cores/base/dp/dp_counter/dp_counter_func.vhd b/cores/base/dp/dp_counter/dp_counter_func.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..188250c85c45a2fcdb8da3c40caae92b244b4316
--- /dev/null
+++ b/cores/base/dp/dp_counter/dp_counter_func.vhd
@@ -0,0 +1,139 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2017
+-- 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:
+-- . Provide an array of counters with dimension carryover
+-- Description:
+-- . Provides g_nof_counters counters,[g_nof_counters-1]..[c0]
+-- . Every counter is specified like Python's range(start,stop,step).
+-- . c0 changes the fastest, c4 changes the slowest
+-- . Faster changing dimensions carry over in slower changing dimensions 
+--   when dimension maximum is reached
+-- . The outputs are in sync with / apply to src_out.
+-- . range(0,1,1) = [0] is the smallest count range
+-- Usage:
+-- . The count values themselves (c0..c4) are very useful to tag streaming
+--   data with corresponding ID indices.
+-- . The extra outputs (e.g. c0_min, c0_max) can be used to trigger other
+--   logic when minimum/maximum values per dimension are reached.
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_counter_func IS
+  GENERIC (
+    g_nof_counters    : NATURAL := 1;
+    g_range_start     : t_nat_natural_arr;  -- range must fit (g_nof_counters-1 DOWNTO 0)
+    g_range_stop      : t_nat_natural_arr;  -- range must fit (g_nof_counters-1 DOWNTO 0)
+    g_range_step      : t_nat_natural_arr   -- range must fit (g_nof_counters-1 DOWNTO 0)
+  );
+  PORT (                                                    
+    clk         : IN  STD_LOGIC;
+    rst         : IN  STD_LOGIC;
+
+    count_en    : IN  STD_LOGIC;
+  
+    count_offset_in_arr : IN  t_nat_natural_arr(g_nof_counters-1 DOWNTO 0) := (OTHERS=>0);  
+    count_src_out_arr   : OUT t_dp_sosi_arr(g_nof_counters-1 DOWNTO 0)
+  );
+END dp_counter_func;
+
+
+ARCHITECTURE str OF dp_counter_func IS
+
+  -- force downto range for unconstraint g_range generics
+  CONSTANT c_range_len             : NATURAL := g_range_start'LENGTH;  -- g_nof_counters must be <= c_range_len
+  CONSTANT c_range_start           : t_nat_natural_arr(c_range_len-1 DOWNTO 0) := g_range_start;
+  CONSTANT c_range_stop            : t_nat_natural_arr(c_range_len-1 DOWNTO 0) := g_range_stop;
+  CONSTANT c_range_step            : t_nat_natural_arr(c_range_len-1 DOWNTO 0) := g_range_step;
+  
+  CONSTANT c_max_count_w : NATURAL := 32;
+
+  SIGNAL count_en_arr   : STD_LOGIC_VECTOR(g_nof_counters-1 DOWNTO 0);
+  SIGNAL check_max_arr  : STD_LOGIC_VECTOR(g_nof_counters-1 DOWNTO 0);
+  SIGNAL count_init_arr : STD_LOGIC_VECTOR(g_nof_counters-1 DOWNTO 0);
+  SIGNAL count_min_arr  : STD_LOGIC_VECTOR(g_nof_counters-1 DOWNTO 0);
+  SIGNAL count_max_arr  : STD_LOGIC_VECTOR(g_nof_counters-1 DOWNTO 0);
+  TYPE t_count_arr IS ARRAY(g_nof_counters-1 DOWNTO 0) OF STD_LOGIC_VECTOR(c_max_count_w-1 DOWNTO 0);
+  SIGNAL count_arr      : t_count_arr;
+
+BEGIN
+
+  --------------------------------------------------------------------------------
+  -- Counter control inputs
+  -------------------------------------------------------------------------------
+  gen_dp_counter_func_single_input : FOR i IN 0 TO g_nof_counters-1 GENERATE
+
+    gen_c0 : IF i=0 GENERATE
+      count_en_arr(i)  <= count_en;
+      check_max_arr(i) <= count_en;
+    END GENERATE;
+
+    gen_c1_upwards : IF i>0 GENERATE
+       count_en_arr(i)  <= count_init_arr(i-1) OR count_min_arr(i-1);
+       check_max_arr(i) <= count_max_arr(i-1);
+    END GENERATE;
+
+  END GENERATE;
+
+  --------------------------------------------------------------------------------
+  -- Array of dp_counter_func_single instances
+  -------------------------------------------------------------------------------
+  gen_dp_counter_func_single : FOR i IN 0 TO g_nof_counters-1 GENERATE
+    u_dp_counter_func_single : ENTITY work.dp_counter_func_single
+    GENERIC MAP (
+      g_range_start => c_range_start(i),
+      g_range_stop  => c_range_stop(i),
+      g_range_step  => c_range_step(i)
+    )
+    PORT MAP (
+      rst        => rst,
+      clk        => clk,
+   
+      count_en   => count_en_arr(i),
+      check_max  => check_max_arr(i),
+      count_offset => count_offset_in_arr(i),
+   
+      count      => count_arr(i),
+      count_init => count_init_arr(i),
+      count_min  => count_min_arr(i),
+      count_max  => count_max_arr(i)
+    );
+  END GENERATE;
+ 
+  --------------------------------------------------------------------------------
+  -- Counter outputs
+  -------------------------------------------------------------------------------
+  gen_dp_counter_func_single_output : FOR i IN 0 TO g_nof_counters-1 GENERATE
+    count_src_out_arr(i).sync <= '0';  -- not used, force to '0' to avoid toggling between '0' and 'X' in Wave window
+                                       -- when sync is passed on through other components
+    count_src_out_arr(i).sop <= count_min_arr(i);
+    count_src_out_arr(i).eop <= count_max_arr(i);
+    count_src_out_arr(i).valid <= count_en;
+    count_src_out_arr(i).data <= RESIZE_DP_DATA(count_arr(i));
+  END GENERATE;
+    
+END str;
diff --git a/cores/base/dp/dp_counter/dp_counter_func_single.vhd b/cores/base/dp/dp_counter/dp_counter_func_single.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..7281e35970e3b8a343554998e78dde688e9015ba
--- /dev/null
+++ b/cores/base/dp/dp_counter/dp_counter_func_single.vhd
@@ -0,0 +1,152 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2017
+-- 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:
+-- . Simple counter with start, stop, step; used in dp_counter_func.
+-- Description:
+-- . range(0,2,1) = [0, 1] is the smallest count range allowed
+-- Usage:
+-- . Not for standalone use; part of dp_counter_func.
+ 
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_counter_func_single IS --FIXME move this to common
+  GENERIC (
+    g_range_start : NATURAL; -- (start,stop,step) like python range(start, stop, step)
+    g_range_stop  : NATURAL;
+    g_range_step  : NATURAL
+  );
+  PORT (                                                    
+    clk        : IN  STD_LOGIC;
+    rst        : IN  STD_LOGIC;
+
+    count_en   : IN STD_LOGIC;
+    check_max  : IN STD_LOGIC := '1';
+    count_offset : NATURAL := 0;
+   
+    count      : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
+    count_init : OUT STD_LOGIC; -- Pulses at first init
+    count_min  : OUT STD_LOGIC; --Pulses when count=start
+    count_max  : OUT STD_LOGIC  --Pulses when count=max
+  );
+END dp_counter_func_single;
+
+
+ARCHITECTURE rtl OF dp_counter_func_single IS
+
+ -- The user defines the counters like a Python range(start,stop,step) in which the stop value
+  -- is never actually reached. Calculate the actual maximum values here.
+  -- . Example:
+  --   . range(0,4,2) = [0, 2]
+  --   . range(0,5,2) = [0, 2, 4]
+  --   . range(0,6,2) = [0, 2, 4]
+  --   . range(0,7,2) = [0, 2, 4, 6]
+  --   . range(1,7,2) = [1, 3, 5]
+  -- . The maximum value is: start+((stop-1-start)/step)*step
+  CONSTANT c_nof_count : NATURAL := (g_range_stop-1-g_range_start)/g_range_step + 1;
+  CONSTANT c_count_max : NATURAL := g_range_start+(c_nof_count-1)*g_range_step;
+  CONSTANT c_count_w   : NATURAL := ceil_log2(c_count_max+1);
+
+  TYPE t_reg IS RECORD
+    count_en  : STD_LOGIC;
+    count     : STD_LOGIC_VECTOR(c_count_w-1 DOWNTO 0);
+    count_min : STD_LOGIC;
+    count_max : STD_LOGIC;
+    count_init : STD_LOGIC;
+  END RECORD;
+
+  SIGNAL r, nxt_r : t_reg;
+
+BEGIN
+  
+  --------------------------------------------------------------------------------
+  -- Combinational logic
+  --------------------------------------------------------------------------------
+  p_comb : PROCESS(rst, r, count_en, check_max, count_offset) 
+    VARIABLE v : t_reg;
+  BEGIN
+    v           := r;
+    v.count_min := '0';
+    v.count_max := '0';
+    v.count_init := '0';
+
+    IF count_en='1' THEN
+
+      -- Start counting / init
+      IF r.count_en='0' THEN
+        v.count_en := '1';
+        v.count := TO_UVEC(g_range_start+count_offset, c_count_w);
+        v.count_min := '1';
+        v.count_init := '1';     
+      -- keep counting
+      ELSE
+        v.count := INCR_UVEC(r.count, g_range_step);
+        IF c_count_max>0 AND check_max='1' AND r.count = TO_UVEC(c_count_max-g_range_step, c_count_w) THEN -- count max almost reached
+          v.count_max := '1';
+        ELSIF r.count = TO_UVEC(c_count_max, c_count_w) THEN -- count max reached
+          -- Reset count to start value
+          v.count := TO_UVEC(g_range_start, c_count_w);
+          v.count_min := '1';
+        END IF;
+      END IF;
+
+      -- If the maximum count is 0, count_max is always high.
+      IF c_count_max=0 THEN
+        v.count_max := '1';       
+      END IF;   
+
+    ELSIF check_max='1' AND r.count = TO_UVEC(c_count_max, c_count_w) THEN -- count max reached
+      v.count_max := '1';
+    END IF;
+   
+    IF rst = '1' THEN
+      v.count_en  := '0';
+      v.count     := (OTHERS=>'0');
+      v.count_min := '0';
+      v.count_max := '0';
+      v.count_init := '0';
+    END IF;
+ 
+    nxt_r <= v;
+  END PROCESS;
+
+  --------------------------------------------------------------------------------
+  -- Register stage
+  --------------------------------------------------------------------------------
+  r <= nxt_r WHEN rising_edge(clk);
+
+  --------------------------------------------------------------------------------
+  -- Outputs
+  --------------------------------------------------------------------------------
+  count(31 DOWNTO c_count_w)  <= (OTHERS=>'0');
+  count(c_count_w-1 DOWNTO 0) <= nxt_r.count;
+  count_init <= nxt_r.count_init;
+  count_min  <= nxt_r.count_min;
+  count_max  <= nxt_r.count_max;
+
+
+END rtl;
diff --git a/cores/base/dp/dp_counter/hdllib.cfg b/cores/base/dp/dp_counter/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..fb79f9a247cdd852618c3c2efcc21e5fa8608313
--- /dev/null
+++ b/cores/base/dp/dp_counter/hdllib.cfg
@@ -0,0 +1,23 @@
+hdl_lib_name = dp_counter
+hdl_library_clause_name = dp_counter_lib
+hdl_lib_uses_synth = dp_pipeline
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    dp_counter_func_single.vhd
+    dp_counter_func.vhd
+    dp_counter.vhd
+   
+test_bench_files = 
+    tb_dp_counter.vhd
+    tb_tb_dp_counter.vhd
+
+regression_test_vhdl = 
+    tb_dp_counter_func.vhd
+    tb_tb_dp_counter.vhd
+    
+[modelsim_project_file]
+
+
+[quartus_project_file]
diff --git a/cores/base/dp/dp_counter/tb_dp_counter.vhd b/cores/base/dp/dp_counter/tb_dp_counter.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..386a231b946fb2b37d10def31cfcb8562ea15267
--- /dev/null
+++ b/cores/base/dp/dp_counter/tb_dp_counter.vhd
@@ -0,0 +1,224 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2017
+-- 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:
+--   Eric Kooistra, 23 Apr 2018
+-- Purpose:
+-- . Test bench for dp_counter.
+-- Description:
+--   Functional details are verified by tb_dp_counter_func.vhd. This
+--   tb_dp_counter.vhd shows the dp_counter with pipelining.
+--Usage:
+-- . as 10
+-- . run -all
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_str_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_counter IS
+  GENERIC (
+    -- general
+    g_flow_control_stimuli   : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
+    g_flow_control_verify    : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
+    -- dut
+    g_pipeline_src_out : NATURAL := 1;  -- Pipeline source outputs (data,valid,sop,eop etc)
+    g_pipeline_src_in  : NATURAL := 0;  -- Pipeline source inputs (ready,xon). This will also pipeline src_out.
+    g_nof_counters     : NATURAL := 3;
+    -- min range = [0,2,1] => (0,1) 'the Python way'
+    g_range_start      : t_nat_natural_arr(9 DOWNTO 0) := (0,0,0,0,0,0,0, 1, 0, 0);
+    g_range_stop       : t_nat_natural_arr(9 DOWNTO 0) := (2,2,2,2,2,2,7,16,16, 1);
+    g_range_step       : t_nat_natural_arr(9 DOWNTO 0) := (1,1,1,1,1,1,2, 2, 2, 1)
+  );
+END tb_dp_counter;
+
+
+ARCHITECTURE tb OF tb_dp_counter IS
+
+  ------------------------------------------------------------------------------
+  -- Clock & reset
+  ------------------------------------------------------------------------------
+  CONSTANT c_clk_period : TIME := 5 ns;
+  CONSTANT c_max_count_w : NATURAL := 32;
+
+  CONSTANT c_rl          : NATURAL := 1;
+  CONSTANT c_data_w      : NATURAL := 32;
+  CONSTANT c_data_init   : NATURAL := 0;
+  
+  SIGNAL clk            : STD_LOGIC := '1';
+  SIGNAL rst            : STD_LOGIC := '1';
+  SIGNAL tb_end         : STD_LOGIC := '0';
+
+  ------------------------------------------------------------------------------
+  -- dp_counter
+  ------------------------------------------------------------------------------ 
+  SIGNAL snk_in            : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL snk_out           : t_dp_siso;
+  SIGNAL src_out           : t_dp_sosi;
+  SIGNAL src_in            : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL count_src_out_arr : t_dp_sosi_arr(g_nof_counters-1 DOWNTO 0);
+  SIGNAL period            : NATURAL;
+  
+  FUNCTION calculate_period(g_counter : NATURAL) RETURN NATURAL IS
+    VARIABLE v_range_period : t_nat_natural_arr(g_counter DOWNTO 0);
+    VARIABLE v_period       : NATURAL := 1;
+  BEGIN
+    FOR I IN 0 TO g_counter LOOP
+      v_range_period(I) := (g_range_stop(I)-1 - g_range_start(I)) / g_range_step(I) + 1;  -- Python style range(start, stop, step)
+      v_period := v_period * v_range_period(I);
+    END LOOP;
+    RETURN v_period;
+  END;
+  
+  ------------------------------------------------------------------------------
+  -- flow control
+  ------------------------------------------------------------------------------ 
+  CONSTANT c_in_random_w       : NATURAL := 15;
+  CONSTANT c_out_random_w      : NATURAL := 16;  -- use different length per random source
+  CONSTANT c_in_pulse_active   : NATURAL := 1;
+  CONSTANT c_out_pulse_active  : NATURAL := 1;
+  CONSTANT c_in_pulse_period   : NATURAL := 2;
+  CONSTANT c_out_pulse_period  : NATURAL := 2;
+  
+  SIGNAL in_random           : STD_LOGIC_VECTOR(c_in_random_w-1 DOWNTO 0) := TO_UVEC(1, c_in_random_w);
+  SIGNAL out_random          : STD_LOGIC_VECTOR(c_out_random_w-1 DOWNTO 0) := TO_UVEC(1, c_out_random_w);
+  SIGNAL in_pulse            : STD_LOGIC;
+  SIGNAL out_pulse           : STD_LOGIC;
+  SIGNAL in_pulse_en         : STD_LOGIC := '1';
+  SIGNAL out_pulse_en        : STD_LOGIC := '1';
+  
+  SIGNAL in_en          : STD_LOGIC := '0';
+  SIGNAL out_ready      : STD_LOGIC := '0';
+  
+  
+BEGIN
+  
+  ------------------------------------------------------------------------------
+  -- Flow control
+  ------------------------------------------------------------------------------
+  in_random <= func_common_random(in_random) WHEN rising_edge(clk);
+  out_random <= func_common_random(out_random) WHEN rising_edge(clk);
+  
+  proc_common_gen_duty_pulse(c_in_pulse_active, c_in_pulse_period, '1', rst, clk, in_pulse_en, in_pulse);
+  proc_common_gen_duty_pulse(c_out_pulse_active, c_out_pulse_period, '1', rst, clk, out_pulse_en, out_pulse);
+
+  in_en <= '1'                       WHEN g_flow_control_stimuli=e_active ELSE
+           in_random(in_random'HIGH) WHEN g_flow_control_stimuli=e_random ELSE
+           in_pulse                  WHEN g_flow_control_stimuli=e_pulse;
+
+  out_ready <= '1'                         WHEN g_flow_control_verify=e_active ELSE
+               out_random(out_random'HIGH) WHEN g_flow_control_verify=e_random ELSE
+               out_pulse                   WHEN g_flow_control_verify=e_pulse;
+                
+  src_in.ready <= out_ready;
+  src_in.xon <= NOT src_in.xon WHEN rising_edge(clk);  -- should have no effect, only passed on from src_in to snk_out
+
+  ------------------------------------------------------------------------------
+  -- Clock & reset
+  ------------------------------------------------------------------------------
+  clk <= (NOT clk) OR tb_end AFTER c_clk_period/2;
+  rst <= '1', '0' AFTER c_clk_period*7;
+  
+  ------------------------------------------------------------------------------
+  -- Stimuli: 
+  ------------------------------------------------------------------------------
+
+  -- Generate snk_in incrementing data with valid
+  proc_dp_gen_data(c_rl,
+                   c_data_w,
+                   c_data_init,
+                   rst,
+                   clk,
+                   in_en,
+                   snk_out,
+                   snk_in);
+  
+  p_stimuli : PROCESS
+  BEGIN
+    -- run some more intervals for slowest counter, to more view how the slowest counter behaves
+    FOR I IN 0 TO 2 LOOP
+      proc_common_wait_until_hi_lo(clk, count_src_out_arr(g_nof_counters-1).eop);  -- wait for carry over
+    END LOOP;
+    
+    tb_end <= '1';    
+    WAIT;
+  END PROCESS;
+
+  ------------------------------------------------------------------------------
+  -- DUT
+  ------------------------------------------------------------------------------     
+  u_dp_counter : ENTITY work.dp_counter
+  GENERIC MAP (
+    g_nof_counters     => g_nof_counters,
+    g_range_start      => g_range_start,
+    g_range_stop       => g_range_stop,
+    g_range_step       => g_range_step,
+    g_pipeline_src_out => g_pipeline_src_out,
+    g_pipeline_src_in  => g_pipeline_src_in
+  )
+  PORT MAP (
+    rst               => rst,
+    clk               => clk,
+
+    snk_in            => snk_in,
+    snk_out           => snk_out,
+
+    src_out           => src_out,
+    src_in            => src_in,
+
+    count_src_out_arr => count_src_out_arr
+  );
+  
+  ------------------------------------------------------------------------------
+  -- Verification
+  --   Verify dp_counter using the counter data from the stimuli as reference.
+  --   Only verify the dp_counter for the highest counter, because that covers
+  --   also the low level counters. The details of dp_counter_func are tested
+  --   in tb_dp_counter_func.vhd.
+  ------------------------------------------------------------------------------
+  p_verify : PROCESS(clk)
+    CONSTANT c_period  : NATURAL := calculate_period(g_nof_counters-1);
+    
+    VARIABLE v_cnt : NATURAL := 0;
+  BEGIN
+    period <= c_period;  -- to view c_period in wave window
+    IF rising_edge(clk) THEN
+      IF count_src_out_arr(g_nof_counters-1).valid='1' THEN
+        ASSERT v_cnt = TO_UINT(src_out.data) REPORT "Wrong cnt at valid : " & int_to_str(v_cnt) SEVERITY ERROR;
+        IF count_src_out_arr(g_nof_counters-1).sop='1' THEN
+          ASSERT v_cnt MOD c_period = 0 REPORT "Wrong cnt at sop : " & int_to_str(v_cnt) SEVERITY ERROR;
+        END IF;
+        IF count_src_out_arr(g_nof_counters-1).eop='1' THEN
+          ASSERT v_cnt MOD c_period = c_period-1 REPORT "Wrong cnt at eop : " & int_to_str(v_cnt) SEVERITY ERROR;
+        END IF;
+        v_cnt := v_cnt + 1;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+END tb;
diff --git a/cores/base/dp/dp_counter/tb_dp_counter_func.vhd b/cores/base/dp/dp_counter/tb_dp_counter_func.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..3ac3804f058b6f66683b1161b4037339d7b3ab88
--- /dev/null
+++ b/cores/base/dp/dp_counter/tb_dp_counter_func.vhd
@@ -0,0 +1,249 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2017
+-- 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:
+-- . initial, Daniel van der Schuur
+--   Pieter Donker, Mar-2018, filled in verify process. 
+--   Pieter Donker, Apr-2018, add stop test. 
+-- Purpose:
+-- . Test bench for dp_counter_func
+-- Description:
+-- . dp_counter_func contains *only* the function
+--   . so no flow control (taken care of in dp_counter.vhd wrapper)
+--   . so no pipelining   (taken care of in dp_counter.vhd wrapper)
+-- . The above means that this TB does not have to cover flow control or
+--   pipelining either, which greatly simplifies things.
+--Usage:
+-- . as 10
+-- . run -all
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_str_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_counter_func IS
+  GENERIC (
+    g_nof_counters : NATURAL := 2;
+    -- min range = [0,2,1] => (0,1) 'the python way'
+    g_range_start  : t_nat_natural_arr(9 DOWNTO 0) := (0,0,0,0,0,0,0, 1, 0, 0);
+    g_range_stop   : t_nat_natural_arr(9 DOWNTO 0) := (2,2,2,2,2,2,7,16,16,16);
+    g_range_step   : t_nat_natural_arr(9 DOWNTO 0) := (1,1,1,1,1,1,2, 2, 2, 1)
+  );
+END tb_dp_counter_func;
+
+
+ARCHITECTURE tb OF tb_dp_counter_func IS
+
+  ------------------------------------------------------------------------------
+  -- Clock & reset
+  ------------------------------------------------------------------------------
+  CONSTANT c_clk_period : TIME := 5 ns;
+  CONSTANT c_max_count_w : NATURAL := 32;
+
+  SIGNAL clk            : STD_LOGIC := '1';
+  SIGNAL rst            : STD_LOGIC := '1';
+
+  ------------------------------------------------------------------------------
+  -- dp_counter_func
+  ------------------------------------------------------------------------------ 
+  SIGNAL dp_counter_func_count_en          : STD_LOGIC := '0';
+  SIGNAL dp_counter_func_count_src_out_arr : t_dp_sosi_arr(g_nof_counters-1 DOWNTO 0);
+  
+  -- It is difficult / not possible to avoid the glitches in the dp_counter_func outputs, because
+  -- dp_counter_func intentionally works combinatorially, so its outputs can vary during a few
+  -- delta-cycles, before the finalize. Therefore use a pipeline debug signal to view the outputs
+  -- without the combinatorial glitches in the wave window. 
+  SIGNAL dp_counter_func_count_src_out_arr_p : t_dp_sosi_arr(g_nof_counters-1 DOWNTO 0);
+
+  ------------------------------------------------------------------------------
+  -- Verification
+  ------------------------------------------------------------------------------
+  SIGNAL tb_eop_sop_en   : STD_LOGIC := '1';
+  SIGNAL tb_step_en      : STD_LOGIC := '0';
+  SIGNAL tb_start_en     : STD_LOGIC := '0';
+  SIGNAL tb_stopped_en   : STD_LOGIC := '0';
+  SIGNAL tb_carryover_en : STD_LOGIC := '0';
+  SIGNAL tb_end          : STD_LOGIC := '0';
+
+  TYPE t_count_arr IS ARRAY(g_nof_counters-1 DOWNTO 0) OF NATURAL;
+  SIGNAL tb_count_arr      : t_count_arr := (others => 0);
+  SIGNAL tb_last_count_arr : t_count_arr := (others => 0);
+
+  BEGIN
+  
+  ------------------------------------------------------------------------------
+  -- Clock & reset
+  ------------------------------------------------------------------------------
+  clk <= (NOT clk) OR tb_end AFTER c_clk_period/2;
+  rst <= '1', '0' AFTER c_clk_period*7;
+  
+  ------------------------------------------------------------------------------
+  -- Stimuli: 
+  ------------------------------------------------------------------------------
+  
+  p_stimuli : PROCESS
+  VARIABLE run_clk_cnt: NATURAL := 1;
+  BEGIN
+    -- wait for reset
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 1);
+    
+    REPORT "Start tb dp_counter_func";      
+    
+    dp_counter_func_count_en <= '1';  -- start counting
+    proc_common_gen_pulse(clk, tb_start_en);  -- check start value
+    
+    proc_common_wait_some_cycles(clk, 10);  -- wait some time
+    dp_counter_func_count_en <= '0';  -- stop counting
+    proc_common_wait_some_cycles(clk, 10);  -- wait some time
+    proc_common_gen_pulse(clk, tb_stopped_en);  -- check if counting is stopped
+    
+    dp_counter_func_count_en <= '1';  -- start counting again
+    tb_step_en <= '1';  -- enable step-size check
+
+    IF g_nof_counters>1 THEN
+      -- issue strobe to check counter carry over
+      proc_common_wait_until_lo_hi(clk, dp_counter_func_count_src_out_arr(g_nof_counters-2).eop);  -- wait for carryover
+      proc_common_gen_pulse(clk, tb_carryover_en);  -- check if dimension carryover is going right
+    END IF;
+    
+    -- keep running for full range counting of the slowest counter
+    proc_common_wait_until_hi_lo(clk, dp_counter_func_count_src_out_arr(g_nof_counters-1).eop);  -- wait for carryover
+  
+    -- run some more intervals for slowest counter, to more clearly view how the slowest counter behaves
+    proc_common_wait_until_hi_lo(clk, dp_counter_func_count_src_out_arr(g_nof_counters-1).eop);  -- wait for carryover
+    proc_common_wait_until_hi_lo(clk, dp_counter_func_count_src_out_arr(g_nof_counters-1).eop);  -- wait for carryover
+    
+    REPORT "Stop tb dp_counter_func";  
+    tb_end <= '1';    
+    WAIT;
+  END PROCESS;
+
+  ------------------------------------------------------------------------------
+  -- dp_counter_func
+  ------------------------------------------------------------------------------     
+  u_dp_counter_func : ENTITY work.dp_counter_func
+  GENERIC MAP (
+    g_nof_counters => g_nof_counters,
+    g_range_start  => g_range_start,
+    g_range_stop   => g_range_stop,
+    g_range_step   => g_range_step
+  )
+  PORT MAP (
+    rst       => rst,
+    clk       => clk,
+
+    count_en  => dp_counter_func_count_en,
+
+    count_src_out_arr => dp_counter_func_count_src_out_arr
+  );
+  
+  -- Add pipeline to removed combinatorial glitches for viewing in the wave window
+  dp_counter_func_count_src_out_arr_p <= dp_counter_func_count_src_out_arr WHEN rising_edge(clk);
+  
+  ------------------------------------------------------------------------------
+  -- Verification
+  ------------------------------------------------------------------------------
+  p_verify : PROCESS(clk)
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- check if direct after start the counters hold the start value
+      IF tb_start_en = '1' THEN
+        FOR I IN 0 TO g_nof_counters-1 LOOP
+          ASSERT tb_count_arr(I) = g_range_start(I)
+            REPORT "DP : Wrong start of counter " & int_to_str(I) SEVERITY ERROR;
+        END LOOP;
+      END IF; 
+      
+      -- check if dp_counter_func is stopped after dp_counter_func_count_en <= '0'
+      IF tb_stopped_en = '1' THEN
+        FOR I IN 0 TO g_nof_counters-1 LOOP
+          ASSERT tb_count_arr(I) = TO_UINT(dp_counter_func_count_src_out_arr(I).data(c_max_count_w-1 DOWNTO 0))
+            REPORT "DP : Counter " & int_to_str(I) & " not stopped after dp_counter_func_count_en <= 0" SEVERITY ERROR;
+        END LOOP;
+      END IF; 
+
+      -- check dimension carryover
+      IF tb_carryover_en = '1' THEN
+        -- all counters except the last one should hold the start value
+        FOR I IN 0 TO g_nof_counters-2 LOOP
+          ASSERT tb_count_arr(I) = g_range_start(I)
+            REPORT "DP : Wrong carryover, counter:" & int_to_str(I) SEVERITY ERROR;
+        END LOOP;
+        -- the last counter should hold the start value + step
+        ASSERT tb_count_arr(g_nof_counters-1) = g_range_start(g_nof_counters-1) + g_range_step(g_nof_counters-1)
+            REPORT "DP : Wrong carryover, counter:" & int_to_str(g_nof_counters-1) SEVERITY ERROR;
+      END IF;
+
+      -- check counter values on sop and eop
+      IF tb_eop_sop_en = '1' THEN  
+        FOR I IN 0 TO g_nof_counters-1 LOOP
+          -- on eop counter should hold the stop_value-1
+          IF dp_counter_func_count_src_out_arr(I).eop = '1' THEN
+            ASSERT tb_count_arr(I) = ((g_range_stop(I) - 1 - g_range_start(I)) / g_range_step(I)) * g_range_step(I) + g_range_start(I)
+              REPORT "DP : Wrong stop count on eop, counter:" & int_to_str(I) & 
+                     " is:" & int_to_str(tb_count_arr(I)) & 
+                     " expected:" & int_to_str(((g_range_stop(I) - 1 - g_range_start(I)) / g_range_step(I)) * g_range_step(I) + g_range_start(I)) SEVERITY ERROR;
+          END IF;
+          -- on sop counter should hold the start_value
+          IF dp_counter_func_count_src_out_arr(I).sop = '1' THEN
+            ASSERT tb_count_arr(I) = g_range_start(I)
+              REPORT "DP : Wrong start count on sop, counter:" & int_to_str(I) & 
+                     " is:" & int_to_str(tb_count_arr(I)) & 
+                     " expected:" & int_to_str(g_range_start(I)) SEVERITY ERROR;
+          END IF;
+        END LOOP;
+      END IF;
+
+      -- check step values
+      IF tb_step_en = '1' THEN
+        FOR I IN 0 TO g_nof_counters-1 LOOP
+          IF tb_count_arr(I) > tb_last_count_arr(I) THEN
+            ASSERT (tb_last_count_arr(I) + g_range_step(I)) = tb_count_arr(I) 
+              REPORT "DP : Wrong step count, counter:" & int_to_str(I) & 
+                     " is:" & int_to_str(tb_count_arr(I)) & 
+                     " expected:" & int_to_str(tb_last_count_arr(I) + g_range_step(I)) SEVERITY ERROR;
+          ELSIF tb_count_arr(I) < tb_last_count_arr(I) THEN
+            ASSERT g_range_start(I) = tb_count_arr(I)
+              REPORT "DP : Wrong step count, counter:" & int_to_str(I) & 
+                     " is:" & int_to_str(tb_count_arr(I)) & 
+                     " expected:" & int_to_str(g_range_start(I)) & ")" SEVERITY ERROR;
+          END IF;
+        END LOOP;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  
+  tb_last_count_arr <= tb_count_arr WHEN rising_edge(clk);
+
+  gen_tb_count_arr : FOR i IN 0 TO g_nof_counters-1 GENERATE
+    tb_count_arr(I) <= TO_UINT(dp_counter_func_count_src_out_arr(I).data(c_max_count_w-1 DOWNTO 0)) WHEN dp_counter_func_count_en = '1';
+  END GENERATE;
+
+END tb;
diff --git a/cores/base/dp/dp_counter/tb_tb_dp_counter.vhd b/cores/base/dp/dp_counter/tb_tb_dp_counter.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..5652cfa766ef822d726acff3dc860efe30167d41
--- /dev/null
+++ b/cores/base/dp/dp_counter/tb_tb_dp_counter.vhd
@@ -0,0 +1,64 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+-- Purpose: Verify multiple variations of tb_dp_counter
+-- Description:
+-- Usage:
+-- > as 6
+-- > run -all
+
+ENTITY tb_tb_dp_counter IS
+END tb_tb_dp_counter;
+
+
+ARCHITECTURE tb OF tb_tb_dp_counter 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_active;   -- always active, random or pulse flow control
+  -- g_flow_control_verify    : t_dp_flow_control_enum := e_pulse;  -- always active, random or pulse flow control
+  -- -- dut
+  -- g_pipeline_src_out : NATURAL := 1; -- Pipeline source outputs (data,valid,sop,eop etc)
+  -- g_pipeline_src_in  : NATURAL := 0  -- Pipeline source inputs (ready,xon). This will also pipeline src_out.
+  -- g_nof_counters     : NATURAL := 2;
+  -- -- min range = [0,2,1] => (0,1) 'the Python way'
+  -- g_range_start      : t_nat_natural_arr(9 DOWNTO 0) := (0,0,0,0,0,0,0, 1, 0, 0);
+  -- g_range_stop       : t_nat_natural_arr(9 DOWNTO 0) := (2,2,2,2,2,2,7,16,16,16);
+  -- g_range_step       : t_nat_natural_arr(9 DOWNTO 0) := (1,1,1,1,1,1,2, 2, 2, 1);
+
+  u_act_act_comb     : ENTITY work.tb_dp_counter GENERIC MAP (e_active, e_active, 0, 0, 3);
+  u_act_act_pipe_out : ENTITY work.tb_dp_counter GENERIC MAP (e_active, e_active, 1, 0, 3);
+  u_act_act_pipe_in  : ENTITY work.tb_dp_counter GENERIC MAP (e_active, e_active, 0, 1, 3);
+                                                                                         
+  u_rnd_rnd_comb     : ENTITY work.tb_dp_counter GENERIC MAP (e_random, e_random, 0, 0, 3);
+  u_rnd_rnd_pipe_out : ENTITY work.tb_dp_counter GENERIC MAP (e_random, e_random, 1, 0, 3);
+  u_rnd_rnd_pipe_in  : ENTITY work.tb_dp_counter GENERIC MAP (e_random, e_random, 0, 1, 3);
+  
+END tb;
diff --git a/cores/base/dp/dp_pipeline/dp_pipeline.vhd b/cores/base/dp/dp_pipeline/dp_pipeline.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..3ecd34351a44511e80201e87ff83eb98d3fb8092
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/dp_pipeline.vhd
@@ -0,0 +1,156 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, dp_pkg_lib, dp_components_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Purpose:
+--   Pipeline the source output by one cycle or by g_pipeline cycles.
+-- Description:
+--   The dp_pipeline instantiates 0:g_pipeline stages of dp_pipeline_one.
+--   The dp_pipeline_one provides a single clock cycle delay of the source
+--   output (i.e. sosi). The dp_pipeline_one holds valid sink input in case
+--   src_in.ready goes low and makes src_out.valid high again when
+--   src_in.ready goes high again, without the need for a valid sink input to
+--   push this held data out.
+--   The dp_pipeline delays the data, sop, eop by one cycle relative to the
+--   valid. However the src_out.valid still has the same phase as the
+--   snk_in.valid, because both valids depends on the same src_in.ready.
+--   Therefore dp_pipeline cannot be used to delay the valid phase by one
+--   cycle. Hence the may purpose of dp_pipeline is to register the sosi.
+-- Remarks:
+-- . Ready latency = 1
+-- . Without flow control so when src_in.ready = '1' fixed, then the hold
+--   logic in dp_pipeline becomes void and dp_pipeline then just pipelines the
+--   snk_in sosi.
+
+ENTITY dp_pipeline IS
+  GENERIC (
+    g_pipeline   : NATURAL := 1  -- 0 for wires, > 0 for registers, 
+  );
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- ST sink
+    snk_out      : OUT t_dp_siso;
+    snk_in       : IN  t_dp_sosi;
+    -- ST source
+    src_in       : IN  t_dp_siso := c_dp_siso_rdy;
+    src_out      : OUT t_dp_sosi
+  );
+END dp_pipeline;
+
+
+LIBRARY IEEE, dp_pkg_lib, dp_components_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_pipeline_one IS
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- ST sink
+    snk_out      : OUT t_dp_siso;
+    snk_in       : IN  t_dp_sosi;
+    -- ST source
+    src_in       : IN  t_dp_siso := c_dp_siso_rdy;
+    src_out      : OUT t_dp_sosi
+  );
+END dp_pipeline_one;
+
+
+LIBRARY IEEE, dp_pkg_lib, dp_components_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ARCHITECTURE str OF dp_pipeline IS
+
+  SIGNAL snk_out_arr      : t_dp_siso_arr(0 TO g_pipeline);
+  SIGNAL snk_in_arr       : t_dp_sosi_arr(0 TO g_pipeline);
+  
+BEGIN
+
+  -- Input at index 0
+  snk_out       <= snk_out_arr(0);
+  snk_in_arr(0) <= snk_in;
+  
+  -- Output at index g_pipeline
+  snk_out_arr(g_pipeline) <= src_in;
+  src_out                 <= snk_in_arr(g_pipeline);
+  
+  gen_p : FOR I IN 1 TO g_pipeline GENERATE
+    u_p : ENTITY work.dp_pipeline_one
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => snk_out_arr(I-1),
+      snk_in       => snk_in_arr(I-1),
+      -- ST source
+      src_in       => snk_out_arr(I),
+      src_out      => snk_in_arr(I)
+    );
+  END GENERATE;
+  
+END str;
+
+
+LIBRARY IEEE, dp_pkg_lib, dp_components_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ARCHITECTURE str OF dp_pipeline_one IS
+
+  SIGNAL nxt_src_out      : t_dp_sosi;
+  SIGNAL i_src_out        : t_dp_sosi;
+  
+BEGIN
+
+  src_out <= i_src_out;
+
+  -- Pipeline register
+  p_clk : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      i_src_out <= c_dp_sosi_rst;
+    ELSIF rising_edge(clk) THEN
+      i_src_out <= nxt_src_out;
+    END IF;
+  END PROCESS;
+  
+  -- Input control
+  u_hold_input : ENTITY dp_components_lib.dp_hold_input
+  PORT MAP (
+    rst              => rst,
+    clk              => clk,
+    -- ST sink
+    snk_out          => snk_out,
+    snk_in           => snk_in,
+    -- ST source
+    src_in           => src_in,
+    next_src_out     => nxt_src_out,
+    pend_src_out     => OPEN,
+    src_out_reg      => i_src_out
+  );  
+    
+END str;
diff --git a/cores/base/dp/dp_pipeline/dp_pipeline_arr.vhd b/cores/base/dp/dp_pipeline/dp_pipeline_arr.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..f0407d893fd6496e262e0a20381196806a3f325d
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/dp_pipeline_arr.vhd
@@ -0,0 +1,71 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, dp_pkg_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Purpose:
+--   Pipeline array of g_nof_streams by g_pipeline cycles.
+-- Description:
+--   See dp_pipeline.
+
+ENTITY dp_pipeline_arr IS
+  GENERIC (
+    g_nof_streams : NATURAL := 1;
+    g_pipeline    : NATURAL := 1  -- 0 for wires, > 0 for registers, 
+  );
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- ST sink
+    snk_out_arr  : OUT t_dp_siso_arr(g_nof_streams-1 DOWNTO 0);
+    snk_in_arr   : IN  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+    -- ST source
+    src_in_arr   : IN  t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy);
+    src_out_arr  : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0)
+  );
+END dp_pipeline_arr;
+
+
+ARCHITECTURE str OF dp_pipeline_arr IS
+
+BEGIN
+
+  gen_nof_streams : FOR I IN 0 TO g_nof_streams-1 GENERATE
+    u_p : ENTITY work.dp_pipeline
+    GENERIC MAP (
+      g_pipeline => g_pipeline
+    )
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => snk_out_arr(I),
+      snk_in       => snk_in_arr(I),
+      -- ST source
+      src_in       => src_in_arr(I),
+      src_out      => src_out_arr(I)
+    );
+  END GENERATE;
+  
+END str;
diff --git a/cores/base/dp/dp_pipeline/dp_pipeline_ready.vhd b/cores/base/dp/dp_pipeline/dp_pipeline_ready.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..d44b22316b2b436336bebc32d12b0d16372bc160
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/dp_pipeline_ready.vhd
@@ -0,0 +1,157 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, dp_pkg_lib, dp_components_lib;
+USE IEEE.std_logic_1164.all;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+-- Purpose:
+--   Pipeline the source input
+-- Description:
+--   This dp_pipeline_ready provides a single clock cycle delay of the source
+--   input (i.e. siso). It does this by first going from RL = g_in_latency -->
+--   0 and then to RL = g_out_latency. 
+-- Data flow:
+--   . out RL >  in RL                : incr(out RL - in RL)
+--   . out RL <= in RL AND out RL = 0 : incr(1) --> adapt(out RL)
+--   . out RL <= in RL AND out RL > 0 : adapt(0) --> incr(out RL)
+-- Remark:
+-- . The g_in_latency may be 0, but for g_in_latency=0 the sosi.ready acts
+--   as an acknowledge and that could simply also be registered by the user.
+
+ENTITY dp_pipeline_ready IS
+  GENERIC (
+    g_in_latency   : NATURAL := 1;  -- >= 0
+    g_out_latency  : NATURAL := 1   -- >= 0
+  );
+  PORT (
+    rst          : IN  STD_LOGIC;
+    clk          : IN  STD_LOGIC;
+    -- ST sink
+    snk_out      : OUT t_dp_siso;
+    snk_in       : IN  t_dp_sosi;
+    -- ST source
+    src_in       : IN  t_dp_siso;
+    src_out      : OUT t_dp_sosi
+  );
+END dp_pipeline_ready;
+
+
+ARCHITECTURE str OF dp_pipeline_ready IS
+
+  SIGNAL internal_siso  : t_dp_siso;
+  SIGNAL internal_sosi  : t_dp_sosi;
+ 
+BEGIN
+
+  gen_out_incr_rl : IF g_out_latency>g_in_latency GENERATE
+    -- Register siso by incrementing the input RL first
+    u_incr : ENTITY dp_components_lib.dp_latency_increase
+    GENERIC MAP (
+      g_in_latency   => g_in_latency,
+      g_incr_latency => g_out_latency-g_in_latency
+    )
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => snk_out,
+      snk_in       => snk_in,
+      -- ST source
+      src_in       => src_in,
+      src_out      => src_out
+    );
+  END GENERATE;
+  
+  gen_out_rl_0 : IF g_out_latency<=g_in_latency AND g_out_latency=0 GENERATE
+    -- Register siso by incrementing the input RL first
+    u_incr : ENTITY dp_components_lib.dp_latency_increase
+    GENERIC MAP (
+      g_in_latency   => g_in_latency,
+      g_incr_latency => 1
+    )
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => snk_out,
+      snk_in       => snk_in,
+      -- ST source
+      src_in       => internal_siso,
+      src_out      => internal_sosi
+    );
+
+    -- Input RL --> 0
+    u_adapt : ENTITY dp_components_lib.dp_latency_adapter
+    GENERIC MAP (
+      g_in_latency   => g_in_latency+1,
+      g_out_latency  => g_out_latency
+    )
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => internal_siso,
+      snk_in       => internal_sosi,
+      -- ST source
+      src_in       => src_in,
+      src_out      => src_out
+    );
+  END GENERATE;
+  
+  gen_out_rl : IF g_out_latency<=g_in_latency AND g_out_latency>0 GENERATE
+    -- First adapt the input RL --> 0
+    u_adapt : ENTITY dp_components_lib.dp_latency_adapter
+    GENERIC MAP (
+      g_in_latency   => g_in_latency,
+      g_out_latency  => 0
+    )
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => snk_out,
+      snk_in       => snk_in,
+      -- ST source
+      src_in       => internal_siso,
+      src_out      => internal_sosi
+    );
+
+    -- Register siso by incrementing the internal RL = 0 --> the output RL
+    u_incr : ENTITY dp_components_lib.dp_latency_increase
+    GENERIC MAP (
+      g_in_latency   => 0,
+      g_incr_latency => g_out_latency
+    )
+    PORT MAP (
+      rst          => rst,
+      clk          => clk,
+      -- ST sink
+      snk_out      => internal_siso,
+      snk_in       => internal_sosi,
+      -- ST source
+      src_in       => src_in,
+      src_out      => src_out
+    );
+  END GENERATE;
+    
+END str;
diff --git a/cores/base/dp/dp_pipeline/hdllib.cfg b/cores/base/dp/dp_pipeline/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..0ea1977989f467f74cfb23811bdcd0f992e6861f
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/hdllib.cfg
@@ -0,0 +1,25 @@
+hdl_lib_name = dp_pipeline
+hdl_library_clause_name = dp_pipeline_lib
+hdl_lib_uses_synth = dp_components
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    dp_pipeline.vhd
+    dp_pipeline_arr.vhd
+    dp_pipeline_ready.vhd
+   
+test_bench_files = 
+    tb_dp_pipeline.vhd
+    tb_dp_pipeline_ready.vhd
+    tb_tb_dp_pipeline.vhd
+    tb_tb_dp_pipeline_ready.vhd
+
+regression_test_vhdl = 
+    tb_tb_dp_pipeline.vhd
+    tb_tb_dp_pipeline_ready.vhd
+
+[modelsim_project_file]
+
+
+[quartus_project_file]
diff --git a/cores/base/dp/dp_pipeline/tb_dp_pipeline.vhd b/cores/base/dp/dp_pipeline/tb_dp_pipeline.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..52e7b50b71423f14cddf9c090864fcb513592cd4
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/tb_dp_pipeline.vhd
@@ -0,0 +1,164 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_pipeline IS
+  GENERIC (
+    g_pipeline : NATURAL := 5
+  );
+END tb_dp_pipeline;
+
+
+ARCHITECTURE tb OF tb_dp_pipeline IS
+
+  -- See tb_dp_pkg.vhd for explanation and run time
+
+  -- DUT ready latency
+  CONSTANT c_dut_latency    : NATURAL := 1;              -- fixed 1 for dp_pipeline
+  CONSTANT c_tx_latency     : NATURAL := c_dut_latency;  -- TX ready latency of TB
+  CONSTANT c_tx_void        : NATURAL := sel_a_b(c_tx_latency, 1, 0);  -- used to avoid empty range VHDL warnings when c_tx_latency=0
+  CONSTANT c_tx_offset_sop  : NATURAL := 3;
+  CONSTANT c_tx_period_sop  : NATURAL := 7;              -- sop in data valid cycle 3,  10,  17, ...
+  CONSTANT c_tx_offset_eop  : NATURAL := 5;              -- eop in data valid cycle   5,  12,  19, ...
+  CONSTANT c_tx_period_eop  : NATURAL := c_tx_period_sop;
+  CONSTANT c_tx_offset_sync : NATURAL := 3;              -- sync in data valid cycle 3, 20, 37, ...
+  CONSTANT c_tx_period_sync : NATURAL := 17;
+  CONSTANT c_rx_latency     : NATURAL := c_dut_latency;  -- RX ready latency from DUT
+  CONSTANT c_verify_en_wait : NATURAL := 4+g_pipeline;   -- wait some cycles before asserting verify enable
+  
+  CONSTANT c_random_w       : NATURAL := 19;
+  
+  SIGNAL tb_end         : STD_LOGIC := '0';
+  SIGNAL clk            : STD_LOGIC := '0';
+  SIGNAL rst            : STD_LOGIC;
+  SIGNAL sync           : STD_LOGIC;
+  SIGNAL lfsr1          : STD_LOGIC_VECTOR(c_random_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL lfsr2          : STD_LOGIC_VECTOR(c_random_w   DOWNTO 0) := (OTHERS=>'0');
+  
+  SIGNAL cnt_dat        : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL cnt_val        : STD_LOGIC;
+  SIGNAL cnt_en         : STD_LOGIC;
+  
+  SIGNAL tx_data        : t_dp_data_arr(0 TO c_tx_latency + c_tx_void)    := (OTHERS=>(OTHERS=>'0'));
+  SIGNAL tx_val         : STD_LOGIC_VECTOR(0 TO c_tx_latency + c_tx_void) := (OTHERS=>'0');
+  
+  SIGNAL in_ready       : STD_LOGIC;
+  SIGNAL in_data        : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL in_sync        : STD_LOGIC;
+  SIGNAL in_val         : STD_LOGIC;
+  SIGNAL in_sop         : STD_LOGIC;
+  SIGNAL in_eop         : STD_LOGIC;
+  
+  SIGNAL in_siso        : t_dp_siso;
+  SIGNAL in_sosi        : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL out_siso       : t_dp_siso;
+  SIGNAL out_sosi       : t_dp_sosi;
+  
+  SIGNAL out_ready      : STD_LOGIC;
+  SIGNAL prev_out_ready : STD_LOGIC_VECTOR(0 TO c_rx_latency);
+  SIGNAL out_data       : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  SIGNAL out_sync       : STD_LOGIC;
+  SIGNAL out_val        : STD_LOGIC;
+  SIGNAL out_sop        : STD_LOGIC;
+  SIGNAL out_eop        : STD_LOGIC;
+  SIGNAL hold_out_sop   : STD_LOGIC;
+  SIGNAL prev_out_data  : STD_LOGIC_VECTOR(out_data'RANGE);
+    
+  SIGNAL state          : t_dp_state_enum;
+  
+  SIGNAL verify_en      : STD_LOGIC;
+  SIGNAL verify_done    : STD_LOGIC;
+  
+  SIGNAL exp_data       : STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0) := TO_UVEC(sel_a_b(g_pipeline=0, 18953, 18952), c_dp_data_w);
+  
+BEGIN
+
+  clk <= NOT clk OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+  
+  -- Sync interval
+  proc_dp_sync_interval(clk, sync);
+  
+  -- Input data
+  cnt_val <= in_ready AND cnt_en;
+  
+  proc_dp_cnt_dat(rst, clk, cnt_val, cnt_dat);
+  proc_dp_tx_data(c_tx_latency, rst, clk, cnt_val, cnt_dat, tx_data, tx_val, in_data, in_val);
+  proc_dp_tx_ctrl(c_tx_offset_sync, c_tx_period_sync, in_data, in_val, in_sync);
+  proc_dp_tx_ctrl(c_tx_offset_sop, c_tx_period_sop, in_data, in_val, in_sop);
+  proc_dp_tx_ctrl(c_tx_offset_eop, c_tx_period_eop, in_data, in_val, in_eop);
+
+  -- Stimuli control
+  proc_dp_count_en(rst, clk, sync, lfsr1, state, verify_done, tb_end, cnt_en);
+  proc_dp_out_ready(rst, clk, sync, lfsr2, out_ready);
+  
+  -- Output verify
+  proc_dp_verify_en(c_verify_en_wait, rst, clk, sync, verify_en);
+  proc_dp_verify_data("out_sosi.data", c_rx_latency, clk, verify_en, out_ready, out_val, out_data, prev_out_data);
+  proc_dp_verify_valid(c_rx_latency, clk, verify_en, out_ready, prev_out_ready, out_val);
+  proc_dp_verify_sop_and_eop(c_rx_latency, FALSE, clk, out_val, out_val, out_sop, out_eop, hold_out_sop);  -- Verify that sop and eop come in pairs, no check on valid between eop and sop
+  proc_dp_verify_ctrl(c_tx_offset_sync, c_tx_period_sync, "sync", clk, verify_en, out_data, out_val, out_sync);
+  proc_dp_verify_ctrl(c_tx_offset_sop, c_tx_period_sop, "sop", clk, verify_en, out_data, out_val, out_sop);
+  proc_dp_verify_ctrl(c_tx_offset_eop, c_tx_period_eop, "eop", clk, verify_en, out_data, out_val, out_eop);
+  
+  -- Check that the test has ran at all
+  proc_dp_verify_value(e_equal, clk, verify_done, exp_data, out_data);
+  
+  ------------------------------------------------------------------------------
+  -- DUT dp_pipeline
+  ------------------------------------------------------------------------------
+  
+  -- map sl, slv to record
+  in_ready <= in_siso.ready;                        -- SISO
+  in_sosi.data(c_dp_data_w-1 DOWNTO 0) <= in_data;  -- SOSI
+  in_sosi.sync                         <= in_sync;
+  in_sosi.valid                        <= in_val;
+  in_sosi.sop                          <= in_sop;
+  in_sosi.eop                          <= in_eop;
+  
+  out_siso.ready <= out_ready;                        -- SISO
+  out_data <= out_sosi.data(c_dp_data_w-1 DOWNTO 0);  -- SOSI
+  out_sync <= out_sosi.sync;
+  out_val  <= out_sosi.valid;
+  out_sop  <= out_sosi.sop;
+  out_eop  <= out_sosi.eop;
+  
+  dut : ENTITY work.dp_pipeline
+  GENERIC MAP (
+    g_pipeline => g_pipeline
+  )
+  PORT MAP (
+    rst         => rst,
+    clk         => clk,
+    snk_out     => in_siso,     -- OUT = request to upstream ST source
+    snk_in      => in_sosi,
+    src_in      => out_siso,    -- IN  = request from downstream ST sink
+    src_out     => out_sosi
+  );
+  
+END tb;
diff --git a/cores/base/dp/dp_pipeline/tb_dp_pipeline_ready.vhd b/cores/base/dp/dp_pipeline/tb_dp_pipeline_ready.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..4c3bb7b24e5943844dda99186f24fe512c656207
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/tb_dp_pipeline_ready.vhd
@@ -0,0 +1,223 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose: Verify dp_pipeline_ready for different RL
+-- Description:
+-- Usage:
+-- > as 10
+-- > run -all  -- signal tb_end will stop the simulation by stopping the clk
+-- . The verify procedures check the correct output
+  
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib, dp_components_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+
+ENTITY tb_dp_pipeline_ready IS
+  GENERIC (
+    g_in_en          : t_dp_flow_control_enum := e_random;  -- always active, random or pulse flow control
+    g_out_ready      : t_dp_flow_control_enum := e_random;  -- always active, random or pulse flow control
+    g_in_latency     : NATURAL := 1;  -- >= 0
+    g_out_latency    : NATURAL := 0;  -- >= 0
+    g_nof_repeat     : NATURAL := 50
+  );
+END tb_dp_pipeline_ready;
+
+
+ARCHITECTURE tb OF tb_dp_pipeline_ready IS
+  CONSTANT c_data_w          : NATURAL := 16;
+  CONSTANT c_rl              : NATURAL := 1;
+  CONSTANT c_data_init       : INTEGER := 0;
+  CONSTANT c_frame_len_init  : NATURAL := 1;  -- >= 1
+  CONSTANT c_pulse_active    : NATURAL := 1;
+  CONSTANT c_pulse_period    : NATURAL := 7;
+  CONSTANT c_sync_period     : NATURAL := 7;
+  CONSTANT c_sync_offset     : NATURAL := 2;
+
+  SIGNAL tb_end              : STD_LOGIC := '0';
+  SIGNAL clk                 : STD_LOGIC := '1';
+  SIGNAL rst                 : STD_LOGIC := '1';
+
+  -- Flow control
+  SIGNAL random_0            : STD_LOGIC_VECTOR(14 DOWNTO 0) := (OTHERS=>'0');  -- use different lengths to have different random sequences
+  SIGNAL random_1            : STD_LOGIC_VECTOR(15 DOWNTO 0) := (OTHERS=>'0');  -- use different lengths to have different random sequences
+  SIGNAL pulse_0             : STD_LOGIC;
+  SIGNAL pulse_1             : STD_LOGIC;
+  SIGNAL pulse_en            : STD_LOGIC := '1';
+
+  -- Stimuli
+  SIGNAL in_en               : STD_LOGIC := '1';
+  SIGNAL in_siso             : t_dp_siso;
+  SIGNAL in_sosi             : t_dp_sosi;
+  SIGNAL adapt_siso          : t_dp_siso;
+  SIGNAL adapt_sosi          : t_dp_sosi;
+
+  SIGNAL out_siso            : t_dp_siso := c_dp_siso_hold;  -- ready='0', xon='1'
+  SIGNAL out_sosi            : t_dp_sosi;
+
+  -- Verification
+  SIGNAL verify_en           : STD_LOGIC := '0';
+  SIGNAL verify_done         : STD_LOGIC := '0';
+  SIGNAL count_eop           : NATURAL := 0;
+
+  SIGNAL prev_out_ready      : STD_LOGIC_VECTOR(0 TO g_out_latency);
+  SIGNAL prev_out_data       : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0) := TO_SVEC(c_data_init-1, c_data_w);
+  SIGNAL out_bsn             : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+  SIGNAL out_data            : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+  SIGNAL out_sync            : STD_LOGIC;
+  SIGNAL out_val             : STD_LOGIC;
+  SIGNAL out_sop             : STD_LOGIC;
+  SIGNAL out_eop             : STD_LOGIC;
+  SIGNAL hold_out_sop        : STD_LOGIC;
+  SIGNAL expected_out_data   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+
+BEGIN
+
+  clk <= (NOT clk) OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+
+  random_0 <= func_common_random(random_0) WHEN rising_edge(clk);
+  random_1 <= func_common_random(random_1) WHEN rising_edge(clk);
+
+  proc_common_gen_duty_pulse(c_pulse_active, c_pulse_period,   '1', rst, clk, pulse_en, pulse_0);
+  proc_common_gen_duty_pulse(c_pulse_active, c_pulse_period+1, '1', rst, clk, pulse_en, pulse_1);
+
+
+  ------------------------------------------------------------------------------
+  -- STREAM CONTROL
+  ------------------------------------------------------------------------------
+
+  in_en          <= '1'                     WHEN g_in_en=e_active      ELSE
+                    random_0(random_0'HIGH) WHEN g_in_en=e_random      ELSE
+                    pulse_0                 WHEN g_in_en=e_pulse;
+
+  out_siso.ready <= '1'                     WHEN g_out_ready=e_active  ELSE
+                    random_1(random_1'HIGH) WHEN g_out_ready=e_random  ELSE
+                    pulse_1                 WHEN g_out_ready=e_pulse;
+
+
+  ------------------------------------------------------------------------------
+  -- DATA GENERATION
+  ------------------------------------------------------------------------------
+
+  -- Generate data path input data
+  p_stimuli : PROCESS
+    VARIABLE v_data_init   : NATURAL;
+    VARIABLE v_frame_len   : NATURAL;
+    VARIABLE v_sync        : STD_LOGIC;
+  BEGIN
+    v_data_init := c_data_init;
+    v_frame_len := c_frame_len_init;
+    in_sosi <= c_dp_sosi_rst;
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 5);
+
+    -- Begin of stimuli
+    FOR R IN 0 TO g_nof_repeat-1 LOOP
+      v_sync := sel_a_b(R MOD c_sync_period = c_sync_offset, '1', '0');
+      proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_data_w, v_data_init, 0, 0, v_frame_len, 0, 0, v_sync, TO_DP_BSN(R), clk, in_en, in_siso, in_sosi);
+      --proc_common_wait_some_cycles(clk, 10);
+      v_data_init := v_data_init + v_frame_len;
+      v_frame_len := v_frame_len + 1;
+    END LOOP;
+
+    -- End of stimuli
+    expected_out_data <= TO_UVEC(v_data_init-1, c_data_w);
+
+    proc_common_wait_until_high(clk, verify_done);
+    proc_common_wait_some_cycles(clk, 10);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+  
+  -- proc_dp_gen_block_data() only supports RL=0 or 1, so use a latency adpater to support any g_in_latency
+  u_input_adapt : ENTITY dp_components_lib.dp_latency_adapter
+  GENERIC MAP (
+    g_in_latency   => c_rl,
+    g_out_latency  => g_in_latency
+  )
+  PORT MAP (
+    rst          => rst,
+    clk          => clk,
+    -- ST sink
+    snk_out      => in_siso,
+    snk_in       => in_sosi,
+    -- ST source
+    src_in       => adapt_siso,
+    src_out      => adapt_sosi 
+  );
+
+
+  ------------------------------------------------------------------------------
+  -- DATA VERIFICATION
+  ------------------------------------------------------------------------------
+
+
+  -- Verification logistics
+  verify_en <= '1'          WHEN rising_edge(clk) AND out_sosi.sop='1';          -- enable verify after first output sop
+  count_eop <= count_eop+1  WHEN rising_edge(clk) AND out_sosi.eop='1' AND((g_out_latency>0) OR
+                                                                           (g_out_latency=0 AND out_siso.ready='1'));  -- count number of output eop
+  verify_done <= '1'        WHEN rising_edge(clk) AND count_eop = g_nof_repeat;  -- signal verify done after g_nof_repeat frames
+
+  -- Actual verification of the output streams
+  proc_dp_verify_data("out_sosi.data", g_out_latency, clk, verify_en, out_siso.ready, out_sosi.valid, out_data, prev_out_data);  -- Verify that the output is incrementing data, like the input stimuli
+  proc_dp_verify_valid(g_out_latency, clk, verify_en, out_siso.ready, prev_out_ready, out_sosi.valid);                           -- Verify that the output valid fits with the output ready latency
+  proc_dp_verify_sop_and_eop(g_out_latency, clk, out_siso.ready, out_sosi.valid, out_sosi.sop, out_sosi.eop, hold_out_sop);      -- Verify that sop and eop come in pairs
+  proc_dp_verify_value(e_equal, clk, verify_done, expected_out_data, prev_out_data);                                             -- Verify that the stimuli have been applied at all
+  proc_dp_verify_sync(c_sync_period, c_sync_offset, clk, verify_en, out_sosi.sync, out_sosi.sop, out_sosi.bsn);
+
+  -- Monitoring
+  out_bsn  <= out_sosi.bsn(c_data_w-1 DOWNTO 0);
+  out_data <= out_sosi.data(c_data_w-1 DOWNTO 0);
+  out_sync <= out_sosi.sync;
+  out_val  <= out_sosi.valid;
+  out_sop  <= out_sosi.sop;
+  out_eop  <= out_sosi.eop;
+  
+  
+  ------------------------------------------------------------------------------
+  -- DUT dp_pipeline_ready
+  ------------------------------------------------------------------------------
+
+  pipeline : ENTITY work.dp_pipeline_ready
+  GENERIC MAP (
+    g_in_latency   => g_in_latency,
+    g_out_latency  => g_out_latency
+  )
+  PORT MAP (
+    rst          => rst,
+    clk          => clk,
+    -- ST sink
+    snk_out      => adapt_siso,
+    snk_in       => adapt_sosi,
+    -- ST source
+    src_in       => out_siso,
+    src_out      => out_sosi
+  );
+
+    
+END tb;
diff --git a/cores/base/dp/dp_pipeline/tb_tb_dp_pipeline.vhd b/cores/base/dp/dp_pipeline/tb_tb_dp_pipeline.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..44c25eb5b35a29785cc8858cafe22c48bad0cf0f
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/tb_tb_dp_pipeline.vhd
@@ -0,0 +1,42 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2013
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+ 
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+
+-- > as 3
+-- > run -all --> OK
+
+ENTITY tb_tb_dp_pipeline IS
+END tb_tb_dp_pipeline;
+
+
+ARCHITECTURE tb OF tb_tb_dp_pipeline IS
+  SIGNAL tb_end : STD_LOGIC := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+BEGIN
+
+  u_p0 : ENTITY work.tb_dp_pipeline GENERIC MAP (0);
+  u_p1 : ENTITY work.tb_dp_pipeline GENERIC MAP (1);
+  u_p2 : ENTITY work.tb_dp_pipeline GENERIC MAP (2);
+  u_p7 : ENTITY work.tb_dp_pipeline GENERIC MAP (7);
+
+END tb;
diff --git a/cores/base/dp/dp_pipeline/tb_tb_dp_pipeline_ready.vhd b/cores/base/dp/dp_pipeline/tb_tb_dp_pipeline_ready.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..15a68bffa37fd4c60cabf991cc33118a3df5a841
--- /dev/null
+++ b/cores/base/dp/dp_pipeline/tb_tb_dp_pipeline_ready.vhd
@@ -0,0 +1,66 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+ 
+LIBRARY IEEE, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+
+-- > as 2
+-- > run -all --> OK
+
+ENTITY tb_tb_dp_pipeline_ready IS
+END tb_tb_dp_pipeline_ready;
+
+
+ARCHITECTURE tb OF tb_tb_dp_pipeline_ready IS
+
+  CONSTANT c_nof_repeat : NATURAL := 50;
+  SIGNAL tb_end : STD_LOGIC := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+  
+BEGIN
+
+  --                                                               in_en,    src_in.ready, in_latency, out_latency, nof repeat,
+  -- Random flow control for different RL
+  u_rnd_rnd_0_0    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     0,          0,           c_nof_repeat);
+  u_rnd_rnd_1_0    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     1,          0,           c_nof_repeat);
+  u_rnd_rnd_0_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     0,          1,           c_nof_repeat);
+  u_rnd_rnd_2_0    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     2,          0,           c_nof_repeat);
+  u_rnd_rnd_0_2    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     0,          2,           c_nof_repeat);
+  u_rnd_rnd_2_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     2,          1,           c_nof_repeat);
+  u_rnd_rnd_1_2    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     1,          2,           c_nof_repeat);
+  u_rnd_rnd_2_2    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     2,          2,           c_nof_repeat);
+  
+  -- Other flow control for fixed RL
+  u_act_act_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_active, e_active,     1,          1,           c_nof_repeat);
+  u_act_rnd_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_active, e_random,     1,          1,           c_nof_repeat);
+  u_act_pls_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_active, e_pulse,      1,          1,           c_nof_repeat);
+                                                                                      
+  u_rnd_act_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_active,     1,          1,           c_nof_repeat);
+  u_rnd_rnd_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_random,     1,          1,           c_nof_repeat);
+  u_rnd_pls_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_random, e_pulse,      1,          1,           c_nof_repeat);
+                                                                                      
+  u_pls_act_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_pulse,  e_active,     1,          1,           c_nof_repeat);
+  u_pls_rnd_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_pulse,  e_random,     1,          1,           c_nof_repeat);
+  u_pls_pls_1_1    : ENTITY work.tb_dp_pipeline_ready GENERIC MAP (e_pulse,  e_pulse,      1,          1,           c_nof_repeat);
+  
+END tb;
diff --git a/cores/base/dp/dp_pkg/dp_stream_pkg.vhd b/cores/base/dp/dp_pkg/dp_stream_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..1d19e50d666f0b6ce9924ad4e52636f2d21d3fc1
--- /dev/null
+++ b/cores/base/dp/dp_pkg/dp_stream_pkg.vhd
@@ -0,0 +1,1293 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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_pkg_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+
+PACKAGE dp_stream_pkg Is
+
+  ------------------------------------------------------------------------------
+  -- General DP stream record defintion
+  ------------------------------------------------------------------------------
+  
+  -- Remarks:
+  -- * Choose smallest maximum SOSI slv lengths that fit all use cases, because unconstrained record fields slv is not allowed
+  -- * The large SOSI data field width of 256b has some disadvantages:
+  --   . about 10% extra simulation time and PC memory usage compared to 72b (measured using tb_unb_tse_board)
+  --   . a 256b number has 64 hex digits in the Wave window which is awkward because of the leading zeros when typically
+  --     only 32b are used, fortunately integer representation still works OK (except 0 which is shown as blank).
+  --   However the alternatives are not attractive, because they affect the implementation of the streaming
+  --   components that use the SOSI record. Alternatives are e.g.:
+  --   . define an extra long SOSI data field ldata[255:0] in addition to the existing data[71:0] field
+  --   . use the array of SOSI records to contain wider data, all with the same SOSI control field values
+  --   . define another similar SOSI record with data[255:0].
+  --   Therefore define data width as 256b, because the disadvantages are acceptable and the benefit is great, because all
+  --   streaming components can remain as they are.
+  -- * Added sync and bsn to SOSI to have timestamp information with the data
+  -- * Added re and im to SOSI to support complex data for DSP
+  -- * The sosi fields can be labeled in diffent groups: ctrl, info and data as shown in comment at the t_dp_sosi definition.
+  --   This grouping is useful for functions that operate on a t_dp_sosi signal.
+  -- * The info fields are valid at the sop or at the eop, but typically they hold their last active value to avoid unnessary
+  --   toggling and to ease viewing in the wave window.
+  CONSTANT c_dp_stream_bsn_w      : NATURAL :=  64;  -- 64 is sufficient to count blocks of data for years
+  CONSTANT c_dp_stream_data_w     : NATURAL := 768;  -- 72 is sufficient for max word 8 * 9-bit. 576 supports half rate DDR4 bus data width. The current 768 is enough for wide single clock SLVs (e.g. headers)
+  CONSTANT c_dp_stream_dsp_data_w : NATURAL :=  64;  -- 64 is sufficient for DSP data, including complex power accumulates
+  CONSTANT c_dp_stream_empty_w    : NATURAL :=  16;  --  8 is sufficient for max 256 symbols per data word, still use 16 bit to be able to count c_dp_stream_data_w in bits
+  CONSTANT c_dp_stream_channel_w  : NATURAL :=  32;  -- 32 is sufficient for several levels of hierarchy in mapping types of streams on to channels 
+  CONSTANT c_dp_stream_error_w    : NATURAL :=  32;  -- 32 is sufficient for several levels of hierarchy in mapping error numbers, e.g. 32 different one-hot encoded errors, bit [0] = 0 = OK
+  
+  CONSTANT c_dp_stream_ok         : NATURAL := 0;  -- SOSI err field OK value
+  CONSTANT c_dp_stream_err        : NATURAL := 1;  -- SOSI err field error value /= OK
+  
+  CONSTANT c_dp_stream_rl         : NATURAL := 1;  -- SISO default data path stream ready latency RL = 1
+  
+  TYPE t_dp_siso IS RECORD  -- Source In or Sink Out
+    ready    : STD_LOGIC;   -- fine cycle based flow control using ready latency RL >= 0
+    xon      : STD_LOGIC;   -- coarse typically block based flow control using xon/xoff
+  END RECORD;
+  
+  TYPE t_dp_sosi IS RECORD  -- Source Out or Sink In
+    sync     : STD_LOGIC;                                           -- ctrl
+    bsn      : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);      -- info at sop      (block sequence number)
+    data     : STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0);     -- data
+    re       : STD_LOGIC_VECTOR(c_dp_stream_dsp_data_w-1 DOWNTO 0); -- data
+    im       : STD_LOGIC_VECTOR(c_dp_stream_dsp_data_w-1 DOWNTO 0); -- data
+    valid    : STD_LOGIC;                                           -- ctrl
+    sop      : STD_LOGIC;                                           -- ctrl
+    eop      : STD_LOGIC;                                           -- ctrl
+    empty    : STD_LOGIC_VECTOR(c_dp_stream_empty_w-1 DOWNTO 0);    -- info at eop
+    channel  : STD_LOGIC_VECTOR(c_dp_stream_channel_w-1 DOWNTO 0);  -- info at sop
+    err      : STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0);    -- info at eop (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');
+  CONSTANT c_dp_siso_hold  : t_dp_siso := ('0', '1');
+  CONSTANT c_dp_siso_rdy   : t_dp_siso := ('1', '1');
+  CONSTANT c_dp_siso_flush : t_dp_siso := ('1', '0');
+  CONSTANT c_dp_sosi_rst   : t_dp_sosi := ('0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'));
+  CONSTANT c_dp_sosi_x     : t_dp_sosi := ('X', (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'), 'X', 'X', 'X', (OTHERS=>'X'), (OTHERS=>'X'), (OTHERS=>'X'));
+  
+  -- Use integers instead of slv for monitoring purposes (integer range limited to 31 bit plus sign bit)
+  TYPE t_dp_sosi_integer IS RECORD
+    sync     : STD_LOGIC;
+    bsn      : NATURAL;
+    data     : INTEGER;
+    re       : INTEGER;
+    im       : INTEGER;
+    valid    : STD_LOGIC;
+    sop      : STD_LOGIC;
+    eop      : STD_LOGIC;
+    empty    : NATURAL;
+    channel  : NATURAL;
+    err      : NATURAL;
+  END RECORD;
+  
+  -- Use unsigned instead of slv for monitoring purposes beyond the integer range of t_dp_sosi_integer
+  TYPE t_dp_sosi_unsigned IS RECORD
+    sync     : STD_LOGIC;
+    bsn      : UNSIGNED(c_dp_stream_bsn_w-1 DOWNTO 0);
+    data     : UNSIGNED(c_dp_stream_data_w-1 DOWNTO 0);
+    re       : UNSIGNED(c_dp_stream_dsp_data_w-1 DOWNTO 0);
+    im       : UNSIGNED(c_dp_stream_dsp_data_w-1 DOWNTO 0);
+    valid    : STD_LOGIC;
+    sop      : STD_LOGIC;
+    eop      : STD_LOGIC;
+    empty    : UNSIGNED(c_dp_stream_empty_w-1 DOWNTO 0);
+    channel  : UNSIGNED(c_dp_stream_channel_w-1 DOWNTO 0);
+    err      : UNSIGNED(c_dp_stream_error_w-1 DOWNTO 0);
+  END RECORD;
+  
+  CONSTANT c_dp_sosi_unsigned_rst  : t_dp_sosi_unsigned := ('0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), (OTHERS=>'0'));
+  CONSTANT c_dp_sosi_unsigned_ones : t_dp_sosi_unsigned := ('1',
+                                                            TO_UNSIGNED(1, c_dp_stream_bsn_w),
+                                                            TO_UNSIGNED(1, c_dp_stream_data_w),
+                                                            TO_UNSIGNED(1, c_dp_stream_dsp_data_w),
+                                                            TO_UNSIGNED(1, c_dp_stream_dsp_data_w),
+                                                            '1', '1', '1',
+                                                            TO_UNSIGNED(1, c_dp_stream_empty_w),
+                                                            TO_UNSIGNED(1, c_dp_stream_channel_w),
+                                                            TO_UNSIGNED(1, c_dp_stream_error_w));
+  
+  -- Use boolean to define whether a t_dp_siso, t_dp_sosi field is used ('1') or not ('0')
+  TYPE t_dp_siso_sl IS RECORD
+    ready    : STD_LOGIC;
+    xon      : STD_LOGIC;
+  END RECORD;
+  
+  TYPE t_dp_sosi_sl IS RECORD
+    sync     : STD_LOGIC;
+    bsn      : STD_LOGIC;
+    data     : STD_LOGIC;
+    re       : STD_LOGIC;
+    im       : STD_LOGIC;
+    valid    : STD_LOGIC;
+    sop      : STD_LOGIC;
+    eop      : STD_LOGIC;
+    empty    : STD_LOGIC;
+    channel  : STD_LOGIC;
+    err      : STD_LOGIC;
+  END RECORD;
+  
+  CONSTANT c_dp_siso_sl_rst  : t_dp_siso_sl := ('0', '0');
+  CONSTANT c_dp_siso_sl_ones : t_dp_siso_sl := ('1', '1');
+  CONSTANT c_dp_sosi_sl_rst  : t_dp_sosi_sl := ('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0');
+  CONSTANT c_dp_sosi_sl_ones : t_dp_sosi_sl := ('1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1');
+  
+  -- Multi port or multi register array for DP stream records
+  TYPE t_dp_siso_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_siso;
+  TYPE t_dp_sosi_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi;
+
+  TYPE t_dp_sosi_integer_arr  IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_integer;
+  TYPE t_dp_sosi_unsigned_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_unsigned;
+
+  TYPE t_dp_siso_sl_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_sl;
+  TYPE t_dp_sosi_sl_arr IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_sl;
+  
+  -- Multi port or multi register slv arrays for DP stream records fields
+  TYPE t_dp_bsn_slv_arr      IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
+  TYPE t_dp_data_slv_arr     IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0);
+  TYPE t_dp_dsp_data_slv_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_dsp_data_w-1 DOWNTO 0);
+  TYPE t_dp_empty_slv_arr    IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_empty_w-1 DOWNTO 0);
+  TYPE t_dp_channel_slv_arr  IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_channel_w-1 DOWNTO 0);
+  TYPE t_dp_error_slv_arr    IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_stream_error_w-1 DOWNTO 0);
+  
+  -- Multi-dimemsion array types with fixed LS-dimension
+  TYPE t_dp_siso_2arr_1 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(0 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_1 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(0 DOWNTO 0);
+
+  -- . 2 dimensional array with 2 fixed LS sosi/siso interfaces (dp_split, dp_concat)
+  TYPE t_dp_siso_2arr_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(1 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(1 DOWNTO 0);
+
+  TYPE t_dp_siso_2arr_3 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(2 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_3 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(2 DOWNTO 0);
+
+  TYPE t_dp_siso_2arr_4 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(3 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_4 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(3 DOWNTO 0);
+
+  TYPE t_dp_siso_2arr_8 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(7 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_8 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(7 DOWNTO 0);
+
+  TYPE t_dp_siso_2arr_9 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(8 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_9 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(8 DOWNTO 0);
+
+  TYPE t_dp_siso_2arr_12 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_arr(11 DOWNTO 0);
+  TYPE t_dp_sosi_2arr_12 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_arr(11 DOWNTO 0);
+ 
+  TYPE t_dp_siso_3arr_4_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_siso_2arr_2(3 DOWNTO 0);
+  TYPE t_dp_sosi_3arr_4_2 IS ARRAY (INTEGER RANGE <>) OF t_dp_sosi_2arr_2(3 DOWNTO 0);
+ 
+  -- 2-dimensional streaming array type:
+  -- Note:
+  --   This t_*_mat is less useful then a t_*_2arr array of arrays, because assignments can only be done per element (i.e. not per row). However for t_*_2arr
+  --   the arrays dimension must be fixed, so these t_*_2arr types are application dependent and need to be defined where used. 
+  TYPE t_dp_siso_mat IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF t_dp_siso;
+  TYPE t_dp_sosi_mat IS ARRAY (INTEGER RANGE <>, INTEGER RANGE <>) OF t_dp_sosi;
+
+  -- Check sosi.valid against siso.ready
+  PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN    NATURAL;
+                               SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi            : IN    t_dp_sosi;
+                               SIGNAL   siso            : IN    t_dp_siso;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR);
+
+  -- Default RL=1
+  PROCEDURE proc_dp_siso_alert(SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi            : IN    t_dp_sosi;
+                               SIGNAL   siso            : IN    t_dp_siso;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR);
+
+  -- SOSI/SISO array version
+  PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN    NATURAL;
+                               SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi_arr        : IN    t_dp_sosi_arr;
+                               SIGNAL   siso_arr        : IN    t_dp_siso_arr;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR);
+
+  -- SOSI/SISO array version with RL=1
+  PROCEDURE proc_dp_siso_alert(SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi_arr        : IN    t_dp_sosi_arr;
+                               SIGNAL   siso_arr        : IN    t_dp_siso_arr;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR);
+
+  -- Resize functions to fit an integer or an SLV in the corresponding t_dp_sosi field width
+  -- . Use these functions to assign sosi data TO a record field
+  -- . Use the range selection [n-1 DOWNTO 0] to assign sosi data FROM a record field to an slv
+  -- . The unused sosi data field bits could remain undefined 'X', because the unused bits in the fields are not used at all. 
+  --   Typically the sosi data are treated as unsigned in the record field, so extended with '0'. However for interpretating
+  --   signed data in the simulation wave window it is easier to use sign extension in the record field. Therefore TO_DP_SDATA
+  --   and RESIZE_DP_SDATA are defined as well.
+  FUNCTION TO_DP_BSN(     n : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION TO_DP_DATA(    n : INTEGER) RETURN STD_LOGIC_VECTOR;  -- use integer to support 32 bit range, so -1 = 0xFFFFFFFF = +2**32-1
+  FUNCTION TO_DP_SDATA(   n : INTEGER) RETURN STD_LOGIC_VECTOR;  -- use integer to support 32 bit range and signed
+  FUNCTION TO_DP_UDATA(   n : INTEGER) RETURN STD_LOGIC_VECTOR;  -- alias of TO_DP_DATA()
+  FUNCTION TO_DP_DSP_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR;  -- for re and im fields, signed data
+  FUNCTION TO_DP_DSP_UDATA(n: INTEGER) RETURN STD_LOGIC_VECTOR;  -- for re and im fields, unsigned data (useful to carry indices)
+  FUNCTION TO_DP_EMPTY(   n : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION TO_DP_CHANNEL( n : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION TO_DP_ERROR(   n : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION RESIZE_DP_BSN(     vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION RESIZE_DP_DATA(    vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- set unused MSBits to '0'
+  FUNCTION RESIZE_DP_SDATA(   vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- sign extend unused MSBits
+  FUNCTION RESIZE_DP_XDATA(   vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- set unused MSBits to 'X'
+  FUNCTION RESIZE_DP_DSP_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;  -- sign extend unused MSBits of re and im fields
+  FUNCTION RESIZE_DP_EMPTY(   vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION RESIZE_DP_CHANNEL( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  FUNCTION RESIZE_DP_ERROR(   vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  
+  FUNCTION INCR_DP_DATA(    vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- unsigned vec(w-1:0) + dec
+  FUNCTION INCR_DP_SDATA(   vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR;  --   signed vec(w-1:0) + dec
+  FUNCTION INCR_DP_DSP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR;  --   signed vec(w-1:0) + dec
+  
+  FUNCTION REPLICATE_DP_DATA(  seq  : STD_LOGIC_VECTOR                 ) RETURN STD_LOGIC_VECTOR;  -- replicate seq as often as fits in c_dp_stream_data_w
+  FUNCTION UNREPLICATE_DP_DATA(data : STD_LOGIC_VECTOR; seq_w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- unreplicate data to width seq_w, return low seq_w bits and set mismatch MSbits bits to '1'
+
+  FUNCTION TO_DP_SOSI_UNSIGNED(sync, valid, sop, eop : STD_LOGIC; bsn, data, re, im, empty, channel, err : UNSIGNED) RETURN t_dp_sosi_unsigned;
+
+  -- Keep part of head data and combine part of tail data, use the other sosi from head_sosi
+  FUNCTION func_dp_data_shift_first(head_sosi, tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail              : NATURAL) RETURN t_dp_sosi;
+  -- Shift and combine part of previous data and this data, use the other sosi from prev_sosi
+  FUNCTION func_dp_data_shift(      prev_sosi, this_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_this              : NATURAL) RETURN t_dp_sosi;
+  -- Shift part of tail data and account for input empty
+  FUNCTION func_dp_data_shift_last(            tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail, input_empty : NATURAL) RETURN t_dp_sosi;
+    
+  -- Determine resulting empty if two streams are concatenated or split
+  FUNCTION func_dp_empty_concat(head_empty, tail_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_dp_empty_split(input_empty, head_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR;
+  
+  -- Multiplex the t_dp_sosi_arr based on the valid, assuming that at most one input is active valid.
+  FUNCTION func_dp_sosi_arr_mux(dp : t_dp_sosi_arr) RETURN t_dp_sosi;
+  
+  -- Determine the combined logical value of corresponding STD_LOGIC fields in t_dp_*_arr (for all elements or only for the mask[]='1' elements)
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr;                          str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr;                          str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_or( dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_or( dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_or( dp : t_dp_siso_arr;                          str : STRING) RETURN STD_LOGIC;
+  FUNCTION func_dp_stream_arr_or( dp : t_dp_sosi_arr;                          str : STRING) RETURN STD_LOGIC;
+  
+  -- Functions to set or get a STD_LOGIC field as a STD_LOGIC_VECTOR to or from an siso or an sosi array
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_siso_arr;
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; sl  : STD_LOGIC;        str : STRING) RETURN t_dp_siso_arr;
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; sl  : STD_LOGIC;        str : STRING) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_get(dp : t_dp_siso_arr;                         str : STRING) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_dp_stream_arr_get(dp : t_dp_sosi_arr;                         str : STRING) RETURN STD_LOGIC_VECTOR;
+  
+  -- Functions to select elements from two siso or two sosi arrays (sel[] = '1' selects a, sel[] = '0' selects b)
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a,                 b : t_dp_siso)     RETURN t_dp_siso_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a,                 b : t_dp_sosi)     RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso_arr; b : t_dp_siso)     RETURN t_dp_siso_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi_arr; b : t_dp_sosi)     RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso;     b : t_dp_siso_arr) RETURN t_dp_siso_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi;     b : t_dp_sosi_arr) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a,                 b : t_dp_siso_arr) RETURN t_dp_siso_arr;
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a,                 b : t_dp_sosi_arr) RETURN t_dp_sosi_arr;
+
+  -- Fix reversed buses due to connecting TO to DOWNTO range arrays. 
+  FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_sosi_arr) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_siso_arr) RETURN t_dp_siso_arr;
+
+  -- Functions to combinatorially hold the data fields and to set or reset the control fields in an sosi array
+  FUNCTION func_dp_stream_arr_combine_data_info_ctrl(dp : t_dp_sosi_arr; info, ctrl : t_dp_sosi) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_set_info(              dp : t_dp_sosi_arr; info       : t_dp_sosi) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_set_control(           dp : t_dp_sosi_arr;       ctrl : t_dp_sosi) RETURN t_dp_sosi_arr;
+  FUNCTION func_dp_stream_arr_reset_control(         dp : t_dp_sosi_arr                        ) RETURN t_dp_sosi_arr;
+  
+  -- Reset sosi ctrl and preserve the sosi data (to avoid unnecessary data toggling and to ease data view in Wave window)
+  FUNCTION func_dp_stream_reset_control(dp : t_dp_sosi) RETURN t_dp_sosi;
+  
+  -- Functions to combinatorially determine the maximum and minimum sosi bsn[w-1:0] value in the sosi array (for all elements or only for the mask[]='1' elements)
+  FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr;                          w : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR;
+  FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr;                          w : NATURAL) RETURN STD_LOGIC_VECTOR;
+  
+  -- Function to copy the BSN of one valid stream to all output streams. 
+  FUNCTION func_dp_stream_arr_copy_valid_bsn(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr;
+  
+  -- Functions to combinatorially handle channels
+  -- Note that the *_select and *_remove function are equivalent to dp_demux with g_combined=TRUE
+  FUNCTION func_dp_stream_channel_set   (st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi;  -- select channel nr, add the channel field
+  FUNCTION func_dp_stream_channel_select(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi;  -- select channel nr, skip the channel field
+  FUNCTION func_dp_stream_channel_remove(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi;  -- skip channel nr
+  
+  -- Functions to combinatorially handle the error field
+  FUNCTION func_dp_stream_error_set(st_sosi : t_dp_sosi; n : NATURAL) RETURN t_dp_sosi;  -- force err = 0, is OK
+  
+  -- Functions to combinatorially handle the BSN field
+  FUNCTION func_dp_stream_bsn_set(st_sosi : t_dp_sosi; bsn : STD_LOGIC_VECTOR) RETURN t_dp_sosi;
+  
+  -- Functions to combine sosi fields
+  FUNCTION func_dp_stream_combine_info_and_data(info, data : t_dp_sosi) RETURN t_dp_sosi;
+  
+  -- Functions to convert sosi fields
+  FUNCTION func_dp_stream_slv_to_integer(slv_sosi : t_dp_sosi; w : NATURAL) RETURN t_dp_sosi_integer;
+
+  -- Functions to set the DATA, RE and IM field in a stream.
+  FUNCTION func_dp_stream_set_data(dp : t_dp_sosi;     slv : STD_LOGIC_VECTOR; str : STRING                         ) RETURN t_dp_sosi;
+  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;
+
+
+PACKAGE BODY dp_stream_pkg IS
+ 
+  -- Check sosi.valid against siso.ready
+  PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN    NATURAL;
+                               SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi            : IN    t_dp_sosi;
+                               SIGNAL   siso            : IN    t_dp_siso;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    ready_reg(0) <= siso.ready;
+    -- Register siso.ready in c_ready_latency registers
+    IF rising_edge(clk) THEN
+      -- Check DP sink
+      IF sosi.valid = '1' AND ready_reg(c_ready_latency) = '0' THEN
+        REPORT "RL ERROR" SEVERITY FAILURE;
+      END IF;
+      ready_reg( 1 TO c_ready_latency) <= ready_reg( 0 TO c_ready_latency-1);
+    END IF;
+  END proc_dp_siso_alert;
+
+  -- Default RL=1
+  PROCEDURE proc_dp_siso_alert(SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi            : IN    t_dp_sosi;
+                               SIGNAL   siso            : IN    t_dp_siso;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    proc_dp_siso_alert(1, clk, sosi, siso, ready_reg);
+  END proc_dp_siso_alert;
+
+  -- SOSI/SISO array version
+  PROCEDURE proc_dp_siso_alert(CONSTANT c_ready_latency : IN    NATURAL;
+                               SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi_arr        : IN    t_dp_sosi_arr;
+                               SIGNAL   siso_arr        : IN    t_dp_siso_arr;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    FOR i IN 0 TO sosi_arr'LENGTH-1 LOOP 
+      ready_reg(i*(c_ready_latency+1)) <= siso_arr(i).ready; -- SLV is used as an array: nof_streams*(0..c_ready_latency)
+    END LOOP;
+    -- Register siso.ready in c_ready_latency registers
+    IF rising_edge(clk) THEN
+      FOR i IN 0 TO sosi_arr'LENGTH-1 LOOP
+        -- Check DP sink
+        IF sosi_arr(i).valid = '1' AND ready_reg(i*(c_ready_latency+1)+1) = '0' THEN
+          REPORT "RL ERROR" SEVERITY FAILURE;
+        END IF; 
+        ready_reg(i*(c_ready_latency+1)+1 TO i*(c_ready_latency+1)+c_ready_latency) <=  ready_reg(i*(c_ready_latency+1) TO i*(c_ready_latency+1)+c_ready_latency-1);
+      END LOOP;
+    END IF;  
+  END proc_dp_siso_alert;
+
+  -- SOSI/SISO array version with RL=1
+  PROCEDURE proc_dp_siso_alert(SIGNAL   clk             : IN    STD_LOGIC;
+                               SIGNAL   sosi_arr        : IN    t_dp_sosi_arr;
+                               SIGNAL   siso_arr        : IN    t_dp_siso_arr;
+                               SIGNAL   ready_reg       : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    proc_dp_siso_alert(1, clk, sosi_arr, siso_arr, ready_reg);
+  END proc_dp_siso_alert;
+ 
+  -- Resize functions to fit an integer or an SLV in the corresponding t_dp_sosi field width
+  FUNCTION TO_DP_BSN(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_dp_stream_bsn_w);
+  END TO_DP_BSN;
+  
+  FUNCTION TO_DP_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_dp_stream_data_w);
+  END TO_DP_DATA;
+  
+  FUNCTION TO_DP_SDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_SVEC(TO_SVEC(n, 32), c_dp_stream_data_w);
+  END TO_DP_SDATA;
+  
+  FUNCTION TO_DP_UDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN TO_DP_DATA(n);
+  END TO_DP_UDATA;
+  
+  FUNCTION TO_DP_DSP_DATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_SVEC(TO_SVEC(n, 32), c_dp_stream_dsp_data_w);
+  END TO_DP_DSP_DATA;
+  
+  FUNCTION TO_DP_DSP_UDATA(n : INTEGER) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(TO_SVEC(n, 32), c_dp_stream_dsp_data_w);
+  END TO_DP_DSP_UDATA;
+  
+  FUNCTION TO_DP_EMPTY(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN TO_UVEC(n, c_dp_stream_empty_w);
+  END TO_DP_EMPTY;
+  
+  FUNCTION TO_DP_CHANNEL(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN TO_UVEC(n, c_dp_stream_channel_w);
+  END TO_DP_CHANNEL;
+  
+  FUNCTION TO_DP_ERROR(n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN TO_UVEC(n, c_dp_stream_error_w);
+  END TO_DP_ERROR;
+  
+  FUNCTION RESIZE_DP_BSN(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(vec, c_dp_stream_bsn_w);
+  END RESIZE_DP_BSN;
+  
+  FUNCTION RESIZE_DP_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(vec, c_dp_stream_data_w);
+  END RESIZE_DP_DATA;
+  
+  FUNCTION RESIZE_DP_SDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_SVEC(vec, c_dp_stream_data_w);
+  END RESIZE_DP_SDATA;
+  
+  FUNCTION RESIZE_DP_XDATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_vec : STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0) := (OTHERS=>'X');
+  BEGIN
+    v_vec(vec'LENGTH-1 DOWNTO 0) := vec;
+    RETURN v_vec;
+  END RESIZE_DP_XDATA;
+  
+  FUNCTION RESIZE_DP_DSP_DATA(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_SVEC(vec, c_dp_stream_dsp_data_w);
+  END RESIZE_DP_DSP_DATA;
+  
+  FUNCTION RESIZE_DP_EMPTY(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(vec, c_dp_stream_empty_w);
+  END RESIZE_DP_EMPTY;
+  
+  FUNCTION RESIZE_DP_CHANNEL(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(vec, c_dp_stream_channel_w);
+  END RESIZE_DP_CHANNEL;
+  
+  FUNCTION RESIZE_DP_ERROR(vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_UVEC(vec, c_dp_stream_error_w);
+  END RESIZE_DP_ERROR;
+  
+  FUNCTION INCR_DP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_DP_DATA(STD_LOGIC_VECTOR(UNSIGNED(vec(w-1 DOWNTO 0)) + dec));
+  END INCR_DP_DATA;
+  
+  FUNCTION INCR_DP_SDATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_DP_SDATA(STD_LOGIC_VECTOR(SIGNED(vec(w-1 DOWNTO 0)) + dec));
+  END INCR_DP_SDATA;
+
+  FUNCTION INCR_DP_DSP_DATA(vec : STD_LOGIC_VECTOR; dec : INTEGER; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  BEGIN
+    RETURN RESIZE_DP_DSP_DATA(STD_LOGIC_VECTOR(SIGNED(vec(w-1 DOWNTO 0)) + dec));
+  END INCR_DP_DSP_DATA;  
+  
+  FUNCTION REPLICATE_DP_DATA(seq : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_seq_w            : NATURAL := seq'LENGTH;
+    CONSTANT c_nof_replications : NATURAL := ceil_div(c_dp_stream_data_w, c_seq_w);
+    CONSTANT c_vec_w            : NATURAL := ceil_value(c_dp_stream_data_w, c_seq_w);
+    VARIABLE v_vec              : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0);
+  BEGIN
+    FOR I IN 0 TO c_nof_replications-1 LOOP
+      v_vec((I+1)*c_seq_w-1 DOWNTO I*c_seq_w) := seq;
+    END LOOP;
+    RETURN v_vec(c_dp_stream_data_w-1 DOWNTO 0);
+  END REPLICATE_DP_DATA;
+  
+  FUNCTION UNREPLICATE_DP_DATA(data : STD_LOGIC_VECTOR; seq_w :NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_data_w           : NATURAL := data'LENGTH;
+    CONSTANT c_nof_replications : NATURAL := ceil_div(c_data_w, seq_w);
+    CONSTANT c_vec_w            : NATURAL := ceil_value(c_data_w, seq_w);
+    VARIABLE v_seq              : STD_LOGIC_VECTOR(seq_w-1 DOWNTO 0);
+    VARIABLE v_data             : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0);
+    VARIABLE v_vec              : STD_LOGIC_VECTOR(c_vec_w-1 DOWNTO 0);
+  BEGIN
+    v_data := RESIZE_UVEC(data, c_vec_w);
+    v_seq := v_data(seq_w-1 DOWNTO 0);                                                          -- low data part is the v_seq
+    v_vec(seq_w-1 DOWNTO 0) := v_seq;                                                           -- keep v_seq at low part of return value
+    IF c_nof_replications>1 THEN
+      FOR I IN 1 TO c_nof_replications-1 LOOP
+        v_vec((I+1)*seq_w-1 DOWNTO I*seq_w) := v_data((I+1)*seq_w-1 DOWNTO I*seq_w) XOR v_seq;  -- set return bit to '1' for high part data bits that do not match low part v_seq
+      END LOOP;
+    END IF;
+    RETURN v_vec(c_data_w-1 DOWNTO 0);
+  END UNREPLICATE_DP_DATA;
+  
+  FUNCTION TO_DP_SOSI_UNSIGNED(sync, valid, sop, eop : STD_LOGIC; bsn, data, re, im, empty, channel, err : UNSIGNED) RETURN t_dp_sosi_unsigned IS
+    VARIABLE v_sosi_unsigned : t_dp_sosi_unsigned;
+  BEGIN
+    v_sosi_unsigned.sync    := sync;
+    v_sosi_unsigned.valid   := valid;
+    v_sosi_unsigned.sop     := sop;
+    v_sosi_unsigned.eop     := eop;
+    v_sosi_unsigned.bsn     := RESIZE(bsn,     c_dp_stream_bsn_w);
+    v_sosi_unsigned.data    := RESIZE(data,    c_dp_stream_data_w);
+    v_sosi_unsigned.re      := RESIZE(re,      c_dp_stream_dsp_data_w);
+    v_sosi_unsigned.im      := RESIZE(im,      c_dp_stream_dsp_data_w);
+    v_sosi_unsigned.empty   := RESIZE(empty,   c_dp_stream_empty_w);
+    v_sosi_unsigned.channel := RESIZE(channel, c_dp_stream_channel_w);
+    v_sosi_unsigned.err     := RESIZE(err,     c_dp_stream_error_w);
+    RETURN v_sosi_unsigned;
+  END TO_DP_SOSI_UNSIGNED;
+
+  -- Keep part of head data and combine part of tail data
+  FUNCTION func_dp_data_shift_first(head_sosi, tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE vN     : NATURAL := nof_symbols_per_data;
+    VARIABLE v_sosi : t_dp_sosi;
+  BEGIN
+    ASSERT nof_symbols_from_tail<vN REPORT "func_dp_data_shift_first : no symbols from head" SEVERITY FAILURE;
+    -- use the other sosi from head_sosi
+    v_sosi := head_sosi;     -- I = nof_symbols_from_tail = 0
+    FOR I IN 1 TO vN-1 LOOP  -- I > 0
+      IF nof_symbols_from_tail = I THEN
+        v_sosi.data(I*symbol_w-1 DOWNTO 0) := tail_sosi.data(vN*symbol_w-1 DOWNTO (vN-I)*symbol_w);
+      END IF;
+    END LOOP;
+    RETURN v_sosi;
+  END func_dp_data_shift_first;
+  
+  
+  -- Shift and combine part of previous data and this data,
+  FUNCTION func_dp_data_shift(prev_sosi, this_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_this : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE vK     : NATURAL := nof_symbols_from_this;
+    VARIABLE vN     : NATURAL := nof_symbols_per_data;
+    VARIABLE v_sosi : t_dp_sosi;
+  BEGIN
+    -- use the other sosi from this_sosi if nof_symbols_from_this > 0 else use other sosi from prev_sosi
+    IF vK>0 THEN
+      v_sosi := this_sosi;
+    ELSE
+      v_sosi := prev_sosi;
+    END IF;
+    
+    -- use sosi data from both if 0 < nof_symbols_from_this < nof_symbols_per_data (i.e. 0 < I < vN)
+    IF vK<nof_symbols_per_data THEN   -- I = vK = nof_symbols_from_this < vN
+      -- Implementation using variable vK directly instead of via I in a LOOP
+      -- IF vK > 0 THEN
+      --   v_sosi.data(vN*symbol_w-1 DOWNTO vK*symbol_w)            := prev_sosi.data((vN-vK)*symbol_w-1 DOWNTO                0);
+      --   v_sosi.data(                     vK*symbol_w-1 DOWNTO 0) := this_sosi.data( vN    *symbol_w-1 DOWNTO (vN-vK)*symbol_w);
+      -- END IF;
+      -- Implementaion using LOOP vK rather than VARIABLE vK directly as index to help synthesis and avoid potential multiplier
+      v_sosi.data := prev_sosi.data;  -- I = vK = nof_symbols_from_this = 0
+      FOR I IN 1 TO vN-1 LOOP         -- I = vK = nof_symbols_from_this > 0
+        IF vK = I THEN
+          v_sosi.data(vN*symbol_w-1 DOWNTO I*symbol_w)            := prev_sosi.data((vN-I)*symbol_w-1 DOWNTO               0);
+          v_sosi.data(                     I*symbol_w-1 DOWNTO 0) := this_sosi.data( vN   *symbol_w-1 DOWNTO (vN-I)*symbol_w);
+        END IF;
+      END LOOP;
+    END IF;
+    RETURN v_sosi;
+  END func_dp_data_shift;
+  
+  
+  -- Shift part of tail data and account for input empty
+  FUNCTION func_dp_data_shift_last(tail_sosi : t_dp_sosi; symbol_w, nof_symbols_per_data, nof_symbols_from_tail, input_empty : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE vK     : NATURAL := nof_symbols_from_tail;
+    VARIABLE vL     : NATURAL := input_empty;
+    VARIABLE vN     : NATURAL := nof_symbols_per_data;
+    VARIABLE v_sosi : t_dp_sosi;
+  BEGIN
+    ASSERT vK   > 0  REPORT "func_dp_data_shift_last : no symbols from tail" SEVERITY FAILURE;
+    ASSERT vK+vL<=vN REPORT "func_dp_data_shift_last : impossible shift" SEVERITY FAILURE;
+    v_sosi := tail_sosi;
+    -- Implementation using variable vK directly instead of via I in a LOOP
+    -- IF vK > 0 THEN
+    --   v_sosi.data(vN*symbol_w-1 DOWNTO (vN-vK)*symbol_w) <= tail_sosi.data((vK+vL)*symbol_w-1 DOWNTO vL*symbol_w);
+    -- END IF;  
+    -- Implementation using LOOP vK rather than VARIABLE vK directly as index to help synthesis and avoid potential multiplier
+    -- Implementation using LOOP vL rather than VARIABLE vL directly as index to help synthesis and avoid potential multiplier
+    FOR I IN 1 TO vN-1 LOOP
+      IF vK = I THEN
+        FOR J IN 0 TO vN-1 LOOP
+          IF vL = J THEN
+            v_sosi.data(vN*symbol_w-1 DOWNTO (vN-I)*symbol_w) := tail_sosi.data((I+J)*symbol_w-1 DOWNTO J*symbol_w);
+          END IF;
+        END LOOP;
+      END IF;
+    END LOOP;
+    RETURN v_sosi;
+  END func_dp_data_shift_last;  
+
+  
+  -- Determine resulting empty if two streams are concatenated
+  -- . both empty must use the same nof symbols per data
+  FUNCTION func_dp_empty_concat(head_empty, tail_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_a, v_b, v_empty : NATURAL;
+  BEGIN
+    v_a := TO_UINT(head_empty);
+    v_b := TO_UINT(tail_empty);
+    v_empty := v_a + v_b;
+    IF v_empty >= nof_symbols_per_data THEN
+      v_empty := v_empty - nof_symbols_per_data;
+    END IF;
+    RETURN TO_UVEC(v_empty, head_empty'LENGTH);
+  END func_dp_empty_concat;
+  
+  FUNCTION func_dp_empty_split(input_empty, head_empty : STD_LOGIC_VECTOR; nof_symbols_per_data : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_a, v_b, v_empty : NATURAL;
+  BEGIN
+    v_a   := TO_UINT(input_empty);
+    v_b   := TO_UINT(head_empty);
+    IF v_a >= v_b THEN
+      v_empty := v_a - v_b;
+    ELSE
+      v_empty := (nof_symbols_per_data + v_a) - v_b;
+    END IF;
+    RETURN TO_UVEC(v_empty, head_empty'LENGTH);
+  END func_dp_empty_split;
+  
+  
+  -- Multiplex the t_dp_sosi_arr based on the valid, assuming that at most one input is active valid.
+  FUNCTION func_dp_sosi_arr_mux(dp : t_dp_sosi_arr) RETURN t_dp_sosi IS
+    VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst;
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF dp(I).valid='1' THEN
+        v_sosi := dp(I);
+        EXIT;
+      END IF;
+    END LOOP;
+    RETURN v_sosi;
+  END func_dp_sosi_arr_mux;
+
+  
+  -- Determine the combined logical value of corresponding STD_LOGIC fields in t_dp_*_arr (for all elements or only for the mask[]='1' elements)
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
+    VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');  -- set default v_vec such that unmasked input have no influence on operation result
+    VARIABLE v_any : STD_LOGIC := '0';
+  BEGIN
+    -- map siso field to v_vec
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        v_any := '1';
+        IF    str="READY" THEN v_vec(I) := dp(I).ready;
+        ELSIF str="XON"   THEN v_vec(I) := dp(I).xon;
+        ELSE  REPORT "Error in func_dp_stream_arr_and for t_dp_siso_arr";
+        END IF;
+      END IF;
+    END LOOP;
+    -- do operation on the selected record field
+    IF v_any='1' THEN
+      RETURN vector_and(v_vec);   -- return AND of the masked input fields
+    ELSE
+      RETURN '0';                 -- return '0' if no input was masked
+    END IF;
+  END func_dp_stream_arr_and;
+  
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
+    VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');  -- set default v_vec such that unmasked input have no influence on operation result
+    VARIABLE v_any : STD_LOGIC := '0';
+  BEGIN
+    -- map siso field to v_vec
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        v_any := '1';
+        IF    str="VALID" THEN v_vec(I) := dp(I).valid;
+        ELSIF str="SOP"   THEN v_vec(I) := dp(I).sop;
+        ELSIF str="EOP"   THEN v_vec(I) := dp(I).eop;
+        ELSIF str="SYNC"  THEN v_vec(I) := dp(I).sync;
+        ELSE  REPORT "Error in func_dp_stream_arr_and for t_dp_sosi_arr";
+        END IF;
+      END IF;
+    END LOOP;
+    -- do operation on the selected record field
+    IF v_any='1' THEN
+      RETURN vector_and(v_vec);   -- return AND of the masked input fields
+    ELSE
+      RETURN '0';                 -- return '0' if no input was masked
+    END IF;
+  END func_dp_stream_arr_and;
+  
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC IS
+    CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
+  BEGIN
+    RETURN func_dp_stream_arr_and(dp, c_mask, str);
+  END func_dp_stream_arr_and;
+  
+  FUNCTION func_dp_stream_arr_and(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC IS
+    CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
+  BEGIN
+    RETURN func_dp_stream_arr_and(dp, c_mask, str);
+  END func_dp_stream_arr_and;
+  
+  FUNCTION func_dp_stream_arr_or(dp : t_dp_siso_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
+    VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'0');  -- set default v_vec such that unmasked input have no influence on operation result
+    VARIABLE v_any : STD_LOGIC := '0';
+  BEGIN
+    -- map siso field to v_vec
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        v_any := '1';
+        IF    str="READY" THEN v_vec(I) := dp(I).ready;
+        ELSIF str="XON"   THEN v_vec(I) := dp(I).xon;
+        ELSE  REPORT "Error in func_dp_stream_arr_or for t_dp_siso_arr";
+        END IF;
+      END IF;
+    END LOOP;
+    -- do operation on the selected record field
+    IF v_any='1' THEN
+      RETURN vector_or(v_vec);   -- return OR of the masked input fields
+    ELSE
+      RETURN '0';                -- return '0' if no input was masked
+    END IF;
+  END func_dp_stream_arr_or;
+  
+  FUNCTION func_dp_stream_arr_or(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; str : STRING) RETURN STD_LOGIC IS
+    VARIABLE v_vec : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'0');  -- set default v_vec such that unmasked input have no influence on operation result
+    VARIABLE v_any : STD_LOGIC := '0';
+  BEGIN
+    -- map siso field to v_vec
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        v_any := '1';
+        IF    str="VALID" THEN v_vec(I) := dp(I).valid;
+        ELSIF str="SOP"   THEN v_vec(I) := dp(I).sop;
+        ELSIF str="EOP"   THEN v_vec(I) := dp(I).eop;
+        ELSIF str="SYNC"  THEN v_vec(I) := dp(I).sync;
+        ELSE  REPORT "Error in func_dp_stream_arr_or for t_dp_sosi_arr";
+        END IF;
+      END IF;
+    END LOOP;
+    -- do operation on the selected record field
+    IF v_any='1' THEN
+      RETURN vector_or(v_vec);   -- return OR of the masked input fields
+    ELSE
+      RETURN '0';                -- return '0' if no input was masked
+    END IF;
+  END func_dp_stream_arr_or;
+  
+  FUNCTION func_dp_stream_arr_or(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC IS
+    CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
+  BEGIN
+    RETURN func_dp_stream_arr_or(dp, c_mask, str);
+  END func_dp_stream_arr_or;
+  
+  FUNCTION func_dp_stream_arr_or(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC IS
+    CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
+  BEGIN
+    RETURN func_dp_stream_arr_or(dp, c_mask, str);
+  END func_dp_stream_arr_or;
+  
+  
+  -- Functions to set or get a STD_LOGIC field as a STD_LOGIC_VECTOR to or from an siso or an sosi array
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_siso_arr IS
+    VARIABLE v_dp  : t_dp_siso_arr(dp'RANGE)    := dp;   -- default
+    VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := slv;  -- map to ensure same range as for dp
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF    str="READY" THEN v_dp(I).ready := v_slv(I);
+      ELSIF str="XON"   THEN v_dp(I).xon   := v_slv(I);
+      ELSE  REPORT "Error in func_dp_stream_arr_set for t_dp_siso_arr";
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_set;
+  
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp  : t_dp_sosi_arr(dp'RANGE)    := dp;   -- default
+    VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := slv;  -- map to ensure same range as for dp
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF    str="VALID" THEN v_dp(I).valid := v_slv(I);
+      ELSIF str="SOP"   THEN v_dp(I).sop   := v_slv(I);
+      ELSIF str="EOP"   THEN v_dp(I).eop   := v_slv(I);
+      ELSIF str="SYNC"  THEN v_dp(I).sync  := v_slv(I);
+      ELSE  REPORT "Error in func_dp_stream_arr_set for t_dp_sosi_arr";
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_set;
+  
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_siso_arr; sl : STD_LOGIC; str : STRING) RETURN t_dp_siso_arr IS
+    VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>sl);
+  BEGIN
+    RETURN func_dp_stream_arr_set(dp, v_slv, str);
+  END func_dp_stream_arr_set;
+  
+  FUNCTION func_dp_stream_arr_set(dp : t_dp_sosi_arr; sl : STD_LOGIC; str : STRING) RETURN t_dp_sosi_arr IS
+    VARIABLE v_slv : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>sl);
+  BEGIN
+    RETURN func_dp_stream_arr_set(dp, v_slv, str);
+  END func_dp_stream_arr_set;
+  
+  FUNCTION func_dp_stream_arr_get(dp : t_dp_siso_arr; str : STRING) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_ctrl : STD_LOGIC_VECTOR(dp'RANGE);
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF    str="READY" THEN v_ctrl(I) := dp(I).ready;
+      ELSIF str="XON"   THEN v_ctrl(I) := dp(I).xon;
+      ELSE  REPORT "Error in func_dp_stream_arr_get for t_dp_siso_arr";
+      END IF;
+    END LOOP;
+    RETURN v_ctrl;
+  END func_dp_stream_arr_get;
+  
+  FUNCTION func_dp_stream_arr_get(dp : t_dp_sosi_arr; str : STRING) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_ctrl : STD_LOGIC_VECTOR(dp'RANGE);
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF    str="VALID" THEN v_ctrl(I) := dp(I).valid;
+      ELSIF str="SOP"   THEN v_ctrl(I) := dp(I).sop;
+      ELSIF str="EOP"   THEN v_ctrl(I) := dp(I).eop;
+      ELSIF str="SYNC"  THEN v_ctrl(I) := dp(I).sync;
+      ELSE  REPORT "Error in func_dp_stream_arr_get for t_dp_sosi_arr";
+      END IF;
+    END LOOP;
+    RETURN v_ctrl;
+  END func_dp_stream_arr_get;
+  
+  
+  -- Functions to select elements from two siso or two sosi arrays (sel[] = '1' selects a, sel[] = '0' selects b)
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_siso) RETURN t_dp_siso_arr IS
+    VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a;
+      ELSE
+        v_dp(I) := b;
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso_arr; b : t_dp_siso) RETURN t_dp_siso_arr IS
+    VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a(I);
+      ELSE
+        v_dp(I) := b;
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_siso; b : t_dp_siso_arr) RETURN t_dp_siso_arr IS
+    VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a;
+      ELSE
+        v_dp(I) := b(I);
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_siso_arr) RETURN t_dp_siso_arr IS
+    VARIABLE v_dp : t_dp_siso_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a(I);
+      ELSE
+        v_dp(I) := b(I);
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_sosi) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a;
+      ELSE
+        v_dp(I) := b;
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi_arr; b : t_dp_sosi) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a(I);
+      ELSE
+        v_dp(I) := b;
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a : t_dp_sosi; b : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a;
+      ELSE
+        v_dp(I) := b(I);
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+  
+  FUNCTION func_dp_stream_arr_select(sel : STD_LOGIC_VECTOR; a, b : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(sel'RANGE);
+  BEGIN
+    FOR I IN sel'RANGE LOOP
+      IF sel(I)='1' THEN
+        v_dp(I) := a(I);
+      ELSE
+        v_dp(I) := b(I);
+      END IF;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_select;
+
+  FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_siso_arr) RETURN t_dp_siso_arr IS
+    VARIABLE v_to_range : t_dp_siso_arr(0 TO in_arr'HIGH);
+    VARIABLE v_downto_range : t_dp_siso_arr(in_arr'HIGH DOWNTO 0);
+  BEGIN
+    FOR i IN in_arr'RANGE LOOP
+      v_to_range(i)     := in_arr(in_arr'HIGH-i);
+      v_downto_range(i) := in_arr(in_arr'HIGH-i);
+    END LOOP;
+    IF in_arr'LEFT>in_arr'RIGHT THEN
+      RETURN v_downto_range;
+    ELSIF in_arr'LEFT<in_arr'RIGHT THEN
+      RETURN v_to_range;
+    ELSE
+      RETURN in_arr;
+    END IF;
+  END func_dp_stream_arr_reverse_range;
+
+  FUNCTION func_dp_stream_arr_reverse_range(in_arr : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
+    VARIABLE v_to_range : t_dp_sosi_arr(0 TO in_arr'HIGH);
+    VARIABLE v_downto_range : t_dp_sosi_arr(in_arr'HIGH DOWNTO 0);
+  BEGIN
+    FOR i IN in_arr'RANGE LOOP
+      v_to_range(i)     := in_arr(in_arr'HIGH-i);
+      v_downto_range(i) := in_arr(in_arr'HIGH-i);
+    END LOOP;
+    IF in_arr'LEFT>in_arr'RIGHT THEN
+      RETURN v_downto_range;
+    ELSIF in_arr'LEFT<in_arr'RIGHT THEN
+      RETURN v_to_range;
+    ELSE
+      RETURN in_arr;
+    END IF;
+  END func_dp_stream_arr_reverse_range;
+  
+  -- Functions to combinatorially hold the data fields and to set or reset the info and control fields in an sosi array
+  FUNCTION func_dp_stream_arr_combine_data_info_ctrl(dp : t_dp_sosi_arr; info, ctrl : t_dp_sosi) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;       -- hold sosi data
+  BEGIN
+    v_dp := func_dp_stream_arr_set_info(   v_dp, info);  -- set sosi info
+    v_dp := func_dp_stream_arr_set_control(v_dp, ctrl);  -- set sosi ctrl
+    RETURN v_dp;
+  END func_dp_stream_arr_combine_data_info_ctrl;
+    
+  FUNCTION func_dp_stream_arr_set_info(dp : t_dp_sosi_arr; info : t_dp_sosi) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;  -- hold sosi data
+  BEGIN
+    FOR I IN dp'RANGE LOOP                          -- set sosi info
+      v_dp(I).bsn     := info.bsn;      -- sop
+      v_dp(I).channel := info.channel;  -- sop
+      v_dp(I).empty   := info.empty;    -- eop
+      v_dp(I).err     := info.err;      -- eop
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_set_info;
+  
+  FUNCTION func_dp_stream_arr_set_control(dp : t_dp_sosi_arr; ctrl : t_dp_sosi) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;  -- hold sosi data
+  BEGIN
+    FOR I IN dp'RANGE LOOP                          -- set sosi control
+      v_dp(I).valid := ctrl.valid;
+      v_dp(I).sop   := ctrl.sop;
+      v_dp(I).eop   := ctrl.eop;
+      v_dp(I).sync  := ctrl.sync;
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_set_control;
+  
+  FUNCTION func_dp_stream_arr_reset_control(dp : t_dp_sosi_arr) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;  -- hold sosi data
+  BEGIN
+    FOR I IN dp'RANGE LOOP                          -- reset sosi control
+      v_dp(I).valid := '0';
+      v_dp(I).sop   := '0';
+      v_dp(I).eop   := '0';
+      v_dp(I).sync  := '0';
+    END LOOP;
+    RETURN v_dp;
+  END func_dp_stream_arr_reset_control;
+  
+  FUNCTION func_dp_stream_reset_control(dp : t_dp_sosi) RETURN t_dp_sosi IS
+    VARIABLE v_dp : t_dp_sosi := dp;  -- hold sosi data
+  BEGIN
+    -- reset sosi control
+    v_dp.valid := '0';
+    v_dp.sop   := '0';
+    v_dp.eop   := '0';
+    v_dp.sync  := '0';
+    RETURN v_dp;
+  END func_dp_stream_reset_control;
+  
+  -- Functions to combinatorially determine the maximum and minimum sosi bsn[w-1:0] value in the sosi array (for all elements or only for the mask[]='1' elements)
+  FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_bsn : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := (OTHERS=>'0');  -- init max v_bsn with minimum value
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        IF UNSIGNED(v_bsn) < UNSIGNED(dp(I).bsn(w-1 DOWNTO 0)) THEN
+          v_bsn := dp(I).bsn(w-1 DOWNTO 0);
+        END IF;
+      END IF;
+    END LOOP;
+    RETURN v_bsn;
+  END func_dp_stream_arr_bsn_max;
+  
+  FUNCTION func_dp_stream_arr_bsn_max(dp : t_dp_sosi_arr; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
+  BEGIN
+    RETURN func_dp_stream_arr_bsn_max(dp, c_mask, w);
+  END func_dp_stream_arr_bsn_max;
+  
+  FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    VARIABLE v_bsn : STD_LOGIC_VECTOR(w-1 DOWNTO 0) := (OTHERS=>'1');  -- init min v_bsn with maximum value
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        IF UNSIGNED(v_bsn) > UNSIGNED(dp(I).bsn(w-1 DOWNTO 0)) THEN
+          v_bsn := dp(I).bsn(w-1 DOWNTO 0);
+        END IF;
+      END IF;
+    END LOOP;
+    RETURN v_bsn;
+  END func_dp_stream_arr_bsn_min;
+  
+  FUNCTION func_dp_stream_arr_bsn_min(dp : t_dp_sosi_arr; w : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_mask : STD_LOGIC_VECTOR(dp'RANGE) := (OTHERS=>'1');
+  BEGIN
+    RETURN func_dp_stream_arr_bsn_min(dp, c_mask, w);
+  END func_dp_stream_arr_bsn_min;
+
+  -- Function to copy the BSN number of one valid stream to all other streams. 
+  FUNCTION func_dp_stream_arr_copy_valid_bsn(dp : t_dp_sosi_arr; mask : STD_LOGIC_VECTOR) RETURN t_dp_sosi_arr IS
+    VARIABLE v_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := (OTHERS=>'0');
+    VARIABLE v_dp  : t_dp_sosi_arr(dp'RANGE) := dp;  -- hold sosi data
+  BEGIN
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='1' THEN
+        v_bsn := dp(I).bsn;
+      END IF;
+    END LOOP;
+    FOR I IN dp'RANGE LOOP
+      v_dp(I).bsn := v_bsn;
+    END LOOP;  
+    RETURN v_dp;
+  END func_dp_stream_arr_copy_valid_bsn;
+ 
+  
+  -- Functions to combinatorially handle channels
+  FUNCTION func_dp_stream_channel_set(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE v_rec : t_dp_sosi := st_sosi;
+  BEGIN
+    v_rec.channel := TO_UVEC(ch, c_dp_stream_channel_w);
+    RETURN v_rec;
+  END func_dp_stream_channel_set;
+  
+  FUNCTION func_dp_stream_channel_select(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE v_rec : t_dp_sosi := st_sosi;
+  BEGIN
+    IF UNSIGNED(st_sosi.channel)/=ch THEN
+      v_rec.valid := '0';
+      v_rec.sop   := '0';
+      v_rec.eop   := '0';
+    END IF;
+    RETURN v_rec;
+  END func_dp_stream_channel_select;
+  
+  FUNCTION func_dp_stream_channel_remove(st_sosi : t_dp_sosi; ch : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE v_rec : t_dp_sosi := st_sosi;
+  BEGIN
+    IF UNSIGNED(st_sosi.channel)=ch THEN
+      v_rec.valid := '0';
+      v_rec.sop   := '0';
+      v_rec.eop   := '0';
+    END IF;
+    RETURN v_rec;
+  END func_dp_stream_channel_remove;
+  
+  
+  FUNCTION func_dp_stream_error_set(st_sosi : t_dp_sosi; n : NATURAL) RETURN t_dp_sosi IS
+    VARIABLE v_rec : t_dp_sosi := st_sosi;
+  BEGIN
+    v_rec.err := TO_UVEC(n, c_dp_stream_error_w);
+    RETURN v_rec;
+  END func_dp_stream_error_set;
+  
+  
+  FUNCTION func_dp_stream_bsn_set(st_sosi : t_dp_sosi; bsn : STD_LOGIC_VECTOR) RETURN t_dp_sosi IS
+    VARIABLE v_rec : t_dp_sosi := st_sosi;
+  BEGIN
+    v_rec.bsn := RESIZE_DP_BSN(bsn);
+    RETURN v_rec;
+  END func_dp_stream_bsn_set;
+  
+    
+  FUNCTION func_dp_stream_combine_info_and_data(info, data : t_dp_sosi) RETURN t_dp_sosi IS
+    VARIABLE v_rec : t_dp_sosi := data;  -- Sosi data fields
+  BEGIN
+    -- Combine sosi data with the sosi info fields
+    v_rec.sync    := info.sync AND data.sop;  -- force sync only active at data.sop
+    v_rec.bsn     := info.bsn;
+    v_rec.channel := info.channel;
+    v_rec.empty   := info.empty;
+    v_rec.err     := info.err;
+    RETURN v_rec;
+  END func_dp_stream_combine_info_and_data;
+  
+  
+  FUNCTION func_dp_stream_slv_to_integer(slv_sosi : t_dp_sosi; w : NATURAL) RETURN t_dp_sosi_integer IS
+    VARIABLE v_rec : t_dp_sosi_integer;
+  BEGIN
+    v_rec.sync     := slv_sosi.sync;
+    v_rec.bsn      := TO_UINT(slv_sosi.bsn(30 DOWNTO 0));         -- NATURAL'width = 31 bit
+    v_rec.data     := TO_SINT(slv_sosi.data(w-1 DOWNTO 0));
+    v_rec.re       := TO_SINT(slv_sosi.re(w-1 DOWNTO 0));
+    v_rec.im       := TO_SINT(slv_sosi.im(w-1 DOWNTO 0));
+    v_rec.valid    := slv_sosi.valid;
+    v_rec.sop      := slv_sosi.sop;
+    v_rec.eop      := slv_sosi.eop;
+    v_rec.empty    := TO_UINT(slv_sosi.empty);
+    v_rec.channel  := TO_UINT(slv_sosi.channel);
+    v_rec.err      := TO_UINT(slv_sosi.err);
+    RETURN v_rec;
+  END func_dp_stream_slv_to_integer;
+
+  FUNCTION func_dp_stream_set_data(dp : t_dp_sosi; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi IS
+    VARIABLE v_dp : t_dp_sosi := dp;   
+  BEGIN 
+      IF    str="DATA" THEN v_dp.data := RESIZE_DP_DATA(slv);
+      ELSIF str="DSP"  THEN v_dp.re   := RESIZE_DP_DSP_DATA(slv);
+                            v_dp.im   := RESIZE_DP_DSP_DATA(slv);
+      ELSIF str="RE"  THEN  v_dp.re   := RESIZE_DP_DSP_DATA(slv);
+      ELSIF str="IM"  THEN  v_dp.im   := RESIZE_DP_DSP_DATA(slv);
+      ELSIF str="ALL" THEN  v_dp.data := RESIZE_DP_DATA(slv);    
+                            v_dp.re   := RESIZE_DP_DSP_DATA(slv);
+                            v_dp.im   := RESIZE_DP_DSP_DATA(slv);
+      ELSE  REPORT "Error in func_dp_stream_set_data for t_dp_sosi";
+      END IF;
+    RETURN v_dp;
+  END;
+
+  FUNCTION func_dp_stream_set_data(dp : t_dp_sosi_arr; slv : STD_LOGIC_VECTOR; str : STRING) RETURN t_dp_sosi_arr IS
+    VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;   
+  BEGIN 
+    FOR I IN dp'RANGE LOOP
+      v_dp(I) := func_dp_stream_set_data(dp(I), slv, str);
+    END LOOP;
+    RETURN v_dp;
+  END;
+
+  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 IS
+    VARIABLE v_dp : t_dp_sosi_arr(dp'RANGE) := dp;   
+  BEGIN 
+    FOR I IN dp'RANGE LOOP
+      IF mask(I)='0' THEN
+        v_dp(I) := func_dp_stream_set_data(dp(I), slv, str);
+      END IF; 
+    END LOOP;
+    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 := (OTHERS=>'0');
+      v_src_out_arr(i).re   := (OTHERS=>'0');
+      v_src_out_arr(i).im   := (OTHERS=>'0');
+      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/cores/base/dp/dp_pkg/dp_stream_stimuli.vhd b/cores/base/dp/dp_pkg/dp_stream_stimuli.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..3510fa0e2b0725c92c1c463e84a5b18032006af7
--- /dev/null
+++ b/cores/base/dp/dp_pkg/dp_stream_stimuli.vhd
@@ -0,0 +1,185 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose:
+-- . The dp_stream_stimuli generates as stream of packets with counter data.
+-- Description:
+--
+-- Remark:
+-- . The stimuli empty = 0 because the data in proc_dp_gen_block_data() is
+--   generated with one symbol per data (because symbol_w = data_w).
+--
+-- Usage:
+-- . See tb_dp_example_no_dut for usage example
+--
+
+LIBRARY IEEE, common_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+
+ENTITY dp_stream_stimuli IS
+  GENERIC (
+    g_instance_nr    : NATURAL := 0;
+    -- flow control
+    g_random_w       : NATURAL := 15;                       -- use different random width for stimuli and for verify to have different random sequences
+    g_pulse_active   : NATURAL := 1;
+    g_pulse_period   : NATURAL := 2;
+    g_flow_control   : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
+    -- initializations
+    g_sync_period    : NATURAL := 10;
+    g_sync_offset    : NATURAL := 0;
+    g_data_init      : NATURAL := 0;    -- choose some easy to recognize and unique value, data will increment at every valid
+    g_bsn_init       : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := TO_DP_BSN(0);  -- X"0877665544332211", bsn will increment at every sop
+    g_err_init       : NATURAL := 247;  -- choose some easy to recognize and unique value
+    g_err_incr       : NATURAL := 1;    -- when 0 keep fixed at init value, when 1 increment at every sop
+    g_channel_init   : NATURAL := 5;    -- choose some easy to recognize and unique value
+    g_channel_incr   : NATURAL := 1;    -- when 0 keep fixed at init value, when 1 increment at every sop
+    -- specific
+    g_in_dat_w       : NATURAL := 32;
+    g_nof_repeat     : NATURAL := 5;
+    g_pkt_len        : NATURAL := 16;
+    g_pkt_gap        : NATURAL := 4
+  );
+  PORT (
+    rst               : IN  STD_LOGIC;
+    clk               : IN  STD_LOGIC;
+  
+    -- Generate stimuli
+    src_in            : IN  t_dp_siso := c_dp_siso_rdy;
+    src_out           : OUT t_dp_sosi;
+
+    -- End of stimuli
+    last_snk_in       : OUT t_dp_sosi;   -- expected verify_snk_in after end of stimuli 
+    last_snk_in_evt   : OUT STD_LOGIC;   -- trigger verify to verify the last_snk_in 
+    tb_end            : OUT STD_LOGIC    -- signal end of tb as far as this dp_stream_stimuli is concerned
+  );
+END dp_stream_stimuli;
+
+
+ARCHITECTURE str OF dp_stream_stimuli IS
+  
+  SIGNAL random          : STD_LOGIC_VECTOR(g_random_w-1 DOWNTO 0) := TO_UVEC(g_instance_nr, g_random_w);  -- use different initialization to have different random sequences per stream
+  SIGNAL pulse           : STD_LOGIC;
+  SIGNAL pulse_en        : STD_LOGIC := '1';
+  
+  SIGNAL stimuli_en      : STD_LOGIC := '1';
+  SIGNAL src_out_data    : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL i_src_out       : t_dp_sosi;
+  
+BEGIN
+
+  src_out <= i_src_out;
+  
+  ------------------------------------------------------------------------------
+  -- STREAM CONTROL
+  ------------------------------------------------------------------------------
+  
+  random <= func_common_random(random) WHEN rising_edge(clk);
+  
+  proc_common_gen_duty_pulse(g_pulse_active, g_pulse_period, '1', rst, clk, pulse_en, pulse);
+
+  stimuli_en <= '1'                 WHEN g_flow_control=e_active ELSE
+                random(random'HIGH) WHEN g_flow_control=e_random ELSE
+                pulse               WHEN g_flow_control=e_pulse;
+                       
+  ------------------------------------------------------------------------------
+  -- DATA GENERATION
+  ------------------------------------------------------------------------------
+  
+  -- Generate data path input data
+  p_stimuli_st : PROCESS
+    VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst;
+    VARIABLE v_last : t_dp_sosi := c_dp_sosi_rst;
+  BEGIN
+    -- Initialisations
+    last_snk_in <= c_dp_sosi_rst;
+    last_snk_in_evt <= '0';
+    tb_end <= '0';
+    
+    -- Adjust initial sosi field values by -1 to compensate for auto increment
+    v_sosi.bsn     := INCR_UVEC(g_bsn_init,                    -1);
+    v_sosi.channel := INCR_UVEC(TO_DP_CHANNEL(g_channel_init), -g_channel_incr);
+    v_sosi.data    := INCR_UVEC(TO_DP_DATA(g_data_init),       -g_pkt_len);
+    v_sosi.err     := INCR_UVEC(TO_DP_ERROR(g_err_init),       -g_err_incr);
+    
+    i_src_out <= c_dp_sosi_rst;
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 5);
+
+    -- Generate g_nof_repeat packets
+    FOR I IN 0 TO g_nof_repeat-1 LOOP
+      -- Auto increment v_sosi field values for this packet
+      v_sosi.bsn     := INCR_UVEC(v_sosi.bsn, 1);
+      v_sosi.sync    := sel_a_b((UNSIGNED(v_sosi.bsn) MOD g_sync_period) = g_sync_offset, '1', '0');  -- insert sync starting at BSN=g_sync_offset and with period g_sync_period
+      v_sosi.channel := INCR_UVEC(v_sosi.channel, g_channel_incr);
+      v_sosi.data    := INCR_UVEC(v_sosi.data, g_pkt_len);
+      v_sosi.data    := RESIZE_DP_DATA(v_sosi.data(g_in_dat_w-1 DOWNTO 0));  -- wrap when >= 2**g_in_dat_w
+      v_sosi.err     := INCR_UVEC(v_sosi.err, g_err_incr);
+      
+      -- Send packet
+      proc_dp_gen_block_data(g_in_dat_w, TO_UINT(v_sosi.data), g_pkt_len, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, clk, stimuli_en, src_in, i_src_out);
+      
+      -- Insert optional gap between the packets
+      proc_common_wait_some_cycles(clk, g_pkt_gap);
+      
+      -- Update v_last.sync
+      IF v_sosi.sync='1' THEN v_last.sync := '1'; END IF;
+    END LOOP;
+
+    -- Update v_last control
+    IF g_nof_repeat>0 THEN
+      v_last.sop := '1';
+      v_last.eop := '1';
+      v_last.valid := '1';
+    END IF;
+    
+    -- Determine and keep last expected sosi field values after end of stimuli
+    -- . e_qual
+    v_last.bsn     := STD_LOGIC_VECTOR( UNSIGNED(g_bsn_init) + g_nof_repeat-1);
+    v_last.channel := TO_DP_CHANNEL(g_channel_init           + (g_nof_repeat-1)*g_channel_incr);
+    v_last.err     := TO_DP_ERROR(g_err_init                 + (g_nof_repeat-1)*g_err_incr);
+    -- . account for g_pkt_len
+    v_last.data    := INCR_UVEC(v_sosi.data, g_pkt_len-1);
+    v_last.data    := RESIZE_DP_DATA(v_last.data(g_in_dat_w-1 DOWNTO 0));  -- wrap when >= 2**g_in_dat_w
+    last_snk_in <= v_last;
+    
+    -- Signal end of stimuli
+    proc_common_wait_some_cycles(clk, 100);  -- latency from stimuli to verify depends on the flow control, so wait sufficiently long for last packet to have passed through
+    proc_common_gen_pulse(clk, last_snk_in_evt);
+    proc_common_wait_some_cycles(clk, 50);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+    
+  ------------------------------------------------------------------------------
+  -- Auxiliary
+  ------------------------------------------------------------------------------
+  
+  -- Map to slv to ease monitoring in wave window
+  src_out_data <= i_src_out.data(g_in_dat_w-1 DOWNTO 0);
+  
+END str;
diff --git a/cores/base/dp/dp_pkg/dp_stream_verify.vhd b/cores/base/dp/dp_pkg/dp_stream_verify.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..db4c7cb561f312409e6450a00ecab0b2386f08df
--- /dev/null
+++ b/cores/base/dp/dp_pkg/dp_stream_verify.vhd
@@ -0,0 +1,200 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose:
+-- . The dp_stream_verify verifies the stream of packets with counter data that
+--   are generated by dp_stimuli_st.
+-- Description:
+--   The component can verify a stream:
+--   . The sosi control fields are verified conform the bus specifications
+--     eg. considering the RL, no missing eop, etc.
+--   . The sosi data fields are verified based on their previous value under
+--     the assumption that they contain incrementing data. Whether a field
+--     is checked depends on verify_snk_in_enable.
+--  
+--   The component also checks whether the stream is active at all. A
+--   pulse in verify_expected_snk_in_evt triggers the verification of the
+--   corresponding field in snk_in using the expected_snk_in as reference.
+--
+-- Usage:
+-- . See tb_dp_example_no_dut for usage example
+--
+
+LIBRARY IEEE, common_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+USE work.tb_dp_pkg.ALL;
+
+
+ENTITY dp_stream_verify IS
+  GENERIC (
+    g_instance_nr         : NATURAL := 0;
+    -- flow control
+    g_random_w            : NATURAL := 14;                       -- use different random width for stimuli and for verify to have different random sequences
+    g_pulse_active        : NATURAL := 1;
+    g_pulse_period        : NATURAL := 2;
+    g_flow_control        : t_dp_flow_control_enum := e_active;  -- always active, random or pulse flow control
+    -- initializations
+    g_sync_period         : NATURAL := 10;
+    g_sync_offset         : NATURAL := 7;
+    g_snk_in_cnt_max      : t_dp_sosi_unsigned := c_dp_sosi_unsigned_rst;  -- default 0 is no wrap
+    g_snk_in_cnt_gap      : t_dp_sosi_unsigned := c_dp_sosi_unsigned_ones; -- default only accept increment +1
+    -- specific
+    g_in_dat_w            : NATURAL := 32;
+    g_pkt_len             : NATURAL := 16
+  );
+  PORT (
+    rst                        : IN  STD_LOGIC;
+    clk                        : IN  STD_LOGIC;
+  
+    -- Verify data
+    snk_out                    : OUT t_dp_siso;
+    snk_in                     : IN  t_dp_sosi;
+
+    -- During stimuli
+    verify_snk_in_enable       : IN  t_dp_sosi_sl;  -- enable to verify that the snk_in fields are incrementing 
+    
+    -- End of stimuli
+    expected_snk_in            : IN  t_dp_sosi;          -- expected snk_in at verify_expected_snk_in_evt
+    verify_expected_snk_in_evt : IN  t_dp_sosi_sl   -- trigger to verify the expected_snk_in 
+  );
+END dp_stream_verify;
+
+
+ARCHITECTURE tb OF dp_stream_verify IS
+
+  CONSTANT c_rl                       : NATURAL := 1;
+  CONSTANT c_no_dut                   : BOOLEAN:= TRUE;
+  
+  SIGNAL random                     : STD_LOGIC_VECTOR(g_random_w-1 DOWNTO 0) := TO_UVEC(g_instance_nr, g_random_w);  -- use different initialization to have different random sequences per stream
+  SIGNAL pulse                      : STD_LOGIC;
+  SIGNAL pulse_en                   : STD_LOGIC := '1';
+  
+  SIGNAL i_snk_out                  : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL prev_snk_out               : t_dp_siso;
+  SIGNAL hold_snk_in_data           : STD_LOGIC_VECTOR(c_dp_stream_data_w-1 DOWNTO 0);  -- used to hold valid data for verify at verify_expected_snk_in_evt
+  SIGNAL snk_in_data                : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL prev_snk_in                : t_dp_sosi;
+  
+  SIGNAL hold_snk_in_sop            : STD_LOGIC := '0';
+  SIGNAL detected_snk_in_ctrl       : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+  SIGNAL verify_snk_in_increment    : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+  SIGNAL verify_snk_in_ctrl         : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+
+  SIGNAL exp_size                   : NATURAL;
+  SIGNAL cnt_size                   : NATURAL;
+  
+BEGIN
+
+  snk_out <= i_snk_out;
+
+  ------------------------------------------------------------------------------
+  -- STREAM CONTROL
+  ------------------------------------------------------------------------------
+  
+  random <= func_common_random(random) WHEN rising_edge(clk);
+  
+  proc_common_gen_duty_pulse(g_pulse_active, g_pulse_period, '1', rst, clk, pulse_en, pulse);
+
+  i_snk_out.ready <= '1'                 WHEN g_flow_control=e_active  ELSE
+                     random(random'HIGH) WHEN g_flow_control=e_random  ELSE
+                     pulse               WHEN g_flow_control=e_pulse;
+  
+  ------------------------------------------------------------------------------
+  -- DATA VERIFICATION
+  ------------------------------------------------------------------------------  
+  
+  -- Detect first sync, sop, eop, valid
+  detected_snk_in_ctrl.sync  <= '1' WHEN snk_in.sync='1'  AND rising_edge(clk);
+  detected_snk_in_ctrl.valid <= '1' WHEN snk_in.valid='1' AND rising_edge(clk);
+  detected_snk_in_ctrl.sop   <= '1' WHEN snk_in.sop='1'   AND rising_edge(clk);
+  detected_snk_in_ctrl.eop   <= '1' WHEN snk_in.eop='1'   AND rising_edge(clk);
+  
+  -- Verify that the stimuli have been applied at all so at least one active sosi sync, sop, eop, valid field has been detected
+  proc_dp_verify_value("snk_in.sync",             clk, verify_expected_snk_in_evt.sync,    expected_snk_in.sync,    detected_snk_in_ctrl.sync);
+  proc_dp_verify_value("snk_in.sop",              clk, verify_expected_snk_in_evt.sop,     expected_snk_in.sop,     detected_snk_in_ctrl.sop);
+  proc_dp_verify_value("snk_in.eop",              clk, verify_expected_snk_in_evt.eop,     expected_snk_in.eop,     detected_snk_in_ctrl.eop);
+  proc_dp_verify_value("snk_in.valid",            clk, verify_expected_snk_in_evt.valid,   expected_snk_in.valid,   detected_snk_in_ctrl.valid);
+  
+  -- Verify that the last sosi data, bsn, channel and err fields are correct
+  proc_dp_verify_value("snk_in.data",    e_equal, clk, verify_expected_snk_in_evt.data,    expected_snk_in.data,    hold_snk_in_data);
+  proc_dp_verify_value("snk_in.bsn",     e_equal, clk, verify_expected_snk_in_evt.bsn,     expected_snk_in.bsn,     snk_in.bsn);
+  proc_dp_verify_value("snk_in.channel", e_equal, clk, verify_expected_snk_in_evt.channel, expected_snk_in.channel, snk_in.channel);
+  proc_dp_verify_value("snk_in.err",     e_equal, clk, verify_expected_snk_in_evt.err,     expected_snk_in.err,     snk_in.err);
+  
+  -- Verify that the output is incrementing data, like the input stimuli
+  p_verify_snk_in_increment : PROCESS(verify_snk_in_enable, detected_snk_in_ctrl)
+  BEGIN
+    verify_snk_in_increment         <= verify_snk_in_enable;
+    verify_snk_in_increment.data    <= verify_snk_in_enable.data    AND detected_snk_in_ctrl.valid;
+    verify_snk_in_increment.re      <= verify_snk_in_enable.re      AND detected_snk_in_ctrl.valid;
+    verify_snk_in_increment.im      <= verify_snk_in_enable.im      AND detected_snk_in_ctrl.valid;
+    verify_snk_in_increment.bsn     <= verify_snk_in_enable.bsn     AND detected_snk_in_ctrl.sop;
+    verify_snk_in_increment.channel <= verify_snk_in_enable.channel AND detected_snk_in_ctrl.sop;
+    verify_snk_in_increment.empty   <= verify_snk_in_enable.empty   AND detected_snk_in_ctrl.eop;
+    verify_snk_in_increment.err     <= verify_snk_in_enable.err     AND detected_snk_in_ctrl.eop;
+  END PROCESS;
+  
+  proc_dp_verify_data("snk_in.data",    c_rl, g_snk_in_cnt_max.data,    g_snk_in_cnt_gap.data,    clk, verify_snk_in_increment.data,    i_snk_out.ready, snk_in.valid, snk_in.data,    prev_snk_in.data);
+  proc_dp_verify_data("snk_in.re",      c_rl, g_snk_in_cnt_max.re,      g_snk_in_cnt_gap.re,      clk, verify_snk_in_increment.re,      i_snk_out.ready, snk_in.valid, snk_in.re,      prev_snk_in.re);
+  proc_dp_verify_data("snk_in.im",      c_rl, g_snk_in_cnt_max.im,      g_snk_in_cnt_gap.im,      clk, verify_snk_in_increment.im,      i_snk_out.ready, snk_in.valid, snk_in.im,      prev_snk_in.im);
+  proc_dp_verify_data("snk_in.bsn",     c_rl, g_snk_in_cnt_max.bsn,     g_snk_in_cnt_gap.bsn,     clk, verify_snk_in_increment.bsn,     i_snk_out.ready, snk_in.sop,   snk_in.bsn,     prev_snk_in.bsn);
+  proc_dp_verify_data("snk_in.channel", c_rl, g_snk_in_cnt_max.channel, g_snk_in_cnt_gap.channel, clk, verify_snk_in_increment.channel, i_snk_out.ready, snk_in.sop,   snk_in.channel, prev_snk_in.channel);
+  proc_dp_verify_data("snk_in.empty",   c_rl, g_snk_in_cnt_max.empty,   g_snk_in_cnt_gap.empty,   clk, verify_snk_in_increment.empty,   i_snk_out.ready, snk_in.eop,   snk_in.empty,   prev_snk_in.empty);
+  proc_dp_verify_data("snk_in.err",     c_rl, g_snk_in_cnt_max.err,     g_snk_in_cnt_gap.err,     clk, verify_snk_in_increment.err,     i_snk_out.ready, snk_in.eop,   snk_in.err,     prev_snk_in.err);
+  
+  -- Verify that the snk_in control fields are correct
+  p_verify_snk_in_ctrl: PROCESS(snk_in, verify_snk_in_enable)
+  BEGIN
+    verify_snk_in_ctrl.sync  <= snk_in.sync  AND verify_snk_in_enable.valid AND verify_snk_in_enable.sync;
+    verify_snk_in_ctrl.sop   <= snk_in.sop   AND verify_snk_in_enable.valid AND verify_snk_in_enable.sop AND verify_snk_in_enable.eop;
+    verify_snk_in_ctrl.eop   <= snk_in.eop   AND verify_snk_in_enable.valid AND verify_snk_in_enable.sop AND verify_snk_in_enable.eop;
+    verify_snk_in_ctrl.valid <= snk_in.valid AND verify_snk_in_enable.valid;
+  END PROCESS;
+  
+  -- Verify that the output sync occurs when expected
+  proc_dp_verify_sync(g_sync_period, g_sync_offset, clk, detected_snk_in_ctrl.sop, verify_snk_in_ctrl.sync, verify_snk_in_ctrl.sop, snk_in.bsn);
+  
+  -- Verify output packet ctrl
+  proc_dp_verify_sop_and_eop(clk, verify_snk_in_ctrl.valid, verify_snk_in_ctrl.sop, verify_snk_in_ctrl.eop, hold_snk_in_sop);
+  
+  -- Verify output packet block size
+  exp_size <= g_pkt_len;
+  
+  proc_dp_verify_block_size(exp_size, clk, verify_snk_in_ctrl.valid, verify_snk_in_ctrl.sop, verify_snk_in_ctrl.eop, cnt_size);
+
+  -- Verify output ready latency
+  proc_dp_verify_valid(clk, detected_snk_in_ctrl.valid, i_snk_out.ready, prev_snk_out.ready, verify_snk_in_ctrl.valid);
+    
+  ------------------------------------------------------------------------------
+  -- Auxiliary
+  ------------------------------------------------------------------------------
+  
+  -- Map to slv to ease monitoring in wave window
+  snk_in_data  <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
+  
+  hold_snk_in_data <= snk_in.data WHEN snk_in.valid='1';
+  
+END tb;
diff --git a/cores/base/dp/dp_pkg/hdllib.cfg b/cores/base/dp/dp_pkg/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..12f4b46bfa651daddb71f635882831a7909c2eac
--- /dev/null
+++ b/cores/base/dp/dp_pkg/hdllib.cfg
@@ -0,0 +1,20 @@
+hdl_lib_name = dp_pkg
+hdl_library_clause_name = dp_pkg_lib
+hdl_lib_uses_synth = common_pkg
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    dp_stream_pkg.vhd
+    tb_dp_pkg.vhd
+    dp_stream_stimuli.vhd
+    dp_stream_verify.vhd
+    
+test_bench_files = 
+
+regression_test_vhdl = 
+    
+[modelsim_project_file]
+
+
+[quartus_project_file]
diff --git a/cores/base/dp/dp_pkg/tb_dp_pkg.vhd b/cores/base/dp/dp_pkg/tb_dp_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..2dadc92566dc25b3b8ff42bc671d99a047a16f77
--- /dev/null
+++ b/cores/base/dp/dp_pkg/tb_dp_pkg.vhd
@@ -0,0 +1,2413 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2010
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+
+
+PACKAGE tb_dp_pkg IS
+
+  ------------------------------------------------------------------------------
+  -- Purpose:
+  --
+  -- Test bench package for applying stimuli to a streaming data path. The
+  -- input is counter data, the output is verified and an error is reported
+  -- if a counter value is missing or duplicate.
+  --
+  -- Description:
+  --
+  -- The test is divided into intervals marked by sync to start a new subtest
+  -- named by state. New subtests can be added by adding an extra sync interval
+  -- and state name to this package. In each subtest the streaming interface
+  -- DUT can be verified for different situations by manipulating:
+  -- . cnt_en    : cnt_en not always active when in_ready is asserted
+  -- . out_ready : out_ready not always active
+  --
+  -- Remarks:
+  -- . See e.g. tb_dp_pipeline.vhd for how to use the procedures.
+  -- . To run all stimuli in Modelsim do:
+  --   > as 10
+  --   > run 400 us
+  ------------------------------------------------------------------------------
+
+  CONSTANT clk_period         : TIME := 10 ns;  -- 100 MHz
+  CONSTANT c_dp_sync_interval : NATURAL := 3000;
+  CONSTANT c_dp_test_interval : NATURAL := 100;
+  CONSTANT c_dp_nof_toggle    : NATURAL := 40;
+  CONSTANT c_dp_nof_both      : NATURAL := 50;
+
+  -- The test bench uses other field widths than the standard t_dp_sosi record field widths, the assumptions are:
+  -- . c_dp_data_w < c_dp_stream_data_w
+  -- . c_dp_data_w > c_dp_stream_empty_w
+  -- . c_dp_data_w > c_dp_stream_channel_w
+  -- . c_dp_data_w > c_dp_stream_error_w
+  CONSTANT c_dp_data_w            : NATURAL := c_word_w;  -- =32, choose wide enough to avoid out_data wrap around issue for p_verify
+  CONSTANT c_dp_bsn_w             : NATURAL := c_dp_data_w;  -- c_dp_stream_bsn_w;
+  CONSTANT c_dp_empty_w           : NATURAL := c_dp_stream_empty_w;
+  CONSTANT c_dp_channel_w         : NATURAL := c_dp_stream_channel_w;
+  CONSTANT c_dp_channel_user_w    : NATURAL := c_dp_stream_channel_w/2;     -- support some bits for mux input user streams channel widths
+  CONSTANT c_dp_channel_mux_w     : NATURAL :=(c_dp_stream_channel_w+1)/2;  -- support rest bits for the nof input ports of a mux
+  CONSTANT c_dp_error_w           : NATURAL := c_dp_stream_error_w;
+
+  TYPE t_dp_data_arr IS ARRAY (NATURAL RANGE <>) OF STD_LOGIC_VECTOR(c_dp_data_w-1 DOWNTO 0);
+  
+  -- The state name tells what kind of test is done in the sync interval
+  TYPE t_dp_state_enum IS (
+    s_idle,
+    s_both_active,
+    s_pull_down_out_ready,
+    s_pull_down_cnt_en,
+    s_toggle_out_ready,
+    s_toggle_cnt_en,
+    s_toggle_both,
+    s_pulse_cnt_en,
+    s_chirp_out_ready,
+    s_random,
+    s_done
+  );
+
+  TYPE t_dp_value_enum IS (
+    e_equal,
+    e_at_least
+  );
+  
+  -- always active, random or pulse flow control
+  TYPE t_dp_flow_control_enum IS (
+    e_active,
+    e_random,
+    e_pulse    
+  );
+  
+  TYPE t_dp_flow_control_enum_arr IS ARRAY (NATURAL RANGE <>) OF t_dp_flow_control_enum;
+  
+  CONSTANT c_dp_flow_control_enum_arr : t_dp_flow_control_enum_arr := (e_active, e_random, e_pulse);  -- array all possible values that can be iterated over
+  
+  ------------------------------------------------------------------------------
+  -- Stream source functions
+  ------------------------------------------------------------------------------
+  
+  -- Block data generator with feedforward throttle control
+  -- !!! old style: sync before sop
+  -- !!! used by tb_dp_packetizing, do not use for new DP components
+  PROCEDURE proc_dp_gen_block_data(CONSTANT c_nof_block_per_sync : IN    NATURAL;
+                                   CONSTANT c_block_size         : IN    NATURAL;
+                                   CONSTANT c_gap_size           : IN    NATURAL;
+                                   CONSTANT c_throttle_num       : IN    NATURAL;
+                                   CONSTANT c_throttle_den       : IN    NATURAL;
+                                   SIGNAL   rst                  : IN    STD_LOGIC;
+                                   SIGNAL   clk                  : IN    STD_LOGIC;
+                                   SIGNAL   sync_nr              : INOUT NATURAL;
+                                   SIGNAL   block_nr             : INOUT NATURAL;
+                                   SIGNAL   cnt_sync             : OUT   STD_LOGIC;
+                                   SIGNAL   cnt_val              : OUT   STD_LOGIC;
+                                   SIGNAL   cnt_dat              : INOUT STD_LOGIC_VECTOR);
+                                   
+  -- Block data generator with ready flow control and symbols counter
+  PROCEDURE proc_dp_gen_block_data(CONSTANT c_ready_latency  : IN  NATURAL;    -- 0, 1 are supported by proc_dp_stream_ready_latency()
+                                   CONSTANT c_use_data       : IN  BOOLEAN;    -- when TRUE use data field, else use re, im fields, and keep unused fields at 'X'
+                                   CONSTANT c_data_w         : IN  NATURAL;    -- data width for the data, re and im fields
+                                   CONSTANT c_symbol_w       : IN  NATURAL;    -- c_data_w/c_symbol_w must be an integer
+                                   CONSTANT c_symbol_init    : IN  NATURAL;    -- init counter for symbols in data field
+                                   CONSTANT c_symbol_re_init : IN  NATURAL;    -- init counter for symbols in re field
+                                   CONSTANT c_symbol_im_init : IN  NATURAL;    -- init counter for symbols in im field
+                                   CONSTANT c_nof_symbols    : IN  NATURAL;    -- nof symbols per frame for the data, re and im fields
+                                   CONSTANT c_channel        : IN  NATURAL;    -- channel field
+                                   CONSTANT c_error          : IN  NATURAL;    -- error field
+                                   CONSTANT c_sync           : IN  STD_LOGIC;  -- when '1' issue sync pulse during this block
+                                   CONSTANT c_bsn            : IN  STD_LOGIC_VECTOR;  -- bsn field
+                                   SIGNAL   clk              : IN  STD_LOGIC;
+                                   SIGNAL   in_en            : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                                   SIGNAL   src_in           : IN  t_dp_siso;
+                                   SIGNAL   src_out          : OUT t_dp_sosi);
+                                   
+  PROCEDURE proc_dp_gen_block_data(CONSTANT c_data_w         : IN  NATURAL;    -- data width for the data field
+                                   CONSTANT c_symbol_init    : IN  NATURAL;    -- init counter for the data in the data field
+                                   CONSTANT c_nof_symbols    : IN  NATURAL;    -- nof symbols per frame for the data fields
+                                   CONSTANT c_channel        : IN  NATURAL;    -- channel field
+                                   CONSTANT c_error          : IN  NATURAL;    -- error field
+                                   CONSTANT c_sync           : IN  STD_LOGIC;  -- when '1' issue sync pulse during this block
+                                   CONSTANT c_bsn            : IN  STD_LOGIC_VECTOR;  -- bsn field
+                                   SIGNAL   clk              : IN  STD_LOGIC;
+                                   SIGNAL   in_en            : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                                   SIGNAL   src_in           : IN  t_dp_siso;
+                                   SIGNAL   src_out          : OUT t_dp_sosi);
+                                   
+  -- Handle stream ready signal, only support RL=0 or 1.
+  PROCEDURE proc_dp_stream_ready_latency(CONSTANT c_latency : IN  NATURAL;
+                                         SIGNAL   clk       : IN  STD_LOGIC;
+                                         SIGNAL   ready     : IN  STD_LOGIC;
+                                         SIGNAL   in_en     : IN  STD_LOGIC;  -- when '1' then active output when ready
+                                         CONSTANT c_sync    : IN  STD_LOGIC;
+                                         CONSTANT c_valid   : IN  STD_LOGIC;
+                                         CONSTANT c_sop     : IN  STD_LOGIC;
+                                         CONSTANT c_eop     : IN  STD_LOGIC;
+                                         SIGNAL   out_sync  : OUT STD_LOGIC;
+                                         SIGNAL   out_valid : OUT STD_LOGIC;
+                                         SIGNAL   out_sop   : OUT STD_LOGIC;
+                                         SIGNAL   out_eop   : OUT STD_LOGIC);
+                                         
+  -- Initialize the data per symbol
+  FUNCTION func_dp_data_init(c_data_w, c_symbol_w, init : NATURAL) RETURN STD_LOGIC_VECTOR;
+  
+  -- Increment the data per symbol
+  FUNCTION func_dp_data_incr(c_data_w, c_symbol_w : NATURAL; data : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR;
+  
+  -- Generate a counter data with valid
+  PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN  NATURAL;    -- 0, 1 are supported by proc_dp_stream_ready_latency()
+                             CONSTANT c_data_w        : IN  NATURAL;
+                             CONSTANT c_data_init     : IN  NATURAL;
+                             SIGNAL   rst             : IN  STD_LOGIC;
+                             SIGNAL   clk             : IN  STD_LOGIC;
+                             SIGNAL   in_en           : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                             SIGNAL   src_in          : IN  t_dp_siso;
+                             SIGNAL   src_out         : OUT t_dp_sosi);
+
+  -- As above but with counter max
+  PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency   : IN  NATURAL; 
+                             CONSTANT c_data_w          : IN  NATURAL;
+                             CONSTANT c_data_init       : IN  NATURAL;
+                             CONSTANT c_data_max        : IN  NATURAL; 
+                             SIGNAL   rst             : IN  STD_LOGIC;
+                             SIGNAL   clk             : IN  STD_LOGIC;
+                             SIGNAL   in_en           : IN  STD_LOGIC;
+                             SIGNAL   src_in          : IN  t_dp_siso;
+                             SIGNAL   src_out         : OUT t_dp_sosi);
+   
+  -- Generate a frame with symbols counter
+  PROCEDURE proc_dp_gen_frame(CONSTANT c_ready_latency : IN  NATURAL;    -- 0, 1 are supported by proc_dp_stream_ready_latency()
+                              CONSTANT c_data_w        : IN  NATURAL;
+                              CONSTANT c_symbol_w      : IN  NATURAL;    -- c_data_w/c_symbol_w must be an integer
+                              CONSTANT c_symbol_init   : IN  NATURAL;
+                              CONSTANT c_nof_symbols   : IN  NATURAL;
+                              CONSTANT c_bsn           : IN  NATURAL;
+                              CONSTANT c_sync          : IN  STD_LOGIC;
+                              SIGNAL   clk             : IN  STD_LOGIC;
+                              SIGNAL   in_en           : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                              SIGNAL   src_in          : IN  t_dp_siso;
+                              SIGNAL   src_out         : OUT t_dp_sosi);
+
+  -- Input data counter
+  PROCEDURE proc_dp_cnt_dat(SIGNAL rst     : IN    STD_LOGIC;
+                            SIGNAL clk     : IN    STD_LOGIC;
+                            SIGNAL in_en   : IN    STD_LOGIC;
+                            SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR);
+
+  PROCEDURE proc_dp_cnt_dat(SIGNAL rst     : IN    STD_LOGIC;
+                            SIGNAL clk     : IN    STD_LOGIC;
+                            SIGNAL in_en   : IN    STD_LOGIC;
+                            SIGNAL cnt_val : INOUT STD_LOGIC;
+                            SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR);
+                            
+  -- Transmit data
+  PROCEDURE proc_dp_tx_data(CONSTANT c_ready_latency : IN    NATURAL;
+                            SIGNAL   rst             : IN    STD_LOGIC;
+                            SIGNAL   clk             : IN    STD_LOGIC;
+                            SIGNAL   cnt_val         : IN    STD_LOGIC;
+                            SIGNAL   cnt_dat         : IN    STD_LOGIC_VECTOR;
+                            SIGNAL   tx_data         : INOUT t_dp_data_arr;
+                            SIGNAL   tx_val          : INOUT STD_LOGIC_VECTOR;
+                            SIGNAL   out_data        : OUT   STD_LOGIC_VECTOR;
+                            SIGNAL   out_val         : OUT   STD_LOGIC);
+  
+  -- Transmit data control (use for sop, eop)
+  PROCEDURE proc_dp_tx_ctrl(CONSTANT c_offset : IN  NATURAL;
+                            CONSTANT c_period : IN  NATURAL;
+                            SIGNAL   data     : IN  STD_LOGIC_VECTOR;
+                            SIGNAL   valid    : IN  STD_LOGIC;
+                            SIGNAL   ctrl     : OUT STD_LOGIC);
+                            
+  -- Define sync interval
+  PROCEDURE proc_dp_sync_interval(SIGNAL clk  : IN  STD_LOGIC;
+                                  SIGNAL sync : OUT STD_LOGIC);
+
+  -- Stimuli for cnt_en
+  PROCEDURE proc_dp_count_en(SIGNAL rst    : IN    STD_LOGIC;
+                             SIGNAL clk    : IN    STD_LOGIC;
+                             SIGNAL sync   : IN    STD_LOGIC;
+                             SIGNAL lfsr   : INOUT STD_LOGIC_VECTOR;
+                             SIGNAL state  : OUT   t_dp_state_enum;
+                             SIGNAL done   : OUT   STD_LOGIC;
+                             SIGNAL tb_end : OUT   STD_LOGIC;
+                             SIGNAL cnt_en : OUT   STD_LOGIC);
+
+  ------------------------------------------------------------------------------
+  -- Stream sink functions
+  ------------------------------------------------------------------------------
+  
+  -- Stimuli for out_ready
+  PROCEDURE proc_dp_out_ready(SIGNAL rst       : IN    STD_LOGIC;
+                              SIGNAL clk       : IN    STD_LOGIC;
+                              SIGNAL sync      : IN    STD_LOGIC;
+                              SIGNAL lfsr      : INOUT STD_LOGIC_VECTOR;
+                              SIGNAL out_ready : OUT   STD_LOGIC);
+                              
+  -- DUT output verify enable
+  PROCEDURE proc_dp_verify_en(CONSTANT c_delay   : IN  NATURAL;
+                              SIGNAL   rst       : IN  STD_LOGIC;
+                              SIGNAL   clk       : IN  STD_LOGIC;
+                              SIGNAL   sync      : IN  STD_LOGIC;
+                              SIGNAL   verify_en : OUT STD_LOGIC);
+                              
+  PROCEDURE proc_dp_verify_en(CONSTANT c_continuous : IN  BOOLEAN;
+                              SIGNAL   clk          : IN  STD_LOGIC;
+                              SIGNAL   valid        : IN  STD_LOGIC;
+                              SIGNAL   sop          : IN  STD_LOGIC;
+                              SIGNAL   eop          : IN  STD_LOGIC;
+                              SIGNAL   verify_en    : OUT STD_LOGIC);
+                              
+  -- Run and verify for some cycles
+  PROCEDURE proc_dp_verify_run_some_cycles(CONSTANT nof_pre_clk    : IN   NATURAL;
+                                           CONSTANT nof_verify_clk : IN   NATURAL;
+                                           CONSTANT nof_post_clk   : IN   NATURAL;
+                                           SIGNAL   clk            : IN   STD_LOGIC;
+                                           SIGNAL   verify_en      : OUT  STD_LOGIC);
+                                           
+  -- Verify the expected value
+  PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
+                                 CONSTANT mode  : IN t_dp_value_enum;
+                                 SIGNAL   clk   : IN STD_LOGIC;
+                                 SIGNAL   en    : IN STD_LOGIC;
+                                 SIGNAL   exp   : IN STD_LOGIC_VECTOR;  
+                                 SIGNAL   res   : IN STD_LOGIC_VECTOR);
+                                 
+  PROCEDURE proc_dp_verify_value(CONSTANT mode : IN t_dp_value_enum;
+                                 SIGNAL   clk  : IN STD_LOGIC;
+                                 SIGNAL   en   : IN STD_LOGIC;
+                                 SIGNAL   exp  : IN STD_LOGIC_VECTOR;  
+                                 SIGNAL   res  : IN STD_LOGIC_VECTOR);
+                                
+  PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
+                                 SIGNAL   clk   : IN STD_LOGIC;
+                                 SIGNAL   en    : IN STD_LOGIC;
+                                 SIGNAL   exp   : IN STD_LOGIC;  
+                                 SIGNAL   res   : IN STD_LOGIC);
+                                 
+  -- Verify output global and local BSN
+  -- . incrementing or replicated global BSN
+  -- . incrementing local BSN that starts at 1
+  PROCEDURE proc_dp_verify_bsn(CONSTANT c_use_local_bsn             : IN    BOOLEAN;    -- use local BSN or only use global BSN
+                               CONSTANT c_global_bsn_increment      : IN    POSITIVE;   -- increment per global BSN
+                               CONSTANT c_nof_replicated_global_bsn : IN    POSITIVE;   -- number of replicated global BSN
+                               CONSTANT c_block_per_sync            : IN    POSITIVE;   -- of sop/eop blocks per sync interval
+                               SIGNAL   clk                         : IN    STD_LOGIC;
+                               SIGNAL   out_sync                    : IN    STD_LOGIC;
+                               SIGNAL   out_sop                     : IN    STD_LOGIC;
+                               SIGNAL   out_bsn                     : IN    STD_LOGIC_VECTOR;
+                               SIGNAL   verify_en                   : INOUT STD_LOGIC;  -- initialize '0', becomes '1' when bsn verification starts
+                               SIGNAL   cnt_replicated_global_bsn   : INOUT NATURAL;
+                               SIGNAL   prev_out_bsn_global         : INOUT STD_LOGIC_VECTOR;
+                               SIGNAL   prev_out_bsn_local          : INOUT STD_LOGIC_VECTOR);
+                               
+  -- Verify incrementing data
+  -- . wrap at c_out_data_max when >0, else no wrap when c_out_data_max=0
+  -- . default increment by +1, but also allow an increment by +c_out_data_gap
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_ready_latency : IN    NATURAL;
+                                CONSTANT c_out_data_max  : IN    UNSIGNED;
+                                CONSTANT c_out_data_gap  : IN    UNSIGNED;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_ready       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                
+  -- Verify the DUT incrementing output data that wraps in range 0 ... c_out_data_max
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_ready_latency : IN    NATURAL;
+                                CONSTANT c_out_data_max  : IN    UNSIGNED;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_ready       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                
+  -- Verify the DUT incrementing output data, fixed increment +1
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_ready_latency : IN    NATURAL;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_ready       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;  -- by using sop or eop proc_dp_verify_data() can also be used to verify other SOSI fields like bsn, error, channel, empty
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                
+  -- Verify incrementing data with RL > 0 or no flow control, support wrap at maximum and increment gap
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_out_data_max  : IN    UNSIGNED;
+                                CONSTANT c_out_data_gap  : IN    UNSIGNED;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+  
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_out_data_max  : IN    NATURAL;
+                                CONSTANT c_out_data_gap  : IN    NATURAL;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_out_data_max  : IN    NATURAL;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                
+  -- Verify incrementing data with RL > 0 or no flow control, fixed increment +1
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                
+  -- Verify the DUT output symbols
+  PROCEDURE proc_dp_verify_symbols(CONSTANT c_ready_latency : IN    NATURAL;
+                                   CONSTANT c_data_w        : IN    NATURAL;
+                                   CONSTANT c_symbol_w      : IN    NATURAL;
+                                   SIGNAL   clk             : IN    STD_LOGIC;
+                                   SIGNAL   verify_en       : IN    STD_LOGIC;
+                                   SIGNAL   out_ready       : IN    STD_LOGIC;
+                                   SIGNAL   out_val         : IN    STD_LOGIC;
+                                   SIGNAL   out_eop         : IN    STD_LOGIC;
+                                   SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                   SIGNAL   out_empty       : IN    STD_LOGIC_VECTOR;
+                                   SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR);
+                                   
+  -- Verify the DUT output data with empty
+  PROCEDURE proc_dp_verify_data_empty(CONSTANT c_ready_latency : IN    NATURAL;
+                                      CONSTANT c_last_word     : IN    NATURAL;
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   verify_en       : IN    STD_LOGIC;
+                                      SIGNAL   out_ready       : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop_1       : INOUT STD_LOGIC;
+                                      SIGNAL   out_eop_2       : INOUT STD_LOGIC;
+                                      SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                      SIGNAL   out_data_1      : INOUT STD_LOGIC_VECTOR;
+                                      SIGNAL   out_data_2      : INOUT STD_LOGIC_VECTOR;
+                                      SIGNAL   out_data_3      : INOUT STD_LOGIC_VECTOR;
+                                      SIGNAL   out_empty       : IN    STD_LOGIC_VECTOR;
+                                      SIGNAL   out_empty_1     : INOUT STD_LOGIC_VECTOR);
+                                      
+  PROCEDURE proc_dp_verify_other_sosi(CONSTANT c_str       : IN STRING;
+                                      CONSTANT c_exp_data  : IN STD_LOGIC_VECTOR;
+                                      SIGNAL   clk         : IN STD_LOGIC;
+                                      SIGNAL   verify_en   : IN STD_LOGIC;
+                                      SIGNAL   res_data    : IN STD_LOGIC_VECTOR);
+                                      
+  PROCEDURE proc_dp_verify_valid(CONSTANT c_ready_latency : IN    NATURAL;
+                                 SIGNAL   clk             : IN    STD_LOGIC;
+                                 SIGNAL   verify_en       : IN    STD_LOGIC;
+                                 SIGNAL   out_ready       : IN    STD_LOGIC;
+                                 SIGNAL   prev_out_ready  : INOUT STD_LOGIC_VECTOR;
+                                 SIGNAL   out_val         : IN    STD_LOGIC);
+                                 
+  PROCEDURE proc_dp_verify_valid(SIGNAL   clk             : IN    STD_LOGIC;
+                                 SIGNAL   verify_en       : IN    STD_LOGIC;
+                                 SIGNAL   out_ready       : IN    STD_LOGIC;
+                                 SIGNAL   prev_out_ready  : INOUT STD_LOGIC;
+                                 SIGNAL   out_val         : IN    STD_LOGIC);
+                                 
+  -- Verify the DUT output sync
+  PROCEDURE proc_dp_verify_sync(CONSTANT c_sync_period : IN    NATURAL;
+                                CONSTANT c_sync_offset : IN    NATURAL;
+                                SIGNAL   clk           : IN    STD_LOGIC;
+                                SIGNAL   verify_en     : IN    STD_LOGIC;
+                                SIGNAL   sync          : IN    STD_LOGIC;
+                                SIGNAL   sop           : IN    STD_LOGIC;
+                                SIGNAL   bsn           : IN    STD_LOGIC_VECTOR);
+                                
+  -- Verify the DUT output sop and eop
+  PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN    NATURAL;
+                                       CONSTANT c_verify_valid  : IN    BOOLEAN;
+                                       SIGNAL   clk             : IN    STD_LOGIC;
+                                       SIGNAL   out_ready       : IN    STD_LOGIC;
+                                       SIGNAL   out_val         : IN    STD_LOGIC;
+                                       SIGNAL   out_sop         : IN    STD_LOGIC;
+                                       SIGNAL   out_eop         : IN    STD_LOGIC;
+                                       SIGNAL   hold_sop        : INOUT STD_LOGIC);
+                                       
+  PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN    NATURAL;
+                                       SIGNAL   clk             : IN    STD_LOGIC;
+                                       SIGNAL   out_ready       : IN    STD_LOGIC;
+                                       SIGNAL   out_val         : IN    STD_LOGIC;
+                                       SIGNAL   out_sop         : IN    STD_LOGIC;
+                                       SIGNAL   out_eop         : IN    STD_LOGIC;
+                                       SIGNAL   hold_sop        : INOUT STD_LOGIC);
+                                       
+  PROCEDURE proc_dp_verify_sop_and_eop(SIGNAL clk      : IN    STD_LOGIC;
+                                       SIGNAL out_val  : IN    STD_LOGIC;
+                                       SIGNAL out_sop  : IN    STD_LOGIC;
+                                       SIGNAL out_eop  : IN    STD_LOGIC;
+                                       SIGNAL hold_sop : INOUT STD_LOGIC);
+                                       
+  PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN    NATURAL;
+                                      SIGNAL   alt_size        : IN    NATURAL;     -- alternative size (eg. use exp_size'last_value)
+                                      SIGNAL   exp_size        : IN    NATURAL;     -- expected size
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   out_ready       : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_sop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   cnt_size        : INOUT NATURAL);
+                                      
+  PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN    NATURAL;
+                                      SIGNAL   exp_size        : IN    NATURAL;     -- expected size
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   out_ready       : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_sop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   cnt_size        : INOUT NATURAL);
+                                      
+  PROCEDURE proc_dp_verify_block_size(SIGNAL alt_size : IN    NATURAL;     -- alternative size (eg. use exp_size'last_value)
+                                      SIGNAL exp_size : IN    NATURAL;     -- expected size
+                                      SIGNAL clk      : IN    STD_LOGIC;
+                                      SIGNAL out_val  : IN    STD_LOGIC;
+                                      SIGNAL out_sop  : IN    STD_LOGIC;
+                                      SIGNAL out_eop  : IN    STD_LOGIC;
+                                      SIGNAL cnt_size : INOUT NATURAL);
+                                      
+  PROCEDURE proc_dp_verify_block_size(SIGNAL exp_size : IN    NATURAL;     -- expected size
+                                      SIGNAL clk      : IN    STD_LOGIC;
+                                      SIGNAL out_val  : IN    STD_LOGIC;
+                                      SIGNAL out_sop  : IN    STD_LOGIC;
+                                      SIGNAL out_eop  : IN    STD_LOGIC;
+                                      SIGNAL cnt_size : INOUT NATURAL);
+                                       
+  -- Verify the DUT output invalid between frames
+  PROCEDURE proc_dp_verify_gap_invalid(SIGNAL clk     : IN    STD_LOGIC;
+                                       SIGNAL in_val  : IN    STD_LOGIC;
+                                       SIGNAL in_sop  : IN    STD_LOGIC;
+                                       SIGNAL in_eop  : IN    STD_LOGIC;
+                                       SIGNAL out_gap : INOUT STD_LOGIC);  -- declare initial gap signal = '1'
+                                       
+  -- Verify the DUT output control (use for sop, eop)
+  PROCEDURE proc_dp_verify_ctrl(CONSTANT c_offset  : IN NATURAL;
+                                CONSTANT c_period  : IN NATURAL;
+                                CONSTANT c_str     : IN STRING;
+                                SIGNAL   clk       : IN STD_LOGIC;
+                                SIGNAL   verify_en : IN STD_LOGIC;
+                                SIGNAL   data      : IN STD_LOGIC_VECTOR;
+                                SIGNAL   valid     : IN STD_LOGIC;
+                                SIGNAL   ctrl      : IN STD_LOGIC);
+                                
+  -- Wait for stream valid
+  PROCEDURE proc_dp_stream_valid(SIGNAL clk      : IN  STD_LOGIC;
+                                 SIGNAL in_valid : IN  STD_LOGIC);
+  
+  -- Wait for stream valid AND sop
+  PROCEDURE proc_dp_stream_valid_sop(SIGNAL clk      : IN  STD_LOGIC;
+                                     SIGNAL in_valid : IN  STD_LOGIC;
+                                     SIGNAL in_sop   : IN  STD_LOGIC);
+  
+  -- Wait for stream valid AND eop
+  PROCEDURE proc_dp_stream_valid_eop(SIGNAL clk      : IN  STD_LOGIC;
+                                     SIGNAL in_valid : IN  STD_LOGIC;
+                                     SIGNAL in_eop   : IN  STD_LOGIC);
+  
+END tb_dp_pkg;
+
+
+PACKAGE BODY tb_dp_pkg IS
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Block data generator with feedforward throttle control
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_gen_block_data(CONSTANT c_nof_block_per_sync : IN    NATURAL;
+                                   CONSTANT c_block_size         : IN    NATURAL;
+                                   CONSTANT c_gap_size           : IN    NATURAL;
+                                   CONSTANT c_throttle_num       : IN    NATURAL;
+                                   CONSTANT c_throttle_den       : IN    NATURAL;
+                                   SIGNAL   rst                  : IN    STD_LOGIC;
+                                   SIGNAL   clk                  : IN    STD_LOGIC;
+                                   SIGNAL   sync_nr              : INOUT NATURAL;
+                                   SIGNAL   block_nr             : INOUT NATURAL;
+                                   SIGNAL   cnt_sync             : OUT   STD_LOGIC;
+                                   SIGNAL   cnt_val              : OUT   STD_LOGIC;
+                                   SIGNAL   cnt_dat              : INOUT STD_LOGIC_VECTOR) IS
+    CONSTANT c_start_delay : NATURAL := 10;
+    VARIABLE v_throttle    : NATURAL;
+  BEGIN
+    sync_nr  <= 0;
+    block_nr <= 0;
+    
+    cnt_sync <= '0';    
+    cnt_val  <= '0';
+    cnt_dat  <= (cnt_dat'RANGE=>'1');  -- -1, so first valid cnt_dat starts at 0
+    
+    -- allow some clock cycles before start after rst release
+    WAIT UNTIL rst='0';
+    FOR I IN 0 TO c_start_delay-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- output first sync
+    cnt_sync <= '1';
+    WAIT UNTIL rising_edge(clk);
+    cnt_sync <= '0';
+    FOR I IN 1 TO c_gap_size-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    WHILE TRUE LOOP
+      -- output block
+      IF c_throttle_num >= c_throttle_den THEN
+        -- no need to throttle, so cnt_val active during whole data block
+        FOR I IN 0 TO c_block_size-1 LOOP
+          cnt_val <= '1';
+          cnt_dat <= INCR_UVEC(cnt_dat, 1);
+          WAIT UNTIL rising_edge(clk);
+        END LOOP;
+      ELSE
+        -- throttle cnt_val, so c_throttle_num active cnt_val cycles per c_throttle_den cycles
+        FOR I IN 0 TO c_block_size/c_throttle_num-1 LOOP
+          FOR J IN 0 TO c_throttle_num-1 LOOP
+            cnt_val <= '1';
+            cnt_dat <= INCR_UVEC(cnt_dat, 1);
+            WAIT UNTIL rising_edge(clk);
+          END LOOP;
+          FOR J IN 0 TO c_throttle_den-c_throttle_num-1 LOOP
+            cnt_val <= '0';
+            WAIT UNTIL rising_edge(clk);
+          END LOOP;
+        END LOOP;
+      END IF;
+      cnt_val <= '0';
+      -- output sync for next block at first sample of gap
+      IF block_nr>0 AND ((block_nr + 1) MOD c_nof_block_per_sync)=0 THEN
+        cnt_sync <= '1';
+        sync_nr  <= sync_nr+1;
+      END IF;
+      WAIT UNTIL rising_edge(clk);
+      -- output rest of the gap
+      cnt_sync <= '0';
+      FOR I IN 1 TO c_gap_size-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+      -- next block
+      block_nr <= block_nr+1;
+    END LOOP;    
+  END proc_dp_gen_block_data;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Block data generator with ready flow control and symbols counter
+  -- . dependent on in_en and src_in.ready
+  -- . optional sync pulse at end of frame 
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_gen_block_data(CONSTANT c_ready_latency  : IN  NATURAL;    -- 0, 1 are supported by proc_dp_stream_ready_latency()
+                                   CONSTANT c_use_data       : IN  BOOLEAN;    -- when TRUE use data field, else use re, im fields, and keep unused fields at 'X'
+                                   CONSTANT c_data_w         : IN  NATURAL;    -- data width for the data, re and im fields
+                                   CONSTANT c_symbol_w       : IN  NATURAL;    -- c_data_w/c_symbol_w must be an integer
+                                   CONSTANT c_symbol_init    : IN  NATURAL;    -- init counter for symbols in data field
+                                   CONSTANT c_symbol_re_init : IN  NATURAL;    -- init counter for symbols in re field
+                                   CONSTANT c_symbol_im_init : IN  NATURAL;    -- init counter for symbols in im field
+                                   CONSTANT c_nof_symbols    : IN  NATURAL;    -- nof symbols per frame for the data, re and im fields
+                                   CONSTANT c_channel        : IN  NATURAL;    -- channel field
+                                   CONSTANT c_error          : IN  NATURAL;    -- error field
+                                   CONSTANT c_sync           : IN  STD_LOGIC;  -- when '1' issue sync pulse during this block
+                                   CONSTANT c_bsn            : IN  STD_LOGIC_VECTOR;  -- bsn field
+                                   SIGNAL   clk              : IN  STD_LOGIC;
+                                   SIGNAL   in_en            : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                                   SIGNAL   src_in           : IN  t_dp_siso;
+                                   SIGNAL   src_out          : OUT t_dp_sosi) IS
+    CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
+    CONSTANT c_div                  : NATURAL := c_nof_symbols   / c_nof_symbols_per_data;
+    CONSTANT c_mod                  : NATURAL := c_nof_symbols MOD c_nof_symbols_per_data;
+    CONSTANT c_empty                : NATURAL := sel_a_b(c_mod, c_nof_symbols_per_data - c_mod, 0);
+    CONSTANT c_nof_data             : NATURAL := sel_a_b(c_mod, 1, 0) + c_div;
+    VARIABLE v_data                 : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_init);
+    VARIABLE v_re                   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_re_init);
+    VARIABLE v_im                   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_im_init);
+  BEGIN
+    src_out <= c_dp_sosi_rst;
+    IF src_in.xon='1' THEN
+      -- Generate this block
+      src_out.bsn     <= RESIZE_DP_BSN(c_bsn);
+      src_out.empty   <= TO_DP_EMPTY(c_empty);
+      src_out.channel <= TO_DP_CHANNEL(c_channel);
+      src_out.err     <= TO_DP_ERROR(c_error);
+      IF c_use_data=TRUE  THEN src_out.data  <= RESIZE_DP_DATA(v_data);   END IF;
+      IF c_use_data=FALSE THEN src_out.re    <= RESIZE_DP_DSP_DATA(v_re); END IF;
+      IF c_use_data=FALSE THEN src_out.im    <= RESIZE_DP_DSP_DATA(v_im); END IF;
+      IF c_nof_data>1 THEN
+        -- . sop
+        proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+        -- . valid
+        FOR I IN 1 TO c_nof_data-2 LOOP
+          v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
+          v_re   := func_dp_data_incr(c_data_w, c_symbol_w, v_re);
+          v_im   := func_dp_data_incr(c_data_w, c_symbol_w, v_im);
+          IF c_use_data=TRUE  THEN src_out.data <= RESIZE_DP_DATA(v_data);   END IF;
+          IF c_use_data=FALSE THEN src_out.re   <= RESIZE_DP_DSP_DATA(v_re); END IF;
+          IF c_use_data=FALSE THEN src_out.im   <= RESIZE_DP_DSP_DATA(v_im); END IF;
+          proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+        END LOOP;
+        
+        -- . eop
+        v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
+        v_re   := func_dp_data_incr(c_data_w, c_symbol_w, v_re);
+        v_im   := func_dp_data_incr(c_data_w, c_symbol_w, v_im);
+        IF c_use_data=TRUE  THEN src_out.data <= RESIZE_DP_DATA(v_data);   END IF;
+        IF c_use_data=FALSE THEN src_out.re   <= RESIZE_DP_DSP_DATA(v_re); END IF;
+        IF c_use_data=FALSE THEN src_out.im   <= RESIZE_DP_DSP_DATA(v_im); END IF;
+        proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+      ELSE
+        -- . sop and eop, frame has only one word
+        proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+      END IF;
+    ELSE
+      -- Skip this block
+      proc_common_wait_some_cycles(clk, c_nof_data);
+    END IF;
+  END proc_dp_gen_block_data;
+  
+  
+  PROCEDURE proc_dp_gen_block_data(CONSTANT c_data_w         : IN  NATURAL;    -- data width for the data field
+                                   CONSTANT c_symbol_init    : IN  NATURAL;    -- init counter for the data in the data field
+                                   CONSTANT c_nof_symbols    : IN  NATURAL;    -- nof symbols per frame for the data fields
+                                   CONSTANT c_channel        : IN  NATURAL;    -- channel field
+                                   CONSTANT c_error          : IN  NATURAL;    -- error field
+                                   CONSTANT c_sync           : IN  STD_LOGIC;  -- when '1' issue sync pulse during this block
+                                   CONSTANT c_bsn            : IN  STD_LOGIC_VECTOR;  -- bsn field
+                                   SIGNAL   clk              : IN  STD_LOGIC;
+                                   SIGNAL   in_en            : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                                   SIGNAL   src_in           : IN  t_dp_siso;
+                                   SIGNAL   src_out          : OUT t_dp_sosi) IS
+  BEGIN
+    proc_dp_gen_block_data(1, TRUE, c_data_w, c_data_w, c_symbol_init, 0, 0, c_nof_symbols, c_channel, c_error, c_sync, c_bsn, clk, in_en, src_in, src_out);
+  END proc_dp_gen_block_data;
+                            
+         
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Handle stream ready signal
+  -- . output active when src_in is ready and in_en='1'
+  -- . only support RL=0 or 1, support for RL>1 requires keeping previous ready information in a STD_LOGIC_VECTOR(RL-1 DOWNTO 0).
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_stream_ready_latency(CONSTANT c_latency : IN  NATURAL;
+                                         SIGNAL   clk       : IN  STD_LOGIC;
+                                         SIGNAL   ready     : IN  STD_LOGIC;
+                                         SIGNAL   in_en     : IN  STD_LOGIC;
+                                         CONSTANT c_sync    : IN  STD_LOGIC;
+                                         CONSTANT c_valid   : IN  STD_LOGIC;
+                                         CONSTANT c_sop     : IN  STD_LOGIC;
+                                         CONSTANT c_eop     : IN  STD_LOGIC;
+                                         SIGNAL   out_sync  : OUT STD_LOGIC;
+                                         SIGNAL   out_valid : OUT STD_LOGIC;
+                                         SIGNAL   out_sop   : OUT STD_LOGIC;
+                                         SIGNAL   out_eop   : OUT STD_LOGIC) IS
+  BEGIN
+    -- Default no output
+    out_sync  <= '0';
+    out_valid <= '0';
+    out_sop   <= '0';
+    out_eop   <= '0';
+    
+    -- Skip cycles until in_en='1'
+    WHILE in_en='0' LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+    
+    -- Active output when ready
+    -- . RL = 0
+    IF c_latency=0 THEN
+      -- show the available output until acknowledge
+      out_sync  <= c_sync;
+      out_valid <= c_valid;
+      out_sop   <= c_sop;
+      out_eop   <= c_eop;
+      WAIT UNTIL rising_edge(clk);
+      WHILE ready /= '1' LOOP
+        WAIT UNTIL rising_edge(clk);
+      END LOOP;
+      -- ready has acknowledged the valid output
+    END IF;
+    
+    -- . RL = 1
+    IF c_latency=1 THEN
+      -- no valid output until request
+      WHILE ready /= '1' LOOP
+        WAIT UNTIL rising_edge(clk);
+      END LOOP;
+      -- ready has requested this valid output
+      out_sync  <= c_sync;
+      out_valid <= c_valid;
+      out_sop   <= c_sop;
+      out_eop   <= c_eop;
+      WAIT UNTIL rising_edge(clk);
+    END IF;
+    
+    -- Return with no active output
+    out_sync  <= '0';
+    out_valid <= '0';
+    out_sop   <= '0';
+    out_eop   <= '0';
+  END proc_dp_stream_ready_latency;
+
+  
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Initialize the data per symbol
+  -- . use big endian
+  -- . if c_data_w=32, c_symbol_w=8, init=3 then return 0x03040506
+  ------------------------------------------------------------------------------
+  FUNCTION func_dp_data_init(c_data_w, c_symbol_w, init : NATURAL) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
+    VARIABLE v_data                 : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+    VARIABLE v_sym                  : STD_LOGIC_VECTOR(c_symbol_w-1 DOWNTO 0);
+  BEGIN
+    v_data := (OTHERS=>'0');
+    v_sym  := TO_UVEC(init, c_symbol_w);
+    FOR I IN c_nof_symbols_per_data-1 DOWNTO 0 LOOP
+      v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := v_sym;
+      v_sym := INCR_UVEC(v_sym, 1);
+    END LOOP;
+    RETURN v_data;
+  END func_dp_data_init;
+  
+  
+  ------------------------------------------------------------------------------
+  -- FUNCTION: Increment the data per symbol
+  -- . use big endian
+  -- . if c_data_w=32, c_symbol_w=8 then 0x00010203 returns 0x04050607
+  -- . the actual data'LENGTH must be >= c_data_w, unused bits become 0
+  -- . c_data_w/c_symbol_w must be an integer
+  ------------------------------------------------------------------------------
+  FUNCTION func_dp_data_incr(c_data_w, c_symbol_w : NATURAL; data : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
+    VARIABLE v_data                 : STD_LOGIC_VECTOR(data'LENGTH-1 DOWNTO 0);
+    VARIABLE v_sym                  : STD_LOGIC_VECTOR(c_symbol_w-1 DOWNTO 0);
+  BEGIN
+    v_data := (OTHERS=>'0');
+    v_sym  := data(c_symbol_w-1 DOWNTO 0);
+    FOR I IN c_nof_symbols_per_data-1 DOWNTO 0 LOOP
+      v_sym := INCR_UVEC(v_sym, 1);
+      v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := v_sym;
+    END LOOP;
+    RETURN v_data;
+  END func_dp_data_incr;
+    
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate counter data with valid
+  -- . Output counter data dependent on in_en and src_in.ready
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency : IN  NATURAL;    -- 0, 1 are supported by proc_dp_stream_ready_latency()
+                             CONSTANT c_data_w        : IN  NATURAL;
+                             CONSTANT c_data_init     : IN  NATURAL;
+                             SIGNAL   rst             : IN  STD_LOGIC;
+                             SIGNAL   clk             : IN  STD_LOGIC;
+                             SIGNAL   in_en           : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                             SIGNAL   src_in          : IN  t_dp_siso;
+                             SIGNAL   src_out         : OUT t_dp_sosi) IS
+    VARIABLE v_data : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= TO_UVEC(c_data_init, c_data_w);
+  BEGIN
+    src_out      <= c_dp_sosi_rst;
+    src_out.data <= RESIZE_DP_DATA(v_data);
+    IF rst='0' THEN
+      WAIT UNTIL rising_edge(clk);
+      WHILE TRUE LOOP
+        src_out.data <= RESIZE_DP_DATA(v_data);
+        proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+        v_data := INCR_UVEC(v_data, 1);
+      END LOOP;
+    END IF;
+  END proc_dp_gen_data;
+
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate counter data with valid
+  -- . Output counter data dependent on in_en and src_in.ready
+  -- . with maximum count value
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_gen_data(CONSTANT c_ready_latency   : IN  NATURAL; 
+                             CONSTANT c_data_w          : IN  NATURAL;
+                             CONSTANT c_data_init       : IN  NATURAL;
+                             CONSTANT c_data_max        : IN  NATURAL; 
+                             SIGNAL   rst               : IN  STD_LOGIC;
+                             SIGNAL   clk               : IN  STD_LOGIC;
+                             SIGNAL   in_en             : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                             SIGNAL   src_in            : IN  t_dp_siso;
+                             SIGNAL   src_out           : OUT t_dp_sosi) IS
+    VARIABLE v_cnt     : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= TO_UVEC(c_data_init, c_data_w);
+  BEGIN
+    src_out         <= c_dp_sosi_rst;
+    src_out.data    <= RESIZE_DP_DATA(v_cnt);
+    IF rst='0' THEN
+      WAIT UNTIL rising_edge(clk);
+      WHILE TRUE LOOP
+        src_out.data    <= RESIZE_DP_DATA(v_cnt);
+        proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+        IF TO_UINT(v_cnt)=c_data_max THEN
+          v_cnt := TO_UVEC(c_data_init, c_data_w);
+        ELSE
+          v_cnt := INCR_UVEC(v_cnt, 1);
+        END IF;
+      END LOOP;
+    END IF;
+  END proc_dp_gen_data;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Generate a frame with symbols counter
+  -- . dependent on in_en and src_in.ready
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_gen_frame(CONSTANT c_ready_latency : IN  NATURAL;    -- 0, 1 are supported by proc_dp_stream_ready_latency()
+                              CONSTANT c_data_w        : IN  NATURAL;
+                              CONSTANT c_symbol_w      : IN  NATURAL;    -- c_data_w/c_symbol_w must be an integer
+                              CONSTANT c_symbol_init   : IN  NATURAL;
+                              CONSTANT c_nof_symbols   : IN  NATURAL;
+                              CONSTANT c_bsn           : IN  NATURAL;
+                              CONSTANT c_sync          : IN  STD_LOGIC;
+                              SIGNAL   clk             : IN  STD_LOGIC;
+                              SIGNAL   in_en           : IN  STD_LOGIC;  -- when '0' then no valid output even when src_in is ready
+                              SIGNAL   src_in          : IN  t_dp_siso;
+                              SIGNAL   src_out         : OUT t_dp_sosi) IS
+    CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;
+    CONSTANT c_div                  : NATURAL := c_nof_symbols   / c_nof_symbols_per_data;
+    CONSTANT c_mod                  : NATURAL := c_nof_symbols MOD c_nof_symbols_per_data;
+    CONSTANT c_empty                : NATURAL := sel_a_b(c_mod, c_nof_symbols_per_data - c_mod, 0);
+    CONSTANT c_nof_data             : NATURAL := sel_a_b(c_mod, 1, 0) + c_div;
+    VARIABLE v_data                 : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0):= func_dp_data_init(c_data_w, c_symbol_w, c_symbol_init);
+  BEGIN
+    src_out       <= c_dp_sosi_rst;
+    src_out.bsn   <= TO_DP_BSN(c_bsn);
+    src_out.empty <= TO_DP_EMPTY(c_empty);
+    src_out.data  <= RESIZE_DP_DATA(v_data);
+    IF c_nof_data>1 THEN
+      -- . sop
+      proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+      -- . valid
+      FOR I IN 1 TO c_nof_data-2 LOOP
+        v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
+        src_out.data <= RESIZE_DP_DATA(v_data);
+        proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '0', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+      END LOOP;
+      -- . eop
+      v_data := func_dp_data_incr(c_data_w, c_symbol_w, v_data);
+      src_out.data <= RESIZE_DP_DATA(v_data);
+      proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, '0', '1', '0', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+    ELSE
+      -- . sop and eop, frame has only one word
+      proc_dp_stream_ready_latency(c_ready_latency, clk, src_in.ready, in_en, c_sync, '1', '1', '1', src_out.sync, src_out.valid, src_out.sop, src_out.eop);
+    END IF;
+    src_out.sync  <= '0';
+    src_out.valid <= '0';
+    src_out.sop   <= '0';
+    src_out.eop   <= '0';
+  END proc_dp_gen_frame;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Input data counter
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_cnt_dat(SIGNAL rst     : IN    STD_LOGIC;
+                            SIGNAL clk     : IN    STD_LOGIC;
+                            SIGNAL in_en   : IN    STD_LOGIC;
+                            SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rst='1' THEN
+      cnt_dat <= (cnt_dat'RANGE=>'0');
+    ELSIF rising_edge(clk) THEN
+      IF in_en='1' THEN
+        cnt_dat <= STD_LOGIC_VECTOR(UNSIGNED(cnt_dat)+1);
+      END IF;
+    END IF;
+  END proc_dp_cnt_dat;
+  
+  PROCEDURE proc_dp_cnt_dat(SIGNAL rst     : IN    STD_LOGIC;
+                            SIGNAL clk     : IN    STD_LOGIC;
+                            SIGNAL in_en   : IN    STD_LOGIC;
+                            SIGNAL cnt_val : INOUT STD_LOGIC;
+                            SIGNAL cnt_dat : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rst='1' THEN
+      cnt_val <= '0';
+      cnt_dat <= (cnt_dat'RANGE=>'0');
+    ELSIF rising_edge(clk) THEN
+      cnt_val <= '0';
+      IF in_en='1' THEN
+        cnt_val <= '1';
+        cnt_dat <= STD_LOGIC_VECTOR(UNSIGNED(cnt_dat)+1);
+      END IF;
+    END IF;
+  END proc_dp_cnt_dat;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Transmit data
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_tx_data(CONSTANT c_ready_latency : IN    NATURAL;
+                            SIGNAL   rst             : IN    STD_LOGIC;
+                            SIGNAL   clk             : IN    STD_LOGIC;
+                            SIGNAL   cnt_val         : IN    STD_LOGIC;
+                            SIGNAL   cnt_dat         : IN    STD_LOGIC_VECTOR;
+                            SIGNAL   tx_data         : INOUT t_dp_data_arr;
+                            SIGNAL   tx_val          : INOUT STD_LOGIC_VECTOR;
+                            SIGNAL   out_data        : OUT   STD_LOGIC_VECTOR;
+                            SIGNAL   out_val         : OUT   STD_LOGIC) IS
+    CONSTANT c_void : NATURAL := sel_a_b(c_ready_latency, 1, 0);  -- used to avoid empty range VHDL warnings when c_ready_latency=0
+  BEGIN
+    -- TX data array for output ready latency [c_ready_latency], index [0] for zero latency combinatorial
+    tx_data(0) <= cnt_dat;
+    tx_val( 0) <= cnt_val;
+    
+    IF rst='1' THEN
+      tx_data(1 TO c_ready_latency+c_void) <= (1 TO c_ready_latency+c_void=>(OTHERS=>'0'));
+      tx_val( 1 TO c_ready_latency+c_void) <= (1 TO c_ready_latency+c_void=>'0');
+    ELSIF rising_edge(clk) THEN
+      tx_data(1 TO c_ready_latency+c_void) <= tx_data(0 TO c_ready_latency+c_void-1);
+      tx_val( 1 TO c_ready_latency+c_void) <= tx_val( 0 TO c_ready_latency+c_void-1);
+    END IF;
+    
+    out_data <= tx_data(c_ready_latency);
+    out_val  <= tx_val(c_ready_latency);
+  END proc_dp_tx_data;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Transmit data control (use for sop, eop)
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_tx_ctrl(CONSTANT c_offset : IN  NATURAL;
+                            CONSTANT c_period : IN  NATURAL;
+                            SIGNAL   data     : IN  STD_LOGIC_VECTOR;
+                            SIGNAL   valid    : IN  STD_LOGIC;
+                            SIGNAL   ctrl     : OUT STD_LOGIC) IS
+    VARIABLE v_data : INTEGER;
+  BEGIN
+    v_data := TO_UINT(data);
+    ctrl <= '0';
+    IF valid='1' AND ((v_data-c_offset) MOD c_period)=0 THEN
+      ctrl <= '1';
+    END IF;
+  END proc_dp_tx_ctrl;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Define test sync interval
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_sync_interval(SIGNAL clk  : IN  STD_LOGIC;
+                                  SIGNAL sync : OUT STD_LOGIC) IS
+  BEGIN
+    sync <= '0';
+    FOR I IN 1 TO c_dp_sync_interval-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    sync <= '1';
+    WAIT UNTIL rising_edge(clk);
+  END proc_dp_sync_interval;
+
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Stimuli for cnt_en
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_count_en(SIGNAL rst    : IN    STD_LOGIC;
+                             SIGNAL clk    : IN    STD_LOGIC;
+                             SIGNAL sync   : IN    STD_LOGIC;
+                             SIGNAL lfsr   : INOUT STD_LOGIC_VECTOR;
+                             SIGNAL state  : OUT   t_dp_state_enum;
+                             SIGNAL done   : OUT   STD_LOGIC;
+                             SIGNAL tb_end : OUT   STD_LOGIC;
+                             SIGNAL cnt_en : OUT   STD_LOGIC) IS
+  BEGIN
+    -- The counter operates at zero latency
+    state <= s_idle;
+    done <= '0';
+    tb_end <= '0';
+    cnt_en <= '0';
+    WAIT UNTIL rst='0';
+    WAIT UNTIL rising_edge(clk);
+    -- The cnt_val may be asserted for every active in_ready, but als support
+    -- cnt_val not asserted for every asserted in_ready.
+
+    ----------------------------------------------------------------------------
+    -- Interval 1
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_both_active;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 2
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_pull_down_out_ready;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 3
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_pull_down_cnt_en;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 2 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 3 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 4 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 5 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 6 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 7 cycle
+    cnt_en <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 4
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_toggle_out_ready;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 5
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_toggle_cnt_en;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1-1 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1-2 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    -- . 2-1 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 2-2 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1-3 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    -- . 3-1 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    -- . 2-3 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    -- . 3-2 toggle
+    cnt_en <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      cnt_en <= '1';
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Interval 6
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_toggle_both;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    FOR I IN 1 TO c_dp_nof_both LOOP
+      cnt_en <= '0';
+      FOR J IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+      cnt_en <= '1';
+      FOR J IN I TO c_dp_nof_both LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    END LOOP;
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 7
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_pulse_cnt_en;
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    FOR I IN 1 TO 15 LOOP
+      FOR J IN 1 TO 15 LOOP
+        cnt_en <= '0';
+        FOR K IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+        cnt_en <= '1';
+        WAIT UNTIL rising_edge(clk);
+      END LOOP;
+      FOR J IN 1 TO 20 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    END LOOP;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Interval 8
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_chirp_out_ready;
+    cnt_en <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Interval 9
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_random;
+    cnt_en <= '1';
+    
+    FOR I IN 0 TO c_dp_sync_interval - c_dp_test_interval LOOP
+      lfsr <= func_common_random(lfsr);
+      cnt_en <= lfsr(lfsr'HIGH);
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Done
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    state <= s_done;
+    WAIT UNTIL rising_edge(clk);
+    cnt_en <= '0';
+    
+    -- pulse done
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    done <= '1';
+    WAIT UNTIL rising_edge(clk);
+    done <= '0';
+    
+    ----------------------------------------------------------------------------
+    -- Testbench end
+    ----------------------------------------------------------------------------
+    -- set tb_end
+    WAIT UNTIL sync='1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    tb_end <= '1';
+    WAIT;
+  END proc_dp_count_en;
+
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Stimuli for out_ready
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_out_ready(SIGNAL rst       : IN    STD_LOGIC;
+                              SIGNAL clk       : IN    STD_LOGIC;
+                              SIGNAL sync      : IN    STD_LOGIC;
+                              SIGNAL lfsr      : INOUT STD_LOGIC_VECTOR;
+                              SIGNAL out_ready : OUT   STD_LOGIC) IS
+  BEGIN
+    out_ready <= '0';
+    WAIT UNTIL rst='0';
+    WAIT UNTIL rising_edge(clk);
+
+    ----------------------------------------------------------------------------
+    -- Interval 1 : Assert both cnt_en and out_ready
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 2 : Make out_ready low for 1 or more cycles
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 2 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 3 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 4 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 5 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 6 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    -- . 7 cycle
+    out_ready <= '0';
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    WAIT UNTIL rising_edge(clk);
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Interval 3
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 4 : Toggle out_ready for 1 or more cycles
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1-1 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1-2 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 2-1 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 2-2 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 1-3 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    -- . 3-1 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 2-3 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . 3-2 toggle
+    out_ready <= '0';
+    FOR I IN 1 TO c_dp_nof_toggle LOOP
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '0';
+      WAIT UNTIL rising_edge(clk);
+      WAIT UNTIL rising_edge(clk);
+      out_ready <= '1';
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 5
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 6
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    FOR I IN 1 TO c_dp_nof_both LOOP
+      out_ready <= '0';
+      FOR J IN I TO c_dp_nof_both LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+      out_ready <= '1';
+      FOR J IN 1 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    END LOOP;
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 7
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    ----------------------------------------------------------------------------
+    -- Interval 8 : Chirp out_ready
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+
+    -- . slow toggle
+    out_ready <= '0';
+    FOR I IN 0 TO c_dp_nof_toggle LOOP
+      out_ready <= '0';
+      FOR J IN 0 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+      out_ready <= '1';
+      FOR J IN 0 TO I LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    END LOOP;
+    out_ready <= '1';
+    FOR I IN 0 TO c_dp_test_interval LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Interval 9 : Random
+    ----------------------------------------------------------------------------
+    WAIT UNTIL sync='1';
+    out_ready <= '1';
+    
+    FOR I IN 0 TO c_dp_sync_interval - c_dp_test_interval LOOP
+      lfsr <= func_common_random(lfsr);
+      out_ready <= lfsr(lfsr'HIGH);
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+    
+    ----------------------------------------------------------------------------
+    -- Done
+    ----------------------------------------------------------------------------
+    WAIT;
+  END proc_dp_out_ready;
+
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: DUT output verify enable
+  ------------------------------------------------------------------------------
+ 
+  -- Fixed delay until verify_en active
+  PROCEDURE proc_dp_verify_en(CONSTANT c_delay   : IN  NATURAL;
+                              SIGNAL   rst       : IN  STD_LOGIC;
+                              SIGNAL   clk       : IN  STD_LOGIC;
+                              SIGNAL   sync      : IN  STD_LOGIC;
+                              SIGNAL   verify_en : OUT STD_LOGIC) IS
+  BEGIN
+    verify_en <= '0';
+    WAIT UNTIL rst='0';
+    WAIT UNTIL rising_edge(clk);
+    
+    WAIT UNTIL sync='1';
+    -- Use c_delay delay before enabling the p_verify.
+    FOR I IN 0 TO c_delay LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    
+    verify_en <= '1';
+    WAIT;
+  END proc_dp_verify_en;
+  
+  
+  -- Dynamicly depend on first valid data to make verify_en active
+  PROCEDURE proc_dp_verify_en(CONSTANT c_continuous : IN  BOOLEAN;
+                              SIGNAL   clk          : IN  STD_LOGIC;
+                              SIGNAL   valid        : IN  STD_LOGIC;
+                              SIGNAL   sop          : IN  STD_LOGIC;
+                              SIGNAL   eop          : IN  STD_LOGIC;
+                              SIGNAL   verify_en    : OUT STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF c_continuous=TRUE THEN
+        -- Verify across frames (so enable data verify after the first data has been output)
+        IF valid='1' THEN
+          verify_en <= '1';
+        END IF;
+      ELSE
+        -- Verify only per frame (so re-enable data verify after the every sop)
+        IF eop='1' THEN
+          verify_en <= '0';
+        ELSIF sop='1' THEN
+          verify_en <= '1';
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_en;
+  
+  -- Run and verify for some cycles
+  PROCEDURE proc_dp_verify_run_some_cycles(CONSTANT nof_pre_clk    : IN   NATURAL;
+                                           CONSTANT nof_verify_clk : IN   NATURAL;
+                                           CONSTANT nof_post_clk   : IN   NATURAL;
+                                           SIGNAL   clk            : IN   STD_LOGIC;
+                                           SIGNAL   verify_en      : OUT  STD_LOGIC) IS
+  BEGIN
+    proc_common_wait_some_cycles(clk, nof_pre_clk);
+    verify_en <= '1';
+    proc_common_wait_some_cycles(clk, nof_verify_clk);
+    verify_en <= '0';
+    proc_common_wait_some_cycles(clk, nof_post_clk);
+  END proc_dp_verify_run_some_cycles;
+    
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the expected value
+  ------------------------------------------------------------------------------
+  --  e.g. to check that a test has ran at all
+  PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
+                                 CONSTANT mode  : IN t_dp_value_enum;
+                                 SIGNAL   clk   : IN STD_LOGIC;
+                                 SIGNAL   en    : IN STD_LOGIC;
+                                 SIGNAL   exp   : IN STD_LOGIC_VECTOR;  
+                                 SIGNAL   res   : IN STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF en='1' THEN
+        IF mode = e_equal AND UNSIGNED(res) /= UNSIGNED(exp) THEN
+          REPORT "DP : Wrong " & c_str & " result value" SEVERITY ERROR;
+        END IF;
+        IF mode = e_at_least AND UNSIGNED(res) < UNSIGNED(exp) THEN
+          REPORT "DP : Wrong " & c_str & " result value too small" SEVERITY ERROR;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_value;
+
+  PROCEDURE proc_dp_verify_value(CONSTANT mode : IN t_dp_value_enum;
+                                 SIGNAL   clk  : IN STD_LOGIC;
+                                 SIGNAL   en   : IN STD_LOGIC;
+                                 SIGNAL   exp  : IN STD_LOGIC_VECTOR;  
+                                 SIGNAL   res  : IN STD_LOGIC_VECTOR) IS
+  BEGIN
+    proc_dp_verify_value("", mode, clk, en, exp, res);
+  END proc_dp_verify_value;
+  
+  PROCEDURE proc_dp_verify_value(CONSTANT c_str : IN STRING;
+                                 SIGNAL   clk   : IN STD_LOGIC;
+                                 SIGNAL   en    : IN STD_LOGIC;
+                                 SIGNAL   exp   : IN STD_LOGIC;  
+                                 SIGNAL   res   : IN STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF en='1' THEN
+        IF res /= exp THEN
+          REPORT "DP : Wrong " & c_str & " result value" SEVERITY ERROR;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_value;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify output global and local BSN
+  ------------------------------------------------------------------------------
+  -- Verify BSN:
+  -- . incrementing or replicated global BSN
+  -- . incrementing local BSN that starts at 1
+  --
+  --               _              _              _              _             
+  --  sync      __| |____________| |____________| |____________| |____________
+  --               _    _    _    _    _    _    _    _    _    _    _    _
+  --   sop      __| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__  c_block_per_sync = 3
+  --
+  -- c_use_local_bsn = FALSE:
+  --                                                                            c_nof_replicated_global_bsn = 1
+  --        bsn    3    4    5    6    7    8    9    10   11   12   13   14    c_global_bsn_increment = 1
+  --        bsn    3    5    7    9   11   13   15    17   19   21   22   23    c_global_bsn_increment = 2
+  --
+  -- c_use_local_bsn = TRUE:
+  --
+  -- global bsn    3              4              5               6              c_global_bsn_increment = 1, c_nof_replicated_global_bsn = 1
+  -- global bsn    3              6              9              12              c_global_bsn_increment = 3, c_nof_replicated_global_bsn = 1
+  -- global bsn    3              3              9               9              c_global_bsn_increment = 6, c_nof_replicated_global_bsn = 2
+  --  local bsn    -    1    2    -    1    2    -    1    2     -    1    2    range 1:c_block_per_sync-1
+  --        
+  -- The verify_en should initially be set to '0' and gets enabled when
+  -- sufficient BSN history is available to do the verification.
+  --
+  PROCEDURE proc_dp_verify_bsn(CONSTANT c_use_local_bsn             : IN    BOOLEAN;    -- use local BSN or only use global BSN
+                               CONSTANT c_global_bsn_increment      : IN    POSITIVE;   -- increment per global BSN
+                               CONSTANT c_nof_replicated_global_bsn : IN    POSITIVE;   -- number of replicated global BSN
+                               CONSTANT c_block_per_sync            : IN    POSITIVE;   -- of sop/eop blocks per sync interval
+                               SIGNAL   clk                         : IN    STD_LOGIC;
+                               SIGNAL   out_sync                    : IN    STD_LOGIC;
+                               SIGNAL   out_sop                     : IN    STD_LOGIC;
+                               SIGNAL   out_bsn                     : IN    STD_LOGIC_VECTOR;
+                               SIGNAL   verify_en                   : INOUT STD_LOGIC;  -- initialize '0', becomes '1' when bsn verification starts
+                               SIGNAL   cnt_replicated_global_bsn   : INOUT NATURAL;
+                               SIGNAL   prev_out_bsn_global         : INOUT STD_LOGIC_VECTOR;
+                               SIGNAL   prev_out_bsn_local          : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- out_sop must be active, because only then out_bsn will differ from the previous out_bsn
+      IF out_sop='1' THEN
+        IF c_use_local_bsn=FALSE THEN
+          ------------------------------------------------------------------
+          -- Only use global BSN
+          ------------------------------------------------------------------
+          prev_out_bsn_global <= out_bsn;
+          -- verify
+          IF  out_sync='1' THEN
+            verify_en <= '1';
+          END IF;
+          IF verify_en='1' THEN
+            ASSERT UNSIGNED(out_bsn) = UNSIGNED(prev_out_bsn_global)+c_global_bsn_increment REPORT "DP : Wrong BSN increment" SEVERITY ERROR;
+          END IF;
+        ELSE
+          ------------------------------------------------------------------
+          -- Use global and local BSN
+          ------------------------------------------------------------------
+          IF out_sync='1' THEN
+            prev_out_bsn_global <= out_bsn;
+            IF UNSIGNED(out_bsn) /= UNSIGNED(prev_out_bsn_global) THEN
+              verify_en <= '1';                -- wait until after last replicated global bsn
+              cnt_replicated_global_bsn <= 0;
+            ELSE
+              cnt_replicated_global_bsn <= cnt_replicated_global_bsn + 1;
+            END IF;
+            prev_out_bsn_local <= TO_UVEC(0, prev_out_bsn_global'LENGTH);
+          ELSE
+            prev_out_bsn_local <= out_bsn;
+          END IF;
+          -- verify
+          IF verify_en='1' THEN
+            IF out_sync='1' THEN
+              IF UNSIGNED(out_bsn) /= UNSIGNED(prev_out_bsn_global) THEN
+                ASSERT cnt_replicated_global_bsn=c_nof_replicated_global_bsn-1 REPORT "DP : Wrong number of replicated global BSN" SEVERITY ERROR;
+                ASSERT UNSIGNED(out_bsn)=UNSIGNED(prev_out_bsn_global)+c_global_bsn_increment REPORT "DP : Wrong global BSN increment" SEVERITY ERROR;
+              ELSE
+                ASSERT UNSIGNED(out_bsn)=UNSIGNED(prev_out_bsn_global) REPORT "DP : Wrong replicated global BSN" SEVERITY ERROR;
+              END IF;
+              ASSERT UNSIGNED(prev_out_bsn_local)=c_block_per_sync-1 REPORT "DP : Wrong last local BSN in sync interval" SEVERITY ERROR;
+            ELSE
+              ASSERT UNSIGNED(out_bsn)=UNSIGNED(prev_out_bsn_local)+1 REPORT "DP : Wrong local BSN increment" SEVERITY ERROR;
+            END IF;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_bsn;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output data
+  ------------------------------------------------------------------------------
+  
+  -- Verify incrementing data
+  -- . wrap at c_out_data_max when >0, else no wrap when c_out_data_max=0
+  -- . default increment by 1, but also allow an increment by c_out_data_gap
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_ready_latency : IN    NATURAL;
+                                CONSTANT c_out_data_max  : IN    UNSIGNED;
+                                CONSTANT c_out_data_gap  : IN    UNSIGNED;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_ready       : IN    STD_LOGIC;  -- only needed when c_ready_latency = 0
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- out_val must be active, because only the out_data will it differ from the previous out_data
+      IF out_val='1' THEN
+        -- for ready_latency > 0 out_val indicates new data
+        -- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
+        IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
+          IF c_out_data_max=0 THEN
+            prev_out_data <= out_data;                           -- no wrap detection
+          ELSIF UNSIGNED(out_data)<c_out_data_max THEN
+            prev_out_data <= out_data;                           -- no wrap
+          ELSE
+            prev_out_data <= TO_SVEC(-1, prev_out_data'LENGTH);  -- do wrap
+          END IF;
+          IF verify_en='1' THEN
+            IF UNSIGNED(out_data) /= UNSIGNED(prev_out_data)+1 AND                               -- check increment +1
+               UNSIGNED(out_data) /= UNSIGNED(prev_out_data)+c_out_data_gap AND                  -- increment +c_out_data_gap
+               UNSIGNED(out_data) /= UNSIGNED(prev_out_data)+c_out_data_gap-c_out_data_max THEN  -- increment +c_out_data_gap wrapped
+              REPORT "DP : Wrong out_data " & c_str & " count" SEVERITY ERROR;
+            END IF;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_data;
+  
+  -- Verify incrementing data that wraps in range 0 ... c_out_data_max
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_ready_latency : IN    NATURAL;
+                                CONSTANT c_out_data_max  : IN    UNSIGNED;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_ready       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    proc_dp_verify_data(c_str, c_ready_latency, c_out_data_max, TO_UNSIGNED(1,1), clk, verify_en, out_ready, out_val, out_data, prev_out_data);
+  END proc_dp_verify_data;
+  
+  -- Verify incrementing data
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_ready_latency : IN    NATURAL;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_ready       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    proc_dp_verify_data(c_str, c_ready_latency, TO_UNSIGNED(0,1), TO_UNSIGNED(1,1), clk, verify_en, out_ready, out_val, out_data, prev_out_data);
+  END proc_dp_verify_data;
+  
+  -- Verify incrementing data with RL > 0 or no flow control
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_out_data_max  : IN    UNSIGNED;
+                                CONSTANT c_out_data_gap  : IN    UNSIGNED;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
+    proc_dp_verify_data(c_str, 1, c_out_data_max, c_out_data_gap, clk, verify_en, out_val, out_val, out_data, prev_out_data);
+  END proc_dp_verify_data;
+  
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_out_data_max  : IN    NATURAL;
+                                CONSTANT c_out_data_gap  : IN    NATURAL;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+    CONSTANT c_data_w : NATURAL := out_data'LENGTH;
+  BEGIN
+    proc_dp_verify_data(c_str, TO_UNSIGNED(c_out_data_max, c_data_w), TO_UNSIGNED(c_out_data_gap, c_data_w), clk, verify_en, out_val, out_data, prev_out_data);
+  END proc_dp_verify_data;
+  
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                CONSTANT c_out_data_max  : IN    NATURAL;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+    CONSTANT c_data_w : NATURAL := out_data'LENGTH;
+  BEGIN
+    proc_dp_verify_data(c_str, TO_UNSIGNED(c_out_data_max, c_data_w), TO_UNSIGNED(1, 1), clk, verify_en, out_val, out_data, prev_out_data);
+  END proc_dp_verify_data;
+  
+  PROCEDURE proc_dp_verify_data(CONSTANT c_str           : IN    STRING;
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   out_val         : IN    STD_LOGIC;
+                                SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+  BEGIN
+    -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
+    proc_dp_verify_data(c_str, 1, TO_UNSIGNED(0,1), TO_UNSIGNED(1,1), clk, verify_en, out_val, out_val, out_data, prev_out_data);
+  END proc_dp_verify_data;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify incrementing symbols in data
+  -- . for c_data_w = c_symbol_w proc_dp_verify_symbols() = proc_dp_verify_data()
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_symbols(CONSTANT c_ready_latency : IN    NATURAL;
+                                   CONSTANT c_data_w        : IN    NATURAL;
+                                   CONSTANT c_symbol_w      : IN    NATURAL;
+                                   SIGNAL   clk             : IN    STD_LOGIC;
+                                   SIGNAL   verify_en       : IN    STD_LOGIC;
+                                   SIGNAL   out_ready       : IN    STD_LOGIC;
+                                   SIGNAL   out_val         : IN    STD_LOGIC;
+                                   SIGNAL   out_eop         : IN    STD_LOGIC;
+                                   SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                   SIGNAL   out_empty       : IN    STD_LOGIC_VECTOR;
+                                   SIGNAL   prev_out_data   : INOUT STD_LOGIC_VECTOR) IS
+    CONSTANT c_nof_symbols_per_data : NATURAL := c_data_w/c_symbol_w;  -- must be an integer
+    CONSTANT c_empty_w              : NATURAL := ceil_log2(c_nof_symbols_per_data);
+    VARIABLE v_data                 : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+    VARIABLE v_symbol               : STD_LOGIC_VECTOR(c_symbol_w-1 DOWNTO 0);
+    VARIABLE v_empty                : NATURAL;
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- out_val must be active, because only the out_data will it differ from the previous out_data
+      IF out_val='1' THEN
+        -- for ready_latency > 0 out_val indicates new data
+        -- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
+        IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
+          prev_out_data <= out_data;
+          IF verify_en='1' THEN
+            v_data  := prev_out_data(c_data_w-1 DOWNTO 0);
+            FOR I IN 0 TO c_nof_symbols_per_data-1 LOOP
+              v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := INCR_UVEC(v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w), c_nof_symbols_per_data);  -- increment each symbol
+            END LOOP;
+            IF out_eop='0' THEN
+              IF UNSIGNED(out_data) /= UNSIGNED(v_data) THEN
+                REPORT "DP : Wrong out_data symbols count" SEVERITY ERROR;
+              END IF;
+            ELSE
+              v_empty := TO_UINT(out_empty(c_empty_w-1 DOWNTO 0));
+              IF UNSIGNED(out_data(c_data_w-1 DOWNTO v_empty*c_symbol_w)) /= UNSIGNED(v_data(c_data_w-1 DOWNTO v_empty*c_symbol_w)) THEN
+                REPORT "DP : Wrong out_data symbols count at eop" SEVERITY ERROR;
+              END IF;
+              IF v_empty>0 THEN
+                -- adjust prev_out_data for potentially undefined empty symbols in out_data
+                v_symbol := v_data((v_empty+1)*c_symbol_w-1 DOWNTO v_empty*c_symbol_w);  -- last valid symbol
+                FOR I IN 0 TO c_nof_symbols_per_data-1 LOOP
+                  v_data((I+1)*c_symbol_w-1 DOWNTO I*c_symbol_w) := v_symbol;   -- put the last valid symbol at the end of the v_data
+                  v_symbol := INCR_UVEC(v_symbol, -1);                          -- decrement each symbol towards the beginning of v_data
+                END LOOP;
+                prev_out_data <= v_data;
+              END IF;
+            END IF;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_symbols;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output data with empty
+  -- . account for stream empty
+  -- . support last word replace (e.g. by a CRC instead of the count, or use
+  --   c_last_word=out_data for no replace)
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_data_empty(CONSTANT c_ready_latency : IN    NATURAL;
+                                      CONSTANT c_last_word     : IN    NATURAL;
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   verify_en       : IN    STD_LOGIC;
+                                      SIGNAL   out_ready       : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop_1       : INOUT STD_LOGIC;
+                                      SIGNAL   out_eop_2       : INOUT STD_LOGIC;
+                                      SIGNAL   out_data        : IN    STD_LOGIC_VECTOR;
+                                      SIGNAL   out_data_1      : INOUT STD_LOGIC_VECTOR;
+                                      SIGNAL   out_data_2      : INOUT STD_LOGIC_VECTOR;
+                                      SIGNAL   out_data_3      : INOUT STD_LOGIC_VECTOR;
+                                      SIGNAL   out_empty       : IN    STD_LOGIC_VECTOR;
+                                      SIGNAL   out_empty_1     : INOUT STD_LOGIC_VECTOR) IS
+    VARIABLE v_last_word    : STD_LOGIC_VECTOR(out_data'RANGE);
+    VARIABLE v_ref_data     : STD_LOGIC_VECTOR(out_data'RANGE);
+    VARIABLE v_empty_data   : STD_LOGIC_VECTOR(out_data'RANGE);
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- out_val must be active, because only then out_data will differ from the previous out_data
+      IF out_val='1' THEN
+        -- for ready_latency > 0 out_val indicates new data
+        -- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
+        IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
+          -- default expected data
+          out_data_1  <= out_data;
+          out_data_2  <= out_data_1;
+          out_data_3  <= out_data_2;
+          out_empty_1 <= out_empty;
+          out_eop_1   <= out_eop;
+          out_eop_2   <= out_eop_1;
+          IF verify_en='1' THEN
+            -- assume sufficient valid cycles between eop and sop, so no need to check for out_sop with regard to eop empty
+            IF out_eop='0' AND out_eop_1='0' AND out_eop_2='0'THEN
+              -- verify out_data from eop-n to eop-2 and from eop+1 to eop+n, n>2
+              v_ref_data := INCR_UVEC(out_data_2, 1);
+              IF UNSIGNED(out_data_1) /= UNSIGNED(v_ref_data) THEN
+                REPORT "DP : Wrong out_data count" SEVERITY ERROR;
+              END IF;
+            ELSE
+              -- the empty and crc replace affect data at eop_1 and eop, so need to check data from eop-2 to eop-1 to eop to eop+1
+              v_last_word := TO_UVEC(c_last_word, out_data'LENGTH);
+              IF out_eop='1' THEN
+                -- verify out_data at eop
+                CASE TO_INTEGER(UNSIGNED(out_empty)) IS
+                  WHEN 0 => v_empty_data := v_last_word;
+                  WHEN 1 => v_empty_data := v_last_word(3*c_byte_w-1 DOWNTO 0) & c_slv0(1*c_byte_w-1 DOWNTO 0);
+                  WHEN 2 => v_empty_data := v_last_word(2*c_byte_w-1 DOWNTO 0) & c_slv0(2*c_byte_w-1 DOWNTO 0);
+                  WHEN 3 => v_empty_data := v_last_word(1*c_byte_w-1 DOWNTO 0) & c_slv0(3*c_byte_w-1 DOWNTO 0);
+                  WHEN OTHERS => NULL;
+                END CASE;
+                IF UNSIGNED(out_data) /= UNSIGNED(v_empty_data) THEN
+                  REPORT "DP : Wrong out_data count at eop" SEVERITY ERROR;
+                END IF;
+              ELSIF out_eop_1='1' THEN
+                -- verify out_data from eop-2 to eop-1
+                v_ref_data := INCR_UVEC(out_data_3, 1);
+                CASE TO_INTEGER(UNSIGNED(out_empty_1)) IS
+                  WHEN 0 => v_empty_data := v_ref_data;
+                  WHEN 1 => v_empty_data := v_ref_data(4*c_byte_w-1 DOWNTO 1*c_byte_w) & v_last_word(4*c_byte_w-1 DOWNTO 3*c_byte_w);
+                  WHEN 2 => v_empty_data := v_ref_data(4*c_byte_w-1 DOWNTO 2*c_byte_w) & v_last_word(4*c_byte_w-1 DOWNTO 2*c_byte_w);
+                  WHEN 3 => v_empty_data := v_ref_data(4*c_byte_w-1 DOWNTO 3*c_byte_w) & v_last_word(4*c_byte_w-1 DOWNTO 1*c_byte_w);
+                  WHEN OTHERS => NULL;
+                END CASE;
+                IF UNSIGNED(out_data_2) /= UNSIGNED(v_empty_data) THEN
+                  REPORT "DP : Wrong out_data count at eop-1" SEVERITY ERROR;
+                END IF;
+                -- verify out_data from eop-2 to eop+1
+                v_ref_data := INCR_UVEC(out_data_3, 3);
+                IF UNSIGNED(out_data) /= UNSIGNED(v_ref_data) THEN
+                  REPORT "DP : Wrong out_data count at eop+1" SEVERITY ERROR;
+                END IF;
+              END IF;
+            END IF;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_data_empty;  
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output other SOSI data
+  -- . Suited to verify the empty, error, channel fields assuming that these
+  --   are treated in the same way in parallel to the SOSI data.
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_other_sosi(CONSTANT c_str       : IN STRING;
+                                      CONSTANT c_exp_data  : IN STD_LOGIC_VECTOR;    -- use constant to support assignment via FUNCTION return value
+                                      SIGNAL   clk         : IN STD_LOGIC;
+                                      SIGNAL   verify_en   : IN STD_LOGIC;
+                                      SIGNAL   res_data    : IN STD_LOGIC_VECTOR) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF verify_en='1' THEN
+        IF    c_str="bsn" THEN
+          IF UNSIGNED(c_exp_data(c_dp_bsn_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_bsn_w-1 DOWNTO 0)) THEN
+            REPORT "DP : Wrong sosi.bsn value" SEVERITY ERROR;
+          END IF;
+        ELSIF c_str="empty" THEN
+          IF UNSIGNED(c_exp_data(c_dp_empty_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_empty_w-1 DOWNTO 0)) THEN
+            REPORT "DP : Wrong sosi.empty value" SEVERITY ERROR;
+          END IF;
+        ELSIF c_str="channel" THEN
+          IF UNSIGNED(c_exp_data(c_dp_channel_user_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_channel_user_w-1 DOWNTO 0)) THEN
+            REPORT "DP : Wrong sosi.channel value" SEVERITY ERROR;
+          END IF;
+        ELSIF c_str="error" THEN
+          IF UNSIGNED(c_exp_data(c_dp_error_w-1 DOWNTO 0))/=UNSIGNED(res_data(c_dp_error_w-1 DOWNTO 0)) THEN
+            REPORT "DP : Wrong sosi.error value" SEVERITY ERROR;
+          END IF;
+        ELSE
+          REPORT "proc_dp_verify_other_sosi : Unknown sosi." & c_str & "field" SEVERITY FAILURE;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_other_sosi;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output valid
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_valid(CONSTANT c_ready_latency : IN    NATURAL;
+                                 SIGNAL   clk             : IN    STD_LOGIC;
+                                 SIGNAL   verify_en       : IN    STD_LOGIC;
+                                 SIGNAL   out_ready       : IN    STD_LOGIC;
+                                 SIGNAL   prev_out_ready  : INOUT STD_LOGIC_VECTOR;
+                                 SIGNAL   out_val         : IN    STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      -- for ready_latency > 0 out_val may only be asserted after out_ready
+      -- for ready_latency = 0 out_val may always be asserted
+      prev_out_ready <= (prev_out_ready'RANGE=>'0');
+      IF c_ready_latency/=0 THEN
+        IF c_ready_latency=1 THEN
+          prev_out_ready(0) <= out_ready;
+        ELSE
+          prev_out_ready    <= out_ready & prev_out_ready(0 TO c_ready_latency-1);
+        END IF;
+        IF verify_en='1' AND out_val='1' THEN
+          IF prev_out_ready(c_ready_latency-1)/='1' THEN
+            REPORT "DP : Wrong ready latency between out_ready and out_val" SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_valid;
+  
+  PROCEDURE proc_dp_verify_valid(SIGNAL   clk             : IN    STD_LOGIC;
+                                 SIGNAL   verify_en       : IN    STD_LOGIC;
+                                 SIGNAL   out_ready       : IN    STD_LOGIC;
+                                 SIGNAL   prev_out_ready  : INOUT STD_LOGIC;
+                                 SIGNAL   out_val         : IN    STD_LOGIC) IS
+  BEGIN
+    -- Can not reuse:
+    --   proc_dp_verify_valid(1, clk, verify_en, out_ready, prev_out_ready, out_val);
+    -- because prev_out_ready needs to map from STD_LOGIC to STD_LOGIC_VECTOR. Therefore copy paste code for RL=1:
+    IF rising_edge(clk) THEN
+      -- for ready_latency = 1 out_val may only be asserted after out_ready
+      prev_out_ready <= out_ready;
+      IF verify_en='1' AND out_val='1' THEN
+        IF prev_out_ready/='1' THEN
+          REPORT "DP : Wrong ready latency between out_ready and out_val" SEVERITY ERROR;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_valid;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output sync
+  -- . sync is defined such that it can only be active at sop
+  -- . assume that the sync occures priodically at bsn MOD c_sync_period = c_sync_offset
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_sync(CONSTANT c_sync_period   : IN    NATURAL;    -- BSN sync period
+                                CONSTANT c_sync_offset   : IN    NATURAL;    -- BSN sync offset
+                                SIGNAL   clk             : IN    STD_LOGIC;
+                                SIGNAL   verify_en       : IN    STD_LOGIC;
+                                SIGNAL   sync            : IN    STD_LOGIC;
+                                SIGNAL   sop             : IN    STD_LOGIC;
+                                SIGNAL   bsn             : IN    STD_LOGIC_VECTOR) IS
+    CONSTANT c_bsn_w         : NATURAL := sel_a_b(bsn'LENGTH>31, 31, bsn'LENGTH);  -- use maximally 31 bit of BSN slv to allow calculations with integers
+    VARIABLE v_expected_sync : BOOLEAN;
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF verify_en='1' THEN
+        v_expected_sync := (TO_UINT(bsn(c_bsn_w-1 DOWNTO 0))-c_sync_offset) MOD c_sync_period = 0;
+        -- Check for unexpected sync
+        IF sync='1' THEN
+          ASSERT v_expected_sync = TRUE
+            REPORT "Error: Unexpected sync at BSN" SEVERITY ERROR;
+          ASSERT sop = '1'
+            REPORT "Error: Unexpected sync at inactive sop" SEVERITY ERROR;
+        END IF;
+        -- Check for missing sync
+        IF sop='1' AND v_expected_sync=TRUE THEN
+          ASSERT sync = '1'
+            REPORT "Error: Missing sync" SEVERITY ERROR;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_sync;
+  
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output sop and eop
+  ------------------------------------------------------------------------------
+  -- sop and eop in pairs, valid during packet and invalid between packets
+  PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN    NATURAL;
+                                       CONSTANT c_verify_valid  : IN    BOOLEAN;
+                                       SIGNAL   clk             : IN    STD_LOGIC;
+                                       SIGNAL   out_ready       : IN    STD_LOGIC;
+                                       SIGNAL   out_val         : IN    STD_LOGIC;
+                                       SIGNAL   out_sop         : IN    STD_LOGIC;
+                                       SIGNAL   out_eop         : IN    STD_LOGIC;
+                                       SIGNAL   hold_sop        : INOUT STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF out_val='0' THEN
+        IF out_sop='1' THEN REPORT "DP : Wrong active sop during invalid" SEVERITY ERROR; END IF;
+        IF out_eop='1' THEN REPORT "DP : Wrong active eop during invalid" SEVERITY ERROR; END IF;
+      ELSE
+        -- for ready_latency > 0 out_val indicates new data
+        -- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
+        IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
+          IF out_sop='1' THEN
+            hold_sop <= '1';
+            IF hold_sop='1' THEN
+              REPORT "DP : Unexpected sop without eop" SEVERITY ERROR;
+            END IF;
+          END IF;
+          IF out_eop='1' THEN
+            hold_sop <= '0';
+            IF hold_sop='0' AND out_sop='0' THEN
+              REPORT "DP : Unexpected eop without sop" SEVERITY ERROR;
+            END IF;
+          END IF;
+          -- out_val='1'
+          IF c_verify_valid=TRUE AND out_sop='0' AND hold_sop='0' THEN
+            REPORT "DP : Unexpected valid in gap between eop and sop" SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_sop_and_eop;
+  
+  PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN    NATURAL;
+                                       SIGNAL   clk             : IN    STD_LOGIC;
+                                       SIGNAL   out_ready       : IN    STD_LOGIC;
+                                       SIGNAL   out_val         : IN    STD_LOGIC;
+                                       SIGNAL   out_sop         : IN    STD_LOGIC;
+                                       SIGNAL   out_eop         : IN    STD_LOGIC;
+                                       SIGNAL   hold_sop        : INOUT STD_LOGIC) IS
+  BEGIN
+    proc_dp_verify_sop_and_eop(c_ready_latency, TRUE, clk, out_ready, out_val, out_sop, out_eop, hold_sop);
+  END proc_dp_verify_sop_and_eop;
+  
+  PROCEDURE proc_dp_verify_sop_and_eop(SIGNAL   clk      : IN    STD_LOGIC;
+                                       SIGNAL   out_val  : IN    STD_LOGIC;
+                                       SIGNAL   out_sop  : IN    STD_LOGIC;
+                                       SIGNAL   out_eop  : IN    STD_LOGIC;
+                                       SIGNAL   hold_sop : INOUT STD_LOGIC) IS
+  BEGIN
+    -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
+    proc_dp_verify_sop_and_eop(1, TRUE, clk, out_val, out_val, out_sop, out_eop, hold_sop);
+  END proc_dp_verify_sop_and_eop;
+  
+  PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN    NATURAL;
+                                      SIGNAL   alt_size        : IN    NATURAL;     -- alternative size
+                                      SIGNAL   exp_size        : IN    NATURAL;     -- expected size 
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   out_ready       : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_sop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   cnt_size        : INOUT NATURAL) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF out_val='1' THEN
+        -- for ready_latency > 0 out_val indicates new data
+        -- for ready_latency = 0 out_val only indicates new data when it is confirmed by out_ready
+        IF c_ready_latency/=0 OR (c_ready_latency=0 AND out_ready='1') THEN
+          IF out_sop='1' THEN
+            cnt_size <= 1;
+          ELSIF out_eop='1' THEN
+            cnt_size <= 0;
+            IF cnt_size/=alt_size-1 AND cnt_size/=exp_size-1 THEN
+              REPORT "DP : Unexpected block size" SEVERITY ERROR;
+            END IF;
+          ELSE
+            cnt_size <= cnt_size+1;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_block_size;
+  
+  PROCEDURE proc_dp_verify_block_size(CONSTANT c_ready_latency : IN    NATURAL;
+                                      SIGNAL   exp_size        : IN    NATURAL;
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   out_ready       : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_sop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   cnt_size        : INOUT NATURAL) IS
+  BEGIN
+    proc_dp_verify_block_size(c_ready_latency, exp_size, exp_size, clk, out_ready, out_val, out_sop, out_eop, cnt_size);
+  END proc_dp_verify_block_size;
+    
+  PROCEDURE proc_dp_verify_block_size(SIGNAL   alt_size        : IN    NATURAL;     -- alternative size
+                                      SIGNAL   exp_size        : IN    NATURAL;     -- expected size   
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_sop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   cnt_size        : INOUT NATURAL) IS
+  BEGIN
+    -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
+    proc_dp_verify_block_size(1, alt_size, exp_size, clk, out_val, out_val, out_sop, out_eop, cnt_size);
+  END proc_dp_verify_block_size;
+  
+  PROCEDURE proc_dp_verify_block_size(SIGNAL   exp_size        : IN    NATURAL;
+                                      SIGNAL   clk             : IN    STD_LOGIC;
+                                      SIGNAL   out_val         : IN    STD_LOGIC;
+                                      SIGNAL   out_sop         : IN    STD_LOGIC;
+                                      SIGNAL   out_eop         : IN    STD_LOGIC;
+                                      SIGNAL   cnt_size        : INOUT NATURAL) IS
+  BEGIN
+    -- Use out_val as void signal to pass on to unused out_ready, because a signal input can not connect a constant or variable
+    proc_dp_verify_block_size(1, exp_size, exp_size, clk, out_val, out_val, out_sop, out_eop, cnt_size);
+  END proc_dp_verify_block_size;
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output invalid between frames
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_gap_invalid(SIGNAL clk     : IN    STD_LOGIC;
+                                       SIGNAL in_val  : IN    STD_LOGIC;
+                                       SIGNAL in_sop  : IN    STD_LOGIC;
+                                       SIGNAL in_eop  : IN    STD_LOGIC;
+                                       SIGNAL out_gap : INOUT STD_LOGIC) IS
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF in_eop='1' THEN
+        out_gap <= '1';
+      ELSIF in_sop='1' THEN
+        out_gap <= '0';
+      ELSIF in_val='1' AND out_gap='1' THEN
+        REPORT "DP : Wrong valid in gap between eop and sop" SEVERITY ERROR;
+      END IF;
+    END IF;
+  END proc_dp_verify_gap_invalid;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output control (use for sop, eop)
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_ctrl(CONSTANT c_offset  : IN NATURAL;
+                                CONSTANT c_period  : IN NATURAL;
+                                CONSTANT c_str     : IN STRING;
+                                SIGNAL   clk       : IN STD_LOGIC;
+                                SIGNAL   verify_en : IN STD_LOGIC;
+                                SIGNAL   data      : IN STD_LOGIC_VECTOR;
+                                SIGNAL   valid     : IN STD_LOGIC;
+                                SIGNAL   ctrl      : IN STD_LOGIC) IS
+    VARIABLE v_data : INTEGER;
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF verify_en='1' THEN
+        v_data := TO_UINT(data);
+        IF ((v_data-c_offset) MOD c_period)=0 THEN
+          IF valid='1' AND ctrl/='1' THEN
+            REPORT "DP : Wrong data control, missing " & c_str SEVERITY ERROR;
+          END IF;
+        ELSE
+          IF ctrl='1' THEN
+            REPORT "DP : Wrong data control, unexpected " & c_str SEVERITY ERROR;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END proc_dp_verify_ctrl;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Wait for stream valid
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_stream_valid(SIGNAL clk      : IN  STD_LOGIC;
+                                 SIGNAL in_valid : IN  STD_LOGIC) IS
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    WHILE in_valid /= '1' LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_dp_stream_valid;
+  
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Wait for stream valid AND sop
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_stream_valid_sop(SIGNAL clk      : IN  STD_LOGIC;
+                                     SIGNAL in_valid : IN  STD_LOGIC;
+                                     SIGNAL in_sop   : IN  STD_LOGIC) IS
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    WHILE in_valid /= '1' AND in_sop /= '1' LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_dp_stream_valid_sop;
+
+  
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Wait for stream valid AND eop
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_stream_valid_eop(SIGNAL clk      : IN  STD_LOGIC;
+                                     SIGNAL in_valid : IN  STD_LOGIC;
+                                     SIGNAL in_eop   : IN  STD_LOGIC) IS
+  BEGIN
+    WAIT UNTIL rising_edge(clk);
+    WHILE in_valid /= '1' AND in_eop /= '1' LOOP
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+  END proc_dp_stream_valid_eop;
+  
+END tb_dp_pkg;
diff --git a/cores/base/dp/dp_repack_data/dp_repack_data.vhd b/cores/base/dp/dp_repack_data/dp_repack_data.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..0e052cb06330c2c48656f8bd71e297e8d375931b
--- /dev/null
+++ b/cores/base/dp/dp_repack_data/dp_repack_data.vhd
@@ -0,0 +1,748 @@
+--------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+--------------------------------------------------------------------------------
+
+-- Purpose:
+--   The dp_repack_data works both as packer and as unpacker.
+--
+-- Block diagram:
+--
+-- A) Functional
+--   The drawing shows g_in_nof_words=4 and g_out_nof_words=2 as example:
+--
+--                dp_repack_in               dp_repack_out
+--                     ___                        ___
+--                    |   |      pack_sosi       |   |--> src_out
+--                    | 3 |--------------------->| 1 |
+--                    |   |                      |   |
+--                    | 2 | ^                    |   | ^
+--                    |   | |valid               |   | |shift
+--                    | 1 | |flush               | 0 | |
+--                    |   | |                    |   | |
+--                    | 0 |                      |   |
+--   snk_in        -->|___|      pack_siso       |___|
+--   snk_out.ready <--     <---------------------     <-- src_in.ready
+--   snk_out.xon   <------------------------------------- src_in.xon
+--
+--
+-- B) Flow control
+--
+--      RL=1                        RL=1               RL=1
+--        .                           .                  .
+--        .        /-----------------------------------------\
+--        .        |                  .           _____  .   |
+--        .        |   /------\     nxt_r        |     | r   |
+--        .        \-->|      |---*-------*----->|p_reg|-----*---> src_out
+--        .            |      |   |       |      |_____|
+--     snk_in -------->|p_comb|<--|-------|--------------*-------- src_in
+--                     |      |   |       |              |
+--                     |      |   |       v              |
+--                     |      |   |   /-------\          |
+--                     |      |   |   |p_flow |          |
+--                     \------/   |   \-------/          |
+--                                |       |              |
+--           nxt_r.hold_out.valid |       |              |
+--                                v       |              |
+--                                /|      |r_snk_out     |
+--                               |0|------/              |
+--    snk_out <------------------| |                     |
+--                               |1|---------------------/
+--                                \|
+--
+-- Description:
+--   The dp_repack_data repacks g_in_nof_words of width g_in_dat_w into
+--   g_out_nof_words of width g_out_dat_w.
+--
+-- . g_in_bypass, g_out_bypass
+--   The dp_repack_in and dp_repack_out can be bypassed to save logic and to
+--   avoid the pipeline stage. Default both are FALSE, but they can be set
+--   TRUE if:
+--
+--   . g_in_bypass =TRUE if g_in_nof_words=g_out_nof_words or g_in_nof_words=1
+--   . g_out_bypass=TRUE if g_in_nof_words=g_out_nof_words or g_out_nof_words=1
+--
+--   Both the dp_repack_in and dp_repack_out stage do work correctly independent
+--   of the g_*_bypass setting. When g_*_bypass=FALSE then they merely
+--   add a transparant pipeline delay. It is important that they also work for
+--   g_*_bypass=FALSE because that gives confidence that their implementation
+--   structure is ok.
+--
+-- . g_in_nof_words and input block size
+--   The input block size in words is indicated by snk_in.sop and snk_in.eop.
+--   Each subsection of g_in_nof_words is packed into g_out_nof_words. The
+--   input block size does not have to be a multiple of g_in_nof_words. When
+--   the snk_in.eop occurs the last repack is initiated without need for input
+--   data padding. If the block length is an integer multiple of
+--   g_in_nof_words then the dp_repack_data introduces no gaps between blocks.
+--   If the block length is a fractional multiple of g_in_nof_words then there
+--   will be a gap after the block due to that the dp_repack_in needs to
+--   shift up the last subsection for the 'missing' input words.
+--
+-- . g_in_dat_w*g_in_nof_words <, =, > g_in_dat_w*g_in_nof_words
+--   . = : no subsection zero padding
+--   . < : the subsections will be zero padded
+--   . > : then the input must have sufficient zero padded bits per
+--         subsection that can be stripped without data loss.
+--
+-- . Resolution of the empty field
+--   The g_in_symbol_w is used to define the resolution of snk_in.empty and
+--   the g_out_symbol_w is used to define the resolution of src_out.empty. If
+--   they are 1 then the resolution is in number of bits, because the symbol
+--   size is then 1 bit. Their value has no effect on the packed data it self,
+--   only on the meaning of the empty field. Hence if the empty field is not
+--   used, then the setting of g_in_symbol_w and g_out_symbol_w is dont care.
+--
+-- Remarks:
+-- . Originally reused from LOFAR rad_repack.vhd and rad_repack(rtl).vhd. This
+--   dp_repack_data still uses the shift in input register in and the shift out
+--   output register, but no longer the intermediate buffer register.
+--   Using shift in and shift out may ease timing closure because the routing
+--   is more local compared to using a demultiplexer to put the input data in
+--   the input register and a multiplexer to get the data directly from the
+--   output register. For the demultiplexer / multiplexer it would be possible
+--   to only use one internal register.
+--   Using shift up is sufficient, the shift down option is not needed. With
+--   shift up the data is input a [0] and output the high index.
+--   Instead of requiring an snk_in.valid duty cycle this dp_repack_data uses
+--   snk_out.ready flow control and can handle src_in.ready flow control.
+--
+-- . To pack ETH/IP/UDP header slv of 14 + 20 + 8 = 42 octets into 32 bit words
+--   use:
+--     u_dp_repack_data : ENTITY .dp_repack_data
+--     GENERIC MAP (
+--       g_in_bypass         => TRUE,
+--       g_in_dat_w          => 8 * 42,
+--       g_in_nof_words      => 1,
+--       g_in_symbol_w       => 8,
+--       g_out_bypass        => FALSE,
+--       g_out_dat_w         => 32,
+--       g_out_nof_words     => 11,
+--       g_out_symbol_w      => 8
+--     )
+--   The src_out.empty will be 2, because:
+--     (g_out_dat_w*g_out_nof_words-g_in_dat_w*g_in_nof_words)/g_out_symbol_w
+--      = (32*11 - 42*8*1)/ 8 = 2 octet symbols
+--       
+-- Design steps:
+-- * In total the development took 5 days. On day 3 I was in distress because
+--   I could not get it to work so I needed to rethink. After changing to the
+--   new flow control scheme that uses nxt_r the design was gradually improved
+--   by getting the dp_repack_data instances in tb_tb_dp_repack_data to work one
+--   by one. First only for e_active stimuli and later also for e_random and
+--   e_pulse. Initially about 80 % of the functionality was implemented but
+--   and subsequently each feature was verified starting with the basic 
+--   features and then themore detailed features. This step by step approach
+--   makes that the bugs appear one by one instead of all together. Without a
+--   step by step approach the bugs are too big to solve.
+--   . First cases with g_in_nof_words=1 and g_out_nof_words were made to work
+--     for different g_pkt_len <, =, > g_in_nof_words.
+--   . Then the empty functionality for g_pkt_len MOD g_in_nof_words /= 0 was
+--     added.
+--   . Tried g_out_dat_w=1 which makes dp_repack_data a serializer/deserializer.
+--   . Then apply external flow control using c_dp_flow_control_enum_arr in
+--     the tb_tb_dp_repack_data was verified resulting in small corrections.
+--   . Then verified g_in_dat_w * g_in_nof_words > or < g_out_dat_w *
+--     g_out_nof_words which require padding in the subsection. The > case
+--     occurs for packing and the < case then occurs for unpacking.
+--   . Added g_bypass to force using wires instead of a void dp_repack_in or
+--     dp_repack_out stage.
+--   . Verified g_in_symbol_w and g_out_symbol_w /= 1.
+-- * The development used the tb_dp_repack_data testbench that does a pack and
+--   an unpack to be able to verify the data. The c_no_unpack and
+--   c_enable_repack_in and c_enable_repack_out parameters in the tb are
+--   useful to be able to isolate a component for debugging.
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_repack_in IS
+  GENERIC (
+    g_bypass          : BOOLEAN := FALSE;
+    g_in_dat_w        : NATURAL;
+    g_in_nof_words    : NATURAL;
+    g_in_symbol_w     : NATURAL := 1  -- default 1 for snk_in.empty in nof bits, else use power of 2
+  );
+  PORT (
+    rst              : IN  STD_LOGIC;
+    clk              : IN  STD_LOGIC;
+
+    snk_out          : OUT t_dp_siso;
+    snk_in           : IN  t_dp_sosi;
+
+    src_in           : IN  t_dp_siso;
+    src_out          : OUT t_dp_sosi
+  );
+END dp_repack_in;
+
+
+ARCHITECTURE rtl OF dp_repack_in IS
+
+  CONSTANT c_in_buf_dat_w      : NATURAL := g_in_dat_w * g_in_nof_words;
+  CONSTANT c_bit_cnt_max       : NATURAL := c_in_buf_dat_w;
+  CONSTANT c_in_empty_lo       : NATURAL := true_log2(g_in_symbol_w);
+
+  TYPE t_dat_arr  IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+
+  TYPE t_reg IS RECORD
+    dat_arr       : t_dat_arr(g_in_nof_words-1 DOWNTO 0);     -- internally use dat_arr[] to represent v.src_out.data
+    src_out       : t_dp_sosi;                                -- sosi output
+    hold_out      : t_dp_sosi;                                -- hold snk_in.sync/sop/eop until end of section and then hold valid src_out until src_in.ready
+    flush         : STD_LOGIC;                                -- shift when snk_in.valid or flush in case the last subsection has < g_in_nof_words
+    dat_bit_cnt   : NATURAL RANGE 0 TO c_bit_cnt_max;         -- actual nof bits in subsection
+    pack_bit_cnt  : NATURAL RANGE 0 TO c_bit_cnt_max;         -- count nof bits in subsection
+  END RECORD;
+
+  SIGNAL data_vec   : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
+
+  SIGNAL r_snk_out  : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL r          : t_reg;
+  SIGNAL nxt_r      : t_reg;
+
+  -- Debug signals
+  SIGNAL snk_in_data        : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL i_src_out          : t_dp_sosi;
+  SIGNAL src_out_data       : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
+
+  SIGNAL dbg_g_in_dat_w   : NATURAL := g_in_dat_w;
+  SIGNAL dbg_in_nof_words : NATURAL := g_in_nof_words;
+  SIGNAL dbg_in_symbol_w  : NATURAL := g_in_symbol_w;
+  SIGNAL dbc_in_buf_dat_w : NATURAL := c_in_buf_dat_w;
+
+BEGIN
+
+  snk_in_data <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
+  
+  src_out      <= i_src_out;
+  src_out_data <= i_src_out.data(c_in_buf_dat_w-1 DOWNTO 0);
+  
+  gen_bypass : IF g_bypass=TRUE GENERATE
+    snk_out   <= src_in;
+    i_src_out <= snk_in;
+  END GENERATE;
+  
+  no_bypass : IF g_bypass=FALSE GENERATE
+
+    p_comb : PROCESS(rst, r, snk_in, data_vec, src_in)
+      VARIABLE v : t_reg;
+    BEGIN
+      ------------------------------------------------------------------------
+      -- Default
+      v := r;
+      v.src_out.sync  := '0';
+      v.src_out.valid := '0';
+      v.src_out.sop   := '0';
+      v.src_out.eop   := '0';
+  
+      --------------------------------------------------------------------------
+      -- Function
+      IF r.hold_out.valid='0' THEN
+      
+        -- Clear hold_out for new output valid (= new subsection)
+        IF r.src_out.valid='1' THEN
+          v.hold_out := c_dp_sosi_rst;
+        END IF;
+  
+        -- Capture the snk_in block info that is valid at sop and eop
+        IF snk_in.sop='1' THEN
+          v.hold_out.sop    := '1';
+          v.hold_out.sync   := snk_in.sync;
+          v.src_out.bsn     := snk_in.bsn;
+          v.src_out.channel := snk_in.channel;
+        END IF;
+        IF snk_in.eop='1' THEN
+          v.hold_out.eop    := '1';
+          v.hold_out.empty  := SHIFT_UVEC(snk_in.empty, -c_in_empty_lo);  -- use snk_in.empty as offset for src_out.empty in nof bits
+          v.src_out.err     := snk_in.err;
+        END IF;
+  
+        -- Capture the data per subsection in a block
+        IF snk_in.valid='1' OR r.flush='1' THEN
+          -- shift in during block
+          v.dat_arr(g_in_nof_words-1 DOWNTO 1) := r.dat_arr(g_in_nof_words-2 DOWNTO 0);  -- shift up from low to high and shift in at index 0
+          IF r.flush='1' THEN
+            v.dat_arr(0) := (OTHERS=>'0');                                               -- shift in data=0 for flush
+          ELSE
+            v.dat_arr(0) := snk_in.data(g_in_dat_w-1 DOWNTO 0);                          -- shift in valid data
+          END IF;
+  
+          -- pack subsection
+          IF r.pack_bit_cnt<c_in_buf_dat_w-g_in_dat_w THEN
+            v.pack_bit_cnt := r.pack_bit_cnt + g_in_dat_w;
+  
+            -- early end of pack subsection
+            IF snk_in.eop='1' THEN
+              v.flush := '1';                   -- enable flush in case eop occurs before end of pack subsection
+              v.dat_bit_cnt := v.pack_bit_cnt;  -- capture the current subsection pack_bit_cnt
+            END IF;
+          ELSE                                  -- r.pack_bit_cnt=c_in_buf_dat_w-g_in_dat_w
+            -- default end of pack subsection
+            v.pack_bit_cnt := 0;
+            v.flush := '0';
+            IF r.flush='0' THEN
+              v.dat_bit_cnt := c_in_buf_dat_w;  -- set default subsection pack_bit_cnt
+            END IF;
+            
+            v.hold_out.valid := '1';            -- the function has new data to output
+          END IF;
+        END IF;
+  
+        -- pass on the v.dat_arr as data vector
+        v.src_out.data := RESIZE_DP_DATA(data_vec);
+  
+        -- pass on dat_bit_cnt via DP empty field
+        v.src_out.empty := INCR_UVEC(v.hold_out.empty, c_in_buf_dat_w - v.dat_bit_cnt);
+  
+        -- output input stage into output stage when ready, else hold_out.valid to signal pending output
+        IF v.hold_out.valid='1' THEN
+          IF src_in.ready='1' THEN
+            v.src_out.valid := '1';
+            v.src_out.sync  := v.hold_out.sync;
+            v.src_out.sop   := v.hold_out.sop;
+            v.src_out.eop   := v.hold_out.eop;
+            v.hold_out.valid := '0';
+          END IF;
+        END IF;
+      ELSE
+        -- pending output
+        IF src_in.ready='1' THEN
+          v.src_out.valid := '1';
+          v.src_out.sync  := r.hold_out.sync;
+          v.src_out.sop   := r.hold_out.sop;
+          v.src_out.eop   := r.hold_out.eop;
+          v.hold_out.valid := '0';
+        END IF;
+      END IF;
+  
+      ------------------------------------------------------------------------
+      -- Reset and nxt_r
+      IF rst = '1' THEN
+        v.src_out       := c_dp_sosi_rst;
+        v.hold_out      := c_dp_sosi_rst;
+        v.flush         := '0';
+        v.dat_bit_cnt   := 0;
+        v.pack_bit_cnt  := 0;
+      END IF;
+  
+      nxt_r <= v;
+    END PROCESS;
+  
+    --------------------------------------------------------------------------
+    -- p_reg
+    r <= nxt_r WHEN rising_edge(clk);
+  
+    --------------------------------------------------------------------------
+    -- Wires
+    p_data_vec : PROCESS(nxt_r)
+    BEGIN
+      FOR I IN 0 TO g_in_nof_words-1 LOOP
+        data_vec((I+1)*g_in_dat_w-1 DOWNTO I*g_in_dat_w) <= nxt_r.dat_arr(I);
+      END LOOP;
+    END PROCESS;
+  
+    --------------------------------------------------------------------------
+    -- Wired output
+    i_src_out <= r.src_out;
+  
+    --------------------------------------------------------------------------
+    -- Flow control
+  
+    -- local function flow control
+    p_flow : PROCESS(nxt_r)
+    BEGIN
+      r_snk_out <= c_dp_siso_rdy;
+      IF nxt_r.flush='1' THEN
+        r_snk_out.ready <= '0';   -- input shift in stage function is always ready except when flushing
+      END IF;
+    END PROCESS;
+  
+    -- combined local and remote src_in flow control
+    snk_out.ready <= r_snk_out.ready WHEN nxt_r.hold_out.valid='0' ELSE src_in.ready;  -- if there is pending output then the src_in ready determines the flow control
+    snk_out.xon   <= src_in.xon;  -- just pass on the xon/off frame flow control
+  
+  END GENERATE;
+  
+END rtl;
+
+
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_repack_out IS
+  GENERIC (
+    g_bypass           : BOOLEAN := FALSE;
+    g_in_buf_dat_w     : NATURAL;
+    g_out_dat_w        : NATURAL;
+    g_out_nof_words    : NATURAL;
+    g_out_symbol_w     : NATURAL := 1  -- default 1 for snk_in.empty in nof bits, else use power of 2
+  );
+  PORT (
+    rst              : IN  STD_LOGIC;
+    clk              : IN  STD_LOGIC;
+
+    snk_out          : OUT t_dp_siso;
+    snk_in           : IN  t_dp_sosi;
+
+    src_in           : IN  t_dp_siso;
+    src_out          : OUT t_dp_sosi
+  );
+END dp_repack_out;
+
+ARCHITECTURE rtl OF dp_repack_out IS
+
+  CONSTANT c_out_buf_dat_w     : NATURAL := g_out_dat_w * g_out_nof_words;
+  CONSTANT c_out_buf_dat_lo    : NATURAL := sel_a_b(c_out_buf_dat_w > g_in_buf_dat_w, c_out_buf_dat_w -  g_in_buf_dat_w, 0);  -- pack into subsection with 0 or more padding bits
+  CONSTANT c_snk_in_dat_lo     : NATURAL := sel_a_b(c_out_buf_dat_w < g_in_buf_dat_w,  g_in_buf_dat_w - c_out_buf_dat_w, 0);  -- unpack from subsection that has 0 or more padding bits
+  CONSTANT c_bit_cnt_max       : NATURAL := c_out_buf_dat_w;
+  CONSTANT c_out_empty_lo      : NATURAL := true_log2(g_out_symbol_w);
+
+  TYPE t_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+
+  TYPE t_reg IS RECORD
+    dat_arr       : t_dat_arr(g_out_nof_words-1 DOWNTO 0);
+    src_out       : t_dp_sosi;
+    hold_out      : t_dp_sosi;                                -- hold src_out valid and sync/sop/eop until src_in.ready
+    shift         : STD_LOGIC;                                -- shift out the dat_arr
+    dat_bit_cnt   : NATURAL RANGE 0 TO c_bit_cnt_max;         -- actual nof bits in subsection
+    pack_bit_cnt  : NATURAL RANGE 0 TO c_bit_cnt_max;         -- count nof bits in subsection
+    empty_bit_cnt : NATURAL RANGE 0 TO c_bit_cnt_max;         -- empty nof bits in subsection
+    eos           : STD_LOGIC;                                -- end of subsection
+  END RECORD;
+
+  SIGNAL data_vec  : STD_LOGIC_VECTOR(c_out_buf_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
+
+  SIGNAL r_snk_out : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL r         : t_reg;
+  SIGNAL nxt_r     : t_reg;
+
+  -- Debug signals
+  SIGNAL snk_in_data        : STD_LOGIC_VECTOR(g_in_buf_dat_w-1 DOWNTO 0);
+  SIGNAL i_src_out          : t_dp_sosi;
+  SIGNAL src_out_data       : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+
+  SIGNAL dbg_g_in_buf_dat_w : NATURAL := g_in_buf_dat_w;
+  SIGNAL dbg_g_out_dat_w    : NATURAL := g_out_dat_w;
+  SIGNAL dbg_out_nof_words  : NATURAL := g_out_nof_words;
+  SIGNAL dbg_out_symbol_w   : NATURAL := g_out_symbol_w;
+  SIGNAL dbc_out_buf_dat_w  : NATURAL := c_out_buf_dat_w;
+  SIGNAL dbc_out_buf_dat_lo : NATURAL := c_out_buf_dat_lo;
+  SIGNAL dbc_snk_in_dat_lo  : NATURAL := c_snk_in_dat_lo;
+
+BEGIN
+
+  snk_in_data <= snk_in.data(g_in_buf_dat_w-1 DOWNTO 0);
+  
+  src_out      <= i_src_out;
+  src_out_data <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
+  
+  gen_bypass : IF g_bypass=TRUE GENERATE
+    snk_out <= src_in;
+    
+    p_src_out : PROCESS(snk_in)
+    BEGIN
+      i_src_out <= snk_in;
+      IF c_snk_in_dat_lo>0 THEN
+        i_src_out.data  <= SHIFT_UVEC(snk_in.data,   c_snk_in_dat_lo);
+        i_src_out.empty <= INCR_UVEC( snk_in.empty, -c_snk_in_dat_lo);
+      END IF;
+      IF c_out_buf_dat_lo>0 THEN
+        i_src_out.data  <= SHIFT_UVEC(snk_in.data, -c_out_buf_dat_lo);
+        i_src_out.empty <= INCR_UVEC( snk_in.empty, c_out_buf_dat_lo);
+      END IF;
+    END PROCESS;
+  END GENERATE;
+  
+  no_bypass : IF g_bypass=FALSE GENERATE
+
+    p_comb : PROCESS(rst, snk_in, r, data_vec, src_in)
+      VARIABLE v : t_reg;
+    BEGIN
+      ------------------------------------------------------------------------
+      -- Default
+      v := r;
+      v.src_out.sync  := '0';
+      v.src_out.valid := '0';
+      v.src_out.sop   := '0';
+      v.src_out.eop   := '0';
+  
+      ------------------------------------------------------------------------
+      -- Function
+      IF r.hold_out.valid='0' THEN
+      
+        -- Clear hold_out for new output valid
+        IF r.src_out.sop='1' THEN
+          v.hold_out.sync := '0';
+          v.hold_out.sop  := '0';
+        END IF;
+        IF r.src_out.eop='1' THEN
+          v.hold_out.eop := '0';
+        END IF;
+  
+        -- Capture the snk_in block info that is valid at sop and eop
+        IF snk_in.sop='1' THEN
+          v.hold_out.sop    := '1';
+          v.hold_out.sync   := snk_in.sync;
+          v.src_out.bsn     := snk_in.bsn;
+          v.src_out.channel := snk_in.channel;
+        END IF;
+        IF snk_in.eop='1' THEN
+          v.hold_out.eop    := '1';  -- local function will calculate src_out.empty based on snk_in.empty
+          v.src_out.err     := snk_in.err;
+        END IF;
+  
+        IF r.shift='1' THEN
+          -- shift out rest of subsection
+          v.hold_out.valid := '1';
+  
+          v.dat_arr(g_out_nof_words-1 DOWNTO 1) := r.dat_arr(g_out_nof_words-2 DOWNTO 0);  -- shift up from low to high and shift out at high index
+          v.dat_arr(0) := (OTHERS=>'0');                                                   -- shift in data=0
+  
+          v.pack_bit_cnt := r.pack_bit_cnt - g_out_dat_w;
+  
+          -- end of pack subsection
+          IF v.pack_bit_cnt<=r.empty_bit_cnt THEN
+            v.eos   := '1';                     -- end of subsection, so ready for new snk_in
+            v.shift := '0';                     -- stop shifting
+          END IF;
+  
+        ELSIF snk_in.valid='1' THEN
+          -- start of pack subsection
+          v.hold_out.valid := '1';
+  
+          FOR I IN 0 TO g_out_nof_words-1 LOOP
+            v.dat_arr(I) := data_vec((I+1)*g_out_dat_w-1 DOWNTO I*g_out_dat_w);
+          END LOOP;
+  
+          v.dat_bit_cnt := g_in_buf_dat_w - c_snk_in_dat_lo;          -- default dat_bit_cnt per subsection
+          IF snk_in.eop='1' THEN
+            v.dat_bit_cnt := g_in_buf_dat_w - TO_UINT(snk_in.empty);  -- pass on last subsection dat_bit_cnt info via DP empty field
+          END IF;
+          
+          v.pack_bit_cnt  := c_out_buf_dat_w - g_out_dat_w;
+          v.empty_bit_cnt := c_out_buf_dat_w - v.dat_bit_cnt;
+          v.eos           := '0';
+          v.shift         := '1';
+  
+          -- end of pack subsection
+          IF v.pack_bit_cnt<=v.empty_bit_cnt THEN
+            v.eos   := '1';         -- end of subsection, so ready for new snk_in
+            v.shift := '0';
+          END IF;
+        END IF;
+  
+        -- fill in local empty if this is the last subsection of a block
+        IF v.eos='1' THEN
+          IF v.hold_out.eop='1' THEN
+            v.src_out.empty := TO_DP_EMPTY(v.empty_bit_cnt - v.pack_bit_cnt);  -- in nof bits
+            v.src_out.empty := SHIFT_UVEC(v.src_out.empty, c_out_empty_lo);    -- in nof symbols
+          END IF;
+        END IF;
+  
+        -- pass on the v.dat_arr as data vector
+        v.src_out.data  := RESIZE_DP_DATA(v.dat_arr(g_out_nof_words-1));
+  
+        -- output valid data when ready, else hold_out.valid to signal pending output
+        IF v.hold_out.valid='1' THEN
+          IF src_in.ready='1' THEN
+            v.src_out.valid  := '1';
+            v.src_out.sync   := v.hold_out.sync;
+            v.src_out.sop    := v.hold_out.sop;
+            v.src_out.eop    := v.hold_out.eop AND v.eos;  -- output eop at end of subsection
+            v.hold_out.valid := '0';
+          END IF;
+        END IF;
+  
+      ELSE
+        -- pending output
+        IF src_in.ready='1' THEN
+          v.src_out.valid := '1';
+          v.src_out.sync  := r.hold_out.sync;
+          v.src_out.sop   := r.hold_out.sop;
+          v.src_out.eop   := r.hold_out.eop AND r.eos;  -- output eop at end of subsection
+          v.hold_out.valid := '0';
+        END IF;
+      END IF;
+  
+      ------------------------------------------------------------------------
+      -- Reset and nxt_r
+      IF rst = '1' THEN
+        v.src_out       := c_dp_sosi_rst;
+        v.hold_out      := c_dp_sosi_rst;
+        v.shift         := '0';
+        v.dat_bit_cnt   := 0;
+        v.pack_bit_cnt  := 0;
+        v.empty_bit_cnt := 0;
+        v.eos           := '0';
+      END IF;
+  
+      nxt_r <= v;
+    END PROCESS;
+  
+    --------------------------------------------------------------------------
+    -- p_reg
+    r <= nxt_r WHEN rising_edge(clk);
+  
+    --------------------------------------------------------------------------
+    -- Wires
+    data_vec(c_out_buf_dat_w-1 DOWNTO c_out_buf_dat_lo) <= snk_in.data(g_in_buf_dat_w-1 DOWNTO c_snk_in_dat_lo);
+  
+    --------------------------------------------------------------------------
+    -- Wired output
+    i_src_out <= r.src_out;
+  
+    --------------------------------------------------------------------------
+    -- Flow control
+  
+    -- local function flow control
+    p_flow : PROCESS(nxt_r)
+    BEGIN
+      r_snk_out <= c_dp_siso_rdy;
+      IF nxt_r.shift='1' AND nxt_r.eos='0' THEN
+        r_snk_out.ready <= '0';   -- output shift out stage function is only ready when it is not shifting or at the end of the subsection
+      END IF;
+    END PROCESS;
+  
+    -- combined local and remote src_in flow control
+    snk_out.ready <= r_snk_out.ready WHEN nxt_r.hold_out.valid='0' ELSE src_in.ready;  -- if there is pending output then the src_in ready determines the flow control
+    snk_out.xon   <= src_in.xon;  -- just pass on the xon/off frame flow control
+    
+  END GENERATE;
+  
+END rtl;
+
+
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+
+ENTITY dp_repack_data IS
+  GENERIC (
+    g_enable_repack_in  : BOOLEAN := TRUE;
+    g_enable_repack_out : BOOLEAN := TRUE;
+    g_in_bypass         : BOOLEAN := FALSE;
+    g_in_dat_w          : NATURAL;
+    g_in_nof_words      : NATURAL;
+    g_in_symbol_w       : NATURAL := 1;  -- default 1 for snk_in.empty in nof bits, else use power of 2
+    g_out_bypass        : BOOLEAN := FALSE;
+    g_out_dat_w         : NATURAL;
+    g_out_nof_words     : NATURAL;
+    g_out_symbol_w      : NATURAL := 1   -- default 1 for src_out.empty in nof bits, else use power of 2
+  );
+  PORT (
+    rst              : IN  STD_LOGIC;
+    clk              : IN  STD_LOGIC;
+
+    snk_out          : OUT t_dp_siso;
+    snk_in           : IN  t_dp_sosi;
+
+    src_in           : IN  t_dp_siso;
+    src_out          : OUT t_dp_sosi
+  );
+END dp_repack_data;
+
+
+ARCHITECTURE str OF dp_repack_data IS
+
+  CONSTANT c_in_buf_dat_w      : NATURAL := g_in_dat_w * g_in_nof_words;
+
+  SIGNAL snk_in_data       : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL i_snk_out         : t_dp_siso;
+
+  SIGNAL pack_siso         : t_dp_siso;
+  SIGNAL pack_sosi         : t_dp_sosi;
+  SIGNAL pack_sosi_data    : STD_LOGIC_VECTOR(c_in_buf_dat_w-1 DOWNTO 0);
+
+  SIGNAL i_src_out         : t_dp_sosi;
+  SIGNAL src_out_data      : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+
+  SIGNAL snk_out_ready_reg : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl);
+  SIGNAL pack_ready_reg    : STD_LOGIC_VECTOR(0 TO c_dp_stream_rl);
+
+BEGIN
+
+  snk_out <= i_snk_out;
+  src_out <= i_src_out;
+
+  snk_in_data    <= snk_in.data(g_in_dat_w-1 DOWNTO 0);
+  pack_sosi_data <= pack_sosi.data(c_in_buf_dat_w-1 DOWNTO 0);
+  src_out_data   <= i_src_out.data(g_out_dat_w-1 DOWNTO 0);
+
+  no_dp_repack_in : IF g_enable_repack_in=FALSE GENERATE
+    i_snk_out <= pack_siso;
+    pack_sosi <= snk_in;
+  END GENERATE;
+
+  gen_dp_repack_in : IF g_enable_repack_in=TRUE GENERATE
+    u_dp_repack_in : ENTITY work.dp_repack_in
+    GENERIC MAP (
+      g_bypass       => g_in_bypass,
+      g_in_dat_w     => g_in_dat_w,
+      g_in_nof_words => g_in_nof_words,
+      g_in_symbol_w  => g_in_symbol_w
+    )
+    PORT MAP (
+      rst      => rst,
+      clk      => clk,
+
+      snk_out  => i_snk_out,
+      snk_in   => snk_in,
+
+      src_in   => pack_siso,
+      src_out  => pack_sosi
+    );
+  END GENERATE;
+
+  no_dp_repack_out : IF g_enable_repack_out=FALSE GENERATE
+    pack_siso <= src_in;
+    i_src_out <= pack_sosi;
+  END GENERATE;
+
+  gen_dp_repack_out : IF g_enable_repack_out=TRUE GENERATE
+    u_dp_repack_out : ENTITY work.dp_repack_out
+    GENERIC MAP (
+      g_bypass        => g_out_bypass,
+      g_in_buf_dat_w  => c_in_buf_dat_w,
+      g_out_dat_w     => g_out_dat_w,
+      g_out_nof_words => g_out_nof_words,
+      g_out_symbol_w  => g_out_symbol_w
+    )
+    PORT MAP (
+      rst      => rst,
+      clk      => clk,
+
+      snk_out  => pack_siso,
+      snk_in   => pack_sosi,
+
+      src_in   => src_in,
+      src_out  => i_src_out
+    );
+  END GENERATE;
+
+  -- Simulation only: internal stream RL verification
+  proc_dp_siso_alert(clk, snk_in, i_snk_out, snk_out_ready_reg);
+  proc_dp_siso_alert(clk, pack_sosi, pack_siso, pack_ready_reg);
+
+END str;
diff --git a/cores/base/dp/dp_repack_data/hdllib.cfg b/cores/base/dp/dp_repack_data/hdllib.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..bb4139616f9d019c159f9b9a2441177de1533e0a
--- /dev/null
+++ b/cores/base/dp/dp_repack_data/hdllib.cfg
@@ -0,0 +1,20 @@
+hdl_lib_name = dp_repack_data
+hdl_library_clause_name = dp_repack_data_lib
+hdl_lib_uses_synth = dp_pkg
+hdl_lib_uses_sim = 
+hdl_lib_technology = 
+
+synth_files =
+    dp_repack_data.vhd
+   
+test_bench_files = 
+    tb_dp_repack_data.vhd
+    tb_tb_dp_repack_data.vhd
+
+regression_test_vhdl = 
+    tb_tb_dp_repack_data.vhd
+    
+[modelsim_project_file]
+
+
+[quartus_project_file]
diff --git a/cores/base/dp/dp_repack_data/tb_dp_repack_data.vhd b/cores/base/dp/dp_repack_data/tb_dp_repack_data.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..2d2d5f95684a228a8782e1b21fbd7ef157fa2f7a
--- /dev/null
+++ b/cores/base/dp/dp_repack_data/tb_dp_repack_data.vhd
@@ -0,0 +1,317 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+-- Purpose:
+-- . Test bench for dp_repack_data
+-- Description:
+--                                                       c_no_unpack
+--                                                          .
+--             g_in_dat_w             g_pack_dat_w          .   g_in_dat_w
+--             g_in_nof_words         g_pack_nof_words      .   g_in_nof_words
+--                 .                       .                .       .
+--                 .   u_pack              .       u_unpack .       .
+--                 .   ______________      .       ______________   .
+--                 .  |dp_repack_data|     .      |dp_repack_data|  .
+--   stimuli_src ---->|              |----------->|              |----> verify_snk
+--                    | in       out |  pack_src  | in       out |
+--                    |______________|            |______________|
+--
+-- Usage:                                  
+-- > as 10
+-- > run -all
+--
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE common_pkg_lib.common_lfsr_sequences_pkg.ALL;
+USE common_pkg_lib.tb_common_pkg.ALL;
+USE dp_pkg_lib.dp_stream_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+
+ENTITY tb_dp_repack_data IS
+  GENERIC (
+    -- general
+    g_flow_control_stimuli   : t_dp_flow_control_enum := e_active;  -- always e_active, e_random or e_pulse flow control
+    g_flow_control_verify    : t_dp_flow_control_enum := e_active;  -- always e_active, e_random or e_pulse flow control
+    -- specific
+    g_in_dat_w               : NATURAL := 8 * 42;
+    g_in_nof_words           : NATURAL := 1;
+    g_pack_dat_w             : NATURAL := 32;
+    g_pack_nof_words         : NATURAL := 11;
+    g_in_bypass              : BOOLEAN := TRUE;   -- can use TRUE when g_in_nof_words=1  or g_in_nof_words=g_out_nof_words
+    g_pack_bypass            : BOOLEAN := FALSE;  -- can use TRUE when g_out_nof_words=1 or g_in_nof_words=g_out_nof_words
+    g_in_symbol_w            : NATURAL := 8;      -- default 1 for snk_in.empty  in nof bits, else use power of 2
+    g_pack_symbol_w          : NATURAL := 8;      -- default 1 for src_out.empty in nof bits, else use power of 2
+    g_nof_repeat             : NATURAL := 10;
+    g_pkt_len                : NATURAL := 1;     -- if not a multiple of g_in_nof_words then the input stage flush creates gap between blocks
+    g_pkt_gap                : NATURAL := 0
+  );
+END tb_dp_repack_data;
+
+
+ARCHITECTURE tb OF tb_dp_repack_data IS
+
+  CONSTANT c_no_unpack                : BOOLEAN := FALSE;
+  CONSTANT c_enable_repack_in         : BOOLEAN := TRUE;
+  CONSTANT c_enable_repack_out        : BOOLEAN := TRUE;
+
+  -- dp_stream_stimuli
+  CONSTANT c_stimuli_pulse_active     : NATURAL := 3;  --g_in_nof_words;
+  CONSTANT c_stimuli_pulse_period     : NATURAL := 7;
+
+  CONSTANT c_data_init                : NATURAL := 0;
+  CONSTANT c_bsn_init                 : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) := X"0000000000000000";  -- X"0877665544332211"
+  CONSTANT c_err_init                 : NATURAL := 247;
+  CONSTANT c_channel_init             : NATURAL := 5;  -- fixed
+
+  -- dp_stream_verify
+  CONSTANT c_verify_pulse_active      : NATURAL := 1;
+  CONSTANT c_verify_pulse_period      : NATURAL := 5;
+
+  CONSTANT c_data_max                 : UNSIGNED(g_in_dat_w-1 DOWNTO 0) := (OTHERS=>'1');
+  CONSTANT c_dsp_max                  : UNSIGNED(g_in_dat_w-1 DOWNTO 0) := (OTHERS=>'1');
+
+  --CONSTANT c_verify_snk_in_cnt_max    : t_dp_sosi_unsigned := c_dp_sosi_unsigned_rst;  -- default 0 is no wrap
+  CONSTANT c_verify_snk_in_cnt_max    : t_dp_sosi_unsigned := TO_DP_SOSI_UNSIGNED('0', '0', '0', '0', c_data_max, c_dsp_max, c_dsp_max, c_unsigned_0, c_unsigned_0, c_unsigned_0, c_unsigned_0);
+  CONSTANT c_verify_snk_in_cnt_gap    : t_dp_sosi_unsigned := c_dp_sosi_unsigned_ones; -- default only accept increment +1
+
+  CONSTANT c_expected_pkt_len         : NATURAL := sel_a_b(c_no_unpack, g_pkt_len * g_pack_nof_words / g_in_nof_words, g_pkt_len);
+  -- both
+  CONSTANT c_sync_period              : NATURAL := 10;
+  CONSTANT c_sync_offset              : NATURAL := 7;
+
+  SIGNAL clk                        : STD_LOGIC := '1';
+  SIGNAL rst                        : STD_LOGIC := '1';
+  SIGNAL tb_end                     : STD_LOGIC := '0';
+
+  SIGNAL stimuli_src_in             : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL stimuli_src_out            : t_dp_sosi;
+  SIGNAL stimuli_src_out_data       : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+
+  SIGNAL verify_snk_in_enable       : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+  SIGNAL last_snk_in                : t_dp_sosi;
+  SIGNAL last_snk_in_evt            : STD_LOGIC;
+  SIGNAL verify_last_snk_in_evt     : t_dp_sosi_sl := c_dp_sosi_sl_rst;
+
+  SIGNAL verify_snk_out             : t_dp_siso := c_dp_siso_rdy;
+  SIGNAL verify_snk_in              : t_dp_sosi;
+  SIGNAL verify_snk_in_data         : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+
+  -- specific
+  SIGNAL pack_src_in                : t_dp_siso;
+  SIGNAL pack_src_out               : t_dp_sosi;
+  SIGNAL pack_src_out_data          : STD_LOGIC_VECTOR(g_pack_dat_w-1 DOWNTO 0);
+
+  SIGNAL unpack_src_in              : t_dp_siso;
+  SIGNAL unpack_src_out             : t_dp_sosi;
+  SIGNAL unpack_src_out_data        : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+
+BEGIN
+
+  clk <= (NOT clk) OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+
+  ------------------------------------------------------------------------------
+  -- DATA GENERATION
+  ------------------------------------------------------------------------------
+
+  u_dp_stream_stimuli : ENTITY dp_pkg_lib.dp_stream_stimuli
+  GENERIC MAP (
+    g_instance_nr    => 0,                        -- only one stream so choose index 0
+    -- flow control
+    g_random_w       => 15,                       -- use different random width for stimuli and for verify to have different random sequences
+    g_pulse_active   => c_stimuli_pulse_active,
+    g_pulse_period   => c_stimuli_pulse_period,
+    g_flow_control   => g_flow_control_stimuli,   -- always active, random or pulse flow control
+    -- initializations
+    g_sync_period    => c_sync_period,
+    g_sync_offset    => c_sync_offset,
+    g_data_init      => c_data_init,
+    g_bsn_init       => c_bsn_init,
+    g_err_init       => c_err_init,
+    g_channel_init   => c_channel_init,
+    -- specific
+    g_in_dat_w       => g_in_dat_w,
+    g_nof_repeat     => g_nof_repeat,
+    g_pkt_len        => g_pkt_len,
+    g_pkt_gap        => g_pkt_gap
+  )
+  PORT MAP (
+    rst                 => rst,
+    clk                 => clk,
+
+    -- Generate stimuli
+    src_in              => stimuli_src_in,
+    src_out             => stimuli_src_out,
+
+    -- End of stimuli
+    last_snk_in         => last_snk_in,      -- expected verify_snk_in after end of stimuli
+    last_snk_in_evt     => last_snk_in_evt,  -- trigger verify to verify the last_snk_in
+    tb_end              => tb_end            -- signal end of tb as far as this dp_stream_stimuli is concerned
+  );
+
+
+  ------------------------------------------------------------------------------
+  -- DATA VERIFICATION
+  ------------------------------------------------------------------------------
+
+  -- Select fields that need to be verified
+  -- . during the test
+  verify_snk_in_enable.sync    <= '1';
+  verify_snk_in_enable.bsn     <= '1';
+  verify_snk_in_enable.data    <= '1' WHEN c_no_unpack=FALSE ELSE '0';
+  verify_snk_in_enable.re      <= '0';
+  verify_snk_in_enable.im      <= '0';
+  verify_snk_in_enable.valid   <= '1';
+  verify_snk_in_enable.sop     <= '1';
+  verify_snk_in_enable.eop     <= '1';
+  verify_snk_in_enable.empty   <= '0';
+  verify_snk_in_enable.channel <= '1';
+  verify_snk_in_enable.err     <= '1';
+
+  -- . after the test
+  verify_last_snk_in_evt.sync    <= last_snk_in_evt;
+  verify_last_snk_in_evt.bsn     <= last_snk_in_evt;
+  verify_last_snk_in_evt.data    <= last_snk_in_evt WHEN c_no_unpack=FALSE ELSE '0';
+  verify_last_snk_in_evt.re      <= '0';
+  verify_last_snk_in_evt.im      <= '0';
+  verify_last_snk_in_evt.valid   <= last_snk_in_evt;
+  verify_last_snk_in_evt.sop     <= last_snk_in_evt;
+  verify_last_snk_in_evt.eop     <= last_snk_in_evt;
+  verify_last_snk_in_evt.empty   <= '0';
+  verify_last_snk_in_evt.channel <= last_snk_in_evt;
+  verify_last_snk_in_evt.err     <= last_snk_in_evt;
+
+  u_dp_stream_verify : ENTITY dp_pkg_lib.dp_stream_verify
+  GENERIC MAP (
+    g_instance_nr    => 0,                        -- only one stream so choose index 0
+    -- flow control
+    g_random_w       => 14,                       -- use different random width for stimuli and for verify to have different random sequences
+    g_pulse_active   => c_verify_pulse_active,
+    g_pulse_period   => c_verify_pulse_period,
+    g_flow_control   => g_flow_control_verify,    -- always active, random or pulse flow control
+    -- initializations
+    g_sync_period    => c_sync_period,
+    g_sync_offset    => c_sync_offset,
+    g_snk_in_cnt_max => c_verify_snk_in_cnt_max,
+    g_snk_in_cnt_gap => c_verify_snk_in_cnt_gap,
+    -- specific
+    g_in_dat_w       => g_in_dat_w,
+    g_pkt_len        => c_expected_pkt_len
+  )
+  PORT MAP (
+    rst                        => rst,
+    clk                        => clk,
+
+    -- Verify data
+    snk_out                    => verify_snk_out,
+    snk_in                     => verify_snk_in,
+
+    -- During stimuli
+    verify_snk_in_enable       => verify_snk_in_enable,  -- enable verify to verify that the verify_snk_in fields are incrementing
+
+    -- End of stimuli
+    expected_snk_in            => last_snk_in,            -- expected verify_snk_in after end of stimuli
+    verify_expected_snk_in_evt => verify_last_snk_in_evt  -- trigger verify to verify the last_snk_in
+  );
+
+  ------------------------------------------------------------------------------
+  -- DUT Pack
+  ------------------------------------------------------------------------------
+
+  u_pack : ENTITY work.dp_repack_data
+  GENERIC MAP (
+    g_enable_repack_in  => c_enable_repack_in,
+    g_enable_repack_out => c_enable_repack_out,
+    g_in_bypass         => g_in_bypass,
+    g_in_dat_w          => g_in_dat_w,
+    g_in_nof_words      => g_in_nof_words,
+    g_in_symbol_w       => g_in_symbol_w,
+    g_out_bypass        => g_pack_bypass,
+    g_out_dat_w         => g_pack_dat_w,
+    g_out_nof_words     => g_pack_nof_words,
+    g_out_symbol_w      => g_pack_symbol_w
+  )
+  PORT MAP (
+    rst              => rst,
+    clk              => clk,
+
+    snk_out          => stimuli_src_in,
+    snk_in           => stimuli_src_out,
+
+    src_in           => pack_src_in,
+    src_out          => pack_src_out
+  );
+
+  pack_src_out_data <= pack_src_out.data(g_pack_dat_w-1 DOWNTO 0);
+
+  ------------------------------------------------------------------------------
+  -- DUT Unpack
+  ------------------------------------------------------------------------------
+
+  no_unpack : IF c_no_unpack=TRUE GENERATE
+    pack_src_in    <= unpack_src_in;
+    unpack_src_out <= pack_src_out;
+  END GENERATE;
+
+  gen_unpack : IF c_no_unpack=FALSE GENERATE
+    u_unpack : ENTITY work.dp_repack_data
+    GENERIC MAP (
+      g_enable_repack_in  => c_enable_repack_out,
+      g_enable_repack_out => c_enable_repack_in,
+      g_in_bypass         => g_pack_bypass,
+      g_in_dat_w          => g_pack_dat_w,
+      g_in_nof_words      => g_pack_nof_words,
+      g_in_symbol_w       => g_pack_symbol_w,
+      g_out_bypass        => g_in_bypass,
+      g_out_dat_w         => g_in_dat_w,
+      g_out_nof_words     => g_in_nof_words,
+      g_out_symbol_w      => g_in_symbol_w
+    )
+    PORT MAP (
+      rst              => rst,
+      clk              => clk,
+
+      snk_out          => pack_src_in,
+      snk_in           => pack_src_out,
+
+      src_in           => unpack_src_in,
+      src_out          => unpack_src_out
+    );
+  END GENERATE;
+
+  unpack_src_out_data <= unpack_src_out.data(g_in_dat_w-1 DOWNTO 0);
+
+  unpack_src_in <= verify_snk_out;
+  verify_snk_in <= unpack_src_out;
+  
+  ------------------------------------------------------------------------------
+  -- Auxiliary
+  ------------------------------------------------------------------------------
+
+  -- Map to slv to ease monitoring in wave window
+  stimuli_src_out_data <= stimuli_src_out.data(g_in_dat_w-1 DOWNTO 0);
+  verify_snk_in_data   <= verify_snk_in.data(g_in_dat_w-1 DOWNTO 0);
+
+END tb;
diff --git a/cores/base/dp/dp_repack_data/tb_tb_dp_repack_data.vhd b/cores/base/dp/dp_repack_data/tb_tb_dp_repack_data.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..62f5bdb7c4f788ef5e90c96955a5919678652ffc
--- /dev/null
+++ b/cores/base/dp/dp_repack_data/tb_tb_dp_repack_data.vhd
@@ -0,0 +1,166 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2015
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_pkg_lib, dp_pkg_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_pkg_lib.common_pkg.ALL;
+USE dp_pkg_lib.tb_dp_pkg.ALL;
+
+-- Purpose: Verify multiple variations of tb_dp_repack_data
+-- Description:
+-- Usage:
+-- > as 6
+-- > run -all
+
+ENTITY tb_tb_dp_repack_data IS
+END tb_tb_dp_repack_data;
+
+
+ARCHITECTURE tb OF tb_tb_dp_repack_data IS
+
+  CONSTANT c_nof_repeat  : NATURAL := 5;
+  
+  CONSTANT c_flow        : t_dp_flow_control_enum_arr := c_dp_flow_control_enum_arr;
+  CONSTANT c_bool        : t_nat_boolean_arr := c_nat_boolean_arr;
+  
+  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_active;  -- always e_active, e_random or e_pulse flow control
+  -- g_flow_control_verify    : t_dp_flow_control_enum := e_active;  -- always e_active, e_random or e_pulse flow control
+  -- -- specific
+  -- g_in_dat_w               : NATURAL := 5;
+  -- g_in_nof_words           : NATURAL := 2;
+  -- g_pack_dat_w             : NATURAL := 16;
+  -- g_pack_nof_words         : NATURAL := 1;
+  -- g_in_bypass              : BOOLEAN := FALSE;  -- can use TRUE when g_in_nof_words=1  or g_in_nof_words=g_out_nof_words
+  -- g_pack_bypass            : BOOLEAN := FALSE;  -- can use TRUE when g_out_nof_words=1 or g_in_nof_words=g_out_nof_words
+  -- g_in_symbol_w            : NATURAL := 1;      -- default 1 for snk_in.empty  in nof bits, else use power of 2
+  -- g_pack_symbol_w          : NATURAL := 1;      -- default 1 for src_out.empty in nof bits, else use power of 2
+  -- g_nof_repeat             : NATURAL := 10;
+  -- g_pkt_len                : NATURAL := 11;     -- if not a multiple of g_in_nof_words then the input stage flush creates gap between blocks
+  -- g_pkt_gap                : NATURAL := 0
+  
+  g_flow_control_stimuli : FOR I IN 0 TO 2 GENERATE    -- 0 = e_active, 1 = e_random, 2 = e_pulse
+    g_flow_control_verify : FOR J IN 0 TO 2 GENERATE    -- 0 = e_active, 1 = e_random, 2 = e_pulse
+
+      -------------------------------------------------------------------------
+      -- Tests that can use bypass
+      -- . g_in_nof_words = 1
+      -- . g_out_nof_words = 1
+      -- . g_in_nof_words = g_in_nof_words >= 1
+      -------------------------------------------------------------------------
+      
+      gen_bool_bypass : FOR K IN 0 TO 1 GENERATE
+        gen_bool_bypass : FOR L IN 0 TO 1 GENERATE
+          -- no repack, g_in_nof_words = g_out_nof_words = 1
+          u_16_1_16_1_len_10_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 16, 1, 16, 1, c_bool(K), c_bool(L), 1, 1, c_nof_repeat, 10, 0);  -- g_pkt_len > g_in_nof_words
+          u_16_1_16_1_len_3_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 16, 1, 16, 1, c_bool(K), c_bool(L), 1, 1, c_nof_repeat,  3, 0);  -- g_pkt_len > g_in_nof_words, odd
+          u_16_1_16_1_len_2_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 16, 1, 16, 1, c_bool(K), c_bool(L), 1, 1, c_nof_repeat,  2, 0);  -- g_pkt_len > g_in_nof_words, even
+          u_16_1_16_1_len_1_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 16, 1, 16, 1, c_bool(K), c_bool(L), 1, 1, c_nof_repeat,  1, 0);  -- g_pkt_len = g_in_nof_words
+          
+          u_16_1_16_1_len_1_gap_1    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 16, 1, 16, 1, c_bool(K), c_bool(L), 1, 1, c_nof_repeat,  1, 1);  -- g_pkt_gap > 0
+        END GENERATE;
+      
+        -- no repack, g_in_nof_words = g_out_nof_words > 1
+        u_16_3_16_3_len_10_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  16, 3, 16, 3, c_bool(K), c_bool(K), 1, 1, c_nof_repeat, 10,  0);
+        
+        -- g_in_nof_words > g_pack_nof_words can use always active stimuli except when g_pkt_len MOD g_in_nof_words /= 0, because then the input stage needs to flush
+        u_8_4_32_1_len_1_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat,  1,  0);  -- g_pkt_len < g_in_nof_words
+        u_8_4_32_1_len_2_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat,  2,  0);  -- g_pkt_len = g_in_nof_words
+        u_8_4_32_1_len_3_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat,  3,  0);  -- g_pkt_len > g_in_nof_words, MOD /= 0
+        u_8_4_32_1_len_10_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat, 10,  0);  -- g_pkt_len > g_in_nof_words, MOD /= 0
+        u_8_4_32_1_len_11_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat, 11,  0);  -- g_pkt_len > g_in_nof_words, MOD /= 0
+        u_8_4_32_1_len_12_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat, 12,  0);  -- g_pkt_len > g_in_nof_words, MOD = 0
+      
+        u_8_4_32_1_len_12_gap_2    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 4, 32, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat, 12,  2);  -- g_pkt_gap > 0
+      
+        -- g_in_nof_words < g_pack_nof_words will apply backpressure, because the output stage needs to output more
+        u_32_1_8_4_len_1_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 32, 1, 8, 4, c_bool(K), FALSE, 1, 1, c_nof_repeat,  1,  0);  -- g_pkt_len = g_in_nof_words
+        u_32_1_8_4_len_2_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 32, 1, 8, 4, c_bool(K), FALSE, 1, 1, c_nof_repeat,  2,  0);  -- g_pkt_len > g_in_nof_words
+        u_32_1_8_4_len_3_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 32, 1, 8, 4, c_bool(K), FALSE, 1, 1, c_nof_repeat,  3,  0);  -- g_pkt_len > g_in_nof_words
+        u_32_1_8_4_len_10_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 32, 1, 8, 4, c_bool(K), FALSE, 1, 1, c_nof_repeat, 10,  0);  -- g_pkt_len > g_in_nof_words
+        
+        u_32_1_8_4_len_11_gap_1    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 32, 1, 8, 4, c_bool(K), FALSE, 1, 1, c_nof_repeat, 11,  1);  -- g_pkt_gap > 0
+      
+        -- g_in_dat_w MOD 8 /= 0, g_in_nof_words=1
+        u_14_1_8_2_len_10_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 14, 1, 8, 2, c_bool(K), FALSE, 1, 1, c_nof_repeat, 10,  0);  -- repack with subsection padding, even multiple of g_in_nof_words
+        u_14_1_8_2_len_11_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 14, 1, 8, 2, c_bool(K), FALSE, 1, 1, c_nof_repeat, 11,  0);  -- repack with subsection padding, odd multiple of g_in_nof_words
+        
+        -- g_in_dat_w MOD 8 /= 0, g_out_nof_words=1
+        u_5_2_16_1_len_10_gap_0  : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 5, 2, 16, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat, 10,  0);  -- repack with subsection padding, integer multiple of g_in_nof_words
+        u_5_2_16_1_len_11_gap_0  : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 5, 2, 16, 1, FALSE, c_bool(K), 1, 1, c_nof_repeat, 11,  0);  -- repack with subsection padding, fractional multiple of g_in_nof_words
+        
+        -- g_in_nof_words=1, g_pack_nof_words>1
+        u_8_1_4_2_len_10_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   8, 1,  4,  2, c_bool(K), FALSE, 1, 1, c_nof_repeat, 10,  0);
+        u_512_1_32_16_len_1_gap_20 : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 512, 1, 32, 16, c_bool(K), FALSE, 1, 1, c_nof_repeat,  1, 20);  -- pack a larger header slv into g_pack_dat_w words
+        
+        -- serialize to and deserialize from g_pack_dat_w=1 bit
+        u_8_1_1_8_len_10_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  8, 1, 1,  8, c_bool(K), FALSE, 1, 1, c_nof_repeat, 10,  0);  -- g_pack_dat_w=1
+        u_32_1_1_32_len_10_gap_7   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 32, 1, 1, 32, c_bool(K), FALSE, 1, 1, c_nof_repeat, 10,  7);  -- g_pack_dat_w=1
+      
+        -- g_in_symbol_w /= 1, g_out_symbol_w /= 1
+        u_20_1_8_3_symbol_1_4_len_10_gap_0  : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 20, 1, 8, 3, c_bool(K), FALSE, 1, 4, c_nof_repeat, 10, 0);  -- no repack
+        u_20_1_8_3_symbol_4_1_len_10_gap_0  : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 20, 1, 8, 3, c_bool(K), FALSE, 4, 1, c_nof_repeat, 10, 0);  -- no repack
+        u_20_1_8_3_symbol_4_4_len_10_gap_0  : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 20, 1, 8, 3, c_bool(K), FALSE, 4, 4, c_nof_repeat, 10, 0);  -- no repack
+        
+        -- pack ETH/IP/UDP header, g_in_symbol_w = 8, g_out_symbol_w = 8
+        u_336_1_32_11_symbol_8_8_len_1_gap_0  : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 336, 1, 32, 11, c_bool(K), FALSE, 8, 8, c_nof_repeat, 1, 0);  --pack to 32 bit --> empty = 2
+        u_336_1_64_6_symbol_8_8_len_1_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J), 336, 1, 64,  6, c_bool(K), FALSE, 8, 8, c_nof_repeat, 1, 0);  --pack to 64 bit --> empty = 6
+      END GENERATE;
+      
+      -------------------------------------------------------------------------
+      -- Tests that cannot use bypass
+      -------------------------------------------------------------------------
+      
+      -- g_in_nof_words > 1 and g_pack_nof_words > 1
+      u_24_2_16_3_len_1_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  24, 2, 16, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  1, 0);  -- g_pkt_len < g_in_nof_words
+      u_24_2_16_3_len_2_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  24, 2, 16, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  2, 0);  -- g_pkt_len = g_in_nof_words
+      u_24_2_16_3_len_3_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  24, 2, 16, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  3, 0);  -- g_pkt_len = fractional multiple of g_in_nof_words
+      u_24_2_16_3_len_10_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  24, 2, 16, 3, FALSE, FALSE, 1, 1, c_nof_repeat, 10, 0);  -- g_pkt_len = integer multiple of g_in_nof_words
+      u_24_2_16_3_len_11_gap_0   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  24, 2, 16, 3, FALSE, FALSE, 1, 1, c_nof_repeat, 11, 0);  -- g_pkt_len = fractional multiple of g_in_nof_words
+      
+      u_24_2_16_3_len_11_gap_3   : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  24, 2, 16, 3, FALSE, FALSE, 1, 1, c_nof_repeat, 11, 3);  -- g_pkt_gap > 0
+
+      -- g_in_dat_w MOD 8 /= 0
+      u_6_5_10_3_len_1_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  1, 0);  -- g_pkt_len < g_in_nof_words
+      u_6_5_10_3_len_2_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  2, 0);  -- g_pkt_len < g_in_nof_words
+      u_6_5_10_3_len_3_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  3, 0);  -- g_pkt_len < g_in_nof_words
+      u_6_5_10_3_len_4_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  4, 0);  -- g_pkt_len < g_in_nof_words
+      u_6_5_10_3_len_5_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat,  5, 0);  -- g_pkt_len = g_in_nof_words
+      u_6_5_10_3_len_10_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat, 10, 0);  -- g_pkt_len = integer multiple of g_in_nof_words
+      u_6_5_10_3_len_11_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat, 11, 0);  -- g_pkt_len = fractional multiple of g_in_nof_words
+      
+      u_6_5_10_3_len_21_gap_3    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),   6, 5, 10, 3, FALSE, FALSE, 1, 1, c_nof_repeat, 21, 3);  -- g_pkt_gap > 0
+      
+      -- subsection padding, g_in_dat_w * g_in_nof_words < g_pack_dat_w * g_pack_nof_words
+      u_18_2_8_5_len_1_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  18, 2,  8, 5, FALSE, FALSE, 1, 1, c_nof_repeat,  1, 0);  -- g_pkt_len < g_in_nof_words
+      u_18_2_8_5_len_2_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  18, 2,  8, 5, FALSE, FALSE, 1, 1, c_nof_repeat,  2, 0);  -- g_pkt_len = g_in_nof_words
+      u_18_2_8_5_len_3_gap_0     : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  18, 2,  8, 5, FALSE, FALSE, 1, 1, c_nof_repeat,  3, 0);  -- g_pkt_len = fractional multiple of g_in_nof_words
+      u_18_2_8_5_len_10_gap_0    : ENTITY work.tb_dp_repack_data GENERIC MAP (c_flow(I), c_flow(J),  18, 2,  8, 5, FALSE, FALSE, 1, 1, c_nof_repeat, 10, 0);  -- g_pkt_len = integer multiple of g_in_nof_words
+      
+    END GENERATE;
+  END GENERATE;
+                                                                                               
+END tb;
diff --git a/cores/copy_source_files.py b/cores/copy_source_files.py
new file mode 100644
index 0000000000000000000000000000000000000000..09c28c4d0156f20179cd5a514e4bcd8738110dc2
--- /dev/null
+++ b/cores/copy_source_files.py
@@ -0,0 +1,63 @@
+# Author:
+# . Daniel van der Schuur
+# Purpose:
+# . Copy the VHD files from the horizontal $RADIOHDL/libraries libraries to
+#   the vertical libraries located here.
+# Description:
+# . This script scans the hdllib.cfg files located here, then searches
+#   for the listed .vhd file in the horizontal library dirs, and copies it.
+# Remark:
+# . This script could be adapted to call 'svn move' for full migration.
+
+import os
+from shutil import copyfile
+
+"""
+Recursively find occurences of fname in dirname, returns them as list.
+"""
+def find_files(fname, dirname):
+    found_files = []
+    for root, dirs, files in os.walk(dirname):
+      for file in files:
+        if file==fname:
+          found_files.append(os.path.join(root, file))
+        if fname[0]=='*' and file.endswith(fname[1:]):
+          found_files.append(os.path.join(root, file))
+    return found_files
+
+###############################################################################
+# Find the .vhd file listed in the hdllib.cfg and copy it here
+###############################################################################
+if __name__== '__main__':
+
+    for hdllib_file in find_files('hdllib.cfg', '.') :
+    
+        # Set the current target path (hdllib.cfg dir)
+        target_path = os.path.abspath(os.path.dirname(hdllib_file))+'/'
+    
+        # Read the hdllib.cfg file into a list
+        with open(hdllib_file) as f:
+            lines = f.readlines()
+    
+        # Get the paths to the required .VHD files
+        for line in lines:
+            if '.vhd' in line:
+                vhd_file = line.strip('\n').strip(' ')
+    
+                # Find the VHD file in the horizontal RadioHDL libraries
+                found_files = find_files(vhd_file, os.environ['RADIOHDL']+'/libraries')
+    
+                # Copy the VHD file here 
+                if len(found_files)>1:
+                    print 'Warning: multiple files found:'
+                    print vhd_file, found_files
+               
+                try:
+                    print 'Copying', found_files[0], 'to', target_path+vhd_file
+                    copyfile(found_files[0], target_path+vhd_file)
+                except:
+                    print 'Warning: could not copy', vhd_file, found_files, 'to', target_path
+
+
+
+
diff --git a/cores/edit_source_files.py b/cores/edit_source_files.py
new file mode 100644
index 0000000000000000000000000000000000000000..bbe54c491725c8004de8c6d134812c2c28984533
--- /dev/null
+++ b/cores/edit_source_files.py
@@ -0,0 +1,134 @@
+# Author:
+# . Daniel van der Schuur
+# Purpose:
+# . Edit the (copied) source files to make them include and use vertical 
+#   libraries instead of horizontal ones.
+# Description:
+# . The included horizontal libraries at the top are replaced by vertical ones;
+# . The horizontal libraries named in the instantiations are replaced with
+#   vertical ones.
+
+from copy_source_files import find_files
+import os
+
+REPLACE_LIST = [
+
+# common_pkg_lib
+['common_lib.common_pkg','common_pkg_lib.common_pkg'],
+['work.common_pkg','common_pkg_lib.common_pkg'],
+
+['common_lib.common_str_pkg','common_pkg_lib.common_str_pkg'],
+['work.common_str_pkg','common_pkg_lib.common_str_pkg'],
+
+['common_lib.common_lfsr_sequences_pkg','common_pkg_lib.common_lfsr_sequences_pkg'],
+['work.common_lfsr_sequences_pkg','common_pkg_lib.common_lfsr_sequences_pkg'],
+
+['common_lib.tb_common_pkg','common_pkg_lib.tb_common_pkg'],
+['work.tb_common_pkg','common_pkg_lib.tb_common_pkg'],
+
+# dp_pkg_lib
+['dp_lib.dp_stream_pkg','dp_pkg_lib.dp_stream_pkg'],
+['work.dp_stream_pkg','dp_pkg_lib.dp_stream_pkg'],
+
+['dp_lib.tb_dp_pkg','dp_pkg_lib.tb_dp_pkg'],
+['work.tb_dp_pkg','dp_pkg_lib.tb_dp_pkg'],
+
+['dp_lib.dp_stream_stimuli','dp_pkg_lib.dp_stream_stimuli'],
+['work.dp_stream_stimuli','dp_pkg_lib.dp_stream_stimuli'],
+
+['dp_lib.dp_stream_verify','dp_pkg_lib.dp_stream_verify'],
+['work.dp_stream_verify','dp_pkg_lib.dp_stream_verify'],
+
+# common_components_lib
+['common_lib.common_switch','common_components_lib.common_switch'],
+['work.common_switch','common_components_lib.common_switch'],
+
+# dp_components_lib
+['dp_lib.dp_hold_input','dp_components_lib.dp_hold_input'],
+['work.dp_hold_input','dp_components_lib.dp_hold_input'],
+
+['dp_lib.dp_hold_ctrl','dp_components_lib.dp_hold_ctrl'],
+['work.dp_hold_ctrl','dp_components_lib.dp_hold_ctrl'],
+
+['dp_lib.dp_latency_increase','dp_components_lib.dp_latency_increase'],
+['work.dp_latency_increase','dp_components_lib.dp_latency_increase'],
+
+['dp_lib.dp_latency_adapter','dp_components_lib.dp_latency_adapter'],
+['work.dp_latency_adapter','dp_components_lib.dp_latency_adapter'],
+
+# dp_pipeline_lib
+['dp_lib.dp_pipeline','dp_pipeline_lib.dp_pipeline'],
+['work.dp_pipeline','dp_pipeline_lib.dp_pipeline'],
+
+['dp_lib.dp_pipeline_ready','dp_pipeline_lib.dp_pipeline_ready'],
+['work.dp_pipeline_ready','dp_pipeline_lib.dp_pipeline_ready'],
+
+# Delete any remaining references to horizontal libs
+[', common_lib', ''],
+['common_lib', ''],
+[', dp_lib', ''],
+['dp_lib', '']
+
+]
+
+for vhd_file in find_files('*.vhd', '.'):
+
+    core_lib = os.path.dirname(vhd_file).split('/')[-1]+'_lib'
+    print 'Editing', vhd_file
+
+    # Read the VHDL file into a list
+    with open(vhd_file) as f:
+        lines = f.readlines()
+        newlines= []
+
+        # Remove strings from VHDL file
+        for line in lines:
+            newline = line
+            for item in REPLACE_LIST:
+                replace=True
+                if 'work.' in line:
+                    libname=item[1].split('.')[0]
+                    if libname==core_lib:
+                        replace=False
+                if replace==True:
+                    newline = newline.replace(item[0], item[1])
+            
+            newlines.append(newline)
+
+        # find all lines with '_lib'
+        lib_lines = []
+        for line in newlines:
+            if '_lib' in line:
+                lib_lines.append(line)
+        # extract full library name from that line
+        libs = []
+        for line in lib_lines:
+            if 'USE' in line:
+                libname = line.split('.')[0].strip('USE ')
+                if not libname==core_lib: # don't add the work lib as dependency
+                    libs.append(libname)
+            elif 'ENTITY' in line:
+                libname = line.split('.')[0].split(' ')[-1]
+                if not libname==core_lib: # don't add the work lib as dependency
+                    libs.append(libname)
+
+        unique_libs = list(set(libs))        
+        lib_str = str(unique_libs).strip('[]').replace("'", '')
+
+        # Replace the LIBRARY declaration with an updated, complete one
+        final_lines = []
+        for line in newlines:
+            final_line = line
+            if 'LIBRARY' in line and len(unique_libs)>0:
+                final_line = 'LIBRARY IEEE, '+ lib_str + ';\n'
+
+            final_lines.append(final_line.replace('\r', ''))
+            
+        
+    with open(vhd_file, 'wb') as f:
+        f.writelines(final_lines)
+
+    f.close()
+        
+    
+
diff --git a/cores/readme.txt b/cores/readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e6c81efd58fa6e4b000217f6b5d627d9556e5db8
--- /dev/null
+++ b/cores/readme.txt
@@ -0,0 +1,41 @@
+(Daniel van der Schuur, 17 Oct. 2018)
+
+Summary
+=======
+This directory contains vertically grouped versions of the horizontal RadioHDL
+HDL libraries, intended to be uploaded to OpenCores. It cannot harm the current 
+horizontal libraries, yet it syncs the vertical libs with the horizontal ones,
+and provides a clean migration possibility.
+
+Introduction
+============
+This 'cores' directory contains VHDL libraries from the RadioHDL repository, but
+organized differently:
+- The RadioHDL repository has the HDL files ordered in horizontal libraries,
+  grouped together based on hierarchical layer. E.g. all technology-specific 
+  HDL files are in the 'technology'-library, and all 'common' HDL files are
+  grouped together in one very large library as well.
+- This cores repository contains the same (though slightly modifed) HDL files,
+  but grouped together vertically. For example, the dp_mux and dp_demux belong
+  to the very large horizontal 'dp'-library, but here they belong to the 
+  'dp_mux' library.
+
+The original horizontal organization is however still maintained as directory
+structure; e.g. all vertical 'dp' cores are in the 'dp' directory.
+
+copy_source_files.py
+====================
+This script copies the source files from the horizontal RadioHDL repository,
+with the purpose of:
+1) Keeping this 'cores' library in sync with our 'official' RadioHDL library,
+   without risk of doing damage to it.
+2) Provide option to migrate to this vertical for by calling 'svn move'
+
+edit_source_files.py
+====================
+This script edits the copied files such that:
+1) the included horizontal libraries at the top are replaced by vertical ones;
+2) the horizontal libraries named in the instantiations are replaced with
+   vertical ones.
+
+