--==============================================================================
-- CERN (BE-CO-HT)
-- Ring buffer for converter board designs
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- date of creation: 2014-03-19
--
-- version: 1.0
--
-- description:
--    Ring buffer memory with configurable (at synthesis time) data width and
--    size. Although created for the converter board design, it can be used in
--    any desing.
--
-- dependencies:
--    genram_pkg : git://ohwr.org/hdl-core-lib/general-cores.git
--
--==============================================================================
-- GNU LESSER GENERAL PUBLIC LICENSE
--==============================================================================
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--==============================================================================
-- last changes:
--    2014-03-19   Theodor Stana     Created file and copied content from
--                                   fd_ring_buffer.
--==============================================================================
-- TODO: -
--==============================================================================

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

use work.genram_pkg.all;


entity conv_ring_buf is
  generic
  (
    -- Buffer data input and output width
    g_data_width : positive;

    -- Buffer size in number of samples
    g_size       : positive
  );
  port
  (
    -- Clocks and reset
    clk_rd_i       : in  std_logic;
    clk_wr_i       : in  std_logic;
    rst_n_a_i      : in  std_logic;

    -- Buffer inputs
    buf_dat_i      : in  std_logic_vector(g_data_width-1 downto 0);
    buf_rd_req_i   : in  std_logic;
    buf_wr_req_i   : in  std_logic;
    buf_clr_i      : in  std_logic;

    -- Buffer outputs
    buf_dat_o      : out std_logic_vector(g_data_width-1 downto 0);
    buf_count_o    : out std_logic_vector(f_log2_size(g_size)-1 downto 0);
    buf_full_o     : out std_logic;
    buf_empty_o    : out std_logic
  );
end entity conv_ring_buf;


architecture behav of conv_ring_buf is

  --============================================================================
  -- Type declarations
  --============================================================================

  --============================================================================
  -- Constant declarations
  --============================================================================
  constant c_fifo_size : positive := 8;

  --============================================================================
  -- Signal declarations
  --============================================================================
  -- FIFO signals
  signal fifo_full    : std_logic;
  signal fifo_empty   : std_logic;
  signal fifo_read    : std_logic;
  signal fifo_read_d0 : std_logic;
  signal fifo_write   : std_logic;
  signal fifo_in      : std_logic_vector(g_data_width-1 downto 0);
  signal fifo_out     : std_logic_vector(g_data_width-1 downto 0);

  -- Buffer signals
  signal buf_write    : std_logic;
  signal buf_read     : std_logic;
  signal buf_wr_ptr   : unsigned(f_log2_size(g_size)-1 downto 0);
  signal buf_rd_ptr   : unsigned(f_log2_size(g_size)-1 downto 0);
  signal buf_wr_data  : std_logic_vector(g_data_width-1 downto 0);
  signal buf_rd_data  : std_logic_vector(g_data_width-1 downto 0);
  signal buf_count    : unsigned(f_log2_size(g_size)-1 downto 0);
  signal buf_empty    : std_logic;
  signal buf_full     : std_logic;
  signal buf_overflow : std_logic;

--==============================================================================
--  architecture begin
--==============================================================================
begin

  --============================================================================
  -- Buffer FIFO and RAM
  --============================================================================
  -- Assign FIFO input and control
  fifo_in    <= buf_dat_i;
  fifo_write <= not fifo_full and buf_wr_req_i;
  fifo_read  <= not fifo_empty;

  -- Instantiate FIFO to synchronize data inputs from read clock to write clock
  cmp_clk_adjust_fifo : generic_async_fifo
    generic map
    (
      g_data_width => fifo_in'length,
      g_size       => c_fifo_size
    )
    port map (
      rst_n_i    => rst_n_a_i,
      clk_wr_i   => clk_wr_i,
      d_i        => fifo_in,
      we_i       => fifo_write,
      wr_full_o  => fifo_full,
      clk_rd_i   => clk_rd_i,
      q_o        => fifo_out,
      rd_i       => fifo_read,
      rd_empty_o => fifo_empty);

  -- Instantiate the actual buffer RAM
  -- The buffer gets fed with data from the FIFO
  buf_wr_data <= fifo_out;

  cmp_buf_ram : generic_dpram
    generic map (
      g_data_width => g_data_width,
      g_size       => g_size,
      g_dual_clock => false)
    port map (
      rst_n_i => rst_n_a_i,
      clka_i  => clk_rd_i,
      bwea_i  => (others => '1'),
      wea_i   => buf_write,
      aa_i    => std_logic_vector(buf_wr_ptr),
      da_i    => buf_wr_data,
      qa_o    => open,
      clkb_i  => clk_rd_i,
      bweb_i  => (others => '0'),
      web_i   => '0',
      ab_i    => std_logic_vector(buf_rd_ptr),
      db_i    => (others => '0'),
      qb_o    => buf_rd_data);

  --============================================================================
  -- Buffer control
  --============================================================================
  -- Assign buffer control signals
  buf_write    <= fifo_read_d0;
  buf_read     <= '1' when ((buf_rd_req_i = '1') and (buf_empty = '0')) or
                           (buf_overflow = '1')
                   else '0';
  buf_overflow <= '1' when (buf_write = '1') and (buf_full = '1') else '0';

  -- Buffer control process
  p_buffer_control : process(clk_rd_i)
  begin
    if rising_edge(clk_rd_i) then
      if (rst_n_a_i = '0') or (buf_clr_i = '1') then
        buf_rd_ptr   <= (others => '0');
        buf_wr_ptr   <= (others => '0');
        buf_count    <= (others => '0');
        buf_full     <= '0';
        buf_empty    <= '1';

        fifo_read_d0 <= '0';

      else

        fifo_read_d0 <= fifo_read;

        -- Read and write signals
        if(buf_write = '1') then
          buf_wr_ptr <= buf_wr_ptr + 1;
        end if;

        if(buf_read = '1') then
          buf_rd_ptr <= buf_rd_ptr + 1;
        end if;

        -- Buffer count and full/empty control
        if (buf_write = '1') and (buf_read = '0') and (buf_full = '0') then
          buf_count <= buf_count + 1;
          buf_empty <= '0';
          if (buf_count = (buf_count'range => '1')) then
            buf_full <= '1';
          end if;
        end if;

        if (buf_write = '0') and (buf_read = '1') and (buf_empty = '0') then
          buf_count <= buf_count - 1;
          buf_full  <= '0';
          if (buf_count = 1) then
            buf_empty <= '1';
          end if;
        end if;

      end if;
    end if;
  end process;

  --============================================================================
  -- Output signals
  --============================================================================
  buf_full_o  <= buf_full;
  buf_empty_o <= buf_empty;
  buf_count_o <= std_logic_vector(buf_count);
  buf_dat_o   <= buf_rd_data;

end architecture behav;
--==============================================================================
--  architecture end
--==============================================================================
