diff --git a/libraries/io/tr_10GbE/tb/vhdl/tb_tb_tr_10GbE.vhd b/libraries/io/tr_10GbE/tb/vhdl/tb_tb_tr_10GbE.vhd
index 9c38a3ae1d05db6b495675080c25c1e4b5676d5d..3222c5b93fa16bea4de7261b0f0ae1d5c554a11f 100644
--- a/libraries/io/tr_10GbE/tb/vhdl/tb_tb_tr_10GbE.vhd
+++ b/libraries/io/tr_10GbE/tb/vhdl/tb_tb_tr_10GbE.vhd
@@ -26,11 +26,12 @@
 --   > as 5
 --   > run -all
 
-LIBRARY IEEE, technology_lib, tech_mac_10g_lib;
+LIBRARY IEEE, technology_lib, tech_pll_lib, tech_mac_10g_lib;
 USE IEEE.std_logic_1164.ALL;
 USE technology_lib.technology_pkg.ALL;
 USE technology_lib.technology_select_pkg.ALL;
 USE tech_mac_10g_lib.tb_tech_mac_10g_pkg.ALL;
+USE tech_pll_lib.tech_pll_component_pkg.ALL;
 
 
 ENTITY tb_tb_tr_10GbE IS
@@ -38,22 +39,29 @@ END tb_tb_tr_10GbE;
 
 
 ARCHITECTURE tb OF tb_tb_tr_10GbE IS
-  CONSTANT c_tb_end_vec : STD_LOGIC_VECTOR(31 DOWNTO 0) := (OTHERS=>'1');
-  SIGNAL   tb_end_vec   : STD_LOGIC_VECTOR(31 DOWNTO 0) := c_tb_end_vec;  -- sufficiently long to fit all tb instances
+  CONSTANT c_644       : TIME := tech_pll_clk_644_period;
+  CONSTANT c_156       : TIME := 6.4 ns;
+  CONSTANT c_data_type : NATURAL := c_tb_tech_mac_10g_data_type_symbols;
+  
+  CONSTANT c_tb_end_vec : STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS=>'1');
+  SIGNAL   tb_end_vec   : STD_LOGIC_VECTOR(7 DOWNTO 0) := c_tb_end_vec;  -- sufficiently long to fit all tb instances
 BEGIN
 
--- g_technology         : NATURAL := c_tech_stratixiv;
--- g_tb_end             : BOOLEAN := TRUE;   -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
--- g_sim_level          : NATURAL := 0;      -- 0 = use IP; 1 = use fast serdes model
--- g_no_dut             : BOOLEAN := FALSE;  -- default FALSE to verify the DUT, else use TRUE to verify the tb itself without the DUT
--- --   g_data_type = c_tb_tech_mac_10g_data_type_symbols  = 0
--- --   g_data_type = c_tb_tech_mac_10g_data_type_counter  = 1
--- g_data_type        : NATURAL := c_tb_tech_mac_10g_data_type_symbols
+-- g_technology              : NATURAL := c_tech_select_default;
+-- g_tb_end                  : BOOLEAN := TRUE;   -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
+-- g_no_dut                  : BOOLEAN := FALSE;  -- default FALSE to verify the DUT, else use TRUE to verify the tb itself without the DUT
+-- g_sim_level               : NATURAL := 1;      -- 0 = use IP; 1 = use fast serdes model
+-- g_nof_channels            : NATURAL := 1;
+-- g_ref_clk_644_period      : TIME := tech_pll_clk_644_period;  -- for 10GBASE-R
+-- g_ref_clk_156_period      : TIME := 6.4 ns;                   -- for XAUI
+-- g_data_type               : NATURAL := c_tb_tech_mac_10g_data_type_symbols;
+-- g_verify_link_recovery    : BOOLEAN := TRUE;
+-- g_link_status_check       : STD_LOGIC_VECTOR(c_tech_mac_10g_link_status_w-1 DOWNTO 0) := "11"
 
-  u_no_dut_counter                  : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, 0,  TRUE, c_tb_tech_mac_10g_data_type_counter) PORT MAP (tb_end_vec(0));
-  u_no_dut_symbols                  : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, 0,  TRUE, c_tb_tech_mac_10g_data_type_symbols) PORT MAP (tb_end_vec(1));
-  u_tr_10GbE_symbols                : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, 0, FALSE, c_tb_tech_mac_10g_data_type_symbols) PORT MAP (tb_end_vec(5));
-  u_tr_10GbE_symbols_sim_level_is_1 : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, 1, FALSE, c_tb_tech_mac_10g_data_type_symbols) PORT MAP (tb_end_vec(6));
+  u_no_dut                     : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE,  TRUE, 0, 1, c_644, c_156, c_data_type, TRUE, "11") PORT MAP (tb_end_vec(0));
+  u_tr_10GbE                   : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 0, 1, c_644, c_156, c_data_type, TRUE, "11") PORT MAP (tb_end_vec(1));
+  u_tr_10GbE_nof_channels_is_2 : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 0, 2, c_644, c_156, c_data_type, TRUE, "11") PORT MAP (tb_end_vec(2));
+  u_tr_10GbE_sim_level_is_1    : ENTITY work.tb_tr_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 1, 1, c_644, c_156, c_data_type, TRUE, "11") PORT MAP (tb_end_vec(3));
   
   p_tb_end : PROCESS
   BEGIN
diff --git a/libraries/io/tr_10GbE/tb/vhdl/tb_tr_10GbE.vhd b/libraries/io/tr_10GbE/tb/vhdl/tb_tr_10GbE.vhd
index 87578e00b2b3d4d0867ef2ce80cc299300c98f23..c783900be7f683fbbad037a998ad68f9805a8af3 100644
--- a/libraries/io/tr_10GbE/tb/vhdl/tb_tr_10GbE.vhd
+++ b/libraries/io/tr_10GbE/tb/vhdl/tb_tr_10GbE.vhd
@@ -32,9 +32,8 @@
 --   > as 10
 --   > run -all
 
-LIBRARY IEEE, technology_lib, common_lib, dp_lib, tech_mac_10g_lib;
+LIBRARY IEEE, technology_lib, tech_pll_lib, tech_mac_10g_lib, 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.common_interface_layers_pkg.ALL;
@@ -43,20 +42,24 @@ USE common_lib.common_network_total_header_pkg.ALL;
 USE common_lib.tb_common_pkg.ALL;
 USE dp_lib.dp_stream_pkg.ALL;
 USE technology_lib.technology_pkg.ALL;
+USE technology_lib.technology_select_pkg.ALL;
 USE tech_mac_10g_lib.tech_mac_10g_component_pkg.ALL;
 USE tech_mac_10g_lib.tb_tech_mac_10g_pkg.ALL;
-
+USE tech_pll_lib.tech_pll_component_pkg.ALL;
 
 ENTITY tb_tr_10GbE IS
   -- Test bench control parameters
   GENERIC (
-    g_technology         : NATURAL := c_tech_stratixiv;
-    g_tb_end             : BOOLEAN := TRUE;   -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
-    g_sim_level          : NATURAL := 1;      -- 0 = use IP; 1 = use fast serdes model
-    g_no_dut             : BOOLEAN := FALSE;  -- default FALSE to verify the DUT, else use TRUE to verify the tb itself without the DUT
-    --   g_data_type = c_tb_tech_mac_10g_data_type_symbols  = 0
-    --   g_data_type = c_tb_tech_mac_10g_data_type_counter  = 1
-    g_data_type        : NATURAL := c_tb_tech_mac_10g_data_type_symbols
+    g_technology              : NATURAL := c_tech_select_default;
+    g_tb_end                  : BOOLEAN := TRUE;   -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
+    g_no_dut                  : BOOLEAN := FALSE;  -- default FALSE to verify the DUT, else use TRUE to verify the tb itself without the DUT
+    g_sim_level               : NATURAL := 1;      -- 0 = use IP; 1 = use fast serdes model
+    g_nof_channels            : NATURAL := 2;
+    g_ref_clk_644_period      : TIME := tech_pll_clk_644_period;  -- for 10GBASE-R
+    g_ref_clk_156_period      : TIME := 6.4 ns;                   -- for XAUI
+    g_data_type               : NATURAL := c_tb_tech_mac_10g_data_type_symbols;
+    g_verify_link_recovery    : BOOLEAN := TRUE;
+    g_link_status_check       : STD_LOGIC_VECTOR(c_tech_mac_10g_link_status_w-1 DOWNTO 0) := "11"
   );
   PORT (
     tb_end : OUT STD_LOGIC
@@ -68,18 +71,18 @@ ARCHITECTURE tb OF tb_tr_10GbE IS
 
   CONSTANT c_sim                : BOOLEAN := TRUE;  -- tr_xaui_align_dly has time delay ~ 1 sec, so not suitable for simulation
   
-  CONSTANT mm_clk_period        : TIME := 20 ns;    --  50 MHz
-  CONSTANT dp_clk_period        : TIME :=  5 ns;    -- 200 MHz
   CONSTANT cal_clk_period       : TIME := 25 ns;    --  40 MHz
-  CONSTANT clk_156_period       : TIME :=  6.4 ns;  -- 156.25 MHz
-  CONSTANT phy_delay            : TIME := sel_a_b(g_sim_level>0, 0 ns, 1 ns);  -- the sim_xaui and sim_10gbase_r only work with zero or tr_clk delays
+  CONSTANT dp_clk_period        : TIME :=  5 ns;    -- 200 MHz
   
-  CONSTANT c_nof_channels       : NATURAL := 1;
-  CONSTANT c_rl                 : NATURAL := 1;
-  CONSTANT c_nof_tx_not_valid   : NATURAL := 0;  -- when > 0 then pull tx valid low for c_nof_tx_not_valid beats during tx
-  CONSTANT c_pkt_length_arr     : t_nat_natural_arr := array_init(0, 50, 1) & (1472, 1473) & 9000;  -- frame longer than 1518-46 = 1472 is received with rx_sosi.err = 8
+  CONSTANT phy_delay            : TIME := sel_a_b(g_sim_level=0, 1 ns, 0 ns);
+  
+  CONSTANT c_pkt_length_arr1    : t_nat_natural_arr := array_init(0, 50, 1) & (1472, 1473) & 9000;  -- frame longer than 1518-46 = 1472 is received with rx_sosi.err = 8
                                                                                                     -- jumbo frame is 9018-46 = 8972
-  CONSTANT c_nof_pkt            : NATURAL := c_pkt_length_arr'LENGTH;
+  CONSTANT c_pkt_length_arr2    : t_nat_natural_arr := array_init(46, 10, 139) & 1472;
+  CONSTANT c_pkt_length_arr     : t_nat_natural_arr := c_pkt_length_arr1 & c_pkt_length_arr2;
+  CONSTANT c_nof_pkt1           : NATURAL := c_pkt_length_arr1'LENGTH;
+  CONSTANT c_nof_pkt2           : NATURAL := c_pkt_length_arr2'LENGTH;
+  CONSTANT c_nof_pkt            : NATURAL := sel_a_b(g_verify_link_recovery, c_nof_pkt1 + c_nof_pkt2, c_nof_pkt1);
 
   CONSTANT c_dst_mac            : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"10FA01020300";
   CONSTANT c_src_mac            : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"123456789ABC";  -- = 12-34-56-78-9A-BC
@@ -95,202 +98,145 @@ ARCHITECTURE tb OF tb_tr_10GbE IS
   SIGNAL total_header      : t_network_total_header := c_network_total_header_ones;  -- default fill all fields with value 1
   
   -- Clocks and reset
-  SIGNAL rx_end            : STD_LOGIC := '0';
-  
-  SIGNAL clk_644           : STD_LOGIC := '1';  -- 644.53125 MHz
-  SIGNAL clk_312           : STD_LOGIC := '1';  -- 312.5 MHz
-  SIGNAL clk_156           : STD_LOGIC := '1';  -- 156.25 MHz
-  SIGNAL rst_156           : STD_LOGIC;         -- reset synchronous with clk_156
+  SIGNAL tx_end_arr        : STD_LOGIC_VECTOR(g_nof_channels-1 DOWNTO 0);
+  SIGNAL rx_end            : STD_LOGIC;
   SIGNAL cal_clk           : STD_LOGIC := '1';  -- calibration clock
-  SIGNAL mm_clk            : STD_LOGIC := '1';  -- memory-mapped bus clock
+  SIGNAL mm_clk            : STD_LOGIC;         -- memory-mapped bus clock
   SIGNAL mm_rst            : STD_LOGIC;         -- reset synchronous with mm_clk
   SIGNAL dp_clk            : STD_LOGIC := '1';  -- data path clock
   SIGNAL dp_rst            : STD_LOGIC;         -- reset synchronous with dp_clk
+  
+  -- External reference clocks
+  SIGNAL tr_ref_clk_644    : STD_LOGIC := '1';  -- 10GBASE-R
+  SIGNAL tr_ref_clk_312    : STD_LOGIC;         -- 10GBASE-R
+  SIGNAL tr_ref_clk_156    : STD_LOGIC := '1';  -- 10GBASE-R or XAUI
+  SIGNAL tr_ref_rst_156    : STD_LOGIC;         -- 10GBASE-R or XAUI
     
   -- MAC 10G control interface
-  SIGNAL mm_init           : STD_LOGIC := '1';
-  SIGNAL mac_mosi_wrdata   : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- 32 bit;
+  SIGNAL mm_init           : STD_LOGIC;
+  SIGNAL mac_mosi_wrdata   : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for channel 0, 32 bit
   SIGNAL mac_mosi          : t_mem_mosi;
   SIGNAL mac_miso          : t_mem_miso;
-  SIGNAL mac_miso_rdval    : STD_LOGIC;
-  SIGNAL mac_miso_rddata   : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- 32 bit;
+  SIGNAL mac_miso_rdval    : STD_LOGIC;                              -- for channel 0
+  SIGNAL mac_miso_rddata   : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);  -- for channel 0, 32 bit
   
   -- MAC 10G transmit interface
   SIGNAL tx_en             : STD_LOGIC := '1';
-  SIGNAL tx_siso           : t_dp_siso;
-  SIGNAL tx_siso_arr       : t_dp_siso_arr(c_nof_channels-1 DOWNTO 0);
-  SIGNAL tx_sosi           : t_dp_sosi;
-  SIGNAL tx_sosi_arr       : t_dp_sosi_arr(c_nof_channels-1 DOWNTO 0);
-  SIGNAL tx_sosi_data      : STD_LOGIC_VECTOR(c_tech_mac_10g_data_w-1 DOWNTO 0);  -- 64 bit
+  SIGNAL tx_siso_arr       : t_dp_siso_arr(g_nof_channels-1 DOWNTO 0);
+  SIGNAL tx_sosi_arr       : t_dp_sosi_arr(g_nof_channels-1 DOWNTO 0);
+  SIGNAL tx_sosi_data      : STD_LOGIC_VECTOR(c_tech_mac_10g_data_w-1 DOWNTO 0);  -- for channel 0, 64 bit
   
   -- MAC 10G receive interface
-  SIGNAL rx_siso           : t_dp_siso;
-  SIGNAL rx_siso_arr       : t_dp_siso_arr(c_nof_channels-1 DOWNTO 0);
-  SIGNAL rx_sosi           : t_dp_sosi;
-  SIGNAL rx_sosi_reg       : t_dp_sosi;
-  SIGNAL rx_sosi_arr       : t_dp_sosi_arr(c_nof_channels-1 DOWNTO 0);
-  SIGNAL rx_sosi_data      : STD_LOGIC_VECTOR(c_tech_mac_10g_data_w-1 DOWNTO 0);  -- 64 bit
+  SIGNAL rx_siso_arr       : t_dp_siso_arr(g_nof_channels-1 DOWNTO 0);
+  SIGNAL rx_sosi_arr       : t_dp_sosi_arr(g_nof_channels-1 DOWNTO 0);
+  SIGNAL rx_sosi_data      : STD_LOGIC_VECTOR(c_tech_mac_10g_data_w-1 DOWNTO 0);  -- for channel 0, 64 bit
 
   -- PHY XAUI serial I/O
-  SIGNAL xaui_tx_arr       : t_xaui_arr(c_nof_channels-1 DOWNTO 0);
-  SIGNAL xaui_rx_arr       : t_xaui_arr(c_nof_channels-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0'));
+  SIGNAL xaui_tx_arr       : t_xaui_arr(g_nof_channels-1 DOWNTO 0);
+  SIGNAL xaui_rx_arr       : t_xaui_arr(g_nof_channels-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0'));
 
   -- PHY 10GBASE-R serial IO
-  SIGNAL serial_tx_arr     : STD_LOGIC_VECTOR(c_nof_channels-1 downto 0);
-  SIGNAL serial_rx_arr     : STD_LOGIC_VECTOR(c_nof_channels-1 downto 0) := (OTHERS=>'0');
+  SIGNAL serial_tx_arr     : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0);
+  SIGNAL serial_rx_arr     : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0) := (OTHERS=>'0');
 
+  -- Model a serial link fault
+  SIGNAL link_fault_arr    : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0);
+  
   -- Verification
-  SIGNAL expected_sosi_arr : t_dp_sosi_arr(0 TO c_nof_pkt-1);
-
-  SIGNAL tx_pkt_cnt        : NATURAL := 0;
-  SIGNAL rx_pkt_cnt        : NATURAL := 0;
-  SIGNAL rx_toggle         : STD_LOGIC := '0';  -- toggle after every received packet
+  SIGNAL tx_pkt_cnt_arr    : t_natural_arr(g_nof_channels-1 downto 0) := (OTHERS=>0);
+  SIGNAL rx_pkt_cnt_arr    : t_natural_arr(g_nof_channels-1 downto 0) := (OTHERS=>0);
+  SIGNAL rx_toggle_arr     : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0) := (OTHERS=>'0');  -- toggle after every received packet
   
 BEGIN
 
   cal_clk <= NOT cal_clk AFTER cal_clk_period/2;  -- Calibration clock
   
-  mm_clk  <= NOT mm_clk  AFTER mm_clk_period/2;   -- MM clock
   dp_clk  <= NOT dp_clk  AFTER dp_clk_period/2;   -- DP clock
-  clk_156 <= NOT clk_156 AFTER clk_156_period/2;
-  
-  mm_rst  <= '1', '0' AFTER mm_clk_period*10;
   dp_rst  <= '1', '0' AFTER dp_clk_period*10;
-  rst_156 <= '1', '0' AFTER clk_156_period*4;
 
-  -- debug signals to ease monitoring in wave window  
-  tx_sosi_data <= tx_sosi.data(c_tech_mac_10g_data_w-1 DOWNTO 0);
-  rx_sosi_data <= rx_sosi.data(c_tech_mac_10g_data_w-1 DOWNTO 0);
-  
+  -- debug signals to ease monitoring in wave window
   mac_mosi_wrdata <= mac_mosi.wrdata(c_word_w-1 DOWNTO 0);
   mac_miso_rddata <= mac_miso.rddata(c_word_w-1 DOWNTO 0);
   mac_miso_rdval <= '1' WHEN mac_mosi.rd='1' AND mac_miso.waitrequest='0' ELSE '0';  -- c_rd_latency = 1
-                   
+  
+  tx_sosi_data <= tx_sosi_arr(0).data(c_tech_mac_10g_data_w-1 DOWNTO 0);
+  rx_sosi_data <= rx_sosi_arr(0).data(c_tech_mac_10g_data_w-1 DOWNTO 0);
+  
   -- Use signal to leave unused fields 'X'
   total_header.eth <= c_eth_header_ethertype;
 
-  p_mm_setup : PROCESS
-  BEGIN
-    mm_init  <= '1';
-    mac_mosi.wr <= '0';
-    mac_mosi.rd <= '0';
-
-    -- wait until after reset release
-    proc_common_wait_until_low(mm_clk, mm_rst);
-    proc_common_wait_some_cycles(mm_clk, 10);
-
-    proc_tech_mac_10g_setup(g_technology,
-                            c_src_mac,
-                            mm_clk, mac_miso, mac_mosi);
-    mm_init <= '0';
-    WAIT;
-  END PROCESS;
-
-  
-  p_ff_transmitter : PROCESS
-  BEGIN
-    -- . Avalon ST
-    tx_sosi  <= c_dp_sosi_rst;
-
-    WHILE mm_init/='0' LOOP
-      WAIT UNTIL rising_edge(dp_clk);
-    END LOOP;
-    proc_common_wait_some_cycles(dp_clk, 10);
-
-    -- Loopback txp->rxp so use promiscuous mode or use DST_MAC = c_src_mac to send to itself
-    
-    -- TX frame:
-    -- . I=0 is empty payload, so only 4 words of the ETH header with 46 padding zeros, so empty = 2
-    -- . For I=1 to 46 the payload length remains 46 with padding zeros, so empty = 2
-    -- . For I>46 the payload length is I and empty = 4 - (I mod 4)
+  -- Generate reference clocks
+  gen_ref_clocks_xaui : IF g_technology=c_tech_stratixiv GENERATE
+    tr_ref_clk_644 <= 'X';
+    tr_ref_clk_312 <= 'X';
+    tr_ref_clk_156 <= NOT tr_ref_clk_156 AFTER g_ref_clk_156_period/2;
+    tr_ref_rst_156 <= '0' AFTER g_ref_clk_156_period*5;
+  END GENERATE;
     
-    FOR I IN 0 TO c_nof_pkt-1 LOOP
-      proc_tech_mac_10g_tx_packet(total_header, c_pkt_length_arr(I), g_data_type, c_rl, c_nof_tx_not_valid, dp_clk, tx_en, tx_siso, tx_sosi);
-      proc_common_wait_some_cycles(dp_clk, 0);
-    END LOOP;
-
-    proc_common_wait_some_cycles(dp_clk, c_pkt_length_arr(c_nof_pkt-1)/c_tech_mac_10g_symbols_per_beat);
-    proc_common_wait_some_cycles(dp_clk, 100);
-    rx_end <= '1';
-    WAIT;
-  END PROCESS;
-
+  gen_ref_clocks_10gbase_r : IF g_technology=c_tech_arria10 GENERATE
+    tr_ref_clk_644 <= NOT tr_ref_clk_644 AFTER g_ref_clk_644_period/2;
   
-  p_ff_receiver : PROCESS
-  BEGIN
-    -- . Avalon ST
-    rx_siso <= c_dp_siso_hold;
-
-    WHILE mm_init/='0' LOOP
-      WAIT UNTIL rising_edge(dp_clk);
-    END LOOP;
-
-    -- Receive forever
-    WHILE TRUE LOOP
-      proc_tech_mac_10g_rx_packet(total_header, g_data_type, dp_clk, rx_sosi, rx_siso);
-      rx_toggle <= NOT rx_toggle;
-    END LOOP;
-
-    WAIT;
-  END PROCESS;
+    pll : ENTITY tech_pll_lib.tech_pll_xgmii_mac_clocks
+    GENERIC MAP (
+      g_technology => g_technology
+    )
+    PORT MAP (
+      refclk_644 => tr_ref_clk_644,
+      clk_156    => tr_ref_clk_156,
+      clk_312    => tr_ref_clk_312,
+      rst_156    => tr_ref_rst_156,
+      rst_312    => OPEN
+    );
+  END GENERATE;
   
+  -- Setup all MACs in series
+  u_mm_setup : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_setup
+  GENERIC MAP (
+    g_technology    => g_technology,
+    g_nof_macs      => g_nof_channels,
+    g_src_mac       => c_src_mac
+  )
+  PORT MAP (
+    tb_end    => rx_end,
+    mm_clk    => mm_clk,
+    mm_rst    => mm_rst,
+    mm_init   => mm_init,
+    mac_mosi  => mac_mosi,
+    mac_miso  => mac_miso
+  );  
   
-  p_ff_store_tx_sosi_at_eop : PROCESS(dp_clk)
-    VARIABLE vI : NATURAL := 0;
-  BEGIN
-    IF rising_edge(dp_clk) THEN
-      IF tx_sosi.eop='1' THEN
-        expected_sosi_arr(vI) <= tx_sosi;
-        vI := vI +1;
-      END IF;
-    END IF;
-  END PROCESS;
-
-  p_ff_verify_rx_sosi_at_eop : PROCESS(dp_clk)
-    VARIABLE vI   : NATURAL := 0;
-    VARIABLE vLow : NATURAL := 0;
-  BEGIN
-    IF rising_edge(dp_clk) THEN
-      rx_sosi_reg <= rx_sosi;  -- use rx_sosi_reg for verification at eop to account for once cycle latency in expected_sosi_arr()
-      IF rx_sosi_reg.eop='1' THEN
-        IF g_no_dut=FALSE THEN
-          IF c_pkt_length_arr(vI) < 64 - 14 - 20 - 8 - 4 THEN  -- = minimum frame 64 - ETH 14 - IP 20 - UDP 8 - CRC 4
-            -- frame shorter than 64 get padded so empty after stripping the Rx CRC is fixed 4, which becomes 6 due to pre header padding for UDP word align
-            IF TO_UINT(rx_sosi_reg.empty) /= 6 THEN
-              REPORT "RX: Wrong padded empty" SEVERITY ERROR;
-            END IF;
-          END IF;
-        ELSE
-          IF rx_sosi_reg.empty /= expected_sosi_arr(vI).empty THEN
-            REPORT "RX: Wrong empty" SEVERITY ERROR;
-          ELSE
-            vLow := TO_UINT(rx_sosi_reg.empty)*8;
-            ASSERT rx_sosi_reg.data(63 DOWNTO vLow) = expected_sosi_arr(vI).data(63 DOWNTO vLow)  REPORT "RX: Wrong data at eop" SEVERITY ERROR;
-          END IF;
-        END IF;
-        vI := vI +1;
-      END IF;
-    END IF;
-  END PROCESS;
+  gen_transmitter : FOR I IN 0 TO g_nof_channels-1 GENERATE
+    -- Packet transmitter
+    u_transmitter : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_transmitter
+    GENERIC MAP (
+      g_data_type            => g_data_type,
+      g_pkt_length_arr1      => c_pkt_length_arr1,
+      g_pkt_length_arr2      => c_pkt_length_arr2,
+      g_verify_link_recovery => g_verify_link_recovery
+    )
+    PORT MAP (
+      mm_init        => mm_init,
+      total_header   => total_header,
+      tx_clk         => dp_clk,
+      tx_siso        => tx_siso_arr(I),
+      tx_sosi        => tx_sosi_arr(I),
+      link_fault     => link_fault_arr(I),
+      tx_end         => tx_end_arr(I)
+    );
+  END GENERATE;
 
   no_dut : IF g_no_dut=TRUE GENERATE
-    rx_sosi <= tx_sosi;
-    tx_siso <= rx_siso;
+    rx_sosi_arr <= tx_sosi_arr;
+    tx_siso_arr <= rx_siso_arr;
   END GENERATE;
 
   gen_dut : IF g_no_dut=FALSE GENERATE
-    tx_siso        <= tx_siso_arr(0);
-    tx_sosi_arr(0) <= tx_sosi;
-    
-    rx_siso_arr(0) <= rx_siso;
-    rx_sosi        <= rx_sosi_arr(0);
-    
     u_tr_10GbE : ENTITY work.tr_10GbE
     GENERIC MAP (
       g_technology             => g_technology,
       g_sim                    => c_sim,
       g_sim_level              => g_sim_level, -- 0 = use IP; 1 = use fast serdes model
-      g_nof_macs               => c_nof_channels,
+      g_nof_macs               => g_nof_channels,
       g_use_mdio               => TRUE,
       g_mdio_epcs_dis          => TRUE,  -- TRUE disables Enhanced PCS on init; e.g. to target a 10GbE card in PC that does not support it 
       g_pkt_len                => 100,
@@ -298,10 +244,10 @@ BEGIN
     )
     PORT MAP (
       -- Transceiver PLL reference clock
-      tr_ref_clk_644      => clk_644,   -- 644.531250 MHz for 10GBASE-R
-      tr_ref_clk_312      => clk_312,   -- 312.5      MHz for 10GBASE-R
-      tr_ref_clk_156      => clk_156,   -- 156.25     MHz for 10GBASE-R or for XAUI
-      tr_ref_rst_156      => rst_156,   --                for 10GBASE-R or for XAUI
+      tr_ref_clk_644      => tr_ref_clk_644,   -- 644.531250 MHz for 10GBASE-R
+      tr_ref_clk_312      => tr_ref_clk_312,   -- 312.5      MHz for 10GBASE-R
+      tr_ref_clk_156      => tr_ref_clk_156,   -- 156.25     MHz for 10GBASE-R or for XAUI
+      tr_ref_rst_156      => tr_ref_rst_156,   --                for 10GBASE-R or for XAUI
 
       -- Calibration & reconfig clock
       cal_rec_clk         => cal_clk,
@@ -344,29 +290,80 @@ BEGIN
       mdio_mdat_oen_arr   => OPEN
     );
   END GENERATE;
-
-  -- Loopback PHY
-  xaui_rx_arr   <= TRANSPORT xaui_tx_arr    AFTER phy_delay;  -- XAUI
-  serial_rx_arr <= TRANSPORT serial_tx_arr  AFTER phy_delay;  -- 10GBASE-R
-
-  -- Verification
-  tx_pkt_cnt <= tx_pkt_cnt + 1 WHEN tx_sosi.sop='1' AND rising_edge(dp_clk);
-  rx_pkt_cnt <= rx_pkt_cnt + 1 WHEN rx_sosi.eop='1' AND rising_edge(dp_clk);
+  
+  gen_link_connect : FOR I IN 0 TO g_nof_channels-1 GENERATE
+    u_link_connect : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_link_connect
+    GENERIC MAP (
+      g_loopback    => TRUE,
+      g_link_delay  => phy_delay
+    )
+    PORT MAP (
+      link_fault   => link_fault_arr(I), -- when '1' then forces rx_serial_arr(0)='0'
+      
+      -- 10GBASE-R serial layer connect
+      serial_tx    => serial_tx_arr(I),
+      serial_rx    => serial_rx_arr(I),  -- connects to delayed tx_serial when g_loopback=TRUE
+      
+      -- XAUI serial layer connect
+      xaui_tx      => xaui_tx_arr(I),
+      xaui_rx      => xaui_rx_arr(I)     -- connects to delayed xaui_tx when g_loopback=TRUE
+    );
+  END GENERATE;
+  
+  gen_receiver : FOR I IN 0 TO g_nof_channels-1 GENERATE
+    u_receiver : ENTITY tech_mac_10g_lib.tb_tech_mac_10_receiver
+    GENERIC MAP (
+      g_data_type  => g_data_type
+    )
+    PORT MAP (
+      mm_init        => mm_init,
+      total_header   => total_header,
+      rx_clk         => dp_clk,
+      rx_sosi        => rx_sosi_arr(I),
+      rx_siso        => rx_siso_arr(I),
+      rx_toggle      => rx_toggle_arr(I)
+    );
+  END GENERATE;
+  
+  gen_verify_rx_at_eop : FOR I IN 0 TO g_nof_channels-1 GENERATE
+    u_verify_rx_at_eop : ENTITY tech_mac_10g_lib.tb_tech_mac_10_verify_rx_at_eop
+    GENERIC MAP (
+      g_no_padding     => g_no_dut,
+      g_pkt_length_arr => c_pkt_length_arr
+    )
+    PORT MAP (
+      tx_clk      => dp_clk,
+      tx_sosi     => tx_sosi_arr(I),
+      rx_clk      => dp_clk,
+      rx_sosi     => rx_sosi_arr(I)
+    );  
+  END GENERATE;
+  
+  gen_verify_rx_pkt_cnt : FOR I IN 0 TO g_nof_channels-1 GENERATE
+    u_verify_rx_pkt_cnt : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_verify_rx_pkt_cnt
+    GENERIC MAP (
+      g_nof_pkt   => c_nof_pkt
+    )
+    PORT MAP (
+      tx_clk      => dp_clk,
+      tx_sosi     => tx_sosi_arr(I),
+      rx_clk      => dp_clk,
+      rx_sosi     => rx_sosi_arr(I),
+      tx_pkt_cnt  => tx_pkt_cnt_arr(I),
+      rx_pkt_cnt  => rx_pkt_cnt_arr(I),
+      rx_end      => rx_end
+    );
+  END GENERATE;
   
   p_tb_end : PROCESS  
   BEGIN
     tb_end <= '0';
-    WAIT UNTIL rx_end='1';
-    
-    -- Verify that all transmitted packets have been received
-    IF tx_pkt_cnt=0 THEN
-      REPORT "No packets were transmitted." SEVERITY ERROR;
-    ELSIF rx_pkt_cnt=0 THEN
-      REPORT "No packets were received." SEVERITY ERROR;
-    ELSIF tx_pkt_cnt/=rx_pkt_cnt THEN
-      REPORT "Not all transmitted packets were received." SEVERITY ERROR;
-    END IF;
-    proc_common_wait_some_cycles(clk_156, 100);
+    rx_end <= '0';
+    WAIT UNTIL andv(tx_end_arr)='1';
+    proc_common_wait_some_cycles(dp_clk, 1000);
+    rx_end <= '1';
+    proc_common_wait_some_cycles(dp_clk, 100);
+    --proc_common_wait_some_cycles(dp_clk, 10000);  -- uncomment to simulate somewhat longer without tx packet data
     
     -- Stop the simulation
     tb_end <= '1';
@@ -377,5 +374,5 @@ BEGIN
     END IF;
     WAIT;
   END PROCESS;
-  
+
 END tb;