diff --git a/libraries/dsp/st/hdllib.cfg b/libraries/dsp/st/hdllib.cfg
index faba09d3db7d4382948bb971bffd4a62e111bcd4..8b4e7ddfb49e185f428e9f73085d935dfbda8f80 100644
--- a/libraries/dsp/st/hdllib.cfg
+++ b/libraries/dsp/st/hdllib.cfg
@@ -10,7 +10,9 @@ synth_files =
     src/vhdl/st_calc.vhd 
     src/vhdl/st_sst.vhd 
     src/vhdl/st_xsq.vhd 
-    src/vhdl/st_xsq_arr.vhd 
+    src/vhdl/st_xsq_arr.vhd
+    src/vhdl/st_xsq_mm_to_dp.vhd 
+    src/vhdl/st_xst.vhd 
 #    src/vhdl/st_top.vhd 
     src/vhdl/st_histogram.vhd
     src/vhdl/st_histogram_reg.vhd
@@ -25,6 +27,8 @@ test_bench_files =
     tb/vhdl/tb_mmf_st_sst.vhd
     tb/vhdl/tb_st_xsq.vhd
     tb/vhdl/tb_tb_st_xsq.vhd
+    tb/vhdl/tb_st_xst.vhd
+    tb/vhdl/tb_tb_st_xst.vhd
     tb/vhdl/tb_st_histogram.vhd
     tb/vhdl/tb_mms_st_histogram.vhd
     tb/vhdl/tb_tb_st_histogram.vhd
@@ -32,6 +36,7 @@ test_bench_files =
 regression_test_vhdl = 
     tb/vhdl/tb_st_acc.vhd 
     tb/vhdl/tb_tb_st_xsq.vhd
+    tb/vhdl/tb_tb_st_xst.vhd
     #tb/vhdl/tb_st_calc.vhd   -- tb is not self checking yet
 
 
diff --git a/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd b/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..0327d6162cd04d63f778800b4d4b2b04422743c3
--- /dev/null
+++ b/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd
@@ -0,0 +1,146 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2021
+-- 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:
+-- . Read a block of xsq data with size (g_nof_crosslets * g_nof_signal_inputs) 
+--   from memory mapped (MM) location and stream it as a block of data of 
+--   size g_nof_crosslets * g_nof_signal_inputs **2.
+-- Description:
+-- After every in_sosi.sop the st_xsq_mm_to_dp.vhd reads blocks of data 
+-- via g_nof_streams mm and outputs it as g_nof_streams parallel streams via 
+-- out_sosi_arr. In_sosi.sync is passed on to out_sosi.
+-- --------------------------------------------------------------------------
+
+LIBRARY IEEE,common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+
+ENTITY st_xsq_mm_to_dp IS
+  GENERIC (
+    g_nof_streams        : NATURAL;
+    g_nof_crosslets      : NATURAL;
+    g_nof_signal_inputs  : NATURAL;
+    g_dsp_data_w         : NATURAL := 16
+  ); 
+  PORT (
+    rst           : IN  STD_LOGIC;
+    clk           : IN  STD_LOGIC;
+    in_sosi       : IN  t_dp_sosi; -- sop used as start signal
+    mm_mosi_arr   : OUT t_mem_mosi_arr(g_nof_streams -1 DOWNTO 0);
+    mm_miso_arr   : IN  t_mem_miso_arr(g_nof_streams -1 DOWNTO 0);
+    out_sosi_arr  : OUT t_dp_sosi_arr(g_nof_streams -1 DOWNTO 0)
+  );
+END st_xsq_mm_to_dp;
+
+
+ARCHITECTURE rtl OF st_xsq_mm_to_dp IS 
+
+  TYPE t_reg IS RECORD
+    in_sosi_strobe  : t_dp_sosi;
+    out_sosi_ctrl   : t_dp_sosi;
+    busy            : STD_LOGIC;
+    crosslets_index : NATURAL;
+    in_a_index      : NATURAL;
+    in_b_index      : NATURAL;
+  END RECORD;
+
+  CONSTANT c_reg_rst : t_reg := (c_dp_sosi_rst, c_dp_sosi_rst, '0', 0, 0, 0);
+
+  SIGNAL r       : t_reg;
+  SIGNAL nxt_r   : t_reg;
+  SIGNAL mm_mosi : t_mem_mosi := c_mem_mosi_rst;
+
+BEGIN
+
+  mm_mosi_arr <= (OTHERS => mm_mosi); -- all mosi are identical.
+
+  u_sosi : PROCESS(r, mm_miso_arr)
+  BEGIN
+    FOR I IN 0 TO g_nof_streams-1 LOOP
+      out_sosi_arr(I)       <= r.out_sosi_ctrl;
+      out_sosi_arr(I).re    <= RESIZE_DP_DSP_DATA(mm_miso_arr(I).rddata(g_dsp_data_w-1 DOWNTO 0));
+      out_sosi_arr(I).im    <= RESIZE_DP_DSP_DATA(mm_miso_arr(I).rddata(c_nof_complex * g_dsp_data_w -1 DOWNTO g_dsp_data_w));
+      out_sosi_arr(I).valid <= mm_miso_arr(I).rdval;  -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so same as the ready latency (RL = 1)
+    END LOOP;
+  END PROCESS;
+  
+  p_reg : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      r <= c_reg_rst;
+    ELSIF rising_edge(clk) THEN
+      r <= nxt_r;
+    END IF;
+  END PROCESS;
+
+  p_comb : PROCESS(r, in_sosi)
+    VARIABLE v : t_reg;
+  BEGIN
+    v := r;
+    v.out_sosi_ctrl := c_dp_sosi_rst;
+    mm_mosi.rd <= '0';
+
+    -- initiate next block and capture in_sosi strobe
+    IF r.busy = '0' AND in_sosi.sop = '1' THEN
+      v.busy := '1';
+      v.in_sosi_strobe := in_sosi;
+    ELSIF r.busy = '1' THEN
+      -- continue with block
+      mm_mosi.rd <= '1';
+      mm_mosi.address <= TO_MEM_ADDRESS(r.crosslets_index * g_nof_signal_inputs + r.in_b_index); -- streams iterate over in_b_index
+
+      -- Indices counters to select data order
+      IF r.in_b_index < g_nof_signal_inputs - 1 THEN
+        v.in_b_index := r.in_b_index + 1;
+      ELSE
+        v.in_b_index := 0;
+        IF r.in_a_index < g_nof_signal_inputs - 1 THEN
+          v.in_a_index := r.in_a_index + 1;
+        ELSE
+          v.in_a_index := 0;    
+          IF r.crosslets_index < g_nof_crosslets - 1 THEN
+            v.crosslets_index := r.crosslets_index + 1;
+          ELSE
+            v.crosslets_index := 0;    
+          END IF;     
+        END IF;      
+      END IF;
+      
+      -- check start of block
+      IF r.crosslets_index = 0 AND r.in_a_index = 0 AND r.in_b_index = 0 THEN
+        v.out_sosi_ctrl.sop  := '1';
+        v.out_sosi_ctrl.sync := r.in_sosi_strobe.sync;
+        v.out_sosi_ctrl.bsn  := r.in_sosi_strobe.bsn;
+      END IF;
+      
+      -- check end of block
+      IF r.crosslets_index >= (g_nof_crosslets - 1) AND r.in_a_index >= (g_nof_signal_inputs - 1)  AND r.in_b_index >= (g_nof_signal_inputs - 1) THEN
+        v.out_sosi_ctrl.eop := '1';
+        v.out_sosi_ctrl.err  := r.in_sosi_strobe.err;
+        v.busy := '0';
+      END IF;
+    END IF;
+    nxt_r <= v;
+  END PROCESS;
+    
+END rtl;
diff --git a/libraries/dsp/st/src/vhdl/st_xst.vhd b/libraries/dsp/st/src/vhdl/st_xst.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..ba841158b07c5399cc8468ae5a96089e98ef9742
--- /dev/null
+++ b/libraries/dsp/st/src/vhdl/st_xst.vhd
@@ -0,0 +1,194 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2021
+-- 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:
+-- Calculate Crosslets Statistics
+-- Description:                                                          
+-- Consists of st_xsq_mm_to_dp connected to st_xsq_arr. in_b_arr comes directly
+-- from st_xsq_mm_to_dp but all streams in in_a_arr are x_sosi_arr(0) with corrected
+-- indices done by a process.
+-- Remarks:
+--  . More detail, see:
+--    https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+Correlator 
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, mm_lib, technology_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_field_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+ENTITY st_xst IS
+  GENERIC (
+    g_nof_streams       : NATURAL := 1;
+    g_nof_crosslets     : NATURAL := 1;
+    g_nof_signal_inputs : NATURAL := 2;
+    g_in_data_w         : NATURAL := 18;    -- width of the data to be accumulated
+    g_stat_data_w       : NATURAL := 54;    -- statistics accumulator width
+    g_stat_data_sz      : NATURAL := 2      -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words
+  );                
+  PORT (            
+    mm_rst : IN  STD_LOGIC;
+    mm_clk : IN  STD_LOGIC;
+    dp_rst : IN  STD_LOGIC;
+    dp_clk : IN  STD_LOGIC;
+                    
+    -- Streaming    
+    in_sosi : IN  t_dp_sosi; 
+
+    -- DP Memory Mapped
+    mm_mosi_arr : OUT t_mem_mosi_arr(g_nof_streams -1 DOWNTO 0);
+    mm_miso_arr : IN  t_mem_miso_arr(g_nof_streams -1 DOWNTO 0);
+
+    -- MM Memory Mapped
+    ram_st_xsq_mosi : IN  t_mem_mosi;  
+    ram_st_xsq_miso : OUT t_mem_miso
+  );
+END st_xst;
+
+ARCHITECTURE str OF st_xst IS
+
+  CONSTANT c_xsq : NATURAL := g_nof_signal_inputs * g_nof_signal_inputs;
+  CONSTANT c_nof_statistics : NATURAL := g_nof_crosslets * c_xsq;
+  CONSTANT c_nof_word     : NATURAL := g_stat_data_sz*c_nof_statistics*c_nof_complex;
+  CONSTANT c_nof_word_w   : NATURAL := ceil_log2(c_nof_word);
+
+  TYPE t_reg IS RECORD
+    busy            : STD_LOGIC;
+    in_a_index      : NATURAL;
+    in_b_index      : NATURAL;
+  END RECORD;
+
+  CONSTANT c_reg_rst : t_reg := ('0', 0, 0);
+
+  SIGNAL r     : t_reg;
+  SIGNAL nxt_r : t_reg;
+
+  SIGNAL in_a_sosi_arr :  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL in_b_sosi_arr :  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+  SIGNAL x_sosi_arr :  t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
+  
+  SIGNAL reg_x_sosi_0_re : t_slv_64_arr(g_nof_signal_inputs-1 DOWNTO 0);
+  SIGNAL reg_x_sosi_0_im : t_slv_64_arr(g_nof_signal_inputs-1 DOWNTO 0);
+BEGIN
+
+  -- MM -> DP
+  st_xsq_mm_to_dp : ENTITY work.st_xsq_mm_to_dp
+  GENERIC MAP(
+    g_nof_streams       => g_nof_streams, 
+    g_nof_crosslets     => g_nof_crosslets, 
+    g_nof_signal_inputs => g_nof_signal_inputs, 
+    g_dsp_data_w        => g_in_data_w 
+  ) 
+  PORT MAP(
+    rst          => dp_rst,        
+    clk          => dp_clk, 
+    in_sosi      => in_sosi, 
+    mm_mosi_arr  => mm_mosi_arr, 
+    mm_miso_arr  => mm_miso_arr, 
+    out_sosi_arr => x_sosi_arr 
+  );
+
+  -- in_b_sosi_arr = x_sosi_arr
+  in_b_sosi_arr <= x_sosi_arr;
+
+  -- Capture x_sosi_arr(0) data
+  reg_x_sosi_0_re(nxt_r.in_b_index) <= x_sosi_arr(0).re;
+  reg_x_sosi_0_im(nxt_r.in_b_index) <= x_sosi_arr(0).im;
+
+  -- reorder x_sosi_arr(0) data to follow in_a_index instead of in_b_index. All sosi in in_a_sosi_arr are identical.
+  p_in_a : PROCESS(x_sosi_arr, reg_x_sosi_0_re, reg_x_sosi_0_im, nxt_r.in_a_index)
+  BEGIN
+    FOR I IN 0 TO g_nof_streams-1 LOOP
+      in_a_sosi_arr(I) <= x_sosi_arr(0);
+      in_a_sosi_arr(I).re <= reg_x_sosi_0_re(nxt_r.in_a_index);
+      in_a_sosi_arr(I).im <= reg_x_sosi_0_im(nxt_r.in_a_index);
+    END LOOP;
+  END PROCESS;
+
+  -- Register process
+  p_reg : PROCESS(dp_rst, dp_clk)
+  BEGIN
+    IF dp_rst='1' THEN
+      r <= c_reg_rst;
+    ELSIF rising_edge(dp_clk) THEN
+      r <= nxt_r;
+    END IF;
+  END PROCESS;
+
+  -- Combinatorial process to create in_a_index and in_b_index for reoredering x_sosi_arr(0) data.
+  p_comb : PROCESS(r, x_sosi_arr)
+    VARIABLE v : t_reg;
+  BEGIN
+    v := r;
+    -- initiate next block
+    IF r.busy = '0' AND x_sosi_arr(0).sop = '1' THEN
+      v.busy := '1';
+    -- Continue block
+    ELSIF r.busy = '1' THEN
+      -- Indices counters to select data order
+      IF r.in_b_index < g_nof_signal_inputs - 1 THEN
+        v.in_b_index := r.in_b_index + 1;
+      ELSE
+        v.in_b_index := 0;
+        IF r.in_a_index < g_nof_signal_inputs - 1 THEN
+          v.in_a_index := r.in_a_index + 1;
+        ELSE
+          v.in_a_index := 0;    
+        END IF;      
+      END IF;
+    END IF;
+    -- End of block
+    IF x_sosi_arr(0).eop = '1' THEN
+      v.busy := '0';
+      v.in_a_index := 0;
+      v.in_b_index := 0;
+    END IF;
+    nxt_r <= v;
+  END PROCESS;
+
+  -- st_xsq instances
+  st_xsq_arr : ENTITY work.st_xsq_arr 
+  GENERIC MAP (
+    g_nof_streams       => g_nof_streams,
+    g_nof_crosslets     => g_nof_crosslets,
+    g_nof_signal_inputs => g_nof_signal_inputs,
+    g_in_data_w         => g_in_data_w,   
+    g_stat_data_w       => g_stat_data_w,      
+    g_stat_data_sz      => g_stat_data_sz     
+  )
+  PORT MAP (
+
+    mm_rst => mm_rst, 
+    mm_clk => mm_clk, 
+    dp_rst => dp_rst, 
+    dp_clk => dp_clk, 
+             
+    -- Streaming    
+    in_a_arr => in_a_sosi_arr,  
+    in_b_arr => in_b_sosi_arr,  
+    
+    -- Memory Mapped
+    ram_st_xsq_mosi => ram_st_xsq_mosi, 
+    ram_st_xsq_miso => ram_st_xsq_miso 
+  );
+
+  
+END str;
diff --git a/libraries/dsp/st/tb/vhdl/tb_st_xst.vhd b/libraries/dsp/st/tb/vhdl/tb_st_xst.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..53d63fe0aa937b6241052077a3594b7e99193d8c
--- /dev/null
+++ b/libraries/dsp/st/tb/vhdl/tb_st_xst.vhd
@@ -0,0 +1,280 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2021
+-- 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:  Testbench for the st_xst unit. 
+--
+-- Usage in non-auto-mode (c_modelsim_start = 0 in python):
+--   > as 5
+--   > run -all
+-- Description: 
+-- The tb generates random data to feed into st_xst. The output is compared to
+-- a pre-calculated expected array of xsq values.
+-- Remark:
+-- . More detail can be found in:
+--   https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+Correlator
+
+LIBRARY IEEE, common_lib, mm_lib, diag_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_math_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.common_str_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL;
+USE common_lib.common_lfsr_sequences_pkg.ALL;
+USE mm_lib.mm_file_unb_pkg.ALL;
+USE mm_lib.mm_file_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL; 
+USE diag_lib.diag_pkg.ALL; 
+USE dp_lib.tb_dp_pkg.ALL;
+USE work.tb_st_pkg.ALL;
+
+ENTITY tb_st_xst IS 
+  GENERIC(
+    g_nof_streams        : NATURAL := 9; 
+    g_nof_crosslets      : NATURAL := 2; 
+    g_nof_signal_inputs  : NATURAL := 12;  
+    g_in_data_w          : NATURAL := 16;
+    g_nof_sync           : NATURAL := 3;
+    g_stat_data_w        : NATURAL := 64;  -- statistics accumulator width
+    g_stat_data_sz       : NATURAL := 2;   -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words
+    g_nof_block_per_sync : NATURAL := 5;
+    g_nof_clk_per_blk    : NATURAL := 1024
+  );
+END tb_st_xst;
+
+ARCHITECTURE tb OF tb_st_xst IS
+  
+  CONSTANT c_sim                     : BOOLEAN := TRUE;
+  CONSTANT c_rl                      : NATURAL := 1;
+  CONSTANT c_block_size              : NATURAL := g_nof_crosslets * g_nof_signal_inputs;
+  CONSTANT c_random_data_w           : NATURAL := 8;
+  CONSTANT c_xsq                     : NATURAL := g_nof_signal_inputs * g_nof_signal_inputs;
+  CONSTANT c_nof_statistics          : NATURAL := g_nof_crosslets * c_xsq;
+  CONSTANT c_nof_statistics_w        : NATURAL := ceil_log2(c_nof_statistics);
+  CONSTANT c_nof_statistics_mem_size : NATURAL := c_nof_complex * 2**c_nof_statistics_w;
+  CONSTANT c_single_stream_mem_size  : NATURAL := c_nof_complex * c_nof_statistics * g_stat_data_sz;
+  CONSTANT c_total_mem_size          : NATURAL := g_nof_streams * c_nof_statistics_mem_size * g_stat_data_sz;
+  CONSTANT c_random_seed             : NATURAL := 100;
+
+  CONSTANT c_mm_ram   : t_c_mem := (latency  => 1,
+                                    adr_w    => ceil_log2(c_block_size),
+                                    dat_w    => c_nof_complex * g_in_data_w,
+                                    nof_dat  => c_block_size,
+                                    init_sl  => '0');           -- MM side : sla_in, sla_out
+
+  TYPE t_random_in_2arr IS ARRAY (INTEGER RANGE <>) OF t_integer_arr(0 TO c_block_size-1); 
+  TYPE t_xsq_2arr       IS ARRAY (INTEGER RANGE <>) OF t_integer_arr(0 TO c_nof_statistics * c_nof_complex-1); 
+  TYPE t_xsq_out_2arr   IS ARRAY (INTEGER RANGE <>) OF t_slv_32_arr(0 TO c_single_stream_mem_size-1); 
+
+  SIGNAL random_in_re_2arr : t_random_in_2arr(0 TO g_nof_streams-1);
+  SIGNAL random_in_im_2arr : t_random_in_2arr(0 TO g_nof_streams-1);
+  SIGNAL expected_xsq_2arr : t_xsq_2arr(0 TO g_nof_streams-1);
+
+  ----------------------------------------------------------------------------
+  -- Clocks and resets
+  ----------------------------------------------------------------------------   
+  CONSTANT c_mm_clk_period  : TIME := 100 ps;
+  CONSTANT c_dp_clk_period  : TIME := 5 ns;
+
+  SIGNAL tb_end             : STD_LOGIC;
+
+  SIGNAL mm_rst             : STD_LOGIC := '1';
+  SIGNAL mm_clk             : STD_LOGIC := '1';
+
+  SIGNAL dp_rst             : STD_LOGIC;
+  SIGNAL dp_clk             : STD_LOGIC := '1';
+
+  SIGNAL in_sosi            : t_dp_sosi := c_dp_sosi_rst;
+
+  ----------------------------------------------------------------------------
+  -- MM buses
+  ----------------------------------------------------------------------------                                         
+  SIGNAL ram_st_xsq_mosi    : t_mem_mosi := c_mem_mosi_rst;
+  SIGNAL ram_st_xsq_miso    : t_mem_miso := c_mem_miso_rst;
+  SIGNAL st_xst_mm_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_mosi_rst);
+  SIGNAL st_xst_mm_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_miso_rst);
+
+  SIGNAL in_mosi_arr        : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS => c_mem_mosi_rst);
+
+  ----------------------------------------------------------------------------
+  -- Output array
+  ----------------------------------------------------------------------------         
+  SIGNAL st_xsq_out_2arr    : t_xsq_out_2arr(0 TO g_nof_streams-1) := (OTHERS => (OTHERS => (OTHERS => '0')));
+
+BEGIN
+  -- random input and expected xsq
+  gen_in_exp : FOR I IN 0 TO g_nof_streams-1 GENERATE
+    random_in_re_2arr(I) <= common_math_create_random_arr(c_block_size, c_random_data_w, c_random_seed+2*I);
+    random_in_im_2arr(I) <= common_math_create_random_arr(c_block_size, c_random_data_w, c_random_seed+2*I+1);
+    expected_xsq_2arr(I) <= func_st_calculate_expected_xsq(random_in_re_2arr(0), random_in_im_2arr(0), random_in_re_2arr(I), random_in_im_2arr(I), g_nof_crosslets, g_nof_block_per_sync);
+  END GENERATE;
+
+  ----------------------------------------------------------------------------
+  -- Clock and reset generation
+  ----------------------------------------------------------------------------
+  mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2;
+  mm_rst <= '1', '0' AFTER c_mm_clk_period*5;
+
+  dp_clk <= NOT dp_clk OR tb_end AFTER c_dp_clk_period/2;
+  dp_rst <= '1', '0' AFTER c_dp_clk_period*5;
+
+  ------------------------------------------------------------------------------
+  -- in mosi Stimuli
+  ------------------------------------------------------------------------------
+  gen_p_in_mosi : FOR M IN 0 TO g_nof_streams-1 GENERATE
+    p_in_mosi : PROCESS
+      VARIABLE v_ram_arr : t_slv_32_arr(c_block_size-1 DOWNTO 0);
+    BEGIN
+      -- write random data to ram
+      proc_common_wait_until_low(mm_clk, mm_rst);
+      FOR J IN 0 TO c_block_size-1 LOOP
+        v_ram_arr(J) := TO_SVEC(random_in_im_2arr(M)(J), g_in_data_w) & TO_SVEC(random_in_re_2arr(M)(J), g_in_data_w);
+      END LOOP;
+      proc_mem_write_ram(v_ram_arr, mm_clk, in_mosi_arr(M));
+      WAIT;
+    END PROCESS;
+  END GENERATE;
+
+  ------------------------------------------------------------------------------
+  -- MM Stimuli
+  ------------------------------------------------------------------------------
+  gen_mm_stimuli : FOR M IN 0 TO g_nof_streams-1 GENERATE
+    p_mm_stimuli : PROCESS
+    BEGIN
+      -- read statistics
+      FOR I IN 0 TO g_nof_sync -1 LOOP
+        proc_common_wait_until_lo_hi(dp_clk, in_sosi.sync);
+      END LOOP;
+      proc_common_wait_some_cycles(dp_clk, g_nof_clk_per_blk);
+      proc_common_wait_some_cycles(dp_clk, 20);
+      proc_common_wait_some_cycles(mm_clk, 2 * M * c_single_stream_mem_size);
+      proc_mem_read_ram(M*c_nof_statistics_mem_size, c_single_stream_mem_size, mm_clk, ram_st_xsq_mosi, ram_st_xsq_miso, st_xsq_out_2arr(M));  
+      WAIT;
+    END PROCESS;
+  END GENERATE;
+
+  ------------------------------------------------------------------------------
+  -- Data blocks
+  ------------------------------------------------------------------------------
+  p_in_sosi : PROCESS
+  BEGIN  
+    tb_end <= '0';
+    in_sosi <= c_dp_sosi_rst;
+    proc_common_wait_until_low(dp_clk, dp_rst);
+  
+    -- Run some sync intervals with DSP counter data for the real and imag fields
+    WAIT UNTIL rising_edge(dp_clk);
+    proc_common_wait_some_cycles(dp_clk, 7);
+    FOR I IN 0 TO g_nof_sync-1 LOOP
+      in_sosi.sop <= '1';
+      in_sosi.eop <= '1';
+      in_sosi.sync <= '1';
+      proc_common_wait_some_cycles(dp_clk, 1);
+      in_sosi <= c_dp_sosi_rst;
+      proc_common_wait_some_cycles(dp_clk, g_nof_clk_per_blk-1);
+      FOR J IN 0 TO g_nof_block_per_sync-2 LOOP  -- provide sop and eop for block reference
+        in_sosi.sop <= '1';
+        in_sosi.eop <= '1';
+        proc_common_wait_some_cycles(dp_clk, 1);
+        in_sosi <= c_dp_sosi_rst;
+        proc_common_wait_some_cycles(dp_clk, g_nof_clk_per_blk-1);
+      END LOOP;
+    END LOOP;
+    in_sosi <= c_dp_sosi_rst;
+    proc_common_wait_some_cycles(dp_clk, 100);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+  ------------------------------------------------------------------------------
+  -- Verification 
+  ------------------------------------------------------------------------------
+  p_verify : PROCESS
+  BEGIN
+    proc_common_wait_until_high(mm_clk, ram_st_xsq_miso.rdval);
+    proc_common_wait_some_cycles(mm_clk, 2* c_total_mem_size + 10);
+    FOR M IN 0 TO g_nof_streams -1 LOOP
+      FOR I IN 0 TO c_nof_statistics * c_nof_complex -1 LOOP
+        ASSERT TO_SINT(st_xsq_out_2arr(M)(g_stat_data_sz * I)) = expected_xsq_2arr(M)(I) REPORT "WRONG XSQ DATA" SEVERITY ERROR; -- Only read low part of statistic
+      END LOOP;
+    END LOOP;
+    WAIT;
+  END PROCESS;
+
+
+  ----------------------------------------------------------------------------
+  -- RAMs that contain a block of crosslets for each stream
+  ----------------------------------------------------------------------------
+  gen_ram : FOR I IN 0 TO g_nof_streams-1 GENERATE 
+    u_ram : ENTITY common_lib.common_ram_cr_cw
+    GENERIC MAP(
+      g_ram => c_mm_ram
+    )
+    PORT MAP(
+      wr_rst => mm_rst,
+      wr_clk => mm_clk,
+      wr_en  => in_mosi_arr(I).wr,
+      wr_adr => in_mosi_arr(I).address(c_mm_ram.adr_w-1 DOWNTO 0),
+      wr_dat => in_mosi_arr(I).wrdata(c_mm_ram.dat_w-1 DOWNTO 0),
+
+      rd_rst => dp_rst,
+      rd_clk => dp_clk,
+      rd_en  => st_xst_mm_mosi_arr(I).rd,
+      rd_adr  => st_xst_mm_mosi_arr(I).address(c_mm_ram.adr_w-1 DOWNTO 0),
+      rd_dat  => st_xst_mm_miso_arr(I).rddata(c_mm_ram.dat_w-1 DOWNTO 0),
+      rd_val  => st_xst_mm_miso_arr(I).rdval
+    );
+  END GENERATE;
+
+  ----------------------------------------------------------------------------
+  -- DUT: Device Under Test
+  ---------------------------------------------------------------------------- 
+  u_dut : ENTITY work.st_xst
+  GENERIC MAP(
+    g_nof_streams        => g_nof_streams,
+    g_nof_signal_inputs  => g_nof_signal_inputs,      
+    g_nof_crosslets      => g_nof_crosslets,    
+    g_in_data_w          => g_in_data_w,     
+    g_stat_data_w        => g_stat_data_w,   
+    g_stat_data_sz       => g_stat_data_sz  
+  )
+  PORT MAP(
+    mm_rst           =>  mm_rst,
+    mm_clk           =>  mm_clk,
+    dp_rst           =>  dp_rst,
+    dp_clk           =>  dp_clk,
+    
+    -- Streaming
+    in_sosi          => in_sosi, 
+    
+    -- DP Memory Mapped
+    mm_mosi_arr      => st_xst_mm_mosi_arr,  
+    mm_miso_arr      => st_xst_mm_miso_arr, 
+
+    -- Memory Mapped
+    ram_st_xsq_mosi  => ram_st_xsq_mosi,
+    ram_st_xsq_miso  => ram_st_xsq_miso
+  );
+
+END tb;
diff --git a/libraries/dsp/st/tb/vhdl/tb_tb_st_xst.vhd b/libraries/dsp/st/tb/vhdl/tb_tb_st_xst.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..e62c61e10c32fe8cfa0d2a604f2c8cf3bbd4a9ee
--- /dev/null
+++ b/libraries/dsp/st/tb/vhdl/tb_tb_st_xst.vhd
@@ -0,0 +1,60 @@
+-------------------------------------------------------------------------------
+--
+-- Copyright 2021
+-- 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: Test multiple instances of tb_st_xst
+-- Usage:
+-- > as 10
+-- > run -all
+--
+-- Description: See tb_st_xst
+
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+
+ENTITY tb_tb_st_xst IS
+END tb_tb_st_xst;
+
+ARCHITECTURE tb OF tb_tb_st_xst IS
+
+  CONSTANT c_nof_sync       : NATURAL := 3;
+  CONSTANT c_dsp_data_w     : NATURAL := 16;
+  SIGNAL tb_end : STD_LOGIC := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+  
+BEGIN
+--  GENERICS:
+--    g_nof_streams        : NATURAL := 9; 
+--    g_nof_crosslets      : NATURAL := 2; 
+--    g_nof_signal_inputs  : NATURAL := 12;  
+--    g_in_data_w          : NATURAL := 16;
+--    g_nof_sync           : NATURAL := 3;
+--    g_stat_data_w        : NATURAL := 64;  -- statistics accumulator width
+--    g_stat_data_sz       : NATURAL := 2;   -- statistics word width >= statistics accumulator width and fit in a power of 2 multiple 32b MM words
+--    g_nof_block_per_sync : NATURAL := 5;
+--    g_nof_clk_per_blk    : NATURAL := 1024
+
+  u_sdp                : ENTITY work.tb_st_xst GENERIC MAP (9, 1, 12, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024);
+  u_sdp_one            : ENTITY work.tb_st_xst GENERIC MAP (1, 1, 12, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024);
+  u_sdp_mult_crosslets : ENTITY work.tb_st_xst GENERIC MAP (9, 7, 12, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024);
+  -- Note: u_max shows that the dut will skip sync periods if nof_statistics is not < g_nof_clk_per_blk
+  u_max                : ENTITY work.tb_st_xst GENERIC MAP (2, 16, 8, c_dsp_data_w, c_nof_sync, 64, 2, 5, 1024); -- g_nof_crosslets * g_nof_signal_inputs**2 = 16 * 8 * 8 = 1024 = g_nof_clk_per_blk 
+  
+END tb;