library ieee;
use ieee.std_logic_1164.all;

library UNISIM;
use UNISIM.vcomponents.all;

library utilities;

entity processing_block is
  port (
  
		-- clock:
		clk_iserdes_in     : in std_logic;
		clk_iserdes_in_div : in std_logic;
		clk_global 				 : in std_logic;
		
		-- reset:
		rst : in std_logic;
		
		-- bitslip:
		bitslip            : in std_logic;
		bitslip_done       : in std_logic; -- todo: use this
		bitslip_drop_byte  : in std_logic;
		
		-- input signal:
		in_data_p : in std_logic;
		in_data_n : in std_logic;
		in_data_swap_pn : in std_logic;
		
		-- input switch for counter output:
		in_output_counting : in std_logic;
		
		-- output after iserdes and pack16 for bitslip:
		o_iserdes_output : out std_logic_vector( 15 downto 0 );
		o_iserdes_output_valid : out std_logic;
		
		-- output fwft FIFO:
		o_data  : out std_logic_vector( 31 downto 0 );
		o_valid : out std_logic;
		i_rden  : in std_logic
	);		
		
end processing_block;

architecture behavioral of processing_block is
	
	component swap_endianness
  port (
		i_data : in std_logic_vector;
		o_data : out std_logic_vector
	);
	end component;

	component fifo_32x512_dualclk_fwft
	  port (
	    rst : in std_logic;
	    wr_clk : in std_logic;
	    rd_clk : in std_logic;
	    din : in std_logic_vector(31 downto 0);
	    wr_en : in std_logic;
	    rd_en : in std_logic;
	    dout : out std_logic_vector(31 downto 0);
	    full : out std_logic;
	    empty : out std_logic;
	    valid : out std_logic
	  );
	end component;

	component myserdes_ddr_wrapper
	generic
		( sys_w       : integer := 1;
			dev_w       : integer := 8);
	port (
		-- CLOCK:
		clk_in : in std_logic;
		clk_in_div : in std_logic;		
		-- PADS IN:
		data_in_from_pins_p : in std_logic;
		data_in_from_pins_n : in std_logic;
		-- DATA OUT:
		data_in_to_device : out std_logic_vector( dev_w - 1 downto 0 );
		
		bitslip : in std_logic;				
		rst_in : in std_logic );
	end component;
	
	component saw_generator_wrapper
	generic (
		G_INCREASE_EVERY_NTH : positive := 4
	);
  port (
  
		i_clk : in std_logic;
		i_rst : in std_logic;
		
		o_valid : out std_logic;
		o_data  : out std_logic_vector
		
	);		
	end component;
		
	-- Frame signal
	signal s_in_frame_for_data : std_logic_vector( 7 downto 0 );
	signal s_in_frame_for_data_precorrect : std_logic_vector( 7 downto 0 );
	
	signal s_in_frame_for_data_packed16 : std_logic_vector( 15 downto 0 );
	signal s_in_frame_for_data_packed16_le : std_logic_vector( 15 downto 0 );
	signal s_in_frame_for_data_packed16_swapped : std_logic_vector( 15 downto 0 );
	signal s_in_frame_for_data_packed16_valid : std_logic;
	signal s_in_frame_for_data_packed16_valid_wbitslip_done : std_logic;
	signal s_in_frame_for_data_packed32 : std_logic_vector( 31 downto 0 );
	signal s_in_frame_for_data_packed32_valid : std_logic;
	
	signal s_rst_n : std_logic;
	
	-- counter:
	signal s_counter_valid : std_logic;
	signal s_counter_data  : std_logic_vector( 31 downto 0 );
	
	-- selection signals for the final FIFO:
	signal s_selected_source_valid : std_logic;
	signal s_selected_source_data  : std_logic_vector( 31 downto 0 );
	
	-- byte drop request
	signal s_bitslip_drop_byte_n : std_logic;
		
begin
	
	s_rst_n <= not rst;
	s_bitslip_drop_byte_n <= not bitslip_drop_byte;
	
	-- iserdes wrapper:
	myserdes_ddr_wrapper_inst : myserdes_ddr_wrapper
	port map (
		clk_in => clk_iserdes_in, clk_in_div => clk_iserdes_in_div,
		data_in_from_pins_p => in_data_p, data_in_from_pins_n => in_data_n, data_in_to_device => s_in_frame_for_data_precorrect,
		bitslip => bitslip, rst_in => rst );
		
	-- correct hardware swapping of P&N wires:
	s_in_frame_for_data <= s_in_frame_for_data_precorrect when in_data_swap_pn = '0' else
												 not s_in_frame_for_data_precorrect;
	
	-- glue two parts to 16-bit full data:
	glue_data_inst : entity work.glue_data
	port map (
		i_clk => clk_iserdes_in_div, i_reset_n => s_rst_n,
		i_data => s_in_frame_for_data, i_valid => s_bitslip_drop_byte_n, o_enable => open,
		o_data => s_in_frame_for_data_packed16, o_valid => s_in_frame_for_data_packed16_valid, i_enable => '1' );
	
	-- output the 16-bit to manage bitslip:	
	o_iserdes_output       <= s_in_frame_for_data_packed16;
	o_iserdes_output_valid <= s_in_frame_for_data_packed16_valid;
	
	-- these data go further after bitslip has been set:
  s_in_frame_for_data_packed16_le <= s_in_frame_for_data_packed16;	
	s_in_frame_for_data_packed16_valid_wbitslip_done <= bitslip_done and s_in_frame_for_data_packed16_valid;
	
	-- insert the pack block to 32 bits:
	pack_data32_inst : entity utilities.pack_data
	generic map (
		G_OUTPUT_WIDTH => 32 )
	port map (
		i_clk => clk_iserdes_in_div, i_reset_n => s_rst_n,
		i_data => s_in_frame_for_data_packed16_le, i_valid => s_in_frame_for_data_packed16_valid_wbitslip_done, o_enable => open,
		o_data => s_in_frame_for_data_packed32, o_valid => s_in_frame_for_data_packed32_valid, i_enable => '1' );
	
	-- counter:
	counter_inst : saw_generator_wrapper
		generic map( G_INCREASE_EVERY_NTH => 4 )
		port map(
			i_clk => clk_iserdes_in_div, i_rst => rst, o_valid => s_counter_valid, o_data => s_counter_data );
	
	-- output either the grabbed data or the counter, based on request:
	s_selected_source_valid <= s_counter_valid when in_output_counting = '1' else s_in_frame_for_data_packed32_valid;
	s_selected_source_data  <= s_counter_data  when in_output_counting = '1' else s_in_frame_for_data_packed32;
	
	-- insert the cross-domain FIFO:
	cross_domain_fifo_inst : fifo_32x512_dualclk_fwft
	port map (
		rst => rst, wr_clk => clk_iserdes_in_div, rd_clk => clk_global,
		din => s_selected_source_data, wr_en => s_selected_source_valid, full => open,
		dout => o_data, valid => o_valid, rd_en => i_rden, empty => open );
		
end architecture;

