diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/quartus/lofar2_unb2b_sdp_station.sdc b/applications/lofar2/designs/lofar2_unb2b_sdp_station/quartus/lofar2_unb2b_sdp_station.sdc
index ce015b6d6219689533c9506e2b06f5c25c83e9ef..24c9eaf9540dcc1128264503ae15fe2493d8a661 100644
--- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/quartus/lofar2_unb2b_sdp_station.sdc
+++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/quartus/lofar2_unb2b_sdp_station.sdc
@@ -97,8 +97,22 @@ set_clock_groups -asynchronous -group [get_clocks {*xcvr_native_a10_0|g_xcvr_nat
 #-group [get_clocks {inst2|xcvr_4ch_native_phy_inst|xcvr_native_a10_0|g_xcvr_native_insts[?]|rx_pma_clk}] \
 #-group [get_clocks {inst2|xcvr_pll_inst|xcvr_fpll_a10_0|tx_bonding_clocks[0]}]
 
+# JESD
+
+# Increase clock uncertainty to force link_clk to have Fmax > 234MHz
+set_clock_uncertainty -rise_from [get_clocks {*|iopll_0|link_clk}] -rise_to [get_clocks {*|iopll_0|link_clk}]  5.727  
+set_clock_uncertainty -rise_from [get_clocks {*|iopll_0|link_clk}] -fall_to [get_clocks {*|iopll_0|link_clk}]  5.727  
+set_clock_uncertainty -fall_from [get_clocks {*|iopll_0|link_clk}] -rise_to [get_clocks {*|iopll_0|link_clk}]  5.727  
+set_clock_uncertainty -fall_from [get_clocks {*|iopll_0|link_clk}] -fall_to [get_clocks {*|iopll_0|link_clk}]  5.727 
+
+# Increase clock uncertainty to force frame_clk to have Fmax > 222MHz
+set_clock_uncertainty -rise_from [get_clocks {*|iopll_0|frame_clk}] -rise_to [get_clocks {*|iopll_0|frame_clk}]  0.496  
+set_clock_uncertainty -rise_from [get_clocks {*|iopll_0|frame_clk}] -fall_to [get_clocks {*|iopll_0|frame_clk}]  0.496  
+set_clock_uncertainty -fall_from [get_clocks {*|iopll_0|frame_clk}] -rise_to [get_clocks {*|iopll_0|frame_clk}]  0.496  
+set_clock_uncertainty -fall_from [get_clocks {*|iopll_0|frame_clk}] -fall_to [get_clocks {*|iopll_0|frame_clk}]  0.496 
+
 # false paths added for the jesd interface as these clocks are independent.
-set_false_path -from [get_clocks {*xcvr_fpll_a10_0|outclk2}] -to [get_clocks {*iopll_0|link_clk}]
-set_false_path -from [get_clocks {*iopll_0|link_clk}] -to [get_clocks {*xcvr_fpll_a10_0|outclk2}]
-set_false_path -from [get_clocks {*xcvr_fpll_a10_0|outclk2}] -to [get_clocks {*iopll_0|frame_clk}]
-set_false_path -from [get_clocks {*iopll_0|frame_clk}] -to [get_clocks {*xcvr_fpll_a10_0|outclk2}]
+#set_false_path -from [get_clocks {*xcvr_fpll_a10_0|outclk2}] -to [get_clocks {*iopll_0|link_clk}]
+#set_false_path -from [get_clocks {*iopll_0|link_clk}] -to [get_clocks {*xcvr_fpll_a10_0|outclk2}]
+#set_false_path -from [get_clocks {*xcvr_fpll_a10_0|outclk2}] -to [get_clocks {*iopll_0|frame_clk}]
+#set_false_path -from [get_clocks {*iopll_0|frame_clk}] -to [get_clocks {*xcvr_fpll_a10_0|outclk2}]
diff --git a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd
index d77c55d4e5833d2bb638e62cc1da3c5ee73f34cc..ef826f539e50d7f7c2ae6b706e98751697e9bb72 100644
--- a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd
+++ b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_adc_input_and_timing.vhd
@@ -103,8 +103,9 @@ ENTITY node_sdp_adc_input_and_timing IS
 
     -- Streaming data output
     out_sosi_arr                   : OUT t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0);        
-    dp_bsn_source_restart          : OUT STD_LOGIC;
-    dp_bsn_source_new_interval     : OUT STD_LOGIC
+    dp_bsn_source_restart          : OUT STD_LOGIC;  -- for dp_sync_recover in WPFB
+    dp_bsn_source_new_interval     : OUT STD_LOGIC;  -- for SST and BST statistics offload, XST uses new_interval based on xst_processing_enable
+    dp_bsn_source_nof_clk_per_sync : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0)  -- for RSN source in transient buffer
   );
 END node_sdp_adc_input_and_timing;
 
@@ -131,6 +132,7 @@ ARCHITECTURE str OF node_sdp_adc_input_and_timing IS
 
   SIGNAL rx_bsn_source_restart      : STD_LOGIC;
   SIGNAL rx_bsn_source_new_interval : STD_LOGIC;
+  SIGNAL rx_bsn_source_nof_clk_per_sync : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
   SIGNAL rx_aux                     : STD_LOGIC_VECTOR(c_bs_aux_w-1 DOWNTO 0);
   SIGNAL dp_aux                     : STD_LOGIC_VECTOR(c_bs_aux_w-1 DOWNTO 0);
 
@@ -288,7 +290,8 @@ BEGIN
     bs_sosi           => bs_sosi,
 
     bs_restart        => rx_bsn_source_restart,
-    bs_new_interval   => rx_bsn_source_new_interval
+    bs_new_interval   => rx_bsn_source_new_interval,
+    bs_nof_clk_per_sync => rx_bsn_source_nof_clk_per_sync
   );
 
   u_bsn_trigger_wg : ENTITY dp_lib.mms_dp_bsn_scheduler
@@ -533,7 +536,20 @@ BEGIN
       out_aux          => dp_aux
     );
 
-  
+  -- MM write of rx_bsn_source_nof_clk_per_sync occurs with sufficient margin before it
+  -- is used. Still use common_reg_cross_domain nonetheless to get from mm_clk to rx_clk
+  -- in mms_dp_bsn_monitor, and from rx_clk to dp_clk here. No need to go via
+  -- u_dp_fifo_dc_arr, use common_reg_cross_domain instead to save logic and/or RAM.
+  u_dp_nof_block_per_sync : ENTITY common_lib.common_reg_cross_domain
+  PORT MAP (
+    in_rst      => rx_rst,
+    in_clk      => rx_clk,
+    in_dat      => rx_bsn_source_nof_clk_per_sync,
+    out_rst     => dp_rst,
+    out_clk     => dp_clk,
+    out_dat     => dp_bsn_source_nof_clk_per_sync
+  );
+
   -----------------------------------------------------------------------------
   -- JESD Control register
   -----------------------------------------------------------------------------
diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr/hdllib.cfg b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr/hdllib.cfg
index 6d3ea7c1f0f1889b8077bc97282c8c11b39ba696..dda0a9ead95bff45db33748437e74fdf1b39838e 100644
--- a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr/hdllib.cfg
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr/hdllib.cfg
@@ -22,6 +22,11 @@ regression_test_vhdl =
 modelsim_copy_files =
     ../../src/hex hex
 
+modelsim_compile_ip_files =
+    $HDL_WORK/libraries/technology/ip_arria10/ddr4_4g_1600/copy_hex_files.tcl               # 4GB DDR4 model
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_8g_1600/copy_hex_files.tcl          # Unb2c 8GB DDR4 driver
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_64b/copy_hex_files.tcl   # Unb2c 16GB-64b DDR4 driver
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_72b/copy_hex_files.tcl   # Unb2c 16GB-72b DDR4 driver
 
 [quartus_project_file]
 synth_top_level_entity =
diff --git a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr_16G/hdllib.cfg b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr_16G/hdllib.cfg
index bb3b67dbb7cd5b3179f39144691daef93b1146c4..330391473a3e3e2185c98cee211d0ff55b95b378 100644
--- a/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr_16G/hdllib.cfg
+++ b/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr_16G/hdllib.cfg
@@ -23,6 +23,11 @@ regression_test_vhdl =
 modelsim_copy_files =
     ../../src/hex hex
 
+modelsim_compile_ip_files =
+    $HDL_WORK/libraries/technology/ip_arria10/ddr4_4g_1600/copy_hex_files.tcl               # 4GB DDR4 model
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_8g_1600/copy_hex_files.tcl          # Unb2c 8GB DDR4 driver
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_64b/copy_hex_files.tcl   # Unb2c 16GB-64b DDR4 driver
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_72b/copy_hex_files.tcl   # Unb2c 16GB-72b DDR4 driver
 
 [quartus_project_file]
 synth_top_level_entity =
diff --git a/libraries/base/axi4/hdllib.cfg b/libraries/base/axi4/hdllib.cfg
index 3174cab5d7bd9c355e69cd1a246fa88ecbae21e9..6cef475d8b0fc8d940f32a9f4b87ab1f4216cacc 100644
--- a/libraries/base/axi4/hdllib.cfg
+++ b/libraries/base/axi4/hdllib.cfg
@@ -5,8 +5,10 @@ hdl_lib_uses_sim =
 hdl_lib_technology =
 
 synth_files =
+    src/vhdl/axi4_lite_pkg.vhd
     src/vhdl/axi4_stream_pkg.vhd
     src/vhdl/axi4_stream_dp_bridge.vhd
+    src/vhdl/axi4_lite_mm_bridge.vhd
 
 test_bench_files =
     tb/vhdl/tb_axi4_stream_dp_bridge.vhd
diff --git a/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd b/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..a763e876a9dc8e719d8f7d4f88e3c5cb71c57c67
--- /dev/null
+++ b/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd
@@ -0,0 +1,219 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+-- --------------------------------------------------------------------------
+
+-- Author:
+-- . Reinier van der Walle
+-- Purpose:
+-- . Bridge between AXI4 lite and MM interfaces. 
+-- Description:
+-- . This core consists of:
+--   . Combinatorial translation of one interface to the other.
+--   . Ready latency adapters as AXI4-Lite has RL = 0 and MM has RL = 1. 
+-- . Details:
+--   . g_active_low_rst should be set to TRUE when in_rst is active low. This is useful as an
+--     AXI4 interface often comes with an active-low reset while DP comes with an active-high 
+--     reset.
+
+LIBRARY IEEE, common_lib, dp_lib, technology_lib, mm_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE work.axi4_stream_pkg.ALL;
+USE work.axi4_lite_pkg.ALL;
+
+ENTITY axi4_lite_mm_bridge IS
+  GENERIC (
+    g_active_low_rst : BOOLEAN := FALSE -- When True, in_rst is interpreted as active-low.
+  );
+  PORT (
+    in_clk  : IN STD_LOGIC := '0';
+    in_rst  : IN STD_LOGIC := is_true(g_active_low_rst); -- Default state is "not in reset".
+
+    aresetn : OUT STD_LOGIC := '1'; -- AXI4 active-low reset
+    mm_rst  : OUT STD_LOGIC := '0'; -- MM active-high reset
+
+    -- Translate AXI4 lite to MM
+    axi4_in_copi  : IN  t_axi4_lite_copi := c_axi4_lite_copi_rst;
+    axi4_in_cipo  : OUT t_axi4_lite_cipo := c_axi4_lite_cipo_rst;
+
+    mm_out_copi   : OUT t_mem_copi       := c_mem_copi_rst;
+    mm_out_cipo   : IN  t_mem_cipo       := c_mem_cipo_rst;
+
+    -- Translate MM to AXI4 lite
+    mm_in_copi    : IN  t_mem_copi       := c_mem_copi_rst;
+    mm_in_cipo    : OUT t_mem_cipo       := c_mem_cipo_rst;
+
+    axi4_out_copi : OUT t_axi4_lite_copi := c_axi4_lite_copi_rst;
+    axi4_out_cipo : IN  t_axi4_lite_cipo := c_axi4_lite_cipo_rst
+  );
+END axi4_lite_mm_bridge;
+
+ARCHITECTURE str OF axi4_lite_mm_bridge IS
+-- Sum of all t_mem_copi fields widths (synthesis will optimize away unused address and data bits)
+  CONSTANT c_data_w  : NATURAL := c_mem_address_w +  c_mem_data_w + 2;  -- 32 + 72 + 1 (wr) + 1 (rd) = 106
+
+  SIGNAL i_rst : STD_LOGIC := '0'; 
+
+  SIGNAL axi4_from_mm_copi : t_mem_copi;
+  SIGNAL axi4_from_mm_cipo : t_mem_cipo;
+  SIGNAL mm_from_axi4_copi : t_mem_copi;
+  SIGNAL mm_from_axi4_cipo : t_mem_cipo;
+
+  SIGNAL rl_decr_snk_ready : STD_LOGIC := '0';
+  SIGNAL rl_decr_snk_dat   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+  SIGNAL rl_decr_snk_val   : STD_LOGIC := '0'; 
+  SIGNAL rl_decr_src_ready : STD_LOGIC := '0';
+  SIGNAL rl_decr_src_dat   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); 
+
+  SIGNAL rl_incr_snk_ready : STD_LOGIC := '0';
+  SIGNAL rl_incr_snk_dat   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0); 
+  SIGNAL rl_incr_snk_val   : STD_LOGIC := '0';
+  SIGNAL rl_incr_src_ready : STD_LOGIC := '0';
+  SIGNAL rl_incr_src_dat   : STD_LOGIC_VECTOR(c_data_w-1 DOWNTO 0);
+
+  SIGNAL d_bvalid : STD_LOGIC := '0';
+  SIGNAL q_bvalid : STD_LOGIC := '0';
+
+BEGIN
+  i_rst   <= NOT in_rst WHEN g_active_low_rst ELSE in_rst;
+  aresetn <= NOT i_rst;
+  mm_rst  <= i_rst;
+
+  -----------------------------------------------
+  -- Translate MM to AXI4 Lite and RL 1 to RL 0
+  -----------------------------------------------
+  -- Decrease ready latency
+  rl_decr_snk_dat <= func_slv_concat(mm_in_copi.address, mm_in_copi.wrdata, slv(mm_in_copi.wr), slv(mm_in_copi.rd));
+  rl_decr_snk_val <= mm_in_copi.wr OR mm_in_copi.rd;
+
+  u_common_rl_decrease : ENTITY common_lib.common_rl_decrease
+  GENERIC MAP (
+    g_dat_w => c_axi4_lite_data_w
+  )
+  PORT MAP (
+    rst           => i_rst, 
+    clk           => in_clk, 
+    -- Sink RL = 1
+    snk_out_ready => rl_decr_snk_ready, 
+    snk_in_dat    => rl_decr_snk_dat, 
+    snk_in_val    => rl_decr_snk_val, 
+    -- Source RL = 0
+    src_in_ready  => rl_decr_src_ready,
+    src_out_dat   => rl_decr_src_dat, 
+    src_out_val   => OPEN
+  ); 
+    
+  -- Account for opposite meaning of waitrequest and ready
+  mm_in_cipo.waitrequest <= NOT rl_decr_snk_ready;
+  rl_decr_src_ready      <= NOT axi4_from_mm_cipo.waitrequest;
+
+  -- Wire remaining copi/cipo signals
+  mm_from_axi4_cipo.rddata  <= mm_out_cipo.rddata;
+  mm_from_axi4_cipo.rdval   <= mm_out_cipo.rdval;
+  axi4_from_mm_copi.address <=    func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_decr_src_dat, 0);
+  axi4_from_mm_copi.wrdata  <=    func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_decr_src_dat, 1);
+  axi4_from_mm_copi.wr      <= sl(func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_decr_src_dat, 2));
+  axi4_from_mm_copi.rd      <= sl(func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_decr_src_dat, 3));
+  
+  -- MM to AXI4 Lite
+  axi4_out_copi.awaddr  <= axi4_from_mm_copi.address;  
+  axi4_out_copi.awprot  <= (OTHERS => '0');  
+  axi4_out_copi.awvalid <= axi4_from_mm_copi.wr;  
+  axi4_out_copi.wdata   <= axi4_from_mm_copi.wrdata(c_axi4_lite_data_w-1 DOWNTO 0);  
+  axi4_out_copi.wstrb   <= (OTHERS => '1'); -- Either ignored or all bytes selected.  
+  axi4_out_copi.wvalid  <= axi4_from_mm_copi.wr;  
+  axi4_out_copi.bready  <= '1'; -- Unsupported by MM, assuming always ready.  
+  axi4_out_copi.araddr  <= axi4_from_mm_copi.address;  
+  axi4_out_copi.arprot  <= (OTHERS => '0');  
+  axi4_out_copi.arvalid <= axi4_from_mm_copi.rd;  
+  axi4_out_copi.rready  <= '1'; -- Unsupported by MM, assuming always ready.  
+
+  axi4_from_mm_cipo.rddata(c_axi4_lite_data_w-1 DOWNTO 0) <= axi4_out_cipo.rdata;
+  axi4_from_mm_cipo.rdval                                 <= axi4_out_cipo.rvalid;
+  axi4_from_mm_cipo.waitrequest                           <= NOT (axi4_out_cipo.awready AND axi4_out_cipo.wready AND axi4_out_cipo.arready); 
+
+  -------------------------------------------
+  -- Translate AXI4 to MM and RL 0 to RL 1
+  -------------------------------------------
+  -- AXI4 Lite to MM
+  mm_from_axi4_copi.address                               <= axi4_in_copi.awaddr WHEN axi4_in_copi.awvalid = '1' ELSE axi4_in_copi.araddr;
+  mm_from_axi4_copi.wrdata(c_axi4_lite_data_w-1 DOWNTO 0) <= axi4_in_copi.wdata;
+  mm_from_axi4_copi.wr                                    <= axi4_in_copi.awvalid;
+  mm_from_axi4_copi.rd                                    <= axi4_in_copi.arvalid;
+
+  axi4_in_cipo.awready <= NOT mm_from_axi4_cipo.waitrequest;
+  axi4_in_cipo.wready  <= NOT mm_from_axi4_cipo.waitrequest;
+  axi4_in_cipo.bresp   <= c_axi4_lite_resp_okay;
+  axi4_in_cipo.bvalid  <= q_bvalid;
+  axi4_in_cipo.arready <= NOT mm_from_axi4_cipo.waitrequest;
+  axi4_in_cipo.rdata   <= mm_from_axi4_cipo.rddata(c_axi4_lite_data_w-1 DOWNTO 0);
+  axi4_in_cipo.rresp   <= c_axi4_lite_resp_okay;
+  axi4_in_cipo.rvalid  <= mm_from_axi4_cipo.rdval;
+
+  -- Generate bvalid
+  q_bvalid <= d_bvalid WHEN rising_edge(in_clk); 
+
+  p_bvalid : PROCESS(i_rst, q_bvalid, mm_from_axi4_cipo, mm_from_axi4_copi, axi4_in_copi)
+  BEGIN
+    d_bvalid <= q_bvalid;
+    IF mm_from_axi4_cipo.waitrequest = '0' AND mm_from_axi4_copi.wr = '1' THEN
+      d_bvalid <= '1';
+    ELSIF axi4_in_copi.bready = '1' THEN
+      d_bvalid <= '0';
+    END IF;
+    IF i_rst = '1' THEN
+     d_bvalid <= '0';
+    END IF;
+  END PROCESS;
+      
+  -- Increase ready latency
+  rl_incr_snk_dat <= func_slv_concat(mm_from_axi4_copi.address, mm_from_axi4_copi.wrdata, slv(mm_from_axi4_copi.wr), slv(mm_from_axi4_copi.rd));
+  rl_incr_snk_val <= mm_from_axi4_copi.wr OR mm_from_axi4_copi.rd;
+
+  u_common_rl_increase : ENTITY common_lib.common_rl_increase
+  GENERIC MAP (
+    g_dat_w => c_axi4_lite_data_w
+  )
+  PORT MAP (
+    rst           => i_rst, 
+    clk           => in_clk, 
+    -- Sink RL = 0
+    snk_out_ready => rl_incr_snk_ready, 
+    snk_in_dat    => rl_incr_snk_dat, 
+    snk_in_val    => rl_incr_snk_val, 
+    -- Source RL = 1
+    src_in_ready  => rl_incr_src_ready,
+    src_out_dat   => rl_incr_src_dat, 
+    src_out_val   => OPEN
+  ); 
+    
+  -- Account for opposite meaning of waitrequest and ready
+  mm_from_axi4_cipo.waitrequest <= NOT rl_incr_snk_ready;
+  rl_incr_src_ready             <= NOT mm_out_cipo.waitrequest;
+
+  -- Wire remaining copi/cipo signals
+  mm_from_axi4_cipo.rddata <= mm_out_cipo.rddata;
+  mm_from_axi4_cipo.rdval  <= mm_out_cipo.rdval;
+  mm_out_copi.address      <=    func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_incr_src_dat, 0);
+  mm_out_copi.wrdata       <=    func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_incr_src_dat, 1);
+  mm_out_copi.wr           <= sl(func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_incr_src_dat, 2));
+  mm_out_copi.rd           <= sl(func_slv_extract(c_mem_address_w, c_mem_data_w, 1, 1, rl_incr_src_dat, 3));
+    
+END str;
+
diff --git a/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..497c8c9068888f0d5b0d0087b27462af8ff6bb76
--- /dev/null
+++ b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd
@@ -0,0 +1,100 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Author : R vd Walle
+-- Purpose:  
+--   Package containing usefull definitions for working with AXI4-Lite
+-- Description:
+--   Ported from:
+--   https://git.astron.nl/desp/gemini/-/blob/master/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE std.textio.ALL;
+USE IEEE.STD_LOGIC_TEXTIO.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+
+PACKAGE axi4_lite_pkg IS
+
+  ------------------------------------------------------------------------------
+  -- Simple AXI4 lite memory access (for MM control interface)
+  ------------------------------------------------------------------------------
+  CONSTANT c_axi4_lite_address_w  : NATURAL := 32;
+  CONSTANT c_axi4_lite_data_w     : NATURAL := 32;
+  CONSTANT c_axi4_lite_prot_w     : NATURAL := 3;
+  CONSTANT c_axi4_lite_resp_w     : NATURAL := 2;
+
+
+  TYPE t_axi4_lite_copi IS RECORD  -- Controller Out Peripheral In
+    -- write address channel
+    awaddr  : std_logic_vector(c_axi4_lite_address_w-1 downto 0);         -- write address
+    awprot  : std_logic_vector(c_axi4_lite_prot_w-1 downto 0);            -- access permission for write
+    awvalid : std_logic;                                                  -- write address valid
+    -- write data channel
+    wdata   : std_logic_vector(c_axi4_lite_data_w-1 downto 0);            -- write data
+    wstrb   : std_logic_vector((c_axi4_lite_data_w/c_byte_w)-1 downto 0); -- write strobes
+    wvalid  : std_logic;                                                  -- write valid
+    -- write response channel
+    bready  : std_logic;                                                  -- response ready
+    -- read address channel
+    araddr  : std_logic_vector(c_axi4_lite_address_w-1 downto 0);         -- read address
+    arprot  : std_logic_vector(c_axi4_lite_prot_w-1 downto 0);            -- access permission for read
+    arvalid : std_logic;                                                  -- read address valid
+    -- read data channel
+    rready  : std_logic;                                                  -- read ready
+  END RECORD;
+
+  TYPE t_axi4_lite_cipo IS RECORD  -- Controller In Peripheral Out
+    -- write_address channel
+    awready : std_logic;                                       -- write address ready
+    -- write data channel
+    wready  : std_logic;                                       -- write ready
+    -- write response channel
+    bresp   : std_logic_vector(c_axi4_lite_resp_w-1 downto 0); -- write response
+    bvalid  : std_logic;                                       -- write response valid
+    -- read address channel
+    arready : std_logic;                                       -- read address ready
+    -- read data channel
+    rdata   : std_logic_vector(c_axi4_lite_data_w-1 downto 0); -- read data
+    rresp   : std_logic_vector(c_axi4_lite_resp_w-1 downto 0); -- read response
+    rvalid  : std_logic;                                       -- read valid
+  END RECORD;
+
+  CONSTANT c_axi4_lite_copi_rst : t_axi4_lite_copi := ((OTHERS=>'0'), (OTHERS=>'0'), '0', (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), '0', '0');
+  CONSTANT c_axi4_lite_cipo_rst : t_axi4_lite_cipo := ('0', '0', (OTHERS=>'0'), '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), '0');
+
+  -- Multi port array for MM records
+  TYPE t_axi4_lite_cipo_arr IS ARRAY (INTEGER RANGE <>) OF t_axi4_lite_cipo;
+  TYPE t_axi4_lite_copi_arr IS ARRAY (INTEGER RANGE <>) OF t_axi4_lite_copi;
+
+  CONSTANT c_axi4_lite_resp_okay   : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "00"; -- normal access success
+  CONSTANT c_axi4_lite_resp_exokay : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "01"; -- exclusive access okay
+  CONSTANT c_axi4_lite_resp_slverr : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "10"; -- peripheral error
+  CONSTANT c_axi4_lite_resp_decerr : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "11"; -- decode error
+
+END axi4_lite_pkg;
+
+PACKAGE BODY axi4_lite_pkg IS
+
+END axi4_lite_pkg;
diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index bd4c0133127b98c19574b96070c567267ca10a0f..48865ad1dbd81ac2513b08448297ce8eb0e75d85 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -90,6 +90,7 @@ synth_files =
     src/vhdl/dp_bsn_monitor_v2.vhd
     src/vhdl/dp_bsn_monitor_reg_v2.vhd
     src/vhdl/mms_dp_bsn_monitor_v2.vhd
+    src/vhdl/dp_rsn_source.vhd
     src/vhdl/dp_bsn_source.vhd
     src/vhdl/dp_bsn_source_v2.vhd
     src/vhdl/dp_bsn_source_reg.vhd
@@ -220,6 +221,7 @@ test_bench_files =
     tb/vhdl/tb_mmp_dp_bsn_align_v2.vhd
     tb/vhdl/tb_dp_bsn_monitor.vhd
     tb/vhdl/tb_dp_bsn_monitor_v2.vhd
+    tb/vhdl/tb_dp_rsn_source.vhd
     tb/vhdl/tb_dp_bsn_source.vhd
     tb/vhdl/tb_dp_bsn_source_v2.vhd
     tb/vhdl/tb_mms_dp_bsn_source.vhd
@@ -306,6 +308,7 @@ test_bench_files =
     tb/vhdl/tb_tb_dp_bsn_align.vhd
     tb/vhdl/tb_tb_dp_bsn_align_v2.vhd
     tb/vhdl/tb_tb_mmp_dp_bsn_align_v2.vhd
+    tb/vhdl/tb_tb_dp_rsn_source.vhd
     tb/vhdl/tb_tb_dp_bsn_source_v2.vhd
     tb/vhdl/tb_tb_dp_bsn_sync_scheduler.vhd
     tb/vhdl/tb_tb_dp_concat.vhd
@@ -380,6 +383,7 @@ regression_test_vhdl =
     tb/vhdl/tb_tb_dp_block_validate_channel.vhd
     tb/vhdl/tb_tb_dp_bsn_align_v2.vhd
     tb/vhdl/tb_tb_mmp_dp_bsn_align_v2.vhd
+    tb/vhdl/tb_tb_dp_rsn_source.vhd
     tb/vhdl/tb_tb_dp_bsn_source_v2.vhd
     tb/vhdl/tb_tb_dp_bsn_sync_scheduler.vhd
     tb/vhdl/tb_tb_dp_concat.vhd
diff --git a/libraries/base/dp/src/vhdl/dp_rsn_source.vhd b/libraries/base/dp/src/vhdl/dp_rsn_source.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..db0835da04948d894bc2a559f62dc57f77d033d4
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_rsn_source.vhd
@@ -0,0 +1,252 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Author: E. Kooistra
+-- Purpose:
+--   Derive a new block and sync interval from an input bs_sosi stream, and
+--   use the Raw sample Sequence Number (RSN) as rs_sosi.bsn according to the
+--   PPS and RSN grid defined in [1].
+-- Description:
+--   The BSN in the input bs_sosi counts blocks of g_bs_block_size samples
+--   since t_epoch = 1 Jan 1970 [1]. The RSN can start at any BSN, using
+--   RSN = BSN * g_bs_block_size as initial value. The block size
+--   g_rs_block_size of the RSN is free to choose and will typically differ
+--   from the BSN block size g_bs_block_size. Therefore counting back to
+--   t_epoch the very first RSN block in the output rs_sosi will typically
+--   not start at t_epoch. The RSN will start at 0 at t_epoch, because it
+--   counts samples. Therefore choose to let the bsn field in the rs_sosi
+--   record carry the RSN of the first sample in the block, instead of
+--   counting blocks. The RSN thus increments by g_rs_block_size (instead of
+--   by 1) for every block.
+-- Features:
+-- . The rs_sosi timing is derived from the input bs_sosi, but the rs_sosi
+--   uses RSN as rs_sosi.bsn and has its own block and sync intervals.
+-- . Assumption is that every clk cycle carries valid data when the
+--   bs_sosi.valid is '1', so no gaps in bs_sosi.valid.
+-- . The bs_sosi can stop and restart. It (re)starts with bs_sosi.sync and
+--   bs_sosi.sop when bs_sosi.valid becomes '1' and it stops when
+--   bs_sosi.valid becomes '0' immediately after a bs_sosi.eop.
+-- . The rs_sosi block size is g_rs_block_size.
+-- . The rs_sosi sync interval has g_nof_clk_per_sync. If g_nof_clk_per_sync
+--   is not a multiple of g_rs_block_size, then the rs_sosi.sync will occur at
+--   the next start of block.
+-- . The initial RSN in rs_sosi.bsn is bs_sosi.bsn * g_bs_block_size, where
+--   g_bs_block_size is the input block size of bs_sosi.
+-- . The rs_sosi starts when the bs_sosi starts, so when bs_sosi.sync = '1'
+--   and bs_sosi.valid becomes '1'.
+-- . The rs_sosi ends after the rs_sosi.eop, when the bs_sosi ends. There
+--   may be undefined filler data in the last rs_sosi block to finish it
+--   after the rs_sosi.eop.
+-- Remark:
+-- . The bs_sosi typically comes from dp_bsn_source_v2.vhd
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/display/L2M/L2+STAT+Decision%3A+Timing+in+Station
+
+LIBRARY IEEE, common_lib;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE common_lib.common_pkg.ALL;
+USE work.dp_stream_pkg.ALL;
+
+ENTITY dp_rsn_source IS
+  GENERIC (
+    g_bs_block_size     : NATURAL := 256;  -- input bs_sosi block size, >= 3, see state machine
+    g_rs_block_size     : NATURAL := 256;  -- output rs_sosi block size, >= 3, see state machine
+    g_nof_clk_per_sync  : NATURAL := 200 * 10**6;
+    g_bsn_w             : NATURAL := 64
+  );
+  PORT (
+    rst                 : IN  STD_LOGIC;
+    clk                 : IN  STD_LOGIC;
+
+    -- Input stream sosi control using BSN
+    bs_sosi             : IN  t_dp_sosi;  -- input reference stream using BSN
+
+    -- Output stream sosi control using RSN
+    nof_clk_per_sync    : IN  STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := TO_UVEC(g_nof_clk_per_sync, c_word_w);
+    rs_sosi             : OUT t_dp_sosi;  -- output stream using RSN and g_rs_block_size, g_nof_clk_per_sync
+    rs_restart          : OUT STD_LOGIC;  -- = rs_sosi.sync for first sync after bs_sosi.valid went high
+    rs_new_interval     : OUT STD_LOGIC   -- = active during first rs_sosi.sync interval
+  );
+END dp_rsn_source;
+
+
+ARCHITECTURE rtl OF dp_rsn_source IS
+
+  CONSTANT c_bs_block_size_cnt_w : NATURAL := ceil_log2(g_bs_block_size) + 1;  -- +1 because value 2**n requires n + 1 bits
+  CONSTANT c_rs_block_size_cnt_w : NATURAL := ceil_log2(g_rs_block_size) + 1;  -- +1 because value 2**n requires n + 1 bits
+  CONSTANT c_rsn_product_w       : NATURAL := g_bsn_w + c_bs_block_size_cnt_w;
+
+  TYPE t_state_enum IS (s_off, s_on_sop, s_on, s_on_eop);
+
+  SIGNAL state       : t_state_enum;
+  SIGNAL nxt_state   : t_state_enum; 
+  SIGNAL prev_state  : t_state_enum;
+
+  SIGNAL rsn                 : STD_LOGIC_VECTOR(c_rsn_product_w-1 DOWNTO 0);
+
+  SIGNAL nxt_sync            : STD_LOGIC;
+  SIGNAL sync                : STD_LOGIC;
+  SIGNAL sync_size_cnt       : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+  SIGNAL nxt_sync_size_cnt   : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
+
+  SIGNAL rs_block_size_cnt      : STD_LOGIC_VECTOR(c_rs_block_size_cnt_w-1 DOWNTO 0);
+  SIGNAL nxt_rs_block_size_cnt  : STD_LOGIC_VECTOR(c_rs_block_size_cnt_w-1 DOWNTO 0);
+  
+  SIGNAL i_rs_sosi           : t_dp_sosi := c_dp_sosi_init;
+  SIGNAL nxt_rs_sosi         : t_dp_sosi;
+ 
+  SIGNAL i_rs_restart        : STD_LOGIC;
+  SIGNAL nxt_rs_restart      : STD_LOGIC;
+  SIGNAL i_rs_new_interval   : STD_LOGIC;
+  SIGNAL reg_rs_new_interval : STD_LOGIC;
+
+BEGIN
+
+  rs_sosi <= i_rs_sosi;
+  rs_restart <= i_rs_restart;
+  rs_new_interval <= i_rs_new_interval;
+
+  rsn <= MULT_UVEC(bs_sosi.bsn(g_bsn_w-1 DOWNTO 0), TO_UVEC(g_bs_block_size, c_bs_block_size_cnt_w));
+
+  p_state : PROCESS(bs_sosi, nxt_sync, sync, sync_size_cnt, nof_clk_per_sync,
+                    state, prev_state,
+                    i_rs_sosi, rs_block_size_cnt, rsn)
+  BEGIN  
+    -- Maintain sync_size_cnt for nof_clk_per_sync
+    -- . nof_clk_per_sync is the number of clk per sync interval and the
+    --   average number of clk per rs_sosi.sync interval, due to that the
+    --   rs_sosi.sync has to occur at the rs_sosi.sop of a block.
+    -- . The sync_size_cnt is started in s_off at the bs_sosi.sync.
+    -- . The sync interval is nof_clk_per_sync, so when the sync_size_cnt
+    --   wraps, then the sync is used to ensure that rs_sosi.sync will
+    --   pulse at the rs_sosi.sop of the next block.
+    nxt_sync <= sync;
+    nxt_sync_size_cnt <= INCR_UVEC(sync_size_cnt, 1);
+    IF UNSIGNED(sync_size_cnt) = UNSIGNED(nof_clk_per_sync) - 1 THEN
+      nxt_sync <= '1';  -- will set rs_sosi.sync on next rs_sosi.sop
+      nxt_sync_size_cnt <= (OTHERS=>'0');
+    END IF;
+    IF i_rs_sosi.sync = '1' THEN
+      nxt_sync <= '0';  -- clear when sync has been applied in rs_sosi
+    END IF;
+
+    -- State machine for rs_sosi
+    nxt_state                   <= state;
+    nxt_rs_sosi                 <= i_rs_sosi;  -- hold rs_sosi.bsn
+    nxt_rs_sosi.sync            <= '0';
+    nxt_rs_sosi.valid           <= '0';
+    nxt_rs_sosi.sop             <= '0';
+    nxt_rs_sosi.eop             <= '0';
+    nxt_rs_block_size_cnt       <= rs_block_size_cnt;
+
+    CASE state IS
+      WHEN s_off =>
+        nxt_rs_sosi <= c_dp_sosi_rst;
+        nxt_rs_sosi.bsn <= RESIZE_DP_BSN(rsn);  -- RSN fits in g_bsn_w
+        nxt_sync <= '0';
+        nxt_sync_size_cnt <= (OTHERS=>'0');
+        nxt_rs_block_size_cnt <= (OTHERS=>'0');
+        IF bs_sosi.sync = '1' THEN
+          nxt_rs_sosi.sync <= '1';
+          nxt_rs_sosi.sop <= '1';
+          nxt_rs_sosi.valid <= '1';
+          nxt_state <= s_on;
+        END IF;
+
+      -- using separate states s_on_sop and s_on_eop instead of only
+      -- s_on state and rs_block_size_cnt, cause that g_rs_block_size must be
+      -- >= 3, but that is fine.
+      WHEN s_on_sop =>
+        -- Start of block
+        nxt_rs_sosi.sop <= '1';
+        nxt_rs_sosi.valid  <= '1';
+        nxt_state <= s_on;
+        -- rs_block_size_cnt = 0 at rs_sosi.sop
+        nxt_rs_block_size_cnt <= (OTHERS=>'0');
+        -- after first block, increment bsn per block
+        IF prev_state = s_on_eop THEN
+          nxt_rs_sosi.bsn <= INCR_DP_BSN(i_rs_sosi.bsn, g_rs_block_size, g_bsn_w);  -- RSN
+        END IF;
+        -- check for pending sync
+        IF nxt_sync = '1' THEN
+          nxt_rs_sosi.sync <= '1';
+        END IF;
+
+      WHEN s_on =>
+        -- During block
+        nxt_rs_sosi.valid <= '1';
+        -- rs_block_size_cnt increments to determine end of block
+        nxt_rs_block_size_cnt <= INCR_UVEC(rs_block_size_cnt, 1);
+        IF UNSIGNED(rs_block_size_cnt) >= g_rs_block_size - 3 THEN
+          nxt_state <= s_on_eop;
+        END IF;
+
+      WHEN s_on_eop =>
+        -- End of block
+        nxt_rs_sosi.eop <= '1';
+        nxt_rs_sosi.valid <= '1';
+        nxt_state <= s_on_sop;
+        nxt_rs_block_size_cnt <= INCR_UVEC(rs_block_size_cnt, 1);
+        -- rs_block_size_cnt is dont care at at rs_sosi.eop
+        -- accept dp_off after eop, to avoid fractional blocks
+        IF bs_sosi.valid = '0' THEN
+          nxt_state <= s_off;
+        END IF;
+
+      WHEN OTHERS =>  -- reover from undefined state
+        nxt_state <= s_off;
+    END CASE;
+  END PROCESS;
+
+  -- rs_sosi.valid transition from 0 to 1 is a rs_restart, use nxt_rs_restart
+  -- to have rs_restart at first rs_sosi.sync and rs_sosi.sop.
+  nxt_rs_restart <= nxt_rs_sosi.valid AND NOT i_rs_sosi.valid;
+
+  i_rs_new_interval <= '1' WHEN i_rs_restart = '1' ELSE
+                       '0' WHEN i_rs_sosi.sync = '1' ELSE
+                       reg_rs_new_interval;
+
+  p_clk : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      prev_state          <= s_off;
+      state               <= s_off;
+      i_rs_sosi           <= c_dp_sosi_rst;
+      sync_size_cnt       <= (OTHERS=>'0');
+      sync                <= '0';
+      rs_block_size_cnt   <= (OTHERS=>'0');
+      i_rs_restart        <= '0';
+      reg_rs_new_interval <= '0';
+    ELSIF rising_edge(clk) THEN
+      prev_state          <= state;
+      state               <= nxt_state;
+      i_rs_sosi           <= nxt_rs_sosi;
+      sync_size_cnt       <= nxt_sync_size_cnt;
+      sync                <= nxt_sync;
+      rs_block_size_cnt   <= nxt_rs_block_size_cnt;
+      i_rs_restart        <= nxt_rs_restart;
+      reg_rs_new_interval <= i_rs_new_interval;
+    END IF;
+  END PROCESS;
+
+END rtl;
diff --git a/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd b/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd
index 2332d5953b824f0b7d0653621a336a661ce3dc0e..eb2c76424f67471230b55a544414ad09ed1a2513 100644
--- a/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd
+++ b/libraries/base/dp/src/vhdl/dp_strobe_total_count.vhd
@@ -68,7 +68,7 @@
 -- * This dp_strobe_total_count could have been a common_strobe_total_count
 --   component, because it does not use sosi/siso signals. However it is fine
 --   to keep it in dp_lib, to avoid extra work of moving and renaming.
--- * Use clear to clear the total counters
+-- * Use MM clear to clear the total counters, or use in_clr input signal.
 -- * The MM counter values are held at sync. Use flush to force the current
 --   last counter values into the MM counter values. This is useful if the
 --   ref_sync stopped already.
@@ -93,6 +93,7 @@ ENTITY dp_strobe_total_count IS
 
     ref_sync      : IN STD_LOGIC := '1';
     in_strobe_arr : IN STD_LOGIC_VECTOR(g_nof_counts-1 DOWNTO 0);
+    in_clr        : IN STD_LOGIC := '0';
 
     mm_rst        : IN STD_LOGIC;
     mm_clk        : IN STD_LOGIC;
@@ -126,8 +127,9 @@ ARCHITECTURE rtl OF dp_strobe_total_count IS
   SIGNAL rd_reg             : STD_LOGIC_VECTOR(c_mm_reg.nof_dat*c_mm_reg.dat_w-1 DOWNTO 0) := (OTHERS=>'0');
   SIGNAL mm_cnt_clear       : STD_LOGIC;
   SIGNAL mm_cnt_flush       : STD_LOGIC;
-  SIGNAL cnt_flush          : STD_LOGIC;
-  SIGNAL cnt_clr            : STD_LOGIC;
+  SIGNAL dp_cnt_clear       : STD_LOGIC;
+  SIGNAL dp_cnt_flush       : STD_LOGIC;
+  SIGNAL cnt_clr            : STD_LOGIC := '0';
   SIGNAL cnt_en             : STD_LOGIC := '0';
   SIGNAL cnt_en_arr         : STD_LOGIC_VECTOR(g_nof_counts-1 DOWNTO 0);
   SIGNAL cnt_arr            : t_cnt_arr(g_nof_counts-1 DOWNTO 0);
@@ -149,9 +151,13 @@ BEGIN
     in_pulse  => mm_cnt_clear,
     out_rst   => dp_rst,
     out_clk   => dp_clk,
-    out_pulse => cnt_clr
+    out_pulse => dp_cnt_clear
   );
 
+  -- Support cnt clear via either MM or via an input strobe, use register
+  -- to ease timing closure
+  cnt_clr <= dp_cnt_clear OR in_clr WHEN rising_edge(dp_clk);
+
   u_common_spulse_flush : ENTITY common_lib.common_spulse
   PORT MAP (
     in_rst    => mm_rst,
@@ -159,7 +165,7 @@ BEGIN
     in_pulse  => mm_cnt_flush,
     out_rst   => dp_rst,
     out_clk   => dp_clk,
-    out_pulse => cnt_flush
+    out_pulse => dp_cnt_flush
   );
 
   -- Register inputs to ease timing closure
@@ -211,14 +217,14 @@ BEGIN
   END GENERATE;
 
   -- Hold counter values at ref_sync_reg2 to have stable values for MM read
-  -- for comparision between nodes. Use mm_cnt_flush/cnt_flush to support
+  -- for comparision between nodes. Use mm_cnt_flush/dp_cnt_flush to support
   -- observing the current counter values via MM.
   p_hold_counters : PROCESS(dp_clk)
   BEGIN
     IF rising_edge(dp_clk) THEN
       IF cnt_clr = '1' THEN
         hold_cnt_arr <= (OTHERS=>(OTHERS=>'0'));
-      ELSIF ref_sync_reg2 = '1' OR cnt_flush = '1' THEN
+      ELSIF ref_sync_reg2 = '1' OR dp_cnt_flush = '1' THEN
         hold_cnt_arr <= cnt_arr;
       END IF;
     END IF;
diff --git a/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd b/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd
index f4db0b10fd99d351882615f1b2c79db13f73b24c..f853a951e6dc4683c924991fc52c1b595b6f776f 100644
--- a/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd
+++ b/libraries/base/dp/src/vhdl/mms_dp_bsn_source_v2.vhd
@@ -53,7 +53,8 @@ ENTITY mms_dp_bsn_source_v2 IS
     bs_sosi           : OUT t_dp_sosi;
 
     bs_restart        : OUT STD_LOGIC;  -- pulse to indicate if the bsn_source has restarted
-    bs_new_interval   : OUT STD_LOGIC   -- level to indicate first sync interval if the bsn_source has restarted
+    bs_new_interval   : OUT STD_LOGIC;  -- level to indicate first sync interval if the bsn_source has restarted
+    bs_nof_clk_per_sync : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0)
   );
 END mms_dp_bsn_source_v2;
 
@@ -75,6 +76,7 @@ ARCHITECTURE str OF mms_dp_bsn_source_v2 IS
 BEGIN
 
   bs_sosi <= i_bs_sosi;
+  bs_nof_clk_per_sync <= nof_clk_per_sync;
 
   u_mm_reg : ENTITY work.dp_bsn_source_reg_v2
   GENERIC MAP (
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd b/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd
index 6e60576827b6b82a8cf5868f626744dfcf28322a..ec0734db72a4f67002edba348bd84a163b39f5c6 100644
--- a/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd
+++ b/libraries/base/dp/tb/vhdl/tb_dp_pkg.vhd
@@ -502,6 +502,20 @@ PACKAGE tb_dp_pkg IS
                                 SIGNAL   dbg_accumulate   : OUT   NATURAL;
                                 SIGNAL   dbg_expected_bsn : OUT   NATURAL);
 
+  PROCEDURE proc_dp_verify_sync(CONSTANT c_start_bsn      : IN    NATURAL;
+                                CONSTANT c_sync_period    : IN    NATURAL;
+                                CONSTANT c_block_size     : IN    NATURAL;
+                                CONSTANT c_bsn_is_rsn     : IN    BOOLEAN;    -- increment BSN by 1 or by c_block_size for RSN
+                                SIGNAL   clk              : IN    STD_LOGIC;
+                                SIGNAL   verify_en        : IN    STD_LOGIC;
+                                SIGNAL   sync             : IN    STD_LOGIC;
+                                SIGNAL   sop              : IN    STD_LOGIC;
+                                SIGNAL   bsn              : IN    STD_LOGIC_VECTOR;
+                                -- for debug purposes
+                                SIGNAL   dbg_nof_blk      : OUT   NATURAL;
+                                SIGNAL   dbg_accumulate   : OUT   NATURAL;
+                                SIGNAL   dbg_expected_bsn : OUT   NATURAL);
+
   -- Verify the DUT output sop and eop
   PROCEDURE proc_dp_verify_sop_and_eop(CONSTANT c_ready_latency : IN    NATURAL;
                                        CONSTANT c_verify_valid  : IN    BOOLEAN;
@@ -2379,6 +2393,7 @@ PACKAGE BODY tb_dp_pkg IS
   -- . assume that the fractional sync period varies between N and N-1 blocks
   -- . the fractional sync period starts with N blocks and fits e.g.
   --   dp_bsn_source_v2, dp_bsn_sync_scheduler.
+  -- . Use block sequence number (BSN) in dbg_expected_bsn.
   ------------------------------------------------------------------------------
   PROCEDURE proc_dp_verify_sync(CONSTANT c_start_bsn      : IN    NATURAL;    -- BSN of first sync, start of fractional periods
                                 CONSTANT c_sync_period    : IN    NATURAL;    -- number of sample per sync period
@@ -2392,6 +2407,43 @@ PACKAGE BODY tb_dp_pkg IS
                                 SIGNAL   dbg_nof_blk      : OUT   NATURAL;
                                 SIGNAL   dbg_accumulate   : OUT   NATURAL;
                                 SIGNAL   dbg_expected_bsn : OUT   NATURAL) IS
+  BEGIN
+    proc_dp_verify_sync(c_start_bsn,
+                        c_sync_period,
+                        c_block_size,
+                        FALSE,
+                        clk,
+                        verify_en,
+                        sync,
+                        sop,
+                        bsn,
+                        dbg_nof_blk,
+                        dbg_accumulate,
+                        dbg_expected_bsn);
+  END proc_dp_verify_sync;
+
+  ------------------------------------------------------------------------------
+  -- PROCEDURE: Verify the DUT output sync
+  -- . sync is defined such that it can only be active at sop
+  -- . assume that the fractional sync period varies between N and N-1 blocks
+  -- . the fractional sync period starts with N blocks and fits e.g.
+  --   dp_bsn_source_v2, dp_bsn_sync_scheduler.
+  -- . support using block sequence number (BSN) in dbg_expected_bsn or using
+  --   raw samples sequence number (RSN) in dbg_expected_bsn
+  ------------------------------------------------------------------------------
+  PROCEDURE proc_dp_verify_sync(CONSTANT c_start_bsn      : IN    NATURAL;    -- BSN of first sync, start of fractional periods
+                                CONSTANT c_sync_period    : IN    NATURAL;    -- number of sample per sync period
+                                CONSTANT c_block_size     : IN    NATURAL;    -- number of sample per block
+                                CONSTANT c_bsn_is_rsn     : IN    BOOLEAN;    -- increment BSN by 1 or by c_block_size for RSN
+                                SIGNAL   clk              : IN    STD_LOGIC;
+                                SIGNAL   verify_en        : IN    STD_LOGIC;
+                                SIGNAL   sync             : IN    STD_LOGIC;
+                                SIGNAL   sop              : IN    STD_LOGIC;
+                                SIGNAL   bsn              : IN    STD_LOGIC_VECTOR;
+                                -- for debug purposes
+                                SIGNAL   dbg_nof_blk      : OUT   NATURAL;
+                                SIGNAL   dbg_accumulate   : OUT   NATURAL;
+                                SIGNAL   dbg_expected_bsn : OUT   NATURAL) IS
     CONSTANT c_bsn_w         : NATURAL := sel_a_b(bsn'LENGTH>31, 31, bsn'LENGTH);  -- use maximally c_natural_w = 31 bit of BSN slv to allow calculations with integers
     CONSTANT c_nof_blk_min   : NATURAL := c_sync_period / c_block_size;    -- minimum number of blocks in sync period
     CONSTANT c_extra         : NATURAL := c_sync_period MOD c_block_size;  -- number of extra samples in sync period
@@ -2405,12 +2457,21 @@ PACKAGE BODY tb_dp_pkg IS
     IF c_extra = 0 THEN
       -- The sync period contains an integer number of blocks (c_extra = 0)
       -- Determine directly whether the input bsn is expected to have a sync
-      v_expected_sync := ((v_bsn - c_start_bsn) MOD c_nof_blk_min = 0);
+      IF c_bsn_is_rsn THEN
+        v_expected_sync := ((v_bsn - c_start_bsn) MOD (c_nof_blk_min * c_block_size) = 0);
+      ELSE
+        v_expected_sync := ((v_bsn - c_start_bsn) MOD c_nof_blk_min = 0);
+      END IF;
     ELSE
       -- The sync period contains a fractional number of blocks
       -- Determine next expected BSN with sync until the input bsn is reached using a loop
       WHILE v_expected_bsn < v_bsn LOOP
-        v_expected_bsn := v_expected_bsn + v_nof_blk;  -- next expected BSN to have a sync
+        -- next expected BSN to have a sync
+        IF c_bsn_is_rsn THEN
+          v_expected_bsn := v_expected_bsn + v_nof_blk * c_block_size;
+        ELSE
+          v_expected_bsn := v_expected_bsn + v_nof_blk;
+        END IF;
 
         v_nof_blk := c_nof_blk_min;
         v_accumulate   := v_accumulate - c_extra;
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_rsn_source.vhd b/libraries/base/dp/tb/vhdl/tb_dp_rsn_source.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..b1521fa311897defd073be9385793a3ba8a746c4
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_rsn_source.vhd
@@ -0,0 +1,444 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Author: E. Kooistra
+-- Purpose: Tb for tb_dp_rsn_source
+--   Use dp_bsn_source_v2 to create bs_sosi and extending it with dut =
+--   dp_rsn_source to create and verify rs_sosi.
+-- Remark:
+-- * This tb is made based on tb_dp_bsn_source_v2. Difference is that bs_sosi
+--   has block grid that starts at t_epoch = 0, whereas rs_sosi has block
+--   grid that can start at any bs_sosi.sync. Therefore p_exp_grid_rs is
+--   needed
+
+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.tb_common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+
+ENTITY tb_dp_rsn_source IS
+  GENERIC (
+    g_pps_interval   : NATURAL := 40; --101;
+    g_bs_block_size  : NATURAL := 10; --23, input BSN block size <= g_pps_interval
+    g_rs_block_size  : NATURAL := 10 --23, output RSN block size <= g_pps_interval
+  );
+END tb_dp_rsn_source;
+
+ARCHITECTURE tb OF tb_dp_rsn_source IS
+
+  -- The nof block per sync interval will be the same after every
+  -- c_min_nof_pps_interval. The c_gcd is the greatest common divider of
+  -- g_pps_interval and g_bs_block_size, so g_bs_block_size / c_gcd yields an
+  -- integer. When g_pps_interval and g_bs_block_size are relative prime,
+  -- then c_gcd = 1, and then it takes g_bs_block_size nof g_pps_interval
+  -- for the pattern of c_nof_block_per_sync_lo and c_nof_block_per_sync_hi
+  -- to repeat. If c_gcd = g_bs_block_size, then c_nof_block_per_sync_lo =
+  -- c_nof_block_per_sync_hi, so then the nof block per sync interval is
+  -- the same in every pps interval.
+  CONSTANT c_gcd                   : NATURAL := gcd(g_pps_interval, g_bs_block_size);
+  CONSTANT c_min_nof_pps_interval  : NATURAL := g_bs_block_size / c_gcd;
+
+  CONSTANT c_nof_block_per_sync_lo : NATURAL := g_pps_interval / g_bs_block_size;
+  CONSTANT c_nof_block_per_sync_hi : NATURAL := ceil_div(g_pps_interval, g_bs_block_size);
+
+  -- choose c_nof_pps and c_nof_repeat > c_min_nof_pps_interval, because the
+  -- fractional sync pattern will repeat every c_min_nof_pps_interval number
+  -- of g_pps_intervals.
+  CONSTANT c_factor            : NATURAL := 5;
+  CONSTANT c_nof_pps           : NATURAL := c_min_nof_pps_interval * c_factor;
+  CONSTANT c_nof_repeat        : NATURAL := c_min_nof_pps_interval * c_factor;
+
+  CONSTANT c_clk_period        : TIME    := 10 ns;
+  CONSTANT c_bsn_w             : NATURAL := 31;
+  CONSTANT c_bsn_time_offset_w : NATURAL := ceil_log2(g_bs_block_size);
+
+  -- Minimum latency between sync and PPS, due to logic in DUT
+  CONSTANT c_dp_bsn_latency    : NATURAL := 3;
+  CONSTANT c_dp_rsn_latency    : NATURAL := 1;
+  CONSTANT c_dut_latency       : NATURAL := c_dp_bsn_latency + c_dp_rsn_latency;
+
+  -- The state name tells what kind of test is being done
+  TYPE t_state_enum IS (
+    s_disable,
+    s_dp_on,
+    s_dp_on_pps
+  );
+
+  -- Define the PPS (SSN) and BSN grid that both start at 0 according to Figure 3.1 in [1]:
+  TYPE t_time_grid IS RECORD
+    pps  : STD_LOGIC;  -- pulse per second, g_pps_interval clk per pps interval
+    ssn  : NATURAL;  -- seconds sequence number
+    bsn  : NATURAL;  -- block sequence number, g_bs_block_size clk per block
+    sync : STD_LOGIC;  -- active at sop when pps is active or was active
+    sop  : STD_LOGIC;   -- start of block
+    eop  : STD_LOGIC;  -- end of block
+  END RECORD;
+
+  CONSTANT c_time_grid_rst  : t_time_grid := ('0', 0, 0, '0', '0', '0');
+
+  -- Reference grid
+  SIGNAL ref_grid_bs        : t_time_grid := c_time_grid_rst;
+  SIGNAL ssn_eop            : STD_LOGIC := '0';
+  SIGNAL hold_pps           : STD_LOGIC := '0';
+  SIGNAL nxt_hold_pps       : STD_LOGIC := '0';
+
+  -- Tb
+  SIGNAL tb_end             : STD_LOGIC := '0';
+  SIGNAL rst                : STD_LOGIC := '1';
+  SIGNAL clk                : STD_LOGIC := '1';
+  SIGNAL tb_state           : t_state_enum := s_disable;
+
+  -- BSN source
+  SIGNAL dp_on              : STD_LOGIC := '0';
+  SIGNAL dp_on_pps          : STD_LOGIC := '0';
+  SIGNAL dp_on_status       : STD_LOGIC;
+  SIGNAL bs_restart         : STD_LOGIC;
+  SIGNAL bs_new_interval    : STD_LOGIC;
+  SIGNAL tb_new_interval    : STD_LOGIC := '0';
+  SIGNAL bsn_init           : STD_LOGIC_VECTOR(c_bsn_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL bsn_time_offset    : STD_LOGIC_VECTOR(c_bsn_time_offset_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL bs_sosi            : t_dp_sosi;
+  SIGNAL exp_grid_bs        : t_time_grid;  -- to check with bs_sosi.bsn, sync, sop, eop
+
+  -- RSN source
+  SIGNAL rs_restart         : STD_LOGIC;
+  SIGNAL rs_new_interval    : STD_LOGIC;
+  SIGNAL rs_sosi            : t_dp_sosi;
+  SIGNAL exp_grid_rs        : t_time_grid;  -- to verify rs_sosi.bsn, sync, sop, eop
+
+  -- Verify
+  SIGNAL exp_rs_start_bsn   : NATURAL;
+  SIGNAL exp_rs_sync_cnt    : NATURAL;
+  SIGNAL exp_rs_block_cnt   : NATURAL;
+  SIGNAL hold_exp_rs_sync   : STD_LOGIC := '0';
+
+  SIGNAL unexpected_rs_sync : STD_LOGIC;
+  SIGNAL sl0                : STD_LOGIC := '0';
+  SIGNAL verify_en          : STD_LOGIC := '0';
+  SIGNAL verify_sync        : STD_LOGIC := '0';
+  SIGNAL hold_rs_sop        : STD_LOGIC := '0';
+  SIGNAL prev_rs_valid      : STD_LOGIC;
+  SIGNAL rs_starts_cnt      : NATURAL := 0;
+
+  SIGNAL dbg_c_nof_pps      : NATURAL := c_nof_pps;
+  SIGNAL dbg_c_nof_repeat   : NATURAL := c_nof_repeat;
+
+  SIGNAL dbg_nof_blk        : NATURAL;
+  SIGNAL dbg_accumulate     : NATURAL;
+  SIGNAL dbg_expected_bsn   : NATURAL;
+
+BEGIN
+
+  rst <= '1', '0' AFTER c_clk_period*7;
+  clk <= (NOT clk) OR tb_end AFTER c_clk_period/2;
+
+  -----------------------------------------------------------------------------
+  -- Generate reference time grid for bs_sosi
+  -----------------------------------------------------------------------------
+  proc_common_gen_pulse(1, g_pps_interval, '1', sl0, clk, ref_grid_bs.pps);
+  proc_common_gen_pulse(1, g_bs_block_size, '1', sl0, clk, ref_grid_bs.sop);
+  ref_grid_bs.eop <= ref_grid_bs.sop'DELAYED((g_bs_block_size - 1) * c_clk_period);
+  ssn_eop <= ref_grid_bs.pps'DELAYED((g_pps_interval - 1) * c_clk_period);
+  ref_grid_bs.ssn <= ref_grid_bs.ssn + 1 WHEN rising_edge(clk) AND ssn_eop = '1';
+  ref_grid_bs.bsn <= ref_grid_bs.bsn + 1 WHEN rising_edge(clk) AND ref_grid_bs.eop = '1';
+
+  -- Issue sync at start of block
+  p_ref_grid_bs_sync : PROCESS(ref_grid_bs, hold_pps)
+  BEGIN
+    ref_grid_bs.sync <= '0';
+    nxt_hold_pps <= hold_pps;
+
+    IF ref_grid_bs.pps = '1' THEN
+      IF ref_grid_bs.sop = '1' THEN
+        ref_grid_bs.sync <= '1';  -- immediately issue sync
+      ELSE
+        nxt_hold_pps <= '1';  -- wait until next block
+      END IF;
+    END IF;
+
+    IF hold_pps = '1' THEN
+      IF ref_grid_bs.sop = '1' THEN
+        ref_grid_bs.sync <= '1';  -- issue pending sync
+        nxt_hold_pps <= '0';
+      END IF;
+    END IF;
+  END PROCESS;
+
+  hold_pps <= nxt_hold_pps WHEN rising_edge(clk);
+
+  exp_grid_bs <= ref_grid_bs'DELAYED(c_dp_bsn_latency * c_clk_period);
+
+  -----------------------------------------------------------------------------
+  -- Generate reference time grid for rs_sosi
+  -----------------------------------------------------------------------------
+
+  -- using clk process accounts for c_dp_rsn_latency = 1
+  p_exp_grid_rs : PROCESS(clk)
+    VARIABLE v_sop : STD_LOGIC;
+  BEGIN
+    IF rising_edge(clk) THEN
+      v_sop := '0';
+
+      -- same pps, ssn
+      exp_grid_rs.pps <= exp_grid_bs.pps;
+      exp_grid_rs.ssn <= exp_grid_bs.ssn;
+      exp_grid_rs.sync <= '0';
+      exp_grid_rs.sop <= '0';
+      exp_grid_rs.eop <= '0';
+
+      -- bs blocks start at t_epoch = 0, but rs sync and blocks start at
+      -- bs_restart, so not necessarily at t_epoch = 0
+      IF bs_restart = '1' THEN
+        exp_rs_sync_cnt <= 0;
+        exp_rs_block_cnt <= 0;
+        exp_grid_rs.sync <= '1';
+        exp_grid_rs.sop <= '1';
+        exp_grid_rs.bsn <= exp_grid_bs.bsn * g_bs_block_size;
+        exp_rs_start_bsn <= exp_grid_bs.bsn * g_bs_block_size;
+        hold_exp_rs_sync <= '0';
+      ELSE
+        -- expected rs_sosi sop, eop
+        IF exp_rs_block_cnt < g_rs_block_size-2 THEN
+          exp_rs_block_cnt <= exp_rs_block_cnt + 1;
+        ELSIF exp_rs_block_cnt = g_rs_block_size-2 THEN
+          exp_rs_block_cnt <= exp_rs_block_cnt + 1;
+          exp_grid_rs.eop <= '1';
+        ELSIF exp_rs_block_cnt = g_rs_block_size-1 THEN
+          v_sop := '1';
+          exp_rs_block_cnt <= 0;
+          exp_grid_rs.sop <= '1';
+          exp_grid_rs.bsn <= exp_grid_rs.bsn + g_rs_block_size;
+          -- check for pending rs_sosi sync
+          IF hold_exp_rs_sync = '1' THEN
+            exp_grid_rs.sync <= '1';
+            hold_exp_rs_sync <= '0';
+          END IF;
+        END IF;
+
+        -- expected rs_sosi sync
+        IF exp_rs_sync_cnt < g_pps_interval-1 THEN
+          exp_rs_sync_cnt <= exp_rs_sync_cnt + 1;
+        ELSE
+          exp_rs_sync_cnt <= 0;
+          IF v_sop = '1' THEN
+            exp_grid_rs.sync <= '1';  -- issue sync immediately at this exp_grid_rs.sop
+          ELSE
+            hold_exp_rs_sync <= '1';  -- pend sync until next exp_grid_rs.sop
+          END IF;
+        END IF;
+      END IF;
+
+    END IF;
+  END PROCESS;
+
+
+  -----------------------------------------------------------------------------
+  -- Stimuli
+  -----------------------------------------------------------------------------
+  p_mm : PROCESS
+    VARIABLE v_ssn             : NATURAL;
+    VARIABLE v_bsn_init        : NATURAL;
+    VARIABLE v_bsn_time_offset : NATURAL;
+  BEGIN
+    -- Get synchronous to clk
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 10);
+
+    -- Start asynchronously by making dp_on high
+    verify_en <= '0';  -- only verify visualy in wave window
+    tb_state <= s_dp_on;
+    dp_on_pps <= '0';
+    dp_on <= '1';
+    proc_common_wait_some_cycles(clk, c_nof_pps*g_pps_interval);
+    tb_state <= s_disable;
+    dp_on <= '0';
+    dp_on_pps <= '0';
+
+    -- Wait sufficient until bs_sosi is idle again
+    proc_common_wait_some_cycles(clk, 5*g_pps_interval);
+
+    -- Start synchronously by making dp_on and dp_on_pps high
+    verify_en <= '1';  -- verify automatically in test bench
+
+    FOR I IN 0 TO c_nof_repeat-1 LOOP
+      -- Wait some variable time between tests, to enforce testing different
+      -- bsn_time_offset values
+      proc_common_wait_some_cycles(clk, 5*g_pps_interval);
+      proc_common_wait_some_cycles(clk, I*g_pps_interval);
+
+      -- Wait until in the beginning of PPS interval
+      proc_common_wait_until_hi_lo(clk, ref_grid_bs.pps);
+      proc_common_wait_some_cycles(clk, c_dp_bsn_latency);
+
+      -- Determine bsn_init and bsn_time_offset for BSN source start
+      -- . bsn_init = BSN at sync
+      -- . bsn_time_offset = number of clk that sync occurs after PPS
+      v_ssn := ref_grid_bs.ssn + 1;  -- +1 to prepare start in next PPS interval
+      v_bsn_init := ceil_div(v_SSN * g_pps_interval, g_bs_block_size);  -- Equation 3.6 in [1]
+      v_bsn_time_offset := v_bsn_init * g_bs_block_size - v_SSN * g_pps_interval;  -- Equation 3.7 in [1]
+      bsn_init <= TO_UVEC(v_bsn_init, c_bsn_w);  --
+      bsn_time_offset <= TO_UVEC(v_bsn_time_offset, c_bsn_time_offset_w);
+      -- Start synchronously by making dp_on and dp_on_pps high
+      tb_state  <= s_dp_on_pps;
+      dp_on_pps <= '1';
+      dp_on <= '1';
+      proc_common_wait_some_cycles(clk, c_nof_pps*g_pps_interval);
+      tb_state <= s_disable;
+      dp_on <= '0';
+      dp_on_pps <= '0';
+    END LOOP;
+
+    proc_common_wait_some_cycles(clk, 10);
+    ASSERT rs_starts_cnt = 1 + c_nof_repeat REPORT "Wrong number of BSN source starts." SEVERITY ERROR;
+
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+
+  -----------------------------------------------------------------------------
+  -- Verification
+  -- . Some aspects of rs_sosi are verified multiple times in different ways,
+  --   this overlap is fine, because the tb and DUT are rather complicated, so
+  --   using different approaches also helpt to verify the tb itself.
+  -----------------------------------------------------------------------------
+  verify_sync <= verify_en AND rs_sosi.valid;
+
+  proc_dp_verify_sop_and_eop(clk, rs_sosi.valid, rs_sosi.sop, rs_sosi.eop, hold_rs_sop);  -- Verify that sop and eop come in pairs
+  --proc_dp_verify_sync(clk, verify_sync, rs_sosi.sync, exp_grid_rs.sop, exp_grid_rs.sync);  -- Verify sync at sop and at expected_sync
+
+  -- Verify sync at sop and at expected_sync
+  proc_dp_verify_sync(exp_rs_start_bsn,
+                      g_pps_interval,
+                      g_rs_block_size,
+                      TRUE,   -- use BSN as RSN
+                      clk,
+                      verify_en,
+                      rs_sosi.sync,
+                      rs_sosi.sop,
+                      rs_sosi.bsn,
+                      dbg_nof_blk,
+                      dbg_accumulate,
+                      dbg_expected_bsn);
+
+  -- Verify rs_sosi by comparing with exp_grid_rs, this again verifies rs_sosi.sync, sop and bsn
+  p_verify_rs_sosi_grid : PROCESS(clk)
+  BEGIN
+    IF rising_edge(clk) THEN
+      unexpected_rs_sync <= '0';
+      IF verify_en = '1' AND rs_sosi.valid = '1' THEN
+        ASSERT TO_UINT(rs_sosi.bsn) = exp_grid_rs.bsn REPORT "Wrong rs_sosi.bsn /= exp_grid_rs.bsn" SEVERITY ERROR;
+        ASSERT rs_sosi.sync = exp_grid_rs.sync REPORT "Wrong rs_sosi.sync /= exp_grid_rs.sync" SEVERITY ERROR;
+        ASSERT rs_sosi.sop = exp_grid_rs.sop REPORT "Wrong rs_sosi.sop /= exp_grid_rs.sop" SEVERITY ERROR;
+        ASSERT rs_sosi.eop = exp_grid_rs.eop REPORT "Wrong rs_sosi.eop /= exp_grid_rs.eop" SEVERITY ERROR;
+        -- Mark error in Wave window
+        IF rs_sosi.sync = '1' AND rs_sosi.sync /= exp_grid_rs.sync THEN
+          unexpected_rs_sync <= '1';
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  -- Verify that rs_sosi.valid = '1' did happen after dp_on by verifying rs_start
+  prev_rs_valid <= rs_sosi.valid WHEN rising_edge(clk);
+  rs_starts_cnt <= rs_starts_cnt + 1 WHEN rising_edge(clk) AND rs_sosi.valid = '1' AND prev_rs_valid = '0';
+
+  p_verify_rs_restart : PROCESS(clk)
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF rs_restart = '1' THEN
+        ASSERT rs_sosi.sync = '1' REPORT "Unexpected rs_start while rs_sosi.sync /= 1" SEVERITY ERROR;
+        ASSERT prev_rs_valid = '0' REPORT "Unexpected rs_start while prev_rs_valid /= 0" SEVERITY ERROR;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  p_verify_rs_new_interval : PROCESS(clk)
+  BEGIN
+    IF rising_edge(clk) THEN
+      IF rs_restart = '1' THEN
+        ASSERT rs_new_interval = '1' REPORT "Wrong begin of rs_new_interval" SEVERITY ERROR;
+        tb_new_interval <= '1';
+      ELSIF rs_sosi.sync = '1' THEN
+        ASSERT rs_new_interval = '0' REPORT "Wrong end of rs_new_interval" SEVERITY ERROR;
+        tb_new_interval <= '0';
+      ELSIF tb_new_interval = '1' THEN
+        ASSERT rs_new_interval = '1' REPORT "Wrong level during rs_new_interval" SEVERITY ERROR;
+      ELSE
+        ASSERT rs_new_interval = '0' REPORT "Unexpected rs_new_interval" SEVERITY ERROR;
+      END IF;
+    END IF;
+  END PROCESS;
+
+  -----------------------------------------------------------------------------
+  -- DUT: dp_bsn_source_v2 --> dp_rsn_source
+  -----------------------------------------------------------------------------
+
+  u_bsn : ENTITY work.dp_bsn_source_v2
+  GENERIC MAP (
+    g_block_size         => g_bs_block_size,
+    g_nof_clk_per_sync   => g_pps_interval,
+    g_bsn_w              => c_bsn_w,
+    g_bsn_time_offset_w  => c_bsn_time_offset_w
+  )
+  PORT MAP (
+    rst              => rst,
+    clk              => clk,
+    pps              => ref_grid_bs.pps,
+    -- MM control
+    dp_on            => dp_on,
+    dp_on_pps        => dp_on_pps,
+
+    dp_on_status     => dp_on_status,  -- = src_out.valid
+    bs_restart       => bs_restart,    -- = src_out.sync for first sync after dp_on went high
+    bs_new_interval  => bs_new_interval,  -- active during first src_out.sync interval
+
+    bsn_init         => bsn_init,
+    bsn_time_offset  => bsn_time_offset,
+
+    -- Streaming
+    src_out          => bs_sosi
+  );
+
+  u_rsn : ENTITY work.dp_rsn_source
+  GENERIC MAP (
+    g_bs_block_size     => g_bs_block_size,
+    g_rs_block_size     => g_rs_block_size,
+    g_nof_clk_per_sync  => g_pps_interval,
+    g_bsn_w             => c_bsn_w
+  )
+  PORT MAP (
+    rst                 => rst,
+    clk                 => clk,
+
+    -- Input stream sosi control using BSN
+    bs_sosi             => bs_sosi,  -- input reference stream using BSN
+
+    -- Output stream sosi control using RSN
+    rs_sosi             => rs_sosi,  -- output stream using RSN and g_rs_block_size, g_nof_clk_per_sync
+    rs_restart          => rs_restart,  -- = rs_sosi.sync for first sync after bs_sosi.valid went high
+    rs_new_interval     => rs_new_interval   -- = active during first rs_sosi.sync interval
+  );
+
+END tb;
diff --git a/libraries/base/dp/tb/vhdl/tb_tb_dp_rsn_source.vhd b/libraries/base/dp/tb/vhdl/tb_tb_dp_rsn_source.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..377dd47e96a0117119fb4ab1c9fd09196cd5f468
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_tb_dp_rsn_source.vhd
@@ -0,0 +1,97 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2023
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--     http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+-- Author: E. Kooistra
+-- Purpose: Multi dp for tb_dp_rsn_source
+-- Remark:
+-- . Derived from tb_tb_dp_bsn_source_v2
+-- Usage:
+-- > as 4
+-- > run -all --> OK
+
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE work.tb_dp_pkg.ALL;
+
+
+ENTITY tb_tb_dp_rsn_source IS
+END tb_tb_dp_rsn_source;
+
+
+ARCHITECTURE tb OF tb_tb_dp_rsn_source IS
+
+  SIGNAL tb_end : STD_LOGIC := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+
+BEGIN
+  -- from tb_dp_rsn_source.vhd
+  --
+  -- g_pps_interval   : NATURAL := 240
+  -- g_bs_block_size  : NATURAL := 32
+  -- g_rs_block_size  : NATURAL := 5 --23
+
+  -----------------------------------------------------------------------------
+  -- Tests with g_rs_block_size /= g_bs_block_size
+  -----------------------------------------------------------------------------
+  u_12_3_3   : ENTITY work.tb_dp_rsn_source GENERIC MAP (12,  3,  3);  -- smallest block size
+  u_16_8_4   : ENTITY work.tb_dp_rsn_source GENERIC MAP (16,  8,  4);  -- integer number of blocks per g_pps_interval
+  u_25_5     : ENTITY work.tb_dp_rsn_source GENERIC MAP (25,  5,  5);
+  u_29_17_23 : ENTITY work.tb_dp_rsn_source GENERIC MAP (29, 17, 23);  -- fractional number of blocks per g_pps_interval
+
+  u_9_4_5    : ENTITY work.tb_dp_rsn_source GENERIC MAP (9, 4, 5);  -- 2 g_bs_block_size < g_pps_interval < 2 g_rs_block_size
+  u_9_5_4    : ENTITY work.tb_dp_rsn_source GENERIC MAP (9, 5, 4);  -- 2 g_bs_block_size > g_pps_interval > 2 g_rs_block_size
+  u_9_5_9    : ENTITY work.tb_dp_rsn_source GENERIC MAP (9, 5, 9);  -- 1 g_rs_block_size/g_pps_interval
+  u_9_9_5    : ENTITY work.tb_dp_rsn_source GENERIC MAP (9, 9, 5);  -- 1 g_bs_block_size/g_pps_interval
+
+  -----------------------------------------------------------------------------
+  -- Same tests as with tb_dp_bsn_source_v2 with g_rs_block_size = g_bs_block_size
+  -----------------------------------------------------------------------------
+  -- test integer case
+  u_20_10  : ENTITY work.tb_dp_rsn_source GENERIC MAP (20, 10, 10);  -- 20 // 10 = 2, 20 MOD 10 = 0, 20/10 = 2 block/sync
+  u_22_11  : ENTITY work.tb_dp_rsn_source GENERIC MAP (22, 11, 11);  -- 22 // 11 = 2, 22 MOD 11 = 0, 22/11 = 2 block/sync
+  u_39_13  : ENTITY work.tb_dp_rsn_source GENERIC MAP (39, 13, 13);  -- 39 // 13 = 3, 39 MOD 13 = 0, 39/13 = 3 block/sync
+
+  -- test smallest nof block per sync
+  u_10_10  : ENTITY work.tb_dp_rsn_source GENERIC MAP (10, 10, 10);  -- 1 block/sync
+  u_5_5    : ENTITY work.tb_dp_rsn_source GENERIC MAP (5, 5, 5);    -- 1 block/sync
+
+  -- test smallest g_block_size case
+  u_3_3    : ENTITY work.tb_dp_rsn_source GENERIC MAP (3, 3, 3);  -- 3 // 3 = 1, 3 MOD 3 = 0, 3/3 = 1 block/sync
+  u_6_3    : ENTITY work.tb_dp_rsn_source GENERIC MAP (6, 3, 3);  -- 6 // 3 = 2, 6 MOD 3 = 0, 6/3 = 2 block/sync
+  u_7_3    : ENTITY work.tb_dp_rsn_source GENERIC MAP (7, 3, 3);  -- 7 // 3 = 2, 7 MOD 3 = 1, 7/3 = 2.33 block/sync
+
+  -- test lofar case with 0.5 fraction in average nof block/sync
+  u_20_8   : ENTITY work.tb_dp_rsn_source GENERIC MAP (20, 8, 8);  -- 20 // 8 = 2, 20 MOD 8 = 4, 20/8 = 2.5 block/sync
+
+  -- test fractional (corner) cases
+  u_18_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (18, 9, 9);  -- 18 MOD 9 = 0
+  u_17_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (17, 9, 9);  -- 17 MOD 9 = 8 = g_block_size - 1
+  u_19_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (19, 9, 9);  -- 19 MOD 9 = 1
+  u_20_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (20, 9, 9);  -- 20 MOD 9 = 2
+  u_25_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (25, 9, 9);  -- 25 MOD 9 = 7
+  u_26_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (26, 9, 9);  -- 26 MOD 9 = 8 = g_block_size - 1
+  u_27_9   : ENTITY work.tb_dp_rsn_source GENERIC MAP (27, 9, 9);  -- 27 MOD 9 = 0
+
+  -- test some prime values
+  u_17_3   : ENTITY work.tb_dp_rsn_source GENERIC MAP (17, 3, 3);    -- 17 // 3 = 5, 17 MOD 3 = 2, 17/3 = 5.66 block/sync
+  u_101_17 : ENTITY work.tb_dp_rsn_source GENERIC MAP (101, 17, 17);  -- 101 // 17 = 5, 101 MOD 17 = 16, 101/17 = 5.9411 block/sync
+
+END tb;
+  
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC16_D28.vhd b/libraries/external/easics/src/vhdl/PCK_CRC16_D28.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..88718ee4125641ffafe642ebf75b86ba0bb671b8
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC16_D28.vhd
@@ -0,0 +1,70 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^16 + x^14 + x^13 + x^11 + 1
+--   * data width: 28
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC16_D28 is
+  -- polynomial: x^16 + x^14 + x^13 + x^11 + 1
+  -- data width: 28
+  -- convention: the first serial bit is D[27]
+  function nextCRC16_D28
+    (Data: std_logic_vector(27 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector;
+end PCK_CRC16_D28;
+
+
+package body PCK_CRC16_D28 is
+
+  -- polynomial: x^16 + x^14 + x^13 + x^11 + 1
+  -- data width: 28
+  -- convention: the first serial bit is D[27]
+  function nextCRC16_D28
+    (Data: std_logic_vector(27 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(27 downto 0);
+    variable c:      std_logic_vector(15 downto 0);
+    variable newcrc: std_logic_vector(15 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(27) xor d(22) xor d(20) xor d(19) xor d(17) xor d(15) xor d(14) xor d(12) xor d(7) xor d(5) xor d(4) xor d(3) xor d(2) xor d(0) xor c(0) xor c(2) xor c(3) xor c(5) xor c(7) xor c(8) xor c(10) xor c(15);
+    newcrc(1) := d(23) xor d(21) xor d(20) xor d(18) xor d(16) xor d(15) xor d(13) xor d(8) xor d(6) xor d(5) xor d(4) xor d(3) xor d(1) xor c(1) xor c(3) xor c(4) xor c(6) xor c(8) xor c(9) xor c(11);
+    newcrc(2) := d(24) xor d(22) xor d(21) xor d(19) xor d(17) xor d(16) xor d(14) xor d(9) xor d(7) xor d(6) xor d(5) xor d(4) xor d(2) xor c(2) xor c(4) xor c(5) xor c(7) xor c(9) xor c(10) xor c(12);
+    newcrc(3) := d(25) xor d(23) xor d(22) xor d(20) xor d(18) xor d(17) xor d(15) xor d(10) xor d(8) xor d(7) xor d(6) xor d(5) xor d(3) xor c(3) xor c(5) xor c(6) xor c(8) xor c(10) xor c(11) xor c(13);
+    newcrc(4) := d(26) xor d(24) xor d(23) xor d(21) xor d(19) xor d(18) xor d(16) xor d(11) xor d(9) xor d(8) xor d(7) xor d(6) xor d(4) xor c(4) xor c(6) xor c(7) xor c(9) xor c(11) xor c(12) xor c(14);
+    newcrc(5) := d(27) xor d(25) xor d(24) xor d(22) xor d(20) xor d(19) xor d(17) xor d(12) xor d(10) xor d(9) xor d(8) xor d(7) xor d(5) xor c(0) xor c(5) xor c(7) xor c(8) xor c(10) xor c(12) xor c(13) xor c(15);
+    newcrc(6) := d(26) xor d(25) xor d(23) xor d(21) xor d(20) xor d(18) xor d(13) xor d(11) xor d(10) xor d(9) xor d(8) xor d(6) xor c(1) xor c(6) xor c(8) xor c(9) xor c(11) xor c(13) xor c(14);
+    newcrc(7) := d(27) xor d(26) xor d(24) xor d(22) xor d(21) xor d(19) xor d(14) xor d(12) xor d(11) xor d(10) xor d(9) xor d(7) xor c(0) xor c(2) xor c(7) xor c(9) xor c(10) xor c(12) xor c(14) xor c(15);
+    newcrc(8) := d(27) xor d(25) xor d(23) xor d(22) xor d(20) xor d(15) xor d(13) xor d(12) xor d(11) xor d(10) xor d(8) xor c(0) xor c(1) xor c(3) xor c(8) xor c(10) xor c(11) xor c(13) xor c(15);
+    newcrc(9) := d(26) xor d(24) xor d(23) xor d(21) xor d(16) xor d(14) xor d(13) xor d(12) xor d(11) xor d(9) xor c(0) xor c(1) xor c(2) xor c(4) xor c(9) xor c(11) xor c(12) xor c(14);
+    newcrc(10) := d(27) xor d(25) xor d(24) xor d(22) xor d(17) xor d(15) xor d(14) xor d(13) xor d(12) xor d(10) xor c(0) xor c(1) xor c(2) xor c(3) xor c(5) xor c(10) xor c(12) xor c(13) xor c(15);
+    newcrc(11) := d(27) xor d(26) xor d(25) xor d(23) xor d(22) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(13) xor d(12) xor d(11) xor d(7) xor d(5) xor d(4) xor d(3) xor d(2) xor d(0) xor c(0) xor c(1) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(10) xor c(11) xor c(13) xor c(14) xor c(15);
+    newcrc(12) := d(27) xor d(26) xor d(24) xor d(23) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(14) xor d(13) xor d(12) xor d(8) xor d(6) xor d(5) xor d(4) xor d(3) xor d(1) xor c(0) xor c(1) xor c(2) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(11) xor c(12) xor c(14) xor c(15);
+    newcrc(13) := d(25) xor d(24) xor d(21) xor d(18) xor d(17) xor d(13) xor d(12) xor d(9) xor d(6) xor d(3) xor d(0) xor c(0) xor c(1) xor c(5) xor c(6) xor c(9) xor c(12) xor c(13);
+    newcrc(14) := d(27) xor d(26) xor d(25) xor d(20) xor d(18) xor d(17) xor d(15) xor d(13) xor d(12) xor d(10) xor d(5) xor d(3) xor d(2) xor d(1) xor d(0) xor c(0) xor c(1) xor c(3) xor c(5) xor c(6) xor c(8) xor c(13) xor c(14) xor c(15);
+    newcrc(15) := d(27) xor d(26) xor d(21) xor d(19) xor d(18) xor d(16) xor d(14) xor d(13) xor d(11) xor d(6) xor d(4) xor d(3) xor d(2) xor d(1) xor c(1) xor c(2) xor c(4) xor c(6) xor c(7) xor c(9) xor c(14) xor c(15);
+    return newcrc;
+  end nextCRC16_D28;
+
+end PCK_CRC16_D28;
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC16_D28_usb.vhd b/libraries/external/easics/src/vhdl/PCK_CRC16_D28_usb.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..2993572c2f8c79c498ca211dd2b2df8072236c4e
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC16_D28_usb.vhd
@@ -0,0 +1,70 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^16 + x^15 + x^2 + 1
+--   * data width: 28
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC16_D28 is
+  -- polynomial: x^16 + x^15 + x^2 + 1
+  -- data width: 28
+  -- convention: the first serial bit is D[27]
+  function nextCRC16_D28
+    (Data: std_logic_vector(27 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector;
+end PCK_CRC16_D28;
+
+
+package body PCK_CRC16_D28 is
+
+  -- polynomial: x^16 + x^15 + x^2 + 1
+  -- data width: 28
+  -- convention: the first serial bit is D[27]
+  function nextCRC16_D28
+    (Data: std_logic_vector(27 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(27 downto 0);
+    variable c:      std_logic_vector(15 downto 0);
+    variable newcrc: std_logic_vector(15 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(27) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(15) xor d(13) xor d(12) xor d(11) xor d(10) xor d(9) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(2) xor d(1) xor d(0) xor c(0) xor c(1) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(10) xor c(11) xor c(12) xor c(13) xor c(14) xor c(15);
+    newcrc(1) := d(27) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(14) xor d(13) xor d(12) xor d(11) xor d(10) xor d(9) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(2) xor d(1) xor c(0) xor c(1) xor c(2) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(10) xor c(11) xor c(12) xor c(13) xor c(14) xor c(15);
+    newcrc(2) := d(16) xor d(14) xor d(1) xor d(0) xor c(2) xor c(4);
+    newcrc(3) := d(17) xor d(15) xor d(2) xor d(1) xor c(3) xor c(5);
+    newcrc(4) := d(18) xor d(16) xor d(3) xor d(2) xor c(4) xor c(6);
+    newcrc(5) := d(19) xor d(17) xor d(4) xor d(3) xor c(5) xor c(7);
+    newcrc(6) := d(20) xor d(18) xor d(5) xor d(4) xor c(6) xor c(8);
+    newcrc(7) := d(21) xor d(19) xor d(6) xor d(5) xor c(7) xor c(9);
+    newcrc(8) := d(22) xor d(20) xor d(7) xor d(6) xor c(8) xor c(10);
+    newcrc(9) := d(23) xor d(21) xor d(8) xor d(7) xor c(9) xor c(11);
+    newcrc(10) := d(24) xor d(22) xor d(9) xor d(8) xor c(10) xor c(12);
+    newcrc(11) := d(25) xor d(23) xor d(10) xor d(9) xor c(11) xor c(13);
+    newcrc(12) := d(26) xor d(24) xor d(11) xor d(10) xor c(12) xor c(14);
+    newcrc(13) := d(27) xor d(25) xor d(12) xor d(11) xor c(0) xor c(13) xor c(15);
+    newcrc(14) := d(26) xor d(13) xor d(12) xor c(0) xor c(1) xor c(14);
+    newcrc(15) := d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(15) xor d(14) xor d(12) xor d(11) xor d(10) xor d(9) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(2) xor d(1) xor d(0) xor c(0) xor c(2) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(10) xor c(11) xor c(12) xor c(13) xor c(14);
+    return newcrc;
+  end nextCRC16_D28;
+
+end PCK_CRC16_D28;
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC16_D32_usb.vhd b/libraries/external/easics/src/vhdl/PCK_CRC16_D32_usb.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..b6ab9fbb6602cf7a9ec3ad46ad1929887511c805
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC16_D32_usb.vhd
@@ -0,0 +1,70 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^16 + x^15 + x^2 + 1
+--   * data width: 32
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC16_D32 is
+  -- polynomial: x^16 + x^15 + x^2 + 1
+  -- data width: 32
+  -- convention: the first serial bit is D[31]
+  function nextCRC16_D32
+    (Data: std_logic_vector(31 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector;
+end PCK_CRC16_D32;
+
+
+package body PCK_CRC16_D32 is
+
+  -- polynomial: x^16 + x^15 + x^2 + 1
+  -- data width: 32
+  -- convention: the first serial bit is D[31]
+  function nextCRC16_D32
+    (Data: std_logic_vector(31 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(31 downto 0);
+    variable c:      std_logic_vector(15 downto 0);
+    variable newcrc: std_logic_vector(15 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(31) xor d(30) xor d(27) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(15) xor d(13) xor d(12) xor d(11) xor d(10) xor d(9) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(2) xor d(1) xor d(0) xor c(0) xor c(1) xor c(2) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(10) xor c(11) xor c(14) xor c(15);
+    newcrc(1) := d(31) xor d(28) xor d(27) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(14) xor d(13) xor d(12) xor d(11) xor d(10) xor d(9) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(2) xor d(1) xor c(0) xor c(1) xor c(2) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(10) xor c(11) xor c(12) xor c(15);
+    newcrc(2) := d(31) xor d(30) xor d(29) xor d(28) xor d(16) xor d(14) xor d(1) xor d(0) xor c(0) xor c(12) xor c(13) xor c(14) xor c(15);
+    newcrc(3) := d(31) xor d(30) xor d(29) xor d(17) xor d(15) xor d(2) xor d(1) xor c(1) xor c(13) xor c(14) xor c(15);
+    newcrc(4) := d(31) xor d(30) xor d(18) xor d(16) xor d(3) xor d(2) xor c(0) xor c(2) xor c(14) xor c(15);
+    newcrc(5) := d(31) xor d(19) xor d(17) xor d(4) xor d(3) xor c(1) xor c(3) xor c(15);
+    newcrc(6) := d(20) xor d(18) xor d(5) xor d(4) xor c(2) xor c(4);
+    newcrc(7) := d(21) xor d(19) xor d(6) xor d(5) xor c(3) xor c(5);
+    newcrc(8) := d(22) xor d(20) xor d(7) xor d(6) xor c(4) xor c(6);
+    newcrc(9) := d(23) xor d(21) xor d(8) xor d(7) xor c(5) xor c(7);
+    newcrc(10) := d(24) xor d(22) xor d(9) xor d(8) xor c(6) xor c(8);
+    newcrc(11) := d(25) xor d(23) xor d(10) xor d(9) xor c(7) xor c(9);
+    newcrc(12) := d(26) xor d(24) xor d(11) xor d(10) xor c(8) xor c(10);
+    newcrc(13) := d(27) xor d(25) xor d(12) xor d(11) xor c(9) xor c(11);
+    newcrc(14) := d(28) xor d(26) xor d(13) xor d(12) xor c(10) xor c(12);
+    newcrc(15) := d(31) xor d(30) xor d(29) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(20) xor d(19) xor d(18) xor d(17) xor d(16) xor d(15) xor d(14) xor d(12) xor d(11) xor d(10) xor d(9) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(2) xor d(1) xor d(0) xor c(0) xor c(1) xor c(2) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(9) xor c(10) xor c(13) xor c(14) xor c(15);
+    return newcrc;
+  end nextCRC16_D32;
+
+end PCK_CRC16_D32;
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC16_D32_x25.vhd b/libraries/external/easics/src/vhdl/PCK_CRC16_D32_x25.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..e961f7777c976be47e157792d0945b064422ca7d
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC16_D32_x25.vhd
@@ -0,0 +1,70 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^16 + x^12 + x^5 + 1
+--   * data width: 32
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC16_D32 is
+  -- polynomial: x^16 + x^12 + x^5 + 1
+  -- data width: 32
+  -- convention: the first serial bit is D[31]
+  function nextCRC16_D32
+    (Data: std_logic_vector(31 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector;
+end PCK_CRC16_D32;
+
+
+package body PCK_CRC16_D32 is
+
+  -- polynomial: x^16 + x^12 + x^5 + 1
+  -- data width: 32
+  -- convention: the first serial bit is D[31]
+  function nextCRC16_D32
+    (Data: std_logic_vector(31 downto 0);
+     crc:  std_logic_vector(15 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(31 downto 0);
+    variable c:      std_logic_vector(15 downto 0);
+    variable newcrc: std_logic_vector(15 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(28) xor d(27) xor d(26) xor d(22) xor d(20) xor d(19) xor d(12) xor d(11) xor d(8) xor d(4) xor d(0) xor c(3) xor c(4) xor c(6) xor c(10) xor c(11) xor c(12);
+    newcrc(1) := d(29) xor d(28) xor d(27) xor d(23) xor d(21) xor d(20) xor d(13) xor d(12) xor d(9) xor d(5) xor d(1) xor c(4) xor c(5) xor c(7) xor c(11) xor c(12) xor c(13);
+    newcrc(2) := d(30) xor d(29) xor d(28) xor d(24) xor d(22) xor d(21) xor d(14) xor d(13) xor d(10) xor d(6) xor d(2) xor c(5) xor c(6) xor c(8) xor c(12) xor c(13) xor c(14);
+    newcrc(3) := d(31) xor d(30) xor d(29) xor d(25) xor d(23) xor d(22) xor d(15) xor d(14) xor d(11) xor d(7) xor d(3) xor c(6) xor c(7) xor c(9) xor c(13) xor c(14) xor c(15);
+    newcrc(4) := d(31) xor d(30) xor d(26) xor d(24) xor d(23) xor d(16) xor d(15) xor d(12) xor d(8) xor d(4) xor c(0) xor c(7) xor c(8) xor c(10) xor c(14) xor c(15);
+    newcrc(5) := d(31) xor d(28) xor d(26) xor d(25) xor d(24) xor d(22) xor d(20) xor d(19) xor d(17) xor d(16) xor d(13) xor d(12) xor d(11) xor d(9) xor d(8) xor d(5) xor d(4) xor d(0) xor c(0) xor c(1) xor c(3) xor c(4) xor c(6) xor c(8) xor c(9) xor c(10) xor c(12) xor c(15);
+    newcrc(6) := d(29) xor d(27) xor d(26) xor d(25) xor d(23) xor d(21) xor d(20) xor d(18) xor d(17) xor d(14) xor d(13) xor d(12) xor d(10) xor d(9) xor d(6) xor d(5) xor d(1) xor c(1) xor c(2) xor c(4) xor c(5) xor c(7) xor c(9) xor c(10) xor c(11) xor c(13);
+    newcrc(7) := d(30) xor d(28) xor d(27) xor d(26) xor d(24) xor d(22) xor d(21) xor d(19) xor d(18) xor d(15) xor d(14) xor d(13) xor d(11) xor d(10) xor d(7) xor d(6) xor d(2) xor c(2) xor c(3) xor c(5) xor c(6) xor c(8) xor c(10) xor c(11) xor c(12) xor c(14);
+    newcrc(8) := d(31) xor d(29) xor d(28) xor d(27) xor d(25) xor d(23) xor d(22) xor d(20) xor d(19) xor d(16) xor d(15) xor d(14) xor d(12) xor d(11) xor d(8) xor d(7) xor d(3) xor c(0) xor c(3) xor c(4) xor c(6) xor c(7) xor c(9) xor c(11) xor c(12) xor c(13) xor c(15);
+    newcrc(9) := d(30) xor d(29) xor d(28) xor d(26) xor d(24) xor d(23) xor d(21) xor d(20) xor d(17) xor d(16) xor d(15) xor d(13) xor d(12) xor d(9) xor d(8) xor d(4) xor c(0) xor c(1) xor c(4) xor c(5) xor c(7) xor c(8) xor c(10) xor c(12) xor c(13) xor c(14);
+    newcrc(10) := d(31) xor d(30) xor d(29) xor d(27) xor d(25) xor d(24) xor d(22) xor d(21) xor d(18) xor d(17) xor d(16) xor d(14) xor d(13) xor d(10) xor d(9) xor d(5) xor c(0) xor c(1) xor c(2) xor c(5) xor c(6) xor c(8) xor c(9) xor c(11) xor c(13) xor c(14) xor c(15);
+    newcrc(11) := d(31) xor d(30) xor d(28) xor d(26) xor d(25) xor d(23) xor d(22) xor d(19) xor d(18) xor d(17) xor d(15) xor d(14) xor d(11) xor d(10) xor d(6) xor c(1) xor c(2) xor c(3) xor c(6) xor c(7) xor c(9) xor c(10) xor c(12) xor c(14) xor c(15);
+    newcrc(12) := d(31) xor d(29) xor d(28) xor d(24) xor d(23) xor d(22) xor d(18) xor d(16) xor d(15) xor d(8) xor d(7) xor d(4) xor d(0) xor c(0) xor c(2) xor c(6) xor c(7) xor c(8) xor c(12) xor c(13) xor c(15);
+    newcrc(13) := d(30) xor d(29) xor d(25) xor d(24) xor d(23) xor d(19) xor d(17) xor d(16) xor d(9) xor d(8) xor d(5) xor d(1) xor c(0) xor c(1) xor c(3) xor c(7) xor c(8) xor c(9) xor c(13) xor c(14);
+    newcrc(14) := d(31) xor d(30) xor d(26) xor d(25) xor d(24) xor d(20) xor d(18) xor d(17) xor d(10) xor d(9) xor d(6) xor d(2) xor c(1) xor c(2) xor c(4) xor c(8) xor c(9) xor c(10) xor c(14) xor c(15);
+    newcrc(15) := d(31) xor d(27) xor d(26) xor d(25) xor d(21) xor d(19) xor d(18) xor d(11) xor d(10) xor d(7) xor d(3) xor c(2) xor c(3) xor c(5) xor c(9) xor c(10) xor c(11) xor c(15);
+    return newcrc;
+  end nextCRC16_D32;
+
+end PCK_CRC16_D32;
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC28_D28.vhd b/libraries/external/easics/src/vhdl/PCK_CRC28_D28.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..fbb4af22cf1356215d36baad145e846596a785ca
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC28_D28.vhd
@@ -0,0 +1,82 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^28 + x^25 + 1
+--   * data width: 28
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC28_D28 is
+  -- polynomial: x^28 + x^25 + 1
+  -- data width: 28
+  -- convention: the first serial bit is D[27]
+  function nextCRC28_D28
+    (Data: std_logic_vector(27 downto 0);
+     crc:  std_logic_vector(27 downto 0))
+    return std_logic_vector;
+end PCK_CRC28_D28;
+
+
+package body PCK_CRC28_D28 is
+
+  -- polynomial: x^28 + x^25 + 1
+  -- data width: 28
+  -- convention: the first serial bit is D[27]
+  function nextCRC28_D28
+    (Data: std_logic_vector(27 downto 0);
+     crc:  std_logic_vector(27 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(27 downto 0);
+    variable c:      std_logic_vector(27 downto 0);
+    variable newcrc: std_logic_vector(27 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(27) xor d(24) xor d(21) xor d(18) xor d(15) xor d(12) xor d(9) xor d(6) xor d(3) xor d(0) xor c(0) xor c(3) xor c(6) xor c(9) xor c(12) xor c(15) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(1) := d(25) xor d(22) xor d(19) xor d(16) xor d(13) xor d(10) xor d(7) xor d(4) xor d(1) xor c(1) xor c(4) xor c(7) xor c(10) xor c(13) xor c(16) xor c(19) xor c(22) xor c(25);
+    newcrc(2) := d(26) xor d(23) xor d(20) xor d(17) xor d(14) xor d(11) xor d(8) xor d(5) xor d(2) xor c(2) xor c(5) xor c(8) xor c(11) xor c(14) xor c(17) xor c(20) xor c(23) xor c(26);
+    newcrc(3) := d(27) xor d(24) xor d(21) xor d(18) xor d(15) xor d(12) xor d(9) xor d(6) xor d(3) xor c(3) xor c(6) xor c(9) xor c(12) xor c(15) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(4) := d(25) xor d(22) xor d(19) xor d(16) xor d(13) xor d(10) xor d(7) xor d(4) xor c(4) xor c(7) xor c(10) xor c(13) xor c(16) xor c(19) xor c(22) xor c(25);
+    newcrc(5) := d(26) xor d(23) xor d(20) xor d(17) xor d(14) xor d(11) xor d(8) xor d(5) xor c(5) xor c(8) xor c(11) xor c(14) xor c(17) xor c(20) xor c(23) xor c(26);
+    newcrc(6) := d(27) xor d(24) xor d(21) xor d(18) xor d(15) xor d(12) xor d(9) xor d(6) xor c(6) xor c(9) xor c(12) xor c(15) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(7) := d(25) xor d(22) xor d(19) xor d(16) xor d(13) xor d(10) xor d(7) xor c(7) xor c(10) xor c(13) xor c(16) xor c(19) xor c(22) xor c(25);
+    newcrc(8) := d(26) xor d(23) xor d(20) xor d(17) xor d(14) xor d(11) xor d(8) xor c(8) xor c(11) xor c(14) xor c(17) xor c(20) xor c(23) xor c(26);
+    newcrc(9) := d(27) xor d(24) xor d(21) xor d(18) xor d(15) xor d(12) xor d(9) xor c(9) xor c(12) xor c(15) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(10) := d(25) xor d(22) xor d(19) xor d(16) xor d(13) xor d(10) xor c(10) xor c(13) xor c(16) xor c(19) xor c(22) xor c(25);
+    newcrc(11) := d(26) xor d(23) xor d(20) xor d(17) xor d(14) xor d(11) xor c(11) xor c(14) xor c(17) xor c(20) xor c(23) xor c(26);
+    newcrc(12) := d(27) xor d(24) xor d(21) xor d(18) xor d(15) xor d(12) xor c(12) xor c(15) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(13) := d(25) xor d(22) xor d(19) xor d(16) xor d(13) xor c(13) xor c(16) xor c(19) xor c(22) xor c(25);
+    newcrc(14) := d(26) xor d(23) xor d(20) xor d(17) xor d(14) xor c(14) xor c(17) xor c(20) xor c(23) xor c(26);
+    newcrc(15) := d(27) xor d(24) xor d(21) xor d(18) xor d(15) xor c(15) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(16) := d(25) xor d(22) xor d(19) xor d(16) xor c(16) xor c(19) xor c(22) xor c(25);
+    newcrc(17) := d(26) xor d(23) xor d(20) xor d(17) xor c(17) xor c(20) xor c(23) xor c(26);
+    newcrc(18) := d(27) xor d(24) xor d(21) xor d(18) xor c(18) xor c(21) xor c(24) xor c(27);
+    newcrc(19) := d(25) xor d(22) xor d(19) xor c(19) xor c(22) xor c(25);
+    newcrc(20) := d(26) xor d(23) xor d(20) xor c(20) xor c(23) xor c(26);
+    newcrc(21) := d(27) xor d(24) xor d(21) xor c(21) xor c(24) xor c(27);
+    newcrc(22) := d(25) xor d(22) xor c(22) xor c(25);
+    newcrc(23) := d(26) xor d(23) xor c(23) xor c(26);
+    newcrc(24) := d(27) xor d(24) xor c(24) xor c(27);
+    newcrc(25) := d(27) xor d(25) xor d(24) xor d(21) xor d(18) xor d(15) xor d(12) xor d(9) xor d(6) xor d(3) xor d(0) xor c(0) xor c(3) xor c(6) xor c(9) xor c(12) xor c(15) xor c(18) xor c(21) xor c(24) xor c(25) xor c(27);
+    newcrc(26) := d(26) xor d(25) xor d(22) xor d(19) xor d(16) xor d(13) xor d(10) xor d(7) xor d(4) xor d(1) xor c(1) xor c(4) xor c(7) xor c(10) xor c(13) xor c(16) xor c(19) xor c(22) xor c(25) xor c(26);
+    newcrc(27) := d(27) xor d(26) xor d(23) xor d(20) xor d(17) xor d(14) xor d(11) xor d(8) xor d(5) xor d(2) xor c(2) xor c(5) xor c(8) xor c(11) xor c(14) xor c(17) xor c(20) xor c(23) xor c(26) xor c(27);
+    return newcrc;
+  end nextCRC28_D28;
+
+end PCK_CRC28_D28;
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC32_D32_eth.vhd b/libraries/external/easics/src/vhdl/PCK_CRC32_D32_eth.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..1b30aa6c4f9976d3e2db4262d6fee75ed41ad196
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC32_D32_eth.vhd
@@ -0,0 +1,86 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+--   * data width: 32
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC32_D32 is
+  -- polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+  -- data width: 32
+  -- convention: the first serial bit is D[31]
+  function nextCRC32_D32
+    (Data: std_logic_vector(31 downto 0);
+     crc:  std_logic_vector(31 downto 0))
+    return std_logic_vector;
+end PCK_CRC32_D32;
+
+
+package body PCK_CRC32_D32 is
+
+  -- polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+  -- data width: 32
+  -- convention: the first serial bit is D[31]
+  function nextCRC32_D32
+    (Data: std_logic_vector(31 downto 0);
+     crc:  std_logic_vector(31 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(31 downto 0);
+    variable c:      std_logic_vector(31 downto 0);
+    variable newcrc: std_logic_vector(31 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(31) xor d(30) xor d(29) xor d(28) xor d(26) xor d(25) xor d(24) xor d(16) xor d(12) xor d(10) xor d(9) xor d(6) xor d(0) xor c(0) xor c(6) xor c(9) xor c(10) xor c(12) xor c(16) xor c(24) xor c(25) xor c(26) xor c(28) xor c(29) xor c(30) xor c(31);
+    newcrc(1) := d(28) xor d(27) xor d(24) xor d(17) xor d(16) xor d(13) xor d(12) xor d(11) xor d(9) xor d(7) xor d(6) xor d(1) xor d(0) xor c(0) xor c(1) xor c(6) xor c(7) xor c(9) xor c(11) xor c(12) xor c(13) xor c(16) xor c(17) xor c(24) xor c(27) xor c(28);
+    newcrc(2) := d(31) xor d(30) xor d(26) xor d(24) xor d(18) xor d(17) xor d(16) xor d(14) xor d(13) xor d(9) xor d(8) xor d(7) xor d(6) xor d(2) xor d(1) xor d(0) xor c(0) xor c(1) xor c(2) xor c(6) xor c(7) xor c(8) xor c(9) xor c(13) xor c(14) xor c(16) xor c(17) xor c(18) xor c(24) xor c(26) xor c(30) xor c(31);
+    newcrc(3) := d(31) xor d(27) xor d(25) xor d(19) xor d(18) xor d(17) xor d(15) xor d(14) xor d(10) xor d(9) xor d(8) xor d(7) xor d(3) xor d(2) xor d(1) xor c(1) xor c(2) xor c(3) xor c(7) xor c(8) xor c(9) xor c(10) xor c(14) xor c(15) xor c(17) xor c(18) xor c(19) xor c(25) xor c(27) xor c(31);
+    newcrc(4) := d(31) xor d(30) xor d(29) xor d(25) xor d(24) xor d(20) xor d(19) xor d(18) xor d(15) xor d(12) xor d(11) xor d(8) xor d(6) xor d(4) xor d(3) xor d(2) xor d(0) xor c(0) xor c(2) xor c(3) xor c(4) xor c(6) xor c(8) xor c(11) xor c(12) xor c(15) xor c(18) xor c(19) xor c(20) xor c(24) xor c(25) xor c(29) xor c(30) xor c(31);
+    newcrc(5) := d(29) xor d(28) xor d(24) xor d(21) xor d(20) xor d(19) xor d(13) xor d(10) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(1) xor d(0) xor c(0) xor c(1) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(10) xor c(13) xor c(19) xor c(20) xor c(21) xor c(24) xor c(28) xor c(29);
+    newcrc(6) := d(30) xor d(29) xor d(25) xor d(22) xor d(21) xor d(20) xor d(14) xor d(11) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(2) xor d(1) xor c(1) xor c(2) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(11) xor c(14) xor c(20) xor c(21) xor c(22) xor c(25) xor c(29) xor c(30);
+    newcrc(7) := d(29) xor d(28) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(16) xor d(15) xor d(10) xor d(8) xor d(7) xor d(5) xor d(3) xor d(2) xor d(0) xor c(0) xor c(2) xor c(3) xor c(5) xor c(7) xor c(8) xor c(10) xor c(15) xor c(16) xor c(21) xor c(22) xor c(23) xor c(24) xor c(25) xor c(28) xor c(29);
+    newcrc(8) := d(31) xor d(28) xor d(23) xor d(22) xor d(17) xor d(12) xor d(11) xor d(10) xor d(8) xor d(4) xor d(3) xor d(1) xor d(0) xor c(0) xor c(1) xor c(3) xor c(4) xor c(8) xor c(10) xor c(11) xor c(12) xor c(17) xor c(22) xor c(23) xor c(28) xor c(31);
+    newcrc(9) := d(29) xor d(24) xor d(23) xor d(18) xor d(13) xor d(12) xor d(11) xor d(9) xor d(5) xor d(4) xor d(2) xor d(1) xor c(1) xor c(2) xor c(4) xor c(5) xor c(9) xor c(11) xor c(12) xor c(13) xor c(18) xor c(23) xor c(24) xor c(29);
+    newcrc(10) := d(31) xor d(29) xor d(28) xor d(26) xor d(19) xor d(16) xor d(14) xor d(13) xor d(9) xor d(5) xor d(3) xor d(2) xor d(0) xor c(0) xor c(2) xor c(3) xor c(5) xor c(9) xor c(13) xor c(14) xor c(16) xor c(19) xor c(26) xor c(28) xor c(29) xor c(31);
+    newcrc(11) := d(31) xor d(28) xor d(27) xor d(26) xor d(25) xor d(24) xor d(20) xor d(17) xor d(16) xor d(15) xor d(14) xor d(12) xor d(9) xor d(4) xor d(3) xor d(1) xor d(0) xor c(0) xor c(1) xor c(3) xor c(4) xor c(9) xor c(12) xor c(14) xor c(15) xor c(16) xor c(17) xor c(20) xor c(24) xor c(25) xor c(26) xor c(27) xor c(28) xor c(31);
+    newcrc(12) := d(31) xor d(30) xor d(27) xor d(24) xor d(21) xor d(18) xor d(17) xor d(15) xor d(13) xor d(12) xor d(9) xor d(6) xor d(5) xor d(4) xor d(2) xor d(1) xor d(0) xor c(0) xor c(1) xor c(2) xor c(4) xor c(5) xor c(6) xor c(9) xor c(12) xor c(13) xor c(15) xor c(17) xor c(18) xor c(21) xor c(24) xor c(27) xor c(30) xor c(31);
+    newcrc(13) := d(31) xor d(28) xor d(25) xor d(22) xor d(19) xor d(18) xor d(16) xor d(14) xor d(13) xor d(10) xor d(7) xor d(6) xor d(5) xor d(3) xor d(2) xor d(1) xor c(1) xor c(2) xor c(3) xor c(5) xor c(6) xor c(7) xor c(10) xor c(13) xor c(14) xor c(16) xor c(18) xor c(19) xor c(22) xor c(25) xor c(28) xor c(31);
+    newcrc(14) := d(29) xor d(26) xor d(23) xor d(20) xor d(19) xor d(17) xor d(15) xor d(14) xor d(11) xor d(8) xor d(7) xor d(6) xor d(4) xor d(3) xor d(2) xor c(2) xor c(3) xor c(4) xor c(6) xor c(7) xor c(8) xor c(11) xor c(14) xor c(15) xor c(17) xor c(19) xor c(20) xor c(23) xor c(26) xor c(29);
+    newcrc(15) := d(30) xor d(27) xor d(24) xor d(21) xor d(20) xor d(18) xor d(16) xor d(15) xor d(12) xor d(9) xor d(8) xor d(7) xor d(5) xor d(4) xor d(3) xor c(3) xor c(4) xor c(5) xor c(7) xor c(8) xor c(9) xor c(12) xor c(15) xor c(16) xor c(18) xor c(20) xor c(21) xor c(24) xor c(27) xor c(30);
+    newcrc(16) := d(30) xor d(29) xor d(26) xor d(24) xor d(22) xor d(21) xor d(19) xor d(17) xor d(13) xor d(12) xor d(8) xor d(5) xor d(4) xor d(0) xor c(0) xor c(4) xor c(5) xor c(8) xor c(12) xor c(13) xor c(17) xor c(19) xor c(21) xor c(22) xor c(24) xor c(26) xor c(29) xor c(30);
+    newcrc(17) := d(31) xor d(30) xor d(27) xor d(25) xor d(23) xor d(22) xor d(20) xor d(18) xor d(14) xor d(13) xor d(9) xor d(6) xor d(5) xor d(1) xor c(1) xor c(5) xor c(6) xor c(9) xor c(13) xor c(14) xor c(18) xor c(20) xor c(22) xor c(23) xor c(25) xor c(27) xor c(30) xor c(31);
+    newcrc(18) := d(31) xor d(28) xor d(26) xor d(24) xor d(23) xor d(21) xor d(19) xor d(15) xor d(14) xor d(10) xor d(7) xor d(6) xor d(2) xor c(2) xor c(6) xor c(7) xor c(10) xor c(14) xor c(15) xor c(19) xor c(21) xor c(23) xor c(24) xor c(26) xor c(28) xor c(31);
+    newcrc(19) := d(29) xor d(27) xor d(25) xor d(24) xor d(22) xor d(20) xor d(16) xor d(15) xor d(11) xor d(8) xor d(7) xor d(3) xor c(3) xor c(7) xor c(8) xor c(11) xor c(15) xor c(16) xor c(20) xor c(22) xor c(24) xor c(25) xor c(27) xor c(29);
+    newcrc(20) := d(30) xor d(28) xor d(26) xor d(25) xor d(23) xor d(21) xor d(17) xor d(16) xor d(12) xor d(9) xor d(8) xor d(4) xor c(4) xor c(8) xor c(9) xor c(12) xor c(16) xor c(17) xor c(21) xor c(23) xor c(25) xor c(26) xor c(28) xor c(30);
+    newcrc(21) := d(31) xor d(29) xor d(27) xor d(26) xor d(24) xor d(22) xor d(18) xor d(17) xor d(13) xor d(10) xor d(9) xor d(5) xor c(5) xor c(9) xor c(10) xor c(13) xor c(17) xor c(18) xor c(22) xor c(24) xor c(26) xor c(27) xor c(29) xor c(31);
+    newcrc(22) := d(31) xor d(29) xor d(27) xor d(26) xor d(24) xor d(23) xor d(19) xor d(18) xor d(16) xor d(14) xor d(12) xor d(11) xor d(9) xor d(0) xor c(0) xor c(9) xor c(11) xor c(12) xor c(14) xor c(16) xor c(18) xor c(19) xor c(23) xor c(24) xor c(26) xor c(27) xor c(29) xor c(31);
+    newcrc(23) := d(31) xor d(29) xor d(27) xor d(26) xor d(20) xor d(19) xor d(17) xor d(16) xor d(15) xor d(13) xor d(9) xor d(6) xor d(1) xor d(0) xor c(0) xor c(1) xor c(6) xor c(9) xor c(13) xor c(15) xor c(16) xor c(17) xor c(19) xor c(20) xor c(26) xor c(27) xor c(29) xor c(31);
+    newcrc(24) := d(30) xor d(28) xor d(27) xor d(21) xor d(20) xor d(18) xor d(17) xor d(16) xor d(14) xor d(10) xor d(7) xor d(2) xor d(1) xor c(1) xor c(2) xor c(7) xor c(10) xor c(14) xor c(16) xor c(17) xor c(18) xor c(20) xor c(21) xor c(27) xor c(28) xor c(30);
+    newcrc(25) := d(31) xor d(29) xor d(28) xor d(22) xor d(21) xor d(19) xor d(18) xor d(17) xor d(15) xor d(11) xor d(8) xor d(3) xor d(2) xor c(2) xor c(3) xor c(8) xor c(11) xor c(15) xor c(17) xor c(18) xor c(19) xor c(21) xor c(22) xor c(28) xor c(29) xor c(31);
+    newcrc(26) := d(31) xor d(28) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(20) xor d(19) xor d(18) xor d(10) xor d(6) xor d(4) xor d(3) xor d(0) xor c(0) xor c(3) xor c(4) xor c(6) xor c(10) xor c(18) xor c(19) xor c(20) xor c(22) xor c(23) xor c(24) xor c(25) xor c(26) xor c(28) xor c(31);
+    newcrc(27) := d(29) xor d(27) xor d(26) xor d(25) xor d(24) xor d(23) xor d(21) xor d(20) xor d(19) xor d(11) xor d(7) xor d(5) xor d(4) xor d(1) xor c(1) xor c(4) xor c(5) xor c(7) xor c(11) xor c(19) xor c(20) xor c(21) xor c(23) xor c(24) xor c(25) xor c(26) xor c(27) xor c(29);
+    newcrc(28) := d(30) xor d(28) xor d(27) xor d(26) xor d(25) xor d(24) xor d(22) xor d(21) xor d(20) xor d(12) xor d(8) xor d(6) xor d(5) xor d(2) xor c(2) xor c(5) xor c(6) xor c(8) xor c(12) xor c(20) xor c(21) xor c(22) xor c(24) xor c(25) xor c(26) xor c(27) xor c(28) xor c(30);
+    newcrc(29) := d(31) xor d(29) xor d(28) xor d(27) xor d(26) xor d(25) xor d(23) xor d(22) xor d(21) xor d(13) xor d(9) xor d(7) xor d(6) xor d(3) xor c(3) xor c(6) xor c(7) xor c(9) xor c(13) xor c(21) xor c(22) xor c(23) xor c(25) xor c(26) xor c(27) xor c(28) xor c(29) xor c(31);
+    newcrc(30) := d(30) xor d(29) xor d(28) xor d(27) xor d(26) xor d(24) xor d(23) xor d(22) xor d(14) xor d(10) xor d(8) xor d(7) xor d(4) xor c(4) xor c(7) xor c(8) xor c(10) xor c(14) xor c(22) xor c(23) xor c(24) xor c(26) xor c(27) xor c(28) xor c(29) xor c(30);
+    newcrc(31) := d(31) xor d(30) xor d(29) xor d(28) xor d(27) xor d(25) xor d(24) xor d(23) xor d(15) xor d(11) xor d(9) xor d(8) xor d(5) xor c(5) xor c(8) xor c(9) xor c(11) xor c(15) xor c(23) xor c(24) xor c(25) xor c(27) xor c(28) xor c(29) xor c(30) xor c(31);
+    return newcrc;
+  end nextCRC32_D32;
+
+end PCK_CRC32_D32;
diff --git a/libraries/external/easics/src/vhdl/PCK_CRC32_D64_eth.vhd b/libraries/external/easics/src/vhdl/PCK_CRC32_D64_eth.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..3e6c4735b1fb47d9cc300dfd8893c4ccbe70f1e9
--- /dev/null
+++ b/libraries/external/easics/src/vhdl/PCK_CRC32_D64_eth.vhd
@@ -0,0 +1,86 @@
+--------------------------------------------------------------------------------
+-- Copyright (C) 1999-2008 Easics NV.
+-- This source file may be used and distributed without restriction
+-- provided that this copyright statement is not removed from the file
+-- and that any derivative work contains the original copyright notice
+-- and the associated disclaimer.
+--
+-- THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+-- OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+-- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+--
+-- Purpose : synthesizable CRC function
+--   * polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+--   * data width: 64
+--
+-- Info : tools@easics.be
+--        http://www.easics.com
+--------------------------------------------------------------------------------
+library ieee;
+use ieee.std_logic_1164.all;
+
+package PCK_CRC32_D64 is
+  -- polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+  -- data width: 64
+  -- convention: the first serial bit is D[63]
+  function nextCRC32_D64
+    (Data: std_logic_vector(63 downto 0);
+     crc:  std_logic_vector(31 downto 0))
+    return std_logic_vector;
+end PCK_CRC32_D64;
+
+
+package body PCK_CRC32_D64 is
+
+  -- polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+  -- data width: 64
+  -- convention: the first serial bit is D[63]
+  function nextCRC32_D64
+    (Data: std_logic_vector(63 downto 0);
+     crc:  std_logic_vector(31 downto 0))
+    return std_logic_vector is
+
+    variable d:      std_logic_vector(63 downto 0);
+    variable c:      std_logic_vector(31 downto 0);
+    variable newcrc: std_logic_vector(31 downto 0);
+
+  begin
+    d := Data;
+    c := crc;
+
+    newcrc(0) := d(63) xor d(61) xor d(60) xor d(58) xor d(55) xor d(54) xor d(53) xor d(50) xor d(48) xor d(47) xor d(45) xor d(44) xor d(37) xor d(34) xor d(32) xor d(31) xor d(30) xor d(29) xor d(28) xor d(26) xor d(25) xor d(24) xor d(16) xor d(12) xor d(10) xor d(9) xor d(6) xor d(0) xor c(0) xor c(2) xor c(5) xor c(12) xor c(13) xor c(15) xor c(16) xor c(18) xor c(21) xor c(22) xor c(23) xor c(26) xor c(28) xor c(29) xor c(31);
+    newcrc(1) := d(63) xor d(62) xor d(60) xor d(59) xor d(58) xor d(56) xor d(53) xor d(51) xor d(50) xor d(49) xor d(47) xor d(46) xor d(44) xor d(38) xor d(37) xor d(35) xor d(34) xor d(33) xor d(28) xor d(27) xor d(24) xor d(17) xor d(16) xor d(13) xor d(12) xor d(11) xor d(9) xor d(7) xor d(6) xor d(1) xor d(0) xor c(1) xor c(2) xor c(3) xor c(5) xor c(6) xor c(12) xor c(14) xor c(15) xor c(17) xor c(18) xor c(19) xor c(21) xor c(24) xor c(26) xor c(27) xor c(28) xor c(30) xor c(31);
+    newcrc(2) := d(59) xor d(58) xor d(57) xor d(55) xor d(53) xor d(52) xor d(51) xor d(44) xor d(39) xor d(38) xor d(37) xor d(36) xor d(35) xor d(32) xor d(31) xor d(30) xor d(26) xor d(24) xor d(18) xor d(17) xor d(16) xor d(14) xor d(13) xor d(9) xor d(8) xor d(7) xor d(6) xor d(2) xor d(1) xor d(0) xor c(0) xor c(3) xor c(4) xor c(5) xor c(6) xor c(7) xor c(12) xor c(19) xor c(20) xor c(21) xor c(23) xor c(25) xor c(26) xor c(27);
+    newcrc(3) := d(60) xor d(59) xor d(58) xor d(56) xor d(54) xor d(53) xor d(52) xor d(45) xor d(40) xor d(39) xor d(38) xor d(37) xor d(36) xor d(33) xor d(32) xor d(31) xor d(27) xor d(25) xor d(19) xor d(18) xor d(17) xor d(15) xor d(14) xor d(10) xor d(9) xor d(8) xor d(7) xor d(3) xor d(2) xor d(1) xor c(0) xor c(1) xor c(4) xor c(5) xor c(6) xor c(7) xor c(8) xor c(13) xor c(20) xor c(21) xor c(22) xor c(24) xor c(26) xor c(27) xor c(28);
+    newcrc(4) := d(63) xor d(59) xor d(58) xor d(57) xor d(50) xor d(48) xor d(47) xor d(46) xor d(45) xor d(44) xor d(41) xor d(40) xor d(39) xor d(38) xor d(33) xor d(31) xor d(30) xor d(29) xor d(25) xor d(24) xor d(20) xor d(19) xor d(18) xor d(15) xor d(12) xor d(11) xor d(8) xor d(6) xor d(4) xor d(3) xor d(2) xor d(0) xor c(1) xor c(6) xor c(7) xor c(8) xor c(9) xor c(12) xor c(13) xor c(14) xor c(15) xor c(16) xor c(18) xor c(25) xor c(26) xor c(27) xor c(31);
+    newcrc(5) := d(63) xor d(61) xor d(59) xor d(55) xor d(54) xor d(53) xor d(51) xor d(50) xor d(49) xor d(46) xor d(44) xor d(42) xor d(41) xor d(40) xor d(39) xor d(37) xor d(29) xor d(28) xor d(24) xor d(21) xor d(20) xor d(19) xor d(13) xor d(10) xor d(7) xor d(6) xor d(5) xor d(4) xor d(3) xor d(1) xor d(0) xor c(5) xor c(7) xor c(8) xor c(9) xor c(10) xor c(12) xor c(14) xor c(17) xor c(18) xor c(19) xor c(21) xor c(22) xor c(23) xor c(27) xor c(29) xor c(31);
+    newcrc(6) := d(62) xor d(60) xor d(56) xor d(55) xor d(54) xor d(52) xor d(51) xor d(50) xor d(47) xor d(45) xor d(43) xor d(42) xor d(41) xor d(40) xor d(38) xor d(30) xor d(29) xor d(25) xor d(22) xor d(21) xor d(20) xor d(14) xor d(11) xor d(8) xor d(7) xor d(6) xor d(5) xor d(4) xor d(2) xor d(1) xor c(6) xor c(8) xor c(9) xor c(10) xor c(11) xor c(13) xor c(15) xor c(18) xor c(19) xor c(20) xor c(22) xor c(23) xor c(24) xor c(28) xor c(30);
+    newcrc(7) := d(60) xor d(58) xor d(57) xor d(56) xor d(54) xor d(52) xor d(51) xor d(50) xor d(47) xor d(46) xor d(45) xor d(43) xor d(42) xor d(41) xor d(39) xor d(37) xor d(34) xor d(32) xor d(29) xor d(28) xor d(25) xor d(24) xor d(23) xor d(22) xor d(21) xor d(16) xor d(15) xor d(10) xor d(8) xor d(7) xor d(5) xor d(3) xor d(2) xor d(0) xor c(0) xor c(2) xor c(5) xor c(7) xor c(9) xor c(10) xor c(11) xor c(13) xor c(14) xor c(15) xor c(18) xor c(19) xor c(20) xor c(22) xor c(24) xor c(25) xor c(26) xor c(28);
+    newcrc(8) := d(63) xor d(60) xor d(59) xor d(57) xor d(54) xor d(52) xor d(51) xor d(50) xor d(46) xor d(45) xor d(43) xor d(42) xor d(40) xor d(38) xor d(37) xor d(35) xor d(34) xor d(33) xor d(32) xor d(31) xor d(28) xor d(23) xor d(22) xor d(17) xor d(12) xor d(11) xor d(10) xor d(8) xor d(4) xor d(3) xor d(1) xor d(0) xor c(0) xor c(1) xor c(2) xor c(3) xor c(5) xor c(6) xor c(8) xor c(10) xor c(11) xor c(13) xor c(14) xor c(18) xor c(19) xor c(20) xor c(22) xor c(25) xor c(27) xor c(28) xor c(31);
+    newcrc(9) := d(61) xor d(60) xor d(58) xor d(55) xor d(53) xor d(52) xor d(51) xor d(47) xor d(46) xor d(44) xor d(43) xor d(41) xor d(39) xor d(38) xor d(36) xor d(35) xor d(34) xor d(33) xor d(32) xor d(29) xor d(24) xor d(23) xor d(18) xor d(13) xor d(12) xor d(11) xor d(9) xor d(5) xor d(4) xor d(2) xor d(1) xor c(0) xor c(1) xor c(2) xor c(3) xor c(4) xor c(6) xor c(7) xor c(9) xor c(11) xor c(12) xor c(14) xor c(15) xor c(19) xor c(20) xor c(21) xor c(23) xor c(26) xor c(28) xor c(29);
+    newcrc(10) := d(63) xor d(62) xor d(60) xor d(59) xor d(58) xor d(56) xor d(55) xor d(52) xor d(50) xor d(42) xor d(40) xor d(39) xor d(36) xor d(35) xor d(33) xor d(32) xor d(31) xor d(29) xor d(28) xor d(26) xor d(19) xor d(16) xor d(14) xor d(13) xor d(9) xor d(5) xor d(3) xor d(2) xor d(0) xor c(0) xor c(1) xor c(3) xor c(4) xor c(7) xor c(8) xor c(10) xor c(18) xor c(20) xor c(23) xor c(24) xor c(26) xor c(27) xor c(28) xor c(30) xor c(31);
+    newcrc(11) := d(59) xor d(58) xor d(57) xor d(56) xor d(55) xor d(54) xor d(51) xor d(50) xor d(48) xor d(47) xor d(45) xor d(44) xor d(43) xor d(41) xor d(40) xor d(36) xor d(33) xor d(31) xor d(28) xor d(27) xor d(26) xor d(25) xor d(24) xor d(20) xor d(17) xor d(16) xor d(15) xor d(14) xor d(12) xor d(9) xor d(4) xor d(3) xor d(1) xor d(0) xor c(1) xor c(4) xor c(8) xor c(9) xor c(11) xor c(12) xor c(13) xor c(15) xor c(16) xor c(18) xor c(19) xor c(22) xor c(23) xor c(24) xor c(25) xor c(26) xor c(27);
+    newcrc(12) := d(63) xor d(61) xor d(59) xor d(57) xor d(56) xor d(54) xor d(53) xor d(52) xor d(51) xor d(50) xor d(49) xor d(47) xor d(46) xor d(42) xor d(41) xor d(31) xor d(30) xor d(27) xor d(24) xor d(21) xor d(18) xor d(17) xor d(15) xor d(13) xor d(12) xor d(9) xor d(6) xor d(5) xor d(4) xor d(2) xor d(1) xor d(0) xor c(9) xor c(10) xor c(14) xor c(15) xor c(17) xor c(18) xor c(19) xor c(20) xor c(21) xor c(22) xor c(24) xor c(25) xor c(27) xor c(29) xor c(31);
+    newcrc(13) := d(62) xor d(60) xor d(58) xor d(57) xor d(55) xor d(54) xor d(53) xor d(52) xor d(51) xor d(50) xor d(48) xor d(47) xor d(43) xor d(42) xor d(32) xor d(31) xor d(28) xor d(25) xor d(22) xor d(19) xor d(18) xor d(16) xor d(14) xor d(13) xor d(10) xor d(7) xor d(6) xor d(5) xor d(3) xor d(2) xor d(1) xor c(0) xor c(10) xor c(11) xor c(15) xor c(16) xor c(18) xor c(19) xor c(20) xor c(21) xor c(22) xor c(23) xor c(25) xor c(26) xor c(28) xor c(30);
+    newcrc(14) := d(63) xor d(61) xor d(59) xor d(58) xor d(56) xor d(55) xor d(54) xor d(53) xor d(52) xor d(51) xor d(49) xor d(48) xor d(44) xor d(43) xor d(33) xor d(32) xor d(29) xor d(26) xor d(23) xor d(20) xor d(19) xor d(17) xor d(15) xor d(14) xor d(11) xor d(8) xor d(7) xor d(6) xor d(4) xor d(3) xor d(2) xor c(0) xor c(1) xor c(11) xor c(12) xor c(16) xor c(17) xor c(19) xor c(20) xor c(21) xor c(22) xor c(23) xor c(24) xor c(26) xor c(27) xor c(29) xor c(31);
+    newcrc(15) := d(62) xor d(60) xor d(59) xor d(57) xor d(56) xor d(55) xor d(54) xor d(53) xor d(52) xor d(50) xor d(49) xor d(45) xor d(44) xor d(34) xor d(33) xor d(30) xor d(27) xor d(24) xor d(21) xor d(20) xor d(18) xor d(16) xor d(15) xor d(12) xor d(9) xor d(8) xor d(7) xor d(5) xor d(4) xor d(3) xor c(1) xor c(2) xor c(12) xor c(13) xor c(17) xor c(18) xor c(20) xor c(21) xor c(22) xor c(23) xor c(24) xor c(25) xor c(27) xor c(28) xor c(30);
+    newcrc(16) := d(57) xor d(56) xor d(51) xor d(48) xor d(47) xor d(46) xor d(44) xor d(37) xor d(35) xor d(32) xor d(30) xor d(29) xor d(26) xor d(24) xor d(22) xor d(21) xor d(19) xor d(17) xor d(13) xor d(12) xor d(8) xor d(5) xor d(4) xor d(0) xor c(0) xor c(3) xor c(5) xor c(12) xor c(14) xor c(15) xor c(16) xor c(19) xor c(24) xor c(25);
+    newcrc(17) := d(58) xor d(57) xor d(52) xor d(49) xor d(48) xor d(47) xor d(45) xor d(38) xor d(36) xor d(33) xor d(31) xor d(30) xor d(27) xor d(25) xor d(23) xor d(22) xor d(20) xor d(18) xor d(14) xor d(13) xor d(9) xor d(6) xor d(5) xor d(1) xor c(1) xor c(4) xor c(6) xor c(13) xor c(15) xor c(16) xor c(17) xor c(20) xor c(25) xor c(26);
+    newcrc(18) := d(59) xor d(58) xor d(53) xor d(50) xor d(49) xor d(48) xor d(46) xor d(39) xor d(37) xor d(34) xor d(32) xor d(31) xor d(28) xor d(26) xor d(24) xor d(23) xor d(21) xor d(19) xor d(15) xor d(14) xor d(10) xor d(7) xor d(6) xor d(2) xor c(0) xor c(2) xor c(5) xor c(7) xor c(14) xor c(16) xor c(17) xor c(18) xor c(21) xor c(26) xor c(27);
+    newcrc(19) := d(60) xor d(59) xor d(54) xor d(51) xor d(50) xor d(49) xor d(47) xor d(40) xor d(38) xor d(35) xor d(33) xor d(32) xor d(29) xor d(27) xor d(25) xor d(24) xor d(22) xor d(20) xor d(16) xor d(15) xor d(11) xor d(8) xor d(7) xor d(3) xor c(0) xor c(1) xor c(3) xor c(6) xor c(8) xor c(15) xor c(17) xor c(18) xor c(19) xor c(22) xor c(27) xor c(28);
+    newcrc(20) := d(61) xor d(60) xor d(55) xor d(52) xor d(51) xor d(50) xor d(48) xor d(41) xor d(39) xor d(36) xor d(34) xor d(33) xor d(30) xor d(28) xor d(26) xor d(25) xor d(23) xor d(21) xor d(17) xor d(16) xor d(12) xor d(9) xor d(8) xor d(4) xor c(1) xor c(2) xor c(4) xor c(7) xor c(9) xor c(16) xor c(18) xor c(19) xor c(20) xor c(23) xor c(28) xor c(29);
+    newcrc(21) := d(62) xor d(61) xor d(56) xor d(53) xor d(52) xor d(51) xor d(49) xor d(42) xor d(40) xor d(37) xor d(35) xor d(34) xor d(31) xor d(29) xor d(27) xor d(26) xor d(24) xor d(22) xor d(18) xor d(17) xor d(13) xor d(10) xor d(9) xor d(5) xor c(2) xor c(3) xor c(5) xor c(8) xor c(10) xor c(17) xor c(19) xor c(20) xor c(21) xor c(24) xor c(29) xor c(30);
+    newcrc(22) := d(62) xor d(61) xor d(60) xor d(58) xor d(57) xor d(55) xor d(52) xor d(48) xor d(47) xor d(45) xor d(44) xor d(43) xor d(41) xor d(38) xor d(37) xor d(36) xor d(35) xor d(34) xor d(31) xor d(29) xor d(27) xor d(26) xor d(24) xor d(23) xor d(19) xor d(18) xor d(16) xor d(14) xor d(12) xor d(11) xor d(9) xor d(0) xor c(2) xor c(3) xor c(4) xor c(5) xor c(6) xor c(9) xor c(11) xor c(12) xor c(13) xor c(15) xor c(16) xor c(20) xor c(23) xor c(25) xor c(26) xor c(28) xor c(29) xor c(30);
+    newcrc(23) := d(62) xor d(60) xor d(59) xor d(56) xor d(55) xor d(54) xor d(50) xor d(49) xor d(47) xor d(46) xor d(42) xor d(39) xor d(38) xor d(36) xor d(35) xor d(34) xor d(31) xor d(29) xor d(27) xor d(26) xor d(20) xor d(19) xor d(17) xor d(16) xor d(15) xor d(13) xor d(9) xor d(6) xor d(1) xor d(0) xor c(2) xor c(3) xor c(4) xor c(6) xor c(7) xor c(10) xor c(14) xor c(15) xor c(17) xor c(18) xor c(22) xor c(23) xor c(24) xor c(27) xor c(28) xor c(30);
+    newcrc(24) := d(63) xor d(61) xor d(60) xor d(57) xor d(56) xor d(55) xor d(51) xor d(50) xor d(48) xor d(47) xor d(43) xor d(40) xor d(39) xor d(37) xor d(36) xor d(35) xor d(32) xor d(30) xor d(28) xor d(27) xor d(21) xor d(20) xor d(18) xor d(17) xor d(16) xor d(14) xor d(10) xor d(7) xor d(2) xor d(1) xor c(0) xor c(3) xor c(4) xor c(5) xor c(7) xor c(8) xor c(11) xor c(15) xor c(16) xor c(18) xor c(19) xor c(23) xor c(24) xor c(25) xor c(28) xor c(29) xor c(31);
+    newcrc(25) := d(62) xor d(61) xor d(58) xor d(57) xor d(56) xor d(52) xor d(51) xor d(49) xor d(48) xor d(44) xor d(41) xor d(40) xor d(38) xor d(37) xor d(36) xor d(33) xor d(31) xor d(29) xor d(28) xor d(22) xor d(21) xor d(19) xor d(18) xor d(17) xor d(15) xor d(11) xor d(8) xor d(3) xor d(2) xor c(1) xor c(4) xor c(5) xor c(6) xor c(8) xor c(9) xor c(12) xor c(16) xor c(17) xor c(19) xor c(20) xor c(24) xor c(25) xor c(26) xor c(29) xor c(30);
+    newcrc(26) := d(62) xor d(61) xor d(60) xor d(59) xor d(57) xor d(55) xor d(54) xor d(52) xor d(49) xor d(48) xor d(47) xor d(44) xor d(42) xor d(41) xor d(39) xor d(38) xor d(31) xor d(28) xor d(26) xor d(25) xor d(24) xor d(23) xor d(22) xor d(20) xor d(19) xor d(18) xor d(10) xor d(6) xor d(4) xor d(3) xor d(0) xor c(6) xor c(7) xor c(9) xor c(10) xor c(12) xor c(15) xor c(16) xor c(17) xor c(20) xor c(22) xor c(23) xor c(25) xor c(27) xor c(28) xor c(29) xor c(30);
+    newcrc(27) := d(63) xor d(62) xor d(61) xor d(60) xor d(58) xor d(56) xor d(55) xor d(53) xor d(50) xor d(49) xor d(48) xor d(45) xor d(43) xor d(42) xor d(40) xor d(39) xor d(32) xor d(29) xor d(27) xor d(26) xor d(25) xor d(24) xor d(23) xor d(21) xor d(20) xor d(19) xor d(11) xor d(7) xor d(5) xor d(4) xor d(1) xor c(0) xor c(7) xor c(8) xor c(10) xor c(11) xor c(13) xor c(16) xor c(17) xor c(18) xor c(21) xor c(23) xor c(24) xor c(26) xor c(28) xor c(29) xor c(30) xor c(31);
+    newcrc(28) := d(63) xor d(62) xor d(61) xor d(59) xor d(57) xor d(56) xor d(54) xor d(51) xor d(50) xor d(49) xor d(46) xor d(44) xor d(43) xor d(41) xor d(40) xor d(33) xor d(30) xor d(28) xor d(27) xor d(26) xor d(25) xor d(24) xor d(22) xor d(21) xor d(20) xor d(12) xor d(8) xor d(6) xor d(5) xor d(2) xor c(1) xor c(8) xor c(9) xor c(11) xor c(12) xor c(14) xor c(17) xor c(18) xor c(19) xor c(22) xor c(24) xor c(25) xor c(27) xor c(29) xor c(30) xor c(31);
+    newcrc(29) := d(63) xor d(62) xor d(60) xor d(58) xor d(57) xor d(55) xor d(52) xor d(51) xor d(50) xor d(47) xor d(45) xor d(44) xor d(42) xor d(41) xor d(34) xor d(31) xor d(29) xor d(28) xor d(27) xor d(26) xor d(25) xor d(23) xor d(22) xor d(21) xor d(13) xor d(9) xor d(7) xor d(6) xor d(3) xor c(2) xor c(9) xor c(10) xor c(12) xor c(13) xor c(15) xor c(18) xor c(19) xor c(20) xor c(23) xor c(25) xor c(26) xor c(28) xor c(30) xor c(31);
+    newcrc(30) := d(63) xor d(61) xor d(59) xor d(58) xor d(56) xor d(53) xor d(52) xor d(51) xor d(48) xor d(46) xor d(45) xor d(43) xor d(42) xor d(35) xor d(32) xor d(30) xor d(29) xor d(28) xor d(27) xor d(26) xor d(24) xor d(23) xor d(22) xor d(14) xor d(10) xor d(8) xor d(7) xor d(4) xor c(0) xor c(3) xor c(10) xor c(11) xor c(13) xor c(14) xor c(16) xor c(19) xor c(20) xor c(21) xor c(24) xor c(26) xor c(27) xor c(29) xor c(31);
+    newcrc(31) := d(62) xor d(60) xor d(59) xor d(57) xor d(54) xor d(53) xor d(52) xor d(49) xor d(47) xor d(46) xor d(44) xor d(43) xor d(36) xor d(33) xor d(31) xor d(30) xor d(29) xor d(28) xor d(27) xor d(25) xor d(24) xor d(23) xor d(15) xor d(11) xor d(9) xor d(8) xor d(5) xor c(1) xor c(4) xor c(11) xor c(12) xor c(14) xor c(15) xor c(17) xor c(20) xor c(21) xor c(22) xor c(25) xor c(27) xor c(28) xor c(30);
+    return newcrc;
+  end nextCRC32_D64;
+
+end PCK_CRC32_D64;
diff --git a/libraries/io/ddr/ddr.peripheral.yaml b/libraries/io/ddr/ddr.peripheral.yaml
index b2cbd21a659e3682d4ca23512caee423de5bbb86..98a9f8b2e2e0f4cf64617a5608dcd9d63c19ec1f 100644
--- a/libraries/io/ddr/ddr.peripheral.yaml
+++ b/libraries/io/ddr/ddr.peripheral.yaml
@@ -18,8 +18,10 @@ peripherals:
         fields:
           - - field_name: reg_io_ddr 
               field_description: |
-                "IO DDR status bits concatenated: 
-                 ctlr_tech_mosi.wr & ctlr_tech_miso.rdval & ctlr_tech_miso.cal_fail      & ctlr_tech_miso.cal_ok 
+                "IO DDR status bits concatenated:
+                 ddr_gigabytes[7:0] &
+                 ctlr_nof_bytes_per_word[7:0] &
+                 ctlr_tech_mosi.wr & ctlr_tech_miso.rdval & ctlr_tech_miso.cal_fail      & ctlr_tech_miso.cal_ok &
                  ctlr_rst_out_i    & ctlr_wr_flush_en     & ctlr_tech_miso.waitrequest_n & ctlr_tech_miso.done"
               address_offset: 0 * MM_BUS_SIZE
               access_mode: RO
diff --git a/libraries/io/ddr/hdllib.cfg b/libraries/io/ddr/hdllib.cfg
index 8bb8fa2a509c1298653e8d937fca1f57a27d32b7..9ff95327eb81213177806dab86152e81c2270f3a 100644
--- a/libraries/io/ddr/hdllib.cfg
+++ b/libraries/io/ddr/hdllib.cfg
@@ -28,6 +28,7 @@ modelsim_compile_ip_files =
     $HDL_WORK/libraries/technology/ip_arria10_e1sg/ddr4_4g_1600/copy_hex_files.tcl          # Unb2b 4GB DDR4 driver
     $HDL_WORK/libraries/technology/ip_arria10_e1sg/ddr4_8g_1600/copy_hex_files.tcl          # Unb2b 8GB DDR4 driver
     $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_8g_1600/copy_hex_files.tcl          # Unb2c 8GB DDR4 driver
-
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_64b/copy_hex_files.tcl   # Unb2c 16GB-64b DDR4 driver
+    $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_72b/copy_hex_files.tcl   # Unb2c 16GB-72b DDR4 driver
 
 [quartus_project_file]
diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd
index aee6a046f1ff815f50906b1f9a191255d4542aab..78c7bd3c0780d789b4f968750c8ebb0f09cbcecd 100644
--- a/libraries/io/ddr/src/vhdl/io_ddr.vhd
+++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd
@@ -234,6 +234,9 @@ ARCHITECTURE str OF io_ddr IS
   CONSTANT c_wr_use_ctrl       : BOOLEAN := sel_a_b(g_wr_flush_mode="SOP", TRUE, FALSE);
   CONSTANT c_wr_fifo_use_ctrl  : BOOLEAN := c_wr_use_sync OR c_wr_use_ctrl;
   
+  CONSTANT c_ddr_gigabytes           : NATURAL := func_tech_ddr_module_size(g_tech_ddr);  -- units GiByte
+  CONSTANT c_ctlr_nof_bytes_per_word : NATURAL := func_tech_ddr_ctlr_ip_data_w(g_tech_ddr) / c_byte_w;  -- unit byte
+
   CONSTANT c_ctlr_address_w    : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr);
   CONSTANT c_ctlr_data_w       : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr);
   CONSTANT c_wr_fifo_depth     : NATURAL := g_wr_fifo_depth * (c_ctlr_data_w/g_wr_data_w);  -- get FIFO depth at write side
@@ -520,7 +523,9 @@ BEGIN
   mm_reg_io_ddr <= RESIZE_UVEC(rd_fifo_full_reg & wr_fifo_full_reg, c_mem_reg_dat_w) & 
                    RESIZE_UVEC(ctlr_wr_fifo_usedw, c_mem_reg_dat_w) & 
                    RESIZE_UVEC(ctlr_rd_fifo_usedw, c_mem_reg_dat_w) & 
-                   RESIZE_UVEC(ctlr_tech_mosi.wr & ctlr_tech_miso.rdval & ctlr_tech_miso.cal_fail      & ctlr_tech_miso.cal_ok & 
+                   RESIZE_UVEC(TO_UVEC(c_ddr_gigabytes, 8) &
+                               TO_UVEC(c_ctlr_nof_bytes_per_word, 8) &
+                               ctlr_tech_mosi.wr & ctlr_tech_miso.rdval & ctlr_tech_miso.cal_fail      & ctlr_tech_miso.cal_ok &
                                ctlr_rst_out_i    & ctlr_wr_flush_en     & ctlr_tech_miso.waitrequest_n & ctlr_tech_miso.done, c_mem_reg_dat_w);   
   
   u_reg_map : ENTITY common_lib.common_reg_r_w_dc
diff --git a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
index fdb97c7b1131c59a73c79dab71526e3afeab94b0..eac49482da7a7b38127631a97b3feea871207b58 100644
--- a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
+++ b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd
@@ -46,7 +46,9 @@ ENTITY tb_io_ddr IS
     g_sim_model             : BOOLEAN := TRUE;  --FALSE;
     g_technology            : NATURAL := c_tech_select_default;
     g_tech_ddr3             : t_c_tech_ddr := c_tech_ddr3_4g_800m_master;
-    g_tech_ddr4             : t_c_tech_ddr := c_tech_ddr4_4g_1600m;
+    --g_tech_ddr4             : t_c_tech_ddr := c_tech_ddr4_4g_1600m;
+    g_tech_ddr4             : t_c_tech_ddr := c_tech_ddr4_16g_1600m_64;
+    --g_tech_ddr4             : t_c_tech_ddr := c_tech_ddr4_16g_1600m_72_64;
     g_tb_end                : BOOLEAN := TRUE;   -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation
     g_cross_domain_dvr_ctlr : BOOLEAN := TRUE;   -- when TRUE insert clock cross domain logic and also insert clock cross domain logic when g_dvr_clk_period/=c_ctlr_clk_period
     g_dvr_clk_period        : TIME := 5 ns;      -- 200 MHz
@@ -70,7 +72,8 @@ ARCHITECTURE str of tb_io_ddr IS
   CONSTANT c_sim_ddr                  : t_c_tech_ddr := func_tech_sel_ddr(g_technology, c_tech_ddr3_sim_16k, c_tech_ddr4_sim_16k);
   CONSTANT c_tech_ddr                 : t_c_tech_ddr := func_tech_sel_ddr(g_sim_model, c_sim_ddr, c_mem_ddr);
   
-  CONSTANT c_gigabytes                : NATURAL := func_tech_ddr_module_size(c_tech_ddr);
+  CONSTANT c_exp_gigabytes            : NATURAL := func_tech_ddr_module_size(c_tech_ddr);
+  CONSTANT c_exp_nof_bytes_per_word   : NATURAL := func_tech_ddr_ctlr_ip_data_w(c_tech_ddr) / c_byte_w;
 
   CONSTANT c_dp_clk_period            : TIME := 5 ns;   -- 200 MHz
   CONSTANT c_mm_clk_period            : TIME := 8 ns;   -- 125 MHz
@@ -163,7 +166,10 @@ ARCHITECTURE str of tb_io_ddr IS
   SIGNAL dbg_c_ctlr_wr_not_rd_arr     : STD_LOGIC_VECTOR(0 TO c_nof_access-1)  := c_ctlr_wr_not_rd_arr;
   
   SIGNAL dbg_c_tech_ddr               : t_c_tech_ddr := c_tech_ddr;
-  SIGNAL dbg_c_gigabytes              : NATURAL := c_gigabytes;  -- = 0 for sim model, else nof GB
+  SIGNAL dbg_c_exp_gigabytes          : NATURAL := c_exp_gigabytes;  -- = 0 for sim model, else nof GB
+  SIGNAL ddr_gigabytes                : NATURAL;
+  SIGNAL dbg_c_exp_nof_bytes_per_word : NATURAL := c_exp_nof_bytes_per_word;
+  SIGNAL ctlr_nof_bytes_per_word      : NATURAL;
   SIGNAL dbg_c_dp_data_w              : NATURAL := c_dp_data_w;
   SIGNAL dbg_c_wr_fifo_depth          : NATURAL := c_wr_fifo_depth;
   SIGNAL dbg_c_rd_fifo_depth          : NATURAL := c_rd_fifo_depth;
@@ -180,12 +186,14 @@ ARCHITECTURE str of tb_io_ddr IS
   SIGNAL mm_clk               : STD_LOGIC := '0';
   SIGNAL mm_rst               : STD_LOGIC;
 
+  -- Status interface
+  SIGNAL reg_io_ddr_mosi      : t_mem_mosi := c_mem_mosi_rst;
+  SIGNAL reg_io_ddr_miso      : t_mem_miso := c_mem_miso_rst;
+
+  -- Driver interface
   SIGNAL dvr_miso             : t_mem_ctlr_miso;
   SIGNAL dvr_mosi             : t_mem_ctlr_mosi;   
   
-  SIGNAL reg_io_ddr_mosi      : t_mem_mosi := c_mem_mosi_rst;           
-  SIGNAL reg_io_ddr_miso      : t_mem_miso := c_mem_miso_rst;           
-  
   SIGNAL dvr_done             : STD_LOGIC;
   SIGNAL dvr_en               : STD_LOGIC;
   SIGNAL dvr_wr_not_rd        : STD_LOGIC;
@@ -258,8 +266,22 @@ BEGIN
     WAIT FOR 100 ns;
     ctlr_ref_rst      <= '0';
 
+    -- Wait until calibration done (and ctlr_rst released)
     proc_common_wait_until_high(dvr_clk, dvr_done);
     
+    -- Read DDR4 memory status
+    proc_common_wait_cross_clock_domain_latency(mm_clk, dp_clk);
+    proc_mem_mm_bus_rd(0, mm_clk, reg_io_ddr_miso, reg_io_ddr_mosi);
+    proc_mem_mm_bus_rd_latency(1, mm_clk);
+    -- . verify ddr_gigabytes
+    ddr_gigabytes <= TO_UINT(reg_io_ddr_miso.rddata(23 DOWNTO 16));
+    proc_common_wait_some_cycles(mm_clk, 1);
+    ASSERT ddr_gigabytes = c_exp_gigabytes REPORT "Wrong read ddr_gigabytes" SEVERITY ERROR;
+    -- . verify ctlr_nof_bytes_per_word
+    ctlr_nof_bytes_per_word  <= TO_UINT(reg_io_ddr_miso.rddata(15 DOWNTO 8));
+    proc_common_wait_some_cycles(mm_clk, 1);
+    ASSERT ctlr_nof_bytes_per_word = c_exp_nof_bytes_per_word REPORT "Wrong read ctlr_nof_bytes_per_word" SEVERITY ERROR;
+
     -- Start diagnostics source for write and sink for verify read
     proc_common_wait_some_cycles(dp_clk, 1);
     src_diag_en <= '1';