-- Company: BUSE
-- Engineer: PAVEL SUNKA
-- 
-- Create Date:   1.6.2017
-- Module Name:   UART 
-- Project Name:  RGB_PANEL
-- Target Devices: 10M08
-----------------------------         ----------------------------
-- UART komunikator nevhodny pro odesilani dat soubezne ( pri zapooceti noveho retezce dat se změni CLK_enable)
-----------------------------         ----------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use IEEE.std_logic_signed.all;

entity Uart is
	Generic(UART_DIV   : natural := (40000000 / 9600);
	        UART_CNT_B : natural := 12
	       );
	Port(
		CLK      : in  std_logic;
		ARST     : in  std_logic;
		RX       : in  std_logic;
		EN_WR    : in  std_logic;
		DAT_WR   : in  std_logic_vector(7 downto 0);
		END_WR   : out std_logic;
		BYT_END  : out std_logic;
		TX       : out std_logic;
		DAT_READ : out std_logic_vector(7 downto 0));

end entity Uart;

architecture RTL of Uart is
	type stat is (s0, sRst, sData, sPulse, sSync);
	signal state : stat := s0;

	signal out_dat : std_logic_vector(9 downto 0) := (others => '1');

	signal q      : std_logic_vector(8 downto 0);
	signal re_en  : std_logic;
	signal wre_en : std_logic;

	signal rst_reg_i : std_logic;
	signal cnt_wre   : unsigned(UART_CNT_B downto 0) := (others => '0');

	signal cnt         : unsigned(UART_CNT_B downto 0) := (others => '0');
	signal start_b_mem : std_logic;
	signal UART_DIV_u  : unsigned(UART_CNT_B downto 0);

	signal end_wr_cnt : std_logic_vector(3 downto 0);
begin
	-- posuvny zachytny registr cteni--
	process(CLK, ARST, rst_reg_i) is
	begin
		if ARST = '1' or rst_reg_i = '1' then -- v pripade konce bitove komunikace
			q <= (others => '1');
		elsif rising_edge(CLK) then
			if re_en = '1' then
				q <= RX & q(8 downto 1);
			end if;
		end if;
	end process;

	DAT_READ <= q(8 downto 1);

	-- stavovy automan pro prijem
	process(CLK, ARST) is
	begin
		if ARST = '1' then
			state <= s0;
		elsif rising_edge(CLK) then
			case state is
				when s0 =>
					if RX = '0' then
						state <= sRst;
					end if;
				when sRst =>
					state <= sData;
				when sData =>
					if q(0) = '0' then
						state <= sPulse;
					end if;
				when sPulse =>
					state <= sSync;
				when sSync =>
					if q(8) = '1' then
						state <= s0;
					end if;

				when others =>
					state <= s0;
			end case;
		end if;
	end process;

	process(state) is
	begin
		BYT_END   <= '0';
		rst_reg_i <= '0';

		case state is
			when s0 =>
				null;
			when sRst =>
				rst_reg_i <= '1';
			when sData =>
				null;
			when sPulse =>
				BYT_END <= '1';
			when sSync =>
				null;
			when others =>
				null;
		end case;
	end process;

	UART_DIV_u <= to_unsigned(UART_DIV, UART_CNT_B + 1);

	-- uart hodiny/ enable signal--
	process(CLK) is
	begin
		if rising_edge(CLK) then
			re_en <= '0';
			if rst_reg_i = '1' then
				cnt <= (UART_DIV_u / 2) - 1; -- nastavi na polovinu counteru

			elsif cnt = UART_DIV_u then
				cnt   <= (others => '0');
				re_en <= '1';

			else
				cnt <= cnt + 1;
			end if;
		end if;
	end process;
	---------------------------------------------------------------------------------------------odesilani--------------------
	-- uart hodiny/ enable signal--
	process(CLK) is
	begin
		if rising_edge(CLK) then
			wre_en <= '0';
			if cnt_wre = UART_DIV_u then
				cnt_wre <= (others => '0');
				wre_en  <= '1';
			else
				cnt_wre <= cnt_wre + 1;
			end if;
		end if;
	end process;

	-- odesilani dat do mastru
	process(CLK) is
	begin
		if rising_edge(CLK) then
			if EN_WR = '1' then
				out_dat <= DAT_WR(7 downto 0) & "01"; -- v pripade enablu se nastavi posuvny registr

			elsif wre_en = '1' then
				out_dat <= '1' & out_dat(9 downto 1);
			end if;
		end if;
	end process;

	-- citac odeslanych bitu
	process(CLK, ARST) is
	begin
		if ARST = '1' then
			end_wr_cnt <= (others => '0');
		elsif rising_edge(CLK) then
			if EN_WR = '1' then
				end_wr_cnt <= (others => '0');
			elsif wre_en = '1' then
				end_wr_cnt <= end_wr_cnt + '1';
			end if;
		end if;
	end process;

	END_WR <= '1' when end_wr_cnt = "1011" else '0';
	TX     <= out_dat(0);
end architecture RTL;
