    ------------------------------------------------------------------------
    -- fft
    --
    -- calculation of FFT magnitude
    --
    -- Inputs:
    -- 32-Bit Floating Point number in range +-16 expected (loaded from FIFO)
    --
    -- Outputs
    -- 32-Bit Floating Point number in range +-16 calculated (stored in FIFO)
    --
    -----------------------------------------------------------------------
    library ieee;
        use ieee.std_logic_1164.all;
        use ieee.numeric_std.all;

    library work;
        use work.reg32.all;
        use work.task.all;
    	 use work.float.all;

    entity fft is
      generic (

        -- input data width of real/img part
          input_data_width : integer := 32;

        -- output data width of real/img part
          output_data_width : integer := 32

        );
        port (
            clk : in std_logic;
            reset : in std_logic;

            task_start : in std_logic;
            task_state : out work.task.State;

            signal_read : out std_logic;
            signal_readdata : in std_logic_vector( 31 downto 0 );

            signal_write : out std_logic;
            signal_writedata : out std_logic_vector( 31 downto 0 )
        );
    end entity fft;

    architecture rtl of fft is

	function mag_scale(pre_scale : std_logic_vector(31 downto 0))
	return  std_logic_vector
	is 
		variable value_data_out_mag_float : std_logic_vector(31 downto 0);
		variable value_data_out_mag_float_scaled : std_logic_vector(31 downto 0);
	begin

		value_data_out_mag_float := to_float(pre_scale);	

		value_data_out_mag_float_scaled(31) := value_data_out_mag_float(31);
		value_data_out_mag_float_scaled(22 downto 0) := std_logic_vector(signed(value_data_out_mag_float(22 downto 0)));
		if value_data_out_mag_float(30 downto 23) = "00000000" then
		    	value_data_out_mag_float_scaled(30 downto 23) := std_logic_vector(signed(value_data_out_mag_float(30 downto 23)) + 4);
		else
			value_data_out_mag_float_scaled(30 downto 23) := std_logic_vector(signed(value_data_out_mag_float(30 downto 23)) + 5);
		end if;
		return value_data_out_mag_float_scaled;

	end function;

        signal current_task_state : work.task.State;
        signal next_task_state : work.task.State;
        signal index : integer range 0 to work.task.STREAM_LEN;

	type fft_state_dec is (
		FFT_STATE_IDLE,
		FFT_STATE_READ,
		FFT_STATE_FILL_IP_CORE,
		FFT_STATE_GET_IP_CORE,
		FFT_STATE_SORT,
		FFT_STATE_WRITE,
		FFT_STATE_DONE
	); 

	component FFTMAIN
	port (
   		clock : in std_logic;
    		reset : in std_logic;
    		di_en : in std_logic;
		di_re : in std_logic_vector(31 downto 0);
		di_im : in std_logic_vector(31 downto 0);
		do_en : out std_logic;
		do_re : out std_logic_vector(31 downto 0);
		do_im : out std_logic_vector(31 downto 0)
	);
	end component;

	component fft_magnitude_calc
	port (
		clk : in std_logic;
		reset : in std_logic;
			  
		input_valid: in std_logic;		  
		input_re : in std_logic_vector( 31 downto 0 ); -- in Fixpoint
		input_im : in std_logic_vector( 31 downto 0 ); -- in Fixpoint
			  
		output_valid : out std_logic;
		output_magnitude : out std_logic_vector( 31 downto 0 )
	);
	end component fft_magnitude_calc;

	-- Eigene Steuersignale.
	signal value_data_in_ready : std_logic;
	signal value_data_in_real : std_logic_vector(31 downto 0);
	--signal value_data_in_real_scaled : std_logic_vector(31 downto 0);
	signal value_data_in_real_scaled_fixed : std_logic_vector(31 downto 0);
	--signal value_data_in_real_temp : std_logic_vector(31 downto 0);
	signal value_data_in_imag : std_logic_vector(31 downto 0);
	signal value_data_out_ready : std_logic;
	signal value_data_out_real : std_logic_vector(31 downto 0);
	signal value_data_out_imag : std_logic_vector(31 downto 0);
	signal value_data_out_mag : std_logic_vector(31 downto 0);
	signal value_data_out_mag_float : std_logic_vector(31 downto 0);
	signal value_data_out_mag_float_scaled : std_logic_vector(31 downto 0);

	type memory_array is array (0 to work.task.STREAM_LEN) of std_logic_vector(31 downto 0);
	signal memory : memory_array := (others => (others => '0'));
	signal sorted_memory : memory_array := (others => (others => '0'));
	signal bitsort_index : integer range 0 to work.task.STREAM_LEN;

	--signal a_vec : std_logic_vector(9 downto 0);  -- Vector for 1024 range
    	--signal b_vec : std_logic_vector(9 downto 0);  -- Reversed vector

    	--signal b : integer range 0 to 1023;         -- Reversed integer output
	signal read_wait : integer range 0 to (2048);

	signal value_mag_in_ready: std_logic;
	signal value_mag_out_ready: std_logic;

	signal fft_state : fft_state_dec := FFT_STATE_IDLE;
    	signal flag_index : bit;
	signal write_done_flag : bit;

	--signal memory_scale : work.reg.32.RegArray(0 to 1023);

    begin
	
	

	fft_calc : FFTMAIN
		port map (
			clock => clk,
			reset => reset,
			di_en => value_data_in_ready,
			di_re => value_data_in_real_scaled_fixed,
			di_im => value_data_in_imag,
			do_en => value_data_out_ready,
			do_re => value_data_out_real,
			do_im => value_data_out_imag
		);

	fft_mag: fft_magnitude_calc
		port map (
			clk => clk,
			reset => reset,
			input_valid => value_mag_in_ready,
			input_re => value_data_out_real,
			input_im => value_data_out_imag,
			output_valid => value_mag_out_ready,
			output_magnitude => value_data_out_mag
		);
	-- current_task_state, task_start, index

	    task_state_transitions : process ( current_task_state, task_start, index ) is
	    begin
		next_task_state <= current_task_state;
		case current_task_state is
		    when work.task.TASK_IDLE =>
		        if ( task_start = '1' ) then
		            next_task_state <= work.task.TASK_RUNNING;
		        end if;
		    when work.task.TASK_RUNNING =>
			--index = work.task.STREAM_LEN
		        if ( write_done_flag = '1') then
		            next_task_state <= work.task.TASK_DONE;
		        end if;
		    when work.task.TASK_DONE =>
		        if ( task_start = '1' ) then
		            next_task_state <= work.task.TASK_RUNNING;
		        end if;
		end case;
	    end process task_state_transitions;

	    sync : process ( clk, reset ) is
	    begin
		if ( reset = '1' ) then
		    current_task_state <= work.task.TASK_IDLE;
		    index <= 0;
		elsif ( rising_edge( clk ) ) then
		    current_task_state <= next_task_state;
		    case next_task_state is
		    when work.task.TASK_IDLE =>
		        index <= 0;
		        --signal_write <= '0';
		    when work.task.TASK_RUNNING =>
		        --index <= index + 1;
		        
		        --signal_writedata <= ( others => '0' );

				if ( flag_index = '1' ) then
	    				index <= index + 1;
    				end if;
		    when work.task.TASK_DONE =>
		        index <= 0;
		        --signal_write <= '0';
		    end case;
		end if;
	    end process sync;

    	fft : process (clk, reset) is

	variable value_data_in_real_scaled : std_logic_vector(31 downto 0);
	variable value_data_in_real_temp : std_logic_vector(31 downto 0);
	variable a_vec : std_logic_vector(9 downto 0);  -- Reversed vector	
	variable b_vec : std_logic_vector(9 downto 0);  -- Reversed vector
	variable b : integer range 0 to 1023;
	variable mag_temp : std_logic_vector(31 downto 0);


    	begin
		-- Bei Reset alle Signale zurücksetzen
    		if ( reset = '1' ) then
                	value_data_in_ready <= '0';
			value_data_in_real <= ( others => '0');
			value_data_in_imag <= ( others => '0');
			value_mag_in_ready <= '0';
			write_done_flag <= '0';
			signal_write <= '0';
			signal_read <= '0';
			flag_index <= '0';

	  
			read_wait <= 0;			

            	-- Für jeden Takt fft_state Zustandsmaschine aufrufen.
		elsif ( rising_edge( clk ) ) then
    			case fft_state is
				when FFT_STATE_IDLE =>
					flag_index <= '0';
					if ( current_task_state = work.task.TASK_RUNNING ) then
    						fft_state <= FFT_STATE_FILL_IP_CORE;
						signal_read <= '1';
    				end if;

				when FFT_STATE_READ =>
					
					read_wait <= read_wait + 1;
					if (read_wait = 1) then
						fft_state <= FFT_STATE_FILL_IP_CORE;

					end if; 					
			

				when FFT_STATE_FILL_IP_CORE =>

					--value_data_in_real <= signal_readdata;

					read_wait <= read_wait + 1;
	
						value_data_in_real_scaled(31) := signal_readdata(31);
						value_data_in_real_scaled(22 downto 0) := std_logic_vector(signed(signal_readdata(22 downto 0)));
						if value_data_in_real_scaled(30 downto 23) = "00000000" then
						    	value_data_in_real_scaled(30 downto 23) := std_logic_vector(signed(signal_readdata(30 downto 23)));
						else
							value_data_in_real_scaled(30 downto 23) := std_logic_vector(signed(signal_readdata(30 downto 23)) - 4);
						end if;
						value_data_in_real_temp := to_fixed(std_logic_vector(value_data_in_real_scaled));
				
					
						value_data_in_real_scaled_fixed <= value_data_in_real_temp;
						value_data_in_ready <= '1';
					



					if (value_data_out_ready = '1') then
						fft_state <= FFT_STATE_GET_IP_CORE;
						signal_read <= '0';
						value_mag_in_ready <= '1';
					end if;

				when FFT_STATE_GET_IP_CORE =>
					
					if (value_mag_out_ready = '1') then
					
						value_data_out_mag_float <= to_float(value_data_out_mag);	

						value_data_out_mag_float_scaled(31) <= value_data_out_mag_float(31);
						value_data_out_mag_float_scaled(22 downto 0) <= std_logic_vector(signed(value_data_out_mag_float(22 downto 0)));
						if value_data_out_mag_float(30 downto 23) = "00000000" then
						    	value_data_out_mag_float_scaled(30 downto 23) <= std_logic_vector(signed(value_data_out_mag_float(30 downto 23)) + 4);
						else
							value_data_out_mag_float_scaled(30 downto 23) <= std_logic_vector(signed(value_data_out_mag_float(30 downto 23)) + 5);
						
						if (read_wait > 2) then

							memory(index) <= value_data_out_mag_float_scaled;
						end if;

						end if; 			


						flag_index <= '1';
					end if;

					if ( index = work.task.STREAM_LEN - 1 ) then
						--value_data_in_ready <= '0';	
						flag_index <= '0';
						bitsort_index <= 0;
						
						fft_state <= FFT_STATE_SORT;
					end if;

				when FFT_STATE_SORT =>

					a_vec := std_logic_vector(to_unsigned(bitsort_index, a_vec'length));

					for i in 0 to 9 loop
						b_vec(i) := a_vec(9 - i);
					end loop;

					b := to_integer(unsigned(b_vec));
					
					sorted_memory(bitsort_index) <= memory(b);

					bitsort_index <= bitsort_index + 1;
					
					if (bitsort_index = work.task.STREAM_LEN - 1) then 
						bitsort_index <= 0;						
						fft_state <= FFT_STATE_WRITE;
						
					end if;				

				when FFT_STATE_WRITE =>
	
					signal_write <= '1';
					signal_writedata <= sorted_memory(bitsort_index);
					bitsort_index <= bitsort_index + 1;
					if (bitsort_index = work.task.STREAM_LEN - 1) then
						fft_state <= FFT_STATE_DONE;
						write_done_flag <= '1';
					end if;


				when FFT_STATE_DONE =>


					signal_write <= '0';
					flag_index <= '0';
					signal_read <= '0';
					value_data_in_ready <= '0';
					value_mag_in_ready <= '0';

					

			end case;
    		end if;
    	end process fft;

        task_state <= current_task_state;

    end architecture rtl;
