----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    10:45:54 04/05/2010 
-- Design Name: 
-- Module Name:    i2s_driver - RTL 
-- Project Name: 
-- Target Devices: 
-- Tool versions:
-- Description:    Radic pro I2S D/A prevodnik (CS4344)
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity i2s_driver is
    Port ( clk : in  STD_LOGIC;									-- systemove hodiny (50MHz, 16MHz)
           RESET : in  STD_LOGIC;								-- systemovy reset (aktivni pri 1)
           L_DATA : in  STD_LOGIC_VECTOR (23 downto 0);	-- binarni komplement pro levy kanal
           R_DATA : in  STD_LOGIC_VECTOR (23 downto 0);	-- binarni komplement pro pravy kanal
           LOAD : out  STD_LOGIC;								-- signal k nabirani dat (vzorkovani)
           I2S_MCLK : out  STD_LOGIC;							-- I2S master clock
           I2S_SCLK : out  STD_LOGIC;							-- I2S serial clock
           I2S_LRCK : out  STD_LOGIC;							-- I2S left/right clock
           I2S_SDAT : out  STD_LOGIC);							-- I2S data
end i2s_driver;

architecture RTL of i2s_driver is

	component i2s_clkgen
	port ( 
		clk : in  STD_LOGIC;			-- systemove hodiny
      RESET : in  STD_LOGIC;		-- systemovy reset
      RATE : out  STD_LOGIC);		-- Samplovaci frq
	end component;

	signal iRATE : STD_LOGIC;
	signal iLRCK : STD_LOGIC;


	signal scnt	: std_logic_vector(2 downto 0);	-- serial clock divide register
	signal p_sclk	: std_logic;	-- 1 cycle wide copy of serial clock
	signal sreg	: std_logic_vector(47 downto 0); -- Shift register advances on serial clock
	
	signal lrcnt	: std_logic_vector(4 downto 0);
	
	signal sclk_p0	: std_logic;
	
begin

	-- Samplovaci requesty
	LOAD <= iRATE;


	-- MCLK vyrobime ze systemovych hodin
	I2S_MCLK <= clk;
	

	-- hodiny pro stridani kanalu
	I2S_LRCK <= iLRCK;


	-- serial clock
	I2S_SCLK	<= scnt(2);



	-- Zdroj hodin pro vzorkovani
	clkgen: i2s_clkgen
	port map ( 
		clk 	=> clk,			-- systemove hodiny
      RESET	=> RESET,			-- systemovy reset
      RATE	=> iRATE			-- Samplovaci frq
	);


	-- Serial Clock divider
	process ( clk )
	begin
		if clk'event and clk = '1' then
			if RESET = '1' or iRATE = '1' then
				scnt	<= "000";
			else
				scnt	<= scnt + 1;
			end if;
		end if;
	end process;


	-- generate serial clock pulse
	process ( clk )
	begin
		if clk'event and clk = '1' then
			p_sclk	<= not ( scnt(0) or scnt(1) or scnt(2) );
		end if;
	end process;

	

	-- Shift register advances on serial clock
	process ( clk )
	begin
		if clk'event and clk = '1' then
			if iRATE = '1' then
				sreg	<= ( L_DATA & R_DATA );
			elsif p_sclk = '1' then
				sreg	<= ( sreg(46 downto 0) & '0' );
			end if;
		end if;
	end process;



	-- 1 serial clock cycle delay on data relative to LRCLK
	process ( clk )
	begin
		if clk'event and clk = '1' then
			if p_sclk = '1' then
				I2S_SDAT	<= sreg(47);
			end if;
		end if;
	end process;


	-- Generate LR clock
	process ( clk )
	begin
		if clk'event and clk = '1' then
		
			if reset = '1' or iRATE = '1' then
				lrcnt	<= "00000";
				iLRCK	<= '0';
				
			elsif p_sclk = '1' then
				if lrcnt = CONV_STD_LOGIC_VECTOR(23,5) then
					lrcnt	<= "00000";
					iLRCK	<= not iLRCK;
					
				else
					lrcnt	<= lrcnt + 1;
				end if;
				
			end if;
			
		end if;
	end process;


end RTL;

