-----------------------------------------------------------------------
-- UART Rx module
--  Parity not supported, single stop bit operation.
-----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-----------------------------------------------------------------------
ENTITY UART_Basic_Rx IS
    GENERIC( period:   INTEGER := 5208);
    PORT( Clk:            IN  STD_LOGIC;                            -- system clock
          Rx:             IN  STD_LOGIC;                            -- UART serial input
          Data:           OUT STD_LOGIC_VECTOR(7 DOWNTO 0):= X"00"; -- received data
          Data_Ready:     OUT STD_LOGIC:= '0');                     -- new data received (check for rising edge;
                                                                    -- pulse duration is equal to clk period)
END UART_Basic_Rx;
-----------------------------------------------------------------------
ARCHITECTURE Behavioral OF UART_Basic_Rx IS

  TYPE Rx_state IS (idle, startb, bit0, bit1, bit2, bit3, bit4, bit5, bit6, bit7, stopb);

  SIGNAL current_state:     Rx_state := idle;               -- control of transmission
--SIGNAL next_state:        Rx_state := idle;               -- default idle state
  SIGNAL data_int:          STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '0');    -- internal data buffer
  SIGNAL prev_Rx:           STD_LOGIC := '1';
  SIGNAL busy:              STD_LOGIC := '0';

  SIGNAL clk_EN:            STD_LOGIC := '0';               -- clock enable (frequency = baud rate)
  SIGNAL clk_gen:           STD_LOGIC_VECTOR(20 DOWNTO 1) := (OTHERS => '0');
  SIGNAL per_bin:           STD_LOGIC_VECTOR(20 DOWNTO 1) := (OTHERS => '0');   -- one more bit for sign

  SIGNAL Rx_in_shr:         STD_LOGIC_VECTOR(3 DOWNTO 0) := (OTHERS => '1');   -- shift register for metastability removal
-----------------------------------------------------------------------
BEGIN
-----------------------------------------------------------------------
-- generate clock enable signal with frequency eaquel to baud rate
  per_bin <= CONV_STD_LOGIC_VECTOR(period, 20);
  ---------------------------------------------------------------------
--  clk_gen_proc: PROCESS(clk) BEGIN
--    IF clk'EVENT AND clk = '1' THEN
--      IF busy = '0' THEN        -- reset to half of the period
--        clk_gen <= '0' & per_bin(20 DOWNTO 2);
--      ELSE
--        IF clk_gen = per_bin(20 DOWNTO 1) THEN
--          clk_gen(20 DOWNTO 2) <= (OTHERS => '0');
--          clk_gen(1) <= '1';
--          clk_EN <='1';
--        ELSE
--          clk_EN <='0';
--          clk_gen <= clk_gen + 1;
--        END IF;
--      END IF;
--    END IF;
--  END PROCESS clk_gen_proc;

  clk_gen_proc: PROCESS(clk) BEGIN
    IF clk'EVENT AND clk = '1' THEN
      IF busy = '0' THEN
        clk_gen <= X"00002";
      ELSE
        IF clk_gen = per_bin(20 DOWNTO 1) THEN
          clk_gen(20 DOWNTO 2) <= (OTHERS => '0');
          clk_gen(1) <= '1';
          clk_EN <='0';
        ELSIF clk_gen = ('0' & per_bin(20 DOWNTO 2)) THEN   -- half of the bit period
          clk_EN <='1';
          clk_gen <= clk_gen + 1;
        ELSE
          clk_EN <='0';
          clk_gen <= clk_gen + 1;
        END IF;
      END IF;
    END IF;
  END PROCESS clk_gen_proc;

-----------------------------------------------------------------------
-- data receive process
  receive_proc: PROCESS(clk) BEGIN
    IF clk'event AND clk = '1' THEN
      Rx_in_shr <= Rx_in_shr(2 DOWNTO 0) & Rx;
      prev_Rx <= Rx_in_shr(3);                  -- sampling input for edge detection

      IF busy = '0' THEN
        IF Rx_in_shr(3) = '0' AND prev_Rx = '1' THEN    -- start bit detected
          busy <= '1';
          Data_Ready <= '0';
          current_state <= startb;
        ELSE
          Data_Ready <= '0';
        END IF;

      ELSIF clk_EN = '1' THEN                   -- IF busy = '1'
        -- current_state <= next_state;         -- increment state counter (go to next bit)
        CASE (current_state) IS
          WHEN startb => busy <= '1';           -- start bit (no operation)
                         current_state <= bit0;
          WHEN bit0   => data_int(0) <= Rx_in_shr(3);   -- bit 0 (LSB)
                         current_state <= bit1;
          WHEN bit1   => data_int(1) <= Rx_in_shr(3);   -- bit 1
                         current_state <= bit2;
          WHEN bit2   => data_int(2) <= Rx_in_shr(3);   -- bit 2
                         current_state <= bit3;
          WHEN bit3   => data_int(3) <= Rx_in_shr(3);   -- bit 3
                         current_state <= bit4;
          WHEN bit4   => data_int(4) <= Rx_in_shr(3);   -- bit 4
                         current_state <= bit5;
          WHEN bit5   => data_int(5) <= Rx_in_shr(3);   -- bit 5
                         current_state <= bit6;
          WHEN bit6   => data_int(6) <= Rx_in_shr(3);   -- bit 6
                         current_state <= bit7;
          WHEN bit7   => data_int(7) <= Rx_in_shr(3);   -- bit 7
                         current_state <= stopb;
          WHEN stopb  => Data_Ready  <= Rx_in_shr(3);   -- "Data_Ready" = '1' when correct stop-bit is detected
                         busy <= '0';
                         current_state <= idle;
                         Data <= data_int;
          WHEN idle   => busy <= '0';           -- idle state (no operation)
                         current_state <= idle;
                         Data_Ready <= '0';
          WHEN OTHERS => busy <= '0';           -- other states (shold not happen)
                         current_state <= idle;
                         Data_Ready <= '0';
        END CASE;
        ---------------------------------------------------------------
      ELSE
        Data_Ready <= '0';
      END IF;
    -------------------------------------------------------------------
    END IF;
  END PROCESS receive_proc;

-----------------------------------------------------------------------

--  state_mach: PROCESS(current_state, Rx_in_shr(3)) BEGIN
--        CASE (current_state) IS
--          WHEN startb => next_state <= bit0;
--          WHEN bit0   => next_state <= bit1;
--          WHEN bit1   => next_state <= bit2;
--          WHEN bit2   => next_state <= bit3;
--          WHEN bit3   => next_state <= bit4;
--          WHEN bit4   => next_state <= bit5;
--          WHEN bit5   => next_state <= bit6;
--          WHEN bit6   => next_state <= bit7;
--          WHEN bit7   => next_state <= stopb;
--          WHEN stopb  => IF Rx_in_shr(3) =  '0' THEN next_state <= startb;
--                                                ELSE next_state <= idle; END IF;
--          WHEN OTHERS => next_state <= idle;
--        END CASE;
--  END PROCESS state_mach;

-----------------------------------------------------------------------
-----------------------------------------------------------------------

END Behavioral;
