From bf25339ec5dae3da0cadb13c803706693924e7bf Mon Sep 17 00:00:00 2001
From: Reinier van der Walle <walle@astron.nl>
Date: Thu, 6 Apr 2023 11:02:19 +0200
Subject: [PATCH] Added testbench + removed ready-latency adapters

removed ready-latency adapters from axi4-lite_mm_bridge as these are not
needed. Placed functions in package. Also added testbench.
---
 libraries/base/axi4/hdllib.cfg                |   4 +-
 .../axi4/src/vhdl/axi4_lite_mm_bridge.vhd     | 138 ++--------------
 .../base/axi4/src/vhdl/axi4_lite_pkg.vhd      |  62 ++++++++
 .../axi4/tb/vhdl/tb_axi4_lite_mm_bridge.vhd   | 147 ++++++++++++++++++
 4 files changed, 227 insertions(+), 124 deletions(-)
 create mode 100644 libraries/base/axi4/tb/vhdl/tb_axi4_lite_mm_bridge.vhd

diff --git a/libraries/base/axi4/hdllib.cfg b/libraries/base/axi4/hdllib.cfg
index 6cef475d8b..0b31ec4667 100644
--- a/libraries/base/axi4/hdllib.cfg
+++ b/libraries/base/axi4/hdllib.cfg
@@ -1,7 +1,7 @@
 hdl_lib_name = axi4
 hdl_library_clause_name = axi4_lib
 hdl_lib_uses_synth = common dp
-hdl_lib_uses_sim =
+hdl_lib_uses_sim = mm
 hdl_lib_technology =
 
 synth_files =
@@ -11,11 +11,13 @@ synth_files =
     src/vhdl/axi4_lite_mm_bridge.vhd
 
 test_bench_files =
+    tb/vhdl/tb_axi4_lite_mm_bridge.vhd
     tb/vhdl/tb_axi4_stream_dp_bridge.vhd
     tb/vhdl/tb_tb_axi4_stream_dp_bridge.vhd
 
 regression_test_vhdl =
     tb/vhdl/tb_tb_axi4_stream_dp_bridge.vhd
+    tb/vhdl/tb_axi4_lite_mm_bridge.vhd
 
 [modelsim_project_file]
 
diff --git a/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd b/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd
index a763e876a9..443f690a74 100644
--- a/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd
+++ b/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd
@@ -23,18 +23,18 @@
 -- 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.
+-- . Remark:
+--   . The read latency is not adapted. Ensure that the Controller an Peripheral use the same 
+--     read-latency.
 
-LIBRARY IEEE, common_lib, dp_lib, technology_lib, mm_lib;
+LIBRARY IEEE, common_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
@@ -65,27 +65,9 @@ ENTITY axi4_lite_mm_bridge IS
 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'; 
 
-  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 i_mm_out_copi : t_mem_copi;
 
   SIGNAL d_bvalid : STD_LOGIC := '0';
   SIGNAL q_bvalid : STD_LOGIC := '0';
@@ -96,83 +78,25 @@ BEGIN
   mm_rst  <= i_rst;
 
   -----------------------------------------------
-  -- Translate MM to AXI4 Lite and RL 1 to RL 0
+  -- Translate MM to AXI4 Lite 
   -----------------------------------------------
-  -- 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); 
+  axi4_out_copi <= func_axi4_lite_from_mm_copi(mm_in_copi);
+  mm_in_cipo    <= func_axi4_lite_to_mm_cipo(axi4_out_cipo);
 
   -------------------------------------------
-  -- Translate AXI4 to MM and RL 0 to RL 1
+  -- Translate AXI4 to MM
   -------------------------------------------
   -- 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;
+  i_mm_out_copi <= func_axi4_lite_to_mm_copi(axi4_in_copi);
+  axi4_in_cipo  <= func_axi4_lite_from_mm_cipo(mm_out_cipo, q_bvalid);
 
   -- Generate bvalid
   q_bvalid <= d_bvalid WHEN rising_edge(in_clk); 
 
-  p_bvalid : PROCESS(i_rst, q_bvalid, mm_from_axi4_cipo, mm_from_axi4_copi, axi4_in_copi)
+  p_bvalid : PROCESS(i_rst, q_bvalid, mm_out_cipo, i_mm_out_copi, axi4_in_copi)
   BEGIN
     d_bvalid <= q_bvalid;
-    IF mm_from_axi4_cipo.waitrequest = '0' AND mm_from_axi4_copi.wr = '1' THEN
+    IF mm_out_cipo.waitrequest = '0' AND i_mm_out_copi.wr = '1' THEN
       d_bvalid <= '1';
     ELSIF axi4_in_copi.bready = '1' THEN
       d_bvalid <= '0';
@@ -181,39 +105,7 @@ BEGIN
      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));
-    
+
+  mm_out_copi   <= i_mm_out_copi;
 END str;
 
diff --git a/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd
index 497c8c9068..7214af9bff 100644
--- a/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd
+++ b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd
@@ -93,8 +93,70 @@ PACKAGE axi4_lite_pkg IS
   CONSTANT c_axi4_lite_resp_slverr : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "10"; -- peripheral error
   CONSTANT c_axi4_lite_resp_decerr : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "11"; -- decode error
 
+  -- Functions to convert axi4-lite to MM.
+  FUNCTION func_axi4_lite_to_mm_copi(axi4_copi : t_axi4_lite_copi) RETURN t_mem_copi;
+  FUNCTION func_axi4_lite_to_mm_cipo(axi4_cipo : t_axi4_lite_cipo) RETURN t_mem_cipo;
+
+  -- Functions to convert MM to axi4-lite.
+  FUNCTION func_axi4_lite_from_mm_copi(mm_copi : t_mem_copi) RETURN t_axi4_lite_copi;
+  FUNCTION func_axi4_lite_from_mm_cipo(mm_cipo : t_mem_cipo; bvalid : STD_LOGIC) RETURN t_axi4_lite_cipo;
+
 END axi4_lite_pkg;
 
 PACKAGE BODY axi4_lite_pkg IS
 
+  FUNCTION func_axi4_lite_to_mm_copi(axi4_copi : t_axi4_lite_copi) RETURN t_mem_copi IS
+    VARIABLE v_mm_copi : t_mem_copi := c_mem_copi_rst;
+  BEGIN
+    IF axi4_copi.awvalid = '1' THEN
+      v_mm_copi.address := axi4_copi.awaddr;
+    ELSE
+      v_mm_copi.address := axi4_copi.araddr;
+    END IF;
+    v_mm_copi.wrdata(c_axi4_lite_data_w-1 DOWNTO 0) := axi4_copi.wdata;
+    v_mm_copi.wr                                    := axi4_copi.awvalid;
+    v_mm_copi.rd                                    := axi4_copi.arvalid;
+    RETURN v_mm_copi;
+  END;
+
+  FUNCTION func_axi4_lite_to_mm_cipo(axi4_cipo : t_axi4_lite_cipo) RETURN t_mem_cipo IS
+    VARIABLE v_mm_cipo : t_mem_cipo := c_mem_cipo_rst;
+  BEGIN
+    v_mm_cipo.rddata(c_axi4_lite_data_w-1 DOWNTO 0) := axi4_cipo.rdata;
+    v_mm_cipo.rdval                                 := axi4_cipo.rvalid;
+    v_mm_cipo.waitrequest                           := NOT (axi4_cipo.awready AND axi4_cipo.wready AND axi4_cipo.arready);
+    RETURN v_mm_cipo; 
+  END;
+
+  FUNCTION func_axi4_lite_from_mm_copi(mm_copi : t_mem_copi) RETURN t_axi4_lite_copi IS
+    VARIABLE v_axi4_copi : t_axi4_lite_copi := c_axi4_lite_copi_rst;
+  BEGIN
+    v_axi4_copi.awaddr  := mm_copi.address;  
+    v_axi4_copi.awprot  := (OTHERS => '0');  
+    v_axi4_copi.awvalid := mm_copi.wr;  
+    v_axi4_copi.wdata   := mm_copi.wrdata(c_axi4_lite_data_w-1 DOWNTO 0);  
+    v_axi4_copi.wstrb   := (OTHERS => '1'); -- Either ignored or all bytes selected.  
+    v_axi4_copi.wvalid  := mm_copi.wr;  
+    v_axi4_copi.bready  := '1'; -- Unsupported by MM, assuming always ready.  
+    v_axi4_copi.araddr  := mm_copi.address;  
+    v_axi4_copi.arprot  := (OTHERS => '0');  
+    v_axi4_copi.arvalid := mm_copi.rd;  
+    v_axi4_copi.rready  := '1'; -- Unsupported by MM, assuming always ready.  
+    RETURN v_axi4_copi;
+  END;
+
+  FUNCTION func_axi4_lite_from_mm_cipo(mm_cipo : t_mem_cipo; bvalid : STD_LOGIC) RETURN t_axi4_lite_cipo IS
+    VARIABLE v_axi4_cipo : t_axi4_lite_cipo := c_axi4_lite_cipo_rst;
+  BEGIN
+    v_axi4_cipo.awready := NOT mm_cipo.waitrequest;
+    v_axi4_cipo.wready  := NOT mm_cipo.waitrequest;
+    v_axi4_cipo.bresp   := c_axi4_lite_resp_okay;
+    v_axi4_cipo.bvalid  := bvalid;
+    v_axi4_cipo.arready := NOT mm_cipo.waitrequest;
+    v_axi4_cipo.rdata   := mm_cipo.rddata(c_axi4_lite_data_w-1 DOWNTO 0);
+    v_axi4_cipo.rresp   := c_axi4_lite_resp_okay;
+    v_axi4_cipo.rvalid  := mm_cipo.rdval;
+    RETURN v_axi4_cipo; 
+  END;
+
 END axi4_lite_pkg;
diff --git a/libraries/base/axi4/tb/vhdl/tb_axi4_lite_mm_bridge.vhd b/libraries/base/axi4/tb/vhdl/tb_axi4_lite_mm_bridge.vhd
new file mode 100644
index 0000000000..7ae57fa96c
--- /dev/null
+++ b/libraries/base/axi4/tb/vhdl/tb_axi4_lite_mm_bridge.vhd
@@ -0,0 +1,147 @@
+-------------------------------------------------------------------------------
+--
+-- 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 : R vd Walle
+-- Purpose:  
+--   TB for testing axi4_lite_mm_bridge using common_ram_r_w
+-- Description:
+-------------------------------------------------------------------------------
+
+LIBRARY IEEE, common_lib, mm_lib;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE IEEE.std_logic_textio.ALL;
+USE STD.textio.ALL;
+USE common_lib.common_pkg.ALL;
+USE common_lib.common_mem_pkg.ALL;
+USE common_lib.tb_common_mem_pkg.ALL; 
+USE common_lib.tb_common_pkg.ALL; 
+USE common_lib.common_str_pkg.ALL;
+USE work.axi4_lite_pkg.ALL;
+
+ENTITY tb_axi4_lite_mm_bridge IS
+END tb_axi4_lite_mm_bridge;
+
+ARCHITECTURE tb OF tb_axi4_lite_mm_bridge IS
+
+  CONSTANT c_mm_clk_period   : TIME := 40 ns;
+  CONSTANT c_reset_len       : NATURAL := 4;
+
+  CONSTANT c_mm_usr_ram      : t_c_mem :=   (latency    => 1,
+                                             adr_w	    => 5,
+                                             dat_w	    => 8,
+                                             nof_dat	  => 32,
+                                             init_sl    => '0');
+  CONSTANT c_offset          : NATURAL := 57; --Some value to offset the counter data written to ram.
+
+  SIGNAL mm_rst              : STD_LOGIC;
+  SIGNAL mm_clk              : STD_LOGIC := '0';
+  SIGNAL sim_finished        : STD_LOGIC := '0';
+  SIGNAL tb_end              : STD_LOGIC := '0';
+
+  SIGNAL mm_in_copi          : t_mem_copi := c_mem_copi_rst;
+  SIGNAL mm_in_cipo          : t_mem_cipo := c_mem_cipo_rst;
+  SIGNAL mm_out_copi         : t_mem_copi := c_mem_copi_rst;
+  SIGNAL mm_out_cipo         : t_mem_cipo := c_mem_cipo_rst;
+  SIGNAL ram_copi            : t_mem_copi := c_mem_copi_rst;
+  SIGNAL ram_cipo            : t_mem_cipo := c_mem_cipo_rst;
+
+  SIGNAL axi_copi            : t_axi4_lite_copi;
+  SIGNAL axi_cipo            : t_axi4_lite_cipo;
+
+BEGIN
+
+  mm_clk <= NOT mm_clk OR sim_finished  AFTER c_mm_clk_period/2;
+  mm_rst <= '1', '0'    AFTER c_mm_clk_period*c_reset_len;
+
+  u_axi4_lite_mm_bridge : ENTITY work.axi4_lite_mm_bridge
+  PORT MAP (
+     in_clk        => mm_clk,
+     in_rst        => mm_rst,
+
+     axi4_in_copi  => axi_copi,
+     axi4_in_cipo  => axi_cipo,
+     mm_out_copi   => mm_out_copi,
+     mm_out_cipo   => mm_out_cipo,
+     mm_in_copi    => mm_in_copi,
+     mm_in_cipo    => mm_in_cipo,
+     axi4_out_copi => axi_copi,
+     axi4_out_cipo => axi_cipo
+  );
+
+  u_waitrequest_model : ENTITY mm_lib.mm_waitrequest_model
+  GENERIC MAP (
+    g_waitrequest => TRUE,
+    g_seed        => c_offset
+  )
+  PORT MAP (
+    mm_clk     => mm_clk,
+    bus_mosi   => mm_out_copi,
+    bus_miso   => mm_out_cipo,
+    slave_mosi => ram_copi,
+    slave_miso => ram_cipo
+  );
+
+  u_ram : ENTITY common_lib.common_ram_r_w
+  GENERIC MAP (
+    g_ram     => c_mm_usr_ram
+  )
+  PORT MAP (
+    rst       => mm_rst,
+    clk       => mm_clk,
+    clken     => '1',
+    wr_en     => ram_copi.wr,
+    wr_dat    => ram_copi.wrdata(c_mm_usr_ram.dat_w-1 DOWNTO 0),
+    wr_adr    => ram_copi.address(c_mm_usr_ram.adr_w-1 DOWNTO 0),
+    rd_en     => ram_copi.rd,
+    rd_adr    => ram_copi.address(c_mm_usr_ram.adr_w-1 DOWNTO 0),
+    rd_dat    => ram_cipo.rddata(c_mm_usr_ram.dat_w-1 DOWNTO 0),
+    rd_val    => ram_cipo.rdval
+  );
+
+  -- Testbench writes a number of words to memory and then reads them back trough the AXI interface.
+  -- It uses the axi_lite_transaction to write, read and verify the data.
+  tb : PROCESS
+  BEGIN
+    proc_common_wait_until_low(mm_clk, mm_rst);
+    proc_common_wait_some_cycles(mm_clk, 3);
+    -- write a number of words to memory
+    FOR I IN 0 TO 10 LOOP
+      proc_mem_mm_bus_wr(I, (c_offset + I),  mm_clk, mm_in_cipo, mm_in_copi);      
+    END LOOP;
+  
+    proc_common_wait_some_cycles(mm_clk, 10);
+    -- read the words from memory
+    FOR i IN 0 TO 10 LOOP
+      proc_mem_mm_bus_rd(I, mm_clk, mm_in_cipo, mm_in_copi);
+      proc_mem_mm_bus_rd_latency(1, mm_clk); 
+      ASSERT TO_UINT(mm_in_cipo.rddata(c_mm_usr_ram.dat_w-1 DOWNTO 0)) = (c_offset + I) REPORT
+        "Wrong value read from RAM at address " & int_to_str(I) & " expected " & int_to_str(c_offset + I) 
+          & " but received " & int_to_str(TO_UINT(mm_in_cipo.rddata(c_mm_usr_ram.dat_w-1 DOWNTO 0))) SEVERITY ERROR;
+    END LOOP;
+  
+    sim_finished <= '1';
+    tb_end <= '1';
+    WAIT FOR 1 us;
+    REPORT "Finished Simulation" SEVERITY FAILURE;
+    WAIT;
+  END PROCESS tb;
+END tb;
-- 
GitLab