Artem Melnykov
Published © MIT

Pulse counter streaming using AXI interface

Interfacing the custom fast pulse counter with the outside world: streaming, writing control registers, dealing with metastability

IntermediateWork in progress2 hours329
Pulse counter streaming using AXI interface

Things used in this project

Hardware components

Z-turn board (Zynq-7010)
×1
Z-turn cape
×1

Software apps and online services

Vivado Design Suite
AMD Vivado Design Suite

Story

Read more

Code

eventSim

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity eventSim is  generic(
    DATA_WIDTH : integer := 16
  );
  port(
    clk         : in std_logic;
    enable      : in std_logic;
    max_value   : in std_logic_vector(DATA_WIDTH-1 downto 0);
    eventOut    : out std_logic
  );
end eventSim;

architecture behavior of eventSim is
    signal count : unsigned(DATA_WIDTH-1 downto 0);
    signal current_max_count : unsigned(DATA_WIDTH-1 downto 0);
    signal ready_flag : std_logic;
begin    

    prCount : process (clk,enable)
    begin
      if rising_edge(clk) then
        if (enable = '1') then
          count <= to_unsigned(0,DATA_WIDTH);
          current_max_count <= to_unsigned(0,DATA_WIDTH);
          eventOut <= '0';
        else
          count <= count + 1;                       -- increment count
          if (count>=current_max_count) then        -- produce output 
            eventOut <= '1';
            count <= to_unsigned(0,DATA_WIDTH);
            if (current_max_count<unsigned(max_value)-1) then  -- increment current_max_count
              current_max_count <= current_max_count + 1;
            else
              current_max_count <= to_unsigned(1,DATA_WIDTH);
            end if;
          else
            eventOut <= '0';
          end if;
        end if;
      end if;
    end process;
    
end behavior;

iatcollector2ch_axis.vhd

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity iatcollector2ch_axis is
	generic (
		C_M_AXIS_TDATA_WIDTH	: integer	:= 16
	);
	port (
        enable_cnt : in std_logic;
        channel1   : in std_logic;
        channel2   : in std_logic;
        max_count  : in std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
        overflow   : out std_logic;

		m_axis_aclk	     : in std_logic;
		m_axis_aresetn   : in std_logic;
		m_axis_tvalid	 : out std_logic;
		m_axis_tdata	 : out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
		m_axis_tready	 : in std_logic
	);
end iatcollector2ch_axis;

architecture behavior of iatcollector2ch_axis is

    -- inter-arrival time collector
    component iatcollector2ch is
    generic(
      DATA_WIDTH : integer
    );
	port (
      clk        : in std_logic;
      enable     : in std_logic;
      channel1   : in std_logic;
      channel2   : in std_logic;
      max_count  : in std_logic_vector(DATA_WIDTH - 1 downto 0);
      ready      : out std_logic;
      data       : out std_logic_vector(DATA_WIDTH - 1 downto 0)
    );
    end component;
    
    -- intermediate signals
    signal data_ready_i : std_logic;
    signal data_i       : std_logic_vector(C_M_AXIS_TDATA_WIDTH - 1 downto 0);
    signal overflow_i   : std_logic;

begin

	overflow_i <= '1' when (data_ready_i='1' and m_axis_tready='0') else
	              '0';
    
    prDelayOverflow : process(m_axis_aclk)
    begin 
      if (rising_edge(m_axis_aclk)) then
        overflow <= overflow_i; -- delay overflow signal to synchronize with m_axis_tvalid
      end if;
    end process;
		
	process( m_axis_aclk ) is
	begin
	  if (rising_edge(m_axis_aclk)) then
	    if (m_axis_aresetn = '0') then
	      m_axis_tvalid <= '0';
	      m_axis_tdata <= (others => '0');
	    else
	      m_axis_tvalid <= data_ready_i;
	      m_axis_tdata <= data_i;
	    end if;
	  end if;
	end process;
		
    -- instantiate the counter
   iatcollector2ch1 : iatcollector2ch
     generic map ( 
      C_M_AXIS_TDATA_WIDTH
     )
     port map (
       clk => m_axis_aclk,
       enable => enable_cnt, 
       channel1 => channel1,
       channel2 => channel2,
       max_count => max_count,
       ready => data_ready_i,
       data => data_i
     ); 
	
end behavior;

tb_iatcollector2ch_axis.vhd

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity tb_iatcollector2ch_axis is
end tb_iatcollector2ch_axis;

architecture behavior of tb_iatcollector2ch_axis is

component iatcollector2ch_axis is
    generic(
      C_M_AXIS_TDATA_WIDTH : integer
    );
	port (
        enable_cnt : in std_logic;
        channel1   : in std_logic;
        channel2   : in std_logic;
        max_count  : in std_logic_vector(C_M_AXIS_TDATA_WIDTH - 1 downto 0);
        overflow   : out std_logic;
		m_axis_aclk	: in std_logic;
		m_axis_aresetn	: in std_logic;
		m_axis_tvalid	: out std_logic;
		m_axis_tdata	: out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
		m_axis_tready	: in std_logic
	);
end component;

constant C_M_AXIS_TDATA_WIDTH_TB : integer := 8;
constant MAX_COUNT_TB  : integer := 5; 
constant CLK_PERIOD : time := 10 ns;
constant SIGNAL_DURATION : time := 3*CLK_PERIOD;
constant ENABLE_DELAY : time := 2 ns;

--declare inputs and initialize
signal m_axis_aclk      : std_logic := '0';
signal enable_cnt       : std_logic := '1';
signal channel1         : std_logic := '0';
signal channel2         : std_logic := '0';
signal max_count        : std_logic_vector(C_M_AXIS_TDATA_WIDTH_TB - 1 downto 0) := std_logic_vector(to_unsigned(MAX_COUNT_TB,C_M_AXIS_TDATA_WIDTH_TB));
signal m_axis_aresetn	: std_logic := '1';
signal m_axis_tready	: std_logic := '1';

--declare outputs
signal overflow         : std_logic;
signal m_axis_tvalid	: std_logic;
signal m_axis_tdata	    : std_logic_vector(C_M_AXIS_TDATA_WIDTH_TB-1 downto 0);

begin

    -- instantiate the unit under test (uut)
   uut : iatcollector2ch_axis generic map (C_M_AXIS_TDATA_WIDTH_TB) port map (
            enable_cnt => enable_cnt,
            channel1 => channel1,
            channel2 => channel2,
            max_count => max_count,
            overflow => overflow,
            m_axis_aclk => m_axis_aclk,
            m_axis_aresetn => m_axis_aresetn,
            m_axis_tvalid => m_axis_tvalid,
            m_axis_tdata => m_axis_tdata,
            m_axis_tready => m_axis_tready
        ); 
        
   -- Clock process definitions
   Clk_process :process
   begin
        m_axis_aclk <= '0';
        wait for CLK_PERIOD/2;
        m_axis_aclk <= '1';
        wait for CLK_PERIOD/2;
   end process;
    
   -- Stimulus process, Apply inputs here.
  stim_proc: process
   begin        
        wait for CLK_PERIOD*5 + ENABLE_DELAY; -- wait for 5 clock cycles
                                              -- +2 ns for starting while clk is low
                                              -- +7 ns for starting while clk is high
        
        enable_cnt <='0';                  --enable the counter

        -- event generation upon reaching max count
        wait for CLK_PERIOD*(MAX_COUNT_TB+1);--ENABLE_DELAY+CLK_PERIOD/2;
        
        
        channel1 <= '1';
        wait for SIGNAL_DURATION;
        channel1 <= '0';
        
        wait for CLK_PERIOD*8;
        channel1 <= '1';
        wait for SIGNAL_DURATION;
        channel1 <= '0';

        wait for CLK_PERIOD*4;
        channel1 <= '1';
        wait for CLK_PERIOD;
        channel2 <= '1';
        wait for 2*CLK_PERIOD;
        channel1 <= '0';
        wait for CLK_PERIOD;
        channel2 <= '0';

        -- simulate overflow
        wait for CLK_PERIOD*4 - ENABLE_DELAY;
        m_axis_tready <= '0';
        
        wait;

  end process;

end;

iatcollector2chSmart_axis.vhd

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity iatcollector2chSmart_axis is
	generic (
		-- Users to add parameters here
		C_M_AXIS_TDATA_WIDTH	: integer	:= 32;
		-- User parameters ends
		-- Do not modify the parameters beyond this line

		-- Width of S_AXI data bus
		C_S_AXI_DATA_WIDTH	: integer	:= 32;
		-- Width of S_AXI address bus
		C_S_AXI_ADDR_WIDTH	: integer	:= 4
	);
	port (
		-- Users to add ports here
        channel1   : in std_logic;
        channel2   : in std_logic;
        fifo_overflow   : out std_logic;
		M_AXIS_ACLK	 : in std_logic;
		M_AXIS_ARESETN : in std_logic;
		M_AXIS_TVALID	 : out std_logic;
		M_AXIS_TDATA	 : out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
		M_AXIS_TREADY	 : in std_logic;
		-- User ports ends
		-- Do not modify the ports beyond this line

		-- Global Clock Signal
		S_AXI_ACLK	: in std_logic;
		-- Global Reset Signal. This Signal is Active LOW
		S_AXI_ARESETN	: in std_logic;
		-- Write address (issued by master, acceped by Slave)
		S_AXI_AWADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		-- Write channel Protection type. This signal indicates the
    		-- privilege and security level of the transaction, and whether
    		-- the transaction is a data access or an instruction access.
		S_AXI_AWPROT	: in std_logic_vector(2 downto 0);
		-- Write address valid. This signal indicates that the master signaling
    		-- valid write address and control information.
		S_AXI_AWVALID	: in std_logic;
		-- Write address ready. This signal indicates that the slave is ready
    		-- to accept an address and associated control signals.
		S_AXI_AWREADY	: out std_logic;
		-- Write data (issued by master, acceped by Slave) 
		S_AXI_WDATA	: in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		-- Write strobes. This signal indicates which byte lanes hold
    		-- valid data. There is one write strobe bit for each eight
    		-- bits of the write data bus.    
		S_AXI_WSTRB	: in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
		-- Write valid. This signal indicates that valid write
    		-- data and strobes are available.
		S_AXI_WVALID	: in std_logic;
		-- Write ready. This signal indicates that the slave
    		-- can accept the write data.
		S_AXI_WREADY	: out std_logic;
		-- Write response. This signal indicates the status
    		-- of the write transaction.
		S_AXI_BRESP	: out std_logic_vector(1 downto 0);
		-- Write response valid. This signal indicates that the channel
    		-- is signaling a valid write response.
		S_AXI_BVALID	: out std_logic;
		-- Response ready. This signal indicates that the master
    		-- can accept a write response.
		S_AXI_BREADY	: in std_logic;
		-- Read address (issued by master, acceped by Slave)
		S_AXI_ARADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		-- Protection type. This signal indicates the privilege
    		-- and security level of the transaction, and whether the
    		-- transaction is a data access or an instruction access.
		S_AXI_ARPROT	: in std_logic_vector(2 downto 0);
		-- Read address valid. This signal indicates that the channel
    		-- is signaling valid read address and control information.
		S_AXI_ARVALID	: in std_logic;
		-- Read address ready. This signal indicates that the slave is
    		-- ready to accept an address and associated control signals.
		S_AXI_ARREADY	: out std_logic;
		-- Read data (issued by slave)
		S_AXI_RDATA	: out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		-- Read response. This signal indicates the status of the
    		-- read transfer.
		S_AXI_RRESP	: out std_logic_vector(1 downto 0);
		-- Read valid. This signal indicates that the channel is
    		-- signaling the required read data.
		S_AXI_RVALID	: out std_logic;
		-- Read ready. This signal indicates that the master can
    		-- accept the read data and response information.
		S_AXI_RREADY	: in std_logic
	);
end iatcollector2chSmart_axis;

architecture behavior of iatcollector2chSmart_axis is

    -- code iatcllrstreamer component
    component iatcollector2ch_axis is
	generic (
		C_M_AXIS_TDATA_WIDTH	: integer	:= 16
	);
	port (
        enable_cnt : in std_logic;
        channel1   : in std_logic;
        channel2   : in std_logic;
        max_count  : in std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
        overflow   : out std_logic;
		M_AXIS_ACLK	 : in std_logic;
		M_AXIS_ARESETN : in std_logic;
		M_AXIS_TVALID	 : out std_logic;
		M_AXIS_TDATA	 : out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
		M_AXIS_TREADY	 : in std_logic
	);
    end component;
    -- iatcllrstreamer signals
    signal enable_i    : std_logic;
    signal max_count_i : std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);

	-- AXI4LITE signals
	signal axi_awaddr	: std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
	signal axi_awready	: std_logic;
	signal axi_wready	: std_logic;
	signal axi_bresp	: std_logic_vector(1 downto 0);
	signal axi_bvalid	: std_logic;
	signal axi_araddr	: std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
	signal axi_arready	: std_logic;
	signal axi_rdata	: std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal axi_rresp	: std_logic_vector(1 downto 0);
	signal axi_rvalid	: std_logic;

	-- Example-specific design signals
	-- local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
	-- ADDR_LSB is used for addressing 32/64 bit registers/memories
	-- ADDR_LSB = 2 for 32 bits (n downto 2)
	-- ADDR_LSB = 3 for 64 bits (n downto 3)
	constant ADDR_LSB  : integer := (C_S_AXI_DATA_WIDTH/32)+ 1;
	constant OPT_MEM_ADDR_BITS : integer := 1;
	------------------------------------------------
	---- Signals for user logic register space example
	--------------------------------------------------
	---- Number of Slave Registers 4
	signal slv_reg0	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg1	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg2	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg3	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg_rden	: std_logic;
	signal slv_reg_wren	: std_logic;
	signal reg_data_out	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal byte_index	: integer;
	signal aw_en	: std_logic;

begin
	-- I/O Connections assignments

	S_AXI_AWREADY	<= axi_awready;
	S_AXI_WREADY	<= axi_wready;
	S_AXI_BRESP	<= axi_bresp;
	S_AXI_BVALID	<= axi_bvalid;
	S_AXI_ARREADY	<= axi_arready;
	S_AXI_RDATA	<= axi_rdata;
	S_AXI_RRESP	<= axi_rresp;
	S_AXI_RVALID	<= axi_rvalid;
	-- Implement axi_awready generation
	-- axi_awready is asserted for one S_AXI_ACLK clock cycle when both
	-- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
	-- de-asserted when reset is low.

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_awready <= '0';
	      aw_en <= '1';
	    else
	      if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
	        -- slave is ready to accept write address when
	        -- there is a valid write address and write data
	        -- on the write address and data bus. This design 
	        -- expects no outstanding transactions. 
	           axi_awready <= '1';
	           aw_en <= '0';
	        elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then
	           aw_en <= '1';
	           axi_awready <= '0';
	      else
	        axi_awready <= '0';
	      end if;
	    end if;
	  end if;
	end process;

	-- Implement axi_awaddr latching
	-- This process is used to latch the address when both 
	-- S_AXI_AWVALID and S_AXI_WVALID are valid. 

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_awaddr <= (others => '0');
	    else
	      if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
	        -- Write Address latching
	        axi_awaddr <= S_AXI_AWADDR;
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement axi_wready generation
	-- axi_wready is asserted for one S_AXI_ACLK clock cycle when both
	-- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 
	-- de-asserted when reset is low. 

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_wready <= '0';
	    else
	      if (axi_wready = '0' and S_AXI_WVALID = '1' and S_AXI_AWVALID = '1' and aw_en = '1') then
	          -- slave is ready to accept write data when 
	          -- there is a valid write address and write data
	          -- on the write address and data bus. This design 
	          -- expects no outstanding transactions.           
	          axi_wready <= '1';
	      else
	        axi_wready <= '0';
	      end if;
	    end if;
	  end if;
	end process; 

	-- Implement memory mapped register select and write logic generation
	-- The write data is accepted and written to memory mapped registers when
	-- axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
	-- select byte enables of slave registers while writing.
	-- These registers are cleared when reset (active low) is applied.
	-- Slave register write enable is asserted when valid address and data are available
	-- and the slave is ready to accept the write address and write data.
	slv_reg_wren <= axi_wready and S_AXI_WVALID and axi_awready and S_AXI_AWVALID ;

	process (S_AXI_ACLK)
	variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0); 
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      slv_reg0 <= (others => '0');
	      slv_reg1 <= (others => '0');
	      slv_reg2 <= (others => '0');
	      slv_reg3 <= (others => '0');
	    else
	      loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
	      if (slv_reg_wren = '1') then
	        case loc_addr is
	          when b"00" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 0
	                slv_reg0(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when b"01" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 1
	                slv_reg1(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when b"10" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 2
	                slv_reg2(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when b"11" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 3
	                slv_reg3(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when others =>
	            slv_reg0 <= slv_reg0;
	            slv_reg1 <= slv_reg1;
	            slv_reg2 <= slv_reg2;
	            slv_reg3 <= slv_reg3;
	        end case;
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement write response logic generation
	-- The write response and response valid signals are asserted by the slave 
	-- when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
	-- This marks the acceptance of address and indicates the status of 
	-- write transaction.

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_bvalid  <= '0';
	      axi_bresp   <= "00"; --need to work more on the responses
	    else
	      if (axi_awready = '1' and S_AXI_AWVALID = '1' and axi_wready = '1' and S_AXI_WVALID = '1' and axi_bvalid = '0'  ) then
	        axi_bvalid <= '1';
	        axi_bresp  <= "00"; 
	      elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then   --check if bready is asserted while bvalid is high)
	        axi_bvalid <= '0';                                 -- (there is a possibility that bready is always asserted high)
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement axi_arready generation
	-- axi_arready is asserted for one S_AXI_ACLK clock cycle when
	-- S_AXI_ARVALID is asserted. axi_awready is 
	-- de-asserted when reset (active low) is asserted. 
	-- The read address is also latched when S_AXI_ARVALID is 
	-- asserted. axi_araddr is reset to zero on reset assertion.

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_arready <= '0';
	      axi_araddr  <= (others => '1');
	    else
	      if (axi_arready = '0' and S_AXI_ARVALID = '1') then
	        -- indicates that the slave has acceped the valid read address
	        axi_arready <= '1';
	        -- Read Address latching 
	        axi_araddr  <= S_AXI_ARADDR;           
	      else
	        axi_arready <= '0';
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement axi_arvalid generation
	-- axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
	-- S_AXI_ARVALID and axi_arready are asserted. The slave registers 
	-- data are available on the axi_rdata bus at this instance. The 
	-- assertion of axi_rvalid marks the validity of read data on the 
	-- bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	-- is deasserted on reset (active low). axi_rresp and axi_rdata are 
	-- cleared to zero on reset (active low).  
	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then
	    if S_AXI_ARESETN = '0' then
	      axi_rvalid <= '0';
	      axi_rresp  <= "00";
	    else
	      if (axi_arready = '1' and S_AXI_ARVALID = '1' and axi_rvalid = '0') then
	        -- Valid read data is available at the read data bus
	        axi_rvalid <= '1';
	        axi_rresp  <= "00"; -- 'OKAY' response
	      elsif (axi_rvalid = '1' and S_AXI_RREADY = '1') then
	        -- Read data is accepted by the master
	        axi_rvalid <= '0';
	      end if;            
	    end if;
	  end if;
	end process;

	-- Implement memory mapped register select and read logic generation
	-- Slave register read enable is asserted when valid address is available
	-- and the slave is ready to accept the read address.
	slv_reg_rden <= axi_arready and S_AXI_ARVALID and (not axi_rvalid) ;

	process (slv_reg0, slv_reg1, slv_reg2, slv_reg3, axi_araddr, S_AXI_ARESETN, slv_reg_rden)
	variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
	begin
	    -- Address decoding for reading registers
	    loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
	    case loc_addr is
	      when b"00" =>
	        reg_data_out <= slv_reg0;
	      when b"01" =>
	        reg_data_out <= slv_reg1;
	      when b"10" =>
	        reg_data_out <= slv_reg2;
	      when b"11" =>
	        reg_data_out <= slv_reg3;
	      when others =>
	        reg_data_out  <= (others => '0');
	    end case;
	end process; 

	-- Output register or memory read data
	process( S_AXI_ACLK ) is
	begin
	  if (rising_edge (S_AXI_ACLK)) then
	    if ( S_AXI_ARESETN = '0' ) then
	      axi_rdata  <= (others => '0');
	    else
	      if (slv_reg_rden = '1') then
	        -- When there is a valid read address (S_AXI_ARVALID) with 
	        -- acceptance of read address by the slave (axi_arready), 
	        -- output the read dada 
	        -- Read address mux
	          axi_rdata <= reg_data_out;     -- register read data
	      end if;   
	    end if;
	  end if;
	end process;


	-- Add user logic here
    iatcollector2ch_axis1 : iatcollector2ch_axis
	  generic map (
	    C_M_AXIS_TDATA_WIDTH
	  )
	  port map (
        enable_cnt => enable_i,
        channel1 => channel1,
        channel2 => channel2,
        max_count => max_count_i,
        overflow => fifo_overflow,
        M_AXIS_ACLK => M_AXIS_ACLK,
		M_AXIS_ARESETN => M_AXIS_ARESETN,
		M_AXIS_TVALID => M_AXIS_TVALID,
		M_AXIS_TDATA => M_AXIS_TDATA,
		M_AXIS_TREADY => M_AXIS_TREADY
	);
	
	enable_i <= not slv_reg0(0);
	max_count_i <= slv_reg1(C_M_AXIS_TDATA_WIDTH-1 downto 0);

	-- User logic ends

end behavior;

tb_iatcollector2chSmart_axis.vhd

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- entity declaration for your testbench. 
entity tb_iatcollector2chSmart_axis is
end tb_iatcollector2chSmart_axis;

architecture behavior of tb_iatcollector2chSmart_axis is

-- component declaration for the unit under test (uut)
component iatcollector2chSmart_axis is
    generic(
		C_M_AXIS_TDATA_WIDTH	: integer;
		C_S_AXI_DATA_WIDTH	    : integer;
		C_S_AXI_ADDR_WIDTH	    : integer
	);
	port (
        channel1   : in std_logic;
        channel2   : in std_logic;
        fifo_overflow   : out std_logic;
		M_AXIS_ACLK	: in std_logic;
		M_AXIS_ARESETN	: in std_logic;
		M_AXIS_TVALID	: out std_logic;
		M_AXIS_TDATA	: out std_logic_vector(C_M_AXIS_TDATA_WIDTH-1 downto 0);
		M_AXIS_TREADY	: in std_logic;
		S_AXI_ACLK	: in std_logic;
		S_AXI_ARESETN	: in std_logic;
		S_AXI_AWADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		S_AXI_AWPROT	: in std_logic_vector(2 downto 0);
		S_AXI_AWVALID	: in std_logic;
		S_AXI_AWREADY	: out std_logic;
		S_AXI_WDATA	: in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		S_AXI_WSTRB	: in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
		S_AXI_WVALID	: in std_logic;
		S_AXI_WREADY	: out std_logic;
		S_AXI_BRESP	: out std_logic_vector(1 downto 0);
		S_AXI_BVALID	: out std_logic;
		S_AXI_BREADY	: in std_logic;
		S_AXI_ARADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		S_AXI_ARPROT	: in std_logic_vector(2 downto 0);
		S_AXI_ARVALID	: in std_logic;
		S_AXI_ARREADY	: out std_logic;
		S_AXI_RDATA	: out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		S_AXI_RRESP	: out std_logic_vector(1 downto 0);
		S_AXI_RVALID	: out std_logic;
		S_AXI_RREADY	: in std_logic
	);
end component;

constant C_M_AXIS_TDATA_WIDTH_TB : integer := 16;
constant C_S_AXI_DATA_WIDTH_TB : integer := 32;
constant C_S_AXI_ADDR_WIDTH_TB : integer := 4;
constant MAX_COUNT_TB  : integer := 6; 
constant CLK_PERIOD : time := 10 ns;
constant SIGNAL_DURATION : time := 3*CLK_PERIOD;
constant ENABLE_DELAY : time := 2 ns;

--declare inputs and initialize
signal channel1         : std_logic := '0';
signal channel2         : std_logic := '0';
signal M_AXIS_ACLK      : std_logic := '0';
signal M_AXIS_ARESETN	: std_logic := '0';
signal M_AXIS_TREADY	: std_logic := '1';
signal S_AXI_ACLK       : std_logic := '0';
signal S_AXI_ARESETN    : std_logic := '0';
signal S_AXI_AWADDR     : std_logic_vector(C_S_AXI_ADDR_WIDTH_TB-1 downto 0) := (others => '0');
signal S_AXI_AWPROT     : std_logic_vector(2 downto 0) := "000"; -- not used in this component
signal S_AXI_AWVALID	: std_logic := '0';
signal S_AXI_WDATA      : std_logic_vector(C_S_AXI_DATA_WIDTH_TB-1 downto 0) := (others => '0');
signal S_AXI_WSTRB      : std_logic_vector((C_S_AXI_DATA_WIDTH_TB/8)-1 downto 0) := (others => '1'); -- keep all bytes
signal S_AXI_WVALID     : std_logic := '0';
signal S_AXI_BREADY     : std_logic := '1';
signal S_AXI_ARADDR     : std_logic_vector(C_S_AXI_ADDR_WIDTH_TB-1 downto 0) := (others => '1');
signal S_AXI_ARPROT     : std_logic_vector(2 downto 0) := "000"; -- not used in this component
signal S_AXI_ARVALID	: std_logic := '0';
signal S_AXI_RREADY     : std_logic := '0';

--declare outputs
signal fifo_overflow    : std_logic;
signal M_AXIS_TVALID	: std_logic;
signal M_AXIS_TDATA	    : std_logic_vector(C_M_AXIS_TDATA_WIDTH_TB-1 downto 0);
signal S_AXI_AWREADY	: std_logic;
signal S_AXI_WREADY	    : std_logic;
signal S_AXI_BRESP      : std_logic_vector(1 downto 0);
signal S_AXI_BVALID     : std_logic;
signal S_AXI_ARREADY	: std_logic;
signal S_AXI_RDATA      : std_logic_vector(C_S_AXI_DATA_WIDTH_TB-1 downto 0);
signal S_AXI_RRESP      : std_logic_vector(1 downto 0);
signal S_AXI_RVALID     : std_logic;

begin

    -- instantiate the unit under test (uut)
   uut : iatcollector2chSmart_axis 
     generic map (
        C_M_AXIS_TDATA_WIDTH_TB,
        C_S_AXI_DATA_WIDTH_TB,
		C_S_AXI_ADDR_WIDTH_TB
     ) port map (
        channel1 => channel1,
        channel2 => channel2,
        fifo_overflow => fifo_overflow,
		M_AXIS_ACLK => M_AXIS_ACLK,
		M_AXIS_ARESETN => M_AXIS_ARESETN,
		M_AXIS_TVALID => M_AXIS_TVALID,
		M_AXIS_TDATA => M_AXIS_TDATA,
		M_AXIS_TREADY => M_AXIS_TREADY,
		S_AXI_ACLK => S_AXI_ACLK,
		S_AXI_ARESETN => S_AXI_ARESETN,
		S_AXI_AWADDR => S_AXI_AWADDR,
		S_AXI_AWPROT => S_AXI_AWPROT,
		S_AXI_AWVALID => S_AXI_AWVALID,
		S_AXI_AWREADY => S_AXI_AWREADY,
		S_AXI_WDATA => S_AXI_WDATA,
		S_AXI_WSTRB => S_AXI_WSTRB,
		S_AXI_WVALID => S_AXI_WVALID,
		S_AXI_WREADY => S_AXI_WREADY,
		S_AXI_BRESP => S_AXI_BRESP,
		S_AXI_BVALID => S_AXI_BVALID,
		S_AXI_BREADY => S_AXI_BREADY,
		S_AXI_ARADDR => S_AXI_ARADDR,
		S_AXI_ARPROT => S_AXI_ARPROT,
		S_AXI_ARVALID => S_AXI_ARVALID,
		S_AXI_ARREADY => S_AXI_ARREADY,
		S_AXI_RDATA => S_AXI_RDATA,
		S_AXI_RRESP => S_AXI_RRESP,
		S_AXI_RVALID => S_AXI_RVALID,
		S_AXI_RREADY => S_AXI_RREADY
      ); 
        
   -- Clock process definitions
   Clk_process_M :process
   begin
        M_AXIS_ACLK <= '0';
        wait for CLK_PERIOD/2;
        M_AXIS_ACLK <= '1';
        wait for CLK_PERIOD/2;
   end process;
    
   Clk_process_S :process
   begin
        S_AXI_ACLK <= '0';
        wait for CLK_PERIOD/2;
        S_AXI_ACLK <= '1';
        wait for CLK_PERIOD/2;
   end process;

   -- Stimulus process
  stim_proc: process
   begin        
        wait for CLK_PERIOD*5 + ENABLE_DELAY; -- wait for 5 clock cycles
                                              -- +2 ns for starting while clk is low
                                              -- +7 ns for starting while clk is high
        
        M_AXIS_ARESETN <= '1';
        S_AXI_ARESETN <= '1';
        
        -- set enable register to disable the counter
        S_AXI_AWVALID <= '1';
        S_AXI_AWADDR <= "0000";
        S_AXI_WVALID <= '1';
        S_AXI_WDATA <= std_logic_vector(to_unsigned(0,C_S_AXI_DATA_WIDTH_TB));        
        wait for CLK_PERIOD*6;
        S_AXI_AWVALID <= '0';
        S_AXI_WVALID <= '0';        
        wait for CLK_PERIOD*4;

        -- set max_count register to MAX_COUNT_TB
        S_AXI_AWVALID <= '1';
        S_AXI_AWADDR <= "0100";
        S_AXI_WVALID <= '1';
        S_AXI_WDATA <= std_logic_vector(to_unsigned(MAX_COUNT_TB,C_S_AXI_DATA_WIDTH_TB));        
        wait for CLK_PERIOD*6;
        S_AXI_AWVALID <= '0';
        S_AXI_WVALID <= '0';        
        wait for CLK_PERIOD*4;

        -- set enable register to enable the counter
        S_AXI_AWVALID <= '1';
        S_AXI_AWADDR <= "0000";
        S_AXI_WVALID <= '1';
        S_AXI_WDATA <= std_logic_vector(to_unsigned(1,C_S_AXI_DATA_WIDTH_TB));        
        wait for CLK_PERIOD*6;
        S_AXI_AWVALID <= '0';
        S_AXI_WVALID <= '0';        
        wait for CLK_PERIOD*4;

        -- read register 1
        S_AXI_ARVALID <= '1';
        S_AXI_ARADDR <= "0100";
        S_AXI_RREADY <= '1';
        wait for CLK_PERIOD*6;
        S_AXI_ARVALID <= '0';
        S_AXI_RREADY <= '0';        
        wait for CLK_PERIOD*4;

        -- event generation upon reaching max count
        wait for CLK_PERIOD*(MAX_COUNT_TB+1);--ENABLE_DELAY+CLK_PERIOD/2;
                
        channel1 <= '1';
        wait for SIGNAL_DURATION;
        channel1 <= '0';
        
        wait for CLK_PERIOD*8;
        channel1 <= '1';
        wait for SIGNAL_DURATION;
        channel1 <= '0';

        wait for CLK_PERIOD*4;
        channel1 <= '1';
        wait for CLK_PERIOD;
        channel2 <= '1';
        wait for 2*CLK_PERIOD;
        channel1 <= '0';
        wait for CLK_PERIOD;
        channel2 <= '0';

        -- simulate ocerflow of FIFO
        wait for CLK_PERIOD*4;
        M_AXIS_TREADY <= '0';
        
        wait;

  end process;

end;

cascade3

VHDL
library ieee;
use ieee.std_logic_1164.all;
 
entity cascade3 is
  port(
    clk             : in std_logic;
    input_casc      : in std_logic;
    output_casc     : out std_logic
  );
end cascade3;

architecture behavior of cascade3 is
    signal output_csc1 : std_logic;
    signal output_csc2 : std_logic;
    signal output_csc3 : std_logic;
    
begin    

    prCascade1 : process(clk)
    begin 
      if (rising_edge(clk)) then
        output_csc1 <= input_casc;
      end if;
    end process;

    prCascade2 : process(clk)
    begin 
      if (rising_edge(clk)) then
        output_csc2 <= output_csc1;
      end if;
    end process;

    prCascade3 : process(clk)
    begin 
      if (rising_edge(clk)) then
        output_csc3 <= output_csc2;
      end if;
    end process;

    output_casc <= output_csc3;
        
end behavior;

tb_eventSim

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity tb_eventSim is
end tb_eventSim;

architecture behavior of tb_eventSim is

-- component declaration for the unit under test (uut)
component eventSim is
  generic(
    DATA_WIDTH : integer
  );
  port(
    clk         : in std_logic;
    enable      : in std_logic;
    max_value   : in std_logic_vector(DATA_WIDTH-1 downto 0);
    eventOut    : out std_logic
  );
end component;

-- define the period of clock here.
-- It's recommended to use CAPITAL letters to define constants.
constant DATA_WIDTH_TB : integer := 8;
constant MAX_VALUE_TB  : integer := 6; 
constant CLK_PERIOD_TB : time := 10 ns;

--declare inputs and initialize them to zero.
signal clk              : std_logic := '0';
signal enable           : std_logic := '1';
signal max_value        : std_logic_vector(DATA_WIDTH_TB - 1 downto 0) := std_logic_vector(to_unsigned(MAX_VALUE_TB,DATA_WIDTH_TB));

--declare outputs
signal eventOut         : std_logic;

begin

    -- instantiate the unit under test (uut)
   uut : eventSim generic map (DATA_WIDTH_TB) port map (
            clk => clk,
            enable => enable,
            max_value => max_value,
            eventOut => eventOut
        ); 
        
   -- Clock process definitions
   Clk_process :process
   begin
        clk <= '0';
        wait for CLK_PERIOD_TB/2;
        clk <= '1';
        wait for CLK_PERIOD_TB/2;
   end process;
    
   -- Stimulus process, Apply inputs here.
  stim_proc: process
   begin        
        wait for CLK_PERIOD_TB*5;
        
        enable <='0';                  --enable the simulator

        -- event generation upon reaching max count
        wait for CLK_PERIOD_TB * MAX_VALUE_TB * 3;
                
        wait;

  end process;

end;

eventSimSmart

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity eventSimSmart is
	generic (
		-- Users to add parameters here
		-- User parameters ends
		-- Do not modify the parameters beyond this line

		-- Width of S_AXI data bus
		C_S_AXI_DATA_WIDTH	: integer	:= 32;
		-- Width of S_AXI address bus
		C_S_AXI_ADDR_WIDTH	: integer	:= 4
	);
	port (
		-- Users to add ports here
        eventOut   : out std_logic;
		-- User ports ends
		-- Do not modify the ports beyond this line

		-- Global Clock Signal
		S_AXI_ACLK	: in std_logic;
		-- Global Reset Signal. This Signal is Active LOW
		S_AXI_ARESETN	: in std_logic;
		-- Write address (issued by master, acceped by Slave)
		S_AXI_AWADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		-- Write channel Protection type. This signal indicates the
    		-- privilege and security level of the transaction, and whether
    		-- the transaction is a data access or an instruction access.
		S_AXI_AWPROT	: in std_logic_vector(2 downto 0);
		-- Write address valid. This signal indicates that the master signaling
    		-- valid write address and control information.
		S_AXI_AWVALID	: in std_logic;
		-- Write address ready. This signal indicates that the slave is ready
    		-- to accept an address and associated control signals.
		S_AXI_AWREADY	: out std_logic;
		-- Write data (issued by master, acceped by Slave) 
		S_AXI_WDATA	: in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		-- Write strobes. This signal indicates which byte lanes hold
    		-- valid data. There is one write strobe bit for each eight
    		-- bits of the write data bus.    
		S_AXI_WSTRB	: in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
		-- Write valid. This signal indicates that valid write
    		-- data and strobes are available.
		S_AXI_WVALID	: in std_logic;
		-- Write ready. This signal indicates that the slave
    		-- can accept the write data.
		S_AXI_WREADY	: out std_logic;
		-- Write response. This signal indicates the status
    		-- of the write transaction.
		S_AXI_BRESP	: out std_logic_vector(1 downto 0);
		-- Write response valid. This signal indicates that the channel
    		-- is signaling a valid write response.
		S_AXI_BVALID	: out std_logic;
		-- Response ready. This signal indicates that the master
    		-- can accept a write response.
		S_AXI_BREADY	: in std_logic;
		-- Read address (issued by master, acceped by Slave)
		S_AXI_ARADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		-- Protection type. This signal indicates the privilege
    		-- and security level of the transaction, and whether the
    		-- transaction is a data access or an instruction access.
		S_AXI_ARPROT	: in std_logic_vector(2 downto 0);
		-- Read address valid. This signal indicates that the channel
    		-- is signaling valid read address and control information.
		S_AXI_ARVALID	: in std_logic;
		-- Read address ready. This signal indicates that the slave is
    		-- ready to accept an address and associated control signals.
		S_AXI_ARREADY	: out std_logic;
		-- Read data (issued by slave)
		S_AXI_RDATA	: out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		-- Read response. This signal indicates the status of the
    		-- read transfer.
		S_AXI_RRESP	: out std_logic_vector(1 downto 0);
		-- Read valid. This signal indicates that the channel is
    		-- signaling the required read data.
		S_AXI_RVALID	: out std_logic;
		-- Read ready. This signal indicates that the master can
    		-- accept the read data and response information.
		S_AXI_RREADY	: in std_logic
	);
end eventSimSmart;

architecture behavior of eventSimSmart is

    -- code eventSimSmart component
    component eventSim is
	generic (
      DATA_WIDTH : integer := 16
    );
    port(
      clk         : in std_logic;
      enable      : in std_logic;
      max_value   : in std_logic_vector(DATA_WIDTH-1 downto 0);
      eventOut    : out std_logic
    );
    end component;
    
    -- iatcllrstreamer signals
    signal enable_i    : std_logic;
    signal max_value_i : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);

	-- AXI4LITE signals
	signal axi_awaddr	: std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
	signal axi_awready	: std_logic;
	signal axi_wready	: std_logic;
	signal axi_bresp	: std_logic_vector(1 downto 0);
	signal axi_bvalid	: std_logic;
	signal axi_araddr	: std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
	signal axi_arready	: std_logic;
	signal axi_rdata	: std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal axi_rresp	: std_logic_vector(1 downto 0);
	signal axi_rvalid	: std_logic;

	-- Example-specific design signals
	-- local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
	-- ADDR_LSB is used for addressing 32/64 bit registers/memories
	-- ADDR_LSB = 2 for 32 bits (n downto 2)
	-- ADDR_LSB = 3 for 64 bits (n downto 3)
	constant ADDR_LSB  : integer := (C_S_AXI_DATA_WIDTH/32)+ 1;
	constant OPT_MEM_ADDR_BITS : integer := 1;
	------------------------------------------------
	---- Signals for user logic register space example
	--------------------------------------------------
	---- Number of Slave Registers 4
	signal slv_reg0	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg1	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg2	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg3	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal slv_reg_rden	: std_logic;
	signal slv_reg_wren	: std_logic;
	signal reg_data_out	:std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
	signal byte_index	: integer;
	signal aw_en	: std_logic;

begin
	-- I/O Connections assignments

	S_AXI_AWREADY	<= axi_awready;
	S_AXI_WREADY	<= axi_wready;
	S_AXI_BRESP	<= axi_bresp;
	S_AXI_BVALID	<= axi_bvalid;
	S_AXI_ARREADY	<= axi_arready;
	S_AXI_RDATA	<= axi_rdata;
	S_AXI_RRESP	<= axi_rresp;
	S_AXI_RVALID	<= axi_rvalid;
	-- Implement axi_awready generation
	-- axi_awready is asserted for one S_AXI_ACLK clock cycle when both
	-- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
	-- de-asserted when reset is low.

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_awready <= '0';
	      aw_en <= '1';
	    else
	      if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
	        -- slave is ready to accept write address when
	        -- there is a valid write address and write data
	        -- on the write address and data bus. This design 
	        -- expects no outstanding transactions. 
	           axi_awready <= '1';
	           aw_en <= '0';
	        elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then
	           aw_en <= '1';
	           axi_awready <= '0';
	      else
	        axi_awready <= '0';
	      end if;
	    end if;
	  end if;
	end process;

	-- Implement axi_awaddr latching
	-- This process is used to latch the address when both 
	-- S_AXI_AWVALID and S_AXI_WVALID are valid. 

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_awaddr <= (others => '0');
	    else
	      if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
	        -- Write Address latching
	        axi_awaddr <= S_AXI_AWADDR;
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement axi_wready generation
	-- axi_wready is asserted for one S_AXI_ACLK clock cycle when both
	-- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 
	-- de-asserted when reset is low. 

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_wready <= '0';
	    else
	      if (axi_wready = '0' and S_AXI_WVALID = '1' and S_AXI_AWVALID = '1' and aw_en = '1') then
	          -- slave is ready to accept write data when 
	          -- there is a valid write address and write data
	          -- on the write address and data bus. This design 
	          -- expects no outstanding transactions.           
	          axi_wready <= '1';
	      else
	        axi_wready <= '0';
	      end if;
	    end if;
	  end if;
	end process; 

	-- Implement memory mapped register select and write logic generation
	-- The write data is accepted and written to memory mapped registers when
	-- axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
	-- select byte enables of slave registers while writing.
	-- These registers are cleared when reset (active low) is applied.
	-- Slave register write enable is asserted when valid address and data are available
	-- and the slave is ready to accept the write address and write data.
	slv_reg_wren <= axi_wready and S_AXI_WVALID and axi_awready and S_AXI_AWVALID ;

	process (S_AXI_ACLK)
	variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0); 
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      slv_reg0 <= (others => '0');
	      slv_reg1 <= (others => '0');
	      slv_reg2 <= (others => '0');
	      slv_reg3 <= (others => '0');
	    else
	      loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
	      if (slv_reg_wren = '1') then
	        case loc_addr is
	          when b"00" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 0
	                slv_reg0(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when b"01" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 1
	                slv_reg1(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when b"10" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 2
	                slv_reg2(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when b"11" =>
	            for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
	              if ( S_AXI_WSTRB(byte_index) = '1' ) then
	                -- Respective byte enables are asserted as per write strobes                   
	                -- slave registor 3
	                slv_reg3(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
	              end if;
	            end loop;
	          when others =>
	            slv_reg0 <= slv_reg0;
	            slv_reg1 <= slv_reg1;
	            slv_reg2 <= slv_reg2;
	            slv_reg3 <= slv_reg3;
	        end case;
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement write response logic generation
	-- The write response and response valid signals are asserted by the slave 
	-- when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
	-- This marks the acceptance of address and indicates the status of 
	-- write transaction.

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_bvalid  <= '0';
	      axi_bresp   <= "00"; --need to work more on the responses
	    else
	      if (axi_awready = '1' and S_AXI_AWVALID = '1' and axi_wready = '1' and S_AXI_WVALID = '1' and axi_bvalid = '0'  ) then
	        axi_bvalid <= '1';
	        axi_bresp  <= "00"; 
	      elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then   --check if bready is asserted while bvalid is high)
	        axi_bvalid <= '0';                                 -- (there is a possibility that bready is always asserted high)
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement axi_arready generation
	-- axi_arready is asserted for one S_AXI_ACLK clock cycle when
	-- S_AXI_ARVALID is asserted. axi_awready is 
	-- de-asserted when reset (active low) is asserted. 
	-- The read address is also latched when S_AXI_ARVALID is 
	-- asserted. axi_araddr is reset to zero on reset assertion.

	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then 
	    if S_AXI_ARESETN = '0' then
	      axi_arready <= '0';
	      axi_araddr  <= (others => '1');
	    else
	      if (axi_arready = '0' and S_AXI_ARVALID = '1') then
	        -- indicates that the slave has acceped the valid read address
	        axi_arready <= '1';
	        -- Read Address latching 
	        axi_araddr  <= S_AXI_ARADDR;           
	      else
	        axi_arready <= '0';
	      end if;
	    end if;
	  end if;                   
	end process; 

	-- Implement axi_arvalid generation
	-- axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
	-- S_AXI_ARVALID and axi_arready are asserted. The slave registers 
	-- data are available on the axi_rdata bus at this instance. The 
	-- assertion of axi_rvalid marks the validity of read data on the 
	-- bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	-- is deasserted on reset (active low). axi_rresp and axi_rdata are 
	-- cleared to zero on reset (active low).  
	process (S_AXI_ACLK)
	begin
	  if rising_edge(S_AXI_ACLK) then
	    if S_AXI_ARESETN = '0' then
	      axi_rvalid <= '0';
	      axi_rresp  <= "00";
	    else
	      if (axi_arready = '1' and S_AXI_ARVALID = '1' and axi_rvalid = '0') then
	        -- Valid read data is available at the read data bus
	        axi_rvalid <= '1';
	        axi_rresp  <= "00"; -- 'OKAY' response
	      elsif (axi_rvalid = '1' and S_AXI_RREADY = '1') then
	        -- Read data is accepted by the master
	        axi_rvalid <= '0';
	      end if;            
	    end if;
	  end if;
	end process;

	-- Implement memory mapped register select and read logic generation
	-- Slave register read enable is asserted when valid address is available
	-- and the slave is ready to accept the read address.
	slv_reg_rden <= axi_arready and S_AXI_ARVALID and (not axi_rvalid) ;

	process (slv_reg0, slv_reg1, slv_reg2, slv_reg3, axi_araddr, S_AXI_ARESETN, slv_reg_rden)
	variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
	begin
	    -- Address decoding for reading registers
	    loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
	    case loc_addr is
	      when b"00" =>
	        reg_data_out <= slv_reg0;
	      when b"01" =>
	        reg_data_out <= slv_reg1;
	      when b"10" =>
	        reg_data_out <= slv_reg2;
	      when b"11" =>
	        reg_data_out <= slv_reg3;
	      when others =>
	        reg_data_out  <= (others => '0');
	    end case;
	end process; 

	-- Output register or memory read data
	process( S_AXI_ACLK ) is
	begin
	  if (rising_edge (S_AXI_ACLK)) then
	    if ( S_AXI_ARESETN = '0' ) then
	      axi_rdata  <= (others => '0');
	    else
	      if (slv_reg_rden = '1') then
	        -- When there is a valid read address (S_AXI_ARVALID) with 
	        -- acceptance of read address by the slave (axi_arready), 
	        -- output the read dada 
	        -- Read address mux
	          axi_rdata <= reg_data_out;     -- register read data
	      end if;   
	    end if;
	  end if;
	end process;


	-- Add user logic here
    eventSim1 : eventSim
	  generic map (
	    C_S_AXI_DATA_WIDTH
	  )
	  port map (
	    clk => S_AXI_ACLK,
        enable => enable_i,
        max_value => max_value_i,
        eventOut => eventOut
	);
	
	enable_i <= not slv_reg0(0);
	max_value_i <= slv_reg1(C_S_AXI_DATA_WIDTH-1 downto 0);

	-- User logic ends

end behavior;

Credits

Artem Melnykov
4 projects • 2 followers
Contact

Comments

Please log in or sign up to comment.