--
-- Copyright CESR CNRS 
-- 	      9 avenue du Colonel Roche
-- 	      31028 Toulouse Cedex 4
--
-- Contributor(s) : 
--
--  - Bernard Bertrand 
--  
--
-- This software is a computer program whose purpose is to implement a spacewire 
-- link according to the ECSS-E-50-12A.
--
-- This software is governed by the CeCILL-C license under French law and
-- abiding by the rules of distribution of free software.  You can  use, 
-- modify and/ or redistribute the software under the terms of the CeCILL-C
-- license as circulated by CEA, CNRS and INRIA at the following URL
-- "http://www.cecill.info". 
--
-- As a counterpart to the access to the source code and  rights to copy,
-- modify and redistribute granted by the license, users are provided only
-- with a limited warranty  and the software's author,  the holder of the
-- economic rights,  and the successive licensors  have only  limited
-- liability. 
--
-- In this respect, the user's attention is drawn to the risks associated
-- with loading,  using,  modifying and/or developing or reproducing the
-- software by the user in light of its specific status of free software,
-- that may mean  that it is complicated to manipulate,  and  that  also
-- therefore means  that it is reserved for developers  and  experienced
-- professionals having in-depth computer knowledge. Users are therefore
-- encouraged to load and test the software's suitability as regards their
-- requirements in conditions enabling the security of their systems and/or 
-- data to be ensured and,  more generally, to use and operate it in the 
-- same conditions as regards security. 
--
-- The fact that you are presently reading this means that you have had
-- knowledge of the CeCILL-C license and that you accept its terms.
--

----------------------------------------------------------------------------------------
--	B.Bertrand
--	3/08/2009
--	all variable removed
--	shift register reduced
--	Component is reset by Reset_n signal.
--	Output error and got_X is enabled by signal_errorwait signal.
----------------------------------------------------------------------------------------

library IEEE;
use IEEE.std_logic_1164.all;
--use IEEE.numeric_std.all;
use ieee.std_logic_unsigned.all;
--use ieee.std_logic_arith.all;

LIBRARY altera_mf; 
USE altera_mf.altera_mf_components.all;  

use work.Spacewire_Pack.all;

entity Rx is
   port (

	Reset_n : in std_logic;
	Clk : in std_logic;
	Rx_Clk : inout std_logic;
	
	-- Main FSM interface

	State : in FSM_State;

	-- param
	
	wd_timeout : in std_logic_vector(15 downto 0);
	signal_errorwait : in std_logic;
	
	-- Got out
	
	got_NULL_n  : out std_logic;
	got_ESC_n  : out std_logic;
	got_FCT_n   : out std_logic;
	got_EOP_n	  : out std_logic;
	got_EEP_n   : out std_logic;	
	got_NChar_n : out std_logic;
	
	-- error
	
	Error_Par_n : out std_logic;	-- Parity error
	Error_ESC_n : out std_logic;	-- ESC followed by ESC, EOP or EEP
	Error_Dis_n : out std_logic;	-- Disconnected
	
	-- Rx Fifo interface

	Rx_FIFO_D : out std_logic_vector(8 downto 0);
	Rx_FIFO_Wr_n : out std_logic;

	-- Time Code interface

	got_Time_n  : out std_logic;
	
	-- Link

	Din : in std_logic;
	Sin : in std_logic
	

			
      );

end Rx;

architecture r1 of Rx is


type T_Rx_State is (Wait_First_bit, Wait_MSB, Ctrl, Normal);

signal Rx_State : T_Rx_State;
signal Rx_Data : std_logic_vector(7 downto 0);
signal Din_Late, Sin_Late : std_logic;
signal comput_parity: std_logic;
signal Rdata_un, Fdata_un, Rdata_deux, Fdata_deux : std_logic;
signal old_Din, old_Sin : std_logic;
signal Previous : std_logic_vector(2 downto 0);
signal cpt : integer range 0 to 8;

signal Rx_Clk_FF : std_logic;
signal Rx_Clk_FF_fiveteen, Rx_Clk_FF_fourteen, Rx_Clk_FF_theeteen	:  std_logic; 
signal Rx_Clk_FF_twelve, Rx_Clk_FF_eleven, Rx_Clk_FF_ten	:  std_logic;
signal Rx_Clk_FF_nine, Rx_Clk_FF_eight, Rx_Clk_FF_seven, Rx_Clk_FF_six :  std_logic; 
signal Rx_Clk_FF_five, Rx_Clk_FF_one, Rx_Clk_FF_two, Rx_Clk_FF_three :  std_logic;
signal Rx_Clk_FF_four, Rx_Clk_FF_thirteen, Rx_Clk_FF_sixteen	: std_logic;
signal Rx_Clk_FF_eighteen,Rx_Clk_FF_nineteen,Rx_Clk_FF_twenty, Rx_Clk_FF_twenty_one	: std_logic;

begin

-------------------------------------------------------------------------------------------------
-- Recover clock
-------------------------------------------------------------------------------------------------
Rx_Clk <= Din xor Sin;

-------------------------------------------------------------------------------------------------
-- Decode characters
-------------------------------------------------------------------------------------------------
Rising: process(State, Reset_n, Rx_Clk_FF_twenty_one)

begin

  if Reset_n = '0' --or State=ErrorReset
  then 
	
  
	-- Got out
	
	got_NULL_n <= '1';
	got_NChar_n <= '1';
	got_FCT_n <= '1';
	got_EOP_n <= '1';
	got_EEP_n <= '1';
	got_ESC_n <= '1';

	-- Time Code
	
	got_Time_n <= '1';
	
	-- error
	
	Error_ESC_n <= '1';
	Error_Par_n <= '1';

	
	-- variable
	
	Previous <= "000";--C_NCHAR;
	cpt <= 0;
	
	-- rx fifo
	
	Rx_FIFO_D <=  (others => '0');
	Rx_FIFO_Wr_n <= '1';
	
	-- signal 
		
	comput_parity <= '0';

	Rx_State <= Wait_First_Bit;
	Rx_Data  <= (others=>'0');

	RData_un <= '0';	


  else
    if Rx_Clk_FF_twenty_one = '1' and Rx_Clk_FF_twenty_one'event
    then
    
    --		sample bit rising edge
	
	Rx_Data <= Rx_Data(5 downto 0) & RData_un & Fdata_un;--------------------------modif effect
	Rx_Data(7 downto 2) <=  Rx_Data(5 downto 0);
			        
	got_FCT_n <= '1';
	got_EOP_n <= '1';
	got_EEP_n <= '1';
	got_ESC_n <= '1';
	
	got_NULL_n <= '1';
	got_Time_n <= '1';
	got_NChar_n <= '1';
	Rx_FIFO_Wr_n <= '1';

	RData_un <= Din;
	
	case Rx_State is

	when Wait_First_Bit =>
			if Rx_Data(1 downto 0) = "01"
			then Rx_State <= Ctrl;				
			end if;
			
	when Wait_MSB => 	-- Wait for first Ctrl char

			cpt <= 0;
			if Rx_Data(0)='1'	
			then 		-- ctrl incoming
			 	if Rx_Data(1) /= comput_parity then error_par_n <= '0';
			    else error_par_n <= '1';
 			    end if;
				Rx_State <= Ctrl;
			else 		-- data incoming
				if (Rx_Data(1) /= (not comput_parity))	then error_par_n <= '0'; 			    
				else error_par_n <= '1';				
 			    end if;
				Rx_State <= Normal;
				comput_parity <= '0';
			end if;

	when Ctrl =>	
			if Rx_Data(2 downto 0) = C_FCT
			then 
				if signal_errorwait = '1'
				then
				     if Previous = C_ESC					
				     then got_NULL_n <= '0';
				     else 
				     	got_FCT_n <= '0';
				     	Error_ESC_n <= '1';
				     end if;
				 end if;
				       			
			     comput_parity <= '0';--modify 
				 	     
			     Rx_State<=Wait_MSB;
			     Previous<=Rx_Data(2 downto 0);
			     --Rx_Data<=(others=>'0');

			elsif Rx_Data(2 downto 0) = C_EOP
			then 
				 if signal_errorwait = '1'
				 then 
				 got_EOP_n <= '0';
				     
				 Rx_FIFO_D <= "100000000";
	 			 Rx_FIFO_Wr_n <= '0';	
	
	
				     if (Previous = C_ESC or (Previous =  C_EOP and State /= run))
				     then Error_ESC_n <= '0';
				     else Error_ESC_n <= '1';
				     end if;
			     
			     end if;
			     
			     		     
			     comput_parity <= '1'; -- usually '1' 
			     			     
			     Rx_State <= Wait_MSB;
			     Previous <= Rx_Data(2 downto 0);
			     --Rx_Data <= (others=>'0');

			elsif Rx_Data(2 downto 0) = C_EEP
			then 
				 if signal_errorwait = '1'
				 then 
			     got_EEP_n <= '0';

			     	if Previous = C_ESC
			    	then Error_ESC_n <= '0';
			     	else Error_ESC_n <= '1';					
			     	end if;
			     end if;
			     
			     
			     comput_parity <= '1'; -- usually '1' 
			     			     
			     Rx_State <= Wait_MSB;
			     Previous <= Rx_Data(2 downto 0);
			     --Rx_Data <= (others=>'0');

			elsif Rx_Data(2 downto 0) = C_ESC
			then
				 if signal_errorwait = '1'
				 then 
			     got_ESC_n <= '0';
				
			     	if Previous = C_ESC
			    	then Error_ESC_n <= '0';					
			     	else Error_ESC_n <= '1';				
			     	end if;
			     end if;
				     
			     
			     comput_parity <= '0';
			     
			     Rx_State <= Wait_MSB;
			     Previous <= Rx_Data(2 downto 0);
			     --Rx_Data <= (others=>'0');
			end if; 
			
	when Normal =>
			cpt <= cpt+1;
			comput_parity <= comput_parity xor (Rx_Data(0) xor Rx_Data(1));
			if cpt = 3 
			then 
			    if signal_errorwait = '1'
				then 
				Rx_FIFO_D <= '0'&Rx_Data(0)&Rx_Data(1)&Rx_Data(2)&Rx_Data(3)&Rx_Data(4)&Rx_Data(5)&Rx_Data(6)&Rx_Data(7);
			  		if Previous = C_ESC
			  		then 
			  		got_Time_n <= '0';
			  		Previous <= "000";
			  		else 
			  		got_NChar_n <= '0';
			  		Rx_FIFO_Wr_n <= '0';
			  		end if;
			  	end if;
			  			  	
			Rx_State <= Wait_MSB;
			end if;
		
	when others =>
			Rx_State <= Wait_First_Bit;

	end case;

    end if;
  end if;
end process;


----------------------------------------------------------------------------
-- input on falling edge
----------------------------------------------------------------------------
FF_Fun : process(Reset_n, Rx_Clk_FF_twenty_one)
begin
  if Reset_n = '0' --or State = ErrorReset
  then 
  FData_un <= '0';
  else
    if Rx_Clk_FF_twenty_one = '0' and Rx_Clk_FF_twenty_one 'event
    then 
    FData_un <= Din;
    end if;
  end if;
end process;


-------------------------------------------------------------------------------------------------
-- Disconnection watch-dog
-------------------------------------------------------------------------------------------------

Disconnection_Detect: process(Reset_n, Clk)
variable WD_Cpt :  std_logic_vector(15 downto 0);
begin
  if Reset_n = '0' --or State=ErrorReset
  then 
	Error_Dis_n <= '1';
	WD_Cpt := (others => '0');
	Din_Late <= '0';
	Sin_Late <= '0';
	
  else
    if Clk='1' and Clk'event
    then 
	Din_Late<=old_Din;
	Sin_Late<=old_Sin;
		if Rx_State /= Wait_First_Bit
		then
			if WD_Cpt = wd_timeout
			then 	
			Error_Dis_n <= '0';
			else 	
			Error_Dis_n <= '1';
				if Din_Late/=old_Din or Sin_Late/=old_Sin
				then 
				WD_Cpt := (others => '0');
				else 
				WD_Cpt := WD_Cpt + 1;
				end if;
			end if;
		end if;
    end if;
  end if;
end process;

----------------------------------------------------------------------------
-- resynchro din on clk
----------------------------------------------------------------------------

process(Reset_n, Clk)
begin
if Reset_n = '0' --or State = ErrorReset
then 
old_Din <= '0';
else
    if Clk='1' and Clk'event
    then 
	old_Din <= Din;
	
    end if;
	
end if;
end process;

----------------------------------------------------------------------------
-- resynchro sin on clk
----------------------------------------------------------------------------

process(Reset_n, Clk)
begin
if Reset_n = '0' --or State = ErrorReset
then 
old_Sin <= '0';
else
    if Clk='1' and Clk'event
    then 
	old_Sin <= Sin;
    end if;	
end if;
end process;

l_cell_one : LCELL port map(
		a_in => Rx_Clk,
        a_out => Rx_Clk_FF_one
		); 

l_cell_two : LCELL port map(
		a_in => Rx_Clk_FF_one,
        a_out => Rx_Clk_FF_two
		); 
		
l_cell_three : LCELL port map(
		a_in => Rx_Clk_FF_two,
        a_out => Rx_Clk_FF_three
		); 		
		
l_cell_four : LCELL port map(
		a_in => Rx_Clk_FF_three,
        a_out => Rx_Clk_FF_four
		); 		

l_cell_five : LCELL port map(
		a_in => Rx_Clk_FF_four,
        a_out => Rx_Clk_FF_five
		); 

l_cell_six : LCELL port map(
		a_in => Rx_Clk_FF_five,
        a_out => Rx_Clk_FF_six
		); 
		
l_cell_seven : LCELL port map(
		a_in => Rx_Clk_FF_six,
        a_out => Rx_Clk_FF_seven
		); 		
		
l_cell_eight : LCELL port map(
		a_in => Rx_Clk_FF_seven,
        a_out => Rx_Clk_FF_eight
		); 	
		
l_cell_nine : LCELL port map(
		a_in => Rx_Clk_FF_eight,
        a_out => Rx_Clk_FF_nine
		); 		
		
l_cell_ten : LCELL port map(
		a_in => Rx_Clk_FF_nine,
        a_out => Rx_Clk_FF_ten
		); 		
		
l_cell_eleven : LCELL port map(
		a_in => Rx_Clk_FF_ten,
        a_out => Rx_Clk_FF_eleven
		); 		
		
l_cell_twelve : LCELL port map(
		a_in => Rx_Clk_FF_eleven,
        a_out => Rx_Clk_FF_twelve
		); 	
		
l_cell_thirteen : LCELL port map(
		a_in => Rx_Clk_FF_twelve,
        a_out => Rx_Clk_FF_thirteen
		); 		
		
l_cell_fourteen : LCELL port map(
		a_in => Rx_Clk_FF_thirteen,
        a_out => Rx_Clk_FF_fourteen
		); 				
		
l_cell_fiveteen : LCELL port map(
		a_in => Rx_Clk_FF_fourteen,
        a_out => Rx_Clk_FF_fiveteen
		); 

l_cell_sixteen : LCELL port map(
		a_in => Rx_Clk_FF_fiveteen,
        a_out => Rx_Clk_FF_sixteen
		); 

l_cell_seventeen : LCELL port map(
		a_in => Rx_Clk_FF_sixteen,
        a_out => Rx_Clk_FF_eighteen
		); 

l_cell_eighteen : LCELL port map(
		a_in => Rx_Clk_FF_eighteen,
        a_out => Rx_Clk_FF_nineteen
		); 

l_cell_nineteen : LCELL port map(
		a_in => Rx_Clk_FF_nineteen,
        a_out => Rx_Clk_FF_twenty
		); 		

l_cell_twenty : LCELL port map(
		a_in => Rx_Clk_FF_twenty,
        a_out => Rx_Clk_FF_twenty_one
		); 				

end r1;