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;