-------------------------------------------------------------------------------
-- Clock derivation sub-module to receive ultranet signals
--
-- Requires:
--      - A 122.88 MHz master clock 
--      - The 12.288 MHz bit clock recovered from aes3rx
--      - The 192 kHz word clock recovered from aes3rx
--      - The aes3 block start signal
--  
-- Outputs:
--      - A 3.072 MHz i2s bit clock
--      - A 48 Khz word clock 
-- Both output clocks are synchronized to the AES3 signals
------------------------------------------------------------------------------- 

LIBRARY IEEE;    
USE IEEE.STD_LOGIC_1164.ALL;    

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

        -- Synchronization signal
        bsync	            : in std_logic;

        -- AES3 clocks
        aes_bclk	        : in std_logic;
        aes_lrclk           : in std_logic;

        -- Audio clocks
        i2s_bclk	        : inout std_logic;
        i2s_lrclk	        : inout std_logic
    );
end entity;

architecture Behavioral of ultranet_rx_clocks is
    -- Clock dividers for the output I2S clocks
    signal count_i2s_bclk : integer := 0;
    signal count_i2s_lrclk : integer := 0;

    -- AES3 Block start detector & signals
	signal zbsync,      zzbsync,        zzzbsync,       bsync_pos_edge          : std_logic;

    -- AES3 word clock clock detector & signals
	signal zaes_lrclk,  zzaes_lrclk,    zzzaes_lrclk,   aes_lrclk_pos_edge      : std_logic;

    -- AES3 bit clock detector & signals
	signal zaes_bclk,   zzaes_bclk,     zzzaes_bclk,    aes_bclk_neg_edge       : std_logic;

begin
	detect_bsync_edge : process(aes_bclk) begin
		if rising_edge(aes_bclk) 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_aes_lrck_pos_edge : process(clk) begin
		if rising_edge(clk) then
			zaes_lrclk <= aes_lrclk;
            zzaes_lrclk <= zaes_lrclk;
            zzzaes_lrclk <= zzaes_lrclk;
			if zzaes_lrclk = '1' and zzzaes_lrclk = '0' then
				aes_lrclk_pos_edge <= '1';
			else
				aes_lrclk_pos_edge <= '0';
			end if;
		end if;
	end process;	

	detect_aes_bclk_neg_edge : process(clk) begin
		if rising_edge(clk) then
			zaes_bclk <= aes_bclk;
			zzaes_bclk <= zaes_bclk;
            zzzaes_bclk <= zzaes_bclk;
			if zzaes_bclk = '0' and zzzaes_bclk = '1' then
				aes_bclk_neg_edge <= '1';
			else
				aes_bclk_neg_edge <= '0';
			end if;
		end if;
	end process;	

	

    i2s_bit_clock: process(aes_bclk)  begin
        if(rising_edge(aes_bclk)) then
            -- Make sure the clock is properly synchronized at the block start
            if(bsync_pos_edge = '1') then
                i2s_bclk <= '1';
                count_i2s_bclk <= 0;
            else
                -- Divide the AES3 bit clock to get the I2S bit clock 
                count_i2s_bclk <= count_i2s_bclk + 1;
                if(count_i2s_bclk = 1) then
                    i2s_bclk <= not i2s_bclk;
                    count_i2s_bclk <= 0;
                end if;

            end if;
        end if;
    end process;

    i2s_lr_clock: process(clk) begin
        if(rising_edge(clk)) then
            -- Make sure the clock is properly synchronized at the block start
            if(bsync = '1') then
                i2s_lrclk <= '0';
                count_i2s_lrclk <= 0;
            else
                -- Make sure the word clock is properly synchronized to the bit clock
                if(aes_bclk_neg_edge = '1' and aes_lrclk_pos_edge = '1') then

                    -- Divide the AES3 bit clock to get the I2S bit clock 
                    count_i2s_lrclk <= count_i2s_lrclk + 1;
                    if(count_i2s_lrclk = 1) then
                        i2s_lrclk <= not i2s_lrclk;
                        count_i2s_lrclk <=0;
                    end if;

                end if;
            end if;
        end if;
    end process;
end;