-------------------------------------------------------------
-- MSS copyright 2016
--	Filename:  DELAY2.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 0
--	Date last modified: 7/31/16
-- Inheritance: 	DELAY.VHD 6/21/15
--
-- description:  Delay output by N samples
-- Delay is NSAMPLES_DELAY + 2 CLKs
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity DELAY2 is
	generic (
		ADDR_WIDTH: integer := 5;	
			-- memory address width (i.e. memory size)
			-- must meet ADDR_WIDTH > log2(NSAMPLES_DELAY) 
		DATA_WIDTH: integer := 18;
			-- data width. Valid values: 18 (future: 1,2,9,18,36)
		NSAMPLES_DELAY: integer := 1
			-- delay expressed in samples. Range 2 to (2**ADDR_WIDTH -1)
	);
    port ( 
		--GLOBAL CLOCKS, RESET
		CLK : in std_logic;				-- synchronous clock

		--// Input data stream
		DATA_IN: in std_logic_vector((DATA_WIDTH-1) downto 0);
			-- 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.


		--// Output data stream
		DATA_OUT: out std_logic_vector((DATA_WIDTH-1) downto 0);
			-- Read at rising edge of CLK when SAMPLE_CLK_OUT  = '1'.
		SAMPLE_CLK_OUT: out std_logic
			-- one CLK-wide pulse. 2 CLK latency w.r.t. SAMPLE_CLK_IN
			);
end entity;

architecture behavioral of DELAY2 is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT BRAM_DP2
    GENERIC(
		DATA_WIDTHA: integer;
		ADDR_WIDTHA: integer;
		DATA_WIDTHB: integer;
		ADDR_WIDTHB: integer
    );
    PORT(
		CSA : IN std_logic;
		CLKA   : in  std_logic;
		WEA    : in  std_logic;
		OEA : IN std_logic;
		ADDRA  : in  std_logic_vector(ADDR_WIDTHA-1 downto 0);
		DIA   : in  std_logic_vector(DATA_WIDTHA-1 downto 0);
		DOA  : out std_logic_vector(DATA_WIDTHA-1 downto 0);
		CSB : IN std_logic;
		CLKB   : in  std_logic;
		WEB    : in  std_logic;
		OEB : IN std_logic;
		ADDRB  : in  std_logic_vector(ADDR_WIDTHB-1 downto 0);
		DIB   : in  std_logic_vector(DATA_WIDTHB-1 downto 0);
		DOB  : out std_logic_vector(DATA_WIDTHB-1 downto 0)
        );
    END COMPONENT;
--------------------------------------------------------
--     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
signal WPTR: unsigned((ADDR_WIDTH-1) downto 0) := (others => '0');
signal RPTR: unsigned((ADDR_WIDTH-1) downto 0) := (others => '0');
signal SAMPLE_CLK_OUT_E: std_logic := '0';
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin


-- read/write pointers management.
PTR_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') then
			WPTR <= (WPTR + 1);
			RPTR <= WPTR - NSAMPLES_DELAY;
			SAMPLE_CLK_OUT_E <= '1';
		else
			SAMPLE_CLK_OUT_E <= '0';
		end if;
	end if;
end process;

BRAM_DP2_001: BRAM_DP2 
GENERIC MAP(
	DATA_WIDTHA => DATA_WIDTH,
	ADDR_WIDTHA => ADDR_WIDTH,	
	DATA_WIDTHB => DATA_WIDTH,
	ADDR_WIDTHB => ADDR_WIDTH
)
PORT MAP(
	CSA => '1',
	CLKA => CLK,
	WEA => SAMPLE_CLK_IN,
	ADDRA => std_logic_vector(WPTR),
	DIA => DATA_IN,
	OEA => '0',
	DOA => open,
	CSB => '1',
	CLKB => CLK,
	WEB => '0',
	ADDRB => std_logic_vector(RPTR),
	DIB => (others => '0'),
	OEB => '1',
	DOB => DATA_OUT
);

SAMPLE_CLK_OUT_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		SAMPLE_CLK_OUT <= SAMPLE_CLK_OUT_E;
	end if;
end process;
end architecture;
