rtps-fpga/src/rtps_config_package.vhd

1189 lines
60 KiB
VHDL

-- 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;