diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg
index b5890bb8eb13e7910a555888274c1a32b5b94567..4ef63308767f3dca39fdbd3a44b2645954626c8d 100644
--- a/libraries/base/dp/hdllib.cfg
+++ b/libraries/base/dp/hdllib.cfg
@@ -166,6 +166,10 @@ synth_files =
     src/vhdl/dp_selector_arr.vhd
     src/vhdl/dp_selector.vhd
     src/vhdl/mms_dp_scale.vhd
+    
+    src/vhdl/dp_block_from_mm.vhd
+    src/vhdl/dp_block_to_mm.vhd
+    
     tb/vhdl/dp_stream_player.vhd
     tb/vhdl/dp_sosi_recorder.vhd
     tb/vhdl/dp_stream_rec_play.vhd
@@ -251,6 +255,7 @@ test_bench_files =
     tb/vhdl/tb_mms_dp_force_data_serial_arr.vhd
     tb/vhdl/tb_mms_dp_gain_arr.vhd
     tb/vhdl/tb_mms_dp_gain_serial_arr.vhd
+    tb/vhdl/tb_dp_block_from_mm.vhd
 
     tb/vhdl/tb_tb_dp_block_select.vhd
     tb/vhdl/tb_tb_dp_block_reshape.vhd
diff --git a/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd b/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..794f823ec30b620bf176d89dbcfffae62681eab0
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd
@@ -0,0 +1,131 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2020
+-- 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: 
+-- . Pieter Donker
+-- Purpose:
+-- . Read a block of data from memory mapped (MM) location and stream it as a block of data.
+-- Description:
+-- . " "
+-- --------------------------------------------------------------------------
+
+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 work.dp_stream_pkg.ALL;
+
+ENTITY dp_block_from_mm 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;
+    start_address : IN  NATURAL RANGE 0 TO g_step_size * g_nof_data;
+    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 dp_block_from_mm;
+
+
+ARCHITECTURE rtl OF dp_block_from_mm 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 RANGE 0 TO g_data_size-1;
+    step_index : NATURAL RANGE 0 TO c_mem_size;
+  END RECORD;
+
+  CONSTANT c_reg_rst : t_reg := ('0', '0', '0', 0, 0);
+
+  SIGNAL r : t_reg;
+  SIGNAL d : t_reg;
+
+BEGIN
+
+  mm_mosi.address <= TO_MEM_ADDRESS(start_address + r.word_index + r.step_index);
+
+  out_sosi.data  <= RESIZE_DP_DATA(mm_miso.rddata);
+  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
+  
+  mm_done <= not r.busy;
+
+  p_reg : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      r <= c_reg_rst;
+    ELSIF rising_edge(clk) THEN
+      r <= d;
+    END IF;
+  END PROCESS;
+
+  p_comb : PROCESS(r, start_pulse, out_siso, d)
+  BEGIN
+    d <= r;
+    d.sop <= '0';
+    d.eop <= '0';
+    mm_mosi.rd <= '0';
+    IF r.busy = '0' AND start_pulse = '1' THEN
+      -- initiate next block
+      d.busy <= '1';
+    ELSIF r.busy = '1' THEN
+      IF out_siso.ready = '1' THEN
+        -- continue with block
+        IF r.step_index < c_mem_size THEN
+          mm_mosi.rd <= '1';
+          IF r.word_index < g_data_size - 1 THEN
+            d.word_index <= r.word_index + 1;
+          ELSE
+            d.word_index <= 0;
+            d.step_index <= r.step_index + g_step_size;
+          END IF;
+        END IF;
+        
+        -- check start of block
+        IF r.word_index = 0 AND r.step_index = 0 THEN
+          d.sop <= '1';
+        END IF;
+        
+        -- check end of block
+        IF r.step_index >= c_mem_size THEN  -- use d rather than r to have easier end of block condition
+          d.eop <= '1';
+          -- prepare for next block
+          d.busy <= '0';
+          d.word_index <= 0;
+          d.step_index <= 0;
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+    
+END rtl;
\ No newline at end of file
diff --git a/libraries/base/dp/src/vhdl/dp_block_to_mm.vhd b/libraries/base/dp/src/vhdl/dp_block_to_mm.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..ed847f9d39dfe2b917b1f7684b0974e3fd6e5f1c
--- /dev/null
+++ b/libraries/base/dp/src/vhdl/dp_block_to_mm.vhd
@@ -0,0 +1,122 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2020
+-- 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: 
+-- . Pieter Donker
+-- Purpose:
+-- . get a block of data from a stream and write it to a memory mapped (MM) location.
+-- Description:
+-- . " "
+-- --------------------------------------------------------------------------
+
+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 work.dp_stream_pkg.ALL;
+
+ENTITY dp_block_to_mm IS
+  GENERIC (
+    g_data_size  : NATURAL;
+    g_step_size  : NATURAL;
+    g_nof_data   : NATURAL
+  ); 
+  PORT (
+    rst           : IN  STD_LOGIC;
+    clk           : IN  STD_LOGIC;
+    start_address : IN  NATURAL RANGE 0 TO g_step_size * g_nof_data;
+    mm_miso       : IN  t_mem_miso;
+    mm_mosi       : OUT t_mem_mosi;
+    in_sosi       : IN  t_dp_sosi;
+    in_siso       : OUT t_dp_siso
+  );
+END dp_block_to_mm;
+
+
+ARCHITECTURE rtl OF dp_block_to_mm IS 
+
+  CONSTANT c_mem_size : NATURAL := g_step_size * g_nof_data;
+
+  TYPE t_reg IS RECORD
+    busy       : STD_LOGIC;
+    wr         : STD_LOGIC;
+    word_index : NATURAL RANGE 0 TO g_data_size-1;
+    step_index : NATURAL RANGE 0 TO c_mem_size;
+  END RECORD;
+
+  CONSTANT c_reg_rst : t_reg := ('0', '0', 0, 0);
+
+  SIGNAL r : t_reg;
+  SIGNAL d : t_reg;
+
+BEGIN
+
+  in_siso.ready   <= '1';
+  mm_mosi.address <= TO_MEM_ADDRESS(start_address + r.word_index + r.step_index);
+  mm_mosi.wrdata  <= RESIZE_MEM_DATA(in_sosi.data);
+  mm_mosi.wr      <= r.wr;
+  
+  p_reg : PROCESS(rst, clk)
+  BEGIN
+    IF rst='1' THEN
+      r <= c_reg_rst;
+    ELSIF rising_edge(clk) THEN
+      r <= d;
+    END IF;
+  END PROCESS;
+
+  p_comb : PROCESS(r, in_sosi, d)
+  BEGIN
+    d <= r;
+    d.wr <= '0';
+    
+    -- if start of block
+    IF in_sosi.sop = '1' THEN
+      d.busy       <= '1';
+      d.word_index <= 0;
+      d.step_index <= 0;
+    END IF;
+
+    -- if end of block
+    IF in_sosi.eop = '1' THEN
+      -- prepare for next block
+      d.busy       <= '0';
+      d.word_index <= 0;
+      d.step_index <= 0;
+    END IF;
+
+    -- while receiving block
+    IF r.busy = '1' THEN
+      IF in_sosi.valid = '1' THEN
+        -- continue with block
+        IF r.step_index < c_mem_size THEN
+          d.wr <= '1';
+          IF r.word_index < g_data_size - 1 THEN
+            d.word_index <= r.word_index + 1;
+          ELSE
+            d.word_index <= 0;
+            d.step_index <= r.step_index + g_step_size;
+          END IF;
+        END IF;
+      END IF;
+    END IF;
+  END PROCESS;
+    
+END rtl;
\ No newline at end of file
diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..80c018c91622b6e867f33a99b2f75c6545e3731a
--- /dev/null
+++ b/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd
@@ -0,0 +1,223 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2020
+-- 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: 
+-- . Pieter Donker
+-- Purpose:
+-- . Read a block of data from memory mapped (MM) location and stream it as a block of data.
+-- Description:
+-- . " "
+-- --------------------------------------------------------------------------
+
+-- > as 10
+-- > run -all  -- signal tb_end will stop the simulation by stopping the clk
+  
+LIBRARY IEEE, common_lib, dp_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.tb_common_pkg.ALL;
+USE dp_lib.dp_stream_pkg.ALL;
+USE dp_lib.tb_dp_pkg.ALL;
+
+
+ENTITY tb_dp_block_from_mm IS
+  GENERIC (
+    g_data_size : NATURAL := 2;
+    g_step_size : NATURAL := 2;
+    g_nof_data  : NATURAL := 512  -- 512
+  );
+END tb_dp_block_from_mm;
+
+
+ARCHITECTURE tb OF tb_dp_block_from_mm IS
+
+  CONSTANT c_ram_data_size : NATURAL := g_nof_data * g_step_size;
+  CONSTANT c_ram_adr_w     : NATURAL := ceil_log2(c_ram_data_size);
+
+  CONSTANT c_ram : t_c_mem := (c_mem_ram_rd_latency, c_ram_adr_w, c_word_w, 2**c_ram_adr_w, '0');
+
+  SIGNAL tb_end             : STD_LOGIC := '0';
+  SIGNAL clk                : STD_LOGIC := '1';
+  SIGNAL rst                : STD_LOGIC := '1';
+
+  SIGNAL start_pulse        : STD_LOGIC := '0';
+  SIGNAL start_address      : NATURAL := 0;
+  SIGNAL block_done         : STD_LOGIC;
+
+  SIGNAL rd_mosi           : t_mem_mosi;
+  SIGNAL rd_miso           : t_mem_miso;
+  
+  SIGNAL blk_sosi           : t_dp_sosi;
+  SIGNAL blk_siso           : t_dp_siso := c_dp_siso_rdy;
+
+  SIGNAL wr_mosi           : t_mem_mosi;
+  SIGNAL wr_miso           : t_mem_miso;
+
+  -- needed for init and verify
+  SIGNAL ram_wr_en   : STD_LOGIC := '0';
+  SIGNAL ram_wr_adr  : STD_LOGIC_VECTOR(c_ram.adr_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL ram_wr_dat  : STD_LOGIC_VECTOR(c_ram.dat_w-1 DOWNTO 0) := (OTHERS=>'0');
+  SIGNAL ram_rd_en   : STD_LOGIC := '1';
+  SIGNAL ram_rd_adr  : STD_LOGIC_VECTOR(c_ram.adr_w-1 DOWNTO 0);
+  SIGNAL ram_rd_dat  : STD_LOGIC_VECTOR(c_ram.dat_w-1 DOWNTO 0);
+  SIGNAL ram_rd_val  : STD_LOGIC;
+
+  SIGNAL init_done    : STD_LOGIC := '0';
+  SIGNAL transfer_done : STD_LOGIC := '0';
+  
+BEGIN
+
+  clk <= (NOT clk) OR tb_end AFTER clk_period/2;
+  rst <= '1', '0' AFTER clk_period*7;
+  
+  
+  ------------------------------------------------------------------------------
+  -- STIMULI
+  ------------------------------------------------------------------------------
+  
+  p_init_ram : PROCESS
+  BEGIN
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 10);
+    FOR i IN 0 TO c_ram.nof_dat-1 LOOP
+      ram_wr_adr <= TO_UVEC(i, c_ram.adr_w);
+      ram_wr_dat <= TO_UVEC(i, c_ram.dat_w);
+      ram_wr_en <= '1'; 
+      proc_common_wait_some_cycles(clk, 20);
+    END LOOP;
+    ram_wr_en <= '0'; 
+
+    init_done <= '1';
+    WAIT;
+  END PROCESS;
+
+  p_transfer : PROCESS
+  BEGIN
+    proc_common_wait_until_high(clk, init_done);
+
+    start_address <= 0;
+    start_pulse <= '1';
+    proc_common_wait_some_cycles(clk, 20);
+    start_pulse <= '0';
+    proc_common_wait_until_high(clk, block_done);
+    
+    transfer_done <= '1';
+    WAIT;
+  END PROCESS;
+
+
+  p_verify_ram : PROCESS
+  BEGIN
+    proc_common_wait_until_high(clk, transfer_done);
+    
+    FOR i IN 0 TO c_ram.nof_dat-1 LOOP
+      ram_rd_adr <= TO_UVEC(i, c_ram.adr_w);
+      ram_rd_en <= '1';
+      proc_common_wait_some_cycles(clk, 1);
+      ram_rd_en <= '0'; 
+      ASSERT i = TO_UINT(ram_rd_dat) REPORT "RAM values not equal" SEVERITY ERROR;
+      proc_common_wait_some_cycles(clk, 1);
+    END LOOP;
+
+    proc_common_wait_some_cycles(clk, 10);
+    tb_end <= '1';
+    WAIT;
+  END PROCESS;
+
+
+  -- RAM with test data
+  u_ram_rd: ENTITY common_lib.common_ram_r_w
+  GENERIC MAP (
+    g_ram => c_ram
+  )
+  PORT MAP (
+    rst     => rst,    
+    clk     => clk,
+    wr_en   => ram_wr_en,
+    wr_adr  => ram_wr_adr,
+    wr_dat  => ram_wr_dat,
+    rd_en   => rd_mosi.rd,
+    rd_adr  => rd_mosi.address(c_ram.adr_w-1 DOWNTO 0),
+    rd_dat  => rd_miso.rddata(c_ram.dat_w-1 DOWNTO 0),
+    rd_val  => rd_miso.rdval
+  );
+
+  
+  -- DUT : dp_block_from_mm
+  u_dut: ENTITY work.dp_block_from_mm
+  GENERIC MAP (
+    g_data_size => g_data_size,
+    g_step_size => g_step_size,
+    g_nof_data  => g_nof_data
+  )
+  PORT MAP (
+    rst           => rst,
+    clk           => clk,
+    
+    start_pulse   => start_pulse,
+    start_address => start_address,
+    mm_done       => block_done,
+
+    mm_mosi       => rd_mosi,
+    mm_miso       => rd_miso,
+
+    out_sosi      => blk_sosi,
+    out_siso      => blk_siso
+  );
+    
+  -- convert mm back to block
+  u_tets: ENTITY work.dp_block_to_mm
+  GENERIC MAP (
+    g_data_size => g_data_size,
+    g_step_size => g_step_size,
+    g_nof_data  => g_nof_data
+  )
+  PORT MAP (
+    rst           => rst,
+    clk           => clk,
+    
+    start_address => start_address,
+
+    mm_mosi       => wr_mosi,
+    mm_miso       => wr_miso,
+
+    in_sosi      => blk_sosi,
+    in_siso      => blk_siso
+  );
+
+  -- RAM with converted result
+  u_ram_wr: ENTITY common_lib.common_ram_r_w
+  GENERIC MAP (
+    g_ram => c_ram
+  )
+  PORT MAP (
+    rst     => rst,    
+    clk     => clk,
+    wr_en   => wr_mosi.wr,
+    wr_adr  => wr_mosi.address(c_ram.adr_w-1 DOWNTO 0),
+    wr_dat  => wr_mosi.wrdata(c_ram.dat_w-1 DOWNTO 0),
+    rd_en   => ram_rd_en,
+    rd_adr  => ram_rd_adr,
+    rd_dat  => ram_rd_dat,
+    rd_val  => ram_rd_val
+  );
+
+END tb;