From 28ff4e33c1fe41fef974b867925b95231025a29e Mon Sep 17 00:00:00 2001 From: Reinier van der Walle <walle@astron.nl> Date: Fri, 31 Mar 2023 17:18:28 +0200 Subject: [PATCH] added axi4_lite_mm_bridge --- libraries/base/axi4/hdllib.cfg | 1 + .../axi4/src/vhdl/axi4_lite_mm_bridge.vhd | 216 ++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd diff --git a/libraries/base/axi4/hdllib.cfg b/libraries/base/axi4/hdllib.cfg index 21929d4db4..0442544293 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 0000000000..6c50c09f77 --- /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; + -- GitLab