
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all; 
use ieee.numeric_std.all; -- lib for unsigned and signed

entity i2s_quad_deserializer is
	port (
		clk 		: in std_logic; -- Master clock

		bsync		: in std_logic; 
		bclk 		: in std_logic; -- bit clock
		lrclk		: in std_logic; -- word-select (left/right)

		sdata1		: in std_logic; -- serial data for ADC 1
		sdata2		: in std_logic; -- serial data for ADC 2
		sdata3		: in std_logic; -- serial data for ADC 3
		sdata4		: in std_logic; -- serial data for ADC 4
			
		sample_out_ch_1_l	: out std_logic_vector(23 downto 0); -- received audio sample of ADC1/1
		sample_out_ch_1_r	: out std_logic_vector(23 downto 0); -- received audio sample of ADC1/2
		sample_out_ch_2_l	: out std_logic_vector(23 downto 0); -- received audio sample of ADC2/1
		sample_out_ch_2_r	: out std_logic_vector(23 downto 0); -- received audio sample of ADC2/2
		sample_out_ch_3_l	: out std_logic_vector(23 downto 0); -- received audio sample of ADC3/1
		sample_out_ch_3_r	: out std_logic_vector(23 downto 0); -- received audio sample of ADC3/2
		sample_out_ch_4_l	: out std_logic_vector(23 downto 0); -- received audio sample of ADC4/1
		sample_out_ch_4_r	: out std_logic_vector(23 downto 0); -- received audio sample of ADC4/2

		new_data	: out std_logic -- new data received successfully
    );
end entity;

architecture rtl of i2s_quad_deserializer is
    -- Buffers to hold the partially completed sample buffers
	signal sample_ch_1_l_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_1_r_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_2_l_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_2_r_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_3_l_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_3_r_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_4_l_buf			    		: std_logic_vector(23 downto 0);
	signal sample_ch_4_r_buf			    		: std_logic_vector(23 downto 0);
    
    -- Bsync delays and signal for the Bsync positive edge
	signal zbsync, zzbsync, zzzbsync	    		: std_logic;
	signal bsync_pos_edge                   		: std_logic;

    -- Bit clock delays and signal for the bit clock positive edge
	signal zbclk, zzbclk, zzzbclk 	        		: std_logic;
	signal bclk_neg_edge, bclk_pos_edge 			: std_logic;

    -- Lr clock delays and signal for an lr clock edge
	signal lrck_edge, lrck_neg_edge, lrck_pos_edge	: std_logic;
	signal zlrclk, zzlrclk, zzzlrclk	    		: std_logic;
    
    -- Signal to specify when we should be reading bits
	signal has_data 		            			: std_logic;
    
    -- Bit counter
	signal bit_cnt					        		: integer range 0 to 31 := 0;

begin

	detect_bsync_edge : process(clk)
	begin
		if rising_edge(clk) then
			zbsync <= bsync;
			zzbsync <= zbsync;
			zzzbsync <= zzbsync;
			if zzbsync = '1' and zzzbsync = '0' then
				bsync_pos_edge <= '1';
			else
				bsync_pos_edge <= '0';
			end if;
		end if;
	end process;

	detect_bclk_edge : process(clk)
	begin
		if rising_edge(clk) then
			zbclk <= bclk;
			zzbclk <= zbclk;
			zzzbclk <= zzbclk;
			if zzbclk = '1' and zzzbclk = '0' then
				bclk_pos_edge <= '1';
			elsif zzbclk = '0' and zzzbclk = '1' then
				bclk_neg_edge <= '1';
			else
				bclk_pos_edge <= '0';
				bclk_neg_edge <= '0';
			end if;
		end if;
	end process;
 
    detect_lrck_edge : process(clk)
	begin
		if rising_edge(clk) then
			zlrclk <= lrclk;
			zzlrclk <= zlrclk;
			zzzlrclk <= zzlrclk;
			if zzlrclk = '1' and zzzlrclk = '0' then
				lrck_pos_edge <= '1';
				lrck_edge <= '1';
			elsif zzlrclk = '0' and zzzlrclk = '1' then
				lrck_neg_edge <= '1';
				lrck_edge <= '1';
			else
				lrck_pos_edge <= '0';
				lrck_neg_edge <= '0';
				lrck_edge <= '0';
			end if;
		end if;
	end process;
 
    detect_sample : process(clk) begin
		if rising_edge(clk) then
			if bsync_pos_edge = '1' then
                -- Sync detected, reset every signal
				bit_cnt <= 0;
				new_data <= '0';
			else
				if lrck_edge = '1' then
                    -- Left/right clock edge detected this means new channel -> reset the bit counter
					bit_cnt <= 0;
				end if;

				if bclk_pos_edge = '1' then
                    -- Bit clock positive clock edge detected -> increment the bit counter
					bit_cnt <= bit_cnt + 1;
				end if;

				if bclk_neg_edge = '1' then  	
                    -- Bit clock negative clock edge detected ->
                    -- Only read the first 24 bits, cheack the counter and set the signal appropriatly
					if bit_cnt = 0 then
						has_data <= '1';
					elsif bit_cnt >= 24 then
						has_data <= '0';
					end if;
				end if;

                -- Raise new_data at the end of the last bit, only for one clk cycle
				if bit_cnt = 31 and bclk_neg_edge = '1' and lrclk = '0' then 
					new_data <= '1';
				else
					new_data <= '0';
				end if;

   				-- Output the data
				if lrck_pos_edge = '1' then
					sample_out_ch_1_r <= sample_ch_1_r_buf;
					sample_out_ch_2_r <= sample_ch_2_r_buf;
					sample_out_ch_3_r <= sample_ch_3_r_buf;
					sample_out_ch_4_r <= sample_ch_4_r_buf;
				end if;
				if lrck_neg_edge = '1' then
					sample_out_ch_1_l <= sample_ch_1_l_buf;
					sample_out_ch_2_l <= sample_ch_2_l_buf;
					sample_out_ch_3_l <= sample_ch_3_l_buf;
					sample_out_ch_4_l <= sample_ch_4_l_buf;
				end if;
			end if;
		end if;
	end process;

	get_data : process(clk) begin
		if rising_edge(clk) then
			if bclk_pos_edge = '1' and has_data = '1' then
				-- Left shift
				if lrclk = '1' then
					sample_ch_1_l_buf <= sample_ch_1_l_buf(sample_ch_1_l_buf'high-1 downto sample_ch_1_l_buf'low) & sdata1;
					sample_ch_2_l_buf <= sample_ch_2_l_buf(sample_ch_2_l_buf'high-1 downto sample_ch_2_l_buf'low) & sdata2;
					sample_ch_3_l_buf <= sample_ch_3_l_buf(sample_ch_3_l_buf'high-1 downto sample_ch_3_l_buf'low) & sdata3;
					sample_ch_4_l_buf <= sample_ch_4_l_buf(sample_ch_4_l_buf'high-1 downto sample_ch_4_l_buf'low) & sdata4;
                else
					sample_ch_1_r_buf <= sample_ch_1_r_buf(sample_ch_1_r_buf'high-1 downto sample_ch_1_r_buf'low) & sdata1;
					sample_ch_2_r_buf <= sample_ch_2_r_buf(sample_ch_2_r_buf'high-1 downto sample_ch_2_r_buf'low) & sdata2;
					sample_ch_3_r_buf <= sample_ch_3_r_buf(sample_ch_3_r_buf'high-1 downto sample_ch_3_r_buf'low) & sdata3;
					sample_ch_4_r_buf <= sample_ch_4_r_buf(sample_ch_4_r_buf'high-1 downto sample_ch_4_r_buf'low) & sdata4;
				end if;
			end if;
		end if;
	end process;
end rtl;
        