-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- =============================================================================
-- Authors:        Thomas B. Preusser
--
-- Entity:				 Universal Asynchronous Receiver Transmitter (UART) - Receiver
--
-- Description:
-- 
-- :abbr:`UART (Universal Asynchronous Receiver Transmitter)` Receiver:
-- 1 Start + 8 Data + 1 Stop
--
-- License:
-- =============================================================================
-- Copyright 2008-2016 Technische Universitaet Dresden - Germany
--                     Chair of VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--              http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- =============================================================================

library	IEEE;
use			IEEE.std_logic_1164.all;
use			IEEE.numeric_std.all;

library	PoC;


entity [docs]uart_rx is
  generic (
    SYNC_DEPTH : natural := 2  -- use zero for already clock-synchronous rx
	);
  port (
    -- Global Control
    clk : in std_logic;
    rst : in std_logic;

    -- Bit Clock and RX Line
    bclk_x8 : in std_logic;  	-- bit clock, eight strobes per bit length
    rx      : in std_logic;

    -- Byte Stream Output
    do  : out std_logic_vector(7 downto 0);
    stb : out std_logic
  );
end entity;


architecture [docs]rtl of uart_rx is
  -- RX Synchronization
  signal rxs : std_logic;

  --                Buf        Cnt  Vld
  --   Idle     "---------0"    X    0
  --   Start    "0111111111"  5->16  0   -- 1.5 bit length after start of start bit
  --   Recv     "dcba011111"  9->16  0   -- shifting left to right (LSB first)
  --   Done     "1hgfedcba0"    X    1   -- Output strobe

	-- Data buffer
  signal Buf : std_logic_vector(9 downto 0) := (0      => '0', others => '-');
	-- Bit clock counter: 8 ticks per bit
  signal Cnt : unsigned(4 downto 0)         := (others => '-');
	-- Output strobe
  signal Vld : std_logic                    := '0';

begin
  -- Input synchronization
	sync :  entity PoC.sync_Bits
		generic map (
			INIT					=> (SYNC_DEPTH - 1 downto 0 => '1'),	-- initialitation bits
			SYNC_DEPTH		=> SYNC_DEPTH													-- generate SYNC_DEPTH many stages, at least 2
		)
		port map (
			Clock					=> clk,		-- <Clock>	output clock domain
			Input(0)			=> rx,		-- @async:	input bits
			Output(0)			=> rxs		-- @Clock:	output bits
		);

  -- Reception state
  process(clk)
  begin
    if rising_edge(clk) then
			Vld <= '0';
      if rst = '1' then
        Buf <= (0      => '0', others => '-');
        Cnt <= (others => '-');
      else
				if Buf(0) = '0' then
					-- Idle
					if rxs = '0' then
						-- Start bit -> receive byte
						Buf <= (Buf'left => '0', others => '1');
						Cnt <= to_unsigned(5, Cnt'length);
					else
						Buf <= (0 => '0', others => '-');
						Cnt <= (others => '-');
					end if;
				elsif bclk_x8 = '1' then
					if Cnt(Cnt'left) = '1' then
						Buf <= rxs & Buf(Buf'left downto 1);
						Vld <= rxs and not Buf(1);
					end if;
					Cnt <= Cnt + (Cnt(4) & Cnt(4) & "001");
				end if;
      end if;
    end if;
  end process;

  -- Outputs
  do  <= Buf(8 downto 1);
  stb <= Vld;

end architecture;