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..9db9e0d826cb5252aeb0f04fd5942ce043b078fd
--- /dev/null
+++ b/libraries/dsp/st/src/vhdl/st_xsq_mm_to_dp.vhd
@@ -0,0 +1,139 @@
+-------------------------------------------------------------------------------
+--
+-- 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 data from memory mapped (MM) location and stream it as a block of data.
+-- Description:
+-- After every in_sosi.sop the st_xsq_mm_to_dp.vhd reads g_nof_streams blocks of data 
+-- via 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;
+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_data_size  : NATURAL;
+    g_step_size  : NATURAL;
+    g_nof_data   : NATURAL
+  ); 
+  PORT (
+    rst           : IN  STD_LOGIC;
+    clk           : IN  STD_LOGIC;
+    start_pulse   : IN  STD_LOGIC;
+    mm_done       : OUT STD_LOGIC;
+    mm_mosi       : OUT t_mem_mosi;
+    mm_miso       : IN  t_mem_miso;
+    out_sosi      : OUT t_dp_sosi;
+    out_siso      : IN  t_dp_siso
+  );
+END st_xsq_mm_to_dp;
+
+
+ARCHITECTURE rtl OF st_xsq_mm_to_dp IS 
+
+  CONSTANT c_mem_size : NATURAL := g_step_size * g_nof_data;
+
+  TYPE t_reg IS RECORD
+    busy       : STD_LOGIC;
+    sop        : STD_LOGIC;
+    eop        : STD_LOGIC;
+    word_index : NATURAL;
+    step_index : NATURAL;
+  END RECORD;
+
+  CONSTANT c_reg_rst : t_reg := ('0', '0', '0', 0, 0);
+
+  SIGNAL r     : t_reg;
+  SIGNAL nxt_r : t_reg;
+  SIGNAL mm_address      : NATURAL := 0;
+  SIGNAL last_mm_address : NATURAL := 0;
+BEGIN
+
+  last_mm_address <= g_step_size * (g_nof_data - 1) + g_data_size + start_address - 1;
+  mm_address      <= start_address + r.word_index + r.step_index;
+  
+  mm_mosi.address <= TO_MEM_ADDRESS(mm_address);
+
+  u_sosi : PROCESS(r, mm_miso)
+  BEGIN
+    out_sosi       <= c_dp_sosi_rst;  -- To avoid Modelsim warnings on conversion to integer from unused fields.
+    out_sosi.data  <= RESIZE_DP_DATA(mm_miso.rddata(c_word_w-1 DOWNTO 0));
+    out_sosi.valid <= mm_miso.rdval;  -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so same as the ready latency (RL = 1)
+    out_sosi.sop   <= r.sop;          -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.sop can be used for output sop
+    out_sosi.eop   <= r.eop;          -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.eop can be used for output eop
+  END PROCESS;
+  
+  mm_done <= r.eop;
+
+  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, start_pulse, out_siso, mm_address, last_mm_address)
+    VARIABLE v : t_reg;
+  BEGIN
+    v := r;
+    v.sop := '0';
+    v.eop := '0';
+    mm_mosi.rd <= '0';
+    IF r.busy = '0' AND start_pulse = '1' THEN
+      -- initiate next block
+      v.busy := '1';
+    ELSIF r.busy = '1' THEN
+      IF out_siso.ready = '1' THEN
+        -- continue with block
+        mm_mosi.rd <= '1';
+        IF r.word_index < g_data_size - 1 THEN
+          v.word_index := r.word_index + 1;
+        ELSE
+          v.word_index := 0;
+          v.step_index := r.step_index + g_step_size;
+        END IF;
+        
+        -- check start of block
+        IF r.word_index = 0 AND r.step_index = 0 THEN
+          v.sop := '1';
+        END IF;
+        
+        -- check end of block
+        IF mm_address >= last_mm_address THEN
+          v.eop := '1';
+          -- prepare for next block
+          v.busy := '0';
+          v.word_index := 0;
+          v.step_index := 0;
+        END IF;
+      END IF;
+    END IF;
+    nxt_r <= v;
+  END PROCESS;
+    
+END rtl;