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

library work;
    use work.reg32.all;
    use work.avalon_slave.all;
    use work.test_utility.all;
    use work.test_avalon_slave.all;
    use work.task.all;
    use work.sine_data.all;
    use work.test_hardware_task.all;
    use work.test_data_channel_pkg.all;

library std;
    use std.env.all;
    use std.textio.all;

entity test_task_sine is
    generic( CHECK_RESULTS : boolean; GUI_MODE : boolean := false );
end entity test_task_sine;

architecture test of test_task_sine is

    procedure test_configure( signal clk : in std_logic;
        signal req : out work.avalon_slave.Request;
        signal rsp : in work.avalon_slave.Response ) is

        variable index : integer := 0;
        variable writedata : std_logic_vector( 31 downto 0 );
    begin
        std.textio.write( std.textio.OUTPUT, "    test_configure ... " );
        index := 0;
        writedata := x"08000000"; -- 2^32 / 32
        write_and_assert_config_eq( clk => clk, req => req, rsp => rsp,
            index => index, config => writedata );

        index := 1;
        writedata := x"00000000";
        write_and_assert_config_eq( clk => clk, req => req, rsp => rsp,
            index => index, config => writedata );

        index := 2;
        writedata := x"40800000"; -- 2 ** 2 = 4 float
        write_and_assert_config_eq( clk => clk, req => req, rsp => rsp,
            index => index, config => writedata );

        std.textio.write( std.textio.OUTPUT, TEST_OK );

    end procedure test_configure;

    signal clk : std_logic := '0';
    signal reset : std_logic := '1';

    signal req : work.avalon_slave.Request;
    signal rsp : work.avalon_slave.Response;

    signal data_channel_req : work.avalon_slave.Request;
    signal data_channel_rsp : work.avalon_slave.Response;

    signal signal_write : std_logic;
    signal signal_writedata : std_logic_vector( 31 downto 0 );

    signal data_channel_read : std_logic;
    signal data_channel_readdata : std_logic_vector( 31 downto 0 );

begin

    dut : entity work.task_sine
        port map (
            clk => clk,
            reset => reset,

            address => req.address,
            read => req.read,
            readdata => rsp.readdata,
            write => req.write,
            writedata => req.writedata,

            signal_write => signal_write,
            signal_writedata => signal_writedata
        );

    u_data_channel : entity work.data_channel
        port map (
            clk => clk,
            reset => reset,

            ctrl_address => data_channel_req.address,
            ctrl_read => data_channel_req.read,
            ctrl_readdata => data_channel_rsp.readdata,
            ctrl_write => data_channel_req.write,
            ctrl_writedata => data_channel_req.writedata,

            hw_sink_write => signal_write,
            hw_sink_writedata => signal_writedata,

            hw_source_read => data_channel_read,
            hw_source_readdata => data_channel_readdata
        );

    clk <= not clk after 10 ns;

    reset_release : process
    begin
         wait for 35 ns;
         reset <= '0';
         wait;
    end process reset_release;

    stimulus : process
        variable data_channel_config : std_logic_vector( 31 downto 0 ) := x"00000001";
    begin
        wait until falling_edge( reset );

        work.test_data_channel_pkg.write_and_assert_config( clk => clk,
            req => data_channel_req,
            rsp => data_channel_rsp,
            config => data_channel_config );

        test_configure( clk => clk, req => req, rsp => rsp );
        test_execute( clk => clk, req => req, rsp => rsp,
            write => signal_write, writedata => signal_writedata );

        if ( CHECK_RESULTS ) then
            check_and_write_content( clk => clk,
                req => data_channel_req, rsp => data_channel_rsp,
                expected => work.sine_data.expected );
        else
            write_content( clk => clk,
                req => data_channel_req, rsp => data_channel_rsp );
        end if;

        if ( GUI_MODE ) then
            std.env.stop;
        else
            std.env.finish;
        end if;
    end process stimulus;
end architecture test;

