-- altera vhdl_input_version vhdl_2008 -- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.math_pkg.all; use work.rtps_package.all; use work.user_config.all; -- TODO: Convert ALL integers to natural, and remove all conversions (Arithmetics between natural and unsigned are directly supported) package rtps_config_package is subtype ID_TYPE is natural range 0 to NUM_ENDPOINTS-1; constant VENDORID : std_logic_vector(VENDORID_WIDTH-1 downto 0) := VENDORID_UNKNOWN; constant GUIDPREFIX : GUIDPREFIX_TYPE; -- Deferred to Package Body type ENTITYID_TYPE is array (0 to NUM_ENDPOINTS-1) of std_logic_vector(ENTITYID_WIDTH-1 downto 0); constant ENTITYID : ENTITYID_TYPE; -- Deferred to Package Body constant DOMAIN_ID : std_logic_vector(DOMAIN_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(USER_DOMAIN_ID, DOMAIN_ID_WIDTH)); -- Smallest Writer Endpoint Lease Duration constant MIN_ENDPOINT_LEASE_DURATION : DURATION_TYPE; -- Deferred to package Body -- (see DDSI-RTPS 2.3 Section 9.6.1) -- PB + DG * domain_id + d0 constant META_IPv4_MULTICAST_PORT: std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D0 + PORT_CONFIG_DG*USER_DOMAIN_ID, UDP_PORT_WIDTH)); -- (see DDSI-RTPS 2.3 Section 9.6.1) -- PB + DG * domainId + d1 + PG * participant_id -- participant_id=0 constant META_IPv4_UNICAST_PORT : std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D1 + PORT_CONFIG_DG*USER_DOMAIN_ID, UDP_PORT_WIDTH)); -- (see DDSI-RTPS 2.3 Section 9.6.1) -- PB + DG * domainId + d2 constant USER_IPv4_MULTICAST_PORT: std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D2 + PORT_CONFIG_DG*USER_DOMAIN_ID, UDP_PORT_WIDTH)); -- (see DDSI-RTPS 2.3 Section 9.6.1) -- PB + DG * domainId + d3 + PG * participant_id -- participant_id=0 constant USER_IPv4_UNICAST_PORT : std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D3 + PORT_CONFIG_DG*USER_DOMAIN_ID, UDP_PORT_WIDTH)); -- ENDPOINT META OPCODES constant EMO_WIDTH : natural := 32; constant EMO_NOP : std_logic_vector(EMO_WIDTH-1 downto 0) := x"00000000"; constant EMO_ENDPOINT_MATCH : std_logic_vector(EMO_WIDTH-1 downto 0) := x"55000000"; constant EMO_ENDPOINT_UNMATCH : std_logic_vector(EMO_WIDTH-1 downto 0) := x"55000001"; constant EMO_PARTICIPANT_UNMATCH : std_logic_vector(EMO_WIDTH-1 downto 0) := x"55000002"; constant EMO_LIVELINESS_UPDATE : std_logic_vector(EMO_WIDTH-1 downto 0) := x"55000003"; -- Sample Status Info Flags constant SSI_DISPOSED_FLAG : natural := STATUS_INFO_DISPOSED_FLAG; constant SSI_UNREGISTERED_FLAG : natural := STATUS_INFO_UNREGISTERED_FLAG; constant SSI_FILTERED_FLAG : natural := STATUS_INFO_FILTERED_FLAG; constant SSI_KEY_HASH_FLAG : natural := 28; -- Reader Only constant SSI_ALIGNED_FLAG : natural := 29; constant SSI_DATA_FLAG : natural := 30; constant SSI_READ_FLAG : natural := 31; -- Reader Only constant SSI_ACK_FLAG : natural := 31; -- Writer Only -- Instance Status Info Flags constant ISI_NOT_ALIVE_DISPOSED_FLAG : natural := 0; -- Reader Only constant ISI_DISPOSED_FLAG : natural := 0; -- Writer Only constant ISI_NOT_ALIVE_NO_WRITERS_FLAG : natural := 1; -- Reader Only constant ISI_UNREGISTERED_FLAG : natural := 1; -- Writer Only constant ISI_LIVELINESS_FLAG : natural := 2; constant ISI_VIEW_FLAG : natural := 3; -- Reader Only constant ISI_MARK_FLAG : natural := 4; -- Reader Only constant ISI_GENERATE_SAMPLE_FLAG : natural := 5; -- Reader Only -- Remote Endpoint Flags constant READER_FLAGS_WIDTH : natural := 16; constant READER_EXPECTS_INLINE_QOS_FLAG : natural := 0; constant READER_EXPECTS_HISTORICAL_DATA_FLAG : natural := 1; constant READER_IS_BEST_EFFORT_FLAG : natural := 2; -- TODO: Auto generate based on other defaults constant DEFAULT_EXPECTS_HISTORICAL_DATA_FLAG : std_logic := '0'; constant DEFAULT_IS_BEST_EFFORT_FLAG : std_logic := '1'; -- Marks the Reader Endpoint in the Endpoint Array constant ENDPOINT_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1); --Deferred to package body -- Marks the writers with AUTOMATIC Liveliness Qos constant AUTOMATIC_LIVELINESS_WRITERS : std_logic_vector(0 to NUM_ENDPOINTS-1); --Deferred to package body -- Marks the writers with MANUAL BY PARTICIPANT Liveliness Qos constant MANUAL_BY_PARTICIPANT_LIVELINESS_WRITERS : std_logic_vector(0 to NUM_ENDPOINTS-1); --Deferred to package body -- Marks the readers with AUTOMATIC Liveliness Qos constant AUTOMATIC_LIVELINESS_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1); --Deferred to package body -- Marks the readers with MANUAL BY PARTICIPANT Liveliness Qos constant MANUAL_BY_PARTICIPANT_LIVELINESS_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1); --Deferred to package body type WORD_ARRAY_TYPE is array (natural range <>) of std_logic_vector(WORD_WIDTH-1 downto 0); type OUTPUT_DATA_TYPE is record -- Limit DATA to MAX UDPv4 Payload Size - RTPS Header (65487 Bytes) data : WORD_ARRAY_TYPE(0 to 16371); length : natural; end record; constant READER_ENDPOINT_DATA : OUTPUT_DATA_TYPE; --Deferred to package body constant WRITER_ENDPOINT_DATA : OUTPUT_DATA_TYPE; --Deferred to package body constant LOCAL_PARTICIPANT_DATA : OUTPUT_DATA_TYPE; --Deferred to package body type STRING_WORD_ARRAY_TYPE is array (0 to (256/(WORD_WIDTH/8))-1) of std_logic_vector(WORD_WIDTH-1 downto 0); type ENDPOINT_STRING_TYPE is array (0 to NUM_ENDPOINTS-1) of STRING_WORD_ARRAY_TYPE; constant ENDPOINT_TOPIC : ENDPOINT_STRING_TYPE; --Deferred to package body constant ENDPOINT_TYPE : ENDPOINT_STRING_TYPE; --Deferred to package body constant DOMAIN_TAG : STRING_WORD_ARRAY_TYPE; -- Deferred to package body constant DEFAULT_DOMAIN_TAG : STRING_WORD_ARRAY_TYPE; -- Deferred to package body -- TODO: Use everywhere constant EMPTY_STRING : STRING_WORD_ARRAY_TYPE := (others => (others => '0')); type DEFAULT_QOS_MATCH_TYPE is record DURABILITY_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); PRESENTATION_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); DEADLINE_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); LATENCY_BUDGET_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); OWNERSHIP_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); LIVELINESS_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); RELIABILITY_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); DESTINATION_ORDER_QOS : std_logic_vector(0 to NUM_ENDPOINTS-1); end record; constant READER_DEFAULT_QOS_MATCH : DEFAULT_QOS_MATCH_TYPE; -- Deferred to Package Body constant WRITER_DEFAULT_QOS_MATCH : DEFAULT_QOS_MATCH_TYPE; -- Deferred to Package Body type RTPS_OUT_DATA_TYPE is array (0 to NUM_ENDPOINTS) of std_logic_vector(WORD_WIDTH-1 downto 0); constant CLOCK_DURATION : DURATION_TYPE := gen_duration(CLOCK_PERIOD); -- Swap "data" to Big Endian representation. function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector; function endian_swap(swap : std_logic; data : unsigned) return unsigned; -- Return the Byte length of the string. (First NUL Byte is included) function string_len (str : STRING_WORD_ARRAY_TYPE) return natural; function boolean_to_std_logic(input : boolean) return std_logic; function convert_string (str : USER_STRING_TYPE) return STRING_WORD_ARRAY_TYPE; function round_slv(slv : std_logic_vector; width : natural) return std_logic_vector; function check_qos_compatibility(src_is_reader : std_logic; direction : std_logic; remote : unsigned(WORD_WIDTH-1 downto 0); local : unsigned(WORD_WIDTH-1 downto 0)) return boolean; function check_qos_compatibility(src_is_reader : std_logic; direction : std_logic; remote : DOUBLE_WORD_ARRAY; local : DOUBLE_WORD_ARRAY) return boolean; function check_mask(flags : std_logic_vector; mask : std_logic_vector) return boolean; function gen_inline_qos (id : natural) return OUTPUT_DATA_TYPE; end package; package body rtps_config_package is procedure assertions is begin assert (NUM_ENDPOINTS = (NUM_READERS+NUM_WRITERS)) severity failure; assert (ENDPOINT_CONFIG'length = NUM_ENDPOINTS) report "Endpoint Configuration Array has to be NUM_ENDPOINTS long" severity failure; assert (PARTICIPANT_ANNOUNCEMENT_PERIOD+DURATION_DELTA <= PARTICIPANT_LEASE_DURATION) report "Participant Announcement Period has to be less than the Participant Lease Duration" severity failure; for i in 0 to NUM_ENDPOINTS-1 loop assert (unsigned(ENDPOINT_CONFIG(i).DURABILITY_QOS) < unsigned(TRANSIENT_DURABILITY_QOS)) report "TRANSIENT and PERSISTENT Durability QoS not supported" severity failure; assert (ENDPOINT_CONFIG(i).PRESENTATION_QOS /= GROUP_PRESENTATION_QOS) report "GROUP Presentation QoS not supported" severity failure; assert (ENDPOINT_CONFIG(i).DEADLINE_QOS >= ENDPOINT_CONFIG(i).TIME_BASED_FILTER_QOS) report "DEADLINE Qos cannot be less than TIME_BASED_FILTER QoS" severity failure; assert (ENDPOINT_CONFIG(i).OWNERSHIP_QOS = SHARED_OWNERSHIP_QOS) report "Only SHARED Ownership QoS supported" severity failure; assert (unsigned(ENDPOINT_CONFIG(i).MAX_SAMPLES) >= unsigned(ENDPOINT_CONFIG(i).MAX_SAMPLES_PER_INSTANCE)) report "MAX_SAMPLES cannot be less than MAX_SAMPLES_PER_INSTANCE in Resource Limits QoS" severity failure; end loop; end procedure; function gen_endpoint_readers return std_logic_vector is variable ret : std_logic_vector(0 to NUM_ENDPOINTS-1) := (others => '0'); begin ret := (others => '0'); ret(0 to NUM_READERS-1) := (others => '1'); return ret; end function; constant ENDPOINT_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1) := gen_endpoint_readers; function boolean_to_std_logic(input : boolean) return std_logic is variable ret : std_logic := '0'; begin ret := '0'; if (input = TRUE) then ret := '1'; end if; return ret; end function; function gen_entyid return ENTITYID_TYPE is variable ret : ENTITYID_TYPE; begin ret := (others => (others => '0')); for i in 0 to ret'length-1 loop -- (see DDSI-RTPS 2.3 Section 9.3.1.2) -- Entity Kind Mapping ret(i)(ENTITY_KIND_H_RANGE) := USER_DEFINED_ENTITY; if (i <= NUM_READERS-1) then if (ENDPOINT_CONFIG(i).WITH_KEY) then ret(i)(ENTITY_KIND_L_RANGE) := READER_WITH_KEY; else ret(i)(ENTITY_KIND_L_RANGE) := READER_NO_KEY; end if; else if (ENDPOINT_CONFIG(i).WITH_KEY) then ret(i)(ENTITY_KIND_L_RANGE) := WRITER_WITH_KEY; else ret(i)(ENTITY_KIND_L_RANGE) := WRITER_NO_KEY; end if; end if; -- ID Mapping ret(i)(ENTITYID_WIDTH-1 downto 8) := std_logic_vector(to_unsigned(i,ENTITYID_WIDTH-8)); end loop; return ret; end function; constant ENTITYID : ENTITYID_TYPE := gen_entyid; function gen_guidprefix return GUIDPREFIX_TYPE is variable tmp : std_logic_vector(GUIDPREFIX_WIDTH-1 downto 0) := (others => '0'); variable ret : GUIDPREFIX_TYPE := (others => (others => '0')); begin tmp := (others => '0'); ret := (others => (others => '0')); -- First two bytes have to be Vendor ID (see DDSI-RTPS 2.3 Section 9.3.1.5) tmp(GUIDPREFIX_WIDTH-1 downto GUIDPREFIX_WIDTH-VENDORID_WIDTH) := VENDORID; -- Next we insert the MAC address for uniqueness tmp(GUIDPREFIX_WIDTH-VENDORID_WIDTH-1 downto GUIDPREFIX_WIDTH-VENDORID_WIDTH-48) := MAC_ADDRESS; -- Next we insert the Domain ID tmp(DOMAIN_ID_WIDTH-1 downto 0) := DOMAIN_ID; -- Convert to return type for i in 0 to ret'length-1 loop ret(i) := tmp(GUIDPREFIX_WIDTH-(i*ret(i)'length)-1 downto GUIDPREFIX_WIDTH-(i*ret(i)'length)-ret(i)'length); end loop; return ret; end function; constant GUIDPREFIX : GUIDPREFIX_TYPE := gen_guidprefix; function find_min_lease_duration return DURATION_TYPE is variable ret : DURATION_TYPE := (others => (others => '0')); begin ret := DURATION_INFINITE; -- Sanity Check if (NUM_WRITERS = 0) then return ret; end if; -- Iterate through writers for i in NUM_READERS to NUM_ENDPOINTS-1 loop -- Do not consider "MANUAL_BY_TOPIC" Liveliness if (ENDPOINT_CONFIG(i).LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then -- Find Minimum Lease Duration if (ENDPOINT_CONFIG(i).LEASE_DURATION < ret) then ret := ENDPOINT_CONFIG(i).LEASE_DURATION; end if; end if; end loop; return ret; end function; constant MIN_ENDPOINT_LEASE_DURATION : DURATION_TYPE := find_min_lease_duration; function convert_string (str : USER_STRING_TYPE) return STRING_WORD_ARRAY_TYPE is variable ret : STRING_WORD_ARRAY_TYPE := (others => (others => '0')); begin ret := (others => (others => '0')); for i in 0 to ret'length-1 loop ret(i) := std_logic_vector(to_unsigned(character'POS(str((i*4)+1)), 8)) & std_logic_vector(to_unsigned(character'POS(str((i*4)+2)), 8)) & std_logic_vector(to_unsigned(character'POS(str((i*4)+3)), 8)) & std_logic_vector(to_unsigned(character'POS(str((i*4)+4)), 8)); end loop; return ret; end function; function convert_endpoint_topic_string (config_array : CONFIG_ARRAY_TYPE) return ENDPOINT_STRING_TYPE is variable ret : ENDPOINT_STRING_TYPE := (others => (others => (others => '0'))); begin for i in 0 to ret'length-1 loop ret(i) := convert_string(config_array(i).TOPICNAME); end loop; return ret; end function; function convert_endpoint_type_string (config_array : CONFIG_ARRAY_TYPE) return ENDPOINT_STRING_TYPE is variable ret : ENDPOINT_STRING_TYPE := (others => (others => (others => '0'))); begin for i in 0 to ret'length-1 loop ret(i) := convert_string(config_array(i).TYPENAME); end loop; return ret; end function; constant ENDPOINT_TOPIC : ENDPOINT_STRING_TYPE := convert_endpoint_topic_string(ENDPOINT_CONFIG); constant ENDPOINT_TYPE : ENDPOINT_STRING_TYPE := convert_endpoint_type_string(ENDPOINT_CONFIG); constant DOMAIN_TAG : STRING_WORD_ARRAY_TYPE := convert_string(USER_DOMAIN_TAG); constant DEFAULT_DOMAIN_TAG : STRING_WORD_ARRAY_TYPE := convert_string(DEFAULT_USER_DOMAIN_TAG); function string_len (str : STRING_WORD_ARRAY_TYPE) return natural is variable ret : natural := 0; variable done : boolean := FALSE; begin ret := 0; done := FALSE; for i in 0 to str'length-1 loop for j in 0 to (WORD_WIDTH/BYTE_WIDTH)-1 loop -- Count Bytes ret := ret + 1; -- Exit on first NULL byte (NULL Byte included in count) if (str(i)(WORD_WIDTH-(j*BYTE_WIDTH)-1 downto WORD_WIDTH-(j*BYTE_WIDTH)-BYTE_WIDTH) = (0 to BYTE_WIDTH-1 => '0')) then done := TRUE; exit; end if; end loop; if (done) then exit; end if; end loop; return ret; end function; function gen_reader_endpoint_data return OUTPUT_DATA_TYPE is variable ret : OUTPUT_DATA_TYPE := (data => (others => (others => '0')), length => 0); variable ind : natural := 0; variable len : natural := 0; variable tmp : natural := 0; begin ret.data := (others => (others => '0')); ret.length := 0; -- Sanity Check if (NUM_READERS = 0) then return ret; end if; len := 0; ind := 0; -- RTPS Submessages -- One DATA Submessage for each Reader for i in 0 to NUM_READERS-1 loop -- RTPS Submessage Header ret.data(ind) := SID_DATA & "00000100" & x"0000"; -- DATA Header (extraFlags, octetsToInlineQoS) len := len + 1; ret.data(ind+len) := x"0000" & std_logic_vector(to_unsigned(16, 16)); -- DATA Header (Reader Entity ID) len := len + 1; ret.data(ind+len) := ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR; -- DATA Header (Writer Entity ID) len := len + 1; ret.data(ind+len) := ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER; -- DATA Header (Sequence Number) len := len + 1; ret.data(ind+len) := (others => '0'); -- DATA Header (Sequence Number) len := len + 1; ret.data(ind+len) := std_logic_vector(to_unsigned(i+1, ret.data(0)'length)); -- Serialized Payload Header len := len + 1; ret.data(ind+len) := PL_CDR_BE & x"0000"; -- Serialized Payload BEGIN -- GUID len := len + 1; ret.data(ind+len):= PID_ENDPOINT_GUID & std_logic_vector(to_unsigned(16, 16)); len := len + 1; ret.data(ind+len) := GUIDPREFIX(0); len := len + 1; ret.data(ind+len) := GUIDPREFIX(1); len := len + 1; ret.data(ind+len) := GUIDPREFIX(2); len := len + 1; ret.data(ind+len) := ENTITYID(i); -- EXPECTS INLINE QOS -- XXX: Cyclone DDS Compatibility -- Apparently Cyclone DDS does not support Readers with the expectsInlineQoS Flag --len := len + 1; --ret.data(ind+len) := PID_EXPECTS_INLINE_QOS & std_logic_vector(to_unsigned(4, 16)); --len := len + 1; --ret.data(ind+len) := (24 => '1', others => '0'); -- TOPIC NAME tmp := string_len(ENDPOINT_TOPIC(i)); len := len + 1; ret.data(ind+len) := PID_TOPIC_NAME & std_logic_vector(to_unsigned((round_div(tmp,4)+1)*4, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(to_unsigned(tmp, 32)); for j in 0 to round_div(tmp,4)-1 loop len := len + 1; ret.data(ind+len) := ENDPOINT_TOPIC(i)(j); end loop; -- TYPE NAME tmp := string_len(ENDPOINT_TYPE(i)); len := len + 1; ret.data(ind+len) := PID_TYPE_NAME & std_logic_vector(to_unsigned((round_div(tmp,4)+1)*4, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(to_unsigned(tmp, 32)); for j in 0 to round_div(tmp,4)-1 loop len := len + 1; ret.data(ind+len) := ENDPOINT_TYPE(i)(j); end loop; -- DURABILITY if (ENDPOINT_CONFIG(i).DURABILITY_QOS /= DEFAULT_DURABILITY_QOS) then len := len + 1; ret.data(ind+len) := PID_DURABILITY & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_QOS; end if; -- DURABILITY SERVICE if (ENDPOINT_CONFIG(i).DURABILITY_SERVICE_CLEANUP_DELAY /= DEFAULT_DURABILITY_SERVICE_CLEANUP_DELAY or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY /= DEFAULT_DURABILITY_SERVICE_HISTORY or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY_DEPTH /= DEFAULT_DURABILITY_SERVICE_HISTORY_DEPTH or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES /= DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_INSTANCES /= DEFAULT_DURABILITY_SERVICE_MAX_INSTANCES or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE /= DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE ) then len := len + 1; ret.data(ind+len) := PID_DURABILITY_SERVICE & std_logic_vector(to_unsigned(28, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DURABILITY_SERVICE_CLEANUP_DELAY(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DURABILITY_SERVICE_CLEANUP_DELAY(1)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY_DEPTH; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_INSTANCES; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE; end if; -- PRESENTATION if (ENDPOINT_CONFIG(i).PRESENTATION_QOS /= DEFAULT_PRESENTATION_QOS or ENDPOINT_CONFIG(i).COHERENT_ACCESS /= DEFAULT_COHERENT_ACCESS or ENDPOINT_CONFIG(i).ORDERED_ACCESS /= DEFAULT_ORDERED_ACCESS) then len := len + 1; ret.data(ind+len) := PID_PRESENTATION & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).PRESENTATION_QOS; len := len + 1; ret.data(ind+len) := (24 => boolean_to_std_logic(ENDPOINT_CONFIG(i).COHERENT_ACCESS), 16 => boolean_to_std_logic(ENDPOINT_CONFIG(i).ORDERED_ACCESS), others => '0'); end if; -- DEADLINE if (ENDPOINT_CONFIG(i).DEADLINE_QOS /= DEFAULT_DEADLINE_QOS) then len := len + 1; ret.data(ind+len) := PID_DEADLINE & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DEADLINE_QOS(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DEADLINE_QOS(1)); end if; -- LATENCY_BUDGET if (ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS /= DEFAULT_LATENCY_BUDGET_QOS) then len := len + 1; ret.data(ind+len) := PID_LATENCY_BUDGET & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS(1)); end if; -- OWNERSHIP if (ENDPOINT_CONFIG(i).OWNERSHIP_QOS /= DEFAULT_OWNERSHIP_QOS) then len := len + 1; ret.data(ind+len) := PID_OWNERSHIP & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).OWNERSHIP_QOS; end if; -- LIVELINESS if (ENDPOINT_CONFIG(i).LIVELINESS_QOS /= DEFAULT_LIVELINESS_QOS or ENDPOINT_CONFIG(i).LEASE_DURATION /= DEFAULT_LEASE_DURATION) then len := len + 1; ret.data(ind+len) := PID_LIVELINESS & std_logic_vector(to_unsigned(12, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).LIVELINESS_QOS; len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LEASE_DURATION(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LEASE_DURATION(1)); end if; -- TIME BASED FILTER if (ENDPOINT_CONFIG(i).TIME_BASED_FILTER_QOS /= DEFAULT_LATENCY_BUDGET_QOS) then len := len + 1; ret.data(ind+len) := PID_TIME_BASED_FILTER & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).TIME_BASED_FILTER_QOS(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).TIME_BASED_FILTER_QOS(1)); end if; -- RELIABILITY if (ENDPOINT_CONFIG(i).RELIABILITY_QOS /= DEFAULT_RELIABILITY_QOS_R or ENDPOINT_CONFIG(i).MAX_BLOCKING_TIME /= DEFAULT_MAX_BLOCKING_TIME) then len := len + 1; ret.data(ind+len) := PID_RELIABILITY & std_logic_vector(to_unsigned(12, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).RELIABILITY_QOS; len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).MAX_BLOCKING_TIME(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).MAX_BLOCKING_TIME(1)); end if; -- DESTINATION ORDER if (ENDPOINT_CONFIG(i).DESTINATION_ORDER_QOS /= DEFAULT_DESTINATION_ORDER_QOS) then len := len + 1; ret.data(ind+len) := PID_DESTINATION_ORDER & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DESTINATION_ORDER_QOS; end if; -- SENTINEL len := len + 1; ret.data(ind+len) := PID_SENTINEL & std_logic_vector(to_unsigned(0, 16)); -- Fix Submessage Length ret.data(ind)(15 downto 0) := std_logic_vector(to_unsigned(len*4, 16)); -- Reset Pointers ind := ind + len + 1; len := 0; end loop; -- Store Total Length ret.length := ind; return ret; end function; constant READER_ENDPOINT_DATA : OUTPUT_DATA_TYPE := gen_reader_endpoint_data; function gen_writer_endpoint_data return OUTPUT_DATA_TYPE is variable ret : OUTPUT_DATA_TYPE := (data => (others => (others => '0')), length => 0); variable ind : natural := 0; variable len : natural := 0; variable tmp : natural := 0; begin ret.data := (others => (others => '0')); ret.length := 0; -- Sanity Check if (NUM_WRITERS = 0) then return ret; end if; len := 0; ind := 0; -- RTPS Submessages -- One DATA Submessage for each Writer Endpoint for i in NUM_READERS to NUM_ENDPOINTS-1 loop -- RTPS Submessage Header ret.data(ind) := SID_DATA & "00000100" & x"0000"; -- DATA Header (extraFlags, octetsToInlineQoS) len := len + 1; ret.data(ind+len) := x"0000" & std_logic_vector(to_unsigned(16, 16)); -- DATA Header (Reader Entity ID) len := len + 1; ret.data(ind+len) := ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR; -- DATA Header (Writer Entity ID) len := len + 1; ret.data(ind+len) := ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER; -- DATA Header (Sequence Number) len := len + 1; ret.data(ind+len) := (others => '0'); -- DATA Header (Sequence Number) len := len + 1; ret.data(ind+len) := std_logic_vector(to_unsigned(i-NUM_READERS+1, ret.data(0)'length)); -- Serialized Payload Header len := len + 1; ret.data(ind+len) := PL_CDR_BE & x"0000"; -- Serialized Payload BEGIN -- GUID len := len + 1; ret.data(ind+len):= PID_ENDPOINT_GUID & std_logic_vector(to_unsigned(16, 16)); len := len + 1; ret.data(ind+len) := GUIDPREFIX(0); len := len + 1; ret.data(ind+len) := GUIDPREFIX(1); len := len + 1; ret.data(ind+len) := GUIDPREFIX(2); len := len + 1; ret.data(ind+len) := ENTITYID(i); -- TOPIC NAME tmp := string_len(ENDPOINT_TOPIC(i)); len := len + 1; ret.data(ind+len) := PID_TOPIC_NAME & std_logic_vector(to_unsigned((round_div(tmp,4)+1)*4, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(to_unsigned(tmp, 32)); for j in 0 to round_div(tmp,4)-1 loop len := len + 1; ret.data(ind+len) := ENDPOINT_TOPIC(i)(j); end loop; -- TYPE NAME tmp := string_len(ENDPOINT_TYPE(i)); len := len + 1; ret.data(ind+len) := PID_TYPE_NAME & std_logic_vector(to_unsigned((round_div(tmp,4)+1)*4, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(to_unsigned(tmp, 32)); for j in 0 to round_div(tmp,4)-1 loop len := len + 1; ret.data(ind+len) := ENDPOINT_TYPE(i)(j); end loop; -- DURABILITY if (ENDPOINT_CONFIG(i).DURABILITY_QOS /= DEFAULT_DURABILITY_QOS) then len := len + 1; ret.data(ind+len) := PID_DURABILITY & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_QOS; end if; -- DURABILITY SERVICE if (ENDPOINT_CONFIG(i).DURABILITY_SERVICE_CLEANUP_DELAY /= DEFAULT_DURABILITY_SERVICE_CLEANUP_DELAY or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY /= DEFAULT_DURABILITY_SERVICE_HISTORY or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY_DEPTH /= DEFAULT_DURABILITY_SERVICE_HISTORY_DEPTH or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES /= DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_INSTANCES /= DEFAULT_DURABILITY_SERVICE_MAX_INSTANCES or ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE /= DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE ) then len := len + 1; ret.data(ind+len) := PID_DURABILITY_SERVICE & std_logic_vector(to_unsigned(28, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DURABILITY_SERVICE_CLEANUP_DELAY(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DURABILITY_SERVICE_CLEANUP_DELAY(1)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_HISTORY_DEPTH; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_INSTANCES; len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE; end if; -- PRESENTATION if (ENDPOINT_CONFIG(i).PRESENTATION_QOS /= DEFAULT_PRESENTATION_QOS or ENDPOINT_CONFIG(i).COHERENT_ACCESS /= DEFAULT_COHERENT_ACCESS or ENDPOINT_CONFIG(i).ORDERED_ACCESS /= DEFAULT_ORDERED_ACCESS) then len := len + 1; ret.data(ind+len) := PID_PRESENTATION & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).PRESENTATION_QOS; len := len + 1; ret.data(ind+len) := (24 => boolean_to_std_logic(ENDPOINT_CONFIG(i).COHERENT_ACCESS), 16 => boolean_to_std_logic(ENDPOINT_CONFIG(i).ORDERED_ACCESS), others => '0'); end if; -- DEADLINE if (ENDPOINT_CONFIG(i).DEADLINE_QOS /= DEFAULT_DEADLINE_QOS) then len := len + 1; ret.data(ind+len) := PID_DEADLINE & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DEADLINE_QOS(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).DEADLINE_QOS(1)); end if; -- LATENCY_BUDGET if (ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS /= DEFAULT_LATENCY_BUDGET_QOS) then len := len + 1; ret.data(ind+len) := PID_LATENCY_BUDGET & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS(1)); end if; -- OWNERSHIP if (ENDPOINT_CONFIG(i).OWNERSHIP_QOS /= DEFAULT_OWNERSHIP_QOS) then len := len + 1; ret.data(ind+len) := PID_OWNERSHIP & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).OWNERSHIP_QOS; end if; -- OWNERSHIP STRENGTH if (ENDPOINT_CONFIG(i).OWNERSHIP_STRENGTH_QOS /= DEFAULT_OWNERSHIP_STRENGTH_QOS) then len := len + 1; ret.data(ind+len) := PID_OWNERSHIP_STRENGTH & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).OWNERSHIP_STRENGTH_QOS; end if; -- LIVELINESS if (ENDPOINT_CONFIG(i).LIVELINESS_QOS /= DEFAULT_LIVELINESS_QOS or ENDPOINT_CONFIG(i).LEASE_DURATION /= DEFAULT_LEASE_DURATION) then len := len + 1; ret.data(ind+len) := PID_LIVELINESS & std_logic_vector(to_unsigned(12, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).LIVELINESS_QOS; len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LEASE_DURATION(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LEASE_DURATION(1)); end if; -- RELIABILITY if (ENDPOINT_CONFIG(i).RELIABILITY_QOS /= DEFAULT_RELIABILITY_QOS_W or ENDPOINT_CONFIG(i).MAX_BLOCKING_TIME /= DEFAULT_MAX_BLOCKING_TIME) then len := len + 1; ret.data(ind+len) := PID_RELIABILITY & std_logic_vector(to_unsigned(12, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).RELIABILITY_QOS; len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).MAX_BLOCKING_TIME(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).MAX_BLOCKING_TIME(1)); end if; -- LIFESPAN if (ENDPOINT_CONFIG(i).LIFESPAN_QOS /= DEFAULT_LIFESPAN_QOS) then len := len + 1; ret.data(ind+len) := PID_LIFESPAN & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LIFESPAN_QOS(0)); len := len + 1; ret.data(ind+len) := std_logic_vector(ENDPOINT_CONFIG(i).LIFESPAN_QOS(1)); end if; -- DESTINATION ORDER if (ENDPOINT_CONFIG(i).DESTINATION_ORDER_QOS /= DEFAULT_DESTINATION_ORDER_QOS) then len := len + 1; ret.data(ind+len) := PID_DESTINATION_ORDER & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(ind+len) := ENDPOINT_CONFIG(i).DESTINATION_ORDER_QOS; end if; -- TODO: MAX_SIZE_SERIALIZED -- SENTINEL len := len + 1; ret.data(ind+len) := PID_SENTINEL & std_logic_vector(to_unsigned(0, 16)); -- Fix Submessage Length ret.data(ind)(15 downto 0) := std_logic_vector(to_unsigned(len*4, 16)); -- Reset Pointers ind := ind + len + 1; len := 0; end loop; -- Store Total Length ret.length := ind; return ret; end function; constant WRITER_ENDPOINT_DATA : OUTPUT_DATA_TYPE := gen_writer_endpoint_data; function gen_inline_qos (id : natural) return OUTPUT_DATA_TYPE is variable ret : OUTPUT_DATA_TYPE := (data => (others => (others => '0')), length => 0); variable ind : natural := 0; variable tmp : natural := 0; begin -- NOTE: We cannot fail, because the default values of some generics may attempt to generate invalid values before overwritten. --assert (id >= NUM_READERS) report "Inline Qos can only be generated for Writer Endpoints" severity FAILURE; if (id < NUM_READERS) then report "Inline Qos can only be generated for Writer Endpoints (Attempted on ID " & integer'image(id) & ")" severity WARNING; return ret; end if; -- TOPIC NAME tmp := string_len(ENDPOINT_TOPIC(id)); ret.data(ret.length) := PID_TOPIC_NAME & std_logic_vector(to_unsigned((round_div(tmp,4)+1)*4, 16)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(to_unsigned(tmp, 32)); for j in 0 to round_div(tmp,4)-1 loop ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_TOPIC(id)(j); end loop; -- DURABILITY if (ENDPOINT_CONFIG(id).DURABILITY_QOS /= DEFAULT_DURABILITY_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_DURABILITY & std_logic_vector(to_unsigned(4, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).DURABILITY_QOS; end if; -- PRESENTATION if (ENDPOINT_CONFIG(id).PRESENTATION_QOS /= DEFAULT_PRESENTATION_QOS or ENDPOINT_CONFIG(id).COHERENT_ACCESS /= DEFAULT_COHERENT_ACCESS or ENDPOINT_CONFIG(id).ORDERED_ACCESS /= DEFAULT_ORDERED_ACCESS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_PRESENTATION & std_logic_vector(to_unsigned(8, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).PRESENTATION_QOS; ret.length := ret.length + 1; ret.data(ret.length) := (24 => boolean_to_std_logic(ENDPOINT_CONFIG(id).COHERENT_ACCESS), 16 => boolean_to_std_logic(ENDPOINT_CONFIG(id).ORDERED_ACCESS), others => '0'); end if; -- DEADLINE if (ENDPOINT_CONFIG(id).DEADLINE_QOS /= DEFAULT_DEADLINE_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_DEADLINE & std_logic_vector(to_unsigned(8, 16)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).DEADLINE_QOS(0)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).DEADLINE_QOS(1)); end if; -- LATENCY_BUDGET if (ENDPOINT_CONFIG(id).LATENCY_BUDGET_QOS /= DEFAULT_LATENCY_BUDGET_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_LATENCY_BUDGET & std_logic_vector(to_unsigned(8, 16)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).LATENCY_BUDGET_QOS(0)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).LATENCY_BUDGET_QOS(1)); end if; -- OWNERSHIP if (ENDPOINT_CONFIG(id).OWNERSHIP_QOS /= DEFAULT_OWNERSHIP_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_OWNERSHIP & std_logic_vector(to_unsigned(4, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).OWNERSHIP_QOS; end if; -- OWNERSHIP STRENGTH if (ENDPOINT_CONFIG(id).OWNERSHIP_STRENGTH_QOS /= DEFAULT_OWNERSHIP_STRENGTH_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_OWNERSHIP_STRENGTH & std_logic_vector(to_unsigned(4, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).OWNERSHIP_STRENGTH_QOS; end if; -- LIVELINESS if (ENDPOINT_CONFIG(id).LIVELINESS_QOS /= DEFAULT_LIVELINESS_QOS or ENDPOINT_CONFIG(id).LEASE_DURATION /= DEFAULT_LEASE_DURATION) then ret.length := ret.length + 1; ret.data(ret.length) := PID_LIVELINESS & std_logic_vector(to_unsigned(12, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).LIVELINESS_QOS; ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).LEASE_DURATION(0)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).LEASE_DURATION(1)); end if; -- RELIABILITY if (ENDPOINT_CONFIG(id).RELIABILITY_QOS /= DEFAULT_RELIABILITY_QOS_W or ENDPOINT_CONFIG(id).MAX_BLOCKING_TIME /= DEFAULT_MAX_BLOCKING_TIME) then ret.length := ret.length + 1; ret.data(ret.length) := PID_RELIABILITY & std_logic_vector(to_unsigned(12, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).RELIABILITY_QOS; ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).MAX_BLOCKING_TIME(0)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).MAX_BLOCKING_TIME(1)); end if; -- LIFESPAN if (ENDPOINT_CONFIG(id).LIFESPAN_QOS /= DEFAULT_LIFESPAN_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_LIFESPAN & std_logic_vector(to_unsigned(8, 16)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).LIFESPAN_QOS(0)); ret.length := ret.length + 1; ret.data(ret.length) := std_logic_vector(ENDPOINT_CONFIG(id).LIFESPAN_QOS(1)); end if; -- DESTINATION ORDER if (ENDPOINT_CONFIG(id).DESTINATION_ORDER_QOS /= DEFAULT_DESTINATION_ORDER_QOS) then ret.length := ret.length + 1; ret.data(ret.length) := PID_DESTINATION_ORDER & std_logic_vector(to_unsigned(4, 16)); ret.length := ret.length + 1; ret.data(ret.length) := ENDPOINT_CONFIG(id).DESTINATION_ORDER_QOS; end if; -- SENTINEL ret.length := ret.length + 1; ret.data(ret.length) := PID_SENTINEL & std_logic_vector(to_unsigned(0, 16)); -- Final Length ret.length := ret.length + 1; return ret; end function; function gen_participant_data return OUTPUT_DATA_TYPE is variable ret : OUTPUT_DATA_TYPE := (data => (others => (others => '0')), length => 0); variable len : natural := 0; variable tmp : natural := 0; begin ret.data := (others => (others => '0')); ret.length := 0; len := 0; -- RTPS DATA SUBMESSAGE -- RTPS Submessage Header ret.data(len) := SID_DATA & "00000100" & x"0000"; -- DATA Header (extraFlags, octetsToInlineQoS) len := len + 1; ret.data(len) := x"0000" & std_logic_vector(to_unsigned(16, 16)); -- DATA Header (Reader Entity ID) len := len + 1; ret.data(len) := ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR; -- DATA Header (Writer Entity ID) len := len + 1; ret.data(len) := ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER; -- DATA Header (Sequence Number) len := len + 1; ret.data(len) := (others => '0'); -- DATA Header (Sequence Number) len := len + 1; ret.data(len) := std_logic_vector(to_unsigned(1, ret.data(len)'length)); -- Serialized Payload Header len := len + 1; ret.data(len) := PL_CDR_BE & x"0000"; -- Serialized Payload BEGIN -- GUID len := len + 1; ret.data(len):= PID_PARTICIPANT_GUID & std_logic_vector(to_unsigned(16, 16)); len := len + 1; ret.data(len) := GUIDPREFIX(0); len := len + 1; ret.data(len) := GUIDPREFIX(1); len := len + 1; ret.data(len) := GUIDPREFIX(2); len := len + 1; ret.data(len) := ENTITYID_PARTICIPANT; -- DOMAIN ID len := len + 1; ret.data(len):= PID_DOMAIN_ID & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(len):= DOMAIN_ID; -- DOMAIN TAG if (DOMAIN_TAG /= DEFAULT_DOMAIN_TAG) then tmp := string_len(DOMAIN_TAG); len := len + 1; ret.data(len) := PID_DOMAIN_TAG & std_logic_vector(to_unsigned((round_div(tmp,4)+1)*4, 16)); len := len + 1; ret.data(len) := std_logic_vector(to_unsigned(tmp, 32)); for j in 0 to round_div(tmp,4)-1 loop len := len + 1; ret.data(len) := DOMAIN_TAG(j); end loop; end if; -- PROTOCOL VERSION len := len + 1; ret.data(len) := PID_PROTOCOL_VERSION & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(len) := (others => '0'); ret.data(len)(31 downto 16) := PROTOCOLVERSION_2_4; -- VENDORID len := len + 1; ret.data(len) := PID_VENDORID & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(len) := (others => '0'); ret.data(len)(31 downto 16) := VENDORID; -- TODO: Expects inline QoS of Participant -- METATRAFFIC MULTICAST LOCATOR len := len + 1; ret.data(len) := PID_METATRAFFIC_MULTICAST_LOCATOR & std_logic_vector(to_unsigned(24, 16)); len := len + 1; ret.data(len) := LOCATOR_KIND_UDPv4; len := len + 1; ret.data(len) := (others => '0'); ret.data(len)(15 downto 0) := META_IPv4_MULTICAST_PORT; len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := DEFAULT_IPv4_ADDRESS; -- METATRAFFIC UNICAST LOCATOR len := len + 1; ret.data(len) := PID_METATRAFFIC_UNICAST_LOCATOR & std_logic_vector(to_unsigned(24, 16)); len := len + 1; ret.data(len) := LOCATOR_KIND_UDPv4; len := len + 1; ret.data(len) := (others => '0'); ret.data(len)(15 downto 0) := META_IPv4_UNICAST_PORT; len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := DEFAULT_IPv4_ADDRESS; -- DEFAULT MULTICAST LOCATOR len := len + 1; ret.data(len) := PID_DEFAULT_MULTICAST_LOCATOR & std_logic_vector(to_unsigned(24, 16)); len := len + 1; ret.data(len) := LOCATOR_KIND_UDPv4; len := len + 1; ret.data(len) := (others => '0'); ret.data(len)(15 downto 0) := USER_IPv4_MULTICAST_PORT; len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := DEFAULT_IPv4_ADDRESS; -- DEFAULT UNICAST LOCATOR len := len + 1; ret.data(len) := PID_DEFAULT_UNICAST_LOCATOR & std_logic_vector(to_unsigned(24, 16)); len := len + 1; ret.data(len) := LOCATOR_KIND_UDPv4; len := len + 1; ret.data(len) := (others => '0'); ret.data(len)(15 downto 0) := USER_IPv4_UNICAST_PORT; len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := (others => '0'); len := len + 1; ret.data(len) := DEFAULT_IPv4_ADDRESS; -- LEASE DURATION if (PARTICIPANT_LEASE_DURATION /= DEFAULT_PARTICIPANT_LEASE_DURATION) then len := len + 1; ret.data(len) := PID_PARTICIPANT_LEASE_DURATION & std_logic_vector(to_unsigned(8, 16)); len := len + 1; ret.data(len) := std_logic_vector(PARTICIPANT_LEASE_DURATION(0)); len := len + 1; ret.data(len) := std_logic_vector(PARTICIPANT_LEASE_DURATION(1)); end if; -- AVAILABLE ENDPOINTS len := len + 1; ret.data(len) := PID_BUILTIN_ENDPOINT_SET & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(len) := (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'); if (NUM_READERS > 0) then ret.data(len)(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR) := '1'; ret.data(len)(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER):= '1'; end if; if (NUM_WRITERS > 0) then ret.data(len)(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER) := '1'; ret.data(len)(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR) := '1'; end if; -- MANUAL LIVELINESS COUNT len := len + 1; ret.data(len) := PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT & std_logic_vector(to_unsigned(4, 16)); len := len + 1; ret.data(len) := (others => '0'); -- SENTINEL len := len + 1; ret.data(len) := PID_SENTINEL & std_logic_vector(to_unsigned(0, 16)); -- Fix Submessage Length ret.data(0)(15 downto 0) := std_logic_vector(to_unsigned(len*4, 16)); -- Store Length ret.length := len + 1; return ret; end function; constant LOCAL_PARTICIPANT_DATA : OUTPUT_DATA_TYPE := gen_participant_data; -- Direction 0 : Offered <= Requested -- Direction 1 : Offered >= Requested -- src_is_reader 1 : Remote is Subscriber-Requested -- src_is_reader 0 : Remote is Publisher-Offered function check_qos_compatibility(src_is_reader : std_logic; direction : std_logic; remote : unsigned(WORD_WIDTH-1 downto 0); local : unsigned(WORD_WIDTH-1 downto 0)) return boolean is variable ret : boolean; begin -- Default Match ret := TRUE; if ((src_is_reader xor direction) = '1') then if (remote < local) then ret := FALSE; end if; else if (remote > local) then ret := FALSE; end if; end if; return ret; end function; -- Direction 0 : Offered <= Requested -- Direction 1 : Offered >= Requested -- src_is_reader 1 : Remote is Subscriber-Requested -- src_is_reader 0 : Remote is Publisher-Offered function check_qos_compatibility(src_is_reader : std_logic; direction : std_logic; remote : DOUBLE_WORD_ARRAY; local : DOUBLE_WORD_ARRAY) return boolean is variable ret : boolean; begin -- Default Match ret := TRUE; if ((src_is_reader xor direction) = '1') then if (remote < local) then ret := FALSE; end if; else if (remote > local) then ret := FALSE; end if; end if; return ret; end function; function gen_default_qos_match(is_reader : boolean) return DEFAULT_QOS_MATCH_TYPE is variable ret : DEFAULT_QOS_MATCH_TYPE; begin -- Default Match ret := (others => (others => '1')); for i in 0 to NUM_ENDPOINTS-1 loop -- DURABILITY if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '1', unsigned(DEFAULT_DURABILITY_QOS), unsigned(ENDPOINT_CONFIG(i).DURABILITY_QOS))) then ret.DURABILITY_QOS(i) := '0'; end if; -- PRESENTATION if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '1', unsigned(DEFAULT_PRESENTATION_QOS), unsigned(ENDPOINT_CONFIG(i).PRESENTATION_QOS))) then ret.PRESENTATION_QOS(i) := '0'; end if; if (is_reader) then if (DEFAULT_COHERENT_ACCESS and not ENDPOINT_CONFIG(i).COHERENT_ACCESS) then ret.PRESENTATION_QOS(i) := '0'; end if; if (DEFAULT_ORDERED_ACCESS and not ENDPOINT_CONFIG(i).ORDERED_ACCESS) then ret.PRESENTATION_QOS(i) := '0'; end if; else if (not DEFAULT_COHERENT_ACCESS and ENDPOINT_CONFIG(i).COHERENT_ACCESS) then ret.PRESENTATION_QOS(i) := '0'; end if; if (not DEFAULT_ORDERED_ACCESS and ENDPOINT_CONFIG(i).ORDERED_ACCESS) then ret.PRESENTATION_QOS(i) := '0'; end if; end if; -- DEADLINE if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '0', DEFAULT_DEADLINE_QOS(0), ENDPOINT_CONFIG(i).DEADLINE_QOS(0))) then ret.DEADLINE_QOS(i) := '0'; end if; if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '0', DEFAULT_DEADLINE_QOS(1), ENDPOINT_CONFIG(i).DEADLINE_QOS(1))) then ret.DEADLINE_QOS(i) := '0'; end if; -- LATENCY_BUDGET if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '0', DEFAULT_LATENCY_BUDGET_QOS(0), ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS(0))) then ret.LATENCY_BUDGET_QOS(i) := '0'; end if; if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '0', DEFAULT_LATENCY_BUDGET_QOS(1), ENDPOINT_CONFIG(i).LATENCY_BUDGET_QOS(1))) then ret.LATENCY_BUDGET_QOS(i) := '0'; end if; -- OWNERSHIP if (DEFAULT_OWNERSHIP_QOS /= ENDPOINT_CONFIG(i).OWNERSHIP_QOS) then ret.OWNERSHIP_QOS(i) := '0'; end if; -- LIVELINESS if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '1', unsigned(DEFAULT_LIVELINESS_QOS), unsigned(ENDPOINT_CONFIG(i).LIVELINESS_QOS))) then ret.LIVELINESS_QOS(i) := '0'; end if; if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '0', DEFAULT_LEASE_DURATION(0), ENDPOINT_CONFIG(i).LEASE_DURATION(0))) then ret.LIVELINESS_QOS(i) := '0'; end if; if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '0', DEFAULT_LEASE_DURATION(1), ENDPOINT_CONFIG(i).LEASE_DURATION(1))) then ret.LIVELINESS_QOS(i) := '0'; end if; -- RELIABILITY if (is_reader) then if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '1', unsigned(DEFAULT_RELIABILITY_QOS_R), unsigned(ENDPOINT_CONFIG(i).RELIABILITY_QOS))) then ret.RELIABILITY_QOS(i) := '0'; end if; else if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '1', unsigned(DEFAULT_RELIABILITY_QOS_W), unsigned(ENDPOINT_CONFIG(i).RELIABILITY_QOS))) then ret.RELIABILITY_QOS(i) := '0'; end if; end if; -- DESTINATION_ORDER if (not check_qos_compatibility(boolean_to_std_logic(is_reader), '1', unsigned(DEFAULT_DESTINATION_ORDER_QOS), unsigned(ENDPOINT_CONFIG(i).DESTINATION_ORDER_QOS))) then ret.DESTINATION_ORDER_QOS(i) := '0'; end if; end loop; return ret; end function; constant READER_DEFAULT_QOS_MATCH : DEFAULT_QOS_MATCH_TYPE := gen_default_qos_match(TRUE); constant WRITER_DEFAULT_QOS_MATCH : DEFAULT_QOS_MATCH_TYPE := gen_default_qos_match(FALSE); function gen_liveliness_slv(qos : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0)) return std_logic_vector is variable ret : std_logic_vector(0 to NUM_ENDPOINTS-1) := (others => '0'); begin for i in 0 to NUM_ENDPOINTS-1 loop if (ENDPOINT_CONFIG(i).LIVELINESS_QOS = qos) then ret(i) := '1'; end if; end loop; return ret; end function; constant AUTOMATIC_LIVELINESS_WRITERS : std_logic_vector(0 to NUM_ENDPOINTS-1) := gen_liveliness_slv(AUTOMATIC_LIVELINESS_QOS) and (not ENDPOINT_READERS); constant MANUAL_BY_PARTICIPANT_LIVELINESS_WRITERS : std_logic_vector(0 to NUM_ENDPOINTS-1) := gen_liveliness_slv(MANUAL_BY_PARTICIPANT_LIVELINESS_QOS) and (not ENDPOINT_READERS); constant AUTOMATIC_LIVELINESS_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1) := gen_liveliness_slv(AUTOMATIC_LIVELINESS_QOS) and ENDPOINT_READERS; constant MANUAL_BY_PARTICIPANT_LIVELINESS_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1) := gen_liveliness_slv(MANUAL_BY_PARTICIPANT_LIVELINESS_QOS) and ENDPOINT_READERS; -- Returns the 'data' argument either as is, or with reversed Byte order, depending on the -- 'swap' argument. function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector is variable ret, ref : std_logic_vector(data'length-1 downto 0); begin -- Assert that Data Signal is Byte aligned assert (data'length mod 8 = 0) severity failure; -- NOTE: The input signal is explicitly copied over to make sure the slice is (length-1 downto 0) ref := data; -- Little Endian if (swap = '1') then -- Reverse byte Order for i in 0 to (data'length/8)-1 loop ret(i*8+8-1 downto i*8) := ref(((data'length/8)-1-i)*8+8-1 downto ((data'length/8)-1-i)*8); end loop; -- Big Endian else ret := data; end if; return ret; end function; -- Returns the 'data' argument either as is, or with reversed Byte order, depending on the -- 'swap' argument. function endian_swap(swap : std_logic; data : unsigned) return unsigned is begin return unsigned(endian_swap(swap, std_logic_vector(data))); end function; function round_slv(slv : std_logic_vector; width : natural) return std_logic_vector is variable ret : std_logic_vector(width-1 downto 0) := (others => '0'); begin ret := slv(slv'length-1 downto slv'length-width); if (slv(slv'length-width-1 downto 0) /= (slv'length-width-1 downto 0 => '0')) then ret := std_logic_vector(unsigned(ret) + 1); end if; return ret; end function; function check_mask(flags : std_logic_vector; mask : std_logic_vector) return boolean is begin assert (flags'length = mask'length) report "Flag and mask Signal have unequal length" severity FAILURE; if ((flags and mask) = mask) then return TRUE; else return FALSE; end if; end function; end package body;