library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity de2_wm8731_audio is
port (
    clk : in std_logic;       --  Audio CODEC Chip Clock AUD_XCK (18.43 MHz)
    reset_n : in std_logic;
    data_in : in unsigned(23 downto 0);
	data_out: out unsigned(23 downto 0);
  
    -- Audio interface signals
    AUD_ADCLRCK  : out  std_logic;   --    Audio CODEC ADC LR Clock
    AUD_ADCDAT   : in   std_logic;   --    Audio CODEC ADC Data
    AUD_DACLRCK  : out  std_logic;   --    Audio CODEC DAC LR Clock
    AUD_DACDAT   : out  std_logic;   --    Audio CODEC DAC Data
    AUD_BCLK     : inout std_logic  --    Audio CODEC Bit-Stream Clock
  );
end  de2_wm8731_audio;

architecture rtl of de2_wm8731_audio is     

    signal lrck : std_logic;
    signal bclk : std_logic;
    signal xck  : std_logic;
    
    signal lrck_divider : unsigned(7 downto 0); 
    signal bclk_divider : unsigned(3 downto 0);
    
    signal set_bclk : std_logic;
    signal set_lrck : std_logic;
    signal clr_bclk : std_logic;
    
    signal shift_out : unsigned(23 downto 0);
	signal shift_in  : unsigned(23 downto 0);

begin
  
    -- LRCK divider 
    -- Audio chip main clock is 18.432MHz / Sample rate 48KHz
    -- Divider is 18.432 MHz / 48KHz = 192 (X"C0")
    -- Left justify mode set by I2C controller
    
  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then 
        lrck_divider <= (others => '0');
      elsif lrck_divider = X"BF"  then        -- "C0" minus 1
        lrck_divider <= X"00";
      else 
        lrck_divider <= lrck_divider + 1;
      end if;
    end if;   
  end process;

  process (clk)
  begin
    if rising_edge(clk) then      
      if reset_n = '0' then 
        bclk_divider <= (others => '0');
      elsif bclk_divider = X"B" or set_lrck = '1'  then  -- 16-bit audio
		--elsif bclk_divider = X"7" or set_lrck = '1'  then  -- 24-bit audio
        bclk_divider <= X"0";
      else 
        bclk_divider <= bclk_divider + 1;
      end if;
    end if;
  end process;

  set_lrck <= '1' when lrck_divider = X"BF" else '0';
    
  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then
        lrck <= '0';
      elsif set_lrck = '1' then 
        lrck <= not lrck;
      end if;
    end if;
  end process;
    
  -- BCLK divider
  set_bclk <= '1' when bclk_divider(3 downto 0) = "0101" else '0';
  clr_bclk <= '1' when bclk_divider(3 downto 0) = "1011" else '0';
  
  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then
        bclk <= '0';
      elsif set_lrck = '1' or clr_bclk = '1' then
        bclk <= '0';
      elsif set_bclk = '1' then 
        bclk <= '1';
      end if;
    end if;
  end process;

  -- Audio data shift output
  process (clk)
  begin
    if rising_edge(clk) then
      if reset_n = '0' then
        shift_out <= (others => '0');
      elsif set_lrck = '1' then
          shift_out <= data_in;
      elsif clr_bclk = '1' then 
        shift_out <= shift_out (22 downto 0) & '0';
      end if;
    end if;   
  end process;

    -- Audio outputs
    
    AUD_ADCLRCK  <= lrck;          
    AUD_DACLRCK  <= lrck;          
    AUD_DACDAT   <= shift_out(23); 
    AUD_BCLK     <= bclk;          

-- Audio data shift input
process (clk) 
begin
	if rising_edge(clk) then
		if(reset_n = '0') then
			shift_in <= (others => '0');
		elsif set_lrck = '1' then
			data_out <= shift_in;
		elsif clr_bclk = '1' then
			shift_in <= shift_in (22 downto 0) & AUD_ADCDAT;
		end if;
	end if;
end process;



end architecture;


