diff --git a/libraries/base/common/tb/vhdl/tb_common_paged_ram_cr_cw.vhd b/libraries/base/common/tb/vhdl/tb_common_paged_ram_cr_cw.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..05e526c6838c9c5742008eeaac54cc7af1a214df
--- /dev/null
+++ b/libraries/base/common/tb/vhdl/tb_common_paged_ram_cr_cw.vhd
@@ -0,0 +1,231 @@
+-- -----------------------------------------------------------------------------
+--
+-- 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: 
+--   D.F. Brouwer
+-- Purpose: 
+--   Test bench for common_paged_ram_cr_cw
+-- Reference:
+--   Based on tb_common_paged_ram_crw_crw.vhd
+-- Description:
+--   Features:
+--   . Use c_gap_sz = 0 to try writing and reading multiple page without idle
+--     cycles
+--   . Most applications use c_nof_pages = 2, but use > 2 is supported too.
+--   Usage:
+--   > as 10
+--   > run -all
+
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+use work.common_pkg.all;
+use work.tb_common_pkg.all;
+
+entity tb_common_paged_ram_cr_cw is
+end tb_common_paged_ram_cr_cw;
+
+architecture tb of tb_common_paged_ram_cr_cw is
+  constant clk_period        : time := 10 ns;
+
+  constant c_data_w          : natural := 8;
+  constant c_nof_pages       : natural := 2;  -- >= 2
+  constant c_page_sz         : natural := 8;
+  constant c_wr_start_page   : natural := 0;
+  constant c_rd_start_page   : natural := 1;
+  constant c_gap_sz          : natural := 0;  -- >= 0
+  constant c_rl              : natural := 1;
+
+  signal rst                 : std_logic;
+  signal clk                 : std_logic := '1';
+  signal tb_end              : std_logic := '0';
+
+  -- DUT
+  signal next_page           : std_logic;
+
+  signal wr_next_page        : std_logic;
+  signal wr_adr              : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0');
+  signal wr_en               : std_logic;
+  signal wr_dat              : std_logic_vector(c_data_w - 1 downto 0) := (others => '0');
+
+  signal rd_next_page        : std_logic;
+  signal rd_adr              : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0');
+  signal rd_en               : std_logic := '0';
+
+  signal mux_rd_dat          : std_logic_vector(c_data_w - 1 downto 0);
+  signal mux_rd_val          : std_logic;
+
+  signal adr_rd_dat          : std_logic_vector(c_data_w - 1 downto 0);
+  signal adr_rd_val          : std_logic;
+
+  signal ofs_rd_dat          : std_logic_vector(c_data_w - 1 downto 0);
+  signal ofs_rd_val          : std_logic;
+
+  -- Verify
+  signal verify_en           : std_logic;
+  signal ready               : std_logic := '1';
+
+  signal prev_mux_rd_dat     : std_logic_vector(c_data_w - 1 downto 0);
+  signal prev_adr_rd_dat     : std_logic_vector(c_data_w - 1 downto 0);
+  signal prev_ofs_rd_dat     : std_logic_vector(c_data_w - 1 downto 0);
+begin
+  clk <= not clk and not tb_end after clk_period / 2;
+  rst <= '1', '0' after clk_period * 7;
+
+  verify_en <= '0', '1' after clk_period * (15 + (c_nof_pages - 1) * c_page_sz);
+
+  -- Apply stimuli via port 'a', do write 'a' and read 'b', and derive the 'b' stimuli from the 'a' stimuli with 1 clock cycle latency
+  wr_next_page <= next_page;
+  rd_next_page <= next_page when rising_edge(clk);
+
+  wr_dat   <= INCR_UVEC(  wr_dat, 1) when rising_edge(clk) and wr_en = '1';
+  wr_adr   <= INCR_UVEC(  wr_adr, 1) when rising_edge(clk) and wr_en = '1';
+  rd_adr   <=             wr_adr     when rising_edge(clk);
+  rd_en    <=              wr_en     when rising_edge(clk);
+
+  p_stimuli : process
+  begin
+    next_page <= '0';
+    wr_en     <= '0';
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 3);
+
+    -- Access the pages several times
+    for I in 0 to c_nof_pages * 3 loop
+      wr_en <= '1';
+      proc_common_wait_some_cycles(clk, c_page_sz - 1);
+      next_page <= '1';
+      proc_common_wait_some_cycles(clk, 1);
+      next_page <= '0';
+      wr_en <= '0';
+      proc_common_wait_some_cycles(clk, c_gap_sz);  -- optinal gap between the pages
+    end loop;
+
+    wr_en <= '0';
+    proc_common_wait_some_cycles(clk, c_page_sz);
+    tb_end <= '1';
+    wait;
+  end process;
+
+  u_dut_mux : entity work.common_paged_ram_cr_cw
+  generic map (
+    g_str           => "use_mux",
+    g_data_w        => c_data_w,
+    g_nof_pages     => c_nof_pages,
+    g_page_sz       => c_page_sz,
+    g_wr_start_page => c_wr_start_page,
+    g_rd_start_page => c_rd_start_page
+  )
+  port map (
+    -- Write port clock domain
+    wr_rst        => rst,
+    wr_clk        => clk,
+    wr_clken      => '1',
+    wr_next_page  => wr_next_page,
+    wr_adr        => wr_adr,
+    wr_en         => wr_en,
+    wr_dat        => wr_dat,
+    -- Read port clock domain
+    rd_rst        => rst,
+    rd_clk        => clk,
+    rd_clken      => '1',
+    rd_next_page  => rd_next_page,
+    rd_adr        => rd_adr,
+    rd_en         => rd_en,
+    rd_dat        => mux_rd_dat,
+    rd_val        => mux_rd_val
+  );
+
+  u_dut_adr : entity work.common_paged_ram_cr_cw
+  generic map (
+    g_str           => "use_adr",
+    g_data_w        => c_data_w,
+    g_nof_pages     => c_nof_pages,
+    g_page_sz       => c_page_sz,
+    g_wr_start_page => c_wr_start_page,
+    g_rd_start_page => c_rd_start_page
+  )
+  port map (
+    -- Write port clock domain
+    wr_rst        => rst,
+    wr_clk        => clk,
+    wr_clken      => '1',
+    wr_next_page  => wr_next_page,
+    wr_adr        => wr_adr,
+    wr_en         => wr_en,
+    wr_dat        => wr_dat,
+    -- Read port clock domain
+    rd_rst        => rst,
+    rd_clk        => clk,
+    rd_clken      => '1',
+    rd_next_page  => rd_next_page,
+    rd_adr        => rd_adr,
+    rd_en         => rd_en,
+    rd_dat        => adr_rd_dat,
+    rd_val        => adr_rd_val
+  );
+
+  u_dut_ofs : entity work.common_paged_ram_cr_cw
+  generic map (
+    g_str           => "use_ofs",
+    g_data_w        => c_data_w,
+    g_nof_pages     => c_nof_pages,
+    g_page_sz       => c_page_sz,
+    g_wr_start_page => c_wr_start_page,
+    g_rd_start_page => c_rd_start_page
+  )
+  port map (
+    -- Write port clock domain
+    wr_rst        => rst,
+    wr_clk        => clk,
+    wr_clken      => '1',
+    wr_next_page  => wr_next_page,
+    wr_adr        => wr_adr,
+    wr_en         => wr_en,
+    wr_dat        => wr_dat,
+    -- Read port clock domain
+    rd_rst        => rst,
+    rd_clk        => clk,
+    rd_clken      => '1',
+    rd_next_page  => rd_next_page,
+    rd_adr        => rd_adr,
+    rd_en         => rd_en,
+    rd_dat        => ofs_rd_dat,
+    rd_val        => ofs_rd_val
+  );
+
+  -- Verify that the read data is incrementing data
+  proc_common_verify_data(c_rl, clk, verify_en, ready, mux_rd_val, mux_rd_dat, prev_mux_rd_dat);
+  proc_common_verify_data(c_rl, clk, verify_en, ready, adr_rd_val, adr_rd_dat, prev_adr_rd_dat);
+  proc_common_verify_data(c_rl, clk, verify_en, ready, ofs_rd_val, ofs_rd_dat, prev_ofs_rd_dat);
+
+  -- Verify that the read data is the same for all three DUT variants
+  p_verify_equal : process(clk)
+  begin
+    if rising_edge(clk) then
+      if unsigned(mux_rd_dat) /= unsigned(adr_rd_dat) or unsigned(mux_rd_dat) /= unsigned(ofs_rd_dat) then
+        report "DUT : read data differs between two implementations" severity ERROR;
+      end if;
+      if mux_rd_val /= adr_rd_val or mux_rd_val /= ofs_rd_val then
+        report "DUT : read valid differs between two implementations" severity ERROR;
+      end if;
+    end if;
+  end process;
+end tb;
diff --git a/libraries/base/common/tb/vhdl/tb_common_paged_ram_rw_rw.vhd b/libraries/base/common/tb/vhdl/tb_common_paged_ram_rw_rw.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..2de05fffb45fc79828ab8ff58ced5d5406787234
--- /dev/null
+++ b/libraries/base/common/tb/vhdl/tb_common_paged_ram_rw_rw.vhd
@@ -0,0 +1,231 @@
+-- -----------------------------------------------------------------------------
+--
+-- 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: 
+--   D.F. Brouwer
+-- Purpose: 
+--   Test bench for common_paged_ram_rw_rw
+-- Reference:
+--   Based on tb_common_paged_ram_crw_crw.vhd
+-- Description:
+--   Features:
+--   . Use c_gap_sz = 0 to try writing and reading multiple page without idle
+--     cycles
+--   . Most applications use c_nof_pages = 2, but use > 2 is supported too.
+--   Usage:
+--   > as 10
+--   > run -all
+
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+use work.common_pkg.all;
+use work.tb_common_pkg.all;
+
+entity tb_common_paged_ram_rw_rw is
+end tb_common_paged_ram_rw_rw;
+
+architecture tb of tb_common_paged_ram_rw_rw is
+  constant clk_period        : time := 10 ns;
+
+  constant c_data_w          : natural := 8;
+  constant c_nof_pages       : natural := 2;  -- >= 2
+  constant c_page_sz         : natural := 8;
+  constant c_start_page_a    : natural := 0;
+  constant c_start_page_b    : natural := 1;
+  constant c_gap_sz          : natural := 0;  -- >= 0
+  constant c_rl              : natural := 1;
+
+  signal rst                 : std_logic;
+  signal clk                 : std_logic := '1';
+  signal tb_end              : std_logic := '0';
+
+  -- DUT
+  signal next_page           : std_logic;
+
+  signal next_page_a         : std_logic;
+  signal adr_a               : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0');
+  signal wr_en_a             : std_logic;
+  signal wr_dat_a            : std_logic_vector(c_data_w - 1 downto 0) := (others => '0');
+
+  signal next_page_b         : std_logic;
+  signal adr_b               : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0');
+  signal rd_en_b             : std_logic := '0';
+
+  signal mux_rd_dat_b        : std_logic_vector(c_data_w - 1 downto 0);
+  signal mux_rd_val_b        : std_logic;
+
+  signal adr_rd_dat_b        : std_logic_vector(c_data_w - 1 downto 0);
+  signal adr_rd_val_b        : std_logic;
+
+  signal ofs_rd_dat_b        : std_logic_vector(c_data_w - 1 downto 0);
+  signal ofs_rd_val_b        : std_logic;
+
+  -- Verify
+  signal verify_en           : std_logic;
+  signal ready               : std_logic := '1';
+
+  signal prev_mux_rd_dat_b   : std_logic_vector(c_data_w - 1 downto 0);
+  signal prev_adr_rd_dat_b   : std_logic_vector(c_data_w - 1 downto 0);
+  signal prev_ofs_rd_dat_b   : std_logic_vector(c_data_w - 1 downto 0);
+begin
+  clk <= not clk and not tb_end after clk_period / 2;
+  rst <= '1', '0' after clk_period * 7;
+
+  verify_en <= '0', '1' after clk_period * (15 + (c_nof_pages - 1) * c_page_sz);
+
+  -- Apply stimuli via port 'a', do write 'a' and read 'b', and derive the 'b' stimuli from the 'a' stimuli with 1 clock cycle latency
+  next_page_a <= next_page;
+  next_page_b <= next_page when rising_edge(clk);
+
+  wr_dat_a <= INCR_UVEC(wr_dat_a, 1) when rising_edge(clk) and wr_en_a = '1';
+  adr_a    <= INCR_UVEC(   adr_a, 1) when rising_edge(clk) and wr_en_a = '1';
+  adr_b    <=              adr_a     when rising_edge(clk);
+  rd_en_b  <=            wr_en_a     when rising_edge(clk);
+
+  p_stimuli : process
+  begin
+    next_page <= '0';
+    wr_en_a   <= '0';
+    proc_common_wait_until_low(clk, rst);
+    proc_common_wait_some_cycles(clk, 3);
+
+    -- Access the pages several times
+    for I in 0 to c_nof_pages * 3 loop
+      wr_en_a <= '1';
+      proc_common_wait_some_cycles(clk, c_page_sz - 1);
+      next_page <= '1';
+      proc_common_wait_some_cycles(clk, 1);
+      next_page <= '0';
+      wr_en_a <= '0';
+      proc_common_wait_some_cycles(clk, c_gap_sz);  -- optinal gap between the pages
+    end loop;
+
+    wr_en_a <= '0';
+    proc_common_wait_some_cycles(clk, c_page_sz);
+    tb_end <= '1';
+    wait;
+  end process;
+
+  u_dut_mux : entity work.common_paged_ram_rw_rw
+  generic map (
+    g_str           => "use_mux",
+    g_data_w        => c_data_w,
+    g_nof_pages     => c_nof_pages,
+    g_page_sz       => c_page_sz,
+    g_start_page_a  => c_start_page_a,
+    g_start_page_b  => c_start_page_b
+  )
+  port map (
+    rst         => rst,
+    clk         => clk,
+    clken       => '1',
+    next_page_a => next_page_a,
+    adr_a       => adr_a,
+    wr_en_a     => wr_en_a,
+    wr_dat_a    => wr_dat_a,
+    rd_en_a     => '0',
+    rd_dat_a    => OPEN,
+    rd_val_a    => OPEN,
+    next_page_b => next_page_b,
+    adr_b       => adr_b,
+    wr_en_b     => '0',
+    wr_dat_b    => (others => '0'),
+    rd_en_b     => rd_en_b,
+    rd_dat_b    => mux_rd_dat_b,
+    rd_val_b    => mux_rd_val_b
+  );
+
+  u_dut_adr : entity work.common_paged_ram_rw_rw
+  generic map (
+    g_str           => "use_adr",
+    g_data_w        => c_data_w,
+    g_nof_pages     => c_nof_pages,
+    g_page_sz       => c_page_sz,
+    g_start_page_a  => c_start_page_a,
+    g_start_page_b  => c_start_page_b
+  )
+  port map (
+    rst         => rst,
+    clk         => clk,
+    clken       => '1',
+    next_page_a => next_page_a,
+    adr_a       => adr_a,
+    wr_en_a     => wr_en_a,
+    wr_dat_a    => wr_dat_a,
+    rd_en_a     => '0',
+    rd_dat_a    => OPEN,
+    rd_val_a    => OPEN,
+    next_page_b => next_page_b,
+    adr_b       => adr_b,
+    wr_en_b     => '0',
+    wr_dat_b    => (others => '0'),
+    rd_en_b     => rd_en_b,
+    rd_dat_b    => adr_rd_dat_b,
+    rd_val_b    => adr_rd_val_b
+  );
+
+  u_dut_ofs : entity work.common_paged_ram_rw_rw
+  generic map (
+    g_str           => "use_ofs",
+    g_data_w        => c_data_w,
+    g_nof_pages     => c_nof_pages,
+    g_page_sz       => c_page_sz,
+    g_start_page_a  => c_start_page_a,
+    g_start_page_b  => c_start_page_b
+  )
+  port map (
+    rst         => rst,
+    clk         => clk,
+    clken       => '1',
+    next_page_a => next_page_a,
+    adr_a       => adr_a,
+    wr_en_a     => wr_en_a,
+    wr_dat_a    => wr_dat_a,
+    rd_en_a     => '0',
+    rd_dat_a    => OPEN,
+    rd_val_a    => OPEN,
+    next_page_b => next_page_b,
+    adr_b       => adr_b,
+    wr_en_b     => '0',
+    wr_dat_b    => (others => '0'),
+    rd_en_b     => rd_en_b,
+    rd_dat_b    => ofs_rd_dat_b,
+    rd_val_b    => ofs_rd_val_b
+  );
+
+  -- Verify that the read data is incrementing data
+  proc_common_verify_data(c_rl, clk, verify_en, ready, mux_rd_val_b, mux_rd_dat_b, prev_mux_rd_dat_b);
+  proc_common_verify_data(c_rl, clk, verify_en, ready, adr_rd_val_b, adr_rd_dat_b, prev_adr_rd_dat_b);
+  proc_common_verify_data(c_rl, clk, verify_en, ready, ofs_rd_val_b, ofs_rd_dat_b, prev_ofs_rd_dat_b);
+
+  -- Verify that the read data is the same for all three DUT variants
+  p_verify_equal : process(clk)
+  begin
+    if rising_edge(clk) then
+      if unsigned(mux_rd_dat_b) /= unsigned(adr_rd_dat_b) or unsigned(mux_rd_dat_b) /= unsigned(ofs_rd_dat_b) then
+        report "DUT : read data differs between two implementations" severity ERROR;
+      end if;
+      if mux_rd_val_b /= adr_rd_val_b or mux_rd_val_b /= ofs_rd_val_b then
+        report "DUT : read valid differs between two implementations" severity ERROR;
+      end if;
+    end if;
+  end process;
+end tb;