From fd6c573c72a600ed4f378e7ec46503b2b6fedf10 Mon Sep 17 00:00:00 2001
From: Pepping <pepping>
Date: Thu, 10 Dec 2015 13:08:49 +0000
Subject: [PATCH] svn copy

---
 libraries/io/aduh/tb/vhdl/adc08d1020.vhd      | 137 ++++++
 libraries/io/aduh/tb/vhdl/adu_half.vhd        | 179 ++++++++
 libraries/io/aduh/tb/vhdl/tb_aduh_dd.vhd      | 313 ++++++++++++++
 .../io/aduh/tb/vhdl/tb_aduh_mean_sum.vhd      | 152 +++++++
 libraries/io/aduh/tb/vhdl/tb_aduh_pll.vhd     | 409 ++++++++++++++++++
 .../io/aduh/tb/vhdl/tb_aduh_power_sum.vhd     | 151 +++++++
 libraries/io/aduh/tb/vhdl/tb_aduh_verify.vhd  | 260 +++++++++++
 libraries/io/aduh/tb/vhdl/tb_lvdsh_dd.vhd     | 142 ++++++
 .../io/aduh/tb/vhdl/tb_lvdsh_dd_phs4.vhd      | 301 +++++++++++++
 libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_wb4.vhd | 230 ++++++++++
 .../io/aduh/tb/vhdl/tb_mms_aduh_quad.vhd      | 338 +++++++++++++++
 .../io/aduh/tb/vhdl/tb_tb_lvdsh_dd_phs4.vhd   |  53 +++
 .../io/aduh/tb/vhdl/tb_tb_lvdsh_dd_wb4.vhd    |  46 ++
 13 files changed, 2711 insertions(+)
 create mode 100644 libraries/io/aduh/tb/vhdl/adc08d1020.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/adu_half.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_aduh_dd.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_aduh_mean_sum.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_aduh_pll.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_aduh_power_sum.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_aduh_verify.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_lvdsh_dd.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_phs4.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_wb4.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_mms_aduh_quad.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_phs4.vhd
 create mode 100644 libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_wb4.vhd

diff --git a/libraries/io/aduh/tb/vhdl/adc08d1020.vhd b/libraries/io/aduh/tb/vhdl/adc08d1020.vhd
new file mode 100644
index 0000000000..7f5d96d057
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/adc08d1020.vhd
@@ -0,0 +1,137 @@
+-------------------------------------------------------------------------------
+--
+-- 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_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+
+-- Purpose: Behavioral model of the National adc08d1020 ADC on the ADU
+-- Description:
+--   The adc08d1020 model features:
+--   . the sampling analogue input data via AI, AQ and overflow via AOVR
+--   . offset binary ADC data format
+--   . the internal ADC test pattern generation when test_pattern_en is '1'
+--   . allows dynamic setting of skew for each LVDS line
+
+ENTITY adc08d1020 IS
+  GENERIC (
+    g_clk_period      : TIME := 1250 ps;  -- Sample clock period of CLK
+    g_dclk_init_phase : NATURAL := 0  -- When 0 then use default phase for DCLK, else use the other DDR phase
+  );
+  PORT (
+    AI              : IN  INTEGER := 0;
+    AQ              : IN  INTEGER := 0;
+    AOVR            : IN  STD_LOGIC := '0';
+    CLK             : IN  STD_LOGIC := '0';
+    DCLK            : OUT STD_LOGIC;
+    DCLK_RST        : IN  STD_LOGIC := '0';
+    DI              : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
+    DQ              : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
+    OVR             : OUT STD_LOGIC;
+    
+    test_pattern_en : IN STD_LOGIC := '0';
+    lvds_skew_di    : IN t_natural_arr(7 DOWNTO 0) := (OTHERS=>0);  -- ps unit
+    lvds_skew_dq    : IN t_natural_arr(7 DOWNTO 0) := (OTHERS=>0);  -- ps unit
+    lvds_skew_ovr   : IN NATURAL := 0;                              -- ps unit
+    lvds_skew_dclk  : IN NATURAL := 0                               -- ps unit
+  );
+END adc08d1020;
+
+
+ARCHITECTURE beh OF adc08d1020 IS
+
+  CONSTANT c_nof_adc  : NATURAL := 2;                -- for AI and AQ
+
+  TYPE t_adc_dat_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
+
+  SIGNAL adc_dat  : t_adc_dat_arr(0 TO c_nof_adc-1);  -- [0] = AI, [1] = AQ
+  SIGNAL adc_ovr  : STD_LOGIC;
+  
+  SIGNAL tp_cnt   : NATURAL := 0;  -- test pattern sequence index counter
+  
+  SIGNAL dclk_dis : STD_LOGIC := '0';
+  SIGNAL ddr_clk  : STD_LOGIC := sel_a_b(g_dclk_init_phase, '1', '0');
+  
+BEGIN
+
+  -- Sample the analogue I and Q input using the falling edge of the sample clock CLK
+  p_sample : PROCESS(CLK)
+  BEGIN
+    IF falling_edge(CLK) THEN
+      IF test_pattern_en='0' THEN
+        adc_dat(0) <= offset_binary(TO_SVEC(AI, 8));
+        adc_dat(1) <= offset_binary(TO_SVEC(AQ, 8));
+        adc_ovr    <= AOVR;
+      ELSE
+        --    TP_I TP_Q  TP_OV
+        -- T0 02h  01h   0
+        -- T1 FDh  FEh   1
+        -- T2 02h  01h   0
+        -- T3 02h  01h   0
+        -- T4 FDh  FEh   1
+        -- T5 FDh  FEh   1
+        -- T6 02h  01h   0
+        -- T7 02h  01h   0
+        -- T8 FDh  FEh   1
+        -- T9 02h  01h   0
+        CASE tp_cnt IS
+          WHEN 0 | 2 | 3 | 6 | 7 | 9 => adc_dat(0) <= TO_UVEC(16#02#, 8); adc_dat(1) <= TO_UVEC(16#01#, 8); adc_ovr <= '0';
+          WHEN OTHERS                => adc_dat(0) <= TO_UVEC(16#FD#, 8); adc_dat(1) <= TO_UVEC(16#FE#, 8); adc_ovr <= '1';
+        END CASE;
+        tp_cnt <= tp_cnt + 1;
+        IF tp_cnt = 9 THEN
+          tp_cnt <= 0;
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  -- Disable the DDR clock during the DCLK_RST and delay the DDR clock after release of DCLK_RST
+  p_dclk_dis : PROCESS(DCLK_RST, CLK)
+    VARIABLE v_cnt : NATURAL;
+  BEGIN
+    IF DCLK_RST='1' THEN
+      dclk_dis <= '1';
+      v_cnt := 0;
+    ELSIF rising_edge(CLK) THEN
+      dclk_dis <= '0';
+      IF v_cnt<8 THEN   -- latency 3 or 4 CLK cycles and 4 ns propagation delay, so in total about 8 CLK cycles
+        dclk_dis <= '1';
+        v_cnt := v_cnt+1;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  -- Create the DDR clock that is half the rate of the sample clock CLK
+  ddr_clk <= '0' WHEN dclk_dis='1' ELSE NOT ddr_clk WHEN falling_edge(CLK);
+             
+  -- Apply the skew to each LVDS trace
+  gen_skew : FOR S IN 7 DOWNTO 0 GENERATE
+    DI(S) <= TRANSPORT adc_dat(0)(S) AFTER lvds_skew_di(S)* 1 ps;
+    DQ(S) <= TRANSPORT adc_dat(1)(S) AFTER lvds_skew_dq(S)* 1 ps;
+  END GENERATE;
+  
+  OVR  <= TRANSPORT adc_ovr AFTER lvds_skew_ovr * 1 ps;
+  DCLK <= TRANSPORT ddr_clk AFTER lvds_skew_dclk * 1 ps;
+  
+END beh;
diff --git a/libraries/io/aduh/tb/vhdl/adu_half.vhd b/libraries/io/aduh/tb/vhdl/adu_half.vhd
new file mode 100644
index 0000000000..d377d573f6
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/adu_half.vhd
@@ -0,0 +1,179 @@
+-------------------------------------------------------------------------------
+--
+-- 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_lib, i2c_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE i2c_lib.i2c_dev_adu_pkg.ALL;
+
+-- Purpose: Behavioral model of the half ADU including the rewiring on the
+--          backplane (AUB)
+-- Description:
+-- . The half ADU consists of one adc08d1020 which has two ADCs that output
+--   via DI[7:0] and DQ[7:0]. The DI port is wired default, but the DQ port
+--   is cross-wired on the ADU-UniBoard backplane PCB to ease layout.
+-- . Models the I2C peripherals on ADU
+
+ENTITY adu_half IS
+  GENERIC (
+    g_dclk_init_phase : NATURAL := 0     -- When 0 then use default phase for DCLK, else use the other DDR phase
+  );
+  PORT (
+    AI              : IN  INTEGER := 0;
+    AQ              : IN  INTEGER := 0;
+    AOVR            : IN  STD_LOGIC := '0';
+    CLK             : IN  STD_LOGIC := '0';
+    DCLK            : OUT STD_LOGIC;
+    DCLK_RST        : IN  STD_LOGIC := '1';  -- inverted
+    DI              : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
+    DQ              : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
+    OVR             : OUT STD_LOGIC;
+    SCL             : INOUT STD_LOGIC;
+    SDA             : INOUT STD_LOGIC;
+    
+    test_pattern_en : IN STD_LOGIC := '0';
+    lvds_skew_di    : IN t_natural_arr(7 DOWNTO 0) := (OTHERS=>0);  -- ps unit
+    lvds_skew_dq    : IN t_natural_arr(7 DOWNTO 0) := (OTHERS=>0);  -- ps unit
+    lvds_skew_ovr   : IN NATURAL := 0;                              -- ps unit
+    lvds_skew_dclk  : IN NATURAL := 0                               -- ps unit
+  );
+END adu_half;
+
+
+ARCHITECTURE beh OF adu_half IS
+
+  CONSTANT c_dclk_rst_invert : BOOLEAN := FALSE;  -- Default FALSE because DCLK_RST on ADC is active high, use TRUE to model for a P/N cross
+  
+  -- Model I2C slaves on the bus
+  CONSTANT c_max1618_address      : STD_LOGIC_VECTOR := TO_UVEC(I2C_ADU_MAX1617_ADR, 7);  -- MAX1618 address MID MID
+  CONSTANT c_max1618_temp         : INTEGER := 60;
+  CONSTANT c_io_expander_address  : STD_LOGIC_VECTOR := TO_UVEC(I2C_ADU_PCA9555_ADR, 7);  -- ADR_PCA9555 address
+  
+  SIGNAL DI_rewire : STD_LOGIC_VECTOR(7 DOWNTO 0);
+  SIGNAL DQ_rewire : STD_LOGIC_VECTOR(7 DOWNTO 0);
+  
+  SIGNAL DCLK_RST_rewire : STD_LOGIC;
+  
+  -- IO expander  
+  SIGNAL iobank0           : STD_LOGIC_VECTOR(7 DOWNTO 0);
+  SIGNAL iobank1           : STD_LOGIC_VECTOR(7 DOWNTO 0);
+  
+  -- IO expander ADU
+  SIGNAL adu_sclk              : STD_LOGIC;
+  SIGNAL adu_sdata             : STD_LOGIC;
+  SIGNAL adu_led_scs_n         : STD_LOGIC;
+  SIGNAL adu_cal_adc           : STD_LOGIC;
+  SIGNAL adu_pwr_ctrl          : STD_LOGIC_VECTOR(1 DOWNTO 0);
+  SIGNAL adu_pwr_ctrl_1_dig    : STD_LOGIC;
+  SIGNAL adu_pwr_ctrl_0_ana    : STD_LOGIC;
+  SIGNAL adu_ctrl              : STD_LOGIC_VECTOR(3 DOWNTO 0);
+  SIGNAL adu_ctrl_0_atten_le   : STD_LOGIC;
+  SIGNAL adu_ctrl_1_modem_on   : STD_LOGIC;
+  SIGNAL adu_ctrl_2_atten_le   : STD_LOGIC;
+  SIGNAL adu_ctrl_3_modem_on   : STD_LOGIC;
+  
+  SIGNAL adu_atten_ctrl        : STD_LOGIC_VECTOR(5 DOWNTO 0);
+  
+BEGIN
+
+  -- I port A and C wire default
+  DI <= DI_rewire;
+  
+  -- Q port B and D are rewired on AUB and on the single BN-ADU connector board:
+  DQ(0) <= DQ_rewire(6);
+  DQ(1) <= DQ_rewire(7);
+  DQ(2) <= DQ_rewire(4);
+  DQ(3) <= DQ_rewire(5);
+  DQ(4) <= DQ_rewire(2);
+  DQ(5) <= DQ_rewire(3);
+  DQ(6) <= DQ_rewire(0);
+  DQ(7) <= DQ_rewire(1);
+  
+  -- Model swapped P/N pins at the UniBoard back node by a NOT, see also in BACK_NODE_adc_pins.tcl and aduh_dd.vhd
+  DCLK_RST_rewire <= DCLK_RST WHEN c_dclk_rst_invert=FALSE ELSE NOT DCLK_RST;
+
+  u_adc : ENTITY work.adc08d1020
+  GENERIC MAP (
+    g_dclk_init_phase => g_dclk_init_phase
+  )
+  PORT MAP (
+    AI              => AI,
+    AQ              => AQ,
+    AOVR            => AOVR,
+    CLK             => CLK,
+    DCLK            => DCLK,
+    DCLK_RST        => DCLK_RST_rewire,
+    DI              => DI_rewire,
+    DQ              => DQ_rewire,
+    OVR             => OVR,
+    
+    test_pattern_en => test_pattern_en,
+    lvds_skew_di    => lvds_skew_di,
+    lvds_skew_dq    => lvds_skew_dq,
+    lvds_skew_ovr   => lvds_skew_ovr,
+    lvds_skew_dclk  => lvds_skew_dclk
+  );
+  
+  -- I2C bus
+  SCL <= 'H';          -- model I2C pull up
+  SDA <= 'H';          -- model I2C pull up
+  
+  u_sens_temp : ENTITY i2c_lib.dev_max1618
+  GENERIC MAP (
+    g_address => c_max1618_address
+  )
+  PORT MAP (
+    scl  => SCL,
+    sda  => SDA,
+    temp => c_max1618_temp
+  );
+
+  u_io_expander : ENTITY i2c_lib.dev_pca9555
+  GENERIC MAP (
+    g_address => c_io_expander_address
+  )
+  PORT MAP (
+    scl       => SCL,
+    sda       => SDA,
+    iobank0   => iobank0,
+    iobank1   => iobank1
+  );
+    
+  -- ADU interpretation of the IO expander outputs
+  adu_sclk            <= iobank0(4);
+  adu_sdata           <= iobank0(5);
+  adu_led_scs_n       <= iobank0(7);
+  adu_cal_adc         <= iobank1(7);
+  adu_pwr_ctrl        <= iobank0(6) & iobank1(6);
+  adu_pwr_ctrl_1_dig  <= adu_pwr_ctrl(1);
+  adu_pwr_ctrl_0_ana  <= adu_pwr_ctrl(0);
+
+  adu_ctrl            <= iobank0(3 DOWNTO 0);
+  adu_ctrl_0_atten_le <= adu_ctrl(0);
+  adu_ctrl_1_modem_on <= adu_ctrl(1);
+  adu_ctrl_2_atten_le <= adu_ctrl(2);
+  adu_ctrl_3_modem_on <= adu_ctrl(3);
+  
+  adu_atten_ctrl      <= iobank1(5 DOWNTO 0);  
+  
+END beh;
diff --git a/libraries/io/aduh/tb/vhdl/tb_aduh_dd.vhd b/libraries/io/aduh/tb/vhdl/tb_aduh_dd.vhd
new file mode 100644
index 0000000000..cb164a40b8
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_aduh_dd.vhd
@@ -0,0 +1,313 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Usage:
+-- > as 10
+-- > run -all
+-- > observe verify_data as hexadecimal in Wave window, shows the incrementing ADC data when lvds_skew_di = c_lvds_skew_zero and lvds_skew_dq = c_lvds_skew_zero
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+USE work.aduh_dd_pkg.ALL;
+
+ENTITY tb_aduh_dd IS
+END tb_aduh_dd;
+
+ARCHITECTURE tb OF tb_aduh_dd IS
+
+  -- ADU board
+  CONSTANT c_adc_w               : NATURAL := 8;
+  CONSTANT c_ana_diff            : NATURAL := 16;    -- analogue offset value between the port A, B, C, D
+  
+  CONSTANT c_lvds_skew_zero      : t_natural_arr(c_adc_w-1 DOWNTO 0) := (OTHERS=>0);                               -- ps unit
+  CONSTANT c_lvds_skew_init      : t_natural_arr(c_adc_w-1 DOWNTO 0) := (350, 300, 250, 200, 150, 100,  50,   0);  -- ps unit
+  CONSTANT c_lvds_skew_clk       : NATURAL := 35;   -- ps unit
+  
+  CONSTANT c_dclk_init_phase_a   : NATURAL := 0;
+  CONSTANT c_dclk_init_phase_b   : NATURAL := 0;
+  
+  -- ADU handler
+  
+  --TYPE t_c_aduh_dd_ai IS RECORD
+  --  nof_sp      : NATURAL;          -- = 4
+  --  nof_adu     : NATURAL;          -- = 2
+  --  nof_ports   : NATURAL;          -- = 2
+  --  port_w      : NATURAL;          -- = 8
+  --  dd_factor   : NATURAL;          -- = 2
+  --  rx_factor   : NATURAL;          -- = 2
+  --  deskew      : t_c_aduh_delays;  -- = (0, 0, (OTHERS=>0), (OTHERS=>0), (OTHERS=>0), (OTHERS=>0))  -- clock: a, b, data: a, b, c, d
+  --END RECORD;
+  --CONSTANT c_ai                  : t_c_aduh_dd_ai := c_aduh_dd_ai;  -- use defaults
+  CONSTANT c_ai                  : t_c_aduh_dd_ai := (4, 2, 2, c_adc_w, 2, 2, TRUE, FALSE, (7, 7, (0, 1, 2, 3, 4, 5, 6, 7),
+                                                                                                  (0, 1, 2, 3, 4, 5, 6, 7),
+                                                                                                  (0, 1, 2, 3, 4, 5, 6, 7),
+                                                                                                  (0, 1, 2, 3, 4, 5, 6, 7)));  -- use defaults, compensate for c_lvds_skew_init
+  
+  CONSTANT c_dp_factor           : NATURAL := c_ai.rx_factor * c_ai.dd_factor;  -- = 4 = 2 * 2
+  
+  CONSTANT c_sample_period       : TIME := 1250 ps;                         -- 800 MTps
+  CONSTANT c_dp_clk_period       : TIME := c_sample_period*c_dp_factor;     -- 200 MHz
+  
+  CONSTANT c_dp_clk_skew         : NATURAL := 235;  -- ps unit, model skew between dp_clk and SCLK, both are in lock with the same reference
+  
+  CONSTANT c_dp_phs_clk_step     : TIME := c_dp_clk_period/32;  -- the PLL can output clocks with phase shifts of 360/32 = 11.25 degrees
+  CONSTANT c_dp_phs_clk_period   : NATURAL := 32;               -- number of dp_clk periods per dp_phs_clk period
+  CONSTANT c_nof_dp_phs_clk      : NATURAL := 1;
+  
+  CONSTANT c_dp_dat_w            : NATURAL := c_dp_factor * c_adc_w;        -- 32 bit
+  
+  CONSTANT c_rl                  : NATURAL := 1;
+  CONSTANT c_verify_delay        : NATURAL := 10;
+  CONSTANT c_verify_period       : TIME := 3 us;
+  
+  TYPE t_dp_data_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_dat_w-1 DOWNTO 0);
+  
+  -- Analogue
+  SIGNAL ANA_DAT             : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- Common ADC reference data source
+  SIGNAL ANA_A               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port A
+  SIGNAL ANA_B               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port B
+  SIGNAL ANA_C               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port C
+  SIGNAL ANA_D               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port D
+  SIGNAL SCLK                : STD_LOGIC := '1';       -- central sample clock = 800 MHz
+  SIGNAL DCLK_AB             : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DCLK_CD             : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DCLK_RST_AB         : STD_LOGIC;              -- synchronise digital lvds clock
+  SIGNAL DCLK_RST_CD         : STD_LOGIC;              -- synchronise digital lvds clock
+  SIGNAL DIG_A               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_B               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_C               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_D               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  
+  SIGNAL test_pattern_en     : STD_LOGIC := '0';
+  SIGNAL lvds_skew_di        : t_natural_arr(c_ai.port_w-1 DOWNTO 0) := c_lvds_skew_zero;  --c_lvds_skew_init;
+  SIGNAL lvds_skew_dq        : t_natural_arr(c_ai.port_w-1 DOWNTO 0) := c_lvds_skew_zero;  --c_lvds_skew_init;
+  SIGNAL lvds_skew_dclk      : NATURAL := c_lvds_skew_clk;
+  
+  -- Digital streaming
+  SIGNAL tb_end              : STD_LOGIC := '0';
+  SIGNAL dp_clk_ref          : STD_LOGIC := '1';   -- digital data path clock = 200 MHz (deser factor 4);
+  SIGNAL dp_clk              : STD_LOGIC;
+  SIGNAL dp_rst              : STD_LOGIC;
+  SIGNAL dp_phs_cnt          : NATURAL := 0;
+  SIGNAL dp_phs_clk          : STD_LOGIC := '1';
+  SIGNAL dp_phs_clk_vec      : STD_LOGIC_VECTOR(c_nof_dp_phs_clk-1 DOWNTO 0);
+  
+  SIGNAL dp_sosi_arr         : t_dp_sosi_arr(0 TO c_ai.nof_sp-1);
+  
+  -- MM Interface
+  SIGNAL ab_locked           : STD_LOGIC;
+  SIGNAL ab_stable           : STD_LOGIC;
+  SIGNAL ab_stable_ack       : STD_LOGIC := '0';
+  
+  SIGNAL cd_locked           : STD_LOGIC;
+  SIGNAL cd_stable           : STD_LOGIC;
+  SIGNAL cd_stable_ack       : STD_LOGIC := '0';
+    
+  -- Verify
+  SIGNAL verify_en           : STD_LOGIC_VECTOR(0 TO c_ai.nof_sp-1) := (OTHERS=>'0');
+  SIGNAL verify_en_all       : STD_LOGIC := '0';
+  SIGNAL verify_valid        : STD_LOGIC_VECTOR(0 TO c_ai.nof_sp-1) := (OTHERS=>'0');
+  SIGNAL verify_done         : STD_LOGIC_VECTOR(0 TO c_ai.nof_sp-1) := (OTHERS=>'0');
+  SIGNAL verify_data         : t_dp_data_arr(   0 TO c_ai.nof_sp-1);
+  SIGNAL prev_verify_data    : t_dp_data_arr(   0 TO c_ai.nof_sp-1);
+  SIGNAL sl0                 : STD_LOGIC := '0';
+  SIGNAL sl1                 : STD_LOGIC := '1';
+  SIGNAL slv0                : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00";
+  
+BEGIN
+
+  tb_end <= '0', '1' AFTER 10 us;
+  
+  -----------------------------------------------------------------------------
+  -- ADU0 and ADU1 for BN port A,B and C,D
+  -----------------------------------------------------------------------------
+  
+  -- Same analogue reference signal for all ADC, use incrementing data to ease the verification
+  ANA_DAT <= INCR_UVEC(ANA_DAT, 1) WHEN rising_edge(SCLK);
+  ANA_A   <= INCR_UVEC(ANA_DAT, 0*c_ana_diff);
+  ANA_B   <= INCR_UVEC(ANA_DAT, 1*c_ana_diff);
+  ANA_C   <= INCR_UVEC(ANA_DAT, 2*c_ana_diff);
+  ANA_D   <= INCR_UVEC(ANA_DAT, 3*c_ana_diff);
+  
+  -- Same sample clock for all ADC
+  SCLK <= NOT SCLK OR tb_end AFTER c_sample_period/2;
+
+  -- ADU model with National ADC and including backplane rewiring on AUB
+  u_adu_AB : ENTITY work.adu_half
+  GENERIC MAP (
+    g_dclk_init_phase => c_dclk_init_phase_a
+  )
+  PORT MAP (
+    AI              => TO_SINT(ANA_A),
+    AQ              => TO_SINT(ANA_B),
+    CLK             => SCLK,
+    DCLK            => DCLK_AB,
+    DCLK_RST        => DCLK_RST_AB,
+    DI              => DIG_A,
+    DQ              => DIG_B,
+    
+    test_pattern_en => test_pattern_en,
+    lvds_skew_di    => lvds_skew_di,
+    lvds_skew_dq    => lvds_skew_dq,
+    lvds_skew_dclk  => lvds_skew_dclk
+  );
+  
+  u_adu_CD : ENTITY work.adu_half
+  GENERIC MAP (
+    g_dclk_init_phase => c_dclk_init_phase_b
+  )
+  PORT MAP (
+    AI              => TO_SINT(ANA_C),
+    AQ              => TO_SINT(ANA_D),
+    CLK             => SCLK,
+    DCLK            => DCLK_CD,
+    DCLK_RST        => DCLK_RST_CD,
+    DI              => DIG_C,
+    DQ              => DIG_D,
+    
+    test_pattern_en => test_pattern_en,
+    lvds_skew_di    => lvds_skew_di,
+    lvds_skew_dq    => lvds_skew_dq,
+    lvds_skew_dclk  => lvds_skew_dclk
+  );
+  
+  -----------------------------------------------------------------------------
+  -- Stimuli
+  -----------------------------------------------------------------------------
+  
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*7;
+  dp_clk_ref <= NOT dp_clk_ref OR tb_end AFTER c_dp_clk_period/2;
+  dp_clk <= TRANSPORT dp_clk_ref AFTER c_dp_clk_skew * 1 ps;
+
+  -- Create DP phase reference clock 
+  p_dp_phs_clk : PROCESS(dp_clk)
+  BEGIN
+    IF c_dp_phs_clk_period=1 THEN
+      dp_phs_clk <= dp_clk;
+    ELSIF rising_edge(dp_clk) THEN
+      IF dp_phs_cnt MOD (c_dp_phs_clk_period/2) = 0 THEN
+        dp_phs_clk <= NOT dp_phs_clk;
+      END IF;
+      IF dp_phs_cnt=c_dp_phs_clk_period-1 THEN
+        dp_phs_cnt<=0;
+      ELSE
+        dp_phs_cnt<=dp_phs_cnt+1;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  gen_dp_phs_clk_vec : FOR I IN c_nof_dp_phs_clk-1 DOWNTO 0 GENERATE
+    dp_phs_clk_vec(I) <= TRANSPORT dp_phs_clk AFTER I*c_dp_phs_clk_step;
+  END GENERATE;
+  
+  u_aduh_dd : ENTITY work.aduh_dd
+  GENERIC MAP (
+    g_ai => c_ai
+  )
+  PORT MAP (
+    -- LVDS Interface
+    -- . g_ai.nof_sp = 4, fixed support 4 signal paths A,B,C,D
+    ADC_BI_A         => DIG_A,
+    ADC_BI_B         => DIG_B,
+    ADC_BI_C         => DIG_C,
+    ADC_BI_D         => DIG_D,
+    
+    ADC_BI_A_CLK     => DCLK_AB,
+    ADC_BI_D_CLK     => DCLK_CD,
+    
+    ADC_BI_A_CLK_RST => DCLK_RST_AB,
+    ADC_BI_D_CLK_RST => DCLK_RST_CD,
+    
+    -- MM Interface
+    ab_locked        => ab_locked,
+    ab_stable        => ab_stable,
+    ab_stable_ack    => ab_stable_ack,
+  
+    cd_locked        => cd_locked,
+    cd_stable        => cd_stable,
+    cd_stable_ack    => cd_stable_ack,
+    
+    -- DP Interface
+    dp_rst           => dp_rst,
+    dp_clk           => dp_clk,
+    dp_phs_clk_vec   => dp_phs_clk_vec,
+    
+    -- . Streaming
+    src_out_arr      => dp_sosi_arr
+  );
+  
+  -----------------------------------------------------------------------------
+  -- Verify dp_sosi_arr
+  -- . verify that that the test has run at all
+  -- . verify that the valid data per ADC port is incrementing
+  -- . verify that the valid data between the ADC ports has the correct diff (alignment)
+  -----------------------------------------------------------------------------
+  
+  -- Verify that that the test has run at all
+  verify_en_all <= vector_and(verify_en);
+  
+  p_verify_run : PROCESS
+  BEGIN
+    -- Wait some time
+    WAIT FOR c_verify_period;
+    IF verify_en_all/='1' THEN
+      REPORT "ADUH using DD: No valid data, test may not be running." SEVERITY ERROR;
+    END IF;
+    WAIT;
+  END PROCESS;
+
+  verify_valid(0) <= dp_sosi_arr(0).valid;
+  verify_valid(1) <= dp_sosi_arr(1).valid;
+  verify_valid(2) <= dp_sosi_arr(2).valid;
+  verify_valid(3) <= dp_sosi_arr(3).valid;
+  
+  gen_verify : FOR I IN 0 TO c_ai.nof_sp-1 GENERATE
+  
+    -- Enable verify after first valid data and keep it enabled
+    proc_dp_verify_en(c_verify_delay, dp_rst, dp_clk, verify_valid(I), verify_en(I));
+  
+    -- Verify that the symbols in the data are incrementing per ADC (ready not used, empty not used)
+    verify_data(I) <= dp_sosi_arr(I).data(c_dp_dat_w-1 DOWNTO 0);
+    proc_dp_verify_symbols(c_rl, c_dp_dat_w, c_adc_w, dp_clk, verify_en(I), sl1, dp_sosi_arr(I).valid, sl0, verify_data(I), slv0, prev_verify_data(I));
+    
+    -- Verify the data alignment between the ADCs by checking the expected c_ana_diff offset
+    p_alignment : PROCESS(dp_clk)
+    BEGIN
+      IF I > 0 THEN
+        IF rising_edge(dp_clk) THEN
+          IF verify_en_all='1' THEN
+            FOR J IN 0 TO c_dp_factor-1 LOOP
+              IF verify_data(I)((J+1)*c_adc_w-1 DOWNTO J*c_adc_w) /= INCR_UVEC(verify_data(I-1)((J+1)*c_adc_w-1 DOWNTO J*c_adc_w), c_ana_diff) THEN
+                REPORT "ADUH using DD: Wrong alignment between ADCs." SEVERITY ERROR;
+              END IF;
+            END LOOP;
+          END IF;
+        END IF;
+      END IF;
+    END PROCESS;
+    
+  END GENERATE;  -- gen_verify
+    
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_aduh_mean_sum.vhd b/libraries/io/aduh/tb/vhdl/tb_aduh_mean_sum.vhd
new file mode 100644
index 0000000000..dc2610cccb
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_aduh_mean_sum.vhd
@@ -0,0 +1,152 @@
+-------------------------------------------------------------------------------
+--
+-- 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_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+
+
+-- Usage:
+-- > as 10
+-- > run 1 us
+-- observe in_sosi, sum and sum_sync in wave window
+-- expected sum after sum_sync are: 0, 120, 376, ...
+
+
+ENTITY tb_aduh_mean_sum IS
+  GENERIC (
+    g_random_control : BOOLEAN := TRUE  -- use TRUE for random stream flow control, use FALSE for initial debugging
+  );
+END tb_aduh_mean_sum;
+
+
+ARCHITECTURE tb OF tb_aduh_mean_sum IS
+
+  CONSTANT clk_period              : TIME := 10 ns;
+  
+  CONSTANT c_rl                    : NATURAL := 1;
+  CONSTANT c_symbol_w              : NATURAL := 8;
+  CONSTANT c_nof_symbols_per_data  : NATURAL := 4;
+  CONSTANT c_nof_symbols_per_block : NATURAL := 8;         -- nof symbols (= ADC samples) per block
+  
+  CONSTANT c_sum_truncate          : BOOLEAN := TRUE;
+  CONSTANT c_sum_w                 : NATURAL := c_word_w;   -- = 32
+  
+  CONSTANT c_data_w                : NATURAL := c_nof_symbols_per_data*c_symbol_w;
+  
+  CONSTANT c_nof_sync              : NATURAL := 10;
+  CONSTANT c_nof_block_per_sync    : NATURAL := 2;
+  CONSTANT c_nof_symbols_per_sync  : NATURAL := c_nof_block_per_sync * c_nof_symbols_per_block;
+  
+  CONSTANT c_nof_accumulations     : NATURAL := c_nof_symbols_per_sync;  -- integration time in symbols
+  
+  SIGNAL rst             : STD_LOGIC;
+  SIGNAL clk             : STD_LOGIC := '1';
+  
+  SIGNAL random_0        : STD_LOGIC_VECTOR(14 DOWNTO 0) := (OTHERS=>'0');  -- use different lengths to have different random sequences
+  
+  SIGNAL st_en           : STD_LOGIC := '1';
+  SIGNAL st_sosi         : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL st_siso         : t_dp_siso := c_dp_siso_rdy;
+  
+  SIGNAL bsn             : NATURAL;
+  
+  SIGNAL in_sosi         : t_dp_sosi := c_dp_sosi_rst;
+  
+  SIGNAL sum             : STD_LOGIC_VECTOR(c_sum_w-1 DOWNTO 0);
+  SIGNAL sum_sync        : STD_LOGIC;
+  SIGNAL sum_sop         : STD_LOGIC;
+  
+BEGIN
+
+  clk <= NOT clk  AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*5;
+  
+  -- ST domain
+  gen_random_control : IF g_random_control=TRUE GENERATE
+    random_0 <= func_common_random(random_0) WHEN rising_edge(clk);
+    --st_en    <= NOT st_en WHEN rising_edge(clk);
+    --st_en    <= random_0(random_0'HIGH);
+  END GENERATE;  -- else the st_en line is always active
+  
+  p_st_stimuli : PROCESS
+    VARIABLE v_symbol  : NATURAL := 0;
+  BEGIN
+    st_sosi <= c_dp_sosi_rst;
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 5);
+
+    -- Run some sync intervals with DSP counter data for the data field
+    st_sosi.sync <= '1';           -- first sync
+    WAIT UNTIL rising_edge(clk);
+    FOR I IN 0 TO c_nof_sync-1 LOOP
+      FOR J IN 0 TO c_nof_block_per_sync-2 LOOP  -- provide sop and eop for block reference
+        proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_symbol_w, v_symbol, 0, 0, c_nof_symbols_per_block, 0, 0, '0', "0", clk, st_en, st_siso, st_sosi);   -- no sync
+        v_symbol := v_symbol + c_nof_symbols_per_block;
+      END LOOP;
+      proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_symbol_w, v_symbol, 0, 0, c_nof_symbols_per_block, 0, 0, '1', "0", clk, st_en, st_siso, st_sosi);     -- next sync
+      v_symbol := v_symbol + c_nof_symbols_per_block;
+    END LOOP;
+    
+    st_sosi <= c_dp_sosi_rst;
+    WAIT;
+  END PROCESS;
+
+  -- Time stimuli  
+  bsn <= bsn + 1 WHEN rising_edge(clk) AND st_sosi.sync='1';
+  
+  -- Add BSN to the ST data
+  p_in_sosi : PROCESS(st_sosi, bsn)
+  BEGIN
+    in_sosi     <= st_sosi;
+    in_sosi.bsn <= TO_DP_BSN(bsn);
+  END PROCESS;
+  
+  u_dut : ENTITY work.aduh_mean_sum
+  GENERIC MAP (
+    g_symbol_w             => c_symbol_w,
+    g_nof_symbols_per_data => c_nof_symbols_per_data,  -- big endian in_data, t0 in MSSymbol, so [h:0] = [t0]&[t1]&[t2]&[t3]
+    g_nof_accumulations    => c_nof_accumulations,     -- integration time in symbols
+    g_sum_truncate         => c_sum_truncate,          -- when TRUE truncate (keep MS part) else resize (keep sign and LS part)
+    g_sum_w                => c_sum_w                  -- typcially MM word width = 32
+  )
+  PORT MAP (
+    clk         => clk,
+    rst         => rst,
+    
+    -- Streaming inputs
+    in_data     => in_sosi.data(c_data_w-1 DOWNTO 0),
+    in_val      => in_sosi.valid,
+    in_sync     => in_sosi.sync,
+    
+    -- Accumulation outputs
+    sum         => sum,
+    sum_sync    => sum_sync,
+    sum_sop     => sum_sop
+  );
+      
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_aduh_pll.vhd b/libraries/io/aduh/tb/vhdl/tb_aduh_pll.vhd
new file mode 100644
index 0000000000..6aacfff065
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_aduh_pll.vhd
@@ -0,0 +1,409 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+USE work.aduh_pll_pkg.ALL;
+
+ENTITY tb_aduh_pll IS
+END tb_aduh_pll;
+
+ARCHITECTURE tb OF tb_aduh_pll IS
+
+  -- Conclusion from the c_model_rx_clk_* investigations:
+  -- . It appears that it is not possible to avoid the DCLK->rx_clk divide by 2
+  --   phase uncertainty by releasing the CDA reset in the dp-clk domain.
+  CONSTANT c_model_rx_clk_phase_uncertainty_in_time  : BOOLEAN := TRUE;   -- When TRUE model DPA lock at different relative SCLK phase in time (0..dp_deser_factor-1) 
+  CONSTANT c_model_rx_clk_phase_uncertainty_in_space : BOOLEAN := FALSE;  -- When TRUE model DPA lock at different relative SCLK phase for each of the rx_clk (0..nof_clocks-1)
+  CONSTANT c_model_rx_clk_hold_reference             : BOOLEAN := TRUE;   -- When TRUE AND nof_clocks>1 then keep rx_clk(0) active so that rx_clk(0) is a reference
+  
+  -- Conclusion from the c_model_lvds_skew investigations:
+  -- . It appears that the DPA model in altera_mf.vhd does not model DPA for
+  --   semi static skew, e.g. skew that varies with temperature. It can only
+  --   model ppm drift which occurs in soft CDR (clock data recovery) mode,
+  --   such as needed e.g. for SGMII. In the Chip Planner the SERDES_RX that
+  --   implements the DPA is connected but presented as a black box.
+  CONSTANT c_model_lvds_skew     : BOOLEAN := FALSE;  -- When TRUE model DPA lock at different relative SCLK phase in time (0..dp_deser_factor-1) 
+  
+  -- Conclusion from the c_model_dclk_phase investigations:
+  -- . Use
+  --     c_model_rx_clk_phase_uncertainty_in_time  = TRUE;
+  --     c_model_rx_clk_phase_uncertainty_in_space = FALSE;
+  --     c_model_rx_clk_hold_reference             = TRUE;
+  -- . To model the use_lvds_clk_rst it is necessary to deliberately start the
+  --   the DCLK_CD with a different phase then the DCLK_AB and then check that
+  --   a DCLK_RST_CD causes it to align again. This modelling is a bit fussy,
+  --   because using lvds_clk_rst in lvdsh.vhd also makes that the dp_pll_reset
+  --   gets synchronized to the dp_clk domain and that causes the 
+  --   c_model_rx_clk_phase_uncertainty_in_time effect to become void anyway.
+  --   Anyway it is safe to state that using the ADC DCLK_RST is a proper
+  --   means to align the lvds_clk from all ADU in a system to the dp_clk.
+  CONSTANT c_model_dclk_phase    : BOOLEAN := FALSE;  -- When TRUE start DCLK_CD with different phase then DCLK_AB, else use same phase for both
+  
+  -- TYPE t_c_aduh_pll_ai IS RECORD
+  --   nof_sp            : NATURAL;  -- = 4;     -- Fixed support 4 signal paths A,B,C,D, whether they contain active data depends on nof_adu
+  --   nof_adu           : NATURAL;  -- = 2;     -- When 2 ADUs then use all 4 ports A,B,C,D, one ADU on ports A,B and one ADU on ports C,D,
+  --                                             -- when 1 ADU then only use ports C,D
+  --   nof_ports         : NATURAL;  -- = 2;     -- Fixed 2 ADC BI ports per ADU
+  --   port_w            : NATURAL;  -- = 8;     -- Fixed 8 bit ADC BI port width, the ADC sample width is also 8 bit
+  --   nof_ovr           : NATURAL;  -- = 1;     -- There is 1 overflow bit per ADU, use 0 to ignore the overflow input
+  --   lvds_data_rate    : NATURAL;  -- = 800;   -- The ADC sample rate is 800 Msps, so the LVDS rate is 800 Mbps per ADC BI data line, 
+  --   use_dpa           : BOOLEAN;  -- = TRUE;  -- When TRUE use LVDS_RX with DPA, else used fixed IOE delays and/or lvds_clk_phase instead of DPA
+  --   use_lvds_clk      : BOOLEAN;  -- = TRUE;  -- When TRUE use the one or both ADC BI lvds_clk, else use the single dp_clk to capture the lvds data
+  --   use_lvds_clk_rst  : BOOLEAN;  -- = FALSE; -- When TRUE then support reset pulse to ADU to align the lvds_clk to the dp_clk, else no support
+  --   lvds_clk_phase    : NATURAL;  -- = 0;     -- Use PLL phase 0 for edge aligned, phase 180 for center aligned. Only for no DPA
+  --   nof_clocks        : NATURAL;  -- = 2;     -- Must be <= nof_adu
+  --                                             -- 1 --> Use ADC BI clock D or dp_clk for one or both ADU
+  --                                             -- 2 --> Use ADC BI clock A for/from ADU-AB and clock D for/from the ADU-CD
+  --   lvds_deser_factor : NATURAL;  -- = 2;     -- The ADC sampled data comes in with a DDR lvds_clk, so lvds_data_rate / 2 or
+  --                                             -- the 4 when the Data Path clock dp_clk is also used as LVDS data reference lvds_clk clock
+  --   dp_deser_factor   : NATURAL;  -- = 4;     -- The Data Path clock dp_clk frequency is 200 MHz, so lvds_data_rate / 4
+  -- END RECORD;
+  -- Uncomment one of the c_ai settings:
+--   CONSTANT c_ai   : t_c_aduh_pll_ai := (4, 2, 2, 8, 0, 800, FALSE, FALSE, FALSE,  0, 1, 4, 4);  -- model no dpa,  use   dp_clk, lvds_clk_phase =  0
+--   CONSTANT c_ai   : t_c_aduh_pll_ai := (4, 2, 2, 8, 0, 800, FALSE,  TRUE, FALSE,  0, 2, 2, 4);  -- model no dpa,  use lvds_clk, lvds_clk_phase =  0
+--   CONSTANT c_ai   : t_c_aduh_pll_ai := (4, 2, 2, 8, 0, 800, FALSE,  TRUE, FALSE, 90, 2, 2, 4);  -- model no dpa,  use lvds_clk, lvds_clk_phase = 90
+--   CONSTANT c_ai   : t_c_aduh_pll_ai := (4, 2, 2, 8, 0, 800,  TRUE, FALSE, FALSE,  0, 1, 4, 4);  -- model use dpa, use   dp_clk
+  CONSTANT c_ai   : t_c_aduh_pll_ai := (4, 2, 2, 8, 0, 800,  TRUE,  TRUE, FALSE,  0, 2, 2, 4);  -- model use dpa, use lvds_clk
+--   CONSTANT c_ai   : t_c_aduh_pll_ai := (4, 2, 2, 8, 0, 800,  TRUE,  TRUE,  TRUE,  0, 2, 2, 4);  -- model use dpa, use lvds_clk, use lvds_clk_rst
+
+  -- Conclusion on c_ai:
+  -- . Using DPA is preferred.
+  -- . First using dp_clk as LVDS_RX PLL reference is the preferred scheme.
+  -- . If DCLK_RST is supported by BN - ADU then using lvds_clk as LVDS_RX PLL reference with lvds_clk_rst to ADU is preferred.
+  -- . Not using DPA and using the lvds_clk should also be tried and verified on the BN - ADU hardware.
+  
+  CONSTANT c_sample_freq         : NATURAL := c_ai.lvds_data_rate;    -- Msps
+  CONSTANT c_sample_period       : TIME := 1000000 ps / c_sample_freq;
+  
+  CONSTANT c_pll_reset_time      : TIME := 20 ns;    -- minimum 10 ns
+  CONSTANT c_measurement_period  : TIME := 50 us;    -- minimum depends on number of data line toggles for DPA, which can take 10-s of us for MSbit counter data,
+                                                     -- because DPA lock is only achieved after about 256 toggles
+  
+  CONSTANT c_lvds_skew_zero      : t_natural_arr(7 DOWNTO 0) := ( 0,  0,  0,  0,  0,  0,  0,  0);  -- ps unit
+  CONSTANT c_lvds_skew_init      : t_natural_arr(7 DOWNTO 0) := (70, 60, 50, 40, 30, 20, 10,  0);  -- ps unit
+  CONSTANT c_lvds_skew_ovr       : NATURAL := 55;  -- ps unit
+  CONSTANT c_lvds_skew_clk       : NATURAL := 35;  -- ps unit
+  
+  CONSTANT c_dp_clk_period       : TIME := c_ai.dp_deser_factor * c_sample_period;
+  CONSTANT c_dp_clk_skew         : NATURAL := 335;   -- ps unit, model skew between dp_clk and SCLK, both are in lock with the same reference
+  
+  CONSTANT c_ana_diff            : NATURAL := 16;    -- analogue offset value between the port A, B, C, D
+  
+  CONSTANT c_adc_w               : NATURAL := c_ai.port_w;                     -- 8 bit
+  CONSTANT c_dp_dat_w            : NATURAL := c_adc_w * c_ai.dp_deser_factor;  -- 32 bit
+  
+  TYPE t_dp_data_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_dp_dat_w-1 DOWNTO 0);
+  
+  -- ADC : c_ai.port_w = 8-bit
+  SIGNAL ANA_DAT             : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- Common ADC reference data source
+  SIGNAL ANA_A               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port A
+  SIGNAL ANA_B               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port B
+  SIGNAL ANA_C               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port C
+  SIGNAL ANA_D               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0) := (OTHERS=>'0');  -- ADC port D
+  SIGNAL ANA_OVR             : STD_LOGIC := '0';
+  SIGNAL SCLK                : STD_LOGIC := '1';       -- central sample clock = 800 MHz
+  SIGNAL DCLK_AB             : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DCLK_CD             : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DCLK_RST_AB         : STD_LOGIC;              -- synchronise digital lvds clock
+  SIGNAL DCLK_RST_CD         : STD_LOGIC;              -- synchronise digital lvds clock
+  SIGNAL DIG_A               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_B               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_C               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_D               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_OVR_AB          : STD_LOGIC := '0';
+  SIGNAL DIG_OVR_CD          : STD_LOGIC := '0';
+  
+  SIGNAL test_pattern_en     : STD_LOGIC := '0';
+  SIGNAL lvds_skew_di        : t_natural_arr(7 DOWNTO 0) := c_lvds_skew_init;
+  SIGNAL lvds_skew_dq        : t_natural_arr(7 DOWNTO 0) := c_lvds_skew_init;
+  SIGNAL lvds_skew_ovr       : NATURAL := c_lvds_skew_ovr;
+  SIGNAL lvds_skew_dclk      : NATURAL := c_lvds_skew_clk;
+  
+  -- Digital
+  SIGNAL dp_clk_ref          : STD_LOGIC := '1';   -- digital data path clock = 200 MHz (deser factor 4);
+  SIGNAL dp_clk              : STD_LOGIC := '1';   -- digital data path clock = 200 MHz (deser factor 4);
+  
+  -- DUT
+  SIGNAL dp_restart          : STD_LOGIC_VECTOR(c_ai.nof_clocks-1 DOWNTO 0);
+  SIGNAL dp_delay_settings   : t_natural_arr(func_aduh_pll_lvds_dat_w(c_ai)-1 DOWNTO 0) := (OTHERS=>0);  -- ADC_BI IOE data delay settings when g_use_dpa = FALSE
+  SIGNAL dp_cda_settings     : t_natural_arr(func_aduh_pll_lvds_dat_w(c_ai)-1 DOWNTO 0) := (OTHERS=>1);  -- ADC_BI channel data alignment settings
+  SIGNAL dp_sosi             : t_dp_sosi_arr(0 TO c_ai.nof_sp-1);                                    -- ADC_BI ports [0:3] = [A,B,C,D]
+  
+  -- Verify
+  SIGNAL restart_any         : STD_LOGIC := '0';
+  SIGNAL verify_valid        : STD_LOGIC_VECTOR(0 TO c_ai.nof_sp-1) := (OTHERS=>'0');
+  SIGNAL verify_restart      : STD_LOGIC_VECTOR(0 TO c_ai.nof_sp-1) := (OTHERS=>'0');
+  SIGNAL verify_en           : STD_LOGIC_VECTOR(0 TO c_ai.nof_sp-1) := (OTHERS=>'0');
+  SIGNAL verify_en_all       : STD_LOGIC := '0';
+  SIGNAL verify_data         : t_dp_data_arr(   0 TO c_ai.nof_sp-1);
+  SIGNAL prev_verify_data    : t_dp_data_arr(   0 TO c_ai.nof_sp-1);
+  SIGNAL sl0                 : STD_LOGIC := '0';
+  SIGNAL sl1                 : STD_LOGIC := '1';
+  SIGNAL slv0                : STD_LOGIC_VECTOR(0 DOWNTO 0) := "0";
+  
+BEGIN
+
+  -----------------------------------------------------------------------------
+  -- ADU0 and ADU1 for BN port A,B and C,D
+  -----------------------------------------------------------------------------
+  
+  -- Same analogue reference signal for all ADC, use incrementing data to ease the verification
+--   ANA_DAT <= NOT ANA_DAT WHEN rising_edge(SCLK);
+--   ANA_A   <= ANA_DAT;
+--   ANA_B   <= ANA_DAT;
+--   ANA_C   <= ANA_DAT;
+--   ANA_D   <= ANA_DAT;
+  ANA_DAT <= INCR_UVEC(ANA_DAT, 1) WHEN rising_edge(SCLK);
+  ANA_A   <= INCR_UVEC(ANA_DAT, 0*c_ana_diff);
+  ANA_B   <= INCR_UVEC(ANA_DAT, 1*c_ana_diff);
+  ANA_C   <= INCR_UVEC(ANA_DAT, 2*c_ana_diff);
+  ANA_D   <= INCR_UVEC(ANA_DAT, 3*c_ana_diff);
+  ANA_OVR <= NOT ANA_OVR WHEN rising_edge(SCLK);  -- simple overflow model used for both ADC
+  
+  -- Same sample clock for all ADC
+  SCLK <= NOT SCLK AFTER c_sample_period/2;
+
+  -- National ADC
+  u_adu_AB : ENTITY work.adc08d1020
+  GENERIC MAP (
+    g_dclk_init_phase => 0
+  )
+  PORT MAP (
+    AI              => TO_SINT(ANA_A),
+    AQ              => TO_SINT(ANA_B),
+    AOVR            => ANA_OVR,
+    CLK             => SCLK,
+    DCLK            => DCLK_AB,
+    DCLK_RST        => '0',
+    DI              => DIG_A,
+    DQ              => DIG_B,
+    OVR             => DIG_OVR_AB,
+    
+    test_pattern_en => test_pattern_en,
+    lvds_skew_di    => lvds_skew_di,
+    lvds_skew_dq    => lvds_skew_dq,
+    lvds_skew_ovr   => lvds_skew_ovr,
+    lvds_skew_dclk  => lvds_skew_dclk
+  );
+  
+  u_adu_CD : ENTITY work.adc08d1020
+  GENERIC MAP (
+    g_dclk_init_phase => sel_a_b(c_model_dclk_phase, 1, 0)
+  )
+  PORT MAP (
+    AI              => TO_SINT(ANA_C),
+    AQ              => TO_SINT(ANA_D),
+    AOVR            => ANA_OVR,
+    CLK             => SCLK,
+    DCLK            => DCLK_CD,
+    DCLK_RST        => DCLK_RST_CD,
+    DI              => DIG_C,
+    DQ              => DIG_D,
+    OVR             => DIG_OVR_CD,
+    
+    test_pattern_en => test_pattern_en,
+    lvds_skew_di    => lvds_skew_di,
+    lvds_skew_dq    => lvds_skew_dq,
+    lvds_skew_ovr   => lvds_skew_ovr,
+    lvds_skew_dclk  => lvds_skew_dclk
+  );
+  
+  -----------------------------------------------------------------------------
+  -- Stimuli
+  -----------------------------------------------------------------------------
+  
+  dp_clk_ref <= NOT dp_clk_ref AFTER c_dp_clk_period/2;
+  dp_clk <= TRANSPORT dp_clk_ref AFTER c_dp_clk_skew * 1 ps;
+
+  -- Uncomment to try different CDA settings then the init default:
+--   dp_cda_settings <= (0, 1, 2, 3, 0, 1, 2, 3,   1, 1, 1, 1, 2, 2, 2, 2,   2, 2, 2, 2, 3, 3, 3, 3,   0, 3, 1, 3, 4, 2, 2, 0);
+--   dp_cda_settings <= (0, 0, 0, 0, 0, 0, 0, 0,   1, 1, 1, 1, 1, 1, 1, 1,   2, 2, 2, 2, 2, 2, 2, 2,   3, 3, 3, 3, 3, 3, 3, 3);
+--   dp_cda_settings <= (0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0);
+  
+  p_dp_restart : PROCESS
+  BEGIN
+    lvds_skew_di <= c_lvds_skew_zero;
+    lvds_skew_dq <= c_lvds_skew_zero;
+    
+    -- Wait for the ADU
+    dp_restart <= (OTHERS=>'1');       -- assert the LVDS RX PLL reset
+    WAIT UNTIL rising_edge(DCLK_AB);
+    WAIT UNTIL rising_edge(DCLK_CD);   -- wait to ensure that the DCLKs are active
+    WAIT FOR 1*c_sample_period;        -- set arbitrary initial phase
+    
+    -- Run several measurement with ADU
+    FOR I IN 0 TO 10 LOOP
+      WAIT FOR c_pll_reset_time;       -- ensure mimimum LVDS RX PLL reset time
+      
+      IF c_model_rx_clk_phase_uncertainty_in_time = TRUE THEN
+        -- The next measurement will start 1 SCLK c_sample_period later to
+        -- verify that the fixed CDA settings are suitable.
+        -- It appears in simulation that for the odd I it takes much longer for
+        -- the DPA to lock than for the even I.
+        WAIT FOR I*c_sample_period;
+      END IF;
+      
+      IF c_model_rx_clk_phase_uncertainty_in_space = TRUE THEN
+        -- Wait some extra 1 SCLK c_sample_period for each PLL. The assumption
+        -- is that using I*c_sample_period to get a different SCLK phase for
+        -- the dp_restart may cause CDA misalignment between the ADUs when
+        -- g_use_dp_clk_for_cda_reset=FALSE in the lvdsh. In simulation the PLL
+        -- lock time is deterministic, so influencing the SCLK phase of
+        -- dp_start is a way to model the uncertainty of the real PLL lock time
+        -- and of the relative phase of the divided rx_clk (= dclk / 2).
+        -- It appears in simulation that in both cases the data output from
+        -- ADU0 and ADU1 gets offset by 1 sample. Using the dp_clk to release
+        -- the cda_reset does not help. Probably because internally it gets
+        -- retimed to the rx_clk domain anyway and the phase relation between
+        -- the rx_clk derived from ADU0 and ADU1 may differ.
+        FOR J IN c_ai.nof_clocks-1 DOWNTO 0 LOOP
+          dp_restart(J) <= '0';          -- release the LVDS RX PLL(J) reset
+          WAIT FOR c_sample_period;
+        END LOOP;
+      END IF;
+
+      dp_restart <= (OTHERS=>'0');     -- release the LVDS RX PLL reset
+      
+      -- Begin of the measurement
+      
+      IF c_model_lvds_skew=TRUE THEN
+        WAIT FOR c_measurement_period;
+        lvds_skew_di <= (700, 500, 250, 140, 130, 320, 60, 50);  -- ps unit
+        lvds_skew_dq <= (700, 500, 250, 140, 130, 320, 60, 50);  -- ps unit
+        WAIT FOR 10*c_measurement_period;
+        lvds_skew_di <= c_lvds_skew_zero;
+        lvds_skew_dq <= c_lvds_skew_zero;
+      END IF;
+      
+      WAIT FOR c_measurement_period;
+      dp_restart    <= (OTHERS=>'1');     -- assert the LVDS RX PLL reset
+      
+      IF c_model_rx_clk_hold_reference = TRUE THEN
+        -- Do not assert LVDS RX PLL reset for rx_clk 0, so keep this one
+        -- running for reference to verify the dp_sosi sample data alignment
+        -- with the other clock(s) when c_ai.nof_clocks > 1.
+        IF c_ai.nof_clocks > 1 THEN
+          dp_restart(0) <= '0';
+        END IF;
+      END IF;
+      
+      -- End of the measurement        
+    END LOOP;
+    WAIT;
+  END PROCESS;
+  
+  
+  -----------------------------------------------------------------------------
+  -- DUT: ADUH with PLL
+  -----------------------------------------------------------------------------
+  
+  -- Assume the ADU board has no skew between the ADCs. This is not too much
+  -- simplifcation. Any skew between the ADC will be constant and can then be
+  -- compensated for in a fixed, preset way.
+  dut : ENTITY work.aduh_pll
+  GENERIC MAP (
+    g_ai => c_ai
+  )
+  PORT MAP (
+    -- PHY ADU Interface
+    
+    -- . ADU_AB
+    ADC_BI_AB_OVR    => '0',
+    ADC_BI_A         => DIG_A,
+    ADC_BI_B         => DIG_B,
+    ADC_BI_A_CLK     => DCLK_AB,
+    ADC_BI_A_CLK_RST => DCLK_RST_AB,
+    
+    -- . ADU_CD
+    ADC_BI_CD_OVR    => '0',
+    ADC_BI_C         => DIG_C,
+    ADC_BI_D         => DIG_D,
+    ADC_BI_D_CLK     => DCLK_CD,
+    ADC_BI_D_CLK_RST => DCLK_RST_CD,
+    
+    -- DP Interface
+    dp_clk           => dp_clk,
+    
+    -- . Control
+    restart          => dp_restart,
+    delay_settings   => dp_delay_settings,
+    cda_settings     => dp_cda_settings,
+    
+    -- . Streaming
+    src_out          => dp_sosi  -- = [0:3] = ADC_BI ports [A,B,C,D]
+  );
+  
+  
+  -----------------------------------------------------------------------------
+  -- Verify dp_sosi
+  -- . verify that there is valid data, i.e. that the test has run at all
+  -- . verify that the valid data per ADC port is incrementing
+  -- . verify that the valid data between the ADC ports has the correct diff (alignment)
+  -----------------------------------------------------------------------------
+  
+  restart_any   <= vector_or(dp_restart);
+  verify_en_all <= vector_and(verify_en);
+  
+  p_verify_valid : PROCESS
+  BEGIN
+    WHILE TRUE LOOP
+      WAIT UNTIL falling_edge(restart_any);
+      WAIT FOR c_measurement_period;
+      IF verify_en_all='0' THEN
+        REPORT "ADUH with PLL: No valid data, test may not be running." SEVERITY ERROR;
+      END IF;
+    END LOOP;
+  END PROCESS;
+  
+  -- Verify dp_sosi[0,1,2,3].data symbols compared to ADC samples from [ANA_A, ANA_B, ANA_C, ANA_D]
+  gen_verify_increment : FOR I IN 0 TO c_ai.nof_sp-1 GENERATE
+    -- Enable verify after the valid goes active and continue until valid goes low
+    verify_valid(I) <= dp_sosi(I).valid WHEN rising_edge(dp_clk);
+    verify_restart(I) <= dp_restart((I * c_ai.nof_clocks) / c_ai.nof_sp);
+    verify_en(I) <= verify_valid(I) AND NOT verify_restart(I);  -- also and with dp_restart, because of latency in dp_sosi.valid
+    
+    -- Verify that the symbols in the data are incrementing per ADC (ready not used, empty not used)
+    verify_data(I) <= dp_sosi(I).data(c_dp_dat_w-1 DOWNTO 0);
+    proc_dp_verify_symbols(1, c_dp_dat_w, c_adc_w, dp_clk, verify_en(I), sl1, dp_sosi(I).valid, sl0, verify_data(I), slv0, prev_verify_data(I));
+  END GENERATE;  -- gen_verify_increment
+  
+  -- Verify the data alignment between the ADCs by checking the expected c_ana_diff offset
+  gen_verify_alignment : FOR I IN 1 TO c_ai.nof_sp-1 GENERATE
+    p_alignment : PROCESS(dp_clk)
+    BEGIN
+      IF rising_edge(dp_clk) THEN
+        IF verify_en_all='1' THEN
+          FOR J IN 0 TO c_ai.dp_deser_factor-1 LOOP
+            IF verify_data(I)((J+1)*c_adc_w-1 DOWNTO J*c_adc_w) /= INCR_UVEC(verify_data(I-1)((J+1)*c_adc_w-1 DOWNTO J*c_adc_w), c_ana_diff) THEN
+              REPORT "ADUH with PLL: Wrong alignment between ADCs." SEVERITY ERROR;
+            END IF;
+          END LOOP;
+        END IF;
+      END IF;
+    END PROCESS;
+  END GENERATE;  -- gen_verify_alignment
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_aduh_power_sum.vhd b/libraries/io/aduh/tb/vhdl/tb_aduh_power_sum.vhd
new file mode 100644
index 0000000000..2054c37779
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_aduh_power_sum.vhd
@@ -0,0 +1,151 @@
+-------------------------------------------------------------------------------
+--
+-- 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_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+
+
+-- Usage:
+-- > as 10
+-- > run 1 us
+-- observe in_sosi, pwr_sum and pwr_sum_sync in wave window
+-- expected pwr_sum after pwr_sync are: 0, 1240, 9176, ...
+
+ENTITY tb_aduh_power_sum IS
+  GENERIC (
+    g_random_control : BOOLEAN := TRUE  -- use TRUE for random stream flow control, use FALSE for initial debugging
+  );
+END tb_aduh_power_sum;
+
+
+ARCHITECTURE tb OF tb_aduh_power_sum IS
+
+  CONSTANT clk_period              : TIME := 10 ns;
+  
+  CONSTANT c_rl                    : NATURAL := 1;
+  CONSTANT c_symbol_w              : NATURAL := 8;
+  CONSTANT c_nof_symbols_per_data  : NATURAL := 4;
+  CONSTANT c_nof_symbols_per_block : NATURAL := 8;         -- nof symbols (= ADC samples) per block
+  
+  CONSTANT c_pwr_sum_truncate      : BOOLEAN := TRUE;
+  CONSTANT c_pwr_sum_w             : NATURAL := c_word_w;   -- = 32
+  
+  CONSTANT c_data_w                : NATURAL := c_nof_symbols_per_data*c_symbol_w;
+  
+  CONSTANT c_nof_sync              : NATURAL := 10;
+  CONSTANT c_nof_block_per_sync    : NATURAL := 2;
+  CONSTANT c_nof_symbols_per_sync  : NATURAL := c_nof_block_per_sync * c_nof_symbols_per_block;
+  
+  CONSTANT c_nof_accumulations     : NATURAL := c_nof_symbols_per_sync;  -- integration time in symbols
+  
+  SIGNAL rst             : STD_LOGIC;
+  SIGNAL clk             : STD_LOGIC := '1';
+  
+  SIGNAL random_0        : STD_LOGIC_VECTOR(14 DOWNTO 0) := (OTHERS=>'0');  -- use different lengths to have different random sequences
+  
+  SIGNAL st_en           : STD_LOGIC := '1';
+  SIGNAL st_sosi         : t_dp_sosi := c_dp_sosi_rst;
+  SIGNAL st_siso         : t_dp_siso := c_dp_siso_rdy;
+  
+  SIGNAL bsn             : NATURAL;
+  
+  SIGNAL in_sosi         : t_dp_sosi := c_dp_sosi_rst;
+  
+  SIGNAL pwr_sum         : STD_LOGIC_VECTOR(c_pwr_sum_w-1 DOWNTO 0);
+  SIGNAL pwr_sum_sync    : STD_LOGIC;
+  SIGNAL pwr_sum_sop     : STD_LOGIC;
+  
+BEGIN
+
+  clk <= NOT clk  AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*5;
+  
+  -- ST domain
+  gen_random_control : IF g_random_control=TRUE GENERATE
+    random_0 <= func_common_random(random_0) WHEN rising_edge(clk);
+    --st_en    <= NOT st_en WHEN rising_edge(clk);
+    --st_en    <= random_0(random_0'HIGH);
+  END GENERATE;  -- else the st_en line is always active
+  
+  p_st_stimuli : PROCESS
+    VARIABLE v_symbol  : NATURAL := 0;
+  BEGIN
+    st_sosi <= c_dp_sosi_rst;
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 5);
+
+    -- Run some sync intervals with DSP counter data for the data field
+    st_sosi.sync <= '1';           -- first sync
+    WAIT UNTIL rising_edge(clk);
+    FOR I IN 0 TO c_nof_sync-1 LOOP
+      FOR J IN 0 TO c_nof_block_per_sync-2 LOOP  -- provide sop and eop for block reference
+        proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_symbol_w, v_symbol, 0, 0, c_nof_symbols_per_block, 0, 0, '0', "0", clk, st_en, st_siso, st_sosi);   -- no sync
+        v_symbol := v_symbol + c_nof_symbols_per_block;
+      END LOOP;
+      proc_dp_gen_block_data(c_rl, TRUE, c_data_w, c_symbol_w, v_symbol, 0, 0, c_nof_symbols_per_block, 0, 0, '1', "0", clk, st_en, st_siso, st_sosi);     -- next sync
+      v_symbol := v_symbol + c_nof_symbols_per_block;
+    END LOOP;
+    
+    st_sosi <= c_dp_sosi_rst;
+    WAIT;
+  END PROCESS;
+
+  -- Time stimuli  
+  bsn <= bsn + 1 WHEN rising_edge(clk) AND st_sosi.sync='1';
+  
+  -- Add BSN to the ST data
+  p_in_sosi : PROCESS(st_sosi, bsn)
+  BEGIN
+    in_sosi     <= st_sosi;
+    in_sosi.bsn <= TO_DP_BSN(bsn);
+  END PROCESS;
+  
+  u_dut : ENTITY work.aduh_power_sum
+  GENERIC MAP (
+    g_symbol_w             => c_symbol_w,
+    g_nof_symbols_per_data => c_nof_symbols_per_data,  -- big endian in_data, t0 in MSSymbol, so [h:0] = [t0]&[t1]&[t2]&[t3]
+    g_nof_accumulations    => c_nof_accumulations,     -- integration time in symbols
+    g_pwr_sum_truncate     => c_pwr_sum_truncate,      -- when TRUE truncate (keep MS part) else resize (keep sign and LS part)
+    g_pwr_sum_w            => c_pwr_sum_w              -- typcially MM word width = 32
+  )
+  PORT MAP (
+    clk          => clk,
+    rst          => rst,
+    
+    -- Streaming inputs
+    in_data      => in_sosi.data(c_data_w-1 DOWNTO 0),
+    in_val       => in_sosi.valid,
+    in_sync      => in_sosi.sync,
+    
+    -- Accumulation outputs
+    pwr_sum      => pwr_sum,
+    pwr_sum_sync => pwr_sum_sync,
+    pwr_sum_sop  => pwr_sum_sop
+  );
+      
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_aduh_verify.vhd b/libraries/io/aduh/tb/vhdl/tb_aduh_verify.vhd
new file mode 100644
index 0000000000..2145a3f122
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_aduh_verify.vhd
@@ -0,0 +1,260 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Usage:
+-- > as 10
+-- > run -all
+-- > p_verify_res should report no errors
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE work.aduh_dd_pkg.ALL;
+
+ENTITY tb_aduh_verify IS
+END tb_aduh_verify;
+
+ARCHITECTURE tb OF tb_aduh_verify IS
+
+  --TYPE t_c_aduh_dd_ai IS RECORD
+  --  nof_sp      : NATURAL;          -- = 4
+  --  nof_adu     : NATURAL;          -- = 2
+  --  nof_ports   : NATURAL;          -- = 2
+  --  port_w      : NATURAL;          -- = 8
+  --  dd_factor   : NATURAL;          -- = 2
+  --  rx_factor   : NATURAL;          -- = 2
+  --  deskew      : t_c_aduh_delays;  -- = (0, 0, (OTHERS=>0), (OTHERS=>0), (OTHERS=>0), (OTHERS=>0))  -- clock: a, b, data: a, b, c, d
+  --END RECORD;
+  CONSTANT c_ai                  : t_c_aduh_dd_ai := c_aduh_dd_ai;  -- use defaults
+  
+  CONSTANT c_dp_factor           : NATURAL := c_ai.rx_factor * c_ai.dd_factor;  -- = 4 = 2 * 2
+  
+  CONSTANT c_sample_period       : TIME := 1250 ps;                         -- 800 MTps
+  CONSTANT c_dp_clk_period       : TIME := c_sample_period*c_dp_factor;     -- 200 MHz
+  
+  CONSTANT c_dp_phs_clk_step     : TIME := c_dp_clk_period/32;  -- the PLL can output clocks with phase shifts of 360/32 = 11.25 degrees
+  CONSTANT c_dp_phs_clk_period   : NATURAL := 32;               -- number of dp_clk periods per dp_phs_clk period
+  CONSTANT c_nof_dp_phs_clk      : NATURAL := 1;
+  
+  SIGNAL tb_end              : STD_LOGIC := '0';
+  
+  -- Analogue
+  SIGNAL SCLK                : STD_LOGIC := '1';       -- central sample clock = 800 MHz
+  SIGNAL DCLK                : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DIG_A               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_B               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  
+  -- Digital streaming
+  SIGNAL dp_clk              : STD_LOGIC := '1';   -- digital data path clock = 200 MHz (deser factor 4);
+  SIGNAL dp_rst              : STD_LOGIC;
+  SIGNAL dp_phs_cnt          : NATURAL := 0;
+  SIGNAL dp_phs_clk          : STD_LOGIC := '1';
+  SIGNAL dp_phs_clk_vec      : STD_LOGIC_VECTOR(c_nof_dp_phs_clk-1 DOWNTO 0);
+  
+  SIGNAL aduh_sosi_arr       : t_dp_sosi_arr(0 TO c_ai.nof_sp-1);
+  SIGNAL dp_val              : STD_LOGIC;
+  SIGNAL dp_sosi_arr         : t_dp_sosi_arr(0 TO c_ai.nof_sp-1);
+  
+  -- MM Interface
+  SIGNAL ab_locked           : STD_LOGIC;
+  SIGNAL ab_stable           : STD_LOGIC;
+  SIGNAL ab_stable_ack       : STD_LOGIC := '0';
+    
+  SIGNAL test_pattern_en     : STD_LOGIC;
+  SIGNAL verify_ok           : STD_LOGIC;  -- verify that verify_res indicates OK when expected
+  SIGNAL verify_wrong        : STD_LOGIC;  -- verify that verify_res indicates ERROR when expected
+  
+  SIGNAL a_pattern_sel       : NATURAL RANGE 0 TO 1 := 0;    -- 0 = DI, 1 = DQ
+  SIGNAL a_verify_res        : STD_LOGIC_VECTOR(c_ai.port_w DOWNTO 0);
+  SIGNAL a_verify_res_val    : STD_LOGIC;
+  SIGNAL a_verify_res_ack    : STD_LOGIC;
+  
+  SIGNAL b_pattern_sel       : NATURAL RANGE 0 TO 1 := 1;    -- 0 = DI, 1 = DQ
+  SIGNAL b_verify_res        : STD_LOGIC_VECTOR(c_ai.port_w DOWNTO 0);
+  SIGNAL b_verify_res_val    : STD_LOGIC;
+  SIGNAL b_verify_res_ack    : STD_LOGIC;
+  
+BEGIN
+
+  -----------------------------------------------------------------------------
+  -- ADUH_VERIFY port A and B
+  -----------------------------------------------------------------------------
+
+  -- Stimuli:
+  -- . tb_end test bench duration control
+  -- . test_pattern_en
+  -- . BIST restarts due to verify_res_ack
+  -- . dp_val to check that verify reports error when input valid goes low
+  test_pattern_en  <= '1', '0' AFTER 5 us,   '1' AFTER 6 us;
+  dp_val           <= '1',                                     '0' AFTER 15 us,   '1' AFTER 16 us;
+  verify_wrong     <= '0', '1' AFTER 5.5 us, '0' AFTER 6.5 us, '1' AFTER 15.5 us, '0' AFTER 16.5 us;
+  verify_ok        <= '0', '1' AFTER 1 us,   '0' AFTER 4 us, '1' AFTER 8 us                  , '0' AFTER  9 us, '1' AFTER 11 us                  , '0' AFTER 14 us, '1' AFTER 18 us;
+  a_verify_res_ack <= '0',                   '1' AFTER 7 us, '0' AFTER 7 us + c_dp_clk_period, '1' AFTER 10 us, '0' AFTER 10 us + c_dp_clk_period, '1' AFTER 17 us, '0' AFTER 17 us + c_dp_clk_period;
+  b_verify_res_ack <= '0',                   '1' AFTER 7 us, '0' AFTER 7 us + c_dp_clk_period, '1' AFTER 10 us, '0' AFTER 10 us + c_dp_clk_period, '1' AFTER 17 us, '0' AFTER 17 us + c_dp_clk_period;
+  tb_end           <= '0', '1' AFTER 20 us;
+  
+  dp_sosi_arr      <= aduh_sosi_arr WHEN dp_val='1' ELSE (OTHERS=>c_dp_sosi_rst);
+  
+  u_verify_a : ENTITY work.aduh_verify
+  GENERIC MAP (
+    g_symbol_w             => c_ai.port_w,  -- = 8, fixed
+    g_nof_symbols_per_data => c_dp_factor   -- = 4, fixed, big endian in_sosi.data, t0 in MSSymbol, so [h:0] = [t0]&[t1]&[t2]&[t3]
+  )
+  PORT MAP (
+    rst            => dp_rst,
+    clk            => dp_clk,
+    
+    -- ST input
+    in_sosi        => dp_sosi_arr(0),
+                                                             
+    -- Static control input (connect via MM or leave open to use default)
+    pattern_sel    => a_pattern_sel,
+    verify_res     => a_verify_res,
+    verify_res_val => a_verify_res_val,
+    verify_res_ack => a_verify_res_ack
+  );  
+    
+  u_verify_b : ENTITY work.aduh_verify
+  GENERIC MAP (
+    g_symbol_w             => c_ai.port_w,  -- = 8, fixed
+    g_nof_symbols_per_data => c_dp_factor   -- = 4, fixed, big endian in_sosi.data, t0 in MSSymbol, so [h:0] = [t0]&[t1]&[t2]&[t3]
+  )
+  PORT MAP (
+    rst            => dp_rst,
+    clk            => dp_clk,
+    
+    -- ST input
+    in_sosi        => dp_sosi_arr(1),
+                                                             
+    -- Static control input (connect via MM or leave open to use default)
+    pattern_sel    => b_pattern_sel,
+    verify_res     => b_verify_res,
+    verify_res_val => b_verify_res_val,
+    verify_res_ack => b_verify_res_ack
+  );
+  
+  -- Use verify_ok to check that the verify_res is valid and indicates OK when expected
+  p_verify_res_ok : PROCESS(dp_clk)
+  BEGIN
+    IF rising_edge(dp_clk) THEN
+      IF verify_ok='1' THEN
+        IF a_verify_res_val='0' OR UNSIGNED(a_verify_res)/=0 THEN
+          REPORT "ADUH A: test pattern I error." SEVERITY ERROR;
+        END IF;
+        IF b_verify_res_val='0' OR UNSIGNED(b_verify_res)/=0 THEN
+          REPORT "ADUH B: test pattern Q error." SEVERITY ERROR;
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  -- Use verify_wrong to check that the verify_res is valid and indicates ERROR when expected
+  p_verify_res_wrong : PROCESS(dp_clk)
+  BEGIN
+    IF rising_edge(dp_clk) THEN
+      IF verify_wrong='1' THEN
+        IF a_verify_res_val='0' OR UNSIGNED(a_verify_res)=0 THEN
+          REPORT "ADUH A: test pattern I undetected error." SEVERITY ERROR;
+        END IF;
+        IF b_verify_res_val='0' OR UNSIGNED(b_verify_res)=0 THEN
+          REPORT "ADUH B: test pattern Q undetected error." SEVERITY ERROR;
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  -----------------------------------------------------------------------------
+  -- ADU ADC port A,B both in test pattern mode
+  -----------------------------------------------------------------------------
+  
+  -- Same sample clock for all ADC
+  SCLK <= (NOT SCLK) OR tb_end AFTER c_sample_period/2;
+
+  -- National ADC
+  u_adc : ENTITY work.adu_half
+  PORT MAP (
+    CLK             => SCLK,
+    DCLK            => DCLK,
+    DCLK_RST        => '0',
+    DI              => DIG_A,
+    DQ              => DIG_B,
+    
+    test_pattern_en => test_pattern_en
+  );
+  
+  
+  -----------------------------------------------------------------------------
+  -- ADUH_DD using only port A,B
+  -----------------------------------------------------------------------------
+  
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*7;
+  dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2;
+
+  -- Create DP phase reference clock 
+  p_dp_phs_clk : PROCESS(dp_clk)
+  BEGIN
+    IF c_dp_phs_clk_period=1 THEN
+      dp_phs_clk <= dp_clk;
+    ELSIF rising_edge(dp_clk) THEN
+      IF dp_phs_cnt MOD (c_dp_phs_clk_period/2) = 0 THEN
+        dp_phs_clk <= NOT dp_phs_clk;
+      END IF;
+      IF dp_phs_cnt=c_dp_phs_clk_period-1 THEN
+        dp_phs_cnt<=0;
+      ELSE
+        dp_phs_cnt<=dp_phs_cnt+1;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  gen_dp_phs_clk_vec : FOR I IN c_nof_dp_phs_clk-1 DOWNTO 0 GENERATE
+    dp_phs_clk_vec(I) <= TRANSPORT dp_phs_clk AFTER I*c_dp_phs_clk_step;
+  END GENERATE;
+  
+  u_aduh_dd : ENTITY work.aduh_dd
+  GENERIC MAP (
+    g_ai => c_ai
+  )
+  PORT MAP (
+    -- LVDS Interface
+    -- . g_ai.nof_sp = 4, fixed support 4 signal paths A,B,C,D, but only use and connect A,B here
+    ADC_BI_A         => DIG_A,
+    ADC_BI_B         => DIG_B,
+    
+    ADC_BI_A_CLK     => DCLK,
+    
+    -- MM Interface
+    ab_locked        => ab_locked,
+    ab_stable        => ab_stable,
+    ab_stable_ack    => ab_stable_ack,
+  
+    -- DP Interface
+    dp_rst           => dp_rst,
+    dp_clk           => dp_clk,
+    dp_phs_clk_vec   => dp_phs_clk_vec,
+    
+    -- . Streaming
+    src_out_arr      => aduh_sosi_arr
+  );
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd.vhd b/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd.vhd
new file mode 100644
index 0000000000..606238ac35
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd.vhd
@@ -0,0 +1,142 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+
+ENTITY tb_lvdsh_dd IS
+END tb_lvdsh_dd;
+
+-- Usage:
+-- > as 10
+-- > run 10 us
+
+ARCHITECTURE tb OF tb_lvdsh_dd IS
+
+  CONSTANT c_config_clk_period  : TIME := 10 ns;
+  CONSTANT c_sp_clk_period      : TIME := 1250 ps;            -- 800 MSps sample clock
+  CONSTANT c_in_clk_period      : TIME := c_sp_clk_period*2;  -- 400 MHz double data rate clock
+  
+  CONSTANT c_in_dat_w           : NATURAL := 8;
+  CONSTANT c_in_dat_delay_arr   : t_natural_arr(0 TO c_in_dat_w-1) := array_init(0, c_in_dat_w, 1);  -- nof must match g_dat_w
+  CONSTANT c_in_clk_delay       : NATURAL := c_in_dat_delay_arr(c_in_dat_w-1) + 1;
+  CONSTANT c_out_dat_w          : NATURAL := 2*c_in_dat_w;  -- hi & lo
+  CONSTANT c_rx_big_endian      : BOOLEAN := TRUE;
+  CONSTANT c_rx_factor          : NATURAL := 2;             -- 1, 2, 4, ... must be a power of 2 because of the mixed width FIFO
+  CONSTANT c_rx_fifo_size       : NATURAL := 32;            -- see common_fifo_dc_lock_control used in lvds_dd for comment
+  CONSTANT c_rx_fifo_fill       : NATURAL := 16;            -- see common_fifo_dc_lock_control used in lvds_dd for comment
+  
+  CONSTANT c_rx_clk_period      : TIME := c_rx_factor * c_in_clk_period;  -- 200 MHz data path processing clock
+  
+  SIGNAL tb_end        : STD_LOGIC := '0';
+  SIGNAL config_rst    : STD_LOGIC := '1';
+  SIGNAL config_clk    : STD_LOGIC := '1';
+  
+  SIGNAL sp_clk        : STD_LOGIC := '1';
+  SIGNAL in_clk        : STD_LOGIC := '1';
+  SIGNAL in_clk_en     : STD_LOGIC;
+  SIGNAL in_clk_act    : STD_LOGIC;
+  SIGNAL in_dat        : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL in_clk_rst    : STD_LOGIC;
+    
+  SIGNAL out_clk       : STD_LOGIC;
+  SIGNAL out_dat_hi    : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  SIGNAL out_dat_lo    : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+    
+  SIGNAL rx_rst        : STD_LOGIC := '1';
+  SIGNAL rx_clk        : STD_LOGIC := '1';
+  SIGNAL rx_dat        : STD_LOGIC_VECTOR(c_rx_factor*c_out_dat_w-1 DOWNTO 0);
+  SIGNAL rx_val        : STD_LOGIC;
+  
+  SIGNAL rx_locked     : STD_LOGIC;
+  SIGNAL rx_stable     : STD_LOGIC;
+  SIGNAL rx_stable_ack : STD_LOGIC := '0';
+    
+BEGIN
+
+  config_clk <= NOT config_clk OR tb_end AFTER c_config_clk_period/2;
+  config_rst <= '1', '0' AFTER c_config_clk_period*7;
+
+  sp_clk <=  NOT sp_clk                     OR tb_end AFTER c_sp_clk_period/2;
+  in_clk <= (NOT in_clk AND NOT in_clk_rst) OR tb_end AFTER c_in_clk_period/2;
+  
+  -- Briefly disable the in_clk to verify rx_locked and rx_stable
+  tb_end <= '0',    '1' AFTER c_in_clk_period*10000; 
+  in_clk_en <= '1', '0' AFTER c_in_clk_period*1000,
+                    '1' AFTER c_in_clk_period*1100,
+                    '0' AFTER c_in_clk_period*1200,
+                    '1' AFTER c_in_clk_period*1700,
+                    '0' AFTER c_in_clk_period*2300,
+                    '1' AFTER c_in_clk_period*2400;
+  in_clk_act <= in_clk AND in_clk_en;
+  
+  -- Pulse rx_stable_ack to acknowledge rx_stable and re-enable it
+  rx_stable_ack <= '0', '1' AFTER c_rx_clk_period*100,
+                        '0' AFTER c_rx_clk_period*101,
+                        '1' AFTER c_rx_clk_period*1250,
+                        '0' AFTER c_rx_clk_period*1251,
+                        '1' AFTER c_rx_clk_period*3000,
+                        '0' AFTER c_rx_clk_period*3001;
+  
+  rx_clk <= NOT rx_clk OR tb_end AFTER c_rx_clk_period/2;
+  rx_rst <= '1', '0' AFTER c_rx_clk_period*7;
+  
+  in_dat <= INCR_UVEC(in_dat, 1) WHEN rising_edge(sp_clk);
+  
+  u_dut : ENTITY work.lvdsh_dd
+  GENERIC MAP (
+    g_in_dat_w         => c_in_dat_w,
+    g_in_dat_delay_arr => c_in_dat_delay_arr,
+    g_in_clk_delay     => c_in_clk_delay,
+    g_rx_big_endian    => c_rx_big_endian,
+    g_rx_factor        => c_rx_factor,
+    g_rx_fifo_size     => c_rx_fifo_size,
+    g_rx_fifo_fill     => c_rx_fifo_fill
+  )
+  PORT MAP (
+    -- PHY input delay config clock
+    config_rst    => config_rst,
+    config_clk    => config_clk,
+    
+    -- PHY input interface
+    in_clk        => in_clk_act,
+    in_dat        => in_dat,
+    in_clk_rst    => in_clk_rst,
+    
+    -- DD domain output interface (no FIFO)
+    out_clk       => out_clk,
+    out_dat_hi    => out_dat_hi,
+    out_dat_lo    => out_dat_lo,
+    
+    -- DD --> Rx domain interface at in_clk rate or g_rx_factor lower rate (via FIFO)
+    rx_rst        => rx_rst,
+    rx_clk        => rx_clk,
+    rx_dat        => rx_dat,
+    rx_val        => rx_val,
+    
+    rx_locked     => rx_locked,
+    rx_stable     => rx_stable,
+    rx_stable_ack => rx_stable_ack
+  );
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_phs4.vhd b/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_phs4.vhd
new file mode 100644
index 0000000000..25d6be1dcf
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_phs4.vhd
@@ -0,0 +1,301 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2014
+-- 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 lvdsh_dd_phs4
+-- Description:
+--   The following generic combinations are typically applied:
+--
+--   Realigned data mode (g_nof_dp_phs_clk>0):
+--     g_dclk_drift       g_nof_dp_phs_clk
+--           g_dclk_offon     g_dp_phs_clk_en_mask
+--                                     g_dp_phs_clk_en_vary
+--     0   , TRUE         4,  16#FF#,  FALSE       -- default case used to verify ADU restarts
+--     0   , FALSE        4,  16#FF#,  FALSE       -- used by tb_tb_lvdsh_dd_phs4 to verify g_in_phase=0,1,2,3
+--     0   , TRUE         4,  16#FF#,  TRUE        -- used to verify dp_phs_clk select via MM g_dp_phs_clk_en_mask control
+--     0   , TRUE         4,       0,  FALSE       -- used to verify phase alignment disabled for raw data via MM g_dp_phs_clk_en_mask=0 control
+--    -8 ps, TRUE         4,       0,  FALSE       -- used to verify phase alignment disabled for raw data via MM g_dp_phs_clk_en_mask=0 control
+--    +8 ps, TRUE         4,       0,  FALSE       -- used to verify phase alignment disabled for raw data via MM g_dp_phs_clk_en_mask=0 control
+--    -2 ps, FALSE        4,  16#FF#,  FALSE       -- used to verify in_clk - dp_clk phase uncertainty
+--    +2 ps, FALSE        4,  16#FF#,  FALSE       -- used to verify in_clk - dp_clk phase uncertainty
+--
+--   Raw data mode (g_nof_dp_phs_clk=0):
+--     g_dclk_drift       g_nof_dp_phs_clk
+--           g_dclk_offon     g_dp_phs_clk_en_mask
+--                                     g_dp_phs_clk_en_vary
+--     0   , TRUE         0,  16#FF#,  FALSE       -- used to verify ADU restarts with no phase alignment implemented so raw data only
+--     0   , TRUE         0,  16#FF#,  TRUE        -- used to verify that  dp_phs_clk select via MM g_dp_phs_clk_en_mask control has no effect in raw data only mode
+--    +8 ps, TRUE         0,  16#FF#,  FALSE       -- used to verify in_clk - dp_clk phase uncertainty effect on FIFO fill for raw data only
+--    -8 ps, TRUE         0,  16#FF#,  FALSE       -- used to verify in_clk - dp_clk phase uncertainty effect on FIFO fill for raw data only
+--
+--   Changes due to the tb control will cause some ASSERT ERRORs that are expected near that change.
+--
+-- Usage:
+-- > as 10
+-- > run -all
+
+LIBRARY IEEE, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+
+ENTITY tb_lvdsh_dd_phs4 IS
+  GENERIC (
+     g_dclk_drift         : TIME := 0 ps;      -- 0 ps, use -2 ps or 2 ps to model the range of sample phase uncertainty by letting the sclk and dclk drift with respect to the dp_clk,
+                                               -- use factor 2 value because of integer divide by 2 for rising and falling edge per sclk clock period.
+     g_dclk_offon         : BOOLEAN := TRUE;   -- when TRUE switch the dclk off-on periodically, to model ADU not present or ADU restart or ADU replaced, use FALSE when g_dclk_drift/=0 ps
+     g_dp_phs_clk_period  : NATURAL := 32;     -- number of dp_clk periods per dp_phs_clk period
+     g_nof_dp_phs_clk     : NATURAL := 4;      -- nof dp_phs_clk that can be used to detect the lock, use 1 or 4 to ease interpretation of results when g_dclk_drift/=0 ps
+     g_dp_phs_clk_en_mask : NATURAL := 16#FF#; -- bit mask to individually enable or disable a dp_phs_clk in range [g_nof_dp_phs_clk-1:0]
+     g_dp_phs_clk_en_vary : BOOLEAN := FALSE;  -- use FALSE to use g_dp_phs_clk_en_mask, else use TRUE to vary g_dp_phs_clk_en_vec (assuming g_nof_dp_phs_clk>1)
+     g_in_phase           : NATURAL := 0       -- 0:3
+  );
+END tb_lvdsh_dd_phs4;
+
+ARCHITECTURE tb OF tb_lvdsh_dd_phs4 IS
+
+  CONSTANT c_dd_factor          : NATURAL := 2;
+  CONSTANT c_rx_factor          : NATURAL := 2;
+  CONSTANT c_wb_factor          : NATURAL := c_dd_factor*c_rx_factor;
+  
+  CONSTANT c_sim                : BOOLEAN := TRUE;
+  CONSTANT c_tb_duration        : NATURAL := sel_a_b(g_dclk_drift/=0 ps OR g_dclk_offon=TRUE, 1000, 10);   -- nof tb intervals for tb duration
+  CONSTANT c_tb_init            : NATURAL := sel_a_b(g_dclk_drift/=0 ps OR g_dclk_offon=TRUE,   10, 10);   -- nof tb intervals for tb init before verify_en
+  
+  CONSTANT c_clk_factor         : NATURAL := 100;  -- slow down dclk to improve modelling dclk phase uncertainy with g_dclk_drift, which is minimal 2 ps
+  CONSTANT c_ref_s_clk_period   : TIME := c_clk_factor*1.25 ns;                -- 800 MHz sample clock for dp_sample_dat monitor
+  CONSTANT c_adc_s_clk_period   : TIME := c_ref_s_clk_period + g_dclk_drift;   -- 800 MHz single data rate ADC sample clock with optional drift
+  CONSTANT c_ref_dp_clk_period  : TIME := c_ref_s_clk_period*c_wb_factor;      -- 200 MHz data clock for Data Path processing
+  CONSTANT c_dp_phs_clk_step    : TIME := c_ref_dp_clk_period/32;              -- the PLL can output clocks with phase shifts of 360/32 = 11.25 degrees
+  CONSTANT c_dp_phs_clk_en_mask : STD_LOGIC_VECTOR(g_nof_dp_phs_clk-1 DOWNTO 0) := TO_UVEC(g_dp_phs_clk_en_mask, g_nof_dp_phs_clk);
+  
+  CONSTANT c_interval           : NATURAL := 180;   -- some unit tb interval
+  CONSTANT c_on_interval        : TIME := (c_tb_duration * c_interval / 3 + 3) * c_ref_s_clk_period;
+  CONSTANT c_off_interval       : TIME := (c_tb_duration * c_interval / 3 + 7) * c_ref_s_clk_period;
+  --CONSTANT c_off_interval       : TIME := 1 * c_ref_s_clk_period;   -- if multiple of c_wb_factor=4 then the off period is only noticed by the FIFO running empty
+  
+  CONSTANT c_rl                 : NATURAL := 1;
+  CONSTANT c_init               : NATURAL := 0;
+  CONSTANT c_in_dat_w           : NATURAL := 8;
+  CONSTANT c_dp_dat_w           : NATURAL := c_wb_factor*c_in_dat_w;
+  CONSTANT c_dp_phase_even2     : BOOLEAN := g_in_phase MOD 2 = 0;   -- TRUE for g_in_phase=0,2 and FALSE for g_in_phase=1,3
+  CONSTANT c_dp_phase_even4     : BOOLEAN := g_in_phase <   2;       -- TRUE for g_in_phase=0,1 and FALSE for g_in_phase=2,3
+  CONSTANT c_dp_phase_latency   : NATURAL := 1;   -- account for internal pipeling to be able to compare dp_sample_phase with the in_sample_phase
+  
+  SIGNAL tb_g_dclk_drift    : TIME := g_dclk_drift;
+  SIGNAL tb_g_dclk_offon    : BOOLEAN := g_dclk_offon;
+  SIGNAL tb_g_in_phase      : NATURAL := g_in_phase;
+  
+  SIGNAL tb_end             : STD_LOGIC := '0';
+  SIGNAL rst                : STD_LOGIC := '1';
+  SIGNAL adc_s_clk          : STD_LOGIC := '1';
+  SIGNAL adc_d_clk          : STD_LOGIC := '1';
+  SIGNAL adc_d_clk_off      : STD_LOGIC := '0';
+  SIGNAL adc_d_clkg         : STD_LOGIC := '1';  -- = adc_d_clk gated with adc_d_clk_off
+  SIGNAL ref_s_clk          : STD_LOGIC := '1';
+  SIGNAL ref_d_clk          : STD_LOGIC := '1';
+  SIGNAL ref_dp_clk         : STD_LOGIC := '1';
+  SIGNAL dp_clk_vec         : STD_LOGIC_VECTOR(c_wb_factor-1 DOWNTO 0);
+  SIGNAL dp_clk             : STD_LOGIC;
+  SIGNAL dp_phs_cnt         : NATURAL := 0;
+  SIGNAL dp_phs_clk         : STD_LOGIC := '1';
+  SIGNAL dp_phs_clk_vec     : STD_LOGIC_VECTOR(g_nof_dp_phs_clk-1 DOWNTO 0);
+  SIGNAL dp_phs_clk_en_vec  : STD_LOGIC_VECTOR(g_nof_dp_phs_clk-1 DOWNTO 0) := c_dp_phs_clk_en_mask;
+  SIGNAL ready              : STD_LOGIC := '1';
+  SIGNAL verify_en              : STD_LOGIC := '0';
+  SIGNAL verify_phase_en        : STD_LOGIC := '0';
+  SIGNAL verify_sample_phase_en : STD_LOGIC := '0';
+  SIGNAL verify_data_en         : STD_LOGIC := '0';
+  SIGNAL cnt_en             : STD_LOGIC := '1';
+      
+  SIGNAL in_dat             : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL in_dat_lo          : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  SIGNAL in_val             : STD_LOGIC;
+  SIGNAL dp_dat_lo          : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  SIGNAL dp_dat_diff        : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  SIGNAL dp_dat             : STD_LOGIC_VECTOR(c_dp_dat_w-1 DOWNTO 0);
+  SIGNAL dp_val             : STD_LOGIC := '1';
+  SIGNAL dp_sample_dat      : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  SIGNAL prev_dp_sample_dat : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+    
+  SIGNAL in_sample_phase    : NATURAL;
+  SIGNAL dp_sample_phase    : NATURAL;
+  
+  SIGNAL dp_status          : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- extra status information for debug
+  SIGNAL dp_phs_locked      : STD_LOGIC;
+  SIGNAL dp_word_locked     : STD_LOGIC;
+  SIGNAL dp_word_stable     : STD_LOGIC;
+  SIGNAL dp_word_stable_ack : STD_LOGIC;
+    
+BEGIN
+
+  -- ADU clocking with optional on/off and drift
+  adc_s_clk     <= NOT adc_s_clk OR tb_end AFTER c_adc_s_clk_period/2;  
+  adc_d_clk     <= NOT adc_d_clk WHEN rising_edge(adc_s_clk);
+  adc_d_clkg    <= adc_d_clk OR adc_d_clk_off WHEN c_dp_phase_even2=TRUE ELSE NOT adc_d_clk OR adc_d_clk_off;
+
+  p_on_off : PROCESS
+  BEGIN
+    IF g_dclk_offon=FALSE THEN
+      adc_d_clk_off <= '0'; WAIT;
+    ELSE
+      adc_d_clk_off <= '0'; IF tb_end='1' THEN WAIT; ELSE WAIT FOR c_on_interval;  END IF;
+      adc_d_clk_off <= '1'; IF tb_end='1' THEN WAIT; ELSE WAIT FOR c_off_interval; END IF;
+    END IF;
+  END PROCESS;
+  
+  -- TB ideal clocking
+  ref_s_clk  <= NOT ref_s_clk OR tb_end AFTER c_ref_s_clk_period/2;
+  ref_d_clk  <= NOT ref_d_clk  WHEN rising_edge(ref_s_clk);
+  ref_dp_clk <= NOT ref_dp_clk WHEN rising_edge(ref_d_clk);
+  
+  gen_dp_clk_vec : FOR I IN 0 TO c_wb_factor-1 GENERATE
+    dp_clk_vec(I)<= TRANSPORT ref_dp_clk AFTER (REAL(I) + 0.5)*c_ref_s_clk_period;
+  END GENERATE;
+
+  dp_clk <= dp_clk_vec(0) WHEN c_dp_phase_even4=TRUE ELSE dp_clk_vec(2);  -- actually c_dp_phase_even4=TRUE can not truely be modeled from the outside in this tb
+  --dp_clk <= dp_clk_vec(0);
+  
+  -- Create DP phase reference clock 
+  p_dp_phs_clk : PROCESS(dp_clk)
+  BEGIN
+    IF g_dp_phs_clk_period=1 THEN
+      dp_phs_clk <= dp_clk;
+    ELSIF rising_edge(dp_clk) THEN
+      IF dp_phs_cnt MOD (g_dp_phs_clk_period/2) = 0 THEN
+        dp_phs_clk <= NOT dp_phs_clk;
+      END IF;
+      IF dp_phs_cnt=g_dp_phs_clk_period-1 THEN
+        dp_phs_cnt<=0;
+      ELSE
+        dp_phs_cnt<=dp_phs_cnt+1;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  gen_dp_phs_clk_vec : FOR I IN g_nof_dp_phs_clk-1 DOWNTO 0 GENERATE
+    dp_phs_clk_vec(I) <= TRANSPORT dp_phs_clk AFTER I*c_dp_phs_clk_step;
+  END GENERATE;
+  
+  gen_tb_dp_phs_clk_en : IF g_dp_phs_clk_en_vary=TRUE GENERATE
+    dp_phs_clk_en_vec <= TO_UVEC(255, g_nof_dp_phs_clk),
+                         TO_UVEC(  1, g_nof_dp_phs_clk) AFTER 10 ms,
+                         TO_UVEC( 64, g_nof_dp_phs_clk) AFTER 20 ms,
+                         TO_UVEC( 16, g_nof_dp_phs_clk) AFTER 30 ms,
+                         TO_UVEC(  8, g_nof_dp_phs_clk) AFTER 40 ms,
+                         TO_UVEC(  2, g_nof_dp_phs_clk) AFTER 50 ms,
+                         TO_UVEC( 32, g_nof_dp_phs_clk) AFTER 60 ms,
+                         TO_UVEC(  4, g_nof_dp_phs_clk) AFTER 70 ms,
+                         TO_UVEC(128, g_nof_dp_phs_clk) AFTER 80 ms,
+                         TO_UVEC( 14, g_nof_dp_phs_clk) AFTER 90 ms;
+  END GENERATE;
+  
+  rst <= '1', '0' AFTER 16*c_ref_s_clk_period;
+  
+  proc_common_gen_pulse(1, c_interval, '1',  rst, dp_clk, dp_word_stable_ack);
+  
+  -- Stimuli data
+  p_stimuli : PROCESS
+  BEGIN
+    proc_common_wait_some_cycles(dp_clk, c_interval*c_tb_init);
+    verify_en <= '1';
+    
+    proc_common_wait_some_cycles(dp_clk, c_interval*c_tb_duration);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+  
+  proc_common_gen_data(c_rl, c_init, rst, adc_s_clk, cnt_en, ready, in_dat, in_val);
+  
+  in_dat_lo   <= in_dat                                     WHEN rising_edge(dp_clk);
+  dp_dat_lo   <= dp_dat(4*c_in_dat_w-1 DOWNTO 3*c_in_dat_w) WHEN rising_edge(dp_clk);
+  dp_dat_diff <= SUB_UVEC(in_dat_lo, dp_dat_lo)             WHEN rising_edge(dp_clk);
+  in_sample_phase <= TO_UINT(          in_dat_lo                     ) MOD c_wb_factor WHEN rising_edge(dp_clk);
+  dp_sample_phase <= TO_UINT(INCR_UVEC(dp_dat_lo, c_dp_phase_latency)) MOD c_wb_factor WHEN rising_edge(dp_clk);
+  
+  -- Verify data
+  verify_data_en         <= verify_en OR dp_word_locked;
+  verify_phase_en        <= verify_en WHEN g_dclk_offon=FALSE ELSE '0';
+  verify_sample_phase_en <= verify_en WHEN g_dclk_drift=0 ps AND g_dp_phs_clk_en_mask/=0 ELSE '0';
+  
+  proc_common_verify_data(c_rl, ref_s_clk, verify_data_en, ready, dp_val, dp_sample_dat, prev_dp_sample_dat);
+
+  p_verify_phase : PROCESS(dp_clk)
+  BEGIN
+    IF rising_edge(dp_clk) THEN
+      IF verify_phase_en='1' THEN
+        ASSERT dp_phs_locked ='1' REPORT "Unexpected dp phase detected" SEVERITY ERROR;
+      END IF;
+      IF verify_sample_phase_en='1' THEN
+        ASSERT dp_sample_phase=in_sample_phase REPORT "Unexpected dp_sample_phase" SEVERITY ERROR;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  -- DUT (device under test)
+  u_lvdsh_dd_phs4 : ENTITY work.lvdsh_dd_phs4
+  GENERIC MAP (
+    g_sim               => c_sim,
+    g_wb_factor         => c_wb_factor,
+    g_dp_phs_clk_period => g_dp_phs_clk_period,
+    g_nof_dp_phs_clk    => g_nof_dp_phs_clk,
+    g_in_dat_w          => c_in_dat_w
+  )
+  PORT MAP (
+    -- PHY input interface
+    in_clk              => adc_d_clkg,
+    in_dat              => in_dat,
+    
+    -- DD --> Rx domain interface at adc_d_clk rate or g_dp_factor lower rate (via FIFO)
+    dp_rst              => rst,
+    dp_clk              => dp_clk,
+    dp_phs_clk_vec      => dp_phs_clk_vec,
+    dp_phs_clk_en_vec   => dp_phs_clk_en_vec,
+    dp_dat              => dp_dat,
+    dp_val              => dp_val,
+    
+    -- Rx status monitor
+    out_status          => dp_status,
+    out_phs_locked      => dp_phs_locked,
+    out_word_locked     => dp_word_locked,
+    out_word_stable     => dp_word_stable,
+    out_word_stable_ack => dp_word_stable_ack
+  );
+  
+  u_wb_data_scope : ENTITY common_lib.common_wideband_data_scope
+  GENERIC MAP (
+    g_sim                 => TRUE,
+    g_wideband_factor     => c_wb_factor,
+    g_wideband_big_endian => TRUE,
+    g_dat_w               => c_in_dat_w
+  )
+  PORT MAP (
+    -- Sample clock
+    SCLK      => ref_s_clk,
+    
+    -- Streaming input data
+    in_data   => dp_dat,
+    in_val    => dp_val,
+    
+    -- Scope output samples
+    out_dat   => dp_sample_dat
+  );
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_wb4.vhd b/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_wb4.vhd
new file mode 100644
index 0000000000..490388a674
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_lvdsh_dd_wb4.vhd
@@ -0,0 +1,230 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2014
+-- 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 lvdsh_dd_wb4
+-- Description:
+-- Usage:
+-- > as 10
+-- > run -all
+
+LIBRARY IEEE, common_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+
+ENTITY tb_lvdsh_dd_wb4 IS
+  GENERIC (
+     g_dclk_drift  : TIME := 0 ps;     -- 0 ps, use -2 ps or 2 ps to model the range of sample phase uncertainty by letting the sclk and dclk drift with respect to the dp_clk,
+                                       -- use factor 2 value because of integer divide by 2 for rising and falling edge per sclk clock period.
+     g_dclk_offon  : BOOLEAN := TRUE;  -- when TRUE switch the dclk off-on periodically, to model ADU not present or ADU restart or ADU replaced
+     g_in_phase    : NATURAL := 1      -- 0:3
+  );
+END tb_lvdsh_dd_wb4;
+
+ARCHITECTURE tb OF tb_lvdsh_dd_wb4 IS
+
+  CONSTANT c_sim               : BOOLEAN := TRUE;
+  CONSTANT c_tb_duration       : NATURAL := sel_a_b(g_dclk_drift/=0 ps OR g_dclk_offon=TRUE, 1000, 10);   -- nof tb intervals for tb duration
+  CONSTANT c_tb_init           : NATURAL := sel_a_b(g_dclk_drift/=0 ps OR g_dclk_offon=TRUE,   50,  5);   -- nof tb intervals for tb init before verify_en
+  CONSTANT c_interval          : NATURAL := 180;   -- some unit tb interval
+  CONSTANT c_offon_interval    : NATURAL := c_interval*c_tb_duration/13;
+  
+  CONSTANT c_dd_factor         : NATURAL := 2;
+  CONSTANT c_rx_factor         : NATURAL := 2;
+  CONSTANT c_wb_factor         : NATURAL := c_dd_factor*c_rx_factor;
+  CONSTANT c_clk_factor        : NATURAL := 100;  -- slow down dclk to improve modelling dclk phase uncertainy with g_dclk_drift, which is minimal 2 ps
+  
+  CONSTANT c_sclk_period       : TIME := c_clk_factor*1.25 ns + g_dclk_drift;   -- 800 MHz single data rate ADC sample clock with optional drift
+  CONSTANT c_dp_sclk_period    : TIME := c_clk_factor*1.25 ns;                  -- 800 MHz sample clock for dp_sample_dat monitor
+  CONSTANT c_dp_clk_period     : TIME := c_clk_factor*5 ns;                     -- 200 MHz data clock for Data Path processing
+  CONSTANT c_dp_clk_delay      : TIME := (0.0   + 0.05)*c_dp_clk_period;  -- =   0 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.125 + 0.05)*c_dp_clk_period;  -- =  45 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.25  + 0.05)*c_dp_clk_period;  -- =  90 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.375 + 0.05)*c_dp_clk_period;  -- = 135 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.5   + 0.05)*c_dp_clk_period;  -- = 180 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.625 + 0.05)*c_dp_clk_period;  -- = 225 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.75  + 0.05)*c_dp_clk_period;  -- = 270 degrees
+  --CONSTANT c_dp_clk_delay      : TIME := (0.875 + 0.05)*c_dp_clk_period;  -- = 315 degrees
+  
+  CONSTANT c_rl                : NATURAL := 1;
+  CONSTANT c_init              : NATURAL := 0;
+  CONSTANT c_in_dat_w          : NATURAL := 8;
+  CONSTANT c_dp_dat_w          : NATURAL := c_wb_factor*c_in_dat_w;
+  
+  SIGNAL tb_g_dclk_drift    : TIME := g_dclk_drift;
+  SIGNAL tb_g_dclk_offon    : BOOLEAN := g_dclk_offon;
+  SIGNAL tb_g_in_phase      : NATURAL := g_in_phase;
+  
+  SIGNAL tb_end             : STD_LOGIC := '0';
+  SIGNAL rst                : STD_LOGIC := '1';
+  SIGNAL s_clk              : STD_LOGIC := '1';
+  SIGNAL d_clk              : STD_LOGIC := '1';
+  SIGNAL d_clk_off          : STD_LOGIC := '0';
+  SIGNAL d_clk_rst          : STD_LOGIC;
+  SIGNAL dp_clk             : STD_LOGIC := '1';
+  SIGNAL dp_clkq            : STD_LOGIC;
+  SIGNAL dp_clk_dly         : STD_LOGIC;
+  SIGNAL dp_clkq_dly        : STD_LOGIC;
+  SIGNAL dp_sclk            : STD_LOGIC := '1';
+  SIGNAL ready              : STD_LOGIC := '1';
+  SIGNAL verify_en          : STD_LOGIC := '0';
+  SIGNAL verify_phase_en    : STD_LOGIC := '0';
+  SIGNAL verify_data_en     : STD_LOGIC := '0';
+  SIGNAL cnt_en             : STD_LOGIC := '1';
+      
+  SIGNAL in_dat             : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL in_val             : STD_LOGIC;
+  SIGNAL dp_dat             : STD_LOGIC_VECTOR(c_dp_dat_w-1 DOWNTO 0);
+  SIGNAL dp_val             : STD_LOGIC := '1';
+  SIGNAL dp_sample_dat      : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  SIGNAL prev_dp_sample_dat : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+    
+  SIGNAL dp_sync_phase      : NATURAL;
+  SIGNAL dp_status          : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- extra status information for debug
+  SIGNAL dp_locked          : STD_LOGIC;
+  SIGNAL dp_stable          : STD_LOGIC;
+  SIGNAL dp_stable_ack      : STD_LOGIC;
+    
+BEGIN
+
+  d_clk_off <= NOT d_clk_off OR tb_end AFTER c_offon_interval * c_dp_clk_period WHEN g_dclk_offon=TRUE;
+  
+  s_clk   <= NOT s_clk   OR tb_end AFTER c_sclk_period/2;
+  dp_sclk <= NOT dp_sclk OR tb_end AFTER c_dp_sclk_period/2;
+  
+  p_dclk_divider : PROCESS
+  BEGIN
+    IF rst='1' OR d_clk_off='1' THEN
+      d_clk <= '1';
+      WAIT UNTIL rising_edge(s_clk);
+    ELSE
+      CASE g_in_phase IS
+        WHEN 0|2 => d_clk <= '1'; WAIT UNTIL rising_edge(s_clk);
+                    d_clk <= '0'; WAIT UNTIL rising_edge(s_clk);
+        WHEN 1|3 => d_clk <= '0'; WAIT UNTIL rising_edge(s_clk);
+                    d_clk <= '1'; WAIT UNTIL rising_edge(s_clk);
+        WHEN OTHERS => NULL;
+      END CASE;
+    END IF;
+  END PROCESS;
+  
+  p_dp_clk_divider : PROCESS
+  BEGIN
+    IF rst='1' THEN
+      dp_clk <= '1';
+      WAIT UNTIL rising_edge(s_clk);
+    ELSE
+      dp_clk <= '1'; WAIT UNTIL rising_edge(dp_sclk);
+      dp_clk <= '1'; WAIT UNTIL rising_edge(dp_sclk);
+      dp_clk <= '0'; WAIT UNTIL rising_edge(dp_sclk);
+      dp_clk <= '0'; WAIT UNTIL rising_edge(dp_sclk);
+    END IF;
+  END PROCESS;
+  
+  rst <= '1', '0' AFTER 3*c_dp_clk_period;
+  
+  proc_common_gen_pulse(1, c_interval, '1',  rst, dp_clk, dp_stable_ack);
+  
+  -- Stimuli data
+  p_stimuli : PROCESS
+  BEGIN
+    proc_common_wait_some_cycles(dp_clk, c_interval*c_tb_init);
+    IF g_dclk_drift=0 ps THEN
+      verify_en <= '1';
+    END IF;
+    
+    proc_common_wait_some_cycles(dp_clk, c_interval*c_tb_duration);
+    
+    proc_common_wait_some_cycles(dp_clk, c_interval);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+  
+  proc_common_gen_data(c_rl, c_init, rst, s_clk, cnt_en, ready, in_dat, in_val);
+  
+  -- Verify data
+  verify_data_en  <= verify_en OR dp_locked;
+  verify_phase_en <= verify_en;
+  
+  proc_common_verify_data(c_rl, dp_sclk, verify_data_en, ready, dp_val, dp_sample_dat, prev_dp_sample_dat);
+
+  p_verify_phase : PROCESS(dp_clk)
+  BEGIN
+    IF rising_edge(dp_clk) THEN
+      IF verify_phase_en='1' THEN
+        ASSERT dp_sync_phase=g_in_phase OR dp_sync_phase=4+g_in_phase REPORT "Unexpected dp_sync_phase" SEVERITY ERROR;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  -- DUT (device under test)
+  dp_clkq     <= TRANSPORT dp_clk     AFTER c_dp_clk_period/4;
+  dp_clk_dly  <= TRANSPORT dp_clk     AFTER c_dp_clk_delay;
+  dp_clkq_dly <= TRANSPORT dp_clk_dly AFTER c_dp_clk_period/4;
+  
+  u_lvdsh_dd_wb4 : ENTITY work.lvdsh_dd_wb4
+  GENERIC MAP (
+    g_sim       => c_sim,
+    g_sim_phase => g_in_phase,
+    g_wb_factor => c_wb_factor,
+    g_in_dat_w  => c_in_dat_w
+  )
+  PORT MAP (
+    -- PHY input interface
+    in_clk_rst    => d_clk_rst,
+    in_clk        => d_clk,
+    in_dat        => in_dat,
+    
+    -- DD --> Rx domain interface at d_clk rate or g_dp_factor lower rate (via FIFO)
+    dp_rst        => rst,
+    dp_clk        => dp_clk_dly,
+    dp_clkq       => dp_clkq_dly,
+    dp_dat        => dp_dat,
+    dp_val        => dp_val,
+    
+    -- Rx status monitor
+    dp_sync_phase => dp_sync_phase,
+    dp_status     => dp_status,
+    dp_locked     => dp_locked,
+    dp_stable     => dp_stable,
+    dp_stable_ack => dp_stable_ack
+  );
+  
+  u_wb_data_scope : ENTITY common_lib.common_wideband_data_scope
+  GENERIC MAP (
+    g_sim                 => TRUE,
+    g_wideband_factor     => c_wb_factor,
+    g_wideband_big_endian => TRUE,
+    g_dat_w               => c_in_dat_w
+  )
+  PORT MAP (
+    -- Sample clock
+    SCLK      => dp_sclk,
+    
+    -- Streaming input data
+    in_data   => dp_dat,
+    in_val    => dp_val,
+    
+    -- Scope output samples
+    out_dat   => dp_sample_dat
+  );
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_mms_aduh_quad.vhd b/libraries/io/aduh/tb/vhdl/tb_mms_aduh_quad.vhd
new file mode 100644
index 0000000000..bf3451cbed
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_mms_aduh_quad.vhd
@@ -0,0 +1,338 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright (C) 2011
+-- 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/>.
+--
+-------------------------------------------------------------------------------
+
+-- Usage:
+-- > as 10
+-- > run 20 us
+-- > p_verify_res should report no errors
+
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE work.aduh_dd_pkg.ALL;
+
+ENTITY tb_mms_aduh_quad IS
+END tb_mms_aduh_quad;
+
+ARCHITECTURE tb OF tb_mms_aduh_quad IS
+
+  --TYPE t_c_aduh_dd_ai IS RECORD
+  --  nof_sp      : NATURAL;          -- = 4
+  --  nof_adu     : NATURAL;          -- = 2
+  --  nof_ports   : NATURAL;          -- = 2
+  --  port_w      : NATURAL;          -- = 8
+  --  dd_factor   : NATURAL;          -- = 2
+  --  rx_factor   : NATURAL;          -- = 2
+  --  deskew      : t_c_aduh_delays;  -- = (0, 0, (OTHERS=>0), (OTHERS=>0), (OTHERS=>0), (OTHERS=>0))  -- clock: a, b, data: a, b, c, d
+  --END RECORD;
+  CONSTANT c_ai                   : t_c_aduh_dd_ai := c_aduh_dd_ai;  -- use defaults
+  
+  CONSTANT c_dp_factor            : NATURAL := c_ai.rx_factor * c_ai.dd_factor;  -- = 4 = 2 * 2
+  
+  CONSTANT c_sample_period        : TIME := 1250 ps;                         -- 800 MTps
+  CONSTANT c_dp_clk_period        : TIME := c_sample_period*c_dp_factor;     -- 200 MHz
+  CONSTANT c_mm_clk_period        : TIME := 20 ns;                           -- 50 MHz
+  
+  CONSTANT c_aduh_verify_val_bi   : NATURAL := 12;
+  CONSTANT c_aduh_verify_res_hi   : NATURAL := 8;
+  CONSTANT c_aduh_verify_res_mask : NATURAL := 2**(c_aduh_verify_res_hi+1) - 1;
+
+  CONSTANT c_dp_phs_clk_step     : TIME := c_dp_clk_period/32;  -- the PLL can output clocks with phase shifts of 360/32 = 11.25 degrees
+  CONSTANT c_dp_phs_clk_period   : NATURAL := 32;               -- number of dp_clk periods per dp_phs_clk period
+  CONSTANT c_nof_dp_phs_clk      : NATURAL := 1;
+  
+  PROCEDURE proc_verify_bist_expect_ok(aduh_a_verify, aduh_b_verify, aduh_c_verify, aduh_d_verify : STD_LOGIC_VECTOR) IS
+  BEGIN
+    ASSERT aduh_a_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-A bist did not run" SEVERITY ERROR;
+    ASSERT aduh_b_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-B bist did not run" SEVERITY ERROR;
+    ASSERT aduh_c_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-C bist did not run" SEVERITY ERROR;
+    ASSERT aduh_d_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-D bist did not run" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_a_verify(c_aduh_verify_res_hi DOWNTO 0))=0 REPORT "ADU-A bist went wrong" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_b_verify(c_aduh_verify_res_hi DOWNTO 0))=0 REPORT "ADU-B bist went wrong" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_c_verify(c_aduh_verify_res_hi DOWNTO 0))=0 REPORT "ADU-C bist went wrong" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_d_verify(c_aduh_verify_res_hi DOWNTO 0))=0 REPORT "ADU-D bist went wrong" SEVERITY ERROR;
+  END;
+  
+  PROCEDURE proc_verify_bist_expect_errors(aduh_a_verify, aduh_b_verify, aduh_c_verify, aduh_d_verify : STD_LOGIC_VECTOR) IS
+  BEGIN
+    ASSERT aduh_a_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-A bist did not run" SEVERITY ERROR;
+    ASSERT aduh_b_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-B bist did not run" SEVERITY ERROR;
+    ASSERT aduh_c_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-C bist did not run" SEVERITY ERROR;
+    ASSERT aduh_d_verify(c_aduh_verify_val_bi)='1' REPORT "ADU-D bist did not run" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_a_verify(c_aduh_verify_res_hi DOWNTO 0))=c_aduh_verify_res_mask REPORT "ADU-A bist error detection went wrong" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_b_verify(c_aduh_verify_res_hi DOWNTO 0))=c_aduh_verify_res_mask REPORT "ADU-B bist error detection went wrong" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_c_verify(c_aduh_verify_res_hi DOWNTO 0))=c_aduh_verify_res_mask REPORT "ADU-C bist error detection went wrong" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_d_verify(c_aduh_verify_res_hi DOWNTO 0))=c_aduh_verify_res_mask REPORT "ADU-D bist error detection went wrong" SEVERITY ERROR;
+  END;
+  
+  SIGNAL tb_end              : STD_LOGIC := '0';
+  
+  -- Analogue
+  SIGNAL SCLK                : STD_LOGIC := '1';       -- central sample clock = 800 MHz
+  SIGNAL DCLK_AB             : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DCLK_CD             : STD_LOGIC;              -- digital lvds clock   = 400 MHz (DDR)
+  SIGNAL DIG_A               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_B               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_C               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  SIGNAL DIG_D               : STD_LOGIC_VECTOR(c_ai.port_w-1 DOWNTO 0);
+  
+  -- Digital streaming
+  SIGNAL dp_clk              : STD_LOGIC := '1';   -- digital data path clock = 200 MHz (deser factor 4);
+  SIGNAL dp_rst              : STD_LOGIC;
+  SIGNAL dp_phs_cnt          : NATURAL := 0;
+  SIGNAL dp_phs_clk          : STD_LOGIC := '1';
+  SIGNAL dp_phs_clk_vec      : STD_LOGIC_VECTOR(c_nof_dp_phs_clk-1 DOWNTO 0);
+  
+  SIGNAL aduh_sosi_arr       : t_dp_sosi_arr(0 TO c_ai.nof_sp-1);
+  
+  -- MM Interface
+  SIGNAL mm_clk              : STD_LOGIC := '1';   -- MM control clock = 50 MHz
+  SIGNAL mm_rst              : STD_LOGIC;
+  
+  -- MM aduh quad register
+  SIGNAL aduh_ab_locked      : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  SIGNAL aduh_cd_locked      : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  SIGNAL aduh_a_verify       : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  SIGNAL aduh_b_verify       : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  SIGNAL aduh_c_verify       : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  SIGNAL aduh_d_verify       : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  
+  SIGNAL reg_mosi            : t_mem_mosi := c_mem_mosi_rst;  -- ADUH locked status and pattern verify for two half ADUs so 4 ADC inputs A, B, C and D
+  SIGNAL reg_miso            : t_mem_miso;
+  
+  SIGNAL test_pattern_en     : STD_LOGIC;
+  SIGNAL state               : STRING(1 TO 8) := "INIT    ";
+    
+BEGIN
+
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*7;
+  dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2;
+  
+  mm_rst <= '1', '0' AFTER c_mm_clk_period*7;
+  mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2;
+
+  -- Create DP phase reference clock 
+  p_dp_phs_clk : PROCESS(dp_clk)
+  BEGIN
+    IF c_dp_phs_clk_period=1 THEN
+      dp_phs_clk <= dp_clk;
+    ELSIF rising_edge(dp_clk) THEN
+      IF dp_phs_cnt MOD (c_dp_phs_clk_period/2) = 0 THEN
+        dp_phs_clk <= NOT dp_phs_clk;
+      END IF;
+      IF dp_phs_cnt=c_dp_phs_clk_period-1 THEN
+        dp_phs_cnt<=0;
+      ELSE
+        dp_phs_cnt<=dp_phs_cnt+1;
+      END IF;
+    END IF;
+  END PROCESS;
+  
+  gen_dp_phs_clk_vec : FOR I IN c_nof_dp_phs_clk-1 DOWNTO 0 GENERATE
+    dp_phs_clk_vec(I) <= TRANSPORT dp_phs_clk AFTER I*c_dp_phs_clk_step;
+  END GENERATE;
+  
+  ----------------------------------------------------------------------------
+  -- Stimuli for MM REG slave port
+  ----------------------------------------------------------------------------
+  
+  p_mm_reg_stimuli : PROCESS
+  BEGIN
+    reg_mosi         <= c_mem_mosi_rst;
+    test_pattern_en  <= '1';
+    
+    ----------------------------------------------------------------------------
+    -- Initialisations
+    ----------------------------------------------------------------------------
+    
+    proc_common_wait_until_low(mm_clk, mm_rst);
+    proc_common_wait_some_cycles(mm_clk, 10);
+    
+    -- Read aduh locked status for AB, CD
+    proc_common_wait_some_cycles(mm_clk, 10);
+    state <= "LOCKED  ";
+    proc_mem_mm_bus_rd(0, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_ab_locked <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(1, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_cd_locked <= reg_miso.rddata(31 DOWNTO 0);
+    proc_common_wait_some_cycles(mm_clk, 1);
+    ASSERT TO_UINT(aduh_ab_locked)=3 REPORT "ADU-AB in not locked" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_cd_locked)=3 REPORT "ADU-CD in not locked" SEVERITY ERROR;
+    
+    ----------------------------------------------------------------------------
+    -- Expect aduh BIST OK for A, B, C, D
+    ----------------------------------------------------------------------------
+    proc_common_wait_some_cycles(mm_clk, 10);
+    state <= "BIST_OK ";
+    proc_mem_mm_bus_rd(2, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_a_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(3, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_b_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(4, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_c_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(5, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_d_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_common_wait_some_cycles(mm_clk, 1);
+    proc_verify_bist_expect_ok(aduh_a_verify, aduh_b_verify, aduh_c_verify, aduh_d_verify);
+    
+    test_pattern_en  <= '0';
+    -- Read aduh locked status for AB, CD
+    proc_common_wait_some_cycles(mm_clk, 10);
+    proc_mem_mm_bus_rd(0, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_ab_locked <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(1, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_cd_locked <= reg_miso.rddata(31 DOWNTO 0);
+    proc_common_wait_some_cycles(mm_clk, 1);
+    ASSERT TO_UINT(aduh_ab_locked)=3 REPORT "ADU-AB in not locked" SEVERITY ERROR;
+    ASSERT TO_UINT(aduh_cd_locked)=3 REPORT "ADU-CD in not locked" SEVERITY ERROR;
+    
+    ----------------------------------------------------------------------------
+    -- Expect aduh BIST errors for A, B, C, D
+    ----------------------------------------------------------------------------
+    proc_common_wait_some_cycles(mm_clk, 10);
+    state <= "BIST_ERR";
+    proc_mem_mm_bus_rd(2, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_a_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(3, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_b_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(4, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_c_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(5, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_d_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_common_wait_some_cycles(mm_clk, 1);
+    proc_verify_bist_expect_errors(aduh_a_verify, aduh_b_verify, aduh_c_verify, aduh_d_verify);
+    
+    ----------------------------------------------------------------------------
+    -- Expect aduh BIST errors for A, B, C, D
+    ----------------------------------------------------------------------------
+    proc_common_wait_some_cycles(mm_clk, 10);
+    test_pattern_en  <= '1';
+    proc_common_wait_some_cycles(mm_clk, 100);
+    state <= "BIST_ERR";
+    proc_mem_mm_bus_rd(2, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_a_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(3, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_b_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(4, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_c_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(5, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_d_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_common_wait_some_cycles(mm_clk, 1);
+    proc_verify_bist_expect_errors(aduh_a_verify, aduh_b_verify, aduh_c_verify, aduh_d_verify);
+    
+    
+    ----------------------------------------------------------------------------
+    -- Expect aduh BIST OK for A, B, C, D
+    ----------------------------------------------------------------------------
+    proc_common_wait_some_cycles(mm_clk, 10);
+    state <= "BIST_OK ";
+    proc_mem_mm_bus_rd(2, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_a_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(3, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_b_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(4, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_c_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_mem_mm_bus_rd(5, mm_clk, reg_mosi); proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk); aduh_d_verify <= reg_miso.rddata(31 DOWNTO 0);
+    proc_common_wait_some_cycles(mm_clk, 1);
+    proc_verify_bist_expect_ok(aduh_a_verify, aduh_b_verify, aduh_c_verify, aduh_d_verify);
+    
+    proc_common_wait_some_cycles(mm_clk, 10);
+    tb_end <= '1';    
+    WAIT;
+  END PROCESS;
+  
+  
+  ------------------------------------------------------------------------------
+  -- ADUH_QUAD for ADC port [ABCD]
+  ------------------------------------------------------------------------------
+  
+  u_dut : ENTITY work.mms_aduh_quad
+  GENERIC MAP (
+    -- General
+    g_cross_clock_domain => TRUE,
+    -- ADC Interface
+    g_ai                 => c_aduh_dd_ai
+  )
+  PORT MAP (
+    -- ADC Interface
+    -- . ADU_AB
+    ADC_BI_A          => DIG_A,
+    ADC_BI_B          => DIG_B,
+    ADC_BI_A_CLK      => DCLK_AB,
+    ADC_BI_A_CLK_RST  => OPEN,
+    
+    -- . ADU_CD
+    ADC_BI_C          => DIG_A,
+    ADC_BI_D          => DIG_D,
+    ADC_BI_D_CLK      => DCLK_CD,
+    ADC_BI_D_CLK_RST  => OPEN,
+    
+    -- MM clock domain
+    mm_rst            => mm_rst,
+    mm_clk            => mm_clk,
+    
+    reg_mosi          => reg_mosi,
+    reg_miso          => reg_miso,
+    
+    -- Streaming clock domain
+    dp_rst            => dp_rst,
+    dp_clk            => dp_clk,
+    dp_phs_clk_vec    => dp_phs_clk_vec,
+    
+    -- . data
+    aduh_sosi_arr     => aduh_sosi_arr
+  );
+  
+  -- Scope in Wave Window for debug purpose
+  u_scope : ENTITY work.aduh_quad_scope
+  GENERIC MAP (
+    -- General
+    g_sim  => TRUE,
+    -- ADC Interface
+    g_ai   => c_aduh_dd_ai
+  )
+  PORT MAP (
+    -- Sample clock
+    SCLK         => SCLK,
+    
+    -- Streaming samples (can be from ADU or from internal WG)
+    sp_sosi_arr  => aduh_sosi_arr
+  );
+  
+  
+  ------------------------------------------------------------------------------
+  -- ADU-[AB, CD] ADC ports both in test pattern mode
+  ------------------------------------------------------------------------------
+  
+  -- Same sample clock for all ADC
+  SCLK <= (NOT SCLK) OR tb_end AFTER c_sample_period/2;
+
+  -- National ADC
+  u_adc_ab : ENTITY work.adu_half
+  PORT MAP (
+    CLK             => SCLK,
+    DCLK            => DCLK_AB,
+    DCLK_RST        => '0',
+    DI              => DIG_A,
+    DQ              => DIG_B,
+    
+    test_pattern_en => test_pattern_en
+  );
+  
+  -- National ADC
+  u_adc_cd : ENTITY work.adu_half
+  PORT MAP (
+    CLK             => SCLK,
+    DCLK            => DCLK_CD,
+    DCLK_RST        => '0',
+    DI              => DIG_C,
+    DQ              => DIG_D,
+    
+    test_pattern_en => test_pattern_en
+  );
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_phs4.vhd b/libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_phs4.vhd
new file mode 100644
index 0000000000..bfc33a1397
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_phs4.vhd
@@ -0,0 +1,53 @@
+-------------------------------------------------------------------------------
+--
+-- 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;
+USE IEEE.std_logic_1164.ALL;
+
+
+ENTITY tb_tb_lvdsh_dd_phs4 IS
+END tb_tb_lvdsh_dd_phs4;
+
+
+ARCHITECTURE tb OF tb_tb_lvdsh_dd_phs4 IS
+
+  CONSTANT c_dp_phs_clk_period : NATURAL := 32;
+  
+BEGIN
+
+  -- > as 3
+  -- > run -all
+
+  -- g_dclk_drift         : TIME := 0 ps;       -- 0 ps, use -2 ps or 2 ps to model the range of sample phase uncertainty by letting the sclk and dclk drift with respect to the dp_clk,
+  -- g_dclk_offon         : BOOLEAN := TRUE;    -- when TRUE switch the dclk off-on periodically, to model ADU not present or ADU restart or ADU replaced
+  -- g_dp_phs_clk_period  : NATURAL := 32;      -- number of dp_clk periods per dp_phs_clk period
+  -- g_nof_dp_phs_clk     : NATURAL := 1;       -- nof dp_phs_clk that can be used to detect the lock
+  -- g_dp_phs_clk_en_mask : NATURAL := 16#FF#;  -- bit mask to indiviually enable or disable a dp_phs_clk in range [g_nof_dp_phs_clk-1:0]
+  -- g_dp_phs_clk_en_vary : BOOLEAN := FALSE;   -- use FALSE to use g_dp_phs_clk_en_mask, else use TRUE to vary g_dp_phs_clk_en_vec (assuming g_nof_dp_phs_clk>1)
+  -- g_in_phase           : NATURAL := 1        -- 0:3
+
+  u_phase_0    : ENTITY work.tb_lvdsh_dd_phs4 GENERIC MAP (0 ps, FALSE, c_dp_phs_clk_period, 1, 16#FF#, FALSE, 0);
+  u_phase_1    : ENTITY work.tb_lvdsh_dd_phs4 GENERIC MAP (0 ps, FALSE, c_dp_phs_clk_period, 1, 16#FF#, FALSE, 1);
+  u_phase_2    : ENTITY work.tb_lvdsh_dd_phs4 GENERIC MAP (0 ps, FALSE, c_dp_phs_clk_period, 1, 16#FF#, FALSE, 2);
+  u_phase_3    : ENTITY work.tb_lvdsh_dd_phs4 GENERIC MAP (0 ps, FALSE, c_dp_phs_clk_period, 1, 16#FF#, FALSE, 3);
+  
+END tb;
diff --git a/libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_wb4.vhd b/libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_wb4.vhd
new file mode 100644
index 0000000000..21399729c7
--- /dev/null
+++ b/libraries/io/aduh/tb/vhdl/tb_tb_lvdsh_dd_wb4.vhd
@@ -0,0 +1,46 @@
+-------------------------------------------------------------------------------
+--
+-- 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;
+USE IEEE.std_logic_1164.ALL;
+
+
+ENTITY tb_tb_lvdsh_dd_wb4 IS
+END tb_tb_lvdsh_dd_wb4;
+
+
+ARCHITECTURE tb OF tb_tb_lvdsh_dd_wb4 IS
+BEGIN
+
+  -- > as 3
+  -- > run -all
+
+  -- g_dclk_drift  : TIME := 0 ps;     -- 0 ps, use -2 ps or 2 ps to model the range of sample phase uncertainty by letting the sclk and dclk drift with respect to the dp_clk,
+  -- g_dclk_offon  : BOOLEAN := TRUE;  -- when TRUE switch the dclk off-on periodically, to model ADU not present or ADU restart or ADU replaced
+  -- g_in_phase    : NATURAL := 1      -- 0:3
+
+  u_phase_0    : ENTITY work.tb_lvdsh_dd_wb4 GENERIC MAP (0 ps, FALSE, 0);
+  u_phase_1    : ENTITY work.tb_lvdsh_dd_wb4 GENERIC MAP (0 ps, FALSE, 1);
+  u_phase_2    : ENTITY work.tb_lvdsh_dd_wb4 GENERIC MAP (0 ps, FALSE, 2);
+  u_phase_3    : ENTITY work.tb_lvdsh_dd_wb4 GENERIC MAP (0 ps, FALSE, 3);
+  
+END tb;
-- 
GitLab