--
-- LL Packet FIFO
--
-- Clock crossing fifo that buffers whole packets of data 
-- 
-- 
-- 

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

library utils;
use utils.pkg_types.all;


entity ll_pkt_fifo_txcx is
  port(
    -- input interface
    core_lls_i: in t_llsrc;
    core_lld_o : out std_logic;

    --core_src_rdy_i : in  std_logic;
    --core_sof_i     : in  std_logic;
    --core_eof_i     : in  std_logic;
    --core_data_i    : in  std_logic_vector (15 downto 0);
    --core_dst_rdy_o : out std_logic;

    -- output interface
   net_lls_o : out t_llsrc;
    net_lld_i : in std_logic;

    --net_data_o    : out std_logic_vector (15 downto 0);
    --net_sof_o     : out std_logic;
    --net_eof_o     : out std_logic;
    --net_dst_rdy_i : in  std_logic;
    --net_src_rdy_o : out std_logic;
    -- fifo status
    --full_o          : out std_logic;
    --near_full_o     : out std_logic;
    --overflow_o      : out std_logic;
    --underflow_o     : out std_logic;
    --wr_data_count_o : out std_logic_vector (3 downto 0) := "0000";
    clk80         : in  std_logic;
    rst80         : in  std_logic;
    clk125        : in  std_logic;
    rst125        : in  std_logic
    );

-- Declarations

end ll_pkt_fifo_txcx;


architecture rtl of ll_pkt_fifo_txcx is


  signal core_dst_rdy : std_logic;

  component cg_cxbrfifo_2kx18_ft
    port (
      wr_clk      : in  std_logic;
      wr_rst      : in  std_logic;
      din         : in  std_logic_vector(17 downto 0);
      wr_en       : in  std_logic;
      full        : out std_logic;
      --almost_full : out std_logic;
      prog_full   : out std_logic;

      rd_clk : in  std_logic;
      rd_rst : in  std_logic;
      rd_en  : in  std_logic;
      dout   : out std_logic_vector(17 downto 0);
      empty  : out std_logic
      );
  end component;



  signal fifo_rd : std_logic;

  signal fifo_full      : std_logic;
  signal fifo_prog_full : std_logic;
  signal fifo_din       : std_logic_vector(17 downto 0);
  signal fifo_wr        : std_logic;

  signal fifo_dout  : std_logic_vector(17 downto 0);
  --signal fifo_empty : std_logic;


  signal fifo_sof   : std_logic;
  signal fifo_sof_q : std_logic := '0';
  signal fifo_eof   : std_logic;


  signal efifo_rd : std_logic;

  signal efifo_full : std_logic;
  signal efifo_wr   : std_logic;

  signal efifo_dout  : std_logic_vector(0 downto 0);
  signal efifo_empty : std_logic;



  component cg_cxdrfifo_1x16_ft
    port (
      wr_clk : in  std_logic;
      wr_rst : in  std_logic;
      din    : in  std_logic_vector(0 downto 0);
      wr_en  : in  std_logic;
      full   : out std_logic;

      rd_clk : in  std_logic;
      rd_rst : in  std_logic;
      rd_en  : in  std_logic;
      dout   : out std_logic_vector(0 downto 0);
      empty  : out std_logic
      );
  end component;

  type states is (FIFOSOF,
                  SrcRdy, SOF, WaitEOF,
                  NextEOF, Delay,
                  Idle
                  );

  signal state, nstate : states;


begin


  core_dst_rdy   <= not(fifo_prog_full or rst80);
  core_lld_o <= core_dst_rdy;

  fifo_wr <= core_lls_i.src_rdy and core_dst_rdy;

  fifo_din(15 downto 0) <= core_lls_i.data;
  fifo_din(16)          <= core_lls_i.eof;
  fifo_din(17)          <= core_lls_i.sof;



  fifo0 : cg_cxbrfifo_2kx18_ft
    port map (
      wr_clk      => clk80,
      wr_rst      => rst80,
      din         => fifo_din,
      wr_en       => fifo_wr,
      full        => fifo_full,
      --almost_full => open,
      prog_full   => fifo_prog_full,

      rd_clk => clk125,
      rd_rst => rst125,
      rd_en  => fifo_rd,
      dout   => fifo_dout,
      empty  => open

      );

  net_lls_o.data <= fifo_dout(15 downto 0);
  fifo_eof   <= fifo_dout(16);
  fifo_sof   <= fifo_dout(17);





---------------------------------------------------------------

  prc_readsm_sync : process (clk125)
  begin
    if rising_edge(clk125) then
      if (rst125 = '1') then
        state <= Idle;
      else
        state <= nstate;

      end if;
    end if;
  end process;


  prc_readsm_async : process (efifo_dout, efifo_empty, fifo_eof, fifo_sof,
                              net_lld_i, state)
  begin

-- defaults
    nstate        <= Idle;
    net_lls_o.src_rdy <= '0';
    net_lls_o.sof     <= '0';
    net_lls_o.eof     <= '0';
    fifo_rd       <= '0';
    efifo_rd      <= '0';

    case state is

      when Idle =>
        nstate <= Idle;
        if (efifo_dout = "1") and (efifo_empty = '0') then  -- eof seen
          nstate <= FIFOSOF;
        end if;


      when FIFOSOF =>
        nstate <= FIFOSOF;
        if (fifo_sof = '1') then
          net_lls_o.src_rdy <= '1';
          if (net_lld_i = '1') then
            nstate <= SrcRdy;
          end if;
        else
          fifo_rd <= '1';
        end if;


      when SrcRdy =>
        net_lls_o.src_rdy <= '1';
        nstate        <= SOF;


      when SOF =>
        nstate        <= SOF;
        net_lls_o.src_rdy <= '1';
        net_lls_o.sof     <= '1';
        if (net_lld_i = '1') then
          fifo_rd <= '1';
          nstate  <= WaitEOF;
        end if;


      when WaitEOF =>
        nstate        <= WaitEOF;
        net_lls_o.src_rdy <= '1';
        net_lls_o.eof     <= fifo_eof;
        if (net_lld_i = '1') then
          if (fifo_eof = '1') then
            nstate <= NextEOF;          -- no more reads needed now
          else
            fifo_rd <= '1';
          end if;
        end if;


      when NextEOF =>
        efifo_rd <= '1';
        nstate   <= Delay;


      when Delay =>  -- need to wait for the delta_eof to update
        nstate <= Idle;


    end case;

  end process;



  -------------------------------------------------------------------
  -- EOF FIFO
  -------------------------------------------------------------------

  efifo_wr <= (core_lls_i.eof and core_lls_i.src_rdy and core_dst_rdy);


  efifo0 : cg_cxdrfifo_1x16_ft
    port map (
      wr_clk => clk80,
      wr_rst => rst80,
      din    => "1",
      wr_en  => efifo_wr,
      full   => efifo_full,

      rd_clk => clk125,
      rd_rst => rst125,
      rd_en  => efifo_rd,
      dout   => efifo_dout,
      empty  => efifo_empty
      );




end architecture;