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

library Testbench_Lib3;

use Testbench_Lib3.rtps_package.all;
use Testbench_Lib3.user_config.all;
use Testbench_Lib3.rtps_config_package.all;
use Testbench_Lib3.rtps_test_package.all;
use Testbench_Lib3.Type1_package.all;

entity L2_Testbench_Lib3 is
    port (
        -- SYSTEM
        clk                     : in std_logic;
        reset                   : in std_logic;
        time                    : in TIME_TYPE;
        -- INPUT
        empty                   : in std_logic;
        rd                      : out std_logic;
        data_in                 : in std_logic_vector(WORD_WIDTH-1 downto 0);
        -- OUTPUT
        data_out                : out std_logic_vector(WORD_WIDTH-1 downto 0);
        wr                      : out std_logic;
        full                    : in std_logic;
        
        -- TO USER ENTITY
        start_user                          : in std_logic;
        ack_user                            : out std_logic;
        opcode_user                         : in DDS_READER_OPCODE_TYPE;
        instance_state_user                 : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        view_state_user                     : in std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        sample_state_user                   : in std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
        instance_handle_user                : in INSTANCE_HANDLE_TYPE;
        max_samples_user                    : in std_logic_vector(MAX_SAMPLES_WIDTH-1 downto 0);
        get_data_user                       : in std_logic;
        done_user                           : out std_logic;
        return_code_user                    : out std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        sample_info_user                    : out SAMPLE_INFO_TYPE;    
        sample_info_valid_user              : out std_logic;
        sample_info_ack_user                : in std_logic;
        eoc_user                            : out std_logic;
        -- Communication Status
        status_user                         : out std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        decode_error                        : out std_logic;
        
        -- ###GENERATED START###
        id                                  : out std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        a                                   : out std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        -- ###GENERATED END###
        valid                               : out std_logic
    );
end entity;

architecture arch of L2_Testbench_Lib3 is
    
    type ENDPOINT_DATA_TYPE is array (0 to NUM_ENDPOINTS) of std_logic_vector(WORD_WIDTH downto 0);

    -- INTERCONNECT
    signal start_wr_dds, ack_wr_dds, get_data_wr_dds, done_wr_dds, ready_in_wr_dds, valid_in_wr_dds, last_word_in_wr_dds, si_valid_data_wr_dds, si_valid_wr_dds, si_ack_wr_dds, eoc_wr_dds : std_logic;
    signal opcode_wr_dds : DDS_READER_OPCODE_TYPE;
    signal instance_state_wr_dds, si_instance_state_wr_dds : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
    signal view_state_wr_dds, si_view_state_wr_dds : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
    signal sample_state_wr_dds, si_sample_state_wr_dds : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
    signal instance_handle_wr_dds, si_instance_handle_wr_dds : INSTANCE_HANDLE_TYPE;
    signal max_samples_wr_dds : std_logic_vector(MAX_SAMPLES_WIDTH-1 downto 0);
    signal return_code_wr_dds : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
    signal data_in_wr_dds : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal sample_info_wr_dds : SAMPLE_INFO_TYPE;
    signal sample_info_valid_wr_dds, sample_info_ack_wr_dds : std_logic;
    signal status_wr_dds : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
   
    signal start_dds_rtps, ack_dds_rtps, done_dds_rtps, valid_in_dds_rtps, ready_in_dds_rtps, last_word_in_dds_rtps : std_logic;
    signal opcode_dds_rtps : HISTORY_CACHE_OPCODE_TYPE;
    signal ret_dds_rtps : HISTORY_CACHE_RESPONSE_TYPE;
    signal data_in_dds_rtps : std_logic_vector(WORD_WIDTH-1 downto 0);
    
    signal empty_rh, full_rh, rd_rh, wr_rh : std_logic_vector(0 to NUM_ENDPOINTS);
    signal data_in_rh, data_out_rh : ENDPOINT_DATA_TYPE;
    
    signal empty_rtps, full_rtps, rd_rtps, wr_rtps, alive_sig_rtps : std_logic_vector(0 to NUM_ENDPOINTS);
    signal data_in_rtps, data_out_rtps : ENDPOINT_DATA_TYPE;
    
    signal wr_rtps_out, rd_rtps_out, full_rtps_out, empty_rtps_out : std_logic_vector(0 to NUM_ENDPOINTS);
    signal data_out_rtps_out, data_in_rtps_out : ENDPOINT_DATA_TYPE;
    
    signal last_word_out_rbe : std_logic;
    signal data_out_rbe : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal last_word_out_rh_be_s, last_word_out_rh_ue_s : std_logic;
    signal data_out_rh_be_s, data_out_rh_ue_s : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal data_rtps_out_s : RTPS_OUT_DATA_TYPE;
    signal last_word_rtps_out_s : std_logic_vector(0 to NUM_ENDPOINTS);
    
    
    
begin
    
    Type1_reader_interface_r_inst : entity Testbench_Lib3.Type1_reader_interface(arch)
        port map (
            -- SYSTEM
            clk                                 => clk,
            reset                               => reset,
            -- FROM DDS READER
            start_dds                           => start_wr_dds,
            ack_dds                             => ack_wr_dds,
            opcode_dds                          => opcode_wr_dds,
            instance_state_dds                  => instance_state_wr_dds,
            view_state_dds                      => view_state_wr_dds,
            sample_state_dds                    => sample_state_wr_dds,
            instance_handle_dds                 => instance_handle_wr_dds,
            max_samples_dds                     => max_samples_wr_dds,
            get_data_dds                        => get_data_wr_dds,
            done_dds                            => done_wr_dds,
            return_code_dds                     => return_code_wr_dds,
            ready_in_dds                        => ready_in_wr_dds,
            valid_in_dds                        => valid_in_wr_dds,
            data_in_dds                         => data_in_wr_dds,
            last_word_in_dds                    => last_word_in_wr_dds,
            sample_info_dds                     => sample_info_wr_dds,
            sample_info_valid_dds               => sample_info_valid_wr_dds,
            sample_info_ack_dds                 => sample_info_ack_wr_dds,
            eoc_dds                             => eoc_wr_dds,
            -- Communication Status
            status_dds                          => status_wr_dds,
            -- TO USER ENTITY
            start_user                          => start_user,
            ack_user                            => ack_user,
            opcode_user                         => opcode_user,
            instance_state_user                 => instance_state_user,
            view_state_user                     => view_state_user,
            sample_state_user                   => sample_state_user,
            instance_handle_user                => instance_handle_user,
            max_samples_user                    => max_samples_user,
            get_data_user                       => get_data_user,
            done_user                           => done_user,
            return_code_user                    => return_code_user,
            sample_info_user                    => sample_info_user,
            sample_info_valid_user              => sample_info_valid_user,
            sample_info_ack_user                => sample_info_ack_user,
            eoc_user                            => eoc_user,
            -- Communication Status
            status_user                         => status_user,
            decode_error                        => open,
            -- ###GENERATED START###
            id                                  => id,
            a                                   => a,
            -- ###GENERATED END###
            valid                               => valid
        );
    
    dds_reader_r_inst : entity Testbench_Lib3.dds_reader(arch)
        generic map (
            TIME_BASED_FILTER_QOS       => ENDPOINT_CONFIG(0).TIME_BASED_FILTER_QOS,
            DEADLINE_QOS                => ENDPOINT_CONFIG(0).DEADLINE_QOS,
            MAX_INSTANCES               => ENDPOINT_CONFIG(0).MAX_INSTANCES,
            MAX_SAMPLES_PER_INSTANCE    => ENDPOINT_CONFIG(0).MAX_SAMPLES_PER_INSTANCE,
            MAX_SAMPLES                 => ENDPOINT_CONFIG(0).MAX_SAMPLES,
            HISTORY_QOS                 => ENDPOINT_CONFIG(0).HISTORY_QOS,
            RELIABILITY_QOS             => ENDPOINT_CONFIG(0).RELIABILITY_QOS,
            PRESENTATION_QOS            => ENDPOINT_CONFIG(0).PRESENTATION_QOS,
            DESTINATION_ORDER_QOS       => ENDPOINT_CONFIG(0).DESTINATION_ORDER_QOS,
            COHERENT_ACCESS             => ENDPOINT_CONFIG(0).COHERENT_ACCESS,
            ORDERED_ACCESS              => ENDPOINT_CONFIG(0).ORDERED_ACCESS,
            WITH_KEY                    => ENDPOINT_CONFIG(0).WITH_KEY,
            PAYLOAD_FRAME_SIZE          => ENDPOINT_CONFIG(0).MAX_PAYLOAD_SIZE,
            MAX_REMOTE_ENDPOINTS        => 5
        )
        port map (
            -- SYSTEM
            clk                             => clk,
            reset                           => reset,
            time                            => time,
            -- FROM RTPS ENDPOINT
            start_rtps                      => start_dds_rtps,
            opcode_rtps                     => opcode_dds_rtps,
            ack_rtps                        => ack_dds_rtps,
            done_rtps                       => done_dds_rtps,
            ret_rtps                        => ret_dds_rtps,
            data_in_rtps                    => data_in_dds_rtps,
            valid_in_rtps                   => valid_in_dds_rtps,
            ready_in_rtps                   => ready_in_dds_rtps,
            last_word_in_rtps               => last_word_in_dds_rtps,
            -- TO USER ENTITY
            start_dds                       => start_wr_dds,
            ack_dds                         => ack_wr_dds,
            opcode_dds                      => opcode_wr_dds,
            instance_state_dds              => instance_state_wr_dds,
            view_state_dds                  => view_state_wr_dds,
            sample_state_dds                => sample_state_wr_dds,
            instance_handle_dds             => instance_handle_wr_dds,
            max_samples_dds                 => max_samples_wr_dds,
            get_data_dds                    => get_data_wr_dds,
            done_dds                        => done_wr_dds,
            return_code_dds                 => return_code_wr_dds,
            ready_out_dds                   => ready_in_wr_dds,
            valid_out_dds                   => valid_in_wr_dds,
            data_out_dds                    => data_in_wr_dds,
            last_word_out_dds               => last_word_in_wr_dds,
            sample_info                     => sample_info_wr_dds,
            sample_info_valid               => sample_info_valid_wr_dds,
            sample_info_ack                 => sample_info_ack_wr_dds,
            eoc                             => eoc_wr_dds,
            -- Communication Status
            status                          => status_wr_dds
        );
    
    rtps_reader_r_inst : entity Testbench_Lib3.rtps_reader(arch)
        generic map (
            ENTITYID                    => ENTITYID(0),
            RELIABILITY_QOS             => ENDPOINT_CONFIG(0).RELIABILITY_QOS,
            LIVELINESS_QOS              => ENDPOINT_CONFIG(0).LIVELINESS_QOS,
            DURABILITY_QOS              => ENDPOINT_CONFIG(0).DURABILITY_QOS,
            HEARTBEAT_RESPONSE_DELAY    => ENDPOINT_CONFIG(0).HEARTBEAT_RESPONSE_DELAY,
            HEARTBEAT_SUPPRESSION_DELAY => ENDPOINT_CONFIG(0).HEARTBEAT_SUPPRESSION_DELAY,
            LEASE_DURATION              => ENDPOINT_CONFIG(0).LEASE_DURATION,
            WITH_KEY                    => ENDPOINT_CONFIG(0).WITH_KEY,
            MAX_REMOTE_ENDPOINTS        => 5
        )
        port map (
            -- SYSTEM
            clk                     => clk,
            reset                   => reset,
            time                    => time,
            -- FROM RTPS_HANDLER (USER TRAFFIC)
            empty_user              => empty_rh(0),
            rd_user                 => rd_rh(0),
            data_in_user            => data_out_rh(0)(WORD_WIDTH-1 downto 0),
            last_word_in_user       => data_out_rh(0)(WORD_WIDTH),
            -- FROM DISCOVERY MODULE (META TRAFFIC)
            empty_meta              => empty_rtps(0),
            rd_meta                 => rd_rtps(0),
            data_in_meta            => data_out_rtps(0)(WORD_WIDTH-1 downto 0),
            last_word_in_meta       => data_out_rtps(0)(WORD_WIDTH),
            -- RTPS OUTPUT
            wr_ro                   => wr_rtps_out(0),
            full_ro                 => full_rtps_out(0),
            data_out_ro             => data_in_rtps_out(0)(WORD_WIDTH-1 downto 0),
            last_word_out_ro        => data_in_rtps_out(0)(WORD_WIDTH),
            -- TO HISTORY CACHE
            start_hc                => start_dds_rtps,
            opcode_hc               => opcode_dds_rtps,
            ack_hc                  => ack_dds_rtps,
            done_hc                 => done_dds_rtps,
            ret_hc                  => ret_dds_rtps,
            data_out_hc             => data_in_dds_rtps,
            valid_out_hc            => valid_in_dds_rtps,
            ready_out_hc            => ready_in_dds_rtps,
            last_word_out_hc        => last_word_in_dds_rtps
        );
    
    rtps_discovery_module_r_inst : entity Testbench_Lib3.rtps_discovery_module(arch)
        generic map (
            MAX_REMOTE_PARTICIPANTS => 5,
            PREFER_MULTICAST        => PREFER_MULTICAST_LOCATORS
        )
        port map (
            clk                 => clk,
            reset               => reset,
            time                => time,
            -- FROM RTPS HANDLER
            empty               => empty_rh(NUM_ENDPOINTS),
            rd                  => rd_rh(NUM_ENDPOINTS),
            data_in             => data_out_rh(NUM_ENDPOINTS)(WORD_WIDTH-1 downto 0),
            last_word_in        => data_out_rh(NUM_ENDPOINTS)(WORD_WIDTH),
            -- FROM USER ENDPOINTS
            alive               => alive_sig_rtps(0 to NUM_ENDPOINTS-1),
            -- TO USER ENDPOINTS
            full_rtps             => full_rtps(0 to NUM_ENDPOINTS-1),
            wr_rtps               => wr_rtps(0 to NUM_ENDPOINTS-1),
            data_out_rtps         => data_out_rbe,
            last_word_out_rtps    => last_word_out_rbe,
            -- TO RTPS OUT
            full_ro             => full_rtps_out(NUM_ENDPOINTS),
            wr_ro               => wr_rtps_out(NUM_ENDPOINTS),
            data_out_ro         => data_in_rtps_out(NUM_ENDPOINTS)(WORD_WIDTH-1 downto 0),
            last_word_out_ro    => data_in_rtps_out(NUM_ENDPOINTS)(WORD_WIDTH)
        );
    
    data_in_rtps(0 to NUM_ENDPOINTS-1) <= (others => (last_word_out_rbe & data_out_rbe));
    
    rtps_handler_r_inst : entity Testbench_Lib3.rtps_handler(arch)
        port map (
            -- SYSTEM
            clk                 => clk,
            reset               => reset,
            -- INPUT
            empty               => empty,
            rd                  => rd,
            data_in             => data_in,
            -- TO DISCOVERY MODULE
            full_dm             => full_rh(NUM_ENDPOINTS),
            wr_dm               => wr_rh(NUM_ENDPOINTS),
            data_out_dm         => data_out_rh_be_s,
            last_word_out_dm    => last_word_out_rh_be_s,
            -- TO RTPS ENDPOINT
            full_rtps             => full_rh(0 to NUM_ENDPOINTS-1),
            wr_rtps               => wr_rh(0 to NUM_ENDPOINTS-1),
            data_out_rtps         => data_out_rh_ue_s,
            last_word_out_rtps    => last_word_out_rh_ue_s
        );
    
    data_in_rh <= (NUM_ENDPOINTS => (last_word_out_rh_be_s & data_out_rh_be_s), others => (last_word_out_rh_ue_s & data_out_rh_ue_s));
    
    rtps_out_r_inst : entity Testbench_Lib3.rtps_out(arch)
        port map (
            clk             => clk,
            reset           => reset,
            -- INPUT
            data_in         => data_rtps_out_s,
            last_word_in    => last_word_rtps_out_s,
            rd              => rd_rtps_out,
            empty           => empty_rtps_out,
            -- OUTPUT
            data_out        => data_out,
            wr              => wr,
            full            => full
        );
    
    rh_fifo_gen : for i in 0 to NUM_ENDPOINTS generate
    begin
        fifo_inst : configuration Testbench_Lib3.FWFT_FIFO_cfg
            generic map (
                FIFO_DEPTH  => 2,
                DATA_WIDTH  => WORD_WIDTH+1
            )
            port map
            (
                reset       => reset,
                clk         => clk,
                data_in     => data_in_rh(i),
                write       => wr_rh(i),
                read        => rd_rh(i),
                data_out    => data_out_rh(i),
                empty       => empty_rh(i),
                full        => full_rh(i),
                free        => open
            );
    end generate;
    
    rtps_out_fifo_gen : for i in 0 to NUM_ENDPOINTS generate
    begin
        fifo_inst : configuration Testbench_Lib3.FWFT_FIFO_cfg
            generic map (
                FIFO_DEPTH  => 2,
                DATA_WIDTH  => WORD_WIDTH+1
            )
            port map
            (
                reset       => reset,
                clk         => clk,
                data_in     => data_in_rtps_out(i),
                write       => wr_rtps_out(i),
                read        => rd_rtps_out(i),
                data_out    => data_out_rtps_out(i),
                empty       => empty_rtps_out(i),
                full        => full_rtps_out(i),
                free        => open
            );
            
            data_rtps_out_s(i)      <= data_out_rtps_out(i)(WORD_WIDTH-1 downto 0);
            last_word_rtps_out_s(i) <= data_out_rtps_out(i)(WORD_WIDTH);
    end generate;
    
    rtps_fifo_gen : for i in 0 to NUM_ENDPOINTS-1 generate
    begin
        fifo_inst : configuration Testbench_Lib3.FWFT_FIFO_cfg
            generic map (
                FIFO_DEPTH  => 2,
                DATA_WIDTH  => WORD_WIDTH+1
            )
            port map
            (
                reset       => reset,
                clk         => clk,
                data_in     => data_in_rtps(i),
                write       => wr_rtps(i),
                read        => rd_rtps(i),
                data_out    => data_out_rtps(i),
                empty       => empty_rtps(i),
                full        => full_rtps(i),
                free        => open
            );
    end generate;
    
end architecture;