-- UART Receiver
--
-- Version : 1.00 
-- Version Date : 15 December 2016
--
------------------------------------------------------------------------------------
--
-- Library declarations
--
-- The Unisim Library is used to define Xilinx primitives. It is also used during
-- simulation. The source can be viewed at %XILINX%\vhdl\src\unisims\unisim_VCOMP.vhd
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
--
------------------------------------------------------------------------------------
--
-- Main Entity
--
entity juart_rx is
	Port
	(
		rst				: in std_logic;
		clk				: in std_logic;
		ser_in			: in std_logic;  
		dout			: out unsigned(7 downto 0);
		dout_vld		: out std_logic;
		en_16_x_baud	: in std_logic
	);
end juart_rx;
--
------------------------------------------------------------------------------------
--
-- Start of Main Architecture
--	 
architecture behavior of juart_rx is
--
------------------------------------------------------------------------------------
--
------------------------------------------------------------------------------------
--
-- Signals used
--
------------------------------------------------------------------------------------
--
constant OVERSAMPLING : natural := 16;

subtype bit_count_t is natural range 0 to OVERSAMPLING-1;

signal bit_count_rst	    : std_logic;
signal bit_count			: bit_count_t;
signal data_valid		    : std_logic;
signal shiftreg_en		    : std_logic;
signal shiftreg				: unsigned (7 downto 0);
signal sample_count_rst		: std_logic;
signal sample_count			: natural range 0 to OVERSAMPLING-1;
signal bit_sample		    : std_logic;

type state_t is	(idle, wait_start, start, shift, stop);

signal state		: state_t;
signal state_next	: state_t;
--
--	
begin

data_out_reg:
process(clk)
begin
	if rising_edge(clk) then
		dout_vld	<= '0';
		if data_valid = '1' then
			dout 		<= shiftreg;
			dout_vld	<= '1';
		end if;
	end if;
end process;

proc_state_next:
process(clk)
begin
	if rising_edge(clk) then
		if rst = '1' then
			state	<= idle;
		else
			state	<= state_next;
		end if;
	end if;
end process;

statemachine:
process(state, bit_count, bit_sample, ser_in)
begin
	state_next	<= state;
	sample_count_rst	<= '0';
	bit_count_rst		<= '0';
	shiftreg_en			<= '0';
	data_valid			<= '0';
	
	case state is
	when idle =>
		if ser_in = '1' then
			state_next	<= wait_start;
		end if;
	when wait_start =>
		sample_count_rst	<= '1';
		if ser_in = '0' then
			state_next	<= start;
		end if;
	when start =>
		bit_count_rst		<= '1';
		if bit_sample = '1' then
			state_next	<= shift;
		end if;
	when shift =>
		shiftreg_en			<= '1';
		if bit_count = 8 then
			state_next	<= stop;
		end if;
	when stop =>
		if bit_sample = '1' then
			state_next	<= idle;
			data_valid	<= '1';
		end if;
		
	when others =>
		state_next	<= idle;
	end case;
end process;

shift_register:
process(clk)
begin
	if rising_edge(clk) then
		if rst = '1' then
			shiftreg	<= (others => '0');
		elsif shiftreg_en = '1' and bit_sample = '1' then
			shiftreg <= ser_in & shiftreg(shiftreg'left downto 1);
		end if;
	end if;
end process;

sample_counter:
process(clk)
begin
	if rising_edge(clk) then
		bit_sample	<= '0';
		if sample_count_rst = '1' then
			sample_count <= 0;
		elsif en_16_x_baud = '1' then
			if sample_count /= OVERSAMPLING-1 then
				sample_count	<= sample_count + 1;
			else
				sample_count <= 0;
			end if;
			if sample_count = OVERSAMPLING/2-1 then
				bit_sample	<= '1';
			end if;	
		end if;
	end if;
end process;

bit_counter:
process(clk)
begin
	if rising_edge(clk) then
		if bit_count_rst = '1' then
			bit_count <= 0;
		elsif bit_count /= bit_count_t'high and bit_sample = '1' then
			bit_count <= bit_count + 1;
		end if;
	end if;
end process;

end behavior;

------------------------------------------------------------------------------------
--
-- END OF FILE
--
------------------------------------------------------------------------------------


