library ieee;
use ieee.std_logic_1164.all;
--use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity qsfp_playback_intfc_128 is
  port (
    rx_device_clk_in                      : in  std_logic;
    rx_device_clk_aresetn_in              : in  std_logic;
    rx_tdata_128b_in                      : in  std_logic_vector(127 downto 0);
    rx_tvalid_128b_in                     : in  std_logic;
    rx_tready_128b_out                    : out std_logic;
    rx_tvalid_128b_cnt_out                : out std_logic_vector( 31 downto 0);
    rx_tvalid_128b_en_cnt_out             : out std_logic_vector( 31 downto 0);
    rx_overflow_128b_cnt_out              : out std_logic_vector( 31 downto 0);
    playback_data_path_enable_n_in        : in  std_logic;

    qsfp_playback_aclk_in                 : in  std_logic;
    qsfp_playback_aresetn_in              : in  std_logic;
    qsfp_playback_tdata_240b_out          : out std_logic_vector(239 downto 0);
    qsfp_playback_tvalid_240b_out         : out std_logic;
    qsfp_playback_tready_240b_in          : in  std_logic;
    qsfp_playback_tvalid_240b_cnt_out     : out std_logic_vector( 31 downto 0);

    cnt_reset_in                          : in  std_logic 
  );
end entity qsfp_playback_intfc_128;

architecture arch_imp of qsfp_playback_intfc_128 is

  signal playback_data_path_enable_r      : std_logic_vector(0 to 31) := (others => '0');
  signal rx_path_fifo_rst_n               : std_logic;
  signal rx_path_fifo_rst_1_n             : std_logic;  
  signal qsfp_fifo_rst_n                  : std_logic;
  signal qsfp_fifo_rst_n_r                : std_logic_vector(0 to 2) := (others => '0');
  signal iq_512b_to_240b_rst_n            : std_logic;
  signal playback_data_path_enable        : std_logic;
  
  signal rx_tvalid_128b_en                : std_logic;
  signal rx_tvalid_128b_en_cnt_r          : std_logic_vector(31 downto 0) := (others => '0');
  signal rx_tvalid_128b_cnt_r             : std_logic_vector(31 downto 0) := (others => '0');
  signal rx_tready_128b                   : std_logic;
  
  signal rx_tdata_128b_pipe               : std_logic_vector(127 downto 0); 
  signal rx_tvalid_128b_pipe              : std_logic;
  signal rx_tready_128b_pipe              : std_logic;

  signal rx_tdata_512b                    : std_logic_vector(511 downto 0); 
  signal rx_tvalid_512b                   : std_logic;
  signal rx_tready_512b                   : std_logic;
  signal rx_tdata_512b_pipe               : std_logic_vector(511 downto 0); 
  signal rx_tvalid_512b_pipe              : std_logic;
  signal rx_tready_512b_pipe              : std_logic;

  signal rx_tdata_240b                    : std_logic_vector(239 downto 0); 
  signal rx_tvalid_240b                   : std_logic;
  signal rx_tready_240b                   : std_logic;

  signal rx_tdata_240b_pipe               : std_logic_vector(239 downto 0); 
  signal rx_tvalid_240b_pipe              : std_logic;
  signal rx_tready_240b_pipe              : std_logic;

  signal qsfp_playback_tvalid_240b        : std_logic;
  signal qsfp_playback_tvalid_240b_cnt_r  : std_logic_vector(31 downto 0) := (others => '0');
  
  signal rx_overflow_128b_cnt_r           : std_logic_vector(31 downto 0) := (others => '0');

begin

  qsfp_playback_tvalid_240b_out       <= qsfp_playback_tvalid_240b;
  qsfp_playback_tvalid_240b_cnt_out   <= qsfp_playback_tvalid_240b_cnt_r;
  rx_tvalid_128b_cnt_out              <= rx_tvalid_128b_cnt_r;
  rx_tvalid_128b_en_cnt_out           <= rx_tvalid_128b_en_cnt_r;
  rx_tready_128b_out                  <= rx_tready_128b;
  rx_overflow_128b_cnt_out            <= rx_overflow_128b_cnt_r;
   
  process(rx_device_clk_in, rx_device_clk_aresetn_in)  
  begin
    if (rx_device_clk_aresetn_in = '0') then
      playback_data_path_enable_r  <= (others => '0');
    elsif (rising_edge(rx_device_clk_in)) then
      if (playback_data_path_enable_n_in = '1') then 
        playback_data_path_enable_r  <= (others => '0');
      else
        playback_data_path_enable_r  <= playback_data_path_enable_r(1 to 31) & '1';
      end if;
    end if;
  end process;

  rx_path_fifo_rst_n          <= playback_data_path_enable_r(27);
  rx_path_fifo_rst_1_n        <= playback_data_path_enable_r(26);
  iq_512b_to_240b_rst_n       <= playback_data_path_enable_r(20);
  qsfp_fifo_rst_n             <= playback_data_path_enable_r(16);
  playback_data_path_enable   <= playback_data_path_enable_r(0);

  process(rx_device_clk_in)  
  begin
    if (rising_edge(rx_device_clk_in)) then
      if (cnt_reset_in = '1')  then
        rx_tvalid_128b_cnt_r   <= (others => '0');
      elsif (rx_tvalid_128b_in = '1') then
        rx_tvalid_128b_cnt_r   <= rx_tvalid_128b_cnt_r + 1;
      end if;
    end if;
  end process;
       
  process(rx_device_clk_in)  
  begin
    if (rising_edge(rx_device_clk_in)) then
      if ((rx_path_fifo_rst_n = '1' and rx_path_fifo_rst_1_n = '0') or cnt_reset_in = '1')  then
        rx_overflow_128b_cnt_r   <= (others => '0');
      elsif (rx_tvalid_128b_en = '1' and rx_tready_128b = '0') then
        rx_overflow_128b_cnt_r   <= rx_overflow_128b_cnt_r + 1;
      end if;
    end if;
  end process;

  rx_tvalid_128b_en <= rx_tvalid_128b_in when playback_data_path_enable = '1' else '0';

  i_rx_register_slice_128b : entity work.axis_register_slice_128b  
    port map (
      aclk                                 => rx_device_clk_in,        -- in    
      aresetn                              => rx_path_fifo_rst_n,      -- in   
      s_axis_tdata                         => rx_tdata_128b_in,        -- in
      s_axis_tvalid                        => rx_tvalid_128b_en,       -- in
      s_axis_tready                        => rx_tready_128b,          -- out
                                                                       
      m_axis_tdata                         => rx_tdata_128b_pipe,      -- out         
      m_axis_tvalid                        => rx_tvalid_128b_pipe,     -- out         
      m_axis_tready                        => rx_tready_128b_pipe      -- in          
      );


--  i_ila_4 : entity work.ila_4  
--  port map ( 
--    clk                                     => rx_device_clk_in,
--    probe0                                  => rx_tdata_128b_in,      -- 128
--    probe1                                  => rx_tvalid_128b_en,       -- 1
--    probe2                                  => rx_tready_128b,           -- 1
--    probe3                                  => rx_tvalid_128b_cnt_r     -- 32
--    );

   
  process(rx_device_clk_in)  
  begin
    if (rising_edge(rx_device_clk_in)) then
      if ((rx_path_fifo_rst_n = '1' and rx_path_fifo_rst_1_n = '0') or cnt_reset_in = '1')  then
        rx_tvalid_128b_en_cnt_r   <= (others => '0');
      elsif (rx_tvalid_128b_pipe = '1' and rx_tready_128b_pipe = '1') then
        rx_tvalid_128b_en_cnt_r   <= rx_tvalid_128b_en_cnt_r + 1;
      end if;
    end if;
  end process;

  i_axis_dwidth_converter_128b_to_512b : entity work.axis_dwidth_converter_128b_to_512b  
    port map (
      aclk                              => rx_device_clk_in,   -- in               
      aresetn                           => rx_path_fifo_rst_n, -- in            
      s_axis_tdata                      => rx_tdata_128b_pipe, -- in
      s_axis_tvalid                     => rx_tvalid_128b_pipe,-- in
      s_axis_tready                     => rx_tready_128b_pipe,-- out
      m_axis_tdata                      => rx_tdata_512b,      -- out
      m_axis_tvalid                     => rx_tvalid_512b,     -- out
      m_axis_tready                     => rx_tready_512b      -- in
    );

  i_qsfp_reg_slice_512 : entity work.axis_register_slice_512b
    port map (
      aclk                              => rx_device_clk_in,              -- in  
      aresetn                           => rx_path_fifo_rst_n,      -- in  
      s_axis_tdata                      => rx_tdata_512b,           -- in
      s_axis_tvalid                     => rx_tvalid_512b,          -- in
      s_axis_tready                     => rx_tready_512b,          -- out
      m_axis_tdata                      => rx_tdata_512b_pipe,      -- out
      m_axis_tvalid                     => rx_tvalid_512b_pipe,     -- out
      m_axis_tready                     => rx_tready_512b_pipe      -- in
    );

  i_iq_512b_to_240b : entity work.iq_512b_to_240b   
    port map (
      aclk                              => rx_device_clk_in,              -- in
      aresetn                           => iq_512b_to_240b_rst_n,         -- in
      s_axis_tdata                      => rx_tdata_512b_pipe,      --in
      s_axis_tvalid                     => rx_tvalid_512b_pipe,     --in
      s_axis_tready                     => rx_tready_512b_pipe,     --out
      m_axis_tdata                      => rx_tdata_240b,           --out
      m_axis_tvalid                     => rx_tvalid_240b,          --out
      m_axis_tready                     => rx_tready_240b           --in
    );

  i_qsfp_reg_slice_240b : entity work.axis_register_slice_240b 
    port map (
      aclk                              => rx_device_clk_in,            -- in
      aresetn                           => rx_path_fifo_rst_n,    -- in
      s_axis_tdata                      => rx_tdata_240b,         --in
      s_axis_tvalid                     => rx_tvalid_240b,        --in
      s_axis_tready                     => rx_tready_240b,        --out
      m_axis_tdata                      => rx_tdata_240b_pipe,    --out
      m_axis_tvalid                     => rx_tvalid_240b_pipe,   --out
      m_axis_tready                     => rx_tready_240b_pipe    --in
    );

  i_qsfp_fifo : entity work.axis_data_afifo_32x240  
    port map (
      s_axis_aclk                       => rx_device_clk_in,               -- in                    
      s_axis_aresetn                    => qsfp_fifo_rst_n,               -- in                       
      s_axis_tdata                      => rx_tdata_240b_pipe,       --in                 rx_tdata_240b,       --in  
      s_axis_tvalid                     => rx_tvalid_240b_pipe,      --in                 rx_tvalid_240b,      --in  
      s_axis_tready                     => rx_tready_240b_pipe,      --out                rx_tready_240b,      --out 

      m_axis_aclk                       => qsfp_playback_aclk_in,            -- in  
      m_axis_tdata                      => qsfp_playback_tdata_240b_out,          --out                
      m_axis_tvalid                     => qsfp_playback_tvalid_240b,             --out               
      m_axis_tready                     => qsfp_playback_tready_240b_in           --in                    
   );


  process(qsfp_playback_aclk_in)  
  begin
    if (rising_edge(qsfp_playback_aclk_in)) then
      qsfp_fifo_rst_n_r  <= qsfp_fifo_rst_n_r(1 to 2) & qsfp_fifo_rst_n;
    end if;
  end process;
  
  process(qsfp_playback_aclk_in)  
  begin
    if (rising_edge(qsfp_playback_aclk_in)) then
      if ((qsfp_fifo_rst_n_r(1) = '1' and qsfp_fifo_rst_n_r(0) = '0') or cnt_reset_in = '1')  then
        qsfp_playback_tvalid_240b_cnt_r   <= (others => '0');
      elsif (qsfp_playback_tvalid_240b = '1' and qsfp_playback_tready_240b_in = '1') then
        qsfp_playback_tvalid_240b_cnt_r   <= qsfp_playback_tvalid_240b_cnt_r + 1;
      end if;
    end if;
  end process;
  
end architecture arch_imp;

