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

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

use work.math_pkg.all;
use work.rtps_package.all;
use work.user_config.all;
use work.rtps_config_package.all;

package rtps_test_package is
    
    constant RESULTS_FILE : string := "./Test_Results.txt";
    
    constant PARTICIPANT_FRAME_SIZE         : natural := 23;
    constant WRITER_ENDPOINT_FRAME_SIZE_A   : natural := 12;
    constant WRITER_ENDPOINT_FRAME_SIZE_B   : natural := 8;
    constant READER_ENDPOINT_FRAME_SIZE_A   : natural := 15;
    constant READER_ENDPOINT_FRAME_SIZE_B   : natural := 6;
    
    constant DEFAULT_GUIDPREFIX         : GUIDPREFIX_TYPE; -- Deferred to Package Body
    constant DEFAULT_READER_ENTITYID    : std_logic_vector(ENTITYID_WIDTH-1 downto 0); -- Deferred to Package Body
    constant DEFAULT_WRITER_ENTITYID    : std_logic_vector(ENTITYID_WIDTH-1 downto 0); -- Deferred to Package Body
    
    type MATCH_TYPE is (MATCH, UNMATCH);
    
    type TEST_PACKET_TYPE is record
        -- Limit Packet Size to 2^16 (IPv4 size limit)
        data    : WORD_ARRAY_TYPE(0 to (2**16)/4);
        last    : std_logic_vector(0 to (2**16)/4);
        length  : natural;
    end record;
    
    constant EMPTY_TEST_PACKET : TEST_PACKET_TYPE; -- Deferred to Package Body
    
    type TEST_MEMORY_ELEMENT_TYPE is record
        addr    : natural;
        data    : std_logic_vector(WORD_WIDTH-1 downto 0);
    end record;
    
    type TEST_MEMORY_TYPE is array (natural range <>) of TEST_MEMORY_ELEMENT_TYPE;
    
    subtype TEST_PARTICIPANT_MEMORY_FRAME_TYPE is TEST_MEMORY_TYPE(0 to PARTICIPANT_FRAME_SIZE-1);
    subtype TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_A is TEST_MEMORY_TYPE(0 to WRITER_ENDPOINT_FRAME_SIZE_A-1);
    subtype TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_B is TEST_MEMORY_TYPE(0 to WRITER_ENDPOINT_FRAME_SIZE_B-1);
    subtype TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_A is TEST_MEMORY_TYPE(0 to READER_ENDPOINT_FRAME_SIZE_A-1);
    subtype TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_B is TEST_MEMORY_TYPE(0 to READER_ENDPOINT_FRAME_SIZE_B-1);
    
    
    constant LOCATOR_PORT_WIDTH : natural := CDR_LONG_WIDTH;
    constant LOCATOR_ADDR_WIDTH : natural := 4*CDR_LONG_WIDTH;
    
    type LOCATOR_TYPE is record
        kind        : std_logic_vector(LOCATOR_KIND_WIDTH-1 downto 0);
        portn       : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        addr        : std_logic_vector(LOCATOR_ADDR_WIDTH-1 downto 0);
    end record;
    
    constant EMPTY_LOCATOR : LOCATOR_TYPE; -- Deferred to Package Body
    
    -- Limit Number of Locators to maximum number that fits in a maximum length RTPS Submessage
    type LOCATOR_TYPE_ARRAY is array (0 to ((2**16)/4)/6) of LOCATOR_TYPE;
    
    type LOCATOR_LIST_TYPE is record
        numLocators : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        locator     : LOCATOR_TYPE_ARRAY;
    end record;
    
    constant EMPTY_LOCATOR_LIST : LOCATOR_LIST_TYPE; -- Deferred to Package Body
    
    type SEQUENCENUMBER_SET_TYPE is record
        base    : SEQUENCENUMBER_TYPE;
        numBits : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        bitmap  : std_logic_vector(0 to 255);
    end record;
    
    constant DEFAULT_SEQUENCENUMBER_SET : SEQUENCENUMBER_SET_TYPE; -- Deferred to package Body
    
    type FRAGMENTNUMBER_SET_TYPE is record
        base    : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        numBits : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        bitmap  : std_logic_vector(0 to 255);
    end record;
    
    constant DEFAULT_FRAGMENTNUMBER_SET : FRAGMENTNUMBER_SET_TYPE; -- Deferred to Package Body
    
    -- Valid Destination Locators
    type DEST_LOCATOR_LIST_TYPE is record
        meta    : LOCATOR_LIST_TYPE;
        user    : LOCATOR_LIST_TYPE;
    end record;
    
    constant DEST_LOC : DEST_LOCATOR_LIST_TYPE; -- Deferred to Package Body
    
    -- *OUTPUT HEADER*
    type OUTPUT_HEADER_TYPE is record
        src     : LOCATOR_TYPE;
        dest    : LOCATOR_TYPE;
    end record;
    
    constant DEFAULT_OUTPUT_HEADER : OUTPUT_HEADER_TYPE; -- Deferred to Package Body
    
    -- *RTPS HEADER*
    type RTPS_HEADER_TYPE is record 
        protocol    : std_logic_vector(PROTOCOL_WIDTH-1 downto 0);
        version     : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0);
        vendorId    : std_logic_vector(VENDORID_WIDTH-1 downto 0);
        guidPrefix  : GUIDPREFIX_TYPE;
    end record;
    
    constant DEFAULT_RTPS_HEADER : RTPS_HEADER_TYPE; -- Deferred to Package Body
    
    -- *GENERIC RTPS SUBMESSAGE HEADER*
    type RTPS_SUBMESSAGE_TYPE is record
        submessageID            : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0);
        flags                   : std_logic_vector(SUBMESSAGE_FLAGS_WIDTH-1 downto 0);
        submessageLength        : std_logic_vector(SUBMESSAGE_LENGTH_WIDTH-1 downto 0);
        readerId                : std_logic_vector(ENTITYID_WIDTH-1 downto 0);
        writerId                : std_logic_vector(ENTITYID_WIDTH-1 downto 0);
        extraFlags              : std_logic_vector(SUBMESSAGE_DATA_EXTRA_FLAGS_WIDTH-1 downto 0);
        octetsToInlineQos       : std_logic_vector(SUBMESSAGE_LENGTH_WIDTH-1 downto 0);
        readerSNState           : SEQUENCENUMBER_SET_TYPE;
        count                   : std_logic_vector(COUNT_WIDTH-1 downto 0);
        writerSN                : SEQUENCENUMBER_TYPE;
        fragmentNumberState     : FRAGMENTNUMBER_SET_TYPE;
        inlineQos               : TEST_PACKET_TYPE;
        data                    : TEST_PACKET_TYPE;
        fragmentStartingNumber  : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        fragmentsInSubmessage   : std_logic_vector(CDR_SHORT_WIDTH-1 downto 0);
        fragmentSize            : std_logic_vector(CDR_SHORT_WIDTH-1 downto 0);
        sampleSize              : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        gapStart                : SEQUENCENUMBER_TYPE;
        gapList                 : SEQUENCENUMBER_SET_TYPE;
        firstSN                 : SEQUENCENUMBER_TYPE;
        lastSN                  : SEQUENCENUMBER_TYPE;
        lastFragmentNum         : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        guidPrefix              : GUIDPREFIX_TYPE;
        unicastLocatorList      : LOCATOR_LIST_TYPE;
        multicastLocatorList    : LOCATOR_LIST_TYPE;
        unicastLocator          : LOCATOR_TYPE;
        multicastLocator        : LOCATOR_TYPE;
        unused                  : std_logic_vector(31 downto 0);
        version                 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0);
        vendorId                : std_logic_vector(VENDORID_WIDTH-1 downto 0);
        timestamp               : TIME_TYPE;
    end record;
    
    constant DEFAULT_RTPS_SUBMESSAGE : RTPS_SUBMESSAGE_TYPE; -- Deferred to Package Body
    
    type PARTICIPANT_DATA_TYPE is record
        littleEndian                    : std_logic;
        domainId                        : std_logic_vector(DOMAIN_ID_WIDTH-1 downto 0);
        domainTag                       : STRING_WORD_ARRAY_TYPE;
        protocolVersion                 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0);
        vendorId                        : std_logic_vector(VENDORID_WIDTH-1 downto 0);
        guidPrefix                      : GUIDPREFIX_TYPE;
        entityId                        : std_logic_vector(ENTITYID_WIDTH-1 downto 0);
        expectsInlineQoS                : std_logic_vector(CDR_BOOLEAN_WIDTH-1 downto 0);
        metatrafficUnicastLocatorList   : LOCATOR_LIST_TYPE;
        metatrafficMulticastLocatorList : LOCATOR_LIST_TYPE;
        defaultUnicastLocatorList       : LOCATOR_LIST_TYPE;
        defaultMulticastLocatorList     : LOCATOR_LIST_TYPE;
        leaseDuration                   : DURATION_TYPE;
        manualLivelinessCount           : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        builtinEndpointQoS              : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        availableBuiltinEndpoints       : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        match                           : MATCH_TYPE;
        nr                              : natural;
    end record;
    
    constant DEFAULT_PARTICIPANT_DATA : PARTICIPANT_DATA_TYPE; -- Deferred to Pckage Body
    constant THIS_PARTICIPANT_DATA : PARTICIPANT_DATA_TYPE; -- Deferred to Pckage Body
    
    type ENDPOINT_DATA_TYPE is record
        reader                                          : boolean;
        littleEndian                                    : std_logic;
        participant                                     : PARTICIPANT_DATA_TYPE;
        entityId                                        : std_logic_vector(ENTITYID_WIDTH-1 downto 0);
        topic_name                                      : STRING_WORD_ARRAY_TYPE;
        type_name                                       : STRING_WORD_ARRAY_TYPE;
        durability                                      : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        durability_service_cleanup_delay                : DURATION_TYPE;
        durability_service_history                      : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        durability_service_history_depth                : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        durability_service_max_samples                  : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        durability_service_max_instances                : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        durability_service_max_samples_per_instances    : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        presentation                                    : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        coherent_access                                 : std_logic_vector(CDR_BOOLEAN_WIDTH-1 downto 0);
        ordered_access                                  : std_logic_vector(CDR_BOOLEAN_WIDTH-1 downto 0);
        deadline                                        : DURATION_TYPE;
        latency_budget                                  : DURATION_TYPE;
        ownership                                       : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        ownership_strength                              : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        liveliness                                      : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        leaseDuration                                   : DURATION_TYPE;
        time_based_filter                               : DURATION_TYPE;
        reliability                                     : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        max_blocking_time                               : DURATION_TYPE;
        transport_priority                              : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        lifespan                                        : DURATION_TYPE;
        destination_order                               : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
        -- Represent Data as Strings (Ease of Use)
        user_data                                       : STRING_WORD_ARRAY_TYPE;
        topic_data                                      : STRING_WORD_ARRAY_TYPE;
        group_data                                      : STRING_WORD_ARRAY_TYPE;
        expectsInlineQoS                                : std_logic_vector(CDR_BOOLEAN_WIDTH-1 downto 0);
        unicastLocatorList                              : LOCATOR_LIST_TYPE;
        multicastLocatorList                            : LOCATOR_LIST_TYPE;
        max_size_serialized                             : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
        match                                           : MATCH_TYPE;
        nr                                              : natural;
    end record;
    
    constant DEFAULT_ENDPOINT_DATA : ENDPOINT_DATA_TYPE; -- Deferred to Package Body
    type ENDPOINT_DATA_ARRAY_TYPE is array (natural range <>) of ENDPOINT_DATA_TYPE;
    
    type CACHE_CHANGE_TYPE is record
        serialized_key  : boolean;
        kind            : CACHE_CHANGE_KIND_TYPE;
        writer_guid     : GUID_TYPE;
        instance        : INSTANCE_HANDLE_TYPE;
        seq_nr          : SEQUENCENUMBER_TYPE;
        src_timestamp   : TIME_TYPE;
        payload         : TEST_PACKET_TYPE;
    end record;
    
    constant DEFAULT_CACHE_CHANGE : CACHE_CHANGE_TYPE; -- Deferred to Package Body
    
    type SAMPLE_TYPE is record
        inst            : INSTANCE_HANDLE_TYPE;
        data            : TEST_PACKET_TYPE;
        sstate          : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
        istate          : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        vstate          : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        dis_gen_cnt     : natural;
        no_w_gen_cnt    : natural;
        srank           : natural;
        grank           : natural;
        agrank          : natural;
        ts              : TIME_TYPE;
    end record;
    
    constant DEFAULT_SAMPLE : SAMPLE_TYPE; -- Deferred to Package Body
    
    type SAMPLE_ARRAY_TYPE is array (0 to 10) of SAMPLE_TYPE;
    
    type COLLECTION_TYPE is record
        s   : SAMPLE_ARRAY_TYPE;
        len : natural;
    end record;
    
    constant DEFAULT_COLLECTION : COLLECTION_TYPE; -- Deferred to Package Body
    
    type INSTANCE_CACHE_TYPE is record
        inst            : INSTANCE_HANDLE_TYPE;
        istate          : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        vstate          : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        dis_gen_cnt     : natural;
        no_w_gen_cnt    : natural;
    end record;
    
    constant DEFAULT_INSTANCE_CACHE_TYPE : INSTANCE_CACHE_TYPE; -- Deferred to Package Body
    
    type INSTANCE_CACHE_ARRAY_TYPE is array (0 to 10) of INSTANCE_CACHE_TYPE;
    
    type DDS_READER_MEM_TYPE is record
        s       : SAMPLE_ARRAY_TYPE;
        slen    : natural;
        inst    : INSTANCE_CACHE_ARRAY_TYPE;
        ilen    : natural;
    end record;
    
    constant DEFAULT_DDS_READER_MEM : DDS_READER_MEM_TYPE; -- Deferred to Package Body
    
    type DDS_READER_TEST_TYPE is record
        opcode      : DDS_READER_OPCODE_TYPE;
        sstate      : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0);
        istate      : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0);
        vstate      : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0);
        max_samples : natural;
        inst        : INSTANCE_HANDLE_TYPE;
        ret_code    : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
    end record;
    
    constant DEFAULT_DDS_READER_TEST : DDS_READER_TEST_TYPE; -- Deferred to Package Body
    
    type RTPS_WRITER_TEST_TYPE is record
        opcode      : HISTORY_CACHE_OPCODE_TYPE;
        cc          : CACHE_CHANGE_TYPE;
        ret_code    : HISTORY_CACHE_RESPONSE_TYPE;
    end record;
    
    constant DEFAULT_RTPS_WRITER_TEST : RTPS_WRITER_TEST_TYPE; -- Deferred to Package Body
    
    type RTPS_READER_TEST_TYPE is record
        opcode      : HISTORY_CACHE_OPCODE_TYPE;
        cc          : CACHE_CHANGE_TYPE;
        lifespan    : DURATION_TYPE;
        writer_pos  : natural;
        ret_code    : HISTORY_CACHE_RESPONSE_TYPE;
    end record;
    
    constant DEFAULT_RTPS_READER_TEST : RTPS_READER_TEST_TYPE; -- Deferred to Package Body
    
    type DDS_WRITER_TEST_TYPE is record
        opcode      : DDS_WRITER_OPCODE_TYPE;
        cc          : CACHE_CHANGE_TYPE;
        ret_code    : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
        count       : natural;
        change      : natural;
        inst        : INSTANCE_HANDLE_TYPE;
        assertion   : std_logic;
    end record;
    
    constant DEFAULT_DDS_WRITER_TEST : DDS_WRITER_TEST_TYPE; -- Deferred to Package Body
    
    function test_memory_match (A,B : TEST_MEMORY_TYPE) return boolean;
    function to_string (input : TEST_MEMORY_TYPE) return string;
    
    procedure gen_output_header(ref : in OUTPUT_HEADER_TYPE; output : inout TEST_PACKET_TYPE);
    procedure fix_output_packet(output : inout TEST_PACKET_TYPE);
    
    procedure gen_rtps_header( ref : in RTPS_HEADER_TYPE; output : inout TEST_PACKET_TYPE);
    
    procedure gen_rtps_submessage( ref : in RTPS_SUBMESSAGE_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_rtps_handler_out(ref : in RTPS_SUBMESSAGE_TYPE; loc : in LOCATOR_TYPE; is_meta : in boolean; ts : in TIME_TYPE; src_guid : in GUIDPREFIX_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_rtps_handler_out(ref : in RTPS_SUBMESSAGE_TYPE; participant : PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_rtps_handler_out(ref : in RTPS_SUBMESSAGE_TYPE; endpoint : ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    
    function gen_cache_change(ref : RTPS_SUBMESSAGE_TYPE) return CACHE_CHANGE_TYPE;
    procedure gen_add_cache_change_dds(ref : in CACHE_CHANGE_TYPE; lifespan_deadline : in TIME_TYPE; pos : in natural; output : inout TEST_PACKET_TYPE);
    
    procedure gen_participant_data( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_participant_data( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE; pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); offset : in integer);
    function gen_participant_mem_frame (ref : PARTICIPANT_DATA_TYPE) return TEST_PARTICIPANT_MEMORY_FRAME_TYPE;
    function gen_writer_endpoint_mem_frame_a (ref : ENDPOINT_DATA_TYPE) return TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_A;
    function gen_writer_endpoint_mem_frame_b (ref : ENDPOINT_DATA_TYPE) return TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_B;
    function gen_reader_endpoint_mem_frame_a (ref : ENDPOINT_DATA_TYPE) return TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_A;
    function gen_reader_endpoint_mem_frame_b (ref : ENDPOINT_DATA_TYPE) return TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_B;
    
    procedure gen_endpoint_data( ref : in ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_endpoint_data( ref : in ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE; pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); offset : in integer);
    procedure gen_endpoint_match_frame( ref : in ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_participant_match_frame( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_liveliness_update_frame( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE);
    function gen_endpoint(id : natural) return ENDPOINT_DATA_TYPE;
    function gen_endpoint_array(readers : boolean) return ENDPOINT_DATA_ARRAY_TYPE;
    
    procedure gen_liveliness_assertion(participant : in PARTICIPANT_DATA_TYPE; manual : in boolean; extra_data : in TEST_PACKET_TYPE; output : inout TEST_PACKET_TYPE);
    procedure gen_liveliness_assertion(participant : in PARTICIPANT_DATA_TYPE; manual : in boolean; output : inout TEST_PACKET_TYPE);
    
    procedure gen_sentinel(output : inout TEST_PACKET_TYPE);
    procedure gen_parameter(pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); data : in TEST_PACKET_TYPE; output : inout TEST_PACKET_TYPE);
    
    procedure gen_inline_qos(ref : in CACHE_CHANGE_TYPE; endpoint : in ENDPOINT_DATA_TYPE; expectsInlineQoS : in boolean; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE; pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); offset : in integer);
    procedure gen_inline_qos(ref : in CACHE_CHANGE_TYPE; endpoint : in ENDPOINT_DATA_TYPE; expectsInlineQoS : in boolean; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE);
    procedure gen_inline_qos(ref : in CACHE_CHANGE_TYPE; output : inout TEST_PACKET_TYPE);
    
    procedure gen_rand_loc(RV : inout RandomPType; ret : out LOCATOR_TYPE);
    procedure gen_rand_entityid(RV : inout RandomPType; reader : boolean; ret : out std_logic_vector(ENTITYID_WIDTH-1 downto 0));
    function int(n : integer; width : natural) return std_logic_vector;
    function to_string1 (input : std_logic_vector) return string;
    
    --procedure add_instance(inst : inout INSTANCE_HANDLE_TYPE; mem : inout DDS_READER_MEM_TYPE);
    function to_sample(cc : CACHE_CHANGE_TYPE; istate : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0)) return SAMPLE_TYPE;
    procedure change_istate(inst : INSTANCE_HANDLE_TYPE; istate : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); mem : inout DDS_READER_MEM_TYPE);
    procedure add_sample(sample : inout SAMPLE_TYPE; mem : inout DDS_READER_MEM_TYPE; DESTINATION_ORDER_QOS : in std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0));
    procedure remove_sample(ind : in natural; mem : inout DDS_READER_MEM_TYPE);
    procedure remove_inst(inst : in INSTANCE_HANDLE_TYPE; mem : inout DDS_READER_MEM_TYPE);
    --function check_instance(istate : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); vstate : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0); mem : DDS_READER_MEM_TYPE; inst : INSTANCE_HANDLE_TYPE) return boolean;
    --function find_instance(mem : DDS_READER_MEM_TYPE; inst : INSTANCE_HANDLE_TYPE) return natural;
    --procedure gen_collection (mem : inout DDS_READER_MEM_TYPE; col : inout COLLECTION_TYPE; inst : INSTANCE_HANDLE_TYPE; sstate : in std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0); istate : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); vstate : in std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0); max_samples : in natural; remove : in boolean; sort : in boolean);
    procedure gen_collection (mem : inout DDS_READER_MEM_TYPE; col : inout COLLECTION_TYPE; opcode : in DDS_READER_TEST_TYPE; PRESENTATION_QOS : in std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0); ordered : in boolean);
    
    -- NOTE: This assume a specific sending order (Multicast before Unicast)!
    function get_loc (ref : PARTICIPANT_DATA_TYPE; meta : boolean) return LOCATOR_TYPE;
    function get_loc (ref : ENDPOINT_DATA_TYPE) return LOCATOR_TYPE;
    
end package;

package body rtps_test_package is
    
    -- *UTILITY FUNCTIONS*
    procedure gen_rand_loc(RV : inout RandomPType; ret : out LOCATOR_TYPE) is
    begin
        ret                                     := EMPTY_LOCATOR;
        ret.kind                                := LOCATOR_KIND_UDPv4;
        ret.portn(UDP_PORT_WIDTH-1 downto 0)    := RV.RandSlv(UDP_PORT_WIDTH);
        ret.addr(IPv4_ADDRESS_WIDTH-1 downto 0) := RV.RandSlv(IPv4_ADDRESS_WIDTH);
    end procedure;
    
    procedure gen_rand_entityid(RV : inout RandomPType; reader : boolean; ret : out std_logic_vector(ENTITYID_WIDTH-1 downto 0)) is
    begin
        ret                     := RV.RandSlv(ENTITYID_WIDTH);
        ret(ENTITY_KIND_H_RANGE):= USER_DEFINED_ENTITY;
        if (reader) then
            ret(ENTITY_KIND_L_RANGE):= READER_NO_KEY;
        else
            ret(ENTITY_KIND_L_RANGE):= WRITER_NO_KEY;
        end if;
    end procedure;
    
    function int(n : integer; width : natural) return std_logic_vector is
    begin
        return std_logic_vector(to_signed(n, width));
    end function;
    
    -- *DEFERRED DEFINITIONS*
    
    constant DEFAULT_GUIDPREFIX : GUIDPREFIX_TYPE := (0 => x"da27cc3c", 1 => x"687ddcde", 2 => x"88bce3d1");
    
    constant DEFAULT_READER_ENTITYID   : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := x"b9cbad04";
    constant DEFAULT_WRITER_ENTITYID   : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := x"b9cbad03";
    
    constant EMPTY_TEST_PACKET : TEST_PACKET_TYPE := (length => 0, data => (others => (others => '0')), last => (others => '0'));
    
    constant EMPTY_LOCATOR : LOCATOR_TYPE := (
        kind        => LOCATOR_KIND_INVALID,
        portn       => (others => '0'),
        addr        => (others => '0')
    );
    
    constant EMPTY_LOCATOR_LIST : LOCATOR_LIST_TYPE := (
        numLocators => (others => '0'),
        locator     => (others => EMPTY_LOCATOR)
    );
    
    constant DEFAULT_SEQUENCENUMBER_SET : SEQUENCENUMBER_SET_TYPE := (
        base    => FIRST_SEQUENCENUMBER,
        numBits => (others => '0'),
        bitmap  => (others => '0')
    );
    
    constant DEFAULT_FRAGMENTNUMBER_SET : FRAGMENTNUMBER_SET_TYPE := (
        base    => int(1,CDR_LONG_WIDTH),
        numBits => (others => '0'),
        bitmap  => (others => '0')
    );
    
    constant DEST_LOC : DEST_LOCATOR_LIST_TYPE := (
        meta => (
            numLocators => int(4,CDR_LONG_WIDTH),
            locator     => (
                0 => (
                    kind    => LOCATOR_KIND_UDPv4,
                    portn   => (LOCATOR_PORT_WIDTH-1 downto UDP_PORT_WIDTH => '0') & META_IPv4_MULTICAST_PORT,
                    addr    => (LOCATOR_ADDR_WIDTH-1 downto IPv4_ADDRESS_WIDTH => '0') & DEFAULT_IPv4_META_ADDRESS
                ), 
                1 => (
                    kind    => LOCATOR_KIND_UDPv4,
                    portn   => (LOCATOR_PORT_WIDTH-1 downto UDP_PORT_WIDTH => '0') & META_IPv4_UNICAST_PORT,
                    addr    => (LOCATOR_ADDR_WIDTH-1 downto IPv4_ADDRESS_WIDTH => '0') & DEFAULT_IPv4_META_ADDRESS
                ),
                2 => (
                    kind    => LOCATOR_KIND_UDPv4,
                    portn   => (LOCATOR_PORT_WIDTH-1 downto UDP_PORT_WIDTH => '0') & META_IPv4_MULTICAST_PORT,
                    addr    => (LOCATOR_ADDR_WIDTH-1 downto IPv4_ADDRESS_WIDTH => '0') & DEFAULT_IPv4_ADDRESS
                ), 
                3 => (
                    kind    => LOCATOR_KIND_UDPv4,
                    portn   => (LOCATOR_PORT_WIDTH-1 downto UDP_PORT_WIDTH => '0') & META_IPv4_UNICAST_PORT,
                    addr    => (LOCATOR_ADDR_WIDTH-1 downto IPv4_ADDRESS_WIDTH => '0') & DEFAULT_IPv4_ADDRESS
                ),
                others => EMPTY_LOCATOR
            )
        ),
        user => (
            numLocators => int(2,CDR_LONG_WIDTH),
            locator     => (
                0 => (
                    kind    => LOCATOR_KIND_UDPv4,
                    portn   => (LOCATOR_PORT_WIDTH-1 downto UDP_PORT_WIDTH => '0') & USER_IPv4_MULTICAST_PORT,
                    addr    => (LOCATOR_ADDR_WIDTH-1 downto IPv4_ADDRESS_WIDTH => '0') & DEFAULT_IPv4_ADDRESS
                ), 
                1 => (
                    kind    => LOCATOR_KIND_UDPv4,
                    portn   => (LOCATOR_PORT_WIDTH-1 downto UDP_PORT_WIDTH => '0') & USER_IPv4_UNICAST_PORT,
                    addr    => (LOCATOR_ADDR_WIDTH-1 downto IPv4_ADDRESS_WIDTH => '0') & DEFAULT_IPv4_ADDRESS
                ),
                others => EMPTY_LOCATOR
            )
        )
    );
    
    constant DEFAULT_OUTPUT_HEADER : OUTPUT_HEADER_TYPE := (
        src     => EMPTY_LOCATOR,
        dest    => EMPTY_LOCATOR
    );
    
    constant DEFAULT_RTPS_HEADER : RTPS_HEADER_TYPE := (
        protocol    => PROTOCOL_RTPS,
        version     => PROTOCOLVERSION_2_4,
        vendorId    => VENDORID_UNKNOWN,
        guidPrefix  => DEFAULT_GUIDPREFIX
    );
    
    constant DEFAULT_RTPS_SUBMESSAGE : RTPS_SUBMESSAGE_TYPE := (
        submessageID            => (others => '0'),
        flags                   => (others => '0'),
        submessageLength        => (others => '1'),
        readerId                => ENTITYID_UNKNOWN,
        writerId                => ENTITYID_UNKNOWN,
        readerSNState           => DEFAULT_SEQUENCENUMBER_SET,
        count                   => int(1,COUNT_WIDTH),
        extraFlags              => (others => '0'),
        octetsToInlineQos       => int(16, SUBMESSAGE_LENGTH_WIDTH),
        writerSN                => FIRST_SEQUENCENUMBER,
        fragmentNumberState     => DEFAULT_FRAGMENTNUMBER_SET,
        inlineQos               => EMPTY_TEST_PACKET,
        data                    => EMPTY_TEST_PACKET,
        fragmentStartingNumber  => int(1,CDR_LONG_WIDTH),
        fragmentsInSubmessage   => int(1,CDR_SHORT_WIDTH),
        fragmentSize            => (others => '0'),
        sampleSize              => (others => '0'),
        gapStart                => FIRST_SEQUENCENUMBER,
        gapList                 => DEFAULT_SEQUENCENUMBER_SET,
        firstSN                 => FIRST_SEQUENCENUMBER,
        lastSN                  => (others => (others => '0')),
        lastFragmentNum         => int(1,CDR_LONG_WIDTH),
        guidPrefix              => DEFAULT_GUIDPREFIX,
        unicastLocatorList      => EMPTY_LOCATOR_LIST,
        multicastLocatorList    => EMPTY_LOCATOR_LIST,
        unicastLocator          => EMPTY_LOCATOR,
        multicastLocator        => EMPTY_LOCATOR,
        unused                  => (others => '0'),
        version                 => PROTOCOLVERSION_2_4,
        vendorId                => VENDORID_UNKNOWN,
        timestamp               => TIME_ZERO
    );
    
    constant DEFAULT_PARTICIPANT_DATA : PARTICIPANT_DATA_TYPE := (
        littleEndian                    => '0',
        domainId                        => DOMAIN_ID,
        domainTag                       => DOMAIN_TAG,
        protocolVersion                 => PROTOCOLVERSION_2_4,
        vendorId                        => VENDORID_UNKNOWN,
        guidPrefix                      => GUIDPREFIX_UNKNOWN,
        entityId                        => ENTITYID_PARTICIPANT,
        expectsInlineQoS                => (others => '0'),
        metatrafficUnicastLocatorList   => EMPTY_LOCATOR_LIST,
        metatrafficMulticastLocatorList => EMPTY_LOCATOR_LIST,
        defaultUnicastLocatorList       => EMPTY_LOCATOR_LIST, -- NOTE: Has to be initialized
        defaultMulticastLocatorList     => EMPTY_LOCATOR_LIST,
        leaseDuration                   => PARTICIPANT_LEASE_DURATION,
        manualLivelinessCount           => (others => '0'),
        builtinEndpointQoS              => (others => '0'),
        availableBuiltinEndpoints       => (DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER => '1', DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR => '1', BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER => '1', BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER => '1', others => '0'),
        match                           => MATCH,
        nr                              => 0
    );
    
    constant THIS_PARTICIPANT_DATA : PARTICIPANT_DATA_TYPE := (
        littleEndian                    => '0',
        domainId                        => DOMAIN_ID,
        domainTag                       => DOMAIN_TAG,
        protocolVersion                 => PROTOCOLVERSION_2_4,
        vendorId                        => VENDORID_UNKNOWN,
        guidPrefix                      => GUIDPREFIX,
        entityId                        => ENTITYID_PARTICIPANT,
        expectsInlineQoS                => (others => '0'),
        metatrafficUnicastLocatorList   => (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => DEST_LOC.meta.locator(3), others => EMPTY_LOCATOR)),
        metatrafficMulticastLocatorList => (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => DEST_LOC.meta.locator(2), others => EMPTY_LOCATOR)),
        defaultUnicastLocatorList       => (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => DEST_LOC.user.locator(1), others => EMPTY_LOCATOR)),
        defaultMulticastLocatorList     => (numLocators => int(1,CDR_LONG_WIDTH), locator => (0 => DEST_LOC.user.locator(0), others => EMPTY_LOCATOR)),
        leaseDuration                   => PARTICIPANT_LEASE_DURATION,
        manualLivelinessCount           => (others => '0'),
        builtinEndpointQoS              => (others => '0'),
        availableBuiltinEndpoints       => (DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER => '1', DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR => '1', BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER => '1', BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER => '1', DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER => '1', DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR => '1', DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER => '1', DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR => '1', others => '0'),
        match                           => MATCH,
        nr                              => 0
    );
    
    constant DEFAULT_ENDPOINT_DATA : ENDPOINT_DATA_TYPE := (
        reader                                          => TRUE,
        littleEndian                                    => '0',
        participant                                     => DEFAULT_PARTICIPANT_DATA,
        entityId                                        => DEFAULT_READER_ENTITYID,
        topic_name                                      => EMPTY_STRING,
        type_name                                       => EMPTY_STRING,
        durability                                      => DEFAULT_DURABILITY_QOS,
        durability_service_cleanup_delay                => DEFAULT_DURABILITY_SERVICE_CLEANUP_DELAY,
        durability_service_history                      => DEFAULT_DURABILITY_SERVICE_HISTORY,
        durability_service_history_depth                => DEFAULT_DURABILITY_SERVICE_HISTORY_DEPTH,
        durability_service_max_samples                  => DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES,
        durability_service_max_instances                => DEFAULT_DURABILITY_SERVICE_MAX_INSTANCES,
        durability_service_max_samples_per_instances    => DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE,
        presentation                                    => DEFAULT_PRESENTATION_QOS,
        coherent_access                                 => (0 => boolean_to_std_logic(DEFAULT_COHERENT_ACCESS), others => '0'),
        ordered_access                                  => (0 => boolean_to_std_logic(DEFAULT_ORDERED_ACCESS), others => '0'),
        deadline                                        => DEFAULT_DEADLINE_QOS,
        latency_budget                                  => DEFAULT_LATENCY_BUDGET_QOS,
        ownership                                       => DEFAULT_OWNERSHIP_QOS,
        ownership_strength                              => DEFAULT_OWNERSHIP_STRENGTH_QOS,
        liveliness                                      => DEFAULT_LIVELINESS_QOS,
        leaseDuration                                   => DEFAULT_LEASE_DURATION,
        time_based_filter                               => DEFAULT_TIME_BASED_FILTER_QOS,
        reliability                                     => DEFAULT_RELIABILTY_QOS,
        max_blocking_time                               => DEFAULT_MAX_BLOCKING_TIME,
        transport_priority                              => DEFAULT_TRANSPORT_PRIORITY_QOS,
        lifespan                                        => DEFAULT_LIFESPAN_QOS,
        destination_order                               => DEFAULT_DESTINATION_ORDER_QOS,
        user_data                                       => EMPTY_STRING,
        topic_data                                      => EMPTY_STRING,
        group_data                                      => EMPTY_STRING,
        expectsInlineQoS                                => (others => '0'),
        unicastLocatorList                              => EMPTY_LOCATOR_LIST,
        multicastLocatorList                            => EMPTY_LOCATOR_LIST,
        max_size_serialized                             => (others => '0'),
        match                                           => MATCH,
        nr                                              => 0
    );
    
    constant DEFAULT_CACHE_CHANGE : CACHE_CHANGE_TYPE := (
        serialized_key  => FALSE,
        kind            => ALIVE,
        writer_guid     => GUID_UNKNOWN,
        instance        => HANDLE_NIL,
        seq_nr          => SEQUENCENUMBER_UNKNOWN,
        src_timestamp   => TIME_INVALID,
        payload         => EMPTY_TEST_PACKET
    );
    
    constant DEFAULT_SAMPLE : SAMPLE_TYPE := (
        inst            => HANDLE_NIL,
        data            => EMPTY_TEST_PACKET,
        sstate          => NOT_READ_SAMPLE_STATE,
        istate          => ALIVE_INSTANCE_STATE,
        vstate          => NEW_VIEW_STATE,
        dis_gen_cnt     => 0,
        no_w_gen_cnt    => 0,
        srank           => 0,
        grank           => 0,
        agrank          => 0,
        ts              => TIME_INVALID
    );
    
    constant DEFAULT_COLLECTION : COLLECTION_TYPE := (
        s   => (others => DEFAULT_SAMPLE),
        len => 0
    );
    
    constant DEFAULT_INSTANCE_CACHE_TYPE : INSTANCE_CACHE_TYPE := (
        inst            => HANDLE_NIL,
        istate          => ALIVE_INSTANCE_STATE,
        vstate          => NEW_VIEW_STATE,
        dis_gen_cnt     => 0,
        no_w_gen_cnt    => 0
    );
    
    constant DEFAULT_DDS_READER_MEM : DDS_READER_MEM_TYPE := (
        s       => (others => DEFAULT_SAMPLE),
        slen    => 0,
        inst    => (others => DEFAULT_INSTANCE_CACHE_TYPE),
        ilen    => 0
    );
    
    constant DEFAULT_DDS_READER_TEST : DDS_READER_TEST_TYPE := (
        opcode      => NOP,
        sstate      => ANY_SAMPLE_STATE,
        istate      => ANY_INSTANCE_STATE,
        vstate      => ANY_VIEW_STATE,
        max_samples => 1,
        inst        => HANDLE_NIL,
        ret_code    => RETCODE_OK
    );
    
    constant DEFAULT_RTPS_WRITER_TEST : RTPS_WRITER_TEST_TYPE := (
        opcode      => NOP,
        cc          => DEFAULT_CACHE_CHANGE,
        ret_code    => OK
    );
    
    constant DEFAULT_RTPS_READER_TEST : RTPS_READER_TEST_TYPE := (
        opcode      => NOP,
        cc          => DEFAULT_CACHE_CHANGE,
        lifespan    => DURATION_INFINITE,
        writer_pos  => 0,
        ret_code    => OK
    );
    
    constant DEFAULT_DDS_WRITER_TEST : DDS_WRITER_TEST_TYPE := (
        opcode      => NOP,
        cc          => DEFAULT_CACHE_CHANGE,
        ret_code    => RETCODE_OK,
        count       => 0,
        change      => 0,
        inst        => HANDLE_NIL,
        assertion   => '0'
    );
    
    -- *PACKAGE INTERNAL HELPER FUNCTIONS*
    
    procedure store_byte(in_off : in natural range 0 to 3; input : in std_logic_vector(WORD_WIDTH-1 downto 0); out_off : in natural range 0 to 3; output : inout TEST_PACKET_TYPE) is
    begin
        output.data(output.length)((BYTE_WIDTH*out_off)+BYTE_WIDTH-1 downto (BYTE_WIDTH*out_off)) := input((BYTE_WIDTH*in_off)+BYTE_WIDTH-1 downto (BYTE_WIDTH*in_off));
    end procedure;
    
    procedure gen_output_header(ref : in OUTPUT_HEADER_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- IPv4 Source Address
        output.data(output.length)  := ref.src.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
        output.length               := output.length + 1;
        -- IPv4 Destination Address
        output.data(output.length)  := ref.dest.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
        output.length               := output.length + 1;
        -- Source Port & Destination Port
        output.data(output.length)  := ref.src.portn(UDP_PORT_WIDTH-1 downto 0) & ref.dest.portn(UDP_PORT_WIDTH-1 downto 0);
        output.length               := output.length + 1;
        -- Packet Length
        output.data(output.length)  := (others => '0');
        output.length               := output.length + 1;
    end procedure;
    
    procedure fix_output_packet(output : inout TEST_PACKET_TYPE) is
    begin
        assert (output.length < 2**UDP_PORT_WIDTH) report "Exceeded maximum UDP Packet Size" severity error;
        -- Fix Packet Length
        output.data(3)  := int(output.length-4, WORD_WIDTH);
    end procedure;
    
    procedure gen_rtps_header( ref : in RTPS_HEADER_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- Protocol
        output.data(output.length) := ref.protocol;
        output.length       := output.length + 1;
        -- Protocol Version & Vendor ID
        output.data(output.length) := ref.version & ref.vendorId;
        output.length       := output.length + 1;
        -- GUID Prefix
        output.data(output.length) := ref.guidPrefix(0);
        output.length       := output.length + 1;
        output.data(output.length) := ref.guidPrefix(1);
        output.length       := output.length + 1;
        output.data(output.length) := ref.guidPrefix(2);
        output.length       := output.length + 1;
    end procedure;
    
    procedure write_sequence_ns(input : in SEQUENCENUMBER_SET_TYPE; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE) is
    begin
        -- Sequence Number State (Base)
        output.data(output.length) := endian_swap(littleEndian, std_logic_vector(input.base(0)));
        output.length       := output.length + 1;
        output.data(output.length) := endian_swap(littleEndian, std_logic_vector(input.base(1)));
        output.length       := output.length + 1;
        -- Sequence Number State (NumBits)
        assert (unsigned(input.numBits) <= 256) report "SequenceNS.numbits is higher than 256." severity warning;
        output.data(output.length) := endian_swap(littleEndian, input.numBits);
        output.length       := output.length + 1;
        -- Sequence Number State (Bitmap)
        for i in 0 to round_div(to_integer(unsigned(input.numBits)),WORD_WIDTH)-1 loop
            if (i < MAX_BITMAP_WIDTH/WORD_WIDTH) then
                output.data(output.length) := endian_swap(littleEndian, input.bitmap(i*32 to i*32+31));
                output.length       := output.length + 1;
            end if;
        end loop;
    end procedure;
    
    procedure write_fragment_ns(input : in FRAGMENTNUMBER_SET_TYPE; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE) is
    begin
        -- Sequence Number State (Base)
        output.data(output.length) := endian_swap(littleEndian, input.base);
        output.length       := output.length + 1;
        -- Sequence Number State (NumBits)
        assert (unsigned(input.numBits) <= 256) report "SequenceNS.numbits is higher than 256." severity warning;
        output.data(output.length) := endian_swap(littleEndian, input.numBits);
        output.length       := output.length + 1;
        -- Sequence Number State (Bitmap)
        for i in 0 to round_div(to_integer(unsigned(input.numBits)),WORD_WIDTH)-1 loop
            if (i < MAX_BITMAP_WIDTH/WORD_WIDTH) then
                output.data(output.length) := endian_swap(littleEndian, input.bitmap(i*32 to i*32+31));
                output.length       := output.length + 1;
            end if;
        end loop;
    end procedure;
    
    procedure write_locator_list(input : in LOCATOR_LIST_TYPE; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE) is
    begin
        -- NumLocators
        output.data(output.length) := endian_swap(littleEndian, input.numLocators);
        output.length       := output.length + 1;
        for i in 0 to to_integer(unsigned(input.numLocators))-1 loop
            -- Kind
            output.data(output.length) := endian_swap(littleEndian, input.locator(i).kind);
            output.length       := output.length + 1;
            -- Port
            output.data(output.length) := endian_swap(littleEndian, input.locator(i).portn);
            output.length       := output.length + 1;
            -- Address
            output.data(output.length) := input.locator(i).addr(127 downto 96);
            output.length       := output.length + 1;
            output.data(output.length) := input.locator(i).addr(95 downto 64);
            output.length       := output.length + 1;
            output.data(output.length) := input.locator(i).addr(63 downto 32);
            output.length       := output.length + 1;
            output.data(output.length) := input.locator(i).addr(31 downto 0);
            output.length       := output.length + 1;
        end loop;
    end procedure;
    
    function is_valid_loc (ref : LOCATOR_TYPE) return boolean is
    begin
        if (ref.kind /= LOCATOR_KIND_UDPv4) then
            return FALSE;
        elsif (ref.addr(IPv4_ADDRESS_WIDTH-1 downto 0) = (IPv4_ADDRESS_WIDTH-1 downto 0 => '0')) then
            return FALSE;
        elsif (ref.portn(UDP_PORT_WIDTH-1 downto 0) = (UDP_PORT_WIDTH-1 downto 0 => '0')) then
            return FALSE;
        else
            return TRUE;
        end if;
    end function;
    
    function get_loc (ref : LOCATOR_LIST_TYPE) return LOCATOR_TYPE is
        variable ret : LOCATOR_TYPE := EMPTY_LOCATOR;
    begin
        for i in 0 to to_integer(unsigned(ref.numLocators))-1 loop
            if (is_valid_loc(ref.locator(i))) then
                ret := ref.locator(i);
            end if;
        end loop;
        
        return ret;
    end function;
    
    function get_loc (ref : PARTICIPANT_DATA_TYPE; meta : boolean) return LOCATOR_TYPE is
    begin
        if (meta) then
            if (is_valid_loc(get_loc(ref.metatrafficUnicastLocatorList))) then
                return get_loc(ref.metatrafficUnicastLocatorList);
            elsif (is_valid_loc(get_loc(ref.metatrafficMulticastLocatorList))) then
                return get_loc(ref.metatrafficMulticastLocatorList);
            else
                return DEST_LOC.meta.locator(0);
            end if;
        else
            if (is_valid_loc(get_loc(ref.defaultUnicastLocatorList))) then
                return get_loc(ref.defaultUnicastLocatorList);
            elsif (is_valid_loc(get_loc(ref.defaultMulticastLocatorList))) then
                return get_loc(ref.defaultMulticastLocatorList);
            else
                return EMPTY_LOCATOR;
            end if;
        end if;
    end function;
    
    function get_loc (ref : ENDPOINT_DATA_TYPE) return LOCATOR_TYPE is
    begin
        if (is_valid_loc(get_loc(ref.unicastLocatorList))) then
            return get_loc(ref.unicastLocatorList);
        elsif (is_valid_loc(get_loc(ref.multicastLocatorList))) then
            return get_loc(ref.multicastLocatorList);
        elsif (is_valid_loc(get_loc(ref.participant.defaultUnicastLocatorList))) then
            return get_loc(ref.participant.defaultUnicastLocatorList);
        elsif (is_valid_loc(get_loc(ref.participant.defaultMulticastLocatorList))) then
            return get_loc(ref.participant.defaultMulticastLocatorList);
        else
            assert FALSE report "Endpoint has no valid Locators" severity FAILURE;
            return EMPTY_LOCATOR;
        end if;
    end function;
    
    procedure gen_rtps_submessage( ref : in RTPS_SUBMESSAGE_TYPE; output : inout TEST_PACKET_TYPE) is
        variable start  : natural := 0;
        variable tmp    : natural := 0;
    begin
        -- *GENERAL*
        start               := output.length;
        -- Submessage ID & Submessage Flags & Submessage Length
        output.data(output.length) := ref.submessageID & ref.flags & endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.submessageLength);
        output.length       := output.length + 1;
        
        -- *DATA/DATA_FRAG*
        if (ref.submessageID = SID_DATA or ref.submessageID = SID_DATA_FRAG) then
            -- Extra Flags & octetsToInlineQos
            output.data(output.length) := ref.extraFlags & endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.octetsToInlineQos);
            output.length       := output.length + 1;
        end if;
        
        -- *ACKNACK/NACK_FRAG/HEARTBEAT/HEARTBEAT_FRAG/GAP/DATA/DATA_FRAG*
        if (ref.submessageID = SID_ACKNACK or ref.submessageID = SID_NACK_FRAG or ref.submessageID = SID_HEARTBEAT or ref.submessageID = SID_HEARTBEAT_FRAG or ref.submessageID = SID_GAP or ref.submessageID = SID_DATA or ref.submessageID = SID_DATA_FRAG) then
            -- Reader ID
            output.data(output.length) := ref.readerId;
            output.length       := output.length + 1;
            -- Writer ID
            output.data(output.length) := ref.writerId;
            output.length       := output.length + 1;
        end if;
        
        -- *NACK_FRAG/DATA/DATA_FRAG/HEARTBEAT_FRAG*
        if (ref.submessageID = SID_NACK_FRAG or ref.submessageID = SID_DATA or ref.submessageID = SID_DATA_FRAG or ref.submessageID = SID_HEARTBEAT_FRAG) then
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.writerSN(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.writerSN(1)));
            output.length       := output.length + 1;
        end if;
        
        -- *ACKNACK*
        if (ref.submessageID = SID_ACKNACK) then
            -- Reader State
            write_sequence_ns(ref.readerSNState, ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), output);
        -- *NACK_FRAG*
        elsif (ref.submessageID = SID_NACK_FRAG) then
            -- Fragment Number State
            write_fragment_ns(ref.fragmentNumberState, ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), output);
        -- *HEARTBEAT*
        elsif (ref.submessageID = SID_HEARTBEAT) then
            -- First Sequence Number
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.firstSN(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.firstSN(1)));
            output.length       := output.length + 1;
            -- Last Sequence Number
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.lastSN(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.lastSN(1)));
            output.length       := output.length + 1;
        -- *HEARTBEAT_FRAG*
        elsif (ref.submessageID = SID_HEARTBEAT_FRAG) then
            -- Last Fargment Number
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.lastFragmentNum);
            output.length       := output.length + 1;
        end if;
        
        -- *ACKNACK/NACK_FRAG/HEARTBEAT/HEARTBEAT_FRAG*
        if (ref.submessageID = SID_ACKNACK or ref.submessageID = SID_HEARTBEAT or ref.submessageID = SID_NACK_FRAG or ref.submessageID = SID_HEARTBEAT_FRAG) then
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.count);
            output.length       := output.length + 1;
        end if;
        
        -- *GAP*
        if (ref.submessageID = SID_GAP) then
            -- Gap Start
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.gapStart(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.gapStart(1)));
            output.length       := output.length + 1;
            -- Gap List
            write_sequence_ns(ref.gapList, ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), output);
        end if;
        
        -- *DATA_FRAG*
        if (ref.submessageID = SID_DATA_FRAG) then
            -- Fragment Number
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.fragmentStartingNumber);
            output.length       := output.length + 1;
            -- FragmentsinSubmessage & FragmentSize
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.fragmentsInSubmessage) & endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.fragmentSize);
            output.length       := output.length + 1;
            -- Sample Size
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.sampleSize);
            output.length       := output.length + 1;
        end if;
        
        -- *DATA/DATA_FRAG*
        if (ref.submessageID = SID_DATA or ref.submessageID = SID_DATA_FRAG) then
            -- EXTRA HEADER
            tmp := to_integer(unsigned(ref.octetsToInlineQos)) - 16;
            if (tmp > 0) then
                for i in 0 to tmp-1 loop
                    store_byte((i+1) mod 4, x"DEADBEEF", (i+1) mod 4, output);
                    if (i mod 4 = 3) then
                        output.length       := output.length + 1;
                        output.data(output.length) := (others => '0');
                    end if;
                end loop;
            end if;
            -- INLINE QOS
            if (ref.inlineQos.length > 0) then
                for i in 0 to (ref.inlineQos.length*4)-1 loop
                    store_byte((i+tmp) mod 4, ref.inlineQos.data(i/4), i mod 4, output);
                    if ((i+tmp) mod 4 = 3) then
                        output.length       := output.length + 1;
                        output.data(output.length) := (others => '0');
                    end if;
                end loop;
            end if;
            -- DATA
            if (ref.data.length > 0) then
                for i in 0 to (ref.data.length*4)-1 loop
                    store_byte((i+tmp) mod 4, ref.data.data(i/4), i mod 4, output);
                    if ((i+tmp) mod 4 = 3) then
                        output.length       := output.length + 1;
                        output.data(output.length) := (others => '0');
                    end if;
                end loop;
            end if;
            -- Fix Alignement
            if ((tmp + (ref.data.length*4)) mod 4 /= 0) then
                output.length       := output.length + 1;
            end if;
        end if;
        
        -- *INFO_SRC*
        if (ref.submessageID = SID_INFO_SRC) then
            -- UNUSED
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.unused);
            output.length       := output.length + 1;
            -- Protocol Version & Vendor ID
            output.data(output.length) := ref.version & ref.vendorId;
            output.length       := output.length + 1;
        -- *INFO_REPLY*
        elsif (ref.submessageID = SID_INFO_REPLY) then
            write_locator_list(ref.unicastLocatorList, ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), output);
            if (ref.flags(SUBMESSAGE_MULTICAST_FLAG_POS) = '1') then
                write_locator_list(ref.multicastLocatorList, ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), output);
            end if;
        -- *INFO_REPLY_IP4*
        elsif (ref.submessageID = SID_INFO_REPLY_IP4) then
            -- Unicast Locator (Address)
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.unicastLocator.addr(CDR_LONG_WIDTH-1 downto 0));
            output.length       := output.length + 1;
            -- Unicast Locator (Port)
            output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.unicastLocator.portn);
            output.length       := output.length + 1;
            if (ref.flags(SUBMESSAGE_MULTICAST_FLAG_POS) = '1') then
                -- Multicast Locator (Address)
                output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.multicastLocator.addr(CDR_LONG_WIDTH-1 downto 0));
                output.length       := output.length + 1;
                -- Multicast Locator (Port)
                output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), ref.multicastLocator.portn);
                output.length       := output.length + 1;
            end if;
        -- *INFO_TS*
        elsif (ref.submessageID = SID_INFO_TS) then
            -- Timestamp
            if (ref.flags(SUBMESSAGE_INVALIDATE_FLAG_POS) = '0') then
                output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.timestamp(0)));
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), std_logic_vector(ref.timestamp(1)));
                output.length       := output.length + 1;
            end if;
        end if;
        
        -- *INFO_DEST/INFO_SRC*
        if (ref.submessageID = SID_INFO_DST or ref.submessageID = SID_INFO_SRC) then
            -- GUID Prefix
            output.data(output.length) := ref.guidPrefix(0);
            output.length       := output.length + 1;
            output.data(output.length) := ref.guidPrefix(1);
            output.length       := output.length + 1;
            output.data(output.length) := ref.guidPrefix(2);
            output.length       := output.length + 1;
        end if;
        
        -- *ACKNACK/NACK_FRAG/HEARTBEAT/HEARTBEAT_FRAG/GAP/DATA/DATA_FRAG*
        if (ref.submessageID = SID_ACKNACK or ref.submessageID = SID_NACK_FRAG or ref.submessageID = SID_HEARTBEAT or ref.submessageID = SID_HEARTBEAT_FRAG or ref.submessageID = SID_GAP or ref.submessageID = SID_DATA or ref.submessageID = SID_DATA_FRAG or ref.submessageID = SID_INFO_TS or ref.submessageID = SID_INFO_SRC or ref.submessageID = SID_INFO_DST or ref.submessageID = SID_INFO_REPLY or ref.submessageID =SID_INFO_REPLY_IP4) then
            -- NOTE: A Submessage Length of 0 is left as is.
            -- Fix Submessage Length
            if (ref.submessageLength = (ref.submessageLength'range => '1')) then
                output.data(start)(SUBMESSAGE_LENGTH_WIDTH-1 downto 0) := endian_swap(ref.flags(SUBMESSAGE_ENDIAN_FLAG_POS), int((output.length-start-1)*4,SUBMESSAGE_LENGTH_WIDTH));
            -- Fix(Truncate/Extend) Packet Length to specified Length
            elsif (ref.submessageLength /= (ref.submessageLength'range => '0')) then
                output.length := start + to_integer(unsigned(ref.submessageLength));
            end if;
        -- *PAD/UKNOWN*
        else
            -- Padding
            tmp := to_integer(unsigned(ref.submessageLength));
            assert (tmp mod 4 = 0) report "Padding Length has to be multiple of four" severity FAILURE;
            for i in 0 to (tmp/4)-1 loop
                output.data(output.length) := (others => '0');
                output.length       := output.length + 1;
            end loop;
        end if;
    end procedure;
    
    procedure gen_rtps_handler_out(ref : in RTPS_SUBMESSAGE_TYPE; loc : in LOCATOR_TYPE; is_meta : in boolean; ts : in TIME_TYPE; src_guid : in GUIDPREFIX_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- Opcode & Flags & Source Port
        output.data(output.length) := ref.submessageID & ref.flags & loc.portn(UDP_PORT_WIDTH-1 downto 0);
        output.length       := output.length + 1;
        -- Source Address
        output.data(output.length) := loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
        output.length       := output.length + 1;
        -- Source GUID Prefix
        output.data(output.length) := src_guid(0);
        output.length       := output.length + 1;
        output.data(output.length) := src_guid(1);
        output.length       := output.length + 1;
        output.data(output.length) := src_guid(2);
        output.length       := output.length + 1;
        -- Source Entity ID
        if (ref.submessageID = SID_ACKNACK or ref.submessageID = SID_NACK_FRAG) then
            output.data(output.length) := ref.readerId;
            output.length       := output.length + 1;
        else
            output.data(output.length) := ref.writerId;
            output.length       := output.length + 1;
        end if;
        -- Destination Enity ID
        if (is_meta) then
            if (ref.submessageID = SID_ACKNACK or ref.submessageID = SID_NACK_FRAG) then
                output.data(output.length) := ref.writerId;
                output.length       := output.length + 1;
            else
                output.data(output.length) := ref.readerId;
                output.length       := output.length + 1;
            end if;
        end if;
        
        -- *DATA*
        if (ref.submessageID = SID_DATA) then
            -- Sequence Number
            output.data(output.length) := std_logic_vector(ref.writerSN(0));
            output.length       := output.length + 1;
            output.data(output.length) := std_logic_vector(ref.writerSN(1));
            output.length       := output.length + 1;
            -- Timestamp
            if (not is_meta) then
                output.data(output.length) := std_logic_vector(ts(0));
                output.length       := output.length + 1;
                output.data(output.length) := std_logic_vector(ts(1));
                output.length       := output.length + 1;
            end if;
            -- INLINE QOS
            if (ref.inlineQos.length > 0) then
                for i in 0 to ref.inlineQos.length-1 loop
                    output.data(output.length) := ref.inlineQos.data(i);
                    output.length       := output.length + 1;
                end loop;
            end if;
            -- DATA PAYLOAD
            if (ref.data.length > 0) then
                for i in 0 to ref.data.length-1 loop
                    output.data(output.length) := ref.data.data(i);
                    output.length       := output.length + 1;
                end loop;
            end if;
        end if;
        
        -- *ACKNACK*
        if (ref.submessageID = SID_ACKNACK) then
            -- Reader State
            write_sequence_ns(ref.readerSNState, '0', output);
        -- *HEARTBEAT*
        elsif (ref.submessageID = SID_HEARTBEAT) then
            -- First Sequence Number
            output.data(output.length) := std_logic_vector(ref.firstSN(0));
            output.length       := output.length + 1;
            output.data(output.length) := std_logic_vector(ref.firstSN(1));
            output.length       := output.length + 1;
            -- Last Sequence Number
            output.data(output.length) := std_logic_vector(ref.lastSN(0));
            output.length       := output.length + 1;
            output.data(output.length) := std_logic_vector(ref.lastSN(1));
            output.length       := output.length + 1;
        end if;
        
        -- *ACKNACK/HEARTBEAT*
        if (ref.submessageID = SID_ACKNACK or ref.submessageID = SID_HEARTBEAT) then
            output.data(output.length) := ref.count;
            output.length       := output.length + 1;
        end if;
        
        -- *GAP*
        if (ref.submessageID = SID_GAP) then
            -- Gap Start
            output.data(output.length) := std_logic_vector(ref.gapStart(0));
            output.length       := output.length + 1;
            output.data(output.length) := std_logic_vector(ref.gapStart(1));
            output.length       := output.length + 1;
            -- Gap List
            write_sequence_ns(ref.gapList, '0', output);
            -- UNUSED
            output.data(output.length)  := (others => '0');
            output.length               := output.length + 1;
        end if;
        
        -- Mark Last Word
        output.last(output.length-1)    := '1';
    end procedure;
    
    procedure gen_rtps_handler_out(ref : in RTPS_SUBMESSAGE_TYPE; participant : PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        gen_rtps_handler_out(ref, get_loc(participant, TRUE), TRUE, TIME_INVALID, participant.guidPrefix, output);
    end procedure;
    
    procedure gen_rtps_handler_out(ref : in RTPS_SUBMESSAGE_TYPE; endpoint : ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        gen_rtps_handler_out(ref, get_loc(endpoint.participant, TRUE), TRUE, TIME_INVALID, endpoint.participant.guidPrefix, output);
    end procedure;
    
    function gen_cache_change(ref : RTPS_SUBMESSAGE_TYPE) return CACHE_CHANGE_TYPE is
        variable ret : CACHE_CHANGE_TYPE := DEFAULT_CACHE_CHANGE;
    begin
        assert(ref.submessageID = SID_DATA) report "Cache Change can only be derived from DATA Submessages." severity FAILURE;
        ret.seq_nr          := ref.writerSN;
        ret.payload         := ref.data;
        ret.serialized_key  := TRUE when (ref.flags(SUBMESSAGE_KEY_FLAG_POS) = '1') else FALSE;
        return ret;
    end function;
    
    procedure gen_add_cache_change_dds(ref : in CACHE_CHANGE_TYPE; lifespan_deadline : in TIME_TYPE; pos : in  natural; output : inout TEST_PACKET_TYPE) is
    begin
        -- Status Info
        output.data(output.length)  := (others => '0');
        case (ref.kind) is
            when ALIVE_FILTERED =>
                output.data(output.length)(SSI_FILTERED_FLAG)   := '1';
            when NOT_ALIVE_DISPOSED =>
                output.data(output.length)(SSI_DISPOSED_FLAG)   := '1';
            when NOT_ALIVE_UNREGISTERED =>
                output.data(output.length)(SSI_UNREGISTERED_FLAG)   := '1';
            when others =>
                null;
        end case;
        if (ref.payload.length > 0 and (not ref.serialized_key)) then
            output.data(output.length)(SSI_PAYLOAD_FLAG)    := '1';
        end if;
        if (ref.instance /= HANDLE_NIL) then
            output.data(output.length)(SSI_KEY_HASH_FLAG)   := '1';
        end if;
        output.length   := output.length + 1;
        -- Source Timestamp
        output.data(output.length)  := std_logic_vector(ref.src_timestamp(0));
        output.length               := output.length + 1;
        output.data(output.length)  := std_logic_vector(ref.src_timestamp(1));
        output.length               := output.length + 1;
        -- Lifespan Deadline
        output.data(output.length)  := std_logic_vector(lifespan_deadline(0));
        output.length               := output.length + 1;
        output.data(output.length)  := std_logic_vector(lifespan_deadline(1));
        output.length               := output.length + 1;
        -- Key Hash
        if (ref.instance /= HANDLE_NIL) then
            output.data(output.length)  := ref.instance(0);
            output.length               := output.length + 1;
            output.data(output.length)  := ref.instance(1);
            output.length               := output.length + 1;
            output.data(output.length)  := ref.instance(2);
            output.length               := output.length + 1;
            output.data(output.length)  := ref.instance(3);
            output.length               := output.length + 1;
        end if;
        -- Remote Writer Endpoint Position
        output.data(output.length)  := std_logic_vector(to_unsigned(pos, WORD_WIDTH));
        output.length               := output.length + 1;
        -- Payload
        -- NOTE: Do not send Serialized Key if Key Hash is available
        if (ref.payload.length > 0 and (not (ref.serialized_key and ref.instance /= HANDLE_NIL))) then
            for i in 0 to ref.payload.length-1 loop
                output.data(output.length)  := ref.payload.data(i);
                output.length               := output.length + 1;
            end loop;
        end if;
        -- Mark Last Word
        output.last(output.length-1)    := '1';
    end procedure;
    
    procedure gen_liveliness_assertion(participant : in PARTICIPANT_DATA_TYPE; manual : in boolean; extra_data : in TEST_PACKET_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- Representation Identifier & Representation Options
        output.data(output.length)  := CDR_BE & x"0000";
        output.length               := output.length + 1;
        -- GUID Prefix
        output.data(output.length)  := participant.guidPrefix(0);
        output.length               := output.length + 1;
        output.data(output.length)  := participant.guidPrefix(1);
        output.length               := output.length + 1;
        output.data(output.length)  := participant.guidPrefix(2);
        output.length               := output.length + 1;
        -- Participant Message Kind
        if (manual) then
            output.data(output.length)  := PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE;
        else
            output.data(output.length)  := PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE;
        end if;
        output.length   := output.length + 1;
        -- DATA Length
        output.data(output.length)  := int(extra_data.length, WORD_WIDTH);
        output.length               := output.length + 1;
        for i in 0 to extra_data.length-1 loop
            output.data(output.length)  := extra_data.data(i);
            output.length               := output.length + 1;
        end loop;
    end procedure;
    
    procedure gen_liveliness_assertion(participant : in PARTICIPANT_DATA_TYPE; manual : in boolean; output : inout TEST_PACKET_TYPE) is
    begin
        gen_liveliness_assertion(participant, manual, EMPTY_TEST_PACKET, output);
    end procedure;
    
    procedure gen_participant_data( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE; pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); offset : in integer) is
        variable tmp : natural := 0;
    begin
        -- Representation Identifier & Representation Options
        if (ref.littleEndian = '0') then
            output.data(output.length) := PL_CDR_BE & x"0000";
        else
            output.data(output.length) := PL_CDR_LE & x"0000";
        end if;
        output.length       := output.length + 1;
        -- GUID
        if (pid = PID_PARTICIPANT_GUID) then
            assert (16+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_PARTICIPANT_GUID & endian_swap(ref.littleEndian, int(16+(offset*4), PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_PARTICIPANT_GUID & endian_swap(ref.littleEndian, int(16, PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := ref.guidPrefix(0);
        output.length       := output.length + 1;
        output.data(output.length) := ref.guidPrefix(1);
        output.length       := output.length + 1;
        output.data(output.length) := ref.guidPrefix(2);
        output.length       := output.length + 1;
        output.data(output.length) := ref.entityId;
        output.length       := output.length + 1;
        if (pid = PID_PARTICIPANT_GUID) then
            output.length       := output.length + offset;
        end if;
        -- DOMAIN ID
        if (pid = PID_DOMAIN_ID) then
            assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_DOMAIN_ID & endian_swap(ref.littleEndian, int(4+(offset*4), PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_DOMAIN_ID & endian_swap(ref.littleEndian, int(4, PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := endian_swap(ref.littleEndian, ref.domainId);
        output.length       := output.length + 1;
        if (pid = PID_DOMAIN_ID) then
            output.length       := output.length + offset;
        end if;
        -- DOMAIN TAG
        if (ref.domainTag /= DEFAULT_DOMAIN_TAG or pid = PID_DOMAIN_TAG) then
            tmp                 := string_len(ref.domainTag);
            if (pid = PID_DOMAIN_TAG) then
                assert (((round_div(tmp,4)+1)*4)+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_DOMAIN_TAG & endian_swap(ref.littleEndian, int(((round_div(tmp,4)+1)*4)+(offset*4), PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_DOMAIN_TAG & endian_swap(ref.littleEndian, int((round_div(tmp,4)+1)*4, PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, int(tmp, CDR_LONG_WIDTH));
            output.length       := output.length + 1;
            for i in 0 to round_div(tmp,4)-1 loop
                output.data(output.length) := ref.domainTag(i);
                output.length       := output.length + 1;
            end loop;
            if (pid = PID_DOMAIN_TAG) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- PROTOCOL VERSION
        if (pid = PID_PROTOCOL_VERSION) then
            assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_PROTOCOL_VERSION & endian_swap(ref.littleEndian, int(4+(offset*4), PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_PROTOCOL_VERSION & endian_swap(ref.littleEndian, int(4, PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length)                 := (others => '0');
        output.data(output.length)(31 downto 16)   := ref.protocolVersion;
        output.length       := output.length + 1;
        if (pid = PID_PROTOCOL_VERSION) then
            output.length       := output.length + offset;
        end if;
        -- VENDORID
        if (pid = PID_VENDORID) then
            assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_VENDORID & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_VENDORID & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length)                 := (others => '0');
        output.data(output.length)(31 downto 16)   := ref.vendorId;
        output.length                       := output.length + 1;
        if (pid = PID_VENDORID) then
            output.length       := output.length + offset;
        end if;
        -- EXPECTS IN-LINE QOS
        if (ref.expectsInlineQoS(0) /= DEFAULT_EXPECTS_INLINE_QOS or pid = PID_EXPECTS_INLINE_QOS) then
            if (pid = PID_EXPECTS_INLINE_QOS) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_EXPECTS_INLINE_QOS & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_EXPECTS_INLINE_QOS & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length)                 := (others => '0');
            output.data(output.length)(31 downto 24)   := ref.expectsInlineQoS; -- 1 Byte, No endian swap
            output.length                       := output.length + 1;
            if (pid = PID_EXPECTS_INLINE_QOS) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- METATRAFFIC MULTICAST LOCATOR
        if (ref.metatrafficMulticastLocatorList.numLocators /= (ref.metatrafficMulticastLocatorList.numLocators'range => '0')) then
            tmp                 := to_integer(unsigned(ref.metatrafficMulticastLocatorList.numLocators));
            for i in 0 to tmp-1 loop
                if (pid = PID_METATRAFFIC_MULTICAST_LOCATOR) then
                    assert (24+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_METATRAFFIC_MULTICAST_LOCATOR & endian_swap(ref.littleEndian, int(24+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_METATRAFFIC_MULTICAST_LOCATOR & endian_swap(ref.littleEndian, int(24,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;            
                output.data(output.length) := endian_swap(ref.littleEndian, ref.metatrafficMulticastLocatorList.locator(i).kind);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.metatrafficMulticastLocatorList.locator(i).portn);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficMulticastLocatorList.locator(i).addr(127 downto 96);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficMulticastLocatorList.locator(i).addr(95 downto 64);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficMulticastLocatorList.locator(i).addr(63 downto 32);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficMulticastLocatorList.locator(i).addr(31 downto 0);
                output.length       := output.length + 1;
                if (pid = PID_METATRAFFIC_MULTICAST_LOCATOR) then
                    output.length       := output.length + offset;
                end if;
            end loop;
        end if;
        -- METATRAFFIC UNICAST LOCATOR
        if (ref.metatrafficUnicastLocatorList.numLocators /= (ref.metatrafficUnicastLocatorList.numLocators'range => '0')) then
            tmp                 := to_integer(unsigned(ref.metatrafficUnicastLocatorList.numLocators));
            for i in 0 to tmp-1 loop
                if (pid = PID_METATRAFFIC_UNICAST_LOCATOR) then
                    assert (24+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_METATRAFFIC_UNICAST_LOCATOR & endian_swap(ref.littleEndian, int(24+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_METATRAFFIC_UNICAST_LOCATOR & endian_swap(ref.littleEndian, int(24,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;            
                output.data(output.length) := endian_swap(ref.littleEndian, ref.metatrafficUnicastLocatorList.locator(i).kind);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.metatrafficUnicastLocatorList.locator(i).portn);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficUnicastLocatorList.locator(i).addr(127 downto 96);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficUnicastLocatorList.locator(i).addr(95 downto 64);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficUnicastLocatorList.locator(i).addr(63 downto 32);
                output.length       := output.length + 1;
                output.data(output.length) := ref.metatrafficUnicastLocatorList.locator(i).addr(31 downto 0);
                output.length       := output.length + 1;
                if (pid = PID_METATRAFFIC_UNICAST_LOCATOR) then
                    output.length       := output.length + offset;
                end if;
            end loop;
        end if;
        -- DEFAULT MULTICAST LOCATOR
        if (ref.defaultMulticastLocatorList.numLocators /= (ref.defaultMulticastLocatorList.numLocators'range => '0')) then
            tmp                 := to_integer(unsigned(ref.defaultMulticastLocatorList.numLocators));
            for i in 0 to tmp-1 loop
                if (pid = PID_DEFAULT_MULTICAST_LOCATOR) then
                    assert (24+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_DEFAULT_MULTICAST_LOCATOR & endian_swap(ref.littleEndian, int(24+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_DEFAULT_MULTICAST_LOCATOR & endian_swap(ref.littleEndian, int(24,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.defaultMulticastLocatorList.locator(i).kind);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.defaultMulticastLocatorList.locator(i).portn);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultMulticastLocatorList.locator(i).addr(127 downto 96);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultMulticastLocatorList.locator(i).addr(95 downto 64);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultMulticastLocatorList.locator(i).addr(63 downto 32);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultMulticastLocatorList.locator(i).addr(31 downto 0);
                output.length       := output.length + 1;
                if (pid = PID_DEFAULT_MULTICAST_LOCATOR) then
                    output.length       := output.length + offset;
                end if;
            end loop;
        end if;
        -- DEFAULT UNICAST LOCATOR
        assert (unsigned(ref.defaultUnicastLocatorList.numLocators) > 0) report "PARTICIPANT_DATA: Participant needs to have at least one Default Unicast Locator." severity error;
        if (ref.defaultUnicastLocatorList.numLocators /= (ref.defaultUnicastLocatorList.numLocators'range => '0')) then
            tmp                 := to_integer(unsigned(ref.defaultUnicastLocatorList.numLocators));
            for i in 0 to tmp-1 loop
                if (pid = PID_DEFAULT_UNICAST_LOCATOR) then
                    assert (24+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_DEFAULT_UNICAST_LOCATOR & endian_swap(ref.littleEndian, int(24+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_DEFAULT_UNICAST_LOCATOR & endian_swap(ref.littleEndian, int(24,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;            
                output.data(output.length) := endian_swap(ref.littleEndian, ref.defaultUnicastLocatorList.locator(i).kind);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.defaultUnicastLocatorList.locator(i).portn);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultUnicastLocatorList.locator(i).addr(127 downto 96);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultUnicastLocatorList.locator(i).addr(95 downto 64);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultUnicastLocatorList.locator(i).addr(63 downto 32);
                output.length       := output.length + 1;
                output.data(output.length) := ref.defaultUnicastLocatorList.locator(i).addr(31 downto 0);
                output.length       := output.length + 1;
                if (pid = PID_DEFAULT_UNICAST_LOCATOR) then
                    output.length       := output.length + offset;
                end if;
            end loop;
        end if;
        -- LEASE DURATION
        if (ref.leaseDuration /= DEFAULT_PARTICIPANT_LEASE_DURATION or pid = PID_PARTICIPANT_LEASE_DURATION) then
            if (pid = PID_PARTICIPANT_LEASE_DURATION) then
                assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_PARTICIPANT_LEASE_DURATION & endian_swap(ref.littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_PARTICIPANT_LEASE_DURATION & endian_swap(ref.littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.leaseDuration(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.leaseDuration(1)));
            output.length       := output.length + 1;
            if (pid = PID_PARTICIPANT_LEASE_DURATION) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- AVAILABLE ENDPOINTS
        if (pid = PID_BUILTIN_ENDPOINT_SET) then
            assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_BUILTIN_ENDPOINT_SET & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_BUILTIN_ENDPOINT_SET & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := endian_swap(ref.littleEndian, ref.availableBuiltinEndpoints);
        output.length       := output.length + 1;
        if (pid = PID_BUILTIN_ENDPOINT_SET) then
            output.length       := output.length + offset;
        end if;
        -- BUILTIN ENDPOINT QOS
        if (ref.builtinEndpointQoS /= DEFAULT_BUILTIN_ENDPOINT_QOS or pid = PID_BUILTIN_ENDPOINT_QOS) then
            if (pid = PID_BUILTIN_ENDPOINT_QOS) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_BUILTIN_ENDPOINT_QOS & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_BUILTIN_ENDPOINT_QOS & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.builtinEndpointQoS);
            output.length       := output.length + 1;
            if (pid = PID_BUILTIN_ENDPOINT_QOS) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- MANUAL LIVELINESS COUNT
        if (pid = PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT) then
            assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := endian_swap(ref.littleEndian, ref.manualLivelinessCount);
        output.length       := output.length + 1;
        if (pid = PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT) then
            output.length       := output.length + offset;
        end if;
    end procedure;
    
    procedure gen_participant_data( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        gen_participant_data(ref, output, PID_PAD, 0);
    end procedure;
    
    function gen_participant_mem_frame (ref : PARTICIPANT_DATA_TYPE) return TEST_PARTICIPANT_MEMORY_FRAME_TYPE is
        variable ret        : TEST_PARTICIPANT_MEMORY_FRAME_TYPE;
        variable start      : natural;
        variable meta_loc   : LOCATOR_TYPE;
        variable user_loc   : LOCATOR_TYPE;
    begin
        ret := (others => (addr => 0, data => (others => '0')));
        
        -- Calculate Start Address
        start := PARTICIPANT_FRAME_SIZE * ref.nr;
        
        -- Fetch relevant Locators
        meta_loc    := get_loc (ref, TRUE);
        user_loc    := get_loc (ref, FALSE);
        
        for i in 0 to PARTICIPANT_FRAME_SIZE-1 loop
            ret(i).addr := start + i;
            case (i) is
                -- GUID Prefix 1/3
                when 0 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.guidPrefix(0);
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- GUID Prefix 2/3
                when 1 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.guidPrefix(1);
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- GUID Prefix 3/3
                when 2 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.guidPrefix(2);
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- METATRAFFIC IPv4 Address
                when 3 =>
                    if (ref.match = MATCH) then
                        ret(i).data := meta_loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- DEFAULT IPv4 Address
                when 4 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- METATRAFFIC & DEFAULT UDP Port
                when 5 =>
                    if (ref.match = MATCH) then
                        ret(i).data := meta_loc.portn(UDP_PORT_WIDTH-1 downto 0) & user_loc.portn(UDP_PORT_WIDTH-1 downto 0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Lease Duration 1/2
                when 8 =>
                    if (ref.match = MATCH) then
                        ret(i).data := std_logic_vector(ref.leaseDuration(0));
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Lease Duration 2/2
                when 9 =>
                    if (ref.match = MATCH) then
                        ret(i).data := std_logic_vector(ref.leaseDuration(1));
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- EXTRA FLAGS
                when 12 =>
                    if (ref.match = MATCH) then
                        ret(i).data := (0 => ref.expectsInlineQoS(0), others => '-');
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Other Fields Ignored
                when others =>
                    ret(i).data := (others => '-');
            end case;
        end loop;
        return ret;
    end function;
    
    function gen_writer_endpoint_mem_frame_a (ref : ENDPOINT_DATA_TYPE) return TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_A is
        variable ret        : TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_A;
        variable start      : natural;
        variable user_loc   : LOCATOR_TYPE;
    begin
        ret := (others => (addr => 0, data => (others => '0')));
        
        -- Calculate Start Address
        start := WRITER_ENDPOINT_FRAME_SIZE_A * ref.nr;
        
        -- Fetch relevant Locators
        user_loc    := get_loc (ref);
        
        for i in 0 to WRITER_ENDPOINT_FRAME_SIZE_A-1 loop
            ret(i).addr := start + i;
            case (i) is
                -- Entity ID
                when 0 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.entityId;
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- GUID Prefix 1/3
                when 1 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 2/3
                when 2 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(1);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 3/3
                when 3 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(2);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- IPv4 Address
                when 4 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- UDP Port
                when 5 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.portn(UDP_PORT_WIDTH-1 downto 0) & (UDP_PORT_WIDTH-1 downto 0 => '0');
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Other Fields Ignored
                when others =>
                    ret(i).data := (others => '-');
            end case;
        end loop;
        return ret;
    end function;
    
    
    function gen_writer_endpoint_mem_frame_b (ref : ENDPOINT_DATA_TYPE) return TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_B is
        variable ret        : TEST_WRITER_ENDPOINT_MEMORY_FRAME_TYPE_B;
        variable start      : natural;
        variable user_loc   : LOCATOR_TYPE;
    begin
        ret := (others => (addr => 0, data => (others => '0')));
        
        -- Calculate Start Address
        start := WRITER_ENDPOINT_FRAME_SIZE_B * ref.nr;
        
        -- Fetch relevant Locators
        user_loc    := get_loc (ref);
        
        for i in 0 to WRITER_ENDPOINT_FRAME_SIZE_B-1 loop
            ret(i).addr := start + i;
            case (i) is
                -- Entity ID
                when 0 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.entityId;
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- GUID Prefix 1/3
                when 1 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 2/3
                when 2 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(1);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 3/3
                when 3 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(2);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Other Fields Ignored
                when others =>
                    ret(i).data := (others => '-');
            end case;
        end loop;
        return ret;
    end function;
    
    function gen_reader_endpoint_mem_frame_a (ref : ENDPOINT_DATA_TYPE) return TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_A is
        variable ret        : TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_A;
        variable start      : natural;
        variable user_loc   : LOCATOR_TYPE;
    begin
        ret := (others => (addr => 0, data => (others => '0')));
        
        -- Calculate Start Address
        start := READER_ENDPOINT_FRAME_SIZE_A * ref.nr;
        
        -- Fetch relevant Locators
        user_loc    := get_loc (ref);
        
        for i in 0 to READER_ENDPOINT_FRAME_SIZE_A-1 loop
            ret(i).addr := start + i;
            case (i) is
                -- Entity ID
                when 0 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.entityId;
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- GUID Prefix 1/3
                when 1 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 2/3
                when 2 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(1);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 3/3
                when 3 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(2);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- IPv4 Address
                when 4 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- UDP Port
                when 5 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.portn(UDP_PORT_WIDTH-1 downto 0) & (UDP_PORT_WIDTH-1 downto 0 => '0');
                        ret(i).data(READER_EXPECTS_INLINE_QOS_FLAG)         := ref.expectsInlineQoS(0);
                        ret(i).data(READER_EXPECTS_HISTORICAL_DATA_FLAG)    := '1' when (ref.durability /= VOLATILE_DURABILITY_QOS) else '0';
                        ret(i).data(READER_IS_BEST_EFFORT_FLAG)             := '1' when (ref.reliability = BEST_EFFORT_RELIABILITY_QOS) else '0';
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Other Fields Ignored
                when others =>
                    ret(i).data := (others => '-');
            end case;
        end loop;
        return ret;
    end function;
    
    function gen_reader_endpoint_mem_frame_b (ref : ENDPOINT_DATA_TYPE) return TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_B is
        variable ret        : TEST_READER_ENDPOINT_MEMORY_FRAME_TYPE_B;
        variable start      : natural;
        variable user_loc   : LOCATOR_TYPE;
    begin
        ret := (others => (addr => 0, data => (others => '0')));
        
        -- Calculate Start Address
        start := READER_ENDPOINT_FRAME_SIZE_B * ref.nr;
        
        -- Fetch relevant Locators
        user_loc    := get_loc (ref);
        
        for i in 0 to READER_ENDPOINT_FRAME_SIZE_B-1 loop
            ret(i).addr := start + i;
            case (i) is
                -- Entity ID
                when 0 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.entityId;
                    else
                        ret(i).data := (others => '0');
                    end if;
                -- GUID Prefix 1/3
                when 1 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 2/3
                when 2 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(1);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- GUID Prefix 3/3
                when 3 =>
                    if (ref.match = MATCH) then
                        ret(i).data := ref.participant.guidPrefix(2);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- IPv4 Address
                when 4 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- UDP Port
                when 5 =>
                    if (ref.match = MATCH) then
                        ret(i).data := user_loc.portn(UDP_PORT_WIDTH-1 downto 0) & (UDP_PORT_WIDTH-1 downto 0 => '0');
                        ret(i).data(READER_EXPECTS_INLINE_QOS_FLAG)         := ref.expectsInlineQoS(0);
                        ret(i).data(READER_EXPECTS_HISTORICAL_DATA_FLAG)    := '1' when (ref.durability /= VOLATILE_DURABILITY_QOS) else '0';
                        ret(i).data(READER_IS_BEST_EFFORT_FLAG)             := '1' when (ref.reliability = BEST_EFFORT_RELIABILITY_QOS) else '0';
                    else
                        ret(i).data := (others => '-');
                    end if;
                -- Other Fields Ignored
                when others =>
                    ret(i).data := (others => '-');
            end case;
        end loop;
        return ret;
    end function;
    
    procedure gen_participant_match_frame( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- OPCODE
        case (ref.match) is
            when MATCH =>
                report "No Endpoint Frame generated on Participant match" severity WARNING;
                return;
            when UNMATCH =>
                output.data(output.length)  := OPCODE_PARTICIPANT_UNMATCH;
                output.length               := output.length + 1;
            when others => 
                null;
        end case;
        -- GUID Prefix
        output.data(output.length)  := ref.guidPrefix(0);
        output.length               := output.length + 1;
        output.data(output.length)  := ref.guidPrefix(1);
        output.length               := output.length + 1;
        output.data(output.length)  := ref.guidPrefix(2);
        output.length               := output.length + 1;
        
        -- Mark Last Word
        output.last(output.length-1)    := '1';
    end procedure;
    
    procedure gen_liveliness_update_frame( ref : in PARTICIPANT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- OPCODE
        output.data(output.length)  := OPCODE_LIVELINESS_UPDATE;
        output.length               := output.length + 1;
        -- GUID Prefix
        output.data(output.length)  := ref.guidPrefix(0);
        output.length               := output.length + 1;
        output.data(output.length)  := ref.guidPrefix(1);
        output.length               := output.length + 1;
        output.data(output.length)  := ref.guidPrefix(2);
        output.length               := output.length + 1;
        
        -- Mark Last Word
        output.last(output.length-1)    := '1';
    end procedure;
    
    -- The Arguments "pid" and "offset" can be used to modify the parameter generation. More specifically, the length of the parameter denoted by "pid" is modified by "offset" 4-Byte words.
    -- Also setting "pid" forces the respective parameter to be writen out even if it is equal to the default value.
    procedure gen_endpoint_data( ref : in ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE; pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); offset : in integer) is
        variable tmp : natural := 0;
    begin
        -- Representation Identifier & Representation Options
        if (ref.littleEndian = '0') then
            output.data(output.length) := PL_CDR_BE & x"0000";
        else
            output.data(output.length) := PL_CDR_LE & x"0000";
        end if;
        output.length       := output.length + 1;
        -- GUID
        if (pid = PID_ENDPOINT_GUID) then
            assert (16+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_ENDPOINT_GUID & endian_swap(ref.littleEndian, int(16+(offset*4),PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_ENDPOINT_GUID & endian_swap(ref.littleEndian, int(16,PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := ref.participant.guidPrefix(0);
        output.length       := output.length + 1;
        output.data(output.length) := ref.participant.guidPrefix(1);
        output.length       := output.length + 1;
        output.data(output.length) := ref.participant.guidPrefix(2);
        output.length       := output.length + 1;
        output.data(output.length) := ref.entityId;
        output.length       := output.length + 1;
        if (pid = PID_ENDPOINT_GUID) then
            output.length       := output.length + offset;
        end if;
        -- EXPECTS IN-LINE QOS
        if (ref.expectsInlineQoS(0) /= DEFAULT_EXPECTS_INLINE_QOS or pid = PID_EXPECTS_INLINE_QOS) then
            if (pid = PID_EXPECTS_INLINE_QOS) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_EXPECTS_INLINE_QOS & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_EXPECTS_INLINE_QOS & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length)                 := (others => '0');
            output.data(output.length)(31 downto 24)   := ref.expectsInlineQoS; -- 1 Byte, No endian swap
            output.length                       := output.length + 1;
            if (pid = PID_EXPECTS_INLINE_QOS) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- TOPIC NAME
        tmp := string_len(ref.topic_name);
        if (pid = PID_TOPIC_NAME) then
            assert (((round_div(tmp,4)+1)*4)+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_TOPIC_NAME & endian_swap(ref.littleEndian, int(((round_div(tmp,4)+1)*4)+(offset*4),PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_TOPIC_NAME & endian_swap(ref.littleEndian, int((round_div(tmp,4)+1)*4,PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := endian_swap(ref.littleEndian, int(tmp, CDR_LONG_WIDTH));
        output.length       := output.length + 1;
        for i in 0 to round_div(tmp,4)-1 loop
            output.data(output.length) := ref.topic_name(i);
            output.length       := output.length + 1;
        end loop;
        if (pid = PID_TOPIC_NAME) then
            output.length       := output.length + offset;
        end if;
        -- TYPE NAME
        tmp := string_len(ref.type_name);
        if (pid = PID_TYPE_NAME) then
            assert (((round_div(tmp,4)+1)*4)+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
            output.data(output.length) := PID_TYPE_NAME & endian_swap(ref.littleEndian, int(((round_div(tmp,4)+1)*4)+(offset*4),PARAMETER_LENGTH_WIDTH));
        else
            output.data(output.length) := PID_TYPE_NAME & endian_swap(ref.littleEndian, int((round_div(tmp,4)+1)*4,PARAMETER_LENGTH_WIDTH));
        end if;
        output.length       := output.length + 1;
        output.data(output.length) := endian_swap(ref.littleEndian, int(tmp,CDR_LONG_WIDTH));
        output.length       := output.length + 1;
        for i in 0 to round_div(tmp,4)-1 loop
            output.data(output.length) := ref.type_name(i);
            output.length       := output.length + 1;
        end loop;
        if (pid = PID_TYPE_NAME) then
            output.length       := output.length + offset;
        end if;
        -- DURABILITY
        if (ref.durability /= DEFAULT_DURABILITY_QOS or pid = PID_DURABILITY) then
            if (pid = PID_DURABILITY) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_DURABILITY & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_DURABILITY & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.durability);
            output.length       := output.length + 1;
            if (pid = PID_DURABILITY) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- DURABILITY SERVICE
        if (ref.durability_service_cleanup_delay /= DEFAULT_DURABILITY_SERVICE_CLEANUP_DELAY or ref.durability_service_history /= DEFAULT_DURABILITY_SERVICE_HISTORY or 
        ref.durability_service_history_depth /= DEFAULT_DURABILITY_SERVICE_HISTORY_DEPTH or ref.durability_service_max_samples /= DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES or 
        ref.durability_service_max_instances /= DEFAULT_DURABILITY_SERVICE_MAX_INSTANCES or ref.durability_service_max_samples_per_instances /= DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE or pid = PID_DURABILITY_SERVICE) then
            if (pid = PID_DURABILITY_SERVICE) then
                assert (28+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_DURABILITY_SERVICE & endian_swap(ref.littleEndian, int(28+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_DURABILITY_SERVICE & endian_swap(ref.littleEndian, int(28,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.durability_service_cleanup_delay(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.durability_service_cleanup_delay(1)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.durability_service_history);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.durability_service_history_depth);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.durability_service_max_samples);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.durability_service_max_instances);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.durability_service_max_samples_per_instances);
            output.length       := output.length + 1;
            if (pid = PID_DURABILITY_SERVICE) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- PRESENTATION
        if (ref.presentation /= DEFAULT_PRESENTATION_QOS or ref.coherent_access(0) /= boolean_to_std_logic(DEFAULT_COHERENT_ACCESS) or ref.ordered_access(0) /= boolean_to_std_logic(DEFAULT_ORDERED_ACCESS) or pid = PID_PRESENTATION) then
            if (pid = PID_PRESENTATION) then
                assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_PRESENTATION & endian_swap(ref.littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_PRESENTATION & endian_swap(ref.littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.presentation);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.coherent_access) & endian_swap(ref.littleEndian, ref.ordered_access) & (0 to 15 => '0');
            output.length       := output.length + 1;
            if (pid = PID_PRESENTATION) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- DEADLINE
        if (ref.deadline /= DEFAULT_DEADLINE_QOS or pid = PID_DEADLINE) then
            if (pid = PID_DEADLINE) then
                assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_DEADLINE & endian_swap(ref.littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_DEADLINE & endian_swap(ref.littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.deadline(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.deadline(1)));
            output.length       := output.length + 1;
            if (pid = PID_DEADLINE) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- LATENCY BUDGET
        if (ref.latency_budget /= DEFAULT_LATENCY_BUDGET_QOS or pid = PID_LATENCY_BUDGET) then
            if (pid = PID_LATENCY_BUDGET) then
                assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_LATENCY_BUDGET & endian_swap(ref.littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_LATENCY_BUDGET & endian_swap(ref.littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.latency_budget(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.latency_budget(1)));
            output.length       := output.length + 1;
            if (pid = PID_LATENCY_BUDGET) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- OWNERSHIP
        if (ref.ownership /= DEFAULT_OWNERSHIP_QOS or pid = PID_OWNERSHIP) then
            if (pid = PID_OWNERSHIP) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_OWNERSHIP & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_OWNERSHIP & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.ownership);
            output.length       := output.length + 1;
            if (pid = PID_OWNERSHIP) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- OWNERSHIP STRENGTH
        if (ref.ownership_strength /= DEFAULT_OWNERSHIP_STRENGTH_QOS or pid = PID_OWNERSHIP_STRENGTH) then
            if (pid = PID_OWNERSHIP_STRENGTH) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_OWNERSHIP_STRENGTH & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_OWNERSHIP_STRENGTH & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.ownership_strength);
            output.length       := output.length + 1;
            if (pid = PID_OWNERSHIP_STRENGTH) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- LIVELINESS
        if (ref.liveliness /= DEFAULT_LIVELINESS_QOS or ref.leaseDuration /= DEFAULT_LEASE_DURATION or pid = PID_LIVELINESS) then
            if (pid = PID_LIVELINESS) then
                assert (12+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_LIVELINESS & endian_swap(ref.littleEndian, int(12+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_LIVELINESS & endian_swap(ref.littleEndian, int(12,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.liveliness);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.leaseDuration(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.leaseDuration(1)));
            output.length       := output.length + 1;
            if (pid = PID_LIVELINESS) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- TIME BASED FILTER
        if (ref.time_based_filter /= DEFAULT_TIME_BASED_FILTER_QOS or pid = PID_TIME_BASED_FILTER) then
            if (pid = PID_TIME_BASED_FILTER) then
                assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_TIME_BASED_FILTER & endian_swap(ref.littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_TIME_BASED_FILTER & endian_swap(ref.littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.time_based_filter(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.time_based_filter(1)));
            output.length       := output.length + 1;
            if (pid = PID_TIME_BASED_FILTER) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- RELIABILITY
        if (ref.reliability /= DEFAULT_RELIABILTY_QOS or ref.max_blocking_time /= DEFAULT_MAX_BLOCKING_TIME or pid = PID_RELIABILITY) then
            if (pid = PID_RELIABILITY) then
                assert (12+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_RELIABILITY & endian_swap(ref.littleEndian, int(12+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_RELIABILITY & endian_swap(ref.littleEndian, int(12,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.reliability);
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.max_blocking_time(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.max_blocking_time(1)));
            output.length       := output.length + 1;
            if (pid = PID_RELIABILITY) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- TRANSPORT PRIORITY
        if (ref.transport_priority /= DEFAULT_TRANSPORT_PRIORITY_QOS or pid = PID_TRANSPORT_PRIORITY) then
            if (pid = PID_TRANSPORT_PRIORITY) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_TRANSPORT_PRIORITY & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_TRANSPORT_PRIORITY & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.transport_priority);
            output.length       := output.length + 1;
            if (pid = PID_TRANSPORT_PRIORITY) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- LIFESPAN
        if (ref.lifespan /= DEFAULT_LIFESPAN_QOS or pid = PID_LIFESPAN) then
            if (pid = PID_LIFESPAN) then
                assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_LIFESPAN & endian_swap(ref.littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_LIFESPAN & endian_swap(ref.littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.lifespan(0)));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, std_logic_vector(ref.lifespan(1)));
            output.length       := output.length + 1;
            if (pid = PID_LIFESPAN) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- DESTINATION ORDER
        if (ref.destination_order /= DEFAULT_DESTINATION_ORDER_QOS or pid = PID_DESTINATION_ORDER) then
            if (pid = PID_DESTINATION_ORDER) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_DESTINATION_ORDER & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_DESTINATION_ORDER & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.destination_order);
            output.length       := output.length + 1;
            if (pid = PID_DESTINATION_ORDER) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- MULTICAST LOCATORS
        if (unsigned(ref.multicastLocatorList.numLocators) > 0) then
            tmp := to_integer(unsigned(ref.multicastLocatorList.numLocators));
            for i in 0 to tmp-1 loop
                if (pid = PID_MULTICAST_LOCATOR) then
                    assert (24+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_MULTICAST_LOCATOR & endian_swap(ref.littleEndian, int(24+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_MULTICAST_LOCATOR & endian_swap(ref.littleEndian, int(24,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.multicastLocatorList.locator(i).kind);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.multicastLocatorList.locator(i).portn);
                output.length       := output.length + 1;
                output.data(output.length) := ref.multicastLocatorList.locator(i).addr(127 downto 96);
                output.length       := output.length + 1;
                output.data(output.length) := ref.multicastLocatorList.locator(i).addr(95 downto 64);
                output.length       := output.length + 1;
                output.data(output.length) := ref.multicastLocatorList.locator(i).addr(63 downto 32);
                output.length       := output.length + 1;
                output.data(output.length) := ref.multicastLocatorList.locator(i).addr(31 downto 0);
                output.length       := output.length + 1;
                if (pid = PID_MULTICAST_LOCATOR) then
                    output.length       := output.length + offset;
                end if;
            end loop;
        end if;
        -- UNICAST LOCATORS
        if (unsigned(ref.unicastLocatorList.numLocators) > 0) then
            tmp := to_integer(unsigned(ref.unicastLocatorList.numLocators));
            for i in 0 to tmp-1 loop
                if (pid = PID_UNICAST_LOCATOR) then
                    assert (24+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_UNICAST_LOCATOR & endian_swap(ref.littleEndian, int(24+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_UNICAST_LOCATOR & endian_swap(ref.littleEndian, int(24,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.unicastLocatorList.locator(i).kind);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(ref.littleEndian, ref.unicastLocatorList.locator(i).portn);
                output.length       := output.length + 1;
                output.data(output.length) := ref.unicastLocatorList.locator(i).addr(127 downto 96);
                output.length       := output.length + 1;
                output.data(output.length) := ref.unicastLocatorList.locator(i).addr(95 downto 64);
                output.length       := output.length + 1;
                output.data(output.length) := ref.unicastLocatorList.locator(i).addr(63 downto 32);
                output.length       := output.length + 1;
                output.data(output.length) := ref.unicastLocatorList.locator(i).addr(31 downto 0);
                output.length       := output.length + 1;
                if (pid = PID_UNICAST_LOCATOR) then
                    output.length       := output.length + offset;
                end if;
            end loop;
        end if;
        -- USER DATA
        tmp := string_len(ref.user_data);
        if (tmp > 1) then
            output.data(output.length) := PID_USER_DATA & endian_swap(ref.littleEndian, int((round_div(tmp,4)+1)*4,PARAMETER_LENGTH_WIDTH));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, int(tmp, 32));
            output.length       := output.length + 1;
            for i in 0 to round_div(tmp,4)-1 loop
                output.data(output.length) := ref.user_data(i);
                output.length       := output.length + 1;
            end loop;
        end if;
        -- TOPIC DATA
        tmp := string_len(ref.topic_data);
        if (tmp > 1) then
            output.data(output.length) := PID_TOPIC_DATA & endian_swap(ref.littleEndian, int((round_div(tmp,4)+1)*4,PARAMETER_LENGTH_WIDTH));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, int(tmp,32));
            output.length       := output.length + 1;
            for i in 0 to round_div(tmp,4)-1 loop
                output.data(output.length) := ref.topic_data(i);
                output.length       := output.length + 1;
            end loop;
        end if;
        -- GROUP DATA
        tmp := string_len(ref.group_data);
        if (tmp > 1) then
            output.data(output.length) := PID_GROUP_DATA & endian_swap(ref.littleEndian, int((round_div(tmp,4)+1)*4,PARAMETER_LENGTH_WIDTH));
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, int(tmp,32));
            output.length       := output.length + 1;
            for i in 0 to round_div(tmp,4)-1 loop
                output.data(output.length) := ref.group_data(i);
                output.length       := output.length + 1;
            end loop;
        end if;
        -- MAX SIZE SERIALIZED
        -- NOTE: PID_DATA_MAX_SIZE_SERIALIZED has no default value, but we use the value zero as default for not sending the parameter
        if (unsigned(ref.max_size_serialized) /= 0) then
            if (pid = PID_DATA_MAX_SIZE_SERIALIZED) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_DATA_MAX_SIZE_SERIALIZED & endian_swap(ref.littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_DATA_MAX_SIZE_SERIALIZED & endian_swap(ref.littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(ref.littleEndian, ref.max_size_serialized);
            output.length       := output.length + 1;
            if (pid = PID_DATA_MAX_SIZE_SERIALIZED) then
                output.length       := output.length + offset;
            end if;
        end if;
    end procedure;
    
    procedure gen_endpoint_data( ref : in ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        gen_endpoint_data(ref, output, PID_PAD, 0);
    end procedure;
    
    procedure gen_endpoint_match_frame( ref : in ENDPOINT_DATA_TYPE; output : inout TEST_PACKET_TYPE) is
        variable loc   : LOCATOR_TYPE;
    begin
        -- Fetch relevant Locator
        loc := get_loc(ref);
        
        -- OPCODE
        case (ref.match) is
            when MATCH =>
                output.data(output.length)  := OPCODE_ENDPOINT_MATCH;
                output.length               := output.length + 1;
            when UNMATCH =>
                output.data(output.length)  := OPCODE_ENDPOINT_UNMATCH;
                output.length               := output.length + 1;
            when others => 
                null;
        end case;
        -- GUID Prefix
        output.data(output.length)  := ref.participant.guidPrefix(0);
        output.length               := output.length + 1;
        output.data(output.length)  := ref.participant.guidPrefix(1);
        output.length               := output.length + 1;
        output.data(output.length)  := ref.participant.guidPrefix(2);
        output.length               := output.length + 1;
        -- ENTITY ID
        output.data(output.length)  := ref.entityId;
        output.length               := output.length + 1;
        if (ref.match = MATCH) then
            -- IPv4 Address
            output.data(output.length)  := loc.addr(IPv4_ADDRESS_WIDTH-1 downto 0);
            output.length               := output.length + 1;
            -- Port & expectsInlineQoS
            output.data(output.length)  := (others => '0');
            output.data(output.length)(WORD_WIDTH-1 downto UDP_PORT_WIDTH)  := loc.portn(UDP_PORT_WIDTH-1 downto 0);
            if (ref.reader) then
                output.data(output.length)(READER_EXPECTS_INLINE_QOS_FLAG)      := ref.expectsInlineQoS(0);
                output.data(output.length)(READER_EXPECTS_HISTORICAL_DATA_FLAG) := '0' when (ref.durability = VOLATILE_DURABILITY_QOS) else '1';
                output.data(output.length)(READER_IS_BEST_EFFORT_FLAG)          := '1' when (ref.reliability = BEST_EFFORT_RELIABILITY_QOS) else '0';
            end if;
            output.length   := output.length + 1;
        end if;
        
        -- Mark Last Word
        output.last(output.length-1)    := '1';
    end procedure;
    
    procedure gen_sentinel(output : inout TEST_PACKET_TYPE) is
    begin
        output.data(output.length)  := PID_SENTINEL & (PARAMETER_LENGTH_WIDTH-1 downto 0 => '0');
        output.length               := output.length + 1;
    end procedure;
    
    procedure gen_parameter(pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); data : in TEST_PACKET_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        -- PARAMETER HEADER
        output.data(output.length) := pid & int(data.length*4,PARAMETER_LENGTH_WIDTH);
        output.length       := output.length + 1;
        -- DATA
        for i in 0 to data.length-1 loop
            output.data(output.length)  := data.data(i);
            output.length               := output.length + 1;
        end loop;
    end procedure;
    
    procedure gen_inline_qos(ref : in CACHE_CHANGE_TYPE; endpoint : in ENDPOINT_DATA_TYPE; expectsInlineQoS : in boolean; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE; pid : in std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0); offset : in integer) is
        variable tmp : natural := 0;
    begin
        -- *INLINE-ONLY*
        -- Key Hash
        if (ref.instance /= HANDLE_NIL or pid = PID_KEY_HASH) then
            if (pid = PID_KEY_HASH) then
                assert (16+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_KEY_HASH & endian_swap(littleEndian, int(16+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_KEY_HASH & endian_swap(littleEndian, int(16,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length   := output.length + 1;
            output.data(output.length)  := ref.instance(0);
            output.length   := output.length + 1;
            output.data(output.length)  := ref.instance(1);
            output.length   := output.length + 1;
            output.data(output.length)  := ref.instance(2);
            output.length   := output.length + 1;
            output.data(output.length)  := ref.instance(3);
            output.length   := output.length + 1;
            if (pid = PID_KEY_HASH) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- Status Info
        if (ref.kind /= ALIVE or pid = PID_STATUS_INFO) then
            if (pid = PID_STATUS_INFO) then
                assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_STATUS_INFO & endian_swap(littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_STATUS_INFO & endian_swap(littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length   := output.length + 1;
            output.data(output.length) := (others => '0');
            case (ref.kind) is
                when ALIVE_FILTERED =>
                    output.data(output.length)(SSI_FILTERED_FLAG)   := '1';
                when NOT_ALIVE_DISPOSED =>
                    output.data(output.length)(SSI_DISPOSED_FLAG)   := '1';
                when NOT_ALIVE_UNREGISTERED =>
                    output.data(output.length)(SSI_UNREGISTERED_FLAG)   := '1';
                when others =>
                    null;
            end case;
            output.length   := output.length + 1;
            if (pid = PID_STATUS_INFO) then
                output.length       := output.length + offset;
            end if;
        end if;
        -- ENDPOINT DATA QOS
        if (expectsInlineQoS) then
            -- TOPIC NAME
            tmp := string_len(endpoint.topic_name);
            if (pid = PID_TOPIC_NAME) then
                assert (((round_div(tmp,4)+1)*4)+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                output.data(output.length) := PID_TOPIC_NAME & endian_swap(littleEndian, int(((round_div(tmp,4)+1)*4)+(offset*4),PARAMETER_LENGTH_WIDTH));
            else
                output.data(output.length) := PID_TOPIC_NAME & endian_swap(littleEndian, int((round_div(tmp,4)+1)*4,PARAMETER_LENGTH_WIDTH));
            end if;
            output.length       := output.length + 1;
            output.data(output.length) := endian_swap(littleEndian, int(tmp, CDR_LONG_WIDTH));
            output.length       := output.length + 1;
            for i in 0 to round_div(tmp,4)-1 loop
                output.data(output.length) := endpoint.topic_name(i);
                output.length       := output.length + 1;
            end loop;
            if (pid = PID_TOPIC_NAME) then
                output.length       := output.length + offset;
            end if;
            -- DURABILITY
            if (endpoint.durability /= DEFAULT_DURABILITY_QOS or pid = PID_DURABILITY) then
                if (pid = PID_DURABILITY) then
                    assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_DURABILITY & endian_swap(littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_DURABILITY & endian_swap(littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.durability);
                output.length       := output.length + 1;
                if (pid = PID_DURABILITY) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- PRESENTATION
            if (endpoint.presentation /= DEFAULT_PRESENTATION_QOS or endpoint.coherent_access(0) /= boolean_to_std_logic(DEFAULT_COHERENT_ACCESS) or endpoint.ordered_access(0) /= boolean_to_std_logic(DEFAULT_ORDERED_ACCESS) or pid = PID_PRESENTATION) then
                if (pid = PID_PRESENTATION) then
                    assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_PRESENTATION & endian_swap(littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_PRESENTATION & endian_swap(littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.presentation);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.coherent_access) & endian_swap(littleEndian, endpoint.ordered_access) & (0 to 15 => '0');
                output.length       := output.length + 1;
                if (pid = PID_PRESENTATION) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- DEADLINE
            if (endpoint.deadline /= DEFAULT_DEADLINE_QOS or pid = PID_DEADLINE) then
                if (pid = PID_DEADLINE) then
                    assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_DEADLINE & endian_swap(littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_DEADLINE & endian_swap(littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.deadline(0)));
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.deadline(1)));
                output.length       := output.length + 1;
                if (pid = PID_DEADLINE) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- LATENCY BUDGET
            if (endpoint.latency_budget /= DEFAULT_LATENCY_BUDGET_QOS or pid = PID_LATENCY_BUDGET) then
                if (pid = PID_LATENCY_BUDGET) then
                    assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_LATENCY_BUDGET & endian_swap(littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_LATENCY_BUDGET & endian_swap(littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.latency_budget(0)));
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.latency_budget(1)));
                output.length       := output.length + 1;
                if (pid = PID_LATENCY_BUDGET) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- OWNERSHIP
            if (endpoint.ownership /= DEFAULT_OWNERSHIP_QOS or pid = PID_OWNERSHIP) then
                if (pid = PID_OWNERSHIP) then
                    assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_OWNERSHIP & endian_swap(littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_OWNERSHIP & endian_swap(littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.ownership);
                output.length       := output.length + 1;
                if (pid = PID_OWNERSHIP) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- OWNERSHIP STRENGTH
            if (endpoint.ownership_strength /= DEFAULT_OWNERSHIP_STRENGTH_QOS or pid = PID_OWNERSHIP_STRENGTH) then
                if (pid = PID_OWNERSHIP_STRENGTH) then
                    assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_OWNERSHIP_STRENGTH & endian_swap(littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_OWNERSHIP_STRENGTH & endian_swap(littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.ownership_strength);
                output.length       := output.length + 1;
                if (pid = PID_OWNERSHIP_STRENGTH) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- LIVELINESS
            if (endpoint.liveliness /= DEFAULT_LIVELINESS_QOS or endpoint.leaseDuration /= DEFAULT_LEASE_DURATION or pid = PID_LIVELINESS) then
                if (pid = PID_LIVELINESS) then
                    assert (12+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_LIVELINESS & endian_swap(littleEndian, int(12+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_LIVELINESS & endian_swap(littleEndian, int(12,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.liveliness);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.leaseDuration(0)));
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.leaseDuration(1)));
                output.length       := output.length + 1;
                if (pid = PID_LIVELINESS) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- RELIABILITY
            if (endpoint.reliability /= DEFAULT_RELIABILTY_QOS or endpoint.max_blocking_time /= DEFAULT_MAX_BLOCKING_TIME or pid = PID_RELIABILITY) then
                if (pid = PID_RELIABILITY) then
                    assert (12+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_RELIABILITY & endian_swap(littleEndian, int(12+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_RELIABILITY & endian_swap(littleEndian, int(12,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.reliability);
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.max_blocking_time(0)));
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.max_blocking_time(1)));
                output.length       := output.length + 1;
                if (pid = PID_RELIABILITY) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- TRANSPORT PRIORITY
            if (endpoint.transport_priority /= DEFAULT_TRANSPORT_PRIORITY_QOS or pid = PID_TRANSPORT_PRIORITY) then
                if (pid = PID_TRANSPORT_PRIORITY) then
                    assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_TRANSPORT_PRIORITY & endian_swap(littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_TRANSPORT_PRIORITY & endian_swap(littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.transport_priority);
                output.length       := output.length + 1;
                if (pid = PID_TRANSPORT_PRIORITY) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- LIFESPAN
            if (endpoint.lifespan /= DEFAULT_LIFESPAN_QOS or pid = PID_LIFESPAN) then
                if (pid = PID_LIFESPAN) then
                    assert (8+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_LIFESPAN & endian_swap(littleEndian, int(8+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_LIFESPAN & endian_swap(littleEndian, int(8,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.lifespan(0)));
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, std_logic_vector(endpoint.lifespan(1)));
                output.length       := output.length + 1;
                if (pid = PID_LIFESPAN) then
                    output.length       := output.length + offset;
                end if;
            end if;
            -- DESTINATION ORDER
            if (endpoint.destination_order /= DEFAULT_DESTINATION_ORDER_QOS or pid = PID_DESTINATION_ORDER) then
                if (pid = PID_DESTINATION_ORDER) then
                    assert (4+(offset*4) >= 0) report "Parameter Length < 0" severity FAILURE;
                    output.data(output.length) := PID_DESTINATION_ORDER & endian_swap(littleEndian, int(4+(offset*4),PARAMETER_LENGTH_WIDTH));
                else
                    output.data(output.length) := PID_DESTINATION_ORDER & endian_swap(littleEndian, int(4,PARAMETER_LENGTH_WIDTH));
                end if;
                output.length       := output.length + 1;
                output.data(output.length) := endian_swap(littleEndian, endpoint.destination_order);
                output.length       := output.length + 1;
                if (pid = PID_DESTINATION_ORDER) then
                    output.length       := output.length + offset;
                end if;
            end if;
        end if;
    end procedure;
    
    procedure gen_inline_qos(ref : in CACHE_CHANGE_TYPE; endpoint : in ENDPOINT_DATA_TYPE; expectsInlineQoS : in boolean; littleEndian : in std_logic; output : inout TEST_PACKET_TYPE) is
    begin
        gen_inline_qos(ref,endpoint,expectsInlineQoS,littleEndian,output,PID_PAD,0);
    end procedure;
    
    procedure gen_inline_qos(ref : in CACHE_CHANGE_TYPE; output : inout TEST_PACKET_TYPE) is
    begin
        gen_inline_qos(ref,DEFAULT_ENDPOINT_DATA,FALSE,'0',output,PID_PAD,0);
    end procedure;
    
    function test_memory_match (A,B : TEST_MEMORY_TYPE) return boolean is
    begin
        if (A'length /= B'length) then
            return FALSE;
        end if;
        
        for i in 0 to A'length loop
            if (A(i).addr /= B(i).addr or (A(i).data ?/= B(i).data) = '1') then
                return FALSE;
            end if;
        end loop;
        return TRUE;
    end function;
    
    function gen_endpoint(id : natural) return ENDPOINT_DATA_TYPE is
        variable ret : ENDPOINT_DATA_TYPE := DEFAULT_ENDPOINT_DATA;
    begin
        assert (id <= NUM_ENDPOINTS-1) report "ID outside bounds." severity FAILURE;
        
        ret.reader                                           := TRUE when (id < NUM_READERS) else FALSE;
        ret.topic_name                                       := ENDPOINT_TOPIC(id);
        ret.type_name                                        := ENDPOINT_TYPE(id);
        ret.durability                                       := ENDPOINT_DURABILITY_QOS(id);
        ret.durability_service_cleanup_delay                 := ENDPOINT_DURABILITY_SERVICE_CLEANUP_DELAY(id);
        ret.durability_service_history                       := ENDPOINT_DURABILITY_SERVICE_HISTORY(id);
        ret.durability_service_history_depth                 := ENDPOINT_DURABILITY_SERVICE_HISTORY_DEPTH(id);
        ret.durability_service_max_samples                   := ENDPOINT_DURABILITY_SERVICE_MAX_SAMPLES(id);
        ret.durability_service_max_instances                 := ENDPOINT_DURABILITY_SERVICE_MAX_INSTANCES(id);
        ret.durability_service_max_samples_per_instances     := ENDPOINT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE(id);
        ret.presentation                                     := ENDPOINT_PRESENTATION_QOS(id);
        ret.coherent_access(0)                               := boolean_to_std_logic(ENDPOINT_COHERENT_ACCESS(id));
        ret.ordered_access(0)                                := boolean_to_std_logic(ENDPOINT_ORDERED_ACCESS(id));
        ret.deadline                                         := ENDPOINT_DEADLINE_QOS(id);
        ret.latency_budget                                   := ENDPOINT_LATENCY_BUDGET_QOS(id);
        ret.ownership                                        := ENDPOINT_OWNERSHIP_QOS(id);
        ret.ownership_strength                               := ENDPOINT_OWNERSHIP_STRENGTH_QOS(id);
        ret.liveliness                                       := ENDPOINT_LIVELINESS_QOS(id);
        ret.leaseDuration                                    := ENDPOINT_LEASE_DURATION(id);
        ret.time_based_filter                                := ENDPOINT_TIME_BASED_FILTER_QOS(id);
        ret.reliability                                      := ENDPOINT_RELIABILITY_QOS(id);
        ret.max_blocking_time                                := ENDPOINT_MAX_BLOCKING_TIME(id);
        ret.transport_priority                               := ENDPOINT_TRANSPORT_PRIORITY_QOS(id);
        ret.lifespan                                         := ENDPOINT_LIFESPAN_QOS(id);
        ret.destination_order                                := ENDPOINT_DESTINATION_ORDER_QOS(id);
        ret.expectsInlineQoS(0)                              := '1' when (id < NUM_READERS) else '0';
        ret.participant                                      := THIS_PARTICIPANT_DATA;
        ret.entityId                                         := ENTITYID(id);
        ret.nr                                               := id;
        return ret;
    end function;
    
    function gen_endpoint_array(readers : boolean) return ENDPOINT_DATA_ARRAY_TYPE is
        variable ret_readers : ENDPOINT_DATA_ARRAY_TYPE(0 to NUM_READERS-1) := (others => DEFAULT_ENDPOINT_DATA);
        variable ret_writers : ENDPOINT_DATA_ARRAY_TYPE(0 to NUM_WRITERS-1) := (others => DEFAULT_ENDPOINT_DATA);
    begin
        if (readers) then
            for i in 0 to NUM_READERS-1 loop
                ret_readers(i)  := gen_endpoint(i);
            end loop;
            return ret_readers;
        else
            for i in NUM_READERS to NUM_ENDPOINTS-1 loop
                ret_writers(i-NUM_READERS)  := gen_endpoint(i);
            end loop;
            return ret_writers;
        end if;
    end function;
    
    function to_string (input : TEST_MEMORY_TYPE) return string is
    begin
        return "length: " & integer'image(input'length) & ", start_addr: " & integer'image(input(0).addr) & "end_addr: " & integer'image(input(input'length-1).addr);
    end function;
    
    function to_string1 (input : std_logic_vector) return string is
    begin
        return "wr: " & to_string(input(0 to NUM_ENDPOINTS-1)) & ", last_word: " & to_string(input(NUM_ENDPOINTS)) & ", data: " & to_hstring(input(NUM_ENDPOINTS+1 to input'length-1));
    end function;
    
    procedure add_instance(inst : in INSTANCE_HANDLE_TYPE; mem : inout DDS_READER_MEM_TYPE) is
        variable ind : natural := 0;
    begin
        -- Find Position
        ind := mem.ilen;
        for i in 0 to mem.ilen-1 loop
            if (to_unsigned(inst) < to_unsigned(mem.inst(i).inst)) then
                ind := i;
                exit;
            end if;
        end loop;
        
        -- Move elements to make Space
        for i in mem.ilen-1 downto ind loop
            mem.inst(i+1)   := mem.inst(i);
        end loop;
        -- Insert at desired index
        mem.inst(ind)       := DEFAULT_INSTANCE_CACHE_TYPE;
        mem.inst(ind).inst  := inst;
        mem.ilen            := mem.ilen + 1;
    end procedure;
    
    function to_sample(cc : CACHE_CHANGE_TYPE; istate : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0)) return SAMPLE_TYPE is
        variable ret : SAMPLE_TYPE := DEFAULT_SAMPLE;
    begin
        ret.inst     := cc.instance;
        if (not cc.serialized_key) then
            ret.data     := cc.payload;
        end if;
        ret.ts       := cc.src_timestamp;
        ret.istate   := istate;
        return ret;
    end function;
    
    procedure change_istate(inst : in INSTANCE_HANDLE_TYPE; istate : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); mem : inout DDS_READER_MEM_TYPE) is
    begin
        -- Check Instance State
        for i in 0 to mem.ilen-1 loop
            -- Instance Found
            if (inst = mem.inst(i).inst) then
                case (istate) is
                    when ALIVE_INSTANCE_STATE =>
                        case (mem.inst(i).istate) is
                            when NOT_ALIVE_DISPOSED_INSTANCE_STATE =>
                                mem.inst(i).dis_gen_cnt     := mem.inst(i).dis_gen_cnt + 1;
                                mem.inst(i).istate          := ALIVE_INSTANCE_STATE;
                                mem.inst(i).vstate          := NEW_VIEW_STATE;
                            when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE =>
                                mem.inst(i).no_w_gen_cnt    := mem.inst(i).no_w_gen_cnt + 1;
                                mem.inst(i).istate          := ALIVE_INSTANCE_STATE;
                                mem.inst(i).vstate          := NEW_VIEW_STATE;
                            when others =>
                                null;
                        end case;
                    when NOT_ALIVE_DISPOSED_INSTANCE_STATE =>
                        case (mem.inst(i).istate) is
                            when ALIVE_INSTANCE_STATE =>
                                mem.inst(i).istate          := NOT_ALIVE_DISPOSED_INSTANCE_STATE;
                            when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE =>
                                mem.inst(i).istate          := NOT_ALIVE_DISPOSED_INSTANCE_STATE;
                                mem.inst(i).no_w_gen_cnt    := mem.inst(i).no_w_gen_cnt + 1;
                                mem.inst(i).vstate          := NEW_VIEW_STATE;
                            when others =>
                                null;
                        end case;
                    when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE =>
                        case (mem.inst(i).istate) is
                            when ALIVE_INSTANCE_STATE =>
                                mem.inst(i).istate          := NOT_ALIVE_NO_WRITERS_INSTANCE_STATE;
                            when others =>
                                null;
                        end case;
                    when others =>
                        null;
                end case;
                exit;
            end if;
        end loop;
    end procedure;
    
    procedure add_sample(sample : inout SAMPLE_TYPE; mem : inout DDS_READER_MEM_TYPE; DESTINATION_ORDER_QOS : in std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0)) is
        variable found : boolean := FALSE;
        variable ind : natural := 0;
    begin
        -- Zero Meta Data
        sample.dis_gen_cnt  := 0;
        sample.no_w_gen_cnt := 0;
        sample.srank        := 0;
        sample.grank        := 0;
        sample.agrank       := 0;
        sample.sstate       := NOT_READ_SAMPLE_STATE;
        
        change_istate(sample.inst, sample.istate, mem);
        
        -- Check Instance State
        for i in 0 to mem.ilen-1 loop
            -- Instance Found
            if (sample.inst = mem.inst(i).inst) then
                found               := TRUE;
                sample.vstate       := mem.inst(i).vstate;
                sample.dis_gen_cnt  := mem.inst(i).dis_gen_cnt;
                sample.no_w_gen_cnt := mem.inst(i).no_w_gen_cnt;
                exit;
            end if;
        end loop;
        
        -- New Instance
        if (not found) then
            add_instance(sample.inst, mem);
        end if;
        
        -- Add Sample
        ind := mem.slen;
        case (DESTINATION_ORDER_QOS) is
            when BY_RECEPTION_TIMESTAMP_DESTINATION_ORDER_QOS =>
                -- Insert at End of Array
                mem.s(ind)  := sample;
            when BY_SOURCE_TIMESTAMP_DESTINATION_ORDER_QOS =>
                -- Find Position
                for i in 0 to mem.slen-1 loop
                    if (sample.ts > mem.s(i).ts) then
                        ind := i;
                        exit;
                    end if;
                end loop;
                
                -- Move elements to make Space
                for i in mem.slen-1 downto ind loop
                    mem.s(i+1)  := mem.s(i);
                end loop;
                -- Insert at desired index
                mem.s(ind)  := sample;
            when others =>
                assert FALSE report "Unkown DESTINATION_ORDER_QOS" severity FAILURE;
        end case;
        mem.slen    := mem.slen + 1;
    end procedure;
    
    procedure remove_sample(ind : in natural; mem : inout DDS_READER_MEM_TYPE) is
    begin
        assert (ind < mem.slen) report "Index is out of Bounds" severity FAILURE;
        assert (mem.slen /= 0) report "Remove on empty array" severity FAILURE;
        
        -- NOTE: Assumes i+1 is in bounds
        for i in ind to mem.slen-1 loop
            mem.s(i)    := mem.s(i+1);
        end loop;
        mem.slen    := mem.slen - 1;
    end procedure;
    
    procedure remove_inst(inst : in INSTANCE_HANDLE_TYPE; mem : inout DDS_READER_MEM_TYPE) is
        variable ind : natural := 0;
    begin
        assert (mem.ilen /= 0) report "Remove on empty array" severity FAILURE;
        
        ind := mem.ilen;
        for i in 0 to mem.ilen-1 loop
            -- Instance Found
            if (mem.inst(i).inst = inst) then
                ind := i;
                exit;
            end if;
        end loop;
        
        if (ind /= mem.ilen) then
            -- NOTE: Assumes i+1 is in bounds
            for i in ind to mem.ilen-1 loop
                mem.inst(i) := mem.inst(i+1);
            end loop;
            mem.ilen    := mem.ilen - 1;
        end if;
    end procedure;
    
    function check_instance(istate : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); vstate : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0); mem : DDS_READER_MEM_TYPE; inst : INSTANCE_HANDLE_TYPE) return boolean is
    begin
        for i in 0 to mem.ilen-1 loop
            -- Instance Found
            if (inst = mem.inst(i).inst) then
                if (((mem.inst(i).istate and istate) /= (istate'range => '0')) and ((mem.inst(i).vstate and vstate) /= (vstate'range => '0'))) then
                    return TRUE;
                end if;
            end if;
        end loop;
        return FALSE;
    end function;
    
    function find_instance(mem : DDS_READER_MEM_TYPE; inst : INSTANCE_HANDLE_TYPE) return natural is
    begin
        for i in 0 to mem.ilen-1 loop
            -- Instance Found
            if (inst = mem.inst(i).inst) then
                return i;
            end if;
        end loop;
        assert FALSE report "Instance not in Memory" severity FAILURE;
    end function;
    
    procedure gen_collection (mem : inout DDS_READER_MEM_TYPE; col : inout COLLECTION_TYPE; inst : INSTANCE_HANDLE_TYPE; sstate : in std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0); istate : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); vstate : in std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0); max_samples : in natural; remove : in boolean; sort : in boolean) is
        variable i,j        : natural := 0;
        variable tmp_inst   : INSTANCE_HANDLE_TYPE := HANDLE_NIL;
        variable tmp_col    : COLLECTION_TYPE := DEFAULT_COLLECTION;
        variable rank, mrsic_gen, mrs_gen : natural := 0;
        variable done       : std_logic_vector(0 to max_samples-1) := (others => '0');
        variable no_inst    : boolean := FALSE;
    begin
        col := DEFAULT_COLLECTION;
        
        i := 0;
        loop
            -- Sample is in Collection
            if (((mem.s(i).sstate and sstate) /= (sstate'range => '0')) and check_instance(istate, vstate, mem, mem.s(i).inst) and ((inst /= HANDLE_NIL and inst = mem.s(i).inst) or inst = HANDLE_NIL)) then
                col.s(col.len)          := mem.s(i);
                col.s(col.len).istate   := mem.inst(find_instance(mem,mem.s(i).inst)).istate;
                col.s(col.len).vstate   := mem.inst(find_instance(mem,mem.s(i).inst)).vstate;
                col.len := col.len + 1;
                -- Change READ STATE
                mem.s(i).sstate := READ_SAMPLE_STATE;
                
                -- Remove Sample
                if (remove) then
                    remove_sample(i, mem);
                    -- NOTE: We do not increment the loop invariant
                else
                    i := i + 1;
                end if;
            else
                i := i + 1;
            end if;
            
            -- Loop Exit Condition
            if (i >= mem.slen or col.len >= max_samples) then
                exit;
            end if;
        end loop;
        
        if (col.len = 0)  then
            report "Empty Collection" severity NOTE;
            return;
        end if;
        
        -- No Instances (WITH_KEY=FALSE testing)
        if (col.s(0).inst = HANDLE_NIL) then
            no_inst := TRUE;
        end if;
        
        -- Sort
        if (sort and not no_inst) then
            i           := 1;
            j           := 1;
            tmp_inst    := col.s(0).inst;
            tmp_col     := DEFAULT_COLLECTION;
            tmp_col.len := col.len;
            tmp_col.s(0):= col.s(0);
            col.s(0)    := DEFAULT_SAMPLE;    
            loop
                -- Select Next Instance
                if (tmp_inst = HANDLE_NIL) then
                    if (col.s(i).inst /= HANDLE_NIL) then
                        tmp_inst    := col.s(i).inst;
                        i           := 0; --Reset
                    end if;
                elsif (col.s(i).inst = tmp_inst) then
                    tmp_col.s(j)    := col.s(i);
                    col.s(i)        := DEFAULT_SAMPLE;
                    j   := j + 1;
                end if;
                i   := i + 1;
                
                -- DONE
                if (j >= col.len) then
                    col := tmp_col;
                    exit;
                -- Reset Index
                elsif (i >= col.len) then
                    i           := 0;
                    tmp_inst    := HANDLE_NIL;
                end if;
            end loop;
        end if;
        
        -- Calculate Ranks
        i               := col.len-1;
        tmp_inst        := col.s(i).inst;
        j               := find_instance(mem,tmp_inst);
        rank            := 1;
        mrs_gen         := mem.inst(j).dis_gen_cnt + mem.inst(j).no_w_gen_cnt;
        mrsic_gen       := col.s(i).dis_gen_cnt + col.s(i).no_w_gen_cnt;
        col.s(i).agrank := mrs_gen - mrsic_gen;
        if (mrs_gen - mrsic_gen = 0) then
            -- Change VIEW STATE
            mem.inst(j).vstate  := NOT_NEW_VIEW_STATE;
        end if;
        done(col.len-1 to done'length-1)    := (others => '1');
        -- Single Sample
        if (col.len-1 = 0) then
            return;
        else
            loop
                i   := i - 1;
                -- Select Next Instance
                if (not no_inst and tmp_inst = HANDLE_NIL) then
                    if (done(i) = '0') then
                        tmp_inst    := col.s(i).inst;
                        j           := find_instance(mem, tmp_inst);
                        -- Reset
                        rank            := 1;
                        mrs_gen         := mem.inst(j).dis_gen_cnt + mem.inst(j).no_w_gen_cnt;
                        mrsic_gen       := col.s(i).dis_gen_cnt + col.s(i).no_w_gen_cnt;
                        col.s(i).agrank := mrs_gen - mrsic_gen;
                        if (mrs_gen - mrsic_gen = 0) then
                            -- Change VIEW STATE
                            mem.inst(j).vstate  := NOT_NEW_VIEW_STATE;
                        end if;
                        done(i)         := '1';
                    end if;
                elsif (done(i) = '0' and col.s(i).inst = tmp_inst) then
                    col.s(i).srank  := rank;
                    rank            := rank + 1;
                    col.s(i).grank  := mrsic_gen - (col.s(i).dis_gen_cnt + col.s(i).no_w_gen_cnt);
                    col.s(i).agrank := mrs_gen - (col.s(i).dis_gen_cnt + col.s(i).no_w_gen_cnt);
                    done(i)         := '1';
                end if;
                -- Exit Condition
                if (done = (done'range => '1')) then
                    exit;
                -- Reset
                elsif (i = 0) then
                    tmp_inst    := HANDLE_NIL;
                    i           := col.len-1;
                end if;
            end loop;
        end if;
    end procedure;
    
    procedure gen_collection (mem : inout DDS_READER_MEM_TYPE; col : inout COLLECTION_TYPE; opcode : in DDS_READER_TEST_TYPE; PRESENTATION_QOS : in std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0); ordered : in boolean) is
        variable sort       : boolean := FALSE;
        variable tmp_inst   : INSTANCE_HANDLE_TYPE := HANDLE_NIL;
    begin
        col := DEFAULT_COLLECTION;
        
        sort    := TRUE when (not ordered or PRESENTATION_QOS = INSTANCE_PRESENTATION_QOS) else FALSE;
        
        case (opcode.opcode) is
            when READ =>
                gen_collection(mem, col, HANDLE_NIL, opcode.sstate, opcode.istate, opcode.vstate, opcode.max_samples, FALSE, sort);
            when TAKE =>
                gen_collection(mem, col, HANDLE_NIL, opcode.sstate, opcode.istate, opcode.vstate, opcode.max_samples, TRUE, sort);
            when READ_NEXT_SAMPLE =>
                gen_collection(mem, col, HANDLE_NIL, NOT_READ_SAMPLE_STATE, ANY_INSTANCE_STATE, ANY_VIEW_STATE, 1, FALSE, FALSE);
            when TAKE_NEXT_SAMPLE =>
                gen_collection(mem, col, HANDLE_NIL, NOT_READ_SAMPLE_STATE, ANY_INSTANCE_STATE, ANY_VIEW_STATE, 1, TRUE, FALSE);
            when READ_INSTANCE =>
                gen_collection(mem, col, opcode.inst, opcode.sstate, opcode.istate, opcode.vstate, opcode.max_samples, FALSE, sort);
            when TAKE_INSTANCE =>
                gen_collection(mem, col, opcode.inst, opcode.sstate, opcode.istate, opcode.vstate, opcode.max_samples, TRUE, sort);
            when READ_NEXT_INSTANCE =>
                tmp_inst    := mem.inst(find_instance(mem,opcode.inst)+1).inst;
                if (tmp_inst /= HANDLE_NIL) then
                    gen_collection(mem, col, tmp_inst, opcode.sstate, opcode.istate, opcode.vstate, opcode.max_samples, FALSE, sort);
                end if;
            when TAKE_NEXT_INSTANCE =>
                tmp_inst    := mem.inst(find_instance(mem,opcode.inst)+1).inst;
                if (tmp_inst /= HANDLE_NIL) then
                    gen_collection(mem, col, tmp_inst, opcode.sstate, opcode.istate, opcode.vstate, opcode.max_samples, TRUE, sort);
                end if;
            when others =>
                assert FALSE report "Unknown DDS Reader Operation" severity FAILURE;
        end case;
    end procedure;
    
end package body;