--=====================================================
-- Проект 17. Приёмник UART
-- Ловит старт-бит, выбирает каждый бит в середине
-- интервала и выдаёт готовый байт с признаком valid.
--=====================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity uart_rx is
    generic (
        CLK_DIV : integer := 5208                       -- 50 МГц / 9600 бод
    );
    port (
        clk     : in  std_logic;
        rst     : in  std_logic;
        rx      : in  std_logic;                        -- линия приёма
        data    : out std_logic_vector(7 downto 0);
        valid   : out std_logic                         -- байт принят
    );
end entity uart_rx;

architecture rtl of uart_rx is
    type state_t is (IDLE, START_BIT, DATA_BITS, STOP_BIT);
    signal state   : state_t := IDLE;
    signal sync    : std_logic_vector(1 downto 0) := "11";
    signal baud    : integer range 0 to CLK_DIV := 0;
    signal bit_idx : integer range 0 to 7 := 0;
    signal shreg   : std_logic_vector(7 downto 0) := (others => '0');
begin
    process (clk, rst)
    begin
        if rst = '1' then
            state <= IDLE;
            valid <= '0';
            sync  <= "11";
        elsif rising_edge(clk) then
            sync  <= sync(0) & rx;                      -- синхронизация входа
            valid <= '0';                               -- признак живёт один такт

            case state is
                when IDLE =>
                    if sync(1) = '0' then               -- обнаружен старт-бит
                        baud  <= 0;
                        state <= START_BIT;
                    end if;

                when START_BIT =>
                    if baud = CLK_DIV/2 - 1 then        -- смещаемся в середину бита
                        if sync(1) = '0' then
                            baud    <= 0;
                            bit_idx <= 0;
                            state   <= DATA_BITS;
                        else
                            state <= IDLE;              -- ложное срабатывание
                        end if;
                    else
                        baud <= baud + 1;
                    end if;

                when DATA_BITS =>
                    if baud = CLK_DIV - 1 then
                        baud         <= 0;
                        shreg(bit_idx) <= sync(1);      -- выборка в середине бита
                        if bit_idx = 7 then
                            state <= STOP_BIT;
                        else
                            bit_idx <= bit_idx + 1;
                        end if;
                    else
                        baud <= baud + 1;
                    end if;

                when STOP_BIT =>
                    if baud = CLK_DIV - 1 then
                        baud  <= 0;
                        state <= IDLE;
                        if sync(1) = '1' then           -- стоп-бит корректен
                            data  <= shreg;
                            valid <= '1';
                        end if;
                    else
                        baud <= baud + 1;
                    end if;
            end case;
        end if;
    end process;
end architecture rtl;
