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

library osvvm; -- Utility Library
context osvvm.OsvvmContext;

use work.rtps_package.all;
use work.user_config.all;
use work.rtps_config_package.all;
use work.rtps_test_package.all;
use work.Type2_package.all;

-- This testbench tests the Payload encoding/decoding of the TYPE1_interface entities.
-- It does so by interconnecting the writer and reader interface, setting some inputs to the writer and checking if the reader returns the same data.
-- This testbench tests only the Little Endian encoding/decoding.

entity L1_Type1_interface_test2 is
end entity;

architecture testbench of L1_Type1_interface_test2 is
    
    constant DEFAULT_SAMPLE_INFO : SAMPLE_INFO_TYPE := (
        sample_state                => (others => '0'),
        view_state                  => (others => '0'),
        instance_state              => (others => '0'),
        source_timestamp            => TIME_ZERO,
        instance_handle             => HANDLE_NIL,
        publication_handle          => HANDLE_NIL,
        disposed_generation_count   => (others => '0'),
        no_writers_generation_count => (others => '0'),
        sample_rank                 => (others => '0'),
        generation_rank             => (others => '0'),
        absolute_generation_rank    => (others => '0'),
        valid_data                  => '1'
    );
    
    signal clk, reset : std_logic := '0';
    signal ready, valid, last_word : std_logic := '0';
    signal data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
    signal start_w, get_data_r, decode_error, valid_r, encode_done : std_logic := '0';
    
    signal id_in, id_out : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
    signal a_in, a_out : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
begin
    
    uut_w : entity work.Type1_writer_interface(arch)
        generic map (
            LITTLE_ENDIAN   => '1'
        )
        port map (
            clk                                 => clk,
            reset                               => reset,
            start_dds                           => open,
            ack_dds                             => '1',
            opcode_dds                          => open,
            instance_handle_out_dds             => HANDLE_NIL,
            source_ts_dds                       => open,
            max_wait_dds                        => open,
            done_dds                            => '1',
            return_code_dds                     => RETCODE_OK,
            instance_handle_in_dds              => open,
            ready_out_dds                       => ready,
            valid_out_dds                       => valid,
            data_out_dds                        => data,
            last_word_out_dds                   => last_word,
            ready_in_dds                        => open,
            valid_in_dds                        => '0',
            data_in_dds                         => (others => '0'),
            last_word_in_dds                    => '0',
            status_dds                          => (others => '0'),
            start_user                          => start_w,
            ack_user                            => open,
            opcode_user                         => WRITE,
            instance_handle_in_user             => HANDLE_NIL,
            source_ts_user                      => TIME_ZERO,
            max_wait_user                       => TIME_INFINITE,
            done_user                           => open,
            return_code_user                    => open,
            instance_handle_out_user            => open,
            status_user                         => open,
            id                                  => id_in,
            a                                   => a_in,
            encode_done                         => encode_done
        );
    
    uut_r : entity work.Type1_reader_interface(arch)
        port map (
            clk                                 => clk,
            reset                               => reset,
            start_dds                           => open,
            ack_dds                             => '1',
            opcode_dds                          => open,
            instance_state_dds                  => open,
            view_state_dds                      => open,
            sample_state_dds                    => open,
            instance_handle_dds                 => open,
            max_samples_dds                     => open,
            get_data_dds                        => open,
            done_dds                            => '1',
            return_code_dds                     => RETCODE_OK,
            ready_in_dds                        => ready,
            valid_in_dds                        => valid,
            data_in_dds                         => data,
            last_word_in_dds                    => last_word,
            sample_info_dds                     => DEFAULT_SAMPLE_INFO,
            sample_info_valid_dds               => '1',
            sample_info_ack_dds                 => open,
            eoc_dds                             => '1',
            status_dds                          => (others => '0'),
            start_user                          => '0',
            ack_user                            => open,
            opcode_user                         => NOP,
            instance_state_user                 => (others => '0'),
            view_state_user                     => (others => '0'),
            sample_state_user                   => (others => '0'),
            instance_handle_user                => HANDLE_NIL,
            max_samples_user                    => (others => '0'),
            get_data_user                       => get_data_r,
            done_user                           => open,
            return_code_user                    => open,
            sample_info_user                    => open,
            sample_info_valid_user              => open,
            sample_info_ack_user                => '1',
            eoc_user                            => open,
            status_user                         => open,
            decode_error                        => decode_error,
            id                                  => id_out,
            a                                   => a_out,
            valid                               => valid_r
        );
    
    stimulus_prc : process
        variable RV : RandomPType;
        variable ID, A : AlertLogIDType;
        
        procedure wait_on_sig(signal sig : std_logic) is
        begin
            if (sig /= '1') then
                wait on sig until sig = '1';
            end if;
        end procedure;
    begin
        
        SetAlertLogName("L1_Type1_interface_test2 - (Little Endian) - Encoding/Decoding");
        SetAlertEnable(FAILURE, TRUE);
        SetAlertEnable(ERROR, TRUE);
        SetAlertEnable(WARNING, TRUE);
        SetLogEnable(DEBUG, FALSE);
        SetLogEnable(PASSED, FALSE);
        SetLogEnable(INFO, TRUE);
        RV.InitSeed(RV'instance_name);
        ID  := GetAlertLogID("ID", ALERTLOG_BASE_ID);
        A   := GetAlertLogID("A", ALERTLOG_BASE_ID);
        
        Log("Initial Reset", INFO);
        start_w     <= '0';
        get_data_r  <= '0';
        reset       <= '1';
        wait until rising_edge(clk);
        wait until rising_edge(clk);
        reset   <= '0';
        
        Log("Setting Data in Writer Side", INFO);
        -- Static
        id_in   <= RV.RandSlv(id_in'length);
        a_in    <= RV.RandSlv(a_in'length);
        wait for 0 ns;
        
        
        Log("Initiate Writer->Reader Transfer", INFO);
        
        start_w     <= '1';
        get_data_r  <= '1';
        wait until rising_edge(clk);
        start_w     <= '0';
        get_data_r  <= '0';
        
        Log("Wait until Transfer done", INFO);
        wait_on_sig(encode_done);
        wait_on_sig(valid_r);
        
        Log("Compare Writer and Reader Side", INFO);
        AffirmIfEqual(ID, id_out, id_in);
        AffirmIfEqual(A, a_out,a_in);
        
        
        TranscriptOpen(RESULTS_FILE, APPEND_MODE);
        SetTranscriptMirror;
        ReportAlerts;
        TranscriptClose;
        std.env.stop;
        wait;
    end process;
    
    clock_prc : process
    begin
        clk <= '0';
        wait for TEST_CLOCK_PERIOD/2;
        clk <= '1';
        wait for TEST_CLOCK_PERIOD/2;
    end process;
    
    alert_prc : process(all)
    begin
        if rising_edge(clk) then
            alertif(decode_error = '1', "The Reader signals a DECODE Error", ERROR);
        end if;
    end process;
    
    watchdog : process
    begin
        wait for 1 ms;
        Alert("Test timeout", FAILURE);
        std.env.stop;
    end process;
    
end architecture;