-------------------------------------------------------------------------------
-- Ultranet transmitter
-- 
-- Adapted from: SP/DIF Transmitter by Danny Witberg  from ackspace.nl SP/DIF_transmitter_project
------------------------------------------------------------------------------- 

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity aes3tx is
	generic(
		FRAME_COUNTER_RESET 	: std_logic_vector(8 downto 0) := "101111111";
		AES3_PREAMBLE_X 		: std_logic_vector(7 downto 0) := "10010011";
		AES3_PREAMBLE_Y 		: std_logic_vector(7 downto 0) := "10010110";
		AES3_PREAMBLE_Z 		: std_logic_vector(7 downto 0) := "10011100"
	);
	port
	(
		bit_clock	: in std_logic; -- 128x Fsample (6.144MHz for 48K samplerate)
		sample		: in std_logic_vector(23 downto 0);
		biphase_out	: out std_logic;

		bsync	: out std_logic;

		valid	: in std_logic;
		channel_status		: in std_logic_vector(383 downto 0);
		user_status		: in std_logic_vector(383 downto 0)
	);
end entity;

architecture behavioral of aes3tx is

	signal data_in_buffer			: std_logic_vector(23 downto 0);
	signal bit_counter				: std_logic_vector(5 downto 0) := (others => '0');
	signal frame_counter			: std_logic_vector(8 downto 0) := (others => '0');
	signal channel_counter			: std_logic_vector(3 downto 0) := (others => '0');
	signal data_biphase				: std_logic := '0';
	signal data_out_buffer			: std_logic_vector(7 downto 0);
	signal parity					: std_logic;
	signal channel_status_shift		: std_logic_vector(383 downto 0);
	signal user_status_shift		: std_logic_vector(383 downto 0);

begin
	
	bit_clock_counter : process (bit_clock)
	begin
		if bit_clock'event and bit_clock = '1' then
			bit_counter <= bit_counter + 1;
		end if;
	end process bit_clock_counter;

	data_latch : process (bit_clock)
	begin
		if bit_clock'event and bit_clock = '1' then
			parity <= data_in_buffer(23) xor data_in_buffer(22) xor data_in_buffer(21) xor data_in_buffer(20) xor data_in_buffer(19) xor data_in_buffer(18) xor data_in_buffer(17)  xor data_in_buffer(16) xor data_in_buffer(15) xor data_in_buffer(14) xor data_in_buffer(13) xor data_in_buffer(12) xor data_in_buffer(11) xor data_in_buffer(10) xor data_in_buffer(9) xor data_in_buffer(8) xor data_in_buffer(7) xor data_in_buffer(6) xor data_in_buffer(5) xor data_in_buffer(4) xor data_in_buffer(3) xor data_in_buffer(2) xor data_in_buffer(1) xor data_in_buffer(0) xor valid xor user_status_shift(383) xor channel_status_shift(383);


			if bit_counter = 3 then
				-- We are near the end of the preamble, load the sound data in the buffer
				data_in_buffer <= sample;
			end if;

			if bit_counter = 63 then
				-- We are at the 32th bit (2x due to biphase) which means the end of a frame
				
				-- Check if this is the last frame in the audio block
				if frame_counter = FRAME_COUNTER_RESET then
					-- Yes, reset the frame counter
					frame_counter <= (others => '0');
				else
					-- Nope, increment the frame counter
					frame_counter <= frame_counter + 1;
				end if;

				if channel_counter = "111" then
					-- Yes, reset the frame counter
					channel_counter <= (others => '0');
				else
					channel_counter <= channel_counter + 1;
				end if;
			end if;
		end if;
	end process data_latch;

	data_output : process (bit_clock)
	begin
		-- On new bit clock pulse
		if bit_clock'event and bit_clock = '1' then
			if bit_counter = 63 then
				-- We are at the 32th bit of the frame (2x due to biphase) which means the end of a frame
				
				-- Check if this is the last frame in the audio block
				if frame_counter = FRAME_COUNTER_RESET then
					-- Next frame will be the first of the new audio block, load the Z preamble
					channel_status_shift <= channel_status;
                    user_status_shift <= user_status;
					data_out_buffer <= AES3_PREAMBLE_Z;
                    bsync <= '1';
				else
					-- Next frame is NOT the first of the audio block
					-- Check if the frame is even/odd (generally attributed to left/right)
					if frame_counter(0) = '1' then 
						-- Next frame is even, load the X preamble
						data_out_buffer <= AES3_PREAMBLE_X ;
					else 
						-- Next frame is odd, load the Y preamble
						data_out_buffer <= AES3_PREAMBLE_Y;
					end if;
                    -- Shift the channel status and user by one to the left
					channel_status_shift <= channel_status_shift(382 downto 0) & '0';
					user_status_shift <= user_status_shift(382 downto 0) & '0';
				end if;
			else
                    bsync <= '0';
				if bit_counter(2 downto 0) = "111" then -- load new part of data into buffer
					case bit_counter(5 downto 3) is
						when "000" =>
							data_out_buffer <= '1' & data_in_buffer(0) & '1' & data_in_buffer(1) & '1' & data_in_buffer(2) & '1' & data_in_buffer(3);
						when "001" =>
							data_out_buffer <= '1' & data_in_buffer(4) & '1' & data_in_buffer(5) & '1' & data_in_buffer(6) & '1' & data_in_buffer(7);
						when "010" =>
							data_out_buffer <= '1' & data_in_buffer(8) & '1' & data_in_buffer(9) & '1' & data_in_buffer(10) & '1' & data_in_buffer(11);
						when "011" =>
							data_out_buffer <= '1' & data_in_buffer(12) & '1' & data_in_buffer(13) & '1' & data_in_buffer(14) & '1' & data_in_buffer(15);
						when "100" =>
							data_out_buffer <= '1' & data_in_buffer(16) & '1' & data_in_buffer(17) & '1' & data_in_buffer(18) & '1' & data_in_buffer(19);
						when "101" =>
							data_out_buffer <= '1' & data_in_buffer(20) & '1' & data_in_buffer(21) & '1' & data_in_buffer(22) & '1' & data_in_buffer(23);
						when "110" =>
							data_out_buffer <= "1" & valid & "1" & user_status_shift(383) & "1" & channel_status_shift(383) & "1" & parity;
						when others =>
					end case;
				else
					data_out_buffer <= data_out_buffer(6 downto 0) & '0';
				end if;
			end if;
		end if;
	end process data_output;
	
	biphaser : process (bit_clock)
	begin
		if bit_clock'event and bit_clock = '1' then
			if data_out_buffer(data_out_buffer'left) = '1' then
				data_biphase <= not data_biphase;
			end if;
		end if;
	end process biphaser;

	biphase_out <= data_biphase;
	
end behavioral;