----------------------------------------------------------------------------------
-- Company: Imperix SA
-- Engineer: @basso (rafael.basso@imperix.ch)
-- 
-- Create Date: 04/30/2024 12:59:46 PM
-- Module Name: sbio_interconnect - impl
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity sbio_interconnect is
	Port(
		clk_250_mhz       : in  std_logic;
		--* SBIO Bus Master 0 interface
		M0_SBIO_BUS_addr  : in  std_logic_vector(9 downto 0);
		M0_SBIO_BUS_we    : in  std_logic;
		M0_SBIO_BUS_wdata : in  std_logic_vector(15 downto 0);
		M0_SBIO_BUS_rdata : out std_logic_vector(15 downto 0);
		--* SBIO Bus Slave 0 interface
		S0_SBIO_BUS_addr  : out std_logic_vector(9 downto 0);
		S0_SBIO_BUS_we    : out std_logic;
		S0_SBIO_BUS_wdata : out std_logic_vector(15 downto 0);
		S0_SBIO_BUS_rdata : in  std_logic_vector(15 downto 0) := (others => '0');
		--* SBIO Bus Slave 1 interface
		S1_SBIO_BUS_addr  : out std_logic_vector(9 downto 0);
		S1_SBIO_BUS_we    : out std_logic;
		S1_SBIO_BUS_wdata : out std_logic_vector(15 downto 0);
		S1_SBIO_BUS_rdata : in  std_logic_vector(15 downto 0) := (others => '0');
		--* SBIO Bus Slave 2 interface
		S2_SBIO_BUS_addr  : out std_logic_vector(9 downto 0);
		S2_SBIO_BUS_we    : out std_logic;
		S2_SBIO_BUS_wdata : out std_logic_vector(15 downto 0);
		S2_SBIO_BUS_rdata : in  std_logic_vector(15 downto 0) := (others => '0');
		--* SBIO Bus Slave 3 interface
		S3_SBIO_BUS_addr  : out std_logic_vector(9 downto 0);
		S3_SBIO_BUS_we    : out std_logic;
		S3_SBIO_BUS_wdata : out std_logic_vector(15 downto 0);
		S3_SBIO_BUS_rdata : in  std_logic_vector(15 downto 0) := (others => '0');
		--* Sync Pulse (reset)
		sync_pulse_in     : in std_logic
	);
end sbio_interconnect;

architecture impl of sbio_interconnect is

	--* Attribute Definition
	----------------------------------------------------------------------------
	ATTRIBUTE X_INTERFACE_INFO : STRING;
    ATTRIBUTE X_INTERFACE_PARAMETER : STRING;

	ATTRIBUTE X_INTERFACE_INFO of M0_SBIO_BUS_addr:  SIGNAL is "imperix.ch:ix:sbio_bus:1.0 M0_SBIO_BUS sb_addr";
	ATTRIBUTE X_INTERFACE_INFO of M0_SBIO_BUS_we:    SIGNAL is "imperix.ch:ix:sbio_bus:1.0 M0_SBIO_BUS sb_we";
	ATTRIBUTE X_INTERFACE_INFO of M0_SBIO_BUS_wdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 M0_SBIO_BUS sb_wdata";
	ATTRIBUTE X_INTERFACE_INFO of M0_SBIO_BUS_rdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 M0_SBIO_BUS sb_rdata";

	ATTRIBUTE X_INTERFACE_INFO of S0_SBIO_BUS_addr:  SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S0_SBIO_BUS sb_addr";
	ATTRIBUTE X_INTERFACE_INFO of S0_SBIO_BUS_we:    SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S0_SBIO_BUS sb_we";
	ATTRIBUTE X_INTERFACE_INFO of S0_SBIO_BUS_wdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S0_SBIO_BUS sb_wdata";
	ATTRIBUTE X_INTERFACE_INFO of S0_SBIO_BUS_rdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S0_SBIO_BUS sb_rdata";

	ATTRIBUTE X_INTERFACE_INFO of S1_SBIO_BUS_addr:  SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S1_SBIO_BUS sb_addr";
	ATTRIBUTE X_INTERFACE_INFO of S1_SBIO_BUS_we:    SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S1_SBIO_BUS sb_we";
	ATTRIBUTE X_INTERFACE_INFO of S1_SBIO_BUS_wdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S1_SBIO_BUS sb_wdata";
	ATTRIBUTE X_INTERFACE_INFO of S1_SBIO_BUS_rdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S1_SBIO_BUS sb_rdata";

	ATTRIBUTE X_INTERFACE_INFO of S2_SBIO_BUS_addr:  SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S2_SBIO_BUS sb_addr";
	ATTRIBUTE X_INTERFACE_INFO of S2_SBIO_BUS_we:    SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S2_SBIO_BUS sb_we";
	ATTRIBUTE X_INTERFACE_INFO of S2_SBIO_BUS_wdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S2_SBIO_BUS sb_wdata";
	ATTRIBUTE X_INTERFACE_INFO of S2_SBIO_BUS_rdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S2_SBIO_BUS sb_rdata";

	ATTRIBUTE X_INTERFACE_INFO of S3_SBIO_BUS_addr:  SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S3_SBIO_BUS sb_addr";
	ATTRIBUTE X_INTERFACE_INFO of S3_SBIO_BUS_we:    SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S3_SBIO_BUS sb_we";
	ATTRIBUTE X_INTERFACE_INFO of S3_SBIO_BUS_wdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S3_SBIO_BUS sb_wdata";
	ATTRIBUTE X_INTERFACE_INFO of S3_SBIO_BUS_rdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 S3_SBIO_BUS sb_rdata";

    ATTRIBUTE X_INTERFACE_INFO of clk_250_mhz: SIGNAL is "xilinx.com:signal:clock:1.0 clk_250_mhz CLK";
    ATTRIBUTE X_INTERFACE_PARAMETER of clk_250_mhz: SIGNAL is "ASSOCIATED_BUSIF SBIO_BUS";

	--* Type Definition
	----------------------------------------------------------------------------
	type t_select is array(natural range 0 to 3) of std_logic_vector(1 downto 0);

    --* Signal Definition
	----------------------------------------------------------------------------
	signal w_select : std_logic_vector(1 downto 0);
	signal r_select : t_select;

	signal w_addr   : std_logic_vector(9 downto 0);
begin

	P_SEQ : process (clk_250_mhz, sync_pulse_in, r_select, w_select, M0_SBIO_BUS_addr)
	begin

		if (rising_edge(clk_250_mhz)) then

			r_select(0) <= w_select;
			r_select(r_select'left + 1 to r_select'right) <= r_select(r_select'left to r_select'right - 1);

			if (sync_pulse_in = '1') then
				r_select <= (others => (others => '0'));
			end if;
		end if;

	end process P_SEQ;

	w_select <= M0_SBIO_BUS_addr(M0_SBIO_BUS_addr'left downto M0_SBIO_BUS_addr'left - 1);
	w_addr   <= "00" & M0_SBIO_BUS_addr(M0_SBIO_BUS_addr'left - 2 downto 0);

	-- Slave 0 MUX
	S0_SBIO_BUS_addr  <= w_addr  when w_select = "00" else (others => '0');
	S0_SBIO_BUS_we    <= M0_SBIO_BUS_we    when w_select = "00" else '0';
	S0_SBIO_BUS_wdata <= M0_SBIO_BUS_wdata when w_select = "00" else (others => '0');

	-- Slave 1 MUX
	S1_SBIO_BUS_addr  <= w_addr  when w_select = "01" else (others => '0');
	S1_SBIO_BUS_we    <= M0_SBIO_BUS_we    when w_select = "01" else '0';
	S1_SBIO_BUS_wdata <= M0_SBIO_BUS_wdata when w_select = "01" else (others => '0');

	-- Slave 2 MUX
	S2_SBIO_BUS_addr  <= w_addr  when w_select = "10" else (others => '0');
	S2_SBIO_BUS_we    <= M0_SBIO_BUS_we    when w_select = "10" else '0';
	S2_SBIO_BUS_wdata <= M0_SBIO_BUS_wdata when w_select = "10" else (others => '0');

	-- Slave 3 MUX
	S3_SBIO_BUS_addr  <= w_addr  when w_select = "11" else (others => '0');
	S3_SBIO_BUS_we    <= M0_SBIO_BUS_we    when w_select = "11" else '0';
	S3_SBIO_BUS_wdata <= M0_SBIO_BUS_wdata when w_select = "11" else (others => '0');

	-- Read Data MUX
	M0_SBIO_BUS_rdata <= S0_SBIO_BUS_rdata when r_select(3) = "00" else
	                     S1_SBIO_BUS_rdata when r_select(3) = "01" else
	                     S2_SBIO_BUS_rdata when r_select(3) = "10" else
                         S3_SBIO_BUS_rdata when r_select(3) = "11" else (others => '0');

end impl;