diff --git a/libraries/base/axi4/hdllib.cfg b/libraries/base/axi4/hdllib.cfg index 3174cab5d7bd9c355e69cd1a246fa88ecbae21e9..6cef475d8b0fc8d940f32a9f4b87ab1f4216cacc 100644 --- a/libraries/base/axi4/hdllib.cfg +++ b/libraries/base/axi4/hdllib.cfg @@ -5,8 +5,10 @@ hdl_lib_uses_sim = hdl_lib_technology = 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 test_bench_files = tb/vhdl/tb_axi4_stream_dp_bridge.vhd 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..a763e876a9dc8e719d8f7d4f88e3c5cb71c57c67 --- /dev/null +++ b/libraries/base/axi4/src/vhdl/axi4_lite_mm_bridge.vhd @@ -0,0 +1,219 @@ +-- -------------------------------------------------------------------------- +-- 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 + + -- Translate AXI4 lite to MM + 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; + + mm_out_copi : OUT t_mem_copi := c_mem_copi_rst; + mm_out_cipo : IN t_mem_cipo := c_mem_cipo_rst; + + -- Translate MM to AXI4 lite + mm_in_copi : IN t_mem_copi := c_mem_copi_rst; + mm_in_cipo : OUT t_mem_cipo := c_mem_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 + ); +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 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, q_bvalid, 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; + diff --git a/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..497c8c9068888f0d5b0d0087b27462af8ff6bb76 --- /dev/null +++ b/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd @@ -0,0 +1,100 @@ +------------------------------------------------------------------------------- +-- +-- 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: +-- Package containing usefull definitions for working with AXI4-Lite +-- Description: +-- Ported from: +-- https://git.astron.nl/desp/gemini/-/blob/master/libraries/base/axi4/src/vhdl/axi4_lite_pkg.vhd +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE std.textio.ALL; +USE IEEE.STD_LOGIC_TEXTIO.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; + +PACKAGE axi4_lite_pkg IS + + ------------------------------------------------------------------------------ + -- Simple AXI4 lite memory access (for MM control interface) + ------------------------------------------------------------------------------ + CONSTANT c_axi4_lite_address_w : NATURAL := 32; + CONSTANT c_axi4_lite_data_w : NATURAL := 32; + CONSTANT c_axi4_lite_prot_w : NATURAL := 3; + CONSTANT c_axi4_lite_resp_w : NATURAL := 2; + + + TYPE t_axi4_lite_copi IS RECORD -- Controller Out Peripheral In + -- write address channel + awaddr : std_logic_vector(c_axi4_lite_address_w-1 downto 0); -- write address + awprot : std_logic_vector(c_axi4_lite_prot_w-1 downto 0); -- access permission for write + awvalid : std_logic; -- write address valid + -- write data channel + wdata : std_logic_vector(c_axi4_lite_data_w-1 downto 0); -- write data + wstrb : std_logic_vector((c_axi4_lite_data_w/c_byte_w)-1 downto 0); -- write strobes + wvalid : std_logic; -- write valid + -- write response channel + bready : std_logic; -- response ready + -- read address channel + araddr : std_logic_vector(c_axi4_lite_address_w-1 downto 0); -- read address + arprot : std_logic_vector(c_axi4_lite_prot_w-1 downto 0); -- access permission for read + arvalid : std_logic; -- read address valid + -- read data channel + rready : std_logic; -- read ready + END RECORD; + + TYPE t_axi4_lite_cipo IS RECORD -- Controller In Peripheral Out + -- write_address channel + awready : std_logic; -- write address ready + -- write data channel + wready : std_logic; -- write ready + -- write response channel + bresp : std_logic_vector(c_axi4_lite_resp_w-1 downto 0); -- write response + bvalid : std_logic; -- write response valid + -- read address channel + arready : std_logic; -- read address ready + -- read data channel + rdata : std_logic_vector(c_axi4_lite_data_w-1 downto 0); -- read data + rresp : std_logic_vector(c_axi4_lite_resp_w-1 downto 0); -- read response + rvalid : std_logic; -- read valid + END RECORD; + + CONSTANT c_axi4_lite_copi_rst : t_axi4_lite_copi := ((OTHERS=>'0'), (OTHERS=>'0'), '0', (OTHERS=>'0'), (OTHERS=>'0'), '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), '0', '0'); + CONSTANT c_axi4_lite_cipo_rst : t_axi4_lite_cipo := ('0', '0', (OTHERS=>'0'), '0', '0', (OTHERS=>'0'), (OTHERS=>'0'), '0'); + + -- Multi port array for MM records + TYPE t_axi4_lite_cipo_arr IS ARRAY (INTEGER RANGE <>) OF t_axi4_lite_cipo; + TYPE t_axi4_lite_copi_arr IS ARRAY (INTEGER RANGE <>) OF t_axi4_lite_copi; + + CONSTANT c_axi4_lite_resp_okay : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "00"; -- normal access success + CONSTANT c_axi4_lite_resp_exokay : STD_LOGIC_VECTOR(c_axi4_lite_resp_w-1 DOWNTO 0) := "01"; -- exclusive access okay + 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 + +END axi4_lite_pkg; + +PACKAGE BODY axi4_lite_pkg IS + +END axi4_lite_pkg;