LIBRARY ieee;
USE ieee.numeric_std.all;
USE ieee.std_logic_1164.all;

ENTITY sci_master IS
	GENERIC (
		BAUD_RATE	:	positive := 9600;								--! Frekvence SCI v baudech za sekundu
		CLK_FREQ	:	positive := 50_000_000							--! Frekvence interniho hodinoveho signalu
	);
	PORT (
		CLK			:	IN std_logic;									--! Interni hodinovy signal hradloveho pole
		RST			:	IN std_logic;									--! Reset pin, aktivni v log. 1

		TX			:	OUT std_logic;									--! Vystupni signal SCI
		
		DIN			:	IN std_logic_vector(7 DOWNTO 0);				--! Vektor vstupnich dat urcenych pro odeslani po SCI
		SEND		:	IN std_logic;									--! Pri nabezne hrane tohoto signalu zacne zarizeni vysilat
		READY		:	OUT std_logic									--! Log. 1 indikuje, ze je zarizeni pripraveno vysilat
	);
END;
 

ARCHITECTURE Behavioral OF sci_master IS

	CONSTANT	sciCLK_cnt_max	:	integer		:= CLK_FREQ/BAUD_RATE/2;--! Vypocitana maximalni hodnota citace pro spravne deleni kmitoctu
	SIGNAL		sciCLK			:	std_logic 	:= '0';					--! Hodinovy signal SCI
	SIGNAL		sciCLK_prev		:	std_logic 	:= '0';					--! Predchozi hodnota hodinoveho signalu SCI
	SIGNAL		sciCLK_redge	:	std_logic 	:= '0';					--! Paklize je nabezna hrana, tak je v log. 1

	SIGNAL		iSEND			:	std_logic 	:= '0';					--! Signal iSEND v hlavni hodinove domene
	SIGNAL		iSEND_prev		:	std_logic 	:= '0';					--! Predchozi hodnota signalu iSEND
	SIGNAL		iSEND_redge		:	std_logic 	:= '0';					--! Paklize je nabezna hrana, tak je v log. 1
	
	SIGNAL		iDIN			:	std_logic_vector(7 DOWNTO 0) := (OTHERS => '0'); --! Interni buffer s daty pro odesilani
	SIGNAL		iPAR			:	std_logic	:= '0';					--! Hodnota sude parity pro kontrolu dat

	TYPE 	t_State 		IS (Idle, Start, Transmit, Parity, Stop, Success);			--! Stavovy automat pro odesilani
	SIGNAL	State			:	t_State	  := Idle;

BEGIN

	-- delicka kmitoctu na pozadovany baud rate

	Frequency_divider: PROCESS (CLK)
		VARIABLE cnt : integer := 0;
	BEGIN
		IF (rising_edge(CLK)) THEN
			IF(RST = '1') THEN
				cnt := 0;
			ELSIF(cnt = sciCLK_cnt_max) THEN
				sciCLK <= NOT sciCLK;
				cnt := 0;
			ELSE
				cnt := cnt + 1;
			END IF;
		END IF;
	END PROCESS;

	-- synchronizace vstupu s nabeznou hranou hodinoveho signalu do hlavni casove domeny

	Synchronize: PROCESS (CLK)
	BEGIN
		IF (rising_edge(CLK)) THEN
			iSEND <= SEND;
			iSEND_prev <= iSEND;
			sciCLK_prev <= sciCLK;
		END IF;
	END PROCESS;	
	
	-- detekce nabezne hrany signalu SEND a sciCLK

	iSEND_redge <= iSEND AND NOT iSEND_prev;

	sciCLK_redge <= sciCLK AND NOT sciCLK_prev;

	-- parametry komunikace
	-- 1 start bit + 8 datovych bitu + 1 paritni bit + 1 stop bit

	iPAR <= iDIN(0) XOR iDIN(1) XOR iDIN(2) XOR iDIN(3) XOR iDIN(4) XOR iDIN(5) XOR iDIN(6) XOR iDIN(7);

	-- stavovy automat pro odesilani po SCI

	State_machine: PROCESS (CLK)
		VARIABLE sci_cnt : integer := 0;
	BEGIN
		IF rising_edge(CLK) THEN
			IF (RST = '1') THEN
				State <= Idle;
				TX <= '1';
				READY <= '0';
			ELSE
				CASE State IS

					-- cekani na nabeznou hranu signalu SEND
					WHEN Idle =>
						IF (iSEND_redge = '1') THEN
							iDIN <= DIN;
							READY <= '0';
							State <= Start;
						ELSE
							READY <= '1';
							TX <= '1';
						END IF;
					
					-- vysilani START bitu
					WHEN Start =>
						IF (sciCLK_redge = '1') THEN
							TX <= '0';
							State <= Transmit;
						END IF;
					
					-- vysilani datovych bitu
					WHEN Transmit =>
						IF (sciCLK_redge = '1') THEN
							TX <= iDIN(sci_cnt);
							IF(sci_cnt = 7) THEN
								sci_cnt := 0;
								State <= Parity;
							ELSE
								sci_cnt := sci_cnt + 1;
							END IF;
						END IF;
					
					-- vysilani paritniho bitu
					WHEN Parity =>
						IF (sciCLK_redge = '1') THEN
						
							-- generovani paritniho bitu (nefunkcni implementace)
							--FOR i IN iDIN'range loop
							--	iPar <= iPar XOR iDIN(i);
							--END LOOP;
							--TX <= iPar;

							-- generovani paritniho bitu
							TX <= iPAR;

							State <= Stop;
						END IF;
						
					-- vysilani stop bitu	
					WHEN Stop =>
						IF (sciCLK_redge = '1') THEN
							TX <= '1';
							State <= Success;
						END IF;

					-- pri nabezne hrane uz je komunikace spravne ukoncena	
					WHEN Success =>
						IF (sciCLK_redge = '1') THEN
							State <= Idle;
						END IF;	
				END CASE;
			END IF;
		END IF;
	END PROCESS;

END Behavioral;