-------------------------------------------------------------
-- MSS copyright 2006-2009
--	Filename:  ELASTIC_BUFFER16b.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 4
--	Date last modified: 8-17-09
-- Inheritance: 	ELASTIC_BUFFER.VHD 8-11-09
--
-- description:  short elastic buffer to ease flow-control timing
-- requirements (typically in modulators).
-- See also ELASTIC_BUFFER_FLEX.VHD for elastic buffer without width conversion.  
-- 16-bit depth.
--
-- Rev 2. 12-15-06 AZ
-- Major overhaul/bug correction.
--
-- Rev 3. 8-11-09 AZ
-- Updated for simulation.   
--
-- Rev4 8-17-09 AZ
-- updated with parametric depth
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- UNISIM library includes all Xilinx primitives (no longer any need to 
-- declare under the Components section. ISE 6.3.
Library UNISIM;
use UNISIM.vcomponents.all;

entity ELASTIC_BUFFER16b is
    port ( 
		--GLOBAL CLOCKS, RESET
	   CLK: in std_logic;	-- master clock for this FPGA, internal to the module

		--// Input data stream
		DATA_IN: in std_logic;
			-- Read at rising edge of CLK when SAMPLE_CLK_IN  = '1'.
		SAMPLE_CLK_IN: in std_logic;
			-- one CLK wide pulse.
			-- Maximum rate: one SAMPLE_CLK_IN per CLK.
		SAMPLE_CLK_IN_REQ: out std_logic;
			-- requests data bits from the module upstream.


		--// Output data stream
		DATA_OUT: out std_logic;
			-- Read at rising edge of CLK when SAMPLE_CLK_OUT  = '1'.
		SAMPLE_CLK_OUT: out std_logic;
			-- one CLK-wide pulse
		SAMPLE_CLK_OUT_REQ: in std_logic
			-- module downstream requests data.
			-- Latency between request and SAMPLE_CLK_OUT is one CLK IF data is available.

			);
end entity;

architecture behavioral of ELASTIC_BUFFER16b is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _E indicates an extended precision version of the net with the same name
-- Suffix _N indicates an inverted version of the net with the same name
constant DEPTH: integer  := 16;	
	-- buffer depth
constant DEPTH_LOG2: integer := 4;	
	-- number of bits to represent the read/write pointers (log2(DEPTH))

--// Elastic buffer
signal EBUFFER: std_logic_vector((DEPTH-1) downto 0);
signal RPTR: std_logic_vector((DEPTH_LOG2-1) downto 0) := (others => '0');
signal RPTR_DEC: std_logic_vector((DEPTH_LOG2-1) downto 0);
signal RPTR_INC: std_logic_vector((DEPTH_LOG2-1) downto 0); 
signal READ_POINTER: integer range 0 to (DEPTH-1);
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

-- Push data in
PUSH_001: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_IN = '1') then
			EBUFFER(0) <= DATA_IN;
			EBUFFER((DEPTH - 1) downto 1) <= EBUFFER((DEPTH - 2) downto 0);
		end if;	 
	end if;
end process;

-- Manage read pointer
RPTR_DEC <= RPTR - 1;
RPTR_INC <= RPTR + 1;

RPTR_001: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_OUT_REQ = '1') and (RPTR /= 0) then
			-- reading while data available 
			SAMPLE_CLK_OUT <= '1';
			if(SAMPLE_CLK_IN = '0') then
				-- no simultaneous writing
				RPTR <= RPTR_DEC; 
			end if;
		elsif (SAMPLE_CLK_IN = '1') then
			-- writing, no reading
			RPTR <= RPTR_INC;
			SAMPLE_CLK_OUT <= '0';
		else
			SAMPLE_CLK_OUT <= '0';
		end if;	 
	end if;
end process;
   
READ_POINTER <= conv_integer(RPTR_DEC);   
   
-- output data
DATA_OUT_001: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_OUT_REQ = '1') then
			-- reading
			DATA_OUT <= EBUFFER(READ_POINTER); 
		end if;	 
	end if;
end process;

-- for flow control 
-- Ask for input data when elastic buffer is less than half full.
SAMPLE_CLK_IN_REQ <= '1' when (RPTR(DEPTH_LOG2 - 1) = '0') else '0';


end architecture;
