* Package update

- New functions
	- Renames
	- New Definitions
* rtps_handler overhaul
	- Validity Check for Submessages
	- OVERREAD Guard
	- Info Timestamp parsed and sent to Endpoints
This commit is contained in:
Greek 2020-11-09 14:58:59 +01:00
parent 9acd98b32e
commit c68caec626
8 changed files with 854 additions and 403 deletions

View File

@ -1,3 +1,12 @@
RULES 8.3.4.1 (Message Receiver)
================================
* If the full Submessage header cannot be read, the rest of the Message is considered invalid.
* If submessageLength field is invalid, the rest of the Message is invalid.
* A Submessage with an unknown SubmessageId must be ignored and parsing must continue with the next Submessage.
* The receiver of a Submessage should ignore unknown flags.
* A valid submessageLength field must always be used to find the next Submessage.
* A known but invalid Submessage invalidates the rest of the Message.
RULES 8.4.2 RULES 8.4.2
=========== ===========
@ -85,10 +94,64 @@ ENDPOINT FIFO PACKET FORMAT
| | | |
+-------------------------------------------------------------+ +-------------------------------------------------------------+
| | | |
+ Timestamp +
| [only for DATA Submessage and User Destinations] |
+-------------------------------------------------------------+
| |
~ PAYLOAD (SUBMESSAGE CONTENT) ~ ~ PAYLOAD (SUBMESSAGE CONTENT) ~
| | | |
+-------------------------------------------------------------+ +-------------------------------------------------------------+
HEARTBEAT PAYLOAD
-----------------
31............24..............16..............8...............0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-------------------------------------------------------------+
| |
+ FirstSN +
| |
+-------------------------------------------------------------+
| |
+ LastSN +
| |
+-------------------------------------------------------------+
| Count |
+-------------------------------------------------------------+
ACKNACK PAYLOAD
---------------
31............24..............16..............8...............0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-------------------------------------------------------------+
| |
+ ReaderSNState.BASE +
| |
+-------------------------------------------------------------+
| ReaderSNState.NumBits |
+-------------------------------------------------------------+
| [ReaderSNState.Bitmap] x 0-8 |
+-------------------------------------------------------------+
| Count |
+-------------------------------------------------------------+
GAP PAYLOAD
-----------
31............24..............16..............8...............0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-------------------------------------------------------------+
| |
+ GapStart +
| |
+-------------------------------------------------------------+
| |
+ GapList.BASE +
| |
+-------------------------------------------------------------+
| GapList.NumBits |
+-------------------------------------------------------------+
| [GapList.Bitmap] x 0-8 |
+-------------------------------------------------------------+
ENDPOINT_ID ENDPOINT_ID
=========== ===========
@ -306,3 +369,99 @@ implementations must include an InfoTimestamp Submessage with every update from
DDS_Advanced_Tutorial_2006_00-T1-2_Pardo.pdf (P.16) DDS_Advanced_Tutorial_2006_00-T1-2_Pardo.pdf (P.16)
INVALIDATION
============
RTPS HEADER (8.3.6.3)
-----------
* The Message has less than the required number of octets to contain a full Header
* Its protocol value does not match the value of PROTOCOL_RTPS
* The major protocol version is larger than the major protocol version supported by the implementation
ACKNACK (8.3.7.1.3)
-------
* submessageLength in the Submessage header is too small
* readerSNState is invalid
DATA (8.3.7.2.3)
----
* submessageLength in the Submessage header is too small
* writerSN.value is not strictly positive (1, 2, ...) or is SEQUENCENUMBER_UNKNOWN
* inlineQos is invalid
DATA FRAG (8.3.7.3.3)
---------
* submessageLength in the Submessage header is too small
* writerSN.value is not strictly positive (1, 2, ...) or is SEQUENCENUMBER_UNKNOWN
* fragmentStartingNum.value is not strictly positive (1, 2, ...) or exceeds the total number of fragments
* fragmentSize exceeds dataSize
* The size of serializedData exceeds (fragmentsInSubmessage * fragmentSize)
* inlineQos is invalid
GAP (8.3.7.4.3)
---
* submessageLength in the Submessage header is too small
* gapStart is zero or negative
* gapList is invalid
* (If GroupInfoFlag is set) gapStartGSN.value is zero or negative
* (If GroupInfoFlag is set) gapEndGSN.value is zero or negative
* (If GroupInfoFlag is set) gapEndGSN.value < gapStartGSN.value-1
HEARTBEAT (8.3.7.5.3)
---------
* submessageLength in the Submessage header is too small
* firstSN.value is zero or negative
* lastSN.value is negative
* lastSN.value < firstSN.value - 1
* (If GroupInfoFlag is set) currentGSN.value is zero or negative
* (If GroupInfoFlag is set) firstGSN.value is zero or negative
* (If GroupInfoFlag is set) lastGSN.value is negative
* (If GroupInfoFlag is set) lastGSN.value < firstGSN.value - 1
* (If GroupInfoFlag is set) currentGSN.value < firstGSN.value
* (If GroupInfoFlag is set) currentGSN.value < lastGSN.value
HEARTBEAT FRAG (8.3.7.6.3)
--------------
* submessageLength in the Submessage header is too small
* writerSN.value is zero or negative
* lastFragmentNum.value is zero or negative
INFO DESTINATION (8.3.7.7.3)
----------------
* submessageLength in the Submessage header is too small
INFO REPLY (8.3.7.8.3)
----------
* submessageLength in the Submessage header is too small
INFO SOURCE (8.3.7.9.3)
-----------
* submessageLength in the Submessage header is too small
INFO TIMESTAMP (8.3.7.10.3)
--------------
* submessageLength in the Submessage header is too small
NACK FRAG (8.3.7.11.3)
---------
* submessageLength in the Submessage header is too small
* writerSN.value is zero or negative
* fragmentNumberState is invalid
PAD (8.3.7.12.3)
---
ALWAYS VALID
NumberSet (9.4.2.6)
---------
* bitmapBase <= 0
* numBits < 0 or numBits > 256
* M/=(numBits+31)/32 longs in Submessage
Parameter List (8.3.5.9)
--------------
* There shall be no more than 2^16 possible values of the ParameterId_t parameterId
* A range of 2^15 values is reserved for protocol-defined parameters
* A range of 2^15 values is reserved for vendor-defined parameters
* The maximum length of any parameter is limited to 2^16 octets

View File

@ -48,12 +48,15 @@
But then, in 8.4.15.7 it says: But then, in 8.4.15.7 it says:
"So, an implementation should ensure that same logical HEARTBEATs are tagged with the same Count." "So, an implementation should ensure that same logical HEARTBEATs are tagged with the same Count."
Does that mean there are cases were I have to put the same count? What is a logical HEARTBEAT? Does that mean there are cases were I have to put the same count? What is a logical HEARTBEAT?
* Should a "Keyed" Endpoint communicate with a "Non-Keyed"?
* Is the empty String a valid Topic and Type Name?
* We can determine if a Endpoint is a Reader or Writer via the Entity ID. Is it illegal to get a SEDP with incompatible source (Reader Entity ID from Publications Announcer?)
* Fast-RTPS doen not follow DDSI-RTPS Specification * Fast-RTPS doen not follow DDSI-RTPS Specification
- Open Github Issue - Open Github Issue
https://github.com/eProsima/Fast-RTPS/issues/1221 https://github.com/eProsima/Fast-RTPS/issues/1221
- Seems that Fast-RTPS is also not checking the Validity of Submessages according to Spec
* DDSI-RTPS 2.3 ISSUES * DDSI-RTPS 2.3 ISSUES
- 8.3.7.7 InfoDestination - 8.3.7.7 InfoDestination
@ -64,10 +67,13 @@
writerSN is incorrectly shown as only 32 bits in width writerSN is incorrectly shown as only 32 bits in width
- 8.3.4 The RTPS Message Receiver, Table 8.16 - Initial State of the Receiver - 8.3.4 The RTPS Message Receiver, Table 8.16 - Initial State of the Receiver
Port of UnicastReplyLocatorList should be initialized to Source Port. Port of UnicastReplyLocatorList should be initialized to Source Port.
- 8.3.7.4.3 Validity
gapList.Base >= gapStart
- 8.3.7.10.3 Validity - 8.3.7.10.3 Validity
'This Submessage is invalid when the following is true: 'This Submessage is invalid when the following is true:
submessageLength in the Submessage header is too small' submessageLength in the Submessage header is too small'
But if InvalidateFlag is set, Length can be Zero. Since the length is unsigned, there cannot be an invalid length. But if InvalidateFlag is set, Length can be Zero. Since the length is unsigned, there cannot be an invalid length.
- 9.4.5.1.2 Flags - 9.4.5.1.2 Flags
Clarify from where the endianness begins. Clarify from where the endianness begins.
One might think it would begin after the Submessage Header, but the length is also endian dependent. One might think it would begin after the Submessage Header, but the length is also endian dependent.
@ -101,5 +107,15 @@ DESIGN DECISIONS
Use the lowest bit of the Heartbeat/Acknack Deadline stored in the Participant Data to differentiate Use the lowest bit of the Heartbeat/Acknack Deadline stored in the Participant Data to differentiate
between Delay and Suppression. This reduces the resolution from 0.23 ns to 0.47 ns between Delay and Suppression. This reduces the resolution from 0.23 ns to 0.47 ns
PROTOCOL UNCOMPLIANCE
=====================
* Partition QoS
* Built-in Endpoint is NOT the same as a normal Endpoint
-> No User access to Data
* Known but unused Submessage IDs are treated as uknown
-> No validity check
* Inline QoS validated in Endpoint
-> Cannot invalidate Rest of Message/Packet
-- Input FIFO Guard -- Input FIFO Guard
-- Output FIFO Guard -- Output FIFO Guard

View File

@ -58,6 +58,7 @@ package body math_pkg is
return ret_value; return ret_value;
end function; end function;
-- TODO: Rename to ceil_div, since we do not actually round
function round_div(constant divident, divisor : in integer) return integer is function round_div(constant divident, divisor : in integer) return integer is
variable ret : integer; variable ret : integer;
begin begin

View File

@ -115,10 +115,10 @@ architecture arch of rtps_builtin_endpoint is
lease_deadline : TIME_TYPE; lease_deadline : TIME_TYPE;
heartbeat_res_time : TIME_TYPE; heartbeat_res_time : TIME_TYPE;
acknack_res_time : TIME_TYPE; acknack_res_time : TIME_TYPE;
spdp_seq_nr : SEQUENCE_NR_TYPE; spdp_seq_nr : SEQUENCENUMBER_TYPE;
pub_seq_nr : SEQUENCE_NR_TYPE; pub_seq_nr : SEQUENCENUMBER_TYPE;
sub_seq_nr : SEQUENCE_NR_TYPE; sub_seq_nr : SEQUENCENUMBER_TYPE;
mes_seq_nr : SEQUENCE_NR_TYPE; mes_seq_nr : SEQUENCENUMBER_TYPE;
end record; end record;
--*****CONSTANT DECLARATION***** --*****CONSTANT DECLARATION*****
@ -155,11 +155,9 @@ architecture arch of rtps_builtin_endpoint is
-- Signifies if the Reader Endpoint expects in-line QoS -- Signifies if the Reader Endpoint expects in-line QoS
constant EXPECTS_INLINE_QOS_FLAG : natural := 0; constant EXPECTS_INLINE_QOS_FLAG : natural := 0;
-- Highest Sequence Number of Publisher Data -- Highest Sequence Number of Publisher Data
constant PUB_SEQUENCE_NR : SEQUENCE_NR_TYPE := convert_to_double_word(to_unsigned(NUM_WRITERS, 64)); constant PUB_SEQUENCENUMBER : SEQUENCENUMBER_TYPE := convert_to_double_word(to_unsigned(NUM_WRITERS, 64));
-- Highest Sequence Number of Subscriber Data -- Highest Sequence Number of Subscriber Data
constant SUB_SEQUENCE_NR : SEQUENCE_NR_TYPE := convert_to_double_word(to_unsigned(NUM_READERS, 64)); constant SUB_SEQUENCENUMBER : SEQUENCENUMBER_TYPE := convert_to_double_word(to_unsigned(NUM_READERS, 64));
-- Constant for Sequence Number 1
constant SEQUENCE_NR_START : SEQUENCE_NR_TYPE := convert_to_double_word(to_unsigned(1, 64));
-- Heartbeat/Liveliness Assertion Period -- Heartbeat/Liveliness Assertion Period
constant HEARTBEAT_PERIOD : DURATION_TYPE := work.rtps_package.min(MIN_ENDPOINT_LEASE_DURATION, PARTICIPANT_HEARTBEAT_PERIOD) - DURATION_DELTA; constant HEARTBEAT_PERIOD : DURATION_TYPE := work.rtps_package.min(MIN_ENDPOINT_LEASE_DURATION, PARTICIPANT_HEARTBEAT_PERIOD) - DURATION_DELTA;
-- Constant for zero Participant Data -- Constant for zero Participant Data
@ -208,7 +206,7 @@ architecture arch of rtps_builtin_endpoint is
-- Source GUID Latch -- Source GUID Latch
signal guid, guid_next : GUID_TYPE := (others => (others => '0')); signal guid, guid_next : GUID_TYPE := (others => (others => '0'));
-- RTPS DATA Submessage Sequence Number Latch -- RTPS DATA Submessage Sequence Number Latch
signal seq_nr, seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Word aligned End of Parameter -- Word aligned End of Parameter
signal parameter_end, parameter_end_next : unsigned(PARAMETER_LENGTH_WIDTH-1 downto 0) := (others => '0'); signal parameter_end, parameter_end_next : unsigned(PARAMETER_LENGTH_WIDTH-1 downto 0) := (others => '0');
-- RTPS DATA Submessage Content Type -- RTPS DATA Submessage Content Type
@ -269,13 +267,13 @@ architecture arch of rtps_builtin_endpoint is
-- General Purpose Counter (Memory FSM) -- General Purpose Counter (Memory FSM)
signal mem_cnt, mem_cnt_next : natural range 0 to max(22, ENDPOINT_BITMASK_SIZE-1) := 0; signal mem_cnt, mem_cnt_next : natural range 0 to max(22, ENDPOINT_BITMASK_SIZE-1) := 0;
-- Contains the Sequence Number stored in the Buffer of the current relevant Message Type (Participant/Publisher/Subscriber/Message Data) -- Contains the Sequence Number stored in the Buffer of the current relevant Message Type (Participant/Publisher/Subscriber/Message Data)
signal mem_seq_nr, mem_seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal mem_seq_nr, mem_seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Signifies the next expected Sequence Number of the current relevant Message Type (Participant/Publisher/Subscriber/Message Data) -- Signifies the next expected Sequence Number of the current relevant Message Type (Participant/Publisher/Subscriber/Message Data)
signal next_seq_nr, next_seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal next_seq_nr, next_seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Latch used to store the first Sequence Number in ACKNACK/HEARTBEAT/GAP Messages -- Latch used to store the first Sequence Number in ACKNACK/HEARTBEAT/GAP Messages
signal first_seq_nr, first_seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal first_seq_nr, first_seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Latch used to store the last Sequence Number in HEARTBEAT/GAP Messages -- Latch used to store the last Sequence Number in HEARTBEAT/GAP Messages
signal last_seq_nr, last_seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal last_seq_nr, last_seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Signifies if we currently do a Orphan Endpoint Search (Endpoint whose parent Participant was removed) -- Signifies if we currently do a Orphan Endpoint Search (Endpoint whose parent Participant was removed)
signal is_orphan_search, is_orphan_search_next : std_logic := '0'; signal is_orphan_search, is_orphan_search_next : std_logic := '0';
-- Intermediate write enable signal. -- Intermediate write enable signal.
@ -306,13 +304,13 @@ architecture arch of rtps_builtin_endpoint is
signal reset_endpoint_alive : std_logic := '0'; signal reset_endpoint_alive : std_logic := '0';
-- NOTE: The "auto_live_seq_nr" is always higher than "man_live_seq_nr" -- NOTE: The "auto_live_seq_nr" is always higher than "man_live_seq_nr"
-- Contains the highest Sequence Number for automatic liveliness updates -- Contains the highest Sequence Number for automatic liveliness updates
signal auto_live_seq_nr, auto_live_seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal auto_live_seq_nr, auto_live_seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Contains the highest Sequence Number for manual by participant liveliness updates -- Contains the highest Sequence Number for manual by participant liveliness updates
signal man_live_seq_nr, man_live_seq_nr_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal man_live_seq_nr, man_live_seq_nr_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Points to the first Sequence Number after "man_live_seq_nr" (Signifies the start of the GAP between "man_live_seq_nr" and "auto_live_seq_nr") -- Points to the first Sequence Number after "man_live_seq_nr" (Signifies the start of the GAP between "man_live_seq_nr" and "auto_live_seq_nr")
signal live_gap_start, live_gap_start_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal live_gap_start, live_gap_start_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Points to the first Sequence Number before "auto_live_seq_nr" (Signifies the end of the GAP between "man_live_seq_nr" and "auto_live_seq_nr") -- Points to the first Sequence Number before "auto_live_seq_nr" (Signifies the end of the GAP between "man_live_seq_nr" and "auto_live_seq_nr")
signal live_gap_end, live_gap_end_next : SEQUENCE_NR_TYPE := (others => (others => '0')); signal live_gap_end, live_gap_end_next : SEQUENCENUMBER_TYPE := (others => (others => '0'));
-- Participant Announcement Timeout Time -- Participant Announcement Timeout Time
signal announcement_time, announcement_time_next : TIME_TYPE := (others => (others => '0')); signal announcement_time, announcement_time_next : TIME_TYPE := (others => (others => '0'));
-- Heartbeat/Liveliness Assertion Timeout Time -- Heartbeat/Liveliness Assertion Timeout Time
@ -413,20 +411,8 @@ begin
rd <= rd_sig; rd <= rd_sig;
-- This process swaps the input signal "data_in" to Big Endian Representation -- Big Endian Representation
endian_swap_prc: process(all) data_in_swapped <= endian_swap(endian_flag, data_in);
begin
-- DEFAULT
data_in_swapped <= data_in;
-- If in Little Endian Representation
if (endian_flag = '1') then
-- Endian Swap
for i in 0 to 3 loop
data_in_swapped(i*8+8-1 downto i*8) <= data_in((3-i)*8+8-1 downto (3-i)*8);
end loop;
end if;
end process;
-- This process is responsible for toggling the "endpoint_alive" signal -- This process is responsible for toggling the "endpoint_alive" signal
-- The signal is set high when at least one bit of the "alive" signal is high for at least one clock cycle, -- The signal is set high when at least one bit of the "alive" signal is high for at least one clock cycle,
@ -1301,7 +1287,7 @@ begin
-- Subscriber Acknack -- Subscriber Acknack
if (is_subscriber = '1') then if (is_subscriber = '1') then
-- If Reader has not ACKed all Publisher History Cache -- If Reader has not ACKed all Publisher History Cache
if (first_seq_nr <= PUB_SEQUENCE_NR) then if (first_seq_nr <= PUB_SEQUENCENUMBER) then
-- Set Acknack Response Time and Publisher Data as Acknack Response -- Set Acknack Response Time and Publisher Data as Acknack Response
mem_opcode <= UPDATE_PARTICIPANT; mem_opcode <= UPDATE_PARTICIPANT;
deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY; deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY;
@ -1315,7 +1301,7 @@ begin
-- Publisher Acknack -- Publisher Acknack
else else
-- If Reader has not ACKed all Subscriber History Cache -- If Reader has not ACKed all Subscriber History Cache
if (first_seq_nr <= SUB_SEQUENCE_NR) then if (first_seq_nr <= SUB_SEQUENCENUMBER) then
-- Set Acknack Response Time and set Subscriber Data as Acknack Response -- Set Acknack Response Time and set Subscriber Data as Acknack Response
mem_opcode <= UPDATE_PARTICIPANT; mem_opcode <= UPDATE_PARTICIPANT;
deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY; deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY;
@ -1354,7 +1340,7 @@ begin
-- Publisher Data not scheduled for response -- Publisher Data not scheduled for response
if (mem_participant_data.extra_flags(PUB_DATA_FLAG) = '0') then if (mem_participant_data.extra_flags(PUB_DATA_FLAG) = '0') then
-- If Reader has not ACKed all Publisher History Cache -- If Reader has not ACKed all Publisher History Cache
if (first_seq_nr <= PUB_SEQUENCE_NR) then if (first_seq_nr <= PUB_SEQUENCENUMBER) then
-- Set Publisher Data as Acknack Response -- Set Publisher Data as Acknack Response
mem_opcode <= UPDATE_PARTICIPANT; mem_opcode <= UPDATE_PARTICIPANT;
extra_flags_next <= mem_participant_data.extra_flags; extra_flags_next <= mem_participant_data.extra_flags;
@ -1368,7 +1354,7 @@ begin
-- Subscriber Data not scheduled for response -- Subscriber Data not scheduled for response
if (mem_participant_data.extra_flags(SUB_DATA_FLAG) = '0') then if (mem_participant_data.extra_flags(SUB_DATA_FLAG) = '0') then
-- If Reader has not ACKed all Subscriber History Cache -- If Reader has not ACKed all Subscriber History Cache
if (first_seq_nr <= SUB_SEQUENCE_NR) then if (first_seq_nr <= SUB_SEQUENCENUMBER) then
-- Set Subscriber Data as Acknack Response -- Set Subscriber Data as Acknack Response
mem_opcode <= UPDATE_PARTICIPANT; mem_opcode <= UPDATE_PARTICIPANT;
extra_flags_next <= mem_participant_data.extra_flags; extra_flags_next <= mem_participant_data.extra_flags;
@ -1550,7 +1536,7 @@ begin
-- Reset Word Counter -- Reset Word Counter
reset_read_cnt <= '1'; reset_read_cnt <= '1';
-- Latch Parameter End (In order to skip parameters) -- Latch Parameter End (In order to skip parameters)
parameter_end_next <= unsigned(big_endian_swap(endian_flag,parameter_length)); parameter_end_next <= unsigned(endian_swap(endian_flag,parameter_length));
-- DEFAULT STAGE -- DEFAULT STAGE
stage_next <= SKIP_PARAMETER; stage_next <= SKIP_PARAMETER;
@ -1742,7 +1728,7 @@ begin
when PID_PROPERTY_LIST => when PID_PROPERTY_LIST =>
-- Ignore -- Ignore
null; null;
when PID_TYPE_MAX_SIZE_SERIALIZED => when PID_DATA_MAX_SIZE_SERIALIZED =>
-- Ignore -- Ignore
null; null;
when PID_ENTITY_NAME => when PID_ENTITY_NAME =>
@ -2692,16 +2678,16 @@ begin
output_sig <= ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER; output_sig <= ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER;
-- Sequence Number 1/2 -- Sequence Number 1/2
when 3 => when 3 =>
output_sig <= std_logic_vector(SEQUENCE_NR_START(0)); output_sig <= std_logic_vector(FIRST_SEQUENCENUMBER(0));
-- Sequence Number 2/2 -- Sequence Number 2/2
when 4 => when 4 =>
output_sig <= std_logic_vector(SEQUENCE_NR_START(1)); output_sig <= std_logic_vector(FIRST_SEQUENCENUMBER(1));
-- Sequence Number 1/2 -- Sequence Number 1/2
when 5 => when 5 =>
output_sig <= std_logic_vector(PUB_SEQUENCE_NR(0)); output_sig <= std_logic_vector(PUB_SEQUENCENUMBER(0));
-- Sequence Number 1/2 -- Sequence Number 1/2
when 6 => when 6 =>
output_sig <= std_logic_vector(PUB_SEQUENCE_NR(1)); output_sig <= std_logic_vector(PUB_SEQUENCENUMBER(1));
-- Count -- Count
when 7 => when 7 =>
output_sig <= std_logic_vector(count); output_sig <= std_logic_vector(count);
@ -2717,16 +2703,16 @@ begin
output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER; output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER;
-- Sequence Number 1/2 -- Sequence Number 1/2
when 11 => when 11 =>
output_sig <= std_logic_vector(SEQUENCE_NR_START(0)); output_sig <= std_logic_vector(FIRST_SEQUENCENUMBER(0));
-- Sequence Number 2/2 -- Sequence Number 2/2
when 12 => when 12 =>
output_sig <= std_logic_vector(SEQUENCE_NR_START(1)); output_sig <= std_logic_vector(FIRST_SEQUENCENUMBER(1));
-- Sequence Number 1/2 -- Sequence Number 1/2
when 13 => when 13 =>
output_sig <= std_logic_vector(SUB_SEQUENCE_NR(0)); output_sig <= std_logic_vector(SUB_SEQUENCENUMBER(0));
-- Sequence Number 1/2 -- Sequence Number 1/2
when 14 => when 14 =>
output_sig <= std_logic_vector(SUB_SEQUENCE_NR(1)); output_sig <= std_logic_vector(SUB_SEQUENCENUMBER(1));
-- Count -- Count
when 15 => when 15 =>
output_sig <= std_logic_vector(count); output_sig <= std_logic_vector(count);

View File

@ -16,6 +16,9 @@ package rtps_config_package is
constant ENTITYID : ENTITYID_TYPE; -- Deferred to Package Body 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)); constant DOMAIN_ID : std_logic_vector(DOMAIN_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(USER_DOMAIN_ID, DOMAIN_ID_WIDTH));
-- Constant for Sequence Number 1
constant FIRST_SEQUENCENUMBER : SEQUENCENUMBER_TYPE := convert_to_double_word(to_unsigned(1, 64));
-- Smallest Writer Endpoint Lease Duration -- Smallest Writer Endpoint Lease Duration
constant MIN_ENDPOINT_LEASE_DURATION : DURATION_TYPE; -- Deferred to package Body constant MIN_ENDPOINT_LEASE_DURATION : DURATION_TYPE; -- Deferred to package Body
@ -69,11 +72,19 @@ package rtps_config_package is
constant ENDPOINT_TOPIC : ENDPOINT_STRING_TYPE; --Deferred to package body constant ENDPOINT_TOPIC : ENDPOINT_STRING_TYPE; --Deferred to package body
constant ENDPOINT_TYPE : 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 DOMAIN_TAG : STRING_WORD_ARRAY_TYPE; -- Deferred to package body
-- TODO: Use everywhere
constant EMPTY_STRING : STRING_WORD_ARRAY_TYPE := (others => (others => '0'));
-- Swap "data" to Big Endian representation. -- Swap "data" to Big Endian representation.
function big_endian_swap(is_little_endian : std_logic; data : std_logic_vector) return std_logic_vector; function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector;
function big_endian_swap(is_little_endian : std_logic; data : unsigned) return unsigned; 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 : string(1 to 256)) return STRING_WORD_ARRAY_TYPE;
function round_slv(slv : std_logic_vector; width : natural) return std_logic_vector;
end package; end package;
package body rtps_config_package is package body rtps_config_package is
@ -132,7 +143,7 @@ package body rtps_config_package is
end loop; end loop;
end procedure; end procedure;
function booelan_to_std_logic(input : boolean) return std_logic is function boolean_to_std_logic(input : boolean) return std_logic is
variable ret : std_logic := '0'; variable ret : std_logic := '0';
begin begin
ret := '0'; ret := '0';
@ -149,18 +160,18 @@ package body rtps_config_package is
for i in 0 to ret'length-1 loop for i in 0 to ret'length-1 loop
-- (see DDSI-RTPS 2.3 Section 9.3.1.2) -- (see DDSI-RTPS 2.3 Section 9.3.1.2)
-- Entity Kind Mapping -- Entity Kind Mapping
ret(i)(7 downto 6) := USER_DEFINED_ENTITY; ret(i)(ENTITY_KIND_H_RANGE) := USER_DEFINED_ENTITY;
if (i <= NUM_READERS-1) then if (i <= NUM_READERS-1) then
if (ENDPOINT_WITH_KEY(i)) then if (ENDPOINT_WITH_KEY(i)) then
ret(i)(5 downto 0) := READER_WITH_KEY; ret(i)(ENTITY_KIND_L_RANGE) := READER_WITH_KEY;
else else
ret(i)(5 downto 0) := READER_NO_KEY; ret(i)(ENTITY_KIND_L_RANGE) := READER_NO_KEY;
end if; end if;
else else
if (ENDPOINT_WITH_KEY(i)) then if (ENDPOINT_WITH_KEY(i)) then
ret(i)(5 downto 0) := WRITER_WITH_KEY; ret(i)(ENTITY_KIND_L_RANGE) := WRITER_WITH_KEY;
else else
ret(i)(5 downto 0) := WRITER_NO_KEY; ret(i)(ENTITY_KIND_L_RANGE) := WRITER_NO_KEY;
end if; end if;
end if; end if;
-- ID Mapping -- ID Mapping
@ -385,7 +396,7 @@ package body rtps_config_package is
len := len + 1; len := len + 1;
ret.data(ind+len) := ENDPOINT_PRESENTATION_QOS(i); ret.data(ind+len) := ENDPOINT_PRESENTATION_QOS(i);
len := len + 1; len := len + 1;
ret.data(ind+len) := (24 => booelan_to_std_logic(ENDPOINT_COHERENT_ACCESS(i)), 16 => booelan_to_std_logic(ENDPOINT_ORDERED_ACCESS(i)), others => '0'); ret.data(ind+len) := (24 => boolean_to_std_logic(ENDPOINT_COHERENT_ACCESS(i)), 16 => boolean_to_std_logic(ENDPOINT_ORDERED_ACCESS(i)), others => '0');
end if; end if;
-- SENTINEL -- SENTINEL
len := len + 1; len := len + 1;
@ -534,7 +545,7 @@ package body rtps_config_package is
len := len + 1; len := len + 1;
ret.data(ind+len) := ENDPOINT_PRESENTATION_QOS(i); ret.data(ind+len) := ENDPOINT_PRESENTATION_QOS(i);
len := len + 1; len := len + 1;
ret.data(ind+len) := (24 => booelan_to_std_logic(ENDPOINT_COHERENT_ACCESS(i)), 16 => booelan_to_std_logic(ENDPOINT_ORDERED_ACCESS(i)), others => '0'); ret.data(ind+len) := (24 => boolean_to_std_logic(ENDPOINT_COHERENT_ACCESS(i)), 16 => boolean_to_std_logic(ENDPOINT_ORDERED_ACCESS(i)), others => '0');
end if; end if;
-- SENTINEL -- SENTINEL
len := len + 1; len := len + 1;
@ -677,7 +688,7 @@ package body rtps_config_package is
ret.data(ind+len) := DEFAULT_IPv4_META_ADDRESS; ret.data(ind+len) := DEFAULT_IPv4_META_ADDRESS;
-- DEFAULT MULTICAST LOCATOR -- DEFAULT MULTICAST LOCATOR
len := len + 1; len := len + 1;
ret.data(ind+len) := PID_METATRAFFIC_MULTICAST_LOCATOR & std_logic_vector(to_unsigned(24, 16)); ret.data(ind+len) := PID_DEFAULT_MULTICAST_LOCATOR & std_logic_vector(to_unsigned(24, 16));
len := len + 1; len := len + 1;
ret.data(ind+len) := LOCATOR_KIND_UDPv4; ret.data(ind+len) := LOCATOR_KIND_UDPv4;
len := len + 1; len := len + 1;
@ -730,14 +741,14 @@ package body rtps_config_package is
constant PARTICIPANT_DATA : OUTPUT_DATA_TYPE := gen_participant_data; constant PARTICIPANT_DATA : OUTPUT_DATA_TYPE := gen_participant_data;
-- Returns the 'data' argument either as is, or with reversed Byte order, depending on the -- Returns the 'data' argument either as is, or with reversed Byte order, depending on the
-- 'is_little_endian' argument. -- 'swap' argument.
function big_endian_swap(is_little_endian : std_logic; data : std_logic_vector) return std_logic_vector is function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector is
variable ret : std_logic_vector(data'range); variable ret : std_logic_vector(data'range);
begin begin
-- Assert that Data Signal is Byte aligned -- Assert that Data Signal is Byte aligned
assert (data'length mod 8 = 0) severity failure; assert (data'length mod 8 = 0) severity failure;
-- Little Endian -- Little Endian
if (is_little_endian = '1') then if (swap = '1') then
-- Reverse byte Order -- Reverse byte Order
for i in 0 to (data'length/8)-1 loop for i in 0 to (data'length/8)-1 loop
ret(i*8+8-1 downto i*8) := data(((data'length/8)-1-i)*8+8-1 downto ((data'length/8)-1-i)*8); ret(i*8+8-1 downto i*8) := data(((data'length/8)-1-i)*8+8-1 downto ((data'length/8)-1-i)*8);
@ -750,10 +761,20 @@ package body rtps_config_package is
end function; end function;
-- Returns the 'data' argument either as is, or with reversed Byte order, depending on the -- Returns the 'data' argument either as is, or with reversed Byte order, depending on the
-- 'is_little_endian' argument. -- 'swap' argument.
function big_endian_swap(is_little_endian : std_logic; data : unsigned) return unsigned is function endian_swap(swap : std_logic; data : unsigned) return unsigned is
begin begin
return unsigned(big_endian_swap(is_little_endian, std_logic_vector(data))); 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(width-1 downto 0) /= (width-1 downto 0 => '0')) then
ret := std_logic_vector(unsigned(ret) + 1);
end if;
return ret;
end function; end function;
end package body; end package body;

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@ package rtps_package is
constant LOCATOR_KIND_WIDTH : natural := CDR_LONG_WIDTH; constant LOCATOR_KIND_WIDTH : natural := CDR_LONG_WIDTH;
constant COUNT_WIDTH : natural := CDR_LONG_WIDTH; constant COUNT_WIDTH : natural := CDR_LONG_WIDTH;
constant SUBMESSAGE_DATA_EXTRA_FLAGS_WIDTH : natural := 16; constant SUBMESSAGE_DATA_EXTRA_FLAGS_WIDTH : natural := 16;
constant MAX_BITMAP_WIDTH : natural := 256;
-- *TYPES DEFINITION* -- *TYPES DEFINITION*
-- Generic Types -- Generic Types
@ -52,19 +53,30 @@ package rtps_package is
type DOUBLE_WORD_ARRAY is array (0 to 1) of unsigned(WORD_WIDTH-1 downto 0); type DOUBLE_WORD_ARRAY is array (0 to 1) of unsigned(WORD_WIDTH-1 downto 0);
-- RTPS -- RTPS
-- TODO: Define unconstrained WORD_ARRAY and define constrained subtypes -- TODO: Define unconstrained WORD_ARRAY and define constrained subtypes
subtype SEQUENCE_NR_TYPE is DOUBLE_WORD_ARRAY; subtype SEQUENCENUMBER_TYPE is DOUBLE_WORD_ARRAY;
subtype DURATION_TYPE is DOUBLE_WORD_ARRAY; subtype DURATION_TYPE is DOUBLE_WORD_ARRAY;
subtype TIME_TYPE is DOUBLE_WORD_ARRAY; subtype TIME_TYPE is DOUBLE_WORD_ARRAY;
type GUIDPREFIX_TYPE is array (0 to (GUIDPREFIX_WIDTH/WORD_WIDTH)-1) of std_logic_vector(WORD_WIDTH-1 downto 0); type GUIDPREFIX_TYPE is array (0 to (GUIDPREFIX_WIDTH/WORD_WIDTH)-1) of std_logic_vector(WORD_WIDTH-1 downto 0);
type GUID_TYPE is array (0 to (GUID_WIDTH/WORD_WIDTH)-1) of std_logic_vector(WORD_WIDTH-1 downto 0); type GUID_TYPE is array (0 to (GUID_WIDTH/WORD_WIDTH)-1) of std_logic_vector(WORD_WIDTH-1 downto 0);
type BITMAP_TYPE is array (0 to (MAX_BITMAP_WIDTH/WORD_WIDTH)-1) of std_logic_vector(0 to WORD_WIDTH-1);
-- Helper Function -- Helper Function
function gen_duration(s,ns : integer) return DURATION_TYPE; function gen_duration(s,ns : integer) return DURATION_TYPE;
-- *PREDEFINED VALUES* -- *PREDEFINED VALUES*
constant DEFAULT_IPv4_META_ADDRESS : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0) := x"EFFF0001"; -- Default Multicast Ipv4 Address (239.255.0.1) constant DEFAULT_IPv4_META_ADDRESS : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0) := x"EFFF0001"; -- Default Multicast Ipv4 Address (239.255.0.1)
constant DURATION_ZERO : DURATION_TYPE := (others => (others => '0'));
constant DURATION_INFINITE : DURATION_TYPE := (x"7fffffff", x"ffffffff"); constant DURATION_INFINITE : DURATION_TYPE := (x"7fffffff", x"ffffffff");
constant TIME_ZERO : TIME_TYPE := (others => (others => '0'));
constant TIME_INVALID : TIME_TYPE := (others => (others => '1'));
constant TIME_INFINITE : TIME_TYPE := (x"ffffffff", x"fffffffe");
constant SEQUENCENUMBER_UNKNOWN : SEQUENCENUMBER_TYPE := (x"ffffffff", x"00000000");
constant PROTOCOL_RTPS : std_logic_vector(PROTOCOL_WIDTH-1 downto 0) := x"52545053"; -- 'RTPS' in Ascii code constant PROTOCOL_RTPS : std_logic_vector(PROTOCOL_WIDTH-1 downto 0) := x"52545053"; -- 'RTPS' in Ascii code
constant PROTOCOLVERSION_1_0 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0100";
constant PROTOCOLVERSION_1_1 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0101";
constant PROTOCOLVERSION_2_0 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0200";
constant PROTOCOLVERSION_2_1 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0201";
constant PROTOCOLVERSION_2_2 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0202";
constant PROTOCOLVERSION_2_4 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0204"; constant PROTOCOLVERSION_2_4 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0204";
constant VENDORID_UNKNOWN : std_logic_vector(VENDORID_WIDTH-1 downto 0) := (others => '0'); constant VENDORID_UNKNOWN : std_logic_vector(VENDORID_WIDTH-1 downto 0) := (others => '0');
constant GUIDPREFIX_UNKNOWN : GUIDPREFIX_TYPE := (others => (others => '0')); constant GUIDPREFIX_UNKNOWN : GUIDPREFIX_TYPE := (others => (others => '0'));
@ -87,6 +99,7 @@ package rtps_package is
constant SID_DATA_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"16"; constant SID_DATA_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"16";
-- *SUBMESSAGE FLAG POSITIONS* -- *SUBMESSAGE FLAG POSITIONS*
-- NOTE: The KEY and NON_STANDARD_PAYOAD Flags for the DATA_FRAG Submessage are off by one (-1) from this positions
constant SUBMESSAGE_ENDIAN_FLAG_POS : natural := 0; constant SUBMESSAGE_ENDIAN_FLAG_POS : natural := 0;
constant SUBMESSAGE_FINAL_FLAG_POS : natural := 1; constant SUBMESSAGE_FINAL_FLAG_POS : natural := 1;
constant SUBMESSAGE_INLINE_QOS_FLAG_POS : natural := 1; constant SUBMESSAGE_INLINE_QOS_FLAG_POS : natural := 1;
@ -140,7 +153,7 @@ package rtps_package is
constant PID_BUILTIN_ENDPOINT_SET : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0058"; constant PID_BUILTIN_ENDPOINT_SET : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0058";
constant PID_BUILTIN_ENDPOINT_QOS : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0077"; constant PID_BUILTIN_ENDPOINT_QOS : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0077";
constant PID_PROPERTY_LIST : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0059"; constant PID_PROPERTY_LIST : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0059";
constant PID_TYPE_MAX_SIZE_SERIALIZED : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0060"; constant PID_DATA_MAX_SIZE_SERIALIZED : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0060";
constant PID_ENTITY_NAME : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0062"; constant PID_ENTITY_NAME : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"0062";
constant PID_ENDPOINT_GUID : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"005a"; constant PID_ENDPOINT_GUID : std_logic_vector(PARAMETER_ID_WIDTH-1 downto 0) := x"005a";
-- INLINE-QOS ONLY -- INLINE-QOS ONLY
@ -186,13 +199,14 @@ package rtps_package is
constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000200c2"); constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000200c2");
constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000200c7"); constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000200c7");
-- *ENTITY KIND* (Last Byte of Entity ID) -- *ENTITY KIND* (Last Byte of Entity ID)
subtype ENTITY_KIND_H_RANGE is natural range 1 downto 0; subtype ENTITY_KIND_H_RANGE is natural range 7 downto 6;
subtype ENTITY_KIND_L_RANGE is natural range 7 downto 2; subtype ENTITY_KIND_L_RANGE is natural range 5 downto 0;
--FOLLOWING MAP TO ENTITY_KIND_H --FOLLOWING MAP TO ENTITY_KIND_H
constant USER_DEFINED_ENTITY : std_logic_vector(ENTITY_KIND_H_RANGE) := "00"; constant USER_DEFINED_ENTITY : std_logic_vector(ENTITY_KIND_H_RANGE) := "00";
constant BUILT_IN_ENTITY : std_logic_vector(ENTITY_KIND_H_RANGE) := "11"; constant BUILT_IN_ENTITY : std_logic_vector(ENTITY_KIND_H_RANGE) := "11";
constant VENDOR_SPECIFIC_ENTITY : std_logic_vector(ENTITY_KIND_H_RANGE) := "01"; constant VENDOR_SPECIFIC_ENTITY : std_logic_vector(ENTITY_KIND_H_RANGE) := "01";
--FOLLOWING MAP TO ENTITY_KIND_L --FOLLOWING MAP TO ENTITY_KIND_L
constant UNKNOWN_KIND : std_logic_vector(ENTITY_KIND_L_RANGE) := (others => '0');
constant WRITER_WITH_KEY : std_logic_vector(ENTITY_KIND_L_RANGE) := "000010"; constant WRITER_WITH_KEY : std_logic_vector(ENTITY_KIND_L_RANGE) := "000010";
constant WRITER_NO_KEY : std_logic_vector(ENTITY_KIND_L_RANGE) := "000011"; constant WRITER_NO_KEY : std_logic_vector(ENTITY_KIND_L_RANGE) := "000011";
constant READER_NO_KEY : std_logic_vector(ENTITY_KIND_L_RANGE) := "000100"; constant READER_NO_KEY : std_logic_vector(ENTITY_KIND_L_RANGE) := "000100";

View File

@ -39,7 +39,7 @@
set_global_assignment -name FAMILY "Cyclone V" set_global_assignment -name FAMILY "Cyclone V"
set_global_assignment -name DEVICE 5CGXFC7C7F23C8 set_global_assignment -name DEVICE 5CGXFC7C7F23C8
set_global_assignment -name TOP_LEVEL_ENTITY rtps_builtin_endpoint set_global_assignment -name TOP_LEVEL_ENTITY rtps_handler
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 20.1.0 set_global_assignment -name ORIGINAL_QUARTUS_VERSION 20.1.0
set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:33:09 NOVEMBER 02, 2020" set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:33:09 NOVEMBER 02, 2020"
set_global_assignment -name LAST_QUARTUS_VERSION "20.1.0 Lite Edition" set_global_assignment -name LAST_QUARTUS_VERSION "20.1.0 Lite Edition"