    library ieee;
        use ieee.std_logic_1164.all;
        use ieee.numeric_std.all;

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


    entity add is
        port (
            clk : in std_logic;
            reset : in std_logic;

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

            signal_a_read : out std_logic;
            signal_a_readdata : in std_logic_vector( 31 downto 0 );

            signal_b_read : out std_logic;
            signal_b_readdata : in std_logic_vector( 31 downto 0 );

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

    architecture rtl of add is

	-- State Machine für Ansteuerung des ADD-IP Cores.
	type AddState is (
	ADD_STATE_IDLE,
	ADD_STATE_CALCULATE,
	ADD_STATE_WRITE,
	ADD_STATE_DONE
	);

	-- Instanziierung float_add component
    	component float_add
    	port (
    		clk : in std_logic;
    		reset : in std_logic;
    		start : in std_logic;
    		A : in std_logic_vector( 31 downto 0 );
    		B : in std_logic_vector( 31 downto 0 );
    		done : out std_logic;
    		sum : out std_logic_vector( 31 downto 0 )
    		);
    	end component float_add;

        signal current_task_state : work.task.State;
        signal next_task_state : work.task.State;
        signal index : integer range 0 to work.task.STREAM_LEN;
    	
	-- Eigene Steuersignale.
    	signal value_add_start : std_logic;
    	signal value_add_A : std_logic_vector( 31 downto 0 );
    	signal value_add_B : std_logic_vector( 31 downto 0 );
    	signal value_add_done :  std_logic;
    	signal value_add_sum : std_logic_vector( 31 downto 0 );

	signal add_state : AddState := ADD_STATE_IDLE;
    	signal flag_index : bit;


    begin

    	float_adder : float_add
    	port map (
    		clk => clk,
    		reset => reset,
    		start => value_add_start,
		-- Wert von A wird in value_add_A geschrieben.
    		A => value_add_A,		
		-- Wert von B wird in value_add_B geschrieben.
    		B => value_add_B,	
		-- Signal wenn Addition fertig berechnet.
    		done => value_add_done,
		-- Summe der Addition wird in write_data geschrieben
    		sum => value_add_sum		
    	);

        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 =>
                    if ( index = work.task.STREAM_LEN - 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;

                when work.task.TASK_RUNNING => 
    				if ( flag_index = '1' ) then
    					index <= index + 1;
    				end if;

                when work.task.TASK_DONE =>
                    index <= 0;

                end case;
            end if;
        end process sync;

    	add : process (clk, reset) is
    	begin
		-- Bei Reset alle Signale zurücksetzen
    		if ( reset = '1' ) then
                signal_a_read <= '0';
    			signal_b_read <= '0';
    			signal_write <= '0';
    			signal_writedata <= ( others => '0');
    			value_add_start <= '0';
    			value_add_A <= ( others => '0');
    			value_add_B <= ( others => '0');
            	-- Für jeden Takt add_state Zustandsmaschine aufrufen.
		elsif ( rising_edge( clk ) ) then
    			case add_state is
			-- IDLE STATE: Wenn Task im state TASK_RUNNING ist, soll add_state starten.
    			when ADD_STATE_IDLE =>
    				if ( current_task_state = work.task.TASK_RUNNING ) then
    					add_state <= ADD_STATE_CALCULATE;
    				end if;

			-- CALCULATE: Read signale instanziieren und lesen
    			when ADD_STATE_CALCULATE =>
    				signal_a_read <= '1';
    				signal_b_read <= '1';
    				value_add_start <= '1';
    				value_add_A <= signal_a_readdata;
    				value_add_B <= signal_b_readdata;
    				if ( value_add_done = '1' ) then
    					add_state <= ADD_STATE_WRITE;
    				end if;

			-- WRITE: 
    			when ADD_STATE_WRITE =>
    				signal_write <= '1';
    				signal_writedata <= value_add_sum;
    				value_add_start <= '0';
    				signal_a_read <= '0';
    				signal_b_read <= '0';
    				flag_index <= '1';
    				add_state <= ADD_STATE_DONE;
    			when ADD_STATE_DONE =>
    				signal_write <= '0';
    				flag_index <= '0';
    				add_state <= ADD_STATE_IDLE;
    			end case;
    		end if;
    	end process add;

        task_state <= current_task_state;

    end architecture rtl;
