diff --git a/libraries/base/axi4/hdllib.cfg b/libraries/base/axi4/hdllib.cfg
index 21929d4db412e6cec64ac144a62a978ebbc1dad9..0442544293e42ee951e51c3ca99afec5a46b4fe0 100644
--- a/libraries/base/axi4/hdllib.cfg
+++ b/libraries/base/axi4/hdllib.cfg
@@ -8,6 +8,7 @@ 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
     src/vhdl/mem_to_axi4_lite.vhd
 
 test_bench_files =
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..6c50c09f77e33f34d9b5a1e4f25fa9f0f1cdeedb
--- /dev/null
+++ b/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd
@@ -0,0 +1,216 @@
+-- --------------------------------------------------------------------------
+-- 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
+
+    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;
+
+    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;
+
+    mm_in_copi    : IN  t_mem_copi   := c_mem_copi_rst;
+    mm_in_cipo    : OUT t_mem_cipo   := c_mem_cipo_rst;
+
+    mm_out_copi   : OUT t_mem_copi   := c_mem_copi_rst;
+    mm_out_cipo   : IN  t_mem_cipo   := c_mem_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'; -- Internal active high reset.
+
+  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, 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;
+