--
-- FIFO Used for sending OCB Acks/Replies
--
-- Filled with data as per normal, but Opcode etc need only be added at send time.
-- This allow truncations, timeouts etc to be flagged, but existing data to be
-- sent.
-- Based on a BRAM, as it's less LUT hungry
--
-- NOTE: The size is provided by the "client" - and not monitored here. This may
-- have to change, but lets see if we can get away from it ...
--
--
-- Changelog:
-- 2012-07-05 -- Added sof - keeps things tidy. 

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;

library hsio;
use hsio.pkg_core_globals.all;

entity ll_fifo_ack_gen is
  port(

    -- input interface
    data_i : in slv16;
    wren_i : in std_logic;
    eof_i  : in std_logic;
    sof_i  : in std_logic;

    -- send interface
    send_i   : in    std_logic;
    opcode_i : in    slv16;
    ocseq_i  : in    slv16;
    size_i   : in    slv16;
    busy_o   : out   std_logic;
    -- locallink tx interface
    lls_o              : out t_llsrc;
    lld_i              : in std_logic;
    -- infrastucture
    clk      : in    std_logic;
    rst      : in    std_logic

    );

-- Declarations

end ll_fifo_ack_gen;


architecture rtl of ll_fifo_ack_gen is

  component cg_brfifo_1kx18
    port (
      clk        : in  std_logic;
      srst       : in  std_logic;
      din        : in  std_logic_vector(17 downto 0);
      wr_en      : in  std_logic;
      rd_en      : in  std_logic;
      dout       : out std_logic_vector(17 downto 0);
      full       : out std_logic;
      overflow   : out std_logic;
      empty      : out std_logic;
      underflow  : out std_logic;
      data_count : out std_logic_vector(1 downto 0);
      prog_full  : out std_logic
      );
  end component;

  signal fifo_din  : std_logic_vector(17 downto 0);
  signal fifo_dout : std_logic_vector(17 downto 0);
  signal fifo_rd   : std_logic;

  signal fifo_data : slv16;
  signal fifo_eof  : std_logic;
  signal fifo_sof  : std_logic;


  type states is (FIFOSOF, SrcRdy, OpcodeSOF, OCSeq, Size, PayloadEOF, Done,
                  Idle );
  signal state, nstate : states;


begin




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

  prc_sm_sync : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        state <= Idle;
      else
        state <= nstate;

      end if;
    end if;


  end process;


  prc_sm_async : process (lld_i, wren_i, send_i, data_i,
                          fifo_sof, fifo_eof, fifo_data, opcode_i, ocseq_i, size_i,
                          state)
  begin
    -- defaults
    nstate      <= Idle;
    busy_o      <= '1';
    lls_o.src_rdy <= '1';
    lls_o.sof     <= '0';
    lls_o.eof     <= '0';
    lls_o.data    <= fifo_data;
    fifo_rd     <= '0';


    case state is


      when Idle =>
        nstate      <= Idle;
        busy_o      <= '0';
        lls_o.src_rdy <= '0';
        if (send_i = '1') then
          busy_o    <= '1';
          nstate    <= FIFOSOF;
        end if;


      when FIFOSOF =>
        nstate      <= FIFOSOF;
        lls_o.src_rdy <= '0';
        fifo_rd   <= '1';
        if (fifo_sof = '1') then
          lls_o.src_rdy <= '1';
          fifo_rd   <= '0';
          if (lld_i = '1') then
            nstate  <= SrcRdy;
          end if;
        end if;


      when SrcRdy =>
        nstate    <= OpcodeSOF;


      when OpcodeSOF =>
        nstate   <= OpcodeSOF;
        lls_o.sof  <= '1';
        lls_o.data <= opcode_i;
        if (lld_i = '1') then
          nstate <= OCSeq;
        end if;


      when OCSeq =>
        nstate   <= OCSeq;
        lls_o.data <= ocseq_i;
        if (lld_i = '1') then
          nstate <= Size;
        end if;


      when Size =>
        nstate    <= Size;
        lls_o.data  <= size_i;
        if (lld_i = '1') then
          --fifo_rd <= '1';               -- need to get first word ready
          nstate  <= PayloadEOF;
        end if;


      when PayloadEOF =>
        nstate      <= PayloadEOF;
        lls_o.data    <= fifo_data;
        if (fifo_eof = '1') then
          lls_o.eof   <= '1';
        end if;
        if (lld_i = '1') then
          if (fifo_eof = '1') then
            nstate  <= Done;
          else
            fifo_rd <= '1';
          end if;
        end if;


      when Done =>
        nstate      <= Done;
        busy_o      <= '0';
        lls_o.src_rdy <= '0';
        if (send_i = '0') then
          nstate    <= Idle;
        end if;


    end case;
  end process;


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



  fifo0 : cg_brfifo_1kx18
    port map (
      clk        => clk,
      srst       => rst,
      din        => fifo_din,
      wr_en      => wren_i,
      rd_en      => fifo_rd,
      dout       => fifo_dout,
      full       => open,
      overflow   => open,
      empty      => open,
      underflow  => open,
      data_count => open,
      prog_full  => open
      );


  fifo_din(15 downto 0) <= data_i;
  fifo_din(16)          <= eof_i;
  fifo_din(17)          <= sof_i;

  fifo_sof  <= fifo_dout(17);
  fifo_eof  <= fifo_dout(16);
  fifo_data <= fifo_dout(15 downto 0);



-----------------------------------------------------------------------------------
end architecture;