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

entity ix_axis_interface_24adc32 is
	Port (
		------------------------------------------------------------------------
		-- INTERFACE WITH USER FPGA LOGIC
		------------------------------------------------------------------------

		-- ADC outputs (Now 32-bit)

		M_AXIS_ADC_00_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_00_tready : in std_logic;
		M_AXIS_ADC_00_tvalid : out std_logic;

		M_AXIS_ADC_01_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_01_tready : in std_logic;
		M_AXIS_ADC_01_tvalid : out std_logic;

		M_AXIS_ADC_02_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_02_tready : in std_logic;
		M_AXIS_ADC_02_tvalid : out std_logic;

		M_AXIS_ADC_03_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_03_tready : in std_logic;
		M_AXIS_ADC_03_tvalid : out std_logic;

		M_AXIS_ADC_04_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_04_tready : in std_logic;
		M_AXIS_ADC_04_tvalid : out std_logic;

		M_AXIS_ADC_05_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_05_tready : in std_logic;
		M_AXIS_ADC_05_tvalid : out std_logic;

		M_AXIS_ADC_06_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_06_tready : in std_logic;
		M_AXIS_ADC_06_tvalid : out std_logic;

		M_AXIS_ADC_07_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_07_tready : in std_logic;
		M_AXIS_ADC_07_tvalid : out std_logic;

		M_AXIS_ADC_08_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_08_tready : in std_logic;
		M_AXIS_ADC_08_tvalid : out std_logic;

		M_AXIS_ADC_09_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_09_tready : in std_logic;
		M_AXIS_ADC_09_tvalid : out std_logic;

		M_AXIS_ADC_10_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_10_tready : in std_logic;
		M_AXIS_ADC_10_tvalid : out std_logic;

		M_AXIS_ADC_11_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_11_tready : in std_logic;
		M_AXIS_ADC_11_tvalid : out std_logic;

		M_AXIS_ADC_12_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_12_tready : in std_logic;
		M_AXIS_ADC_12_tvalid : out std_logic;

		M_AXIS_ADC_13_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_13_tready : in std_logic;
		M_AXIS_ADC_13_tvalid : out std_logic;

		M_AXIS_ADC_14_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_14_tready : in std_logic;
		M_AXIS_ADC_14_tvalid : out std_logic;

		M_AXIS_ADC_15_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_15_tready : in std_logic;
		M_AXIS_ADC_15_tvalid : out std_logic;
		
		M_AXIS_ADC_16_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_16_tready : in std_logic;
		M_AXIS_ADC_16_tvalid : out std_logic;

		M_AXIS_ADC_17_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_17_tready : in std_logic;
		M_AXIS_ADC_17_tvalid : out std_logic;

		M_AXIS_ADC_18_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_18_tready : in std_logic;
		M_AXIS_ADC_18_tvalid : out std_logic;

		M_AXIS_ADC_19_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_19_tready : in std_logic;
		M_AXIS_ADC_19_tvalid : out std_logic;

		M_AXIS_ADC_20_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_20_tready : in std_logic;
		M_AXIS_ADC_20_tvalid : out std_logic;

		M_AXIS_ADC_21_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_21_tready : in std_logic;
		M_AXIS_ADC_21_tvalid : out std_logic;

		M_AXIS_ADC_22_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_22_tready : in std_logic;
		M_AXIS_ADC_22_tvalid : out std_logic;

		M_AXIS_ADC_23_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_ADC_23_tready : in std_logic;
		M_AXIS_ADC_23_tvalid : out std_logic;

		-- CPU to FPGA outputs

		M_AXIS_CPU2FPGA_00_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_00_tready : in std_logic;
		M_AXIS_CPU2FPGA_00_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_01_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_01_tready : in std_logic;
		M_AXIS_CPU2FPGA_01_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_02_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_02_tready : in std_logic;
		M_AXIS_CPU2FPGA_02_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_03_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_03_tready : in std_logic;
		M_AXIS_CPU2FPGA_03_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_04_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_04_tready : in std_logic;
		M_AXIS_CPU2FPGA_04_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_05_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_05_tready : in std_logic;
		M_AXIS_CPU2FPGA_05_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_06_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_06_tready : in std_logic;
		M_AXIS_CPU2FPGA_06_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_07_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_07_tready : in std_logic;
		M_AXIS_CPU2FPGA_07_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_08_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_08_tready : in std_logic;
		M_AXIS_CPU2FPGA_08_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_09_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_09_tready : in std_logic;
		M_AXIS_CPU2FPGA_09_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_10_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_10_tready : in std_logic;
		M_AXIS_CPU2FPGA_10_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_11_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_11_tready : in std_logic;
		M_AXIS_CPU2FPGA_11_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_12_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_12_tready : in std_logic;
		M_AXIS_CPU2FPGA_12_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_13_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_13_tready : in std_logic;
		M_AXIS_CPU2FPGA_13_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_14_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_14_tready : in std_logic;
		M_AXIS_CPU2FPGA_14_tvalid : out std_logic;

		M_AXIS_CPU2FPGA_15_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_CPU2FPGA_15_tready : in std_logic;
		M_AXIS_CPU2FPGA_15_tvalid : out std_logic;

		-- FPGA to CPU inputs

		S_AXIS_FPGA2CPU_00_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_00_tready : out std_logic;
		S_AXIS_FPGA2CPU_00_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_01_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_01_tready : out std_logic;
		S_AXIS_FPGA2CPU_01_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_02_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_02_tready : out std_logic;
		S_AXIS_FPGA2CPU_02_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_03_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_03_tready : out std_logic;
		S_AXIS_FPGA2CPU_03_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_04_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_04_tready : out std_logic;
		S_AXIS_FPGA2CPU_04_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_05_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_05_tready : out std_logic;
		S_AXIS_FPGA2CPU_05_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_06_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_06_tready : out std_logic;
		S_AXIS_FPGA2CPU_06_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_07_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_07_tready : out std_logic;
		S_AXIS_FPGA2CPU_07_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_08_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_08_tready : out std_logic;
		S_AXIS_FPGA2CPU_08_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_09_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_09_tready : out std_logic;
		S_AXIS_FPGA2CPU_09_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_10_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_10_tready : out std_logic;
		S_AXIS_FPGA2CPU_10_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_11_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_11_tready : out std_logic;
		S_AXIS_FPGA2CPU_11_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_12_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_12_tready : out std_logic;
		S_AXIS_FPGA2CPU_12_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_13_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_13_tready : out std_logic;
		S_AXIS_FPGA2CPU_13_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_14_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_14_tready : out std_logic;
		S_AXIS_FPGA2CPU_14_tvalid : in std_logic := '1';

		S_AXIS_FPGA2CPU_15_tdata  : in std_logic_vector(31 downto 0) := (others => '0');
		S_AXIS_FPGA2CPU_15_tready : out std_logic;
		S_AXIS_FPGA2CPU_15_tvalid : in std_logic := '1';

		-- Sample time Ts output

		M_AXIS_Ts_tdata  : out std_logic_vector(31 downto 0);
		M_AXIS_Ts_tready : in std_logic;
		M_AXIS_Ts_tvalid : out std_logic;
		
		-- reset outputs
		nReset_ctrl : out std_logic; -- Activated by CPU by written "1" in SBO_63. Typically used for PID controller
		nReset_sync : out std_logic; -- Activated when loading user code

		------------------------------------------------------------------------
		-- INTERFACE WITH IMPERIX FIRMWARE IP
		------------------------------------------------------------------------

		-- ADC (Now 32-bit inputs)

		adc_00_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_01_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_02_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_03_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_04_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_05_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_06_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_07_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_08_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_09_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_10_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_11_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_12_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_13_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_14_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_15_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_16_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_17_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_18_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_19_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_20_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_21_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_22_in : in std_logic_vector(31 downto 0) := (others => '0');
		adc_23_in : in std_logic_vector(31 downto 0) := (others => '0');

		-- SBIO

        SBIO_BUS_addr  : in  std_logic_vector(9 downto 0);
		SBIO_BUS_we    : in  std_logic;
		SBIO_BUS_wdata : in  std_logic_vector(15 downto 0);
		SBIO_BUS_rdata : out std_logic_vector(15 downto 0);

		-- Timing pulses

		adc_done_pulse_in   : in std_logic;
		data_valid_pulse_in : in std_logic;
		data_reading_in     : in std_logic;
		sync_pulse_in       : in std_logic;

		-- Main clock running at 250 MHz
		clk : in std_logic
	);
end ix_axis_interface_24adc32;

architecture impl of ix_axis_interface_24adc32 is

	ATTRIBUTE X_INTERFACE_INFO : STRING;
	ATTRIBUTE X_INTERFACE_PARAMETER : STRING;
	ATTRIBUTE X_INTERFACE_INFO of clk: SIGNAL is "xilinx.com:signal:clock:1.0 clk CLK";

    -- SBIO interface

    ATTRIBUTE X_INTERFACE_INFO of SBIO_BUS_addr:  SIGNAL is "imperix.ch:ix:sbio_bus:1.0 SBIO_BUS sb_addr";
	ATTRIBUTE X_INTERFACE_INFO of SBIO_BUS_we:    SIGNAL is "imperix.ch:ix:sbio_bus:1.0 SBIO_BUS sb_we";
	ATTRIBUTE X_INTERFACE_INFO of SBIO_BUS_wdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 SBIO_BUS sb_wdata";
	ATTRIBUTE X_INTERFACE_INFO of SBIO_BUS_rdata: SIGNAL is "imperix.ch:ix:sbio_bus:1.0 SBIO_BUS sb_rdata";

	-- ADC interface

	ATTRIBUTE X_INTERFACE_INFO of adc_00_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_00";
	ATTRIBUTE X_INTERFACE_INFO of adc_01_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_01";
	ATTRIBUTE X_INTERFACE_INFO of adc_02_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_02";
	ATTRIBUTE X_INTERFACE_INFO of adc_03_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_03";
	ATTRIBUTE X_INTERFACE_INFO of adc_04_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_04";
	ATTRIBUTE X_INTERFACE_INFO of adc_05_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_05";
	ATTRIBUTE X_INTERFACE_INFO of adc_06_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_06";
	ATTRIBUTE X_INTERFACE_INFO of adc_07_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_07";
	ATTRIBUTE X_INTERFACE_INFO of adc_08_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_08";
	ATTRIBUTE X_INTERFACE_INFO of adc_09_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_09";
	ATTRIBUTE X_INTERFACE_INFO of adc_10_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_10";
	ATTRIBUTE X_INTERFACE_INFO of adc_11_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_11";
	ATTRIBUTE X_INTERFACE_INFO of adc_12_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_12";
	ATTRIBUTE X_INTERFACE_INFO of adc_13_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_13";
	ATTRIBUTE X_INTERFACE_INFO of adc_14_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_14";
	ATTRIBUTE X_INTERFACE_INFO of adc_15_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_15";
	ATTRIBUTE X_INTERFACE_INFO of adc_16_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_16";
	ATTRIBUTE X_INTERFACE_INFO of adc_17_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_17";
	ATTRIBUTE X_INTERFACE_INFO of adc_18_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_18";
	ATTRIBUTE X_INTERFACE_INFO of adc_19_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_19";
	ATTRIBUTE X_INTERFACE_INFO of adc_20_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_20";
	ATTRIBUTE X_INTERFACE_INFO of adc_21_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_21";
	ATTRIBUTE X_INTERFACE_INFO of adc_22_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_22";
	ATTRIBUTE X_INTERFACE_INFO of adc_23_in: SIGNAL is "imperix.ch:ix:user_regs_rtl:1.0 ADC reg_23";
	    
	-- SBO registers
	type t_sbois is array (0 to 31) of std_logic_vector(15 downto 0);
	signal r_sbo : t_sbois;
	signal r_data_valid : std_logic := '0';

	-- ADC registers
	type t_adcs is array (0 to 23) of std_logic_vector(31 downto 0);
	signal r_adc : t_adcs;
	signal r_adc_done : std_logic := '0';

	-- Ts count
    signal cnt_Ts : unsigned(31 downto 0) := (30 downto 0 => '0') & '1';
    signal r_Ts : std_logic_vector(31 downto 0) := (others => '0');

    -- controller nReset
	signal r_CpuCommand           : std_logic := '1'; -- 1: output disabled; 0: output enabled
	signal reg_nReset_ctrl        : std_logic := '1';
	signal reg_nReset_ctrl_delay1 : std_logic := '1';
	signal reg_nReset_ctrl_delay2 : std_logic := '1';
	signal reg_nReset_ctrl_delay3 : std_logic := '1';

	-- sync nReset
	signal reg_nReset_sync        : std_logic := '1';
	signal reg_nReset_sync_delay1 : std_logic := '1';
	signal reg_nReset_sync_delay2 : std_logic := '1';
	signal reg_nReset_sync_delay3 : std_logic := '1';

    signal r_S_AXIS_FPGA2CPU_tready: std_logic;

    -- SBIO-related signals

    signal r_addr_low_0 : std_logic_vector(3 downto 0);
    signal r_addr_low_1 : std_logic_vector(3 downto 0);
    signal r_addr_low_2 : std_logic_vector(3 downto 0);
    signal r_addr_low_3 : std_logic_vector(3 downto 0);

    signal r_addr_high_0 : std_logic_vector(5 downto 0);
    signal r_addr_high_1 : std_logic_vector(5 downto 0);
    signal r_addr_high_2 : std_logic_vector(5 downto 0);
    signal r_addr_high_3 : std_logic_vector(5 downto 0);

    signal r_addr     : natural range 0 to 31;
    signal r_addr_ff  : natural range 0 to 31;
    signal r_addr_ff2 : natural range 0 to 31;
	
    signal r_we  :	std_logic;

    signal r_wdata_0   :   std_logic_vector(15 downto 0);
    signal r_wdata_1   :   std_logic_vector(15 downto 0);
    signal r_wdata_2   :   std_logic_vector(15 downto 0);
    signal r_wdata_3   :   std_logic_vector(15 downto 0);
	
    signal w_addr_0: natural range 0 to 15;
    signal w_addr_1: natural range 0 to 15;
    signal w_addr_2: natural range 0 to 15;
    signal w_addr_3: natural range 0 to 15;

    signal w_bank_0: natural range 0 to 3;
    signal w_bank_1: natural range 0 to 3;
    signal w_bank_2: natural range 0 to 3;
    signal w_bank_3: natural range 0 to 3;

    type type_sbo_bank is array(natural range 0 to 15) of std_logic_vector(15 downto 0);
    signal r_sbo_bank0 : type_sbo_bank;
    signal r_sbo_bank1 : type_sbo_bank;
    --signal r_sbo_bank2 : type_sbo_bank;
    --signal r_sbo_bank3 : type_sbo_bank;
	signal r_sbo_in_cpu_cmd  : std_logic;
	signal r_sbo_cpu_cmd  : std_logic;

    type type_sbi is array(natural range 0 to 31) of std_logic_vector(15 downto 0);
    signal r_sbi : type_sbi;

    attribute KEEP : string;
    attribute KEEP of r_addr_low_0  : signal is "true";
    attribute KEEP of r_addr_low_1  : signal is "true";
    attribute KEEP of r_addr_low_2  : signal is "true";
    attribute KEEP of r_addr_low_3  : signal is "true";
    attribute KEEP of r_addr_high_0 : signal is "true";
    attribute KEEP of r_addr_high_1 : signal is "true";
    attribute KEEP of r_addr_high_2 : signal is "true";
    attribute KEEP of r_addr_high_3 : signal is "true";
    attribute KEEP of r_wdata_0     : signal is "true";
    attribute KEEP of r_wdata_1     : signal is "true";
    attribute KEEP of r_wdata_2     : signal is "true";
    attribute KEEP of r_wdata_3     : signal is "true";

    attribute SAVE : string;
    attribute SAVE of r_addr_low_0  : signal is "true";
    attribute SAVE of r_addr_low_1  : signal is "true";
    attribute SAVE of r_addr_low_2  : signal is "true";
    attribute SAVE of r_addr_low_3  : signal is "true";
    attribute SAVE of r_addr_high_0 : signal is "true";
    attribute SAVE of r_addr_high_1 : signal is "true";
    attribute SAVE of r_addr_high_2 : signal is "true";
    attribute SAVE of r_addr_high_3 : signal is "true";
    attribute SAVE of r_wdata_0     : signal is "true";
    attribute SAVE of r_wdata_1     : signal is "true";
    attribute SAVE of r_wdata_2     : signal is "true";
    attribute SAVE of r_wdata_3     : signal is "true";

begin

    w_addr_0 <= to_integer(unsigned(r_addr_low_0));
    w_addr_1 <= to_integer(unsigned(r_addr_low_1));
    w_addr_2 <= to_integer(unsigned(r_addr_low_2));
    w_addr_3 <= to_integer(unsigned(r_addr_low_3));

    w_bank_0 <= to_integer(unsigned(r_addr_high_0));
    w_bank_1 <= to_integer(unsigned(r_addr_high_1));
    w_bank_2 <= to_integer(unsigned(r_addr_high_2));
    w_bank_3 <= to_integer(unsigned(r_addr_high_3));

	A : process(clk)
	begin
		if rising_edge(clk) then
			r_we    <= SBIO_BUS_we;
			
			r_wdata_0 <= SBIO_BUS_wdata;
			r_wdata_1 <= SBIO_BUS_wdata;
			r_wdata_2 <= SBIO_BUS_wdata;
			r_wdata_3 <= SBIO_BUS_wdata;

			r_addr <= to_integer(unsigned(SBIO_BUS_addr(4 downto 0)));
			r_addr_ff <= r_addr;
			r_addr_ff2 <= r_addr_ff;
			SBIO_BUS_rdata <= r_sbi(r_addr_ff2); -- latency of 4

			r_addr_low_0 <= SBIO_BUS_addr(3 downto 0);
			r_addr_low_1 <= SBIO_BUS_addr(3 downto 0);
			r_addr_low_2 <= SBIO_BUS_addr(3 downto 0);
			r_addr_low_3 <= SBIO_BUS_addr(3 downto 0);

			r_addr_high_0 <= SBIO_BUS_addr(9 downto 4);
			r_addr_high_1 <= SBIO_BUS_addr(9 downto 4);
			r_addr_high_2 <= SBIO_BUS_addr(9 downto 4);
			r_addr_high_3 <= SBIO_BUS_addr(9 downto 4);

			if r_we = '1' then
				if w_bank_0 = 0 then
					r_sbo_bank0(w_addr_0) <= r_wdata_0;
				elsif w_bank_1 = 1 then
					r_sbo_bank1(w_addr_1) <= r_wdata_1;
				--elsif w_bank_2 = 2 then
				--	r_sbo_bank2(w_addr_2) <= r_wdata_2;
				--elsif w_bank_3 = 3 then 
				--	r_sbo_bank3(w_addr_3) <= r_wdata_3;
				elsif w_bank_3 = 3 then 
					if w_addr_3 = 15 then
						r_sbo_in_cpu_cmd <= r_wdata_3(0);
					end if;
				end if;
			end if;

		end if;
	end process A;

    B : process(clk)
	begin
		if rising_edge(clk) then
			if data_valid_pulse_in = '1' then
				r_sbo(0)  <= r_sbo_bank0(0);
				r_sbo(1)  <= r_sbo_bank0(1);
				r_sbo(2)  <= r_sbo_bank0(2);
				r_sbo(3)  <= r_sbo_bank0(3);
				r_sbo(4)  <= r_sbo_bank0(4);
				r_sbo(5)  <= r_sbo_bank0(5);
				r_sbo(6)  <= r_sbo_bank0(6);
				r_sbo(7)  <= r_sbo_bank0(7);
				r_sbo(8)  <= r_sbo_bank0(8);
				r_sbo(9)  <= r_sbo_bank0(9);
				r_sbo(10) <= r_sbo_bank0(10);
				r_sbo(11) <= r_sbo_bank0(11);
				r_sbo(12) <= r_sbo_bank0(12);
				r_sbo(13) <= r_sbo_bank0(13);
				r_sbo(14) <= r_sbo_bank0(14);
				r_sbo(15) <= r_sbo_bank0(15);
				r_sbo(16) <= r_sbo_bank1(0);
				r_sbo(17) <= r_sbo_bank1(1);
				r_sbo(18) <= r_sbo_bank1(2);
				r_sbo(19) <= r_sbo_bank1(3);
				r_sbo(20) <= r_sbo_bank1(4);
				r_sbo(21) <= r_sbo_bank1(5);
				r_sbo(22) <= r_sbo_bank1(6);
				r_sbo(23) <= r_sbo_bank1(7);
				r_sbo(24) <= r_sbo_bank1(8);
				r_sbo(25) <= r_sbo_bank1(9);
				r_sbo(26) <= r_sbo_bank1(10);
				r_sbo(27) <= r_sbo_bank1(11);
				r_sbo(28) <= r_sbo_bank1(12);
				r_sbo(29) <= r_sbo_bank1(13);
				r_sbo(30) <= r_sbo_bank1(14);
				r_sbo(31) <= r_sbo_bank1(15);
				--r_sbo(32) <= r_sbo_bank2(0);
				--r_sbo(33) <= r_sbo_bank2(1);
				--r_sbo(34) <= r_sbo_bank2(2);
				--r_sbo(35) <= r_sbo_bank2(3);
				--r_sbo(36) <= r_sbo_bank2(4);
				--r_sbo(37) <= r_sbo_bank2(5);
				--r_sbo(38) <= r_sbo_bank2(6);
				--r_sbo(39) <= r_sbo_bank2(7);
				--r_sbo(40) <= r_sbo_bank2(8);
				--r_sbo(41) <= r_sbo_bank2(9);
				--r_sbo(42) <= r_sbo_bank2(10);
				--r_sbo(43) <= r_sbo_bank2(11);
				--r_sbo(44) <= r_sbo_bank2(12);
				--r_sbo(45) <= r_sbo_bank2(13);
				--r_sbo(46) <= r_sbo_bank2(14);
				--r_sbo(47) <= r_sbo_bank2(15);
				--r_sbo(48) <= r_sbo_bank3(0);
				--r_sbo(49) <= r_sbo_bank3(1);
				--r_sbo(50) <= r_sbo_bank3(2);
				--r_sbo(51) <= r_sbo_bank3(3);
				--r_sbo(52) <= r_sbo_bank3(4);
				--r_sbo(53) <= r_sbo_bank3(5);
				--r_sbo(54) <= r_sbo_bank3(6);
				--r_sbo(55) <= r_sbo_bank3(7);
				--r_sbo(56) <= r_sbo_bank3(8);
				--r_sbo(57) <= r_sbo_bank3(9);
				--r_sbo(58) <= r_sbo_bank3(10);
				--r_sbo(59) <= r_sbo_bank3(11);
				--r_sbo(60) <= r_sbo_bank3(12);
				--r_sbo(61) <= r_sbo_bank3(13);
				--r_sbo(62) <= r_sbo_bank3(14);
				--r_sbo(63) <= r_sbo_bank3(15);
				r_sbo_cpu_cmd <= r_sbo_in_cpu_cmd;
			end if;
        end if;
    end process B;

    -- ///////////////////////////////////////////////////

	P_ADC_AXIS : process(clk)
	begin
        if rising_edge(clk) then
            -- ADC0
            if r_data_valid = '1'then
                M_AXIS_ADC_00_tvalid <= '1';
                M_AXIS_ADC_00_tdata <= r_adc(0);
            else
                if M_AXIS_ADC_00_tready = '1' then
                    M_AXIS_ADC_00_tvalid <= '0';
                end if;
            end if;
    
            -- ADC1
            if r_data_valid = '1' then
                M_AXIS_ADC_01_tvalid <= '1';
                M_AXIS_ADC_01_tdata <= r_adc(1);
            else
                if M_AXIS_ADC_01_tready = '1' then
                    M_AXIS_ADC_01_tvalid <= '0';
                end if;
            end if;
    
            -- ADC2
            if r_data_valid = '1'then
                M_AXIS_ADC_02_tvalid <= '1';
                M_AXIS_ADC_02_tdata <= r_adc(2);
            else
                if M_AXIS_ADC_02_tready = '1' then
                    M_AXIS_ADC_02_tvalid <= '0';
                end if;
            end if;
    
            -- ADC3
            if r_data_valid = '1'then
                M_AXIS_ADC_03_tvalid <= '1';
                M_AXIS_ADC_03_tdata <= r_adc(3);
            else
                if M_AXIS_ADC_03_tready = '1' then
                    M_AXIS_ADC_03_tvalid <= '0';
                end if;
            end if;
    
            -- ADC4
            if r_data_valid = '1'then
                M_AXIS_ADC_04_tvalid <= '1';
                M_AXIS_ADC_04_tdata <= r_adc(4);
            else
                if M_AXIS_ADC_04_tready = '1' then
                    M_AXIS_ADC_04_tvalid <= '0';
                end if;
            end if;
    
            -- ADC5
            if r_data_valid = '1'then
                M_AXIS_ADC_05_tvalid <= '1';
                M_AXIS_ADC_05_tdata <= r_adc(5);
            else
                if M_AXIS_ADC_05_tready = '1' then
                    M_AXIS_ADC_05_tvalid <= '0';
                end if;
            end if;
    
            -- ADC6
            if r_data_valid = '1'then
                M_AXIS_ADC_06_tvalid <= '1';
                M_AXIS_ADC_06_tdata <= r_adc(6);
            else
                if M_AXIS_ADC_06_tready = '1' then
                    M_AXIS_ADC_06_tvalid <= '0';
                end if;
            end if;
    
            -- ADC7
            if r_data_valid = '1'then
                M_AXIS_ADC_07_tvalid <= '1';
                M_AXIS_ADC_07_tdata <= r_adc(7);
            else
                if M_AXIS_ADC_07_tready = '1' then
                    M_AXIS_ADC_07_tvalid <= '0';
                end if;
            end if;
    
            -- ADC8
            if r_data_valid = '1'then
                M_AXIS_ADC_08_tvalid <= '1';
                M_AXIS_ADC_08_tdata <= r_adc(8);
            else
                if M_AXIS_ADC_08_tready = '1' then
                    M_AXIS_ADC_08_tvalid <= '0';
                end if;
            end if;
    
            -- ADC9
            if r_data_valid = '1'then
                M_AXIS_ADC_09_tvalid <= '1';
                M_AXIS_ADC_09_tdata <= r_adc(9);
            else
                if M_AXIS_ADC_09_tready = '1' then
                    M_AXIS_ADC_09_tvalid <= '0';
                end if;
            end if;
    
            -- ADC10
            if r_data_valid = '1'then
                M_AXIS_ADC_10_tvalid <= '1';
                M_AXIS_ADC_10_tdata <= r_adc(10);
            else
                if M_AXIS_ADC_10_tready = '1' then
                    M_AXIS_ADC_10_tvalid <= '0';
                end if;
            end if;
    
            -- ADC11
            if r_data_valid = '1'then
                M_AXIS_ADC_11_tvalid <= '1';
                M_AXIS_ADC_11_tdata <= r_adc(11);
            else
                if M_AXIS_ADC_11_tready = '1' then
                    M_AXIS_ADC_11_tvalid <= '0';
                end if;
            end if;
    
            -- ADC12
            if r_data_valid = '1'then
                M_AXIS_ADC_12_tvalid <= '1';
                M_AXIS_ADC_12_tdata <= r_adc(12);
            else
                if M_AXIS_ADC_12_tready = '1' then
                    M_AXIS_ADC_12_tvalid <= '0';
                end if;
            end if;
    
            -- ADC13
            if r_data_valid = '1'then
                M_AXIS_ADC_13_tvalid <= '1';
                M_AXIS_ADC_13_tdata <= r_adc(13);
            else
                if M_AXIS_ADC_13_tready = '1' then
                    M_AXIS_ADC_13_tvalid <= '0';
                end if;
            end if;
    
            -- ADC14
            if r_data_valid = '1'then
                M_AXIS_ADC_14_tvalid <= '1';
                M_AXIS_ADC_14_tdata <= r_adc(14);
            else
                if M_AXIS_ADC_14_tready = '1' then
                    M_AXIS_ADC_14_tvalid <= '0';
                end if;
            end if;
    
            -- ADC15
            if r_data_valid = '1'then
                M_AXIS_ADC_15_tvalid <= '1';
                M_AXIS_ADC_15_tdata <= r_adc(15);
            else
                if M_AXIS_ADC_15_tready = '1' then
                    M_AXIS_ADC_15_tvalid <= '0';
                end if;
            end if;
			
			            -- ADC16
            if r_data_valid = '1'then
                M_AXIS_ADC_16_tvalid <= '1';
                M_AXIS_ADC_16_tdata <= r_adc(16);
            else
                if M_AXIS_ADC_16_tready = '1' then
                    M_AXIS_ADC_16_tvalid <= '0';
                end if;
            end if;

            -- ADC17
            if r_data_valid = '1'then
                M_AXIS_ADC_17_tvalid <= '1';
                M_AXIS_ADC_17_tdata <= r_adc(17);
            else
                if M_AXIS_ADC_17_tready = '1' then
                    M_AXIS_ADC_17_tvalid <= '0';
                end if;
            end if;

            -- ADC18
            if r_data_valid = '1'then
                M_AXIS_ADC_18_tvalid <= '1';
                M_AXIS_ADC_18_tdata <= r_adc(18);
            else
                if M_AXIS_ADC_18_tready = '1' then
                    M_AXIS_ADC_18_tvalid <= '0';
                end if;
            end if;

            -- ADC19
            if r_data_valid = '1'then
                M_AXIS_ADC_19_tvalid <= '1';
                M_AXIS_ADC_19_tdata <= r_adc(19);
            else
                if M_AXIS_ADC_19_tready = '1' then
                    M_AXIS_ADC_19_tvalid <= '0';
                end if;
            end if;

            -- ADC20
            if r_data_valid = '1'then
                M_AXIS_ADC_20_tvalid <= '1';
                M_AXIS_ADC_20_tdata <= r_adc(20);
            else
                if M_AXIS_ADC_20_tready = '1' then
                    M_AXIS_ADC_20_tvalid <= '0';
                end if;
            end if;

            -- ADC21
            if r_data_valid = '1'then
                M_AXIS_ADC_21_tvalid <= '1';
                M_AXIS_ADC_21_tdata <= r_adc(21);
            else
                if M_AXIS_ADC_21_tready = '1' then
                    M_AXIS_ADC_21_tvalid <= '0';
                end if;
            end if;

            -- ADC22
            if r_data_valid = '1'then
                M_AXIS_ADC_22_tvalid <= '1';
                M_AXIS_ADC_22_tdata <= r_adc(22);
            else
                if M_AXIS_ADC_22_tready = '1' then
                    M_AXIS_ADC_22_tvalid <= '0';
                end if;
            end if;

            -- ADC23
            if r_data_valid = '1'then
                M_AXIS_ADC_23_tvalid <= '1';
                M_AXIS_ADC_23_tdata <= r_adc(23);
            else
                if M_AXIS_ADC_23_tready = '1' then
                    M_AXIS_ADC_23_tvalid <= '0';
                end if;
            end if;
		end if;

	end process P_ADC_AXIS;

	------------------------------------------------------------------------
	-- CPU2FPGA output streams
	------------------------------------------------------------------------
	P_CPU2FPGA_AXIS : process(clk)
	begin
        if rising_edge(clk) then
            -- CPU2FPGA 00: 32-bit data using SBO_00 and SBO_01
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_00_tvalid <= '1';
                M_AXIS_CPU2FPGA_00_tdata <= r_sbo(1) & r_sbo(0);
            else
                if M_AXIS_CPU2FPGA_00_tready = '1' then
                    M_AXIS_CPU2FPGA_00_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 01: 32-bit data using SBO_02 and SBO_03
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_01_tvalid <= '1';
                M_AXIS_CPU2FPGA_01_tdata <= r_sbo(3) & r_sbo(2);
            else
                if M_AXIS_CPU2FPGA_01_tready = '1' then
                    M_AXIS_CPU2FPGA_01_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 02: 32-bit data using SBO_04 and SBO_05
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_02_tvalid <= '1';
                M_AXIS_CPU2FPGA_02_tdata <= r_sbo(5) & r_sbo(4);
            else
                if M_AXIS_CPU2FPGA_02_tready = '1' then
                    M_AXIS_CPU2FPGA_02_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 03: 32-bit data using SBO_06 and SBO_07
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_03_tvalid <= '1';
                M_AXIS_CPU2FPGA_03_tdata <= r_sbo(7) & r_sbo(6);
            else
                if M_AXIS_CPU2FPGA_03_tready = '1' then
                    M_AXIS_CPU2FPGA_03_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 04: 32-bit data using SBO_08 and SBO_09
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_04_tvalid <= '1';
                M_AXIS_CPU2FPGA_04_tdata <= r_sbo(9) & r_sbo(8);
            else
                if M_AXIS_CPU2FPGA_04_tready = '1' then
                    M_AXIS_CPU2FPGA_04_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 05: 32-bit data using SBO_10 and SBO_11
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_05_tvalid <= '1';
                M_AXIS_CPU2FPGA_05_tdata <= r_sbo(11) & r_sbo(10);
            else
                if M_AXIS_CPU2FPGA_05_tready = '1' then
                    M_AXIS_CPU2FPGA_05_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 06: 32-bit data using SBO_12 and SBO_13
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_06_tvalid <= '1';
                M_AXIS_CPU2FPGA_06_tdata <= r_sbo(13) & r_sbo(12);
            else
                if M_AXIS_CPU2FPGA_06_tready = '1' then
                    M_AXIS_CPU2FPGA_06_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 07: 32-bit data using SBO_14 and SBO_15
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_07_tvalid <= '1';
                M_AXIS_CPU2FPGA_07_tdata <= r_sbo(15) & r_sbo(14);
            else
                if M_AXIS_CPU2FPGA_07_tready = '1' then
                    M_AXIS_CPU2FPGA_07_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 08: 32-bit data using SBO_16 and SBO_17
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_08_tvalid <= '1';
                M_AXIS_CPU2FPGA_08_tdata <= r_sbo(17) & r_sbo(16);
            else
                if M_AXIS_CPU2FPGA_08_tready = '1' then
                    M_AXIS_CPU2FPGA_08_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 09: 32-bit data using SBO_18 and SBO_19
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_09_tvalid <= '1';
                M_AXIS_CPU2FPGA_09_tdata <= r_sbo(19) & r_sbo(18);
            else
                if M_AXIS_CPU2FPGA_09_tready = '1' then
                    M_AXIS_CPU2FPGA_09_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 10: 32-bit data using SBO_20 and SBO_21
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_10_tvalid <= '1';
                M_AXIS_CPU2FPGA_10_tdata <= r_sbo(21) & r_sbo(20);
            else
                if M_AXIS_CPU2FPGA_10_tready = '1' then
                    M_AXIS_CPU2FPGA_10_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 11: 32-bit data using SBO_22 and SBO_23
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_11_tvalid <= '1';
                M_AXIS_CPU2FPGA_11_tdata <= r_sbo(23) & r_sbo(22);
            else
                if M_AXIS_CPU2FPGA_11_tready = '1' then
                    M_AXIS_CPU2FPGA_11_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 12: 32-bit data using SBO_24 and SBO_25
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_12_tvalid <= '1';
                M_AXIS_CPU2FPGA_12_tdata <= r_sbo(25) & r_sbo(24);
            else
                if M_AXIS_CPU2FPGA_12_tready = '1' then
                    M_AXIS_CPU2FPGA_12_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 13: 32-bit data using SBO_26 and SBO_27
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_13_tvalid <= '1';
                M_AXIS_CPU2FPGA_13_tdata <= r_sbo(27) & r_sbo(26);
            else
                if M_AXIS_CPU2FPGA_13_tready = '1' then
                    M_AXIS_CPU2FPGA_13_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 14: 32-bit data using SBO_28 and SBO_09
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_14_tvalid <= '1';
                M_AXIS_CPU2FPGA_14_tdata <= r_sbo(29) & r_sbo(28);
            else
                if M_AXIS_CPU2FPGA_14_tready = '1' then
                    M_AXIS_CPU2FPGA_14_tvalid <= '0';
                end if;
            end if;
    
            -- CPU2FPGA 15: 32-bit data using SBO_30 and SBO_31
            if r_data_valid = '1' then
                M_AXIS_CPU2FPGA_15_tvalid <= '1';
                M_AXIS_CPU2FPGA_15_tdata <= r_sbo(31) & r_sbo(30);
            else
                if M_AXIS_CPU2FPGA_15_tready = '1' then
                    M_AXIS_CPU2FPGA_15_tvalid <= '0';
                end if;
            end if;
		end if;

	end process P_CPU2FPGA_AXIS;

	------------------------------------------------------------------------
	-- FPGA2CPU input streams
	------------------------------------------------------------------------

    S_AXIS_FPGA2CPU_00_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_01_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_02_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_03_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_04_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_05_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_06_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_07_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_08_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_09_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_10_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_11_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_12_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_13_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_14_tready <= r_S_AXIS_FPGA2CPU_tready;
    S_AXIS_FPGA2CPU_15_tready <= r_S_AXIS_FPGA2CPU_tready;

	P_FPGA2CPU_AXIS : process(clk)
	begin
        if rising_edge(clk) then
            -- accept SBI data only when not reading
            -- EXCEPT for one cycle, but OK because
            -- reading with latency of 4
			r_S_AXIS_FPGA2CPU_tready <= not data_reading_in;
    
            -- FPGA2CPU 00: 32-bit data using SBI_00 and SBI_01
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_00_tvalid = '1' then
                r_sbi(0) <= S_AXIS_FPGA2CPU_00_tdata(15 downto 0);
                r_sbi(1) <= S_AXIS_FPGA2CPU_00_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 01: 32-bit data using SBI_02 and SBI_03
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_01_tvalid = '1' then
                r_sbi(2) <= S_AXIS_FPGA2CPU_01_tdata(15 downto 0);
                r_sbi(3) <= S_AXIS_FPGA2CPU_01_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 02: 32-bit data using SBI_04 and SBI_05
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_02_tvalid = '1' then
                r_sbi(4) <= S_AXIS_FPGA2CPU_02_tdata(15 downto 0);
                r_sbi(5) <= S_AXIS_FPGA2CPU_02_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 03: 32-bit data using SBI_06 and SBI_07
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_03_tvalid = '1' then
                r_sbi(6) <= S_AXIS_FPGA2CPU_03_tdata(15 downto 0);
                r_sbi(7) <= S_AXIS_FPGA2CPU_03_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 04: 32-bit data using SBI_08 and SBI_09
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_04_tvalid = '1' then
                r_sbi(8) <= S_AXIS_FPGA2CPU_04_tdata(15 downto 0);
                r_sbi(9) <= S_AXIS_FPGA2CPU_04_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 05: 32-bit data using SBI_10 and SBI_11
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_05_tvalid = '1' then
                r_sbi(10) <= S_AXIS_FPGA2CPU_05_tdata(15 downto 0);
                r_sbi(11) <= S_AXIS_FPGA2CPU_05_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 06: 32-bit data using SBI_12 and SBI_13
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_06_tvalid = '1' then
                r_sbi(12) <= S_AXIS_FPGA2CPU_06_tdata(15 downto 0);
                r_sbi(13) <= S_AXIS_FPGA2CPU_06_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 07: 32-bit data using SBI_14 and SBI_15
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_07_tvalid = '1' then
                r_sbi(14) <= S_AXIS_FPGA2CPU_07_tdata(15 downto 0);
                r_sbi(15) <= S_AXIS_FPGA2CPU_07_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 08: 32-bit data using SBI_16 and SBI_17
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_08_tvalid = '1' then
                r_sbi(16) <= S_AXIS_FPGA2CPU_08_tdata(15 downto 0);
                r_sbi(17) <= S_AXIS_FPGA2CPU_08_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 09: 32-bit data using SBI_18 and SBI_19
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_09_tvalid = '1' then
                r_sbi(18) <= S_AXIS_FPGA2CPU_09_tdata(15 downto 0);
                r_sbi(19) <= S_AXIS_FPGA2CPU_09_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 10: 32-bit data using SBI_20 and SBI_21
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_10_tvalid = '1' then
                r_sbi(20) <= S_AXIS_FPGA2CPU_10_tdata(15 downto 0);
                r_sbi(21) <= S_AXIS_FPGA2CPU_10_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 11: 32-bit data using SBI_22 and SBI_23
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_11_tvalid = '1' then
                r_sbi(22) <= S_AXIS_FPGA2CPU_11_tdata(15 downto 0);
                r_sbi(23) <= S_AXIS_FPGA2CPU_11_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 12: 32-bit data using SBI_24 and SBI_25
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_12_tvalid = '1' then
                r_sbi(24) <= S_AXIS_FPGA2CPU_12_tdata(15 downto 0);
                r_sbi(25) <= S_AXIS_FPGA2CPU_12_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 13: 32-bit data using SBI_26 and SBI_27
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_13_tvalid = '1' then
                r_sbi(26) <= S_AXIS_FPGA2CPU_13_tdata(15 downto 0);
                r_sbi(27) <= S_AXIS_FPGA2CPU_13_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 14: 32-bit data using SBI_28 and SBI_29
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_14_tvalid = '1' then
                r_sbi(28) <= S_AXIS_FPGA2CPU_14_tdata(15 downto 0);
                r_sbi(29) <= S_AXIS_FPGA2CPU_14_tdata(31 downto 16);
            end if;
    
            -- FPGA2CPU 15: 32-bit data using SBI_30 and SBI_31
            if r_S_AXIS_FPGA2CPU_tready = '1' and S_AXIS_FPGA2CPU_15_tvalid = '1' then
                r_sbi(30) <= S_AXIS_FPGA2CPU_15_tdata(15 downto 0);
                r_sbi(31) <= S_AXIS_FPGA2CPU_15_tdata(31 downto 16);
            end if;
		end if;

	end process P_FPGA2CPU_AXIS;

	P_TS_AXIS : process(clk)
	begin
        if rising_edge(clk) then
            -- Ts
            if r_data_valid = '1'then
                M_AXIS_Ts_tvalid <= '1';
                M_AXIS_Ts_tdata  <= r_Ts;
            else
                if M_AXIS_Ts_tready = '1' then
                    M_AXIS_Ts_tvalid <= '0';
                end if;
            end if;
		end if;

	end process P_TS_AXIS;

	P : process(clk)
	begin
		if rising_edge(clk) then
            -- ADC Input
            r_data_valid <= '0'; -- default
			r_adc_done <= adc_done_pulse_in;
            if r_adc_done = '1' then -- sampled values are available in ADC registers
                -- save ADC inputs into registers
                r_adc(0)  <= adc_00_in;
                r_adc(1)  <= adc_01_in;
                r_adc(2)  <= adc_02_in;
                r_adc(3)  <= adc_03_in;
                r_adc(4)  <= adc_04_in;
                r_adc(5)  <= adc_05_in;
                r_adc(6)  <= adc_06_in;
                r_adc(7)  <= adc_07_in;
                r_adc(8)  <= adc_08_in;
                r_adc(9)  <= adc_09_in;
                r_adc(10) <= adc_10_in;
                r_adc(11) <= adc_11_in;
                r_adc(12) <= adc_12_in;
                r_adc(13) <= adc_13_in;
                r_adc(14) <= adc_14_in;
                r_adc(15) <= adc_15_in;
				r_adc(16) <= adc_16_in;
                r_adc(17) <= adc_17_in;
                r_adc(18) <= adc_18_in;
                r_adc(19) <= adc_19_in;
                r_adc(20) <= adc_20_in;
                r_adc(21) <= adc_21_in;
                r_adc(22) <= adc_22_in;
                r_adc(23) <= adc_23_in;
                r_data_valid <= '1';
            end if;
            
            -- controller nReset
            reg_nReset_ctrl <= '1'; -- default value
            if data_valid_pulse_in = '1' then -- Receive controller nReset from SBO_reg_63
                -- detect falling edge on SBO_reg_63
                r_CpuCommand <= r_sbo_cpu_cmd;
                if r_sbo_cpu_cmd = '0' and r_CpuCommand = '1' then
                    reg_nReset_ctrl <= '0';
                end if;
            end if;
            reg_nReset_ctrl_delay1 <= reg_nReset_ctrl;
            reg_nReset_ctrl_delay2 <= reg_nReset_ctrl_delay1;
            reg_nReset_ctrl_delay3 <= reg_nReset_ctrl_delay2;

            -- sync nReset
            reg_nReset_sync <= not sync_pulse_in;
            reg_nReset_sync_delay1 <= reg_nReset_sync;
            reg_nReset_sync_delay2 <= reg_nReset_sync_delay1;
            reg_nReset_sync_delay3 <= reg_nReset_sync_delay2;

            -- Ts counter control
            cnt_Ts <= cnt_Ts + 4; -- clk is running at 250 Mhz, so increment by 4 ns
            if r_adc_done = '1' then
               r_Ts <= std_logic_vector(cnt_Ts);
               cnt_Ts <= to_unsigned(4, cnt_Ts'length);
			end if;
		end if;
	end process P;
	
	-- nReset outputs are asserted for 4 clock cycles
	nReset_ctrl <= reg_nReset_ctrl and reg_nReset_ctrl_delay1 and reg_nReset_ctrl_delay2 and reg_nReset_ctrl_delay3;
	nReset_sync <= reg_nReset_sync and reg_nReset_sync_delay1 and reg_nReset_sync_delay2 and reg_nReset_sync_delay3;

end impl;