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

library Testbench_Lib2;

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

entity L2_Testbench_Lib2 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_WRITER_OPCODE_TYPE;
        instance_handle_in_user     : in INSTANCE_HANDLE_TYPE;
        source_ts_user              : in TIME_TYPE;
        max_wait_user               : in DURATION_TYPE;
        done_user                   : out std_logic;
        return_code_user            : out std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        instance_handle_out_user    : out INSTANCE_HANDLE_TYPE;
        -- Communication Status
        status_user                 : out std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
        -- ###GENERATED START###
        id                          : in std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        a                           : in std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        -- ###GENERATED END###
        encode_done                 : out std_logic
    );
end entity;

architecture arch of L2_Testbench_Lib2 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, done_wr_dds, ready_out_wr_dds, valid_out_wr_dds, last_word_out_wr_dds, ready_in_wr_dds, valid_in_wr_dds, last_word_in_wr_dds : std_logic;
    signal opcode_wr_dds : DDS_WRITER_OPCODE_TYPE;
    signal instance_handle_in_wr_dds, instance_handle_out_wr_dds : INSTANCE_HANDLE_TYPE;
    signal source_ts_wr_dds : TIME_TYPE;
    signal max_wait_wr_dds : DURATION_TYPE;
    signal return_code_wr_dds : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
    signal data_in_wr_dds, data_out_wr_dds : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal status_wr_dds : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
    signal start_dds_rtps, ack_dds_rtps, done_dds_rtps, get_data_dds_rtps, valid_out_dds_rtps, ready_out_dds_rtps, last_word_out_dds_rtps, liveliness_assertion_dds_rtps, data_available_dds_rtps : std_logic;
    signal data_out_dds_rtps : std_logic_vector(WORD_WIDTH-1 downto 0);
    signal opcode_dds_rtps : HISTORY_CACHE_OPCODE_TYPE;
    signal ret_dds_rtps : HISTORY_CACHE_RESPONSE_TYPE;
    signal seq_nr_dds_rtps : SEQUENCENUMBER_TYPE;
    signal cc_instance_handle_dds_rtps : INSTANCE_HANDLE_TYPE;
    signal cc_kind_dds_rtps : CACHE_CHANGE_KIND_TYPE;
    signal cc_source_timestamp_dds_rtps : TIME_TYPE;
    signal cc_seq_nr_dds_rtps : SEQUENCENUMBER_TYPE;
    
    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_writer_interface_w_inst : entity Testbench_Lib2.Type1_writer_interface(arch)
        port map (
            -- SYSTEM
            clk                         => clk,
            reset                       => reset,
            -- FROM DDS WRITER
            start_dds                   => start_wr_dds,
            ack_dds                     => ack_wr_dds,
            opcode_dds                  => opcode_wr_dds,
            instance_handle_out_dds     => instance_handle_out_wr_dds,
            source_ts_dds               => source_ts_wr_dds,
            max_wait_dds                => max_wait_wr_dds,
            done_dds                    => done_wr_dds,
            return_code_dds             => return_code_wr_dds,
            instance_handle_in_dds      => instance_handle_in_wr_dds,
            ready_out_dds               => ready_out_wr_dds,
            valid_out_dds               => valid_out_wr_dds,
            data_out_dds                => data_out_wr_dds,
            last_word_out_dds           => last_word_out_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,
            -- Communication Status
            status_dds                  => status_wr_dds,
            -- TO USER ENTITY
            start_user                  => start_user,
            ack_user                    => ack_user,
            opcode_user                 => opcode_user,
            instance_handle_in_user     => instance_handle_in_user,
            source_ts_user              => source_ts_user,
            max_wait_user               => max_wait_user,
            done_user                   => done_user,
            return_code_user            => return_code_user,
            instance_handle_out_user    => instance_handle_out_user,
            -- Communication Status
            status_user                 => status_user,
            -- ###GENERATED START###
            id                          => id,
            a                           => a,
            -- ###GENERATED END###
            encode_done                 => encode_done
        );
    
    dds_writer_w_inst : entity Testbench_Lib2.dds_writer(arch)
        generic map (
            HISTORY_QOS                 => ENDPOINT_CONFIG(0).HISTORY_QOS,
            DEADLINE_QOS                => ENDPOINT_CONFIG(0).DEADLINE_QOS,
            LIFESPAN_QOS                => ENDPOINT_CONFIG(0).LIFESPAN_QOS,
            LEASE_DURATION              => ENDPOINT_CONFIG(0).LEASE_DURATION,
            WITH_KEY                    => ENDPOINT_CONFIG(0).WITH_KEY,
            MAX_SAMPLES                 => ENDPOINT_CONFIG(0).MAX_SAMPLES,
            MAX_INSTANCES               => ENDPOINT_CONFIG(0).MAX_INSTANCES,
            MAX_SAMPLES_PER_INSTANCE    => ENDPOINT_CONFIG(0).MAX_SAMPLES_PER_INSTANCE,
            PAYLOAD_FRAME_SIZE          => ENDPOINT_CONFIG(0).MAX_PAYLOAD_SIZE
        )
        port map (
            -- SYSTEM
            clk                     => clk,
            reset                   => reset,
            time                    => time,
            -- TO/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,
            seq_nr_rtps             => seq_nr_dds_rtps,
            get_data_rtps           => get_data_dds_rtps,
            data_out_rtps           => data_out_dds_rtps,
            valid_out_rtps          => valid_out_dds_rtps,
            ready_out_rtps          => ready_out_dds_rtps,
            last_word_out_rtps      => last_word_out_dds_rtps,
            liveliness_assertion    => liveliness_assertion_dds_rtps,
            data_available          => data_available_dds_rtps,
            -- Cache Change
            cc_instance_handle      => cc_instance_handle_dds_rtps,
            cc_kind                 => cc_kind_dds_rtps,
            cc_source_timestamp     => cc_source_timestamp_dds_rtps,
            cc_seq_nr               => cc_seq_nr_dds_rtps,
            -- TO/FROM USER ENTITY
            start_dds               => start_wr_dds,
            ack_dds                 => ack_wr_dds,
            opcode_dds              => opcode_wr_dds,
            instance_handle_in_dds  => instance_handle_in_wr_dds,
            source_ts_dds           => source_ts_wr_dds,
            max_wait_dds            => max_wait_wr_dds,
            done_dds                => done_wr_dds,
            return_code_dds         => return_code_wr_dds,
            instance_handle_out_dds => instance_handle_out_wr_dds,
            ready_in_dds            => ready_out_wr_dds,
            valid_in_dds            => valid_out_wr_dds,
            data_in_dds             => data_out_wr_dds,
            last_word_in_dds        => last_word_out_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,
            -- Communication Status
            status                  => status_wr_dds
        );
    
    rtps_writer_w_inst : entity Testbench_Lib2.rtps_writer(arch)
        generic map (
            RELIABILITY_QOS             => ENDPOINT_CONFIG(0).RELIABILITY_QOS,
            LIVELINESS_QOS              => ENDPOINT_CONFIG(0).LIVELINESS_QOS,
            DURABILITY_QOS              => ENDPOINT_CONFIG(0).DURABILITY_QOS,
            DESTINATION_ORDER_QOS       => ENDPOINT_CONFIG(0).DESTINATION_ORDER_QOS,
            ACKNACK_RESPONSE_DELAY      => ENDPOINT_CONFIG(0).ACKNACK_RESPONSE_DELAY,
            ACKNACK_SUPPRESSION_DELAY   => ENDPOINT_CONFIG(0).ACKNACK_SUPPRESSION_DELAY,
            LEASE_DURATION              => ENDPOINT_CONFIG(0).LEASE_DURATION,
            HEARTBEAT_PERIOD            => ENDPOINT_CONFIG(0).HEARTBEAT_PERIOD,
            ENTITYID                    => ENTITYID(0),
            WITH_KEY                    => ENDPOINT_CONFIG(0).WITH_KEY,
            PUSH_MODE                   => ENDPOINT_CONFIG(0).PUSH_MODE,
            INLINE_QOS                  => gen_inline_qos(0),
            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),
            -- TO DISCOVERY MODULE (META TRAFFIC)
            alive_sig               => alive_sig_rtps(0),
            -- 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),
            -- FROM HC
            liveliness_assertion    => liveliness_assertion_dds_rtps,
            data_available          => data_available_dds_rtps,
            start_hc                => start_dds_rtps,
            opcode_hc               => opcode_dds_rtps,
            ack_hc                  => ack_dds_rtps,
            seq_nr_hc               => seq_nr_dds_rtps,
            done_hc                 => done_dds_rtps,
            ret_hc                  => ret_dds_rtps,
            get_data_hc             => get_data_dds_rtps,
            data_in_hc              => data_out_dds_rtps,
            valid_in_hc             => valid_out_dds_rtps,
            ready_in_hc             => ready_out_dds_rtps,
            last_word_in_hc         => last_word_out_dds_rtps,
            cc_instance_handle      => cc_instance_handle_dds_rtps,
            cc_kind                 => cc_kind_dds_rtps,
            cc_source_timestamp     => cc_source_timestamp_dds_rtps,
            cc_seq_nr               => cc_seq_nr_dds_rtps
        );
    
    rtps_discovery_module_w_inst : entity Testbench_Lib2.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_w_inst : entity Testbench_Lib2.rtps_handler(arch)
        port map (
            -- SYSTEM
            clk                 => clk,
            reset               => reset,
            -- INPUT
            empty               => empty,
            rd                  => rd,
            data_in             => data_in,
            -- TO RTPS 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_w_inst : entity Testbench_Lib2.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_Lib2.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_Lib2.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_Lib2.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;