From 74515d0ecc4b8fcf55255002ddc0d8ecfb4c18fe Mon Sep 17 00:00:00 2001 From: Greek Date: Sat, 24 Oct 2020 17:00:52 +0200 Subject: [PATCH] * Code cleanup * Varius fixes * Code Comment --- src/REF.txt | 4 +- src/TODO.txt | 8 +- src/rtps_builtin_endpoint.vhd | 2357 +++++++++++++++++++-------------- src/rtps_package.vhd | 91 +- 4 files changed, 1448 insertions(+), 1012 deletions(-) diff --git a/src/REF.txt b/src/REF.txt index e9aa856..3ee5f0a 100644 --- a/src/REF.txt +++ b/src/REF.txt @@ -134,7 +134,7 @@ PARTICICPANT DATA + LEASE_DEADLINE + 12| | +-------------------------------------------------------------+ -13|P|S|M| EXTRA_FLAGS |Q| +13| UNUSED |P|S|M|Q| +-------------------------------------------------------------+ 14| | + ACKNACK_RES_TIME + @@ -192,7 +192,7 @@ ENDPOINT MATCH FRAME +-------------------------------------------------------------+ 06| IPv4_ADDRESS | +-------------------------------------------------------------+ -07| UDP_PORT | EXTRA_FLAGS |Q| +07| UDP_PORT | UNUSED |Q| +-------------------------------------------------------------+ ENDPOINT UNMATCH FRAME diff --git a/src/TODO.txt b/src/TODO.txt index 245babf..bafdfa3 100644 --- a/src/TODO.txt +++ b/src/TODO.txt @@ -100,5 +100,11 @@ DESIGN DECISIONS * !REJECTED! (Use the unused extra flags in the stored participant data) 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 - +-- Input FIFO Guard +-- Output FIFO Guard +-- Memory Operation Guard +-- Ignore in-line QoS +-- Only relevant for Endpoint Discovery Protocol +-- Check QoS Compatibility (Unmark match on incompatibility) +-- COMPATIBLE (DDS v1.4): offered >= requested, with INSTANCE < TOPIC < GROUP \ No newline at end of file diff --git a/src/rtps_builtin_endpoint.vhd b/src/rtps_builtin_endpoint.vhd index ebb154e..1da6921 100644 --- a/src/rtps_builtin_endpoint.vhd +++ b/src/rtps_builtin_endpoint.vhd @@ -5,6 +5,9 @@ use ieee.numeric_std.all; use work.math_pkg.all; use work.rtps_package.all; +-- TODO: Skip Packet while we are waiting for memory operation to complete +-- TODO: If we just make the comparison [read_count & "00" >= length] we do not need to "normalize" anything + entity rtps_builtin_endpoint is port ( clk : in std_logic; -- Input Clock @@ -45,18 +48,21 @@ architecture arch of rtps_builtin_endpoint is ); end component; + constant EXTRA_FLAGS_WIDTH : natural := 4; + --*****TYPE DECLARATION***** -- FSM states. Explained below in detail type STAGE_TYPE is (TODO); type MEM_STAGE_TYPE is (TODO); - type MESSAGE_TYPE_TYPE is (PDP, EDP, MESSAGE, NONE); type MEM_OPCODE_TYPE is (NOP, SEARCH_PARTICIPANT, SEARCH_ENDPOINT); + type MESSAGE_TYPE_TYPE is (PDP, EDP, MESSAGE, NONE); + type STRING_CONTENT_TYPE is (TOPIC_NAME, TYPE_NAME, DOMAIN_TAG); type PARTICIPANT_DATA_TYPE is record meta_addr : std_logic_vector(31 downto 0); def_addr : std_logic_vector(31 downto 0); meta_port : std_logic_vector(15 downto 0); def_port : std_logic_vector(15 downto 0); - extra_flags : std_logic_vector(31 downto 0); + extra_flags : std_logic_vector(EXTRA_FLAGS_WIDTH-1 downto 0); lease_duration : DOUBLE_WORD_ARRAY; lease_deadline : DOUBLE_WORD_ARRAY; heartbeat_res_time : DOUBLE_WORD_ARRAY; @@ -70,15 +76,20 @@ architecture arch of rtps_builtin_endpoint is --*****CONSTANT DECLARATION***** constant BUILTIN_BUFFER_SIZE : natural := MAX_REMOTE_PARTICIPANTS*PARTICIPANT_FRAME_SIZE; constant BUILTIN_BUFFER_ADDR_WIDTH : natural := log2c(BUILTIN_BUFFER_SIZE); + constant MAX_ADDRESS : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := to_unsigned(BUILTIN_BUFFER_SIZE, BUILTIN_BUFFER_ADDR_WIDTH); + constant FIRST_PARTICIPANT_ADDRESS : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + constant FIRST_ENDPOINT_ADDRESS : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, BUILTIN_BUFFER_ADDR_WIDTH); constant PARTICIPANT_DATA_FLAG : natural := 0; constant LEASE_DEADLINE_FLAG : natural := 1; constant EXTRA_FLAGS_FLAG : natural := 2; constant ACKNACK_RES_TIME_FLAG : natural := 3; constant HEARTBEAT_RES_TIME_FLAG : natural := 4; constant EDP_SEQ_NR_FLAG : natural := 5; - constant PUB_DATA_FLAG : natural := 31; - constant SUB_DATA_FLAG : natural := 30; - constant MES_DATA_FLAG : natural := 29; + -- Extra Flags Positions + constant PUB_DATA_FLAG : natural := 3; + constant SUB_DATA_FLAG : natural := 2; + constant MES_DATA_FLAG : natural := 1; + constant EXPECTS_INLINE_QOS_FLAG : natural := 0; constant PUB_SEQUENCE_NR : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(NUM_WRITERS, 64)); constant SUB_SEQUENCE_NR : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(NUM_READERS, 64)); constant SEQUENCE_NR_START : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(1, 64)); @@ -110,8 +121,6 @@ architecture arch of rtps_builtin_endpoint is signal reset_read_cnt : std_logic; -- 32-bit Word counter (Counts words read from input fifo) signal read_cnt : unsigned(13 downto 0) := (others => '0'); - -- 32-bit Word aligned total packet length - signal packet_length, packet_length_next : unsigned(13 downto 0) := (others => '0'); signal opcode, opcode_next : std_logic_vector(7 downto 0) := (others => '0'); signal flags, flags_next : std_logic_vector(7 downto 0) := (others => '0'); signal src_port, src_port_next : std_logic_vector(15 downto 0) := (others => '0'); @@ -127,7 +136,7 @@ architecture arch of rtps_builtin_endpoint is signal data_in_swapped : std_logic_vector(31 downto 0) := (others => '0'); signal string_length, string_length_next : unsigned(31 downto 0) := (others => '0'); --TODO: Always reset before COMPARE_STRING stage - signal compare_length, compare_length_next : unsigned(31 downto 0) := (others => '0'); + signal compare_length, compare_length_next : unsigned(29 downto 0) := (others => '0'); signal endpoint_mask, endpoint_mask_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); signal endpoint_match, endpoint_match_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); signal endpoint_unmatch, endpoint_unmatch_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); @@ -136,27 +145,23 @@ architecture arch of rtps_builtin_endpoint is signal is_subscriber, is_subscriber_next : std_logic := '0'; signal lease_duration, lease_duration_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal deadline, deadline_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); - signal lifespan_duration, lifespan_duration_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal addr_latch_index, addr_latch_index_next : std_logic := '0'; -- General Purpose counter -- TODO: Constrain range signal cnt, cnt_next : natural := 0; - signal expects_inline_qos, expects_inline_qos_next : std_logic := '0'; + signal expects_inline_qos_set, expects_inline_qos_set_next : std_logic := '0'; signal guid, guid_next : GUID_ARRAY_TYPE := (others => (others => '0')); - signal start_mem_op, mem_op_busy, mem_op_done : std_logic := '0'; + signal mem_op_start, mem_op_done : std_logic := '0'; signal mem_opcode : MEM_OPCODE_TYPE := NOP; - signal participant_message_best_effort, participant_message_best_effort_next : std_logic := '0'; signal mem_addr, mem_addr_next, mem_addr_base, mem_addr_base_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); signal addr_res, addr_res_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); signal last_addr, last_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); signal max_participant_addr, max_participant_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); signal max_endpoint_addr, max_endpoint_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); signal mem_read_data, mem_write_data : std_logic_vector(31 downto 0) := (others => '0'); - signal mem_rd, mem_wr, mem_busy, mem_done : std_logic := '0'; + signal mem_rd, mem_wr : std_logic := '0'; -- TODO: Re-check range signal mem_cnt, mem_cnt_next : natural range 0 to 3 := 0; - -- NOTE: Participant Index limited to 32 bits - signal participant_index, participant_index_next : std_logic_vector(31 downto 0) := (others => '0'); signal seq_nr, seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal mem_seq_nr, mem_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal next_seq_nr, next_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); @@ -165,9 +170,6 @@ architecture arch of rtps_builtin_endpoint is signal is_orphan_search, is_orphan_search_next : std_logic := '0'; signal orphan_entityid, orphan_entityid_next : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (others => '0'); signal output_sig : std_logic_vector(31 downto 0) := (others => '0'); - signal mem_def_addr, mem_def_addr_next : std_logic_vector(31 downto 0) := (others => '0'); - signal mem_def_port, mem_def_port_next : std_logic_vector(15 downto 0) := (others => '0'); - signal mem_xflags, mem_xflags_next : std_logic_vector(15 downto 0) := (others => '0'); signal reset_max_pointer, reset_max_pointer_next : std_logic := '0'; signal stale_check, stale_check_next : std_logic := '0'; signal mem_guidprefix, mem_guidprefix_next : GUIDPREFIX_ARRAY_TYPE : (others => (others => '0')); @@ -179,15 +181,16 @@ architecture arch of rtps_builtin_endpoint is signal count, count_next : unsigned(31 downto 0) := (others => '0'); signal endpoint_alive : std_logic := '0'; signal reset_endpoint_alive : std_logic := '0'; - -- TODO: Make sure sequences are initialized to 1 + -- TODO: Make sure sequences are initialized correctly signal auto_live_seq_nr, auto_live_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal man_live_seq_nr, man_live_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal live_gap_start, live_gap_start_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal live_gap_end, live_gap_end_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); - signal extra_flags, extra_flags_next : std_logic_vector(31 downto 0) := (others => '0'); + signal extra_flags, extra_flags_next : std_logic_vector(EXTRA_FLAGS_WIDTH-1 downto 0) := (others => '0'); signal announcement_time, announcement_time_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal heartbeat_time, heartbeat_time_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); signal is_live_assert, is_live_assert_next : std_logic := '0'; + signal string_content, string_content_next : STRING_CONTENT_TYPE := TOPIC_NAME; @@ -337,6 +340,8 @@ begin for i in 0 to NUM_DOMAIN-1 loop endpoint_output(i) <= output_sig; end loop; + rtps_output <= output_sig; + --Write Enable Signal endpoint_wr <= (others => '0'); case (stage) is @@ -353,7 +358,7 @@ begin endpoint_wr <= endpoint_mask; end if; when others => - null; + rtps_wr <= wr_sig; end case; end process; @@ -363,7 +368,6 @@ begin --DEFAULT stage_next <= stage; return_stage_next <= return_stage; - packet_length_next <= packet_length; rd_sig <= '0'; reset_read_cnt <= '0'; opcode_next <= opcode; @@ -390,7 +394,7 @@ begin cnt_next <= cnt; expects_inline_qos_next <= expects_inline_qos; mem_opcode <= NOP; - start_mem_op <= '0'; + mem_op_start <= '0'; is_orphan_search_next <= is_orphan_search; extra_flags_next <= extra_flags; output_sig <= (others => '0'); @@ -409,60 +413,81 @@ begin announcement_time_next <= announcement_time; heartbeat_time_next <= heartbeat_time; is_live_assert_next <= is_live_assert; + string_content_next <= string_content; -- Last Word Latch Setter if (last_word_in = '1') then last_word_in_latch_next <= '1'; - -- TODO: Also set in AUTO_PURGE to exit from SKIP_PACKET stage + -- TODO: Also set in LATCH_REMOVED_GUIDPREFIX to exit from SKIP_PACKET stage else last_word_in_latch_next <= last_word_in_latch; end if; -- TODO: Reset Latches - -- TODO: Increment counters before send - -- TODO: Cast unsigned to std_logic_vector - -- TODO: Always check addr_res on completed memory operation case(stage) is -- Initial/Idle State when IDLE => - -- Participant Announcement Trigger + -- Participant Announcement Time Trigger if (time > announcement_time) then announcement_time_next <= time + TODO; - stage_next <= SEND_PARTICIPANT_ANNOUNCEMENT_1; - -- Heartbeat Trigger + stage_next <= SEND_HEADER; + return_stage_next <= SEND_PARTICIPANT_ANNOUNCEMENT; + -- Heartbeat Time Trigger + -- NOTE: Liveliness assertion and Heartbeat sending is done together elsif (time > heartbeat_time) then + -- Memory Operation Guard if (mem_op_done = '1') then + -- NOTE: The sequence number of the automatic liveliness is always higher than that of the manual liveliness + -- If Manual By Participant Liveliness asserted, send both manual and automatic liveliness if (endpoint_alive = '1') then + -- Reset the endpoint alive toggle signal reset_endpoint_alive <= '1'; man_live_seq_nr_next <= auto_live_seq_nr + 1; - live_gap_start_next <= auto_live_seq_nr + 2; auto_live_seq_nr_next <= auto_live_seq_nr + 2; + -- GAP Start is always man_live_seq_nr+1 + live_gap_start_next <= auto_live_seq_nr + 2; + -- GAP End is always auto_live_seq_nr-1 live_gap_end_next <= auto_live_seq_nr + 1; + -- Else send only automatic liveliness else auto_live_seq_nr_next <= auto_live_seq_nr + 1; live_gap_end_next <= live_gap_end + 1; end if; heartbeat_time_next <= time + TODO; + -- Send Heartbeat and Liveliness Assertions to all stored Participants mem_opcode <= FIND_FIRST_PATICIPANT; - start_mem_op <= '1'; + mem_op_start <= '1'; stage_next <= FIND_PARTICIPANT_DEST; + -- Increment the counter for the new Heartbeat Messages + count_next <= count + 1; + -- Mark this as liveliness assertion (Allows the "SEND_MES_AUTO_LIVE" stage to decide on return stage) is_live_assert_next <= '1'; end if; - -- No Packet to process + -- Stale Entry search is initiated between every packet processing and when there is no packet to process elsif (stale_check = '0' or empty = '1') then if (mem_op_done = '1') then mem_opcode <= FIND_STALE_PARTICIPANT; - start_mem_op <= '1'; + mem_op_start <= '1'; + -- Stale Check Toggle (Setter) stale_check_next <= '1'; stage_next <= STALE_CHECK; end if; + -- Process Packet else - -- Process Packet + -- Stale Check Toggle (Resetter) stale_check_next <= '0'; stage_next <= PACKET_HEADER; + + -- TODO: Reset Latches + -- NOTE: We work with a "mark by default, and unmark on first missmatch" System + -- Mark participant as compatible per default + participant_match_next <= '1'; + -- Mark all endpoint as macthed by default + endpoint_mask_next <= (others => '1'); end if; when PACKET_HEADER => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; -- Latch Opcode @@ -471,33 +496,34 @@ begin flags_next <= header_flags; -- Latch Source UDP Port src_port_next <= header_udp_port; - -- Next Stage + stage_next <= PACKET_SRC_ADDR; - -- SANITY CHECK - -- Skip Packet if non-standard Payload + -- SANITY CHECK: Skip Packet if non-standard Payload if(header_opcode = SID_DATA and payload_flag = '1') then stage_next <= SKIP_PACKET; end if; end if; when PACKET_SRC_ADDR => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; -- Latch Source IP Address src_addr_next <= data_in; - -- Next Stage + stage_next <= PACKET_SRC_ENTITYID; end if; when PACKET_SRC_ENTITYID => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; -- Latch Source Entity ID src_entityid_next <= data_in; - -- Reset Counter - cnt_next <= 0; - -- Next Stage - stage_next <= PACKET_SRC_GUIDPREFIX; + + stage_next <= PACKET_SRC_GUIDPREFIX; + cnt_next <= 0; end if; when PACKET_SRC_GUIDPREFIX => + -- Input FIFO Guard and Memory Operation Guard if (empty = '0' and mem_op_done = '1') then rd_sig <= '1'; -- Latch Src GUIDPrefix @@ -511,52 +537,51 @@ begin guid_next(3) <= (others => '0'); -- Start Participant Search mem_opcode <= SEARCH_PARTICIPANT; - start_mem_op <= '1'; - -- Next Stage + mem_op_start <= '1'; + stage_next <= PACKET_DEST_ENTITYID; when others => null; end case; end if; when PACKET_DEST_ENTITYID => + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; + rd_sig <= '1'; -- DEFAULT STAGE - stage_next <= SKIP_PACKET; + stage_next <= SKIP_PACKET; - -- *Check Dest Entity ID* + -- *Check Destination Entity ID* case (data_in) is when ENTITYID_UNKNOWN => -- Wildcard Destination - -- Content has to be determined through src + -- Content has to be determined through Source Entity ID stage_next <= CHECK_SRC_ENTITYID; when ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR => -- Only DATA relevant if (opcode = SID_DATA) then -- Packet Contains Participant Data message_type_next <= PDP; + stage_next <= LATCH_SEQ_NR; - -- Initialise counter cnt_next <= 0; - -- Reset Participant Match - participant_match_next <= '1'; end if; when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER => -- SANITY CHECK: Ignore if no Writers -- Only ACKNACKs are relevant if (NUM_WRITERS /= 0 and opcode = SID_ACKNACK) then message_type_next <= EDP; + stage_next <= PROCESS_ACKNACK; --ACKNACK Processing - -- Initialise Counter cnt_next <= 0; end if; when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR => -- SANITY CHECK: Ignore if no Readers if (NUM_READERS /= 0) then message_type_next <= EDP; - -- QoS is publisher-offered is_subscriber_next <= '0'; + -- Only HEARTBEATs, GAPs and DATA are relevant case (opcode) is when SID_HEARTBEAT => @@ -568,9 +593,11 @@ begin when SID_DATA => stage_next <= LATCH_SEQ_NR; -- DATA Processing cnt_next <= 0; - -- Reset Endpoint Mask (ALL READERS) - endpoint_mask_next <= (others => '0'); - endpoint_mask_next(0 to NUM_READERS-1) <= (others => '1'); + + -- Unmark all Writers + endpoint_mask_next(NUM_READERS to MAX_ENDPOINTS-1) <= (others => '0'); + when others => + null; end case; end if; when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER => @@ -578,16 +605,16 @@ begin -- Only ACKNACKs are relevant if (NUM_READERS /= 0 and opcode = SID_ACKNACK) then message_type_next <= EDP; + stage_next <= PROCESS_ACKNACK; --ACKNACK Processing - -- Initialise counter cnt_next <= 0; end if; when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR => -- SANITY CHECK: Ignore if no Writers if (NUM_WRITERS /= 0) then message_type_next <= EDP; - -- QoS is subscriber-requested is_subscriber_next <= '1'; + -- Only HEARTBEATs, GAPs and DATA are relevant case (opcode) is when SID_HEARTBEAT => @@ -599,9 +626,11 @@ begin when SID_DATA => stage_next <= LATCH_SEQ_NR; -- DATA Processing cnt_next <= 0; - -- Reset Endpoint Mask (ALL WRITERS) - endpoint_mask_next <= (others => '0'); - endpoint_mask_next(NUM_READERS to NUM_READERS+NUM_WRITERS-1) <= (others => '1'); + + -- Unmark all Readers + endpoint_mask_next(0 to NUM_READERS-1) <= (others => '0'); + when others => + null; end case; end if; when ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER => @@ -610,8 +639,8 @@ begin -- Only ACKNACKs are relevant if (opcode = SID_ACKNACK) then message_type_next <= MESSAGE; + stage_next <= PROCESS_ACKNACK; --ACKNACK Processing - -- Initialise counter cnt_next <= 0; end if; end if; @@ -619,6 +648,7 @@ begin -- SANITY CHECK: Ignore if no Readers if (NUM_READERS /= 0) then message_type_next <= MESSAGE; + -- Only HEARTBEATs, GAPs and DATA are relevant case (opcode) is when SID_HEARTBEAT => @@ -630,18 +660,21 @@ begin when SID_DATA => stage_next <= LATCH_SEQ_NR; -- DATA Processing cnt_next <= 0; - -- Reset Endpoint Mask (ALL READERS) - endpoint_mask_next <= (others => '0'); - endpoint_mask_next(0 to NUM_READERS-1) <= (others => '1'); + + -- Unmark all Writers + endpoint_mask_next(NUM_READERS to MAX_ENDPOINTS-1) <= (others => '0'); + when others => + null; end case; end if; when others => + -- Skip Packet null; end case; end if; when CHECK_SRC_ENTITYID => -- DEFAULT STAGE - stage_next <= SKIP_PACKET; + stage_next <= SKIP_PACKET; -- *Check Dest Entity ID* case (src_entityid) is @@ -650,28 +683,25 @@ begin if (opcode = SID_DATA) then -- Packet Contains Participant Data message_type_next <= PDP; - stage_next <= LATCH_SEQ_NR; - -- Initialise counter - cnt_next <= 0; - -- Reset Participant Match - participant_match_next <= '1'; + stage_next <= LATCH_SEQ_NR; + cnt_next <= 0; end if; when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR => -- SANITY CHECK: Ignore if no Writers -- Only ACKNACKs are relevant if (NUM_WRITERS /= 0 and opcode = SID_ACKNACK) then message_type_next <= EDP; + stage_next <= PROCESS_ACKNACK; --ACKNACK Processing - -- Initialise counter cnt_next <= 0; end if; when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER => -- SANITY CHECK: Ignore if no Readers if (NUM_READERS /= 0) then message_type_next <= EDP; - -- QoS is publisher-offered is_subscriber_next <= '0'; + -- Only HEARTBEATs, GAPs and DATA are relevant case (opcode) is when SID_HEARTBEAT => @@ -683,9 +713,11 @@ begin when SID_DATA => stage_next <= LATCH_SEQ_NR; -- DATA Processing cnt_next <= 0; - -- Reset Endpoint Mask (ALL READERS) - endpoint_mask_next <= (others => '0'); - endpoint_mask_next(0 to NUM_READERS-1) <= (others => '1'); + + -- Unmark all Writers + endpoint_mask_next(NUM_READERS to MAX_ENDPOINTS-1) <= (others => '0'); + when others => + null; end case; end if; when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR => @@ -693,20 +725,19 @@ begin -- Only ACKNACKs are relevant if (NUM_READERS /= 0 and opcode = SID_ACKNACK) then message_type_next <= EDP; + stage_next <= PROCESS_ACKNACK; --ACKNACK Processing - -- Initialise counter cnt_next <= 0; end if; when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER => -- SANITY CHECK: Ignore if no Writers if (NUM_WRITERS /= 0) then message_type_next <= EDP; - -- QoS is subscriber-requested is_subscriber_next <= '1'; + -- Only HEARTBEATs, GAPs and DATA are relevant case (opcode) is when SID_HEARTBEAT => - stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing cnt_next <= 0; when SID_GAP => @@ -715,9 +746,11 @@ begin when SID_DATA => stage_next <= LATCH_SEQ_NR; -- DATA Processing cnt_next <= 0; - -- Reset Endpoint Mask (ALL WRITERS) - endpoint_mask_next <= (others => '0'); - endpoint_mask_next(NUM_READERS to NUM_READERS+NUM_WRITERS-1) <= (others => '1'); + + -- Unmark all Readers + endpoint_mask_next(0 to NUM_READERS-1) <= (others => '0'); + when others => + null; end case; end if; when ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER => @@ -726,8 +759,8 @@ begin -- Only ACKNACKs are relevant if (opcode = SID_ACKNACK) then message_type_next <= MESSAGE; + stage_next <= PROCESS_ACKNACK; --ACKNACK Processing - -- Initialise counter cnt_next <= 0; end if; end if; @@ -735,6 +768,7 @@ begin -- SANITY CHECK: Ignore if no Readers if (NUM_READERS /= 0) then message_type_next <= MESSAGE; + -- Only HEARTBEATs, GAPs and DATA are relevant case (opcode) is when SID_HEARTBEAT => @@ -745,27 +779,29 @@ begin cnt_next <= 0; when SID_DATA => stage_next <= LATCH_SEQ_NR; -- DATA Processing - -- Initialise counter cnt_next <= 0; - -- Reset Endpoint Mask (ALL READERS) - endpoint_mask_next <= (others => '0'); - endpoint_mask_next(0 to NUM_READERS-1) <= (others => '1'); + + -- Unmark all Writers + endpoint_mask_next(NUM_READERS to MAX_ENDPOINTS-1) <= (others => '0'); + when others => + null; end case; end if; when others => null; end case; when LATCH_SEQ_NR => + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; - --Increment Counter + rd_sig <= '1'; cnt_next <= cnt + 1; + -- Latch Sequence Number case (cnt) is when 0 => - seq_nr_next(0) <= unsigned(data_in); + seq_nr_next(0) <= unsigned(data_in_swapped); when 1 => - seq_nr_next(1) <= unsigned(data_in); + seq_nr_next(1) <= unsigned(data_in_swapped); stage_next <= PROCESS_DATA; when others => null; @@ -775,41 +811,54 @@ begin -- Data Message contains inline QoS if (qos_flag = '1') then stage_next <= PROCESS_PL; - -- Data Message contains Payload + -- Data Message contains Data Payload elsif (data_flag = '1') then - -- Process Payload Header + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- DEFAULT Stage Next + -- DEFAULT STAGE stage_next <= SKIP_PACKET; -- Process Payload Header case(representation_id) is when PL_CDR_BE => + -- Override Endian Flag endian_flag_next <= '0'; + stage_next <= PROCESS_PL; when PL_CDR_LE => + -- Override Endian Flag endian_flag_next <= '1'; + stage_next <= PROCESS_PL; when CDR_BE => + -- Accept CDR Representation only for Participant Messages if (message_type = MESSAGE) then + -- Override Endian Flag endian_flag_next <= '0'; + stage_next <= PROCESS_MESSAGE; + cnt_next <= 0; end if; when CDR_LE => + -- Accept CDR Representation only for Participant Messages if (message_type = MESSAGE) then + -- Override Endian Flag endian_flag_next <= '1'; + stage_next <= PROCESS_MESSAGE; + cnt_next <= 0; end if; when others => + -- Skip Packet null; end case; end if; end if; when PROCESS_MESSAGE => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -831,9 +880,10 @@ begin end if; -- Participant Mesasge Kind when 3 => + -- NOTE: Rest of Participant Message is ignored -- XXX: The Participant Message Data may contain additional data, and according to DDSI-RTPS 2.3 -- implementations must be able to support up to 128 Bytes of additional data. Due to the unnecessary - -- high complexity this would add to this entity this is not supported. + -- high complexity this would add this is not supported. case (data_in) is -- Automatic Liveliness Assertion when PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE => @@ -859,66 +909,288 @@ begin when others => stage_next <= SKIP_PACKET; end case; + when others => + null; end case; end if; when PROCESS_GAP => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Increment Counter cnt_next <= cnt + 1; + -- Latch Sequence Numbers case (cnt) is when 0 => - first_seq_nr_next(0) <= data_in; + first_seq_nr_next(0) <= data_in_swapped; when 1 => - first_seq_nr_next(1) <= data_in; + first_seq_nr_next(1) <= data_in_swapped; when 2 => - last_seq_nr_next(0) <= data_in; + last_seq_nr_next(0) <= data_in_swapped; when 3 => - last_seq_nr_next(1) <= data_in; + last_seq_nr_next(1) <= data_in_swapped; + -- NOTE: Rest of GAP Message is ignored stage_next <= PROCESS_GAP_SEQUENCE_NUMBERS; + when others => + null; end case; end if; when PROCESS_GAP_SEQUENCE_NUMBERS => -- Wait for Sequence Number to be fetched from buffer - if (mem_done = '1' and seq_prc_done = '1') then - -- XXX: This logic relies on the sender marking continuous GAPs with the GAP Start Sequence Number and GAP End Sequence Number Set Base (i.e. the first bit in the bitmask should be 0/not in GAP) - -- It also relies on the sender starting the GAP from the next expected/requested sequence number (Not Begining the GAP from an already ACKed sequence number) - -- GAP only relevant if GAP start is the next expected sequence number - if (first_seq_nr = next_seq_nr) then - -- Store GAP end as last sequence number - seq_nr_next <= last_seq_nr; - mem_opcode <= UPDATE_PARTICIPANT; - update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0'); - start_mem_op <= '1'; + if (mem_op_done = '1' and seq_prc_done = '1') then + -- Sender known + if (addr_res /= MAX_ADDRESS) then + -- XXX: This logic relies on the sender marking continuous GAPs with the GAP Start Sequence Number and GAP End Sequence Number Set Base (i.e. the first bit in the bitmask should be 0/not in GAP) + -- It also relies on the sender starting the GAP from the next expected/requested sequence number (Not Begining the GAP from an already ACKed sequence number) + -- GAP only relevant if GAP start is the next expected sequence number + if (first_seq_nr = next_seq_nr) then + -- Store GAP end as last sequence number + seq_nr_next <= last_seq_nr; + mem_opcode <= UPDATE_PARTICIPANT; + update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; end if; - -- Done + -- DONE stage_next <= SKIP_PACKET; end if; when PROCESS_PL => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; -- Reset Word Counter reset_read_cnt <= '1'; - -- Latch Parameter End + -- Latch Parameter End (In order to skip parameters) parameter_end_next <= unsigned(normalize_length(endian_swap(endian_flag,parameter_length))); - -- DEFAULT + -- DEFAULT STAGE stage_next <= SKIP_PARAMETER; + -- TODO: Use inline QoS? -- TODO: DDS-XTYPES: When reading data, implementations of this specification shall be robust to any setting of the FLAG_MUST_UNDERSTAND bit and accept the parameter nevertheless. - + + -- NOTE: In-line QoS is completely ignored case (parameter_id) is + when PID_PARTICIPANT_GUID => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_GUID; + cnt_next <= 0; + end if; + when PID_DOMAIN_ID => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= MATCH_DOMAIN_ID; + end if; + when PID_DOMAIN_TAG => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_STRING_LENGTH; + -- Mark String contents (Needed for string comparison) + string_content <= DOMAIN_TAG; + end if; + when PID_PROTOCOL_VERSION => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= MATCH_PROTOCOL_VERSION; + end if; + when PID_DEFAULT_UNICAST_LOCATOR => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_LOCATOR; + cnt_next <= 0; + addr_latch_index_next <= '0'; + end if; + when PID_DEFAULT_MULTICAST_LOCATOR => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_LOCATOR; + cnt_next <= 0; + -- Mark Latch 1 for storing + addr_latch_index_next <= '0'; + end if; + when PID_METATRAFFIC_UNICAST_LOCATOR => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_LOCATOR; + cnt_next <= 0; + -- Mark Latch 2 for storing + addr_latch_index_next <= '1'; + end if; + when PID_METATRAFFIC_MULTICAST_LOCATOR => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_LOCATOR; + cnt_next <= 0; + -- Mark Latch 2 for storing + addr_latch_index_next <= '1'; + end if; + when PID_PARTICIPANT_LEASE_DURATION => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= LATCH_LEASE_DURATION; + cnt_next <= 0; + end if; + when PID_BUILTIN_ENDPOINT_SET => + -- Ignore in-line QoS + -- Only relevant for Participant Discovery Protocol + if(qos_flag = '0' and message_type = PDP) then + stage_next <= CHECK_REMOTE_BUILTIN_ENDPOINTS; + end if; + when PID_BUILTIN_ENDPOINT_QOS => + -- Only relevant for Participant Discovery Protocol + -- NOTE: As of DDSI-RTPS 2.3 the PID_BUILTIN_ENDPOINT_QOS only contains the BEST_EFFORT_PARTICIPANT_MESSAGE_DATA_READER bit + -- Due to how the built-in Endpoint is behaving, this bit as no impact in our case and we can safely ignore it. + -- Ignore + null; when PID_TOPIC_NAME => - -- Topic Name only relevant for EDP + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol if(qos_flag = '0' and message_type = EDP) then stage_next <= LATCH_STRING_LENGTH; + -- Mark String contents (Needed for string comparison) + string_content <= TOPIC_NAME; end if; when PID_TYPE_NAME => - -- Type Name only relevant for EDP + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol if(qos_flag = '0' and message_type = EDP) then stage_next <= LATCH_STRING_LENGTH; + -- Mark String contents (Needed for string comparison) + string_content <= TYPE_NAME; end if; + when PID_DURABILITY => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_DURABILITY; + end if; + when PID_DEADLINE => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_DEADLINE; + cnt_next <= 0; + end if; + when PID_LIVELINESS => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_LIVELINESS; + end if; + when PID_RELIABILITY => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_RELIABILITY; + end if; + when PID_DESTINATION_ORDER => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_DESTINATION_ORDER; + end if; + when PID_OWNERSHIP => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_OWNERSHIP; + end if; + when PID_PRESENTATION => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_PRESENTATION; + cnt_next <= 0; + end if; + when PID_PARTITION => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= RXO_PARTITION; + end if; + when PID_UNICAST_LOCATOR => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= LATCH_LOCATOR; + cnt_next <= 0; + -- Mark Latch 1 for storing + addr_latch_index_next <= '0'; + end if; + when PID_MULTICAST_LOCATOR => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= LATCH_LOCATOR; + cnt_next <= 0; + -- Mark Latch 1 for storing + addr_latch_index_next <= '0'; + end if; + when PID_ENDPOINT_GUID => + -- Ignore in-line QoS + -- Only relevant for Endpoint Discovery Protocol + if(qos_flag = '0' and message_type = EDP) then + stage_next <= LATCH_GUID; + cnt_next <= 0; + end if; + when PID_EXPECTS_INLINE_QOS => + stage_next <= LATCH_EXPECTS_INLINE_QOS; + when PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT => + -- Ignore + null; + when PID_CONTENT_FILTER_PROPERTY => + -- Ignore + null; + when PID_GROUP_GUID => + -- Ignore + null; + when PID_PROPERTY_LIST => + -- Ignore + null; + when PID_TYPE_MAX_SIZE_SERIALIZED => + -- Ignore + null; + when PID_ENTITY_NAME => + -- Ignore + null; + when PID_TIME_BASED_FILTER => + -- Ignore + null; + when PID_TRANSPORT_PRIORITY => + -- Ignore + null; + when PID_VENDORID => + -- Ignore + null; + when PID_OWNERSHIP_STRENGTH => + -- Ignore + null; + when PID_HISTORY => + -- Ignore + null; + when PID_RESOURCE_LIMITS => + -- Ignore + null; + when PID_LIFESPAN => + -- Ignore + -- NOTE: Lifespan is requested via in-line QoS and handled directly by the endpoint + null; + when PID_LATENCY_BUDGET => + -- Ignore + null; + when PID_DURABILITY_SERVICE => + -- Ignore + null; when PID_USER_DATA => -- Ignore null; @@ -928,187 +1200,58 @@ begin when PID_TOPIC_DATA => -- Ignore null; - when PID_DURABILITY => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_DURABILITY; - end if; - when PID_DURABILITY_SERVICE => - -- Ignore - when PID_DEADLINE => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_DEADLINE_1; - end if; - when PID_LATENCY_BUDGET => - -- Ignore - when PID_LIVELINESS => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_LIVELINESS; - end if; - when PID_RELIABILITY => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_RELIABILITY; - end if; - when PID_LIFESPAN => - if(qos_flag = '0' and message_type = EDP) then - -- TODO: Do not latch lifespan. Request it via inline QoS - stage_next <= LATCH_LIFESPAN_1; - end if; - when PID_DESTINATION_ORDER => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_DESTINATION_ORDER; - end if; - when PID_HISTORY => - -- Ignore - when PID_RESOURCE_LIMITS => - -- Ignore - when PID_OWNERSHIP => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_OWNERSHIP; - end if; - when PID_OWNERSHIP_STRENGTH => - -- Ignore - when PID_PRESENTATION => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_PRESENTATION; - end if; - when PID_PARTITION => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= RXO_PARTITION; - end if; - when PID_TIME_BASED_FILTER => - -- Ignore - when PID_TRANSPORT_PRIORITY => - -- Ignore - when PID_DOMAIN_ID => - if(qos_flag = '0' and message_type = PDP) then - stage_next <= MATCH_DOMAIN_ID; - end if; - when PID_DOMAIN_TAG => - if(qos_flag = '0' and message_type = PDP) then - stage_next <= LATCH_STRING_LENGTH; - end if; - when PID_PROTOCOL_VERSION => - if(qos_flag = '0' and message_type = PDP) then - stage_next <= MATCH_PROTOCOL_VERSION; - end if; - when PID_VENDORID => - -- Ignore - when PID_UNICAST_LOCATOR => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= LATCH_LOCATOR; - addr_latch_index_next <= '0'; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_MULTICAST_LOCATOR => - if(qos_flag = '0' and message_type = EDP) then - stage_next <= LATCH_LOCATOR; - addr_latch_index_next <= '0'; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_DEFAULT_UNICAST_LOCATOR => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_LOCATOR; - addr_latch_index_next <= '0'; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_DEFAULT_MULTICAST_LOCATOR => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_LOCATOR; - addr_latch_index_next <= '0'; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_METATRAFFIC_UNICAST_LOCATOR => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_LOCATOR; - addr_latch_index_next <= '1'; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_METATRAFFIC_MULTICAST_LOCATOR => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_LOCATOR; - addr_latch_index_next <= '1'; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_EXPECTS_INLINE_QOS => - stage_next <= LATCH_EXPECTS_INLINE_QOS; - when PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT => - -- Ignore - when PID_PARTICIPANT_LEASE_DURATION => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_LEASE_DURATION_1; - end if; - when PID_CONTENT_FILTER_PROPERTY => - -- Ignore - when PID_PARTICIPANT_GUID => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_GUID; - -- Initialise counter - cnt_next <= 0; - end if; - when PID_GROUP_GUID => - -- Ignore - when PID_BUILTIN_ENDPOINT_SET => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= CHECK_REMOTE_BUILTIN_ENDPOINTS; - end if; - when PID_BUILTIN_ENDPOINT_QOS => - if(qos_flag = '0' and message_type = DPD) then - stage_next <= LATCH_BUILTIN_ENDPOINT_QOS; - end if; - when PID_PROPERTY_LIST => - -- Ignore - when PID_TYPE_MAX_SIZE_SERIALIZED => - -- Ignore - when PID_ENTITY_NAME => - -- Ignore - when PID_ENDPOINT_GUID => - if(qos_flag = '0' and message_type = EPD) then - stage_next <= LATCH_GUID; - -- Initialise counter - cnt_next <= 0; - end if; when PID_CONTENT_FILTER_INFO => -- Ignore + null; when PID_COHERENT_SET => -- Ignore + null; when PID_DIRECTED_WRITE => -- Ignore + null; when PID_ORIGINAL_WRITER_INFO => -- Ignore + null; when PID_GROUP_COHERENT_SET => -- Ignore + null; when PID_GROUP_SEQ_NUM => -- Ignore + null; when PID_WRITER_GROUP_INFO => -- Ignore + null; when PID_SECURE_WRITER_GROUP_INFO => -- Ignore + null; when PID_KEY_HASH => -- Ignore + null; when PID_STATUS_INFO => -- Ignore - when PID_EXTENDED => - -- TODO + null; when PID_PAD => -- Ignore + null; + when PID_EXTENDED => + -- TODO + null; when PID_IGNORE => -- Ignore + null; when PID_SENTINEL => - -- If Processing in-line QoS until now + -- If Processing in-line QoS until now, start processing data if(qos_flag = '1') then + -- Override QoS Flag qos_flag_next <= '0'; stage_next <= PROCESS_DATA; + -- Else check Participant/Endpoint Matching else stage_next <= PARTICIPANT_MATCH_STAGE; end if; when PID_LIST_END => -- TODO + null; when others => -- If MUST_UNDERSTAND Flag is set, we have incompatible communication. Drop Packet if (must_undersand = '1') then @@ -1120,6 +1263,7 @@ begin end case; end if; when LATCH_STRING_LENGTH => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; string_length_next <= unsigned(data_in_swapped); @@ -1127,36 +1271,51 @@ begin compare_length_next <= (others => '0'); end if; when COMPARE_STRING => - -- TODO: FIX (Type Name not handled) + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; - -- Increment compare position counter - compare_length_next <= compare_length + 32; - -- Compare Strings - if (message_type = EDP) then - for i in 0 to ENDPOINT_TOPIC'length-1 loop - if (data_in /= ENDPOINT_TOPIC(i)(to_integer(compare_length) to to_integer(compare_length)+7)) then - endpoint_mask_next(i) <= '0'; - end if; - end loop; - elsif (message_type = DPD) then - if (data_in /= DOMAIN_TAG(to_integer(compare_length) to to_integer(compare_length)+7)) then - participant_match_next <= '0'; - end if; - end if; + rd_sig <= '1'; + compare_length_next <= compare_length + 1; + + -- NOTE: This assumes that the Parameter is padded with zeroes (Since we also compare the padding) + -- XTypes 7.4.1.1 requires padding bytes for "PLAIN_CDR" to be zero, but does not specify the value for "PL_CDR" + + -- Unmark matches on string comparison missmatch + case (string_content) is + when TOPIC_NAME => + for i in 0 to MAX_ENDPOINTS-1 loop + if (data_in /= ENDPOINT_TOPIC(i)(cnt)) then + endpoint_mask_next(i) <= '0'; + end if; + end loop; + when TYPE_NAME => + for i in 0 to MAX_ENDPOINTS-1 loop + if (data_in /= ENDPOINT_TYPE(i)(cnt)) then + endpoint_mask_next(i) <= '0'; + end if; + end loop; + when DOMAIN_TAG => + if (data_in /= DOMAIN_TAG(cnt)) then + participant_match_next <= '0'; + end if; + when others => + null; + end case; + + -- NOTE: "compare_length" counts the 32-bit words, while "string_length" contains the total string octets/bytes -- End of String (Exit Condition) - -- NOTE: This assumes that the Parameter is padded with zeroes - -- TODO: XTypes 7.4.1.1 requires padding bytes for "PLAIN_CDR" to be zero, but does not specify the value for "PL_CDR" - if (compare_length >= string_length) then - stage_next <= SKIP_PARAMETER; + if ((compare_length & "00") >= string_length) then + -- DONE + stage_next => SKIP_PARAMETER; end if; end if; when RXO_DURABILITY => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered >= requested, with VOLATILE < TRANSIENT_LOCAL < TRANSIENT < PERSISTENT + for i in 0 to MAX_ENDPOINTS-1 loop -- data-in is Subscriber-Requested if (is_subscriber = '1') then if (data_in_swapped > ENDPOINT_DURABILITY(i)) then @@ -1169,57 +1328,62 @@ begin end if; end if; end loop; - -- Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; - when RXO_DEADLINE_1 => + when RXO_DEADLINE => + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; + rd_sig <= '1'; + cnt_next <= cnt + 1; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop - -- data-in is Subscriber-Requested - if (is_subscriber = '1') then - if (data_in_swapped < ENDPOINT_DEADLINE(i)(1)) then - endpoint_mask_next(i) <= '0'; - end if; - -- data-in is Publisher-Offered - else - if (data_in_swapped > ENDPOINT_DEADLINE(i)(1)) then - endpoint_mask_next(i) <= '0'; - end if; - end if; - end loop; - -- Next Stage - stage_next <= RXO_DEADLINE_2; - end if; - when RXO_DEADLINE_2 => - if (empty = '0') then - rd_sig <= '1'; - - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop - -- data-in is Subscriber-Requested - if (is_subscriber = '1') then - if (data_in_swapped < ENDPOINT_DEADLINE(i)(0)) then - endpoint_mask_next(i) <= '0'; - end if; - -- data-in is Publisher-Offered - else - if (data_in_swapped > ENDPOINT_DEADLINE(i)(0)) then - endpoint_mask_next(i) <= '0'; - end if; - end if; - end loop; - -- Next Stage - stage_next <= SKIP_PARAMETER; + case (cnt) is + when 0 => + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered <= requested + for i in 0 to MAX_ENDPOINTS-1 loop + -- data-in is Subscriber-Requested + if (is_subscriber = '1') then + if (data_in_swapped < ENDPOINT_DEADLINE(i)(0)) then + endpoint_mask_next(i) <= '0'; + end if; + -- data-in is Publisher-Offered + else + if (data_in_swapped > ENDPOINT_DEADLINE(i)(0)) then + endpoint_mask_next(i) <= '0'; + end if; + end if; + end loop; + when 1 => + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered <= requested + for i in 0 to MAX_ENDPOINTS-1 loop + -- data-in is Subscriber-Requested + if (is_subscriber = '1') then + if (data_in_swapped < ENDPOINT_DEADLINE(i)(1)) then + endpoint_mask_next(i) <= '0'; + end if; + -- data-in is Publisher-Offered + else + if (data_in_swapped > ENDPOINT_DEADLINE(i)(1)) then + endpoint_mask_next(i) <= '0'; + end if; + end if; + end loop; + -- DONE + stage_next <= SKIP_PARAMETER; + when others => + null; + end case; end if; when RXO_LIVELINESS => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered >= requested, with AUTOMATIC < MANUAL_BY_PARTICIPANT < MANUAL_BY_TOPIC + for i in 0 to MAX_ENDPOINTS-1 loop -- data-in is Subscriber-Requested if (is_subscriber = '1') then if (data_in_swapped > ENDPOINT_LIVELINESS(i)) then @@ -1232,58 +1396,81 @@ begin end if; end if; end loop; - -- Next Stage + stage_next <= RXO_LEASE_DURATION; cnt_next <= 0; end if; when RXO_LEASE_DURATION => - -- TODO: Convert to two stages to avoid counter complexity? + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop - -- data-in is Subscriber-Requested - if (is_subscriber = '1') then - if (data_in_swapped > ENDPOINT_LEASE_DURATION(i)(cnt)) then - endpoint_mask_next(i) <= '0'; - end if; - -- data-in is Publisher-Offered - else - if (data_in_swapped < ENDPOINT_LIVELINESS(i)(cnt)) then - endpoint_mask_next(i) <= '0'; - end if; - end if; - end loop; - --Increment Counter + rd_sig <= '1'; cnt_next <= cnt + 1; - -- Exit Condition - if (cnt = 1) then - -- Next Stage - stage_next <= SKIP_PARAMETER; - end if; + + case (cnt) is + when 0 => + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered <= requested + for i in 0 to MAX_ENDPOINTS-1 loop + -- data-in is Subscriber-Requested + if (is_subscriber = '1') then + if (data_in_swapped > ENDPOINT_LEASE_DURATION(i)(0)) then + endpoint_mask_next(i) <= '0'; + end if; + -- data-in is Publisher-Offered + else + if (data_in_swapped < ENDPOINT_LIVELINESS(i)(0)) then + endpoint_mask_next(i) <= '0'; + end if; + end if; + end loop; + when 1 => + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered <= requested + for i in 0 to MAX_ENDPOINTS-1 loop + -- data-in is Subscriber-Requested + if (is_subscriber = '1') then + if (data_in_swapped > ENDPOINT_LEASE_DURATION(i)(1)) then + endpoint_mask_next(i) <= '0'; + end if; + -- data-in is Publisher-Offered + else + if (data_in_swapped < ENDPOINT_LIVELINESS(i)(1)) then + endpoint_mask_next(i) <= '0'; + end if; + end if; + end loop; + -- DONE + stage_next <= SKIP_PARAMETER; + when others => + null; + end case; end if; - when LATCH_LEASE_DURATION_1 => + when LATCH_LEASE_DURATION => + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; + rd_sig <= '1'; + cnt_next <= cnt + 1; + -- Latch Lease Duration - lease_duration_next(0) <= data_in_swapped; - -- Next Stage - stage_next <= LATCH_LEASE_DURATION_2; - end if; - when LATCH_LEASE_DURATION_2 => - if (empty = '0') then - rd_sig <= '1'; - -- Latch Lease Duration - lease_duration_next(1) <= data_in_swapped; - -- Next Stage - stage_next <= SKIP_PARAMETER; + case (cnt) is + when 0 => + lease_duration_next(0) <= data_in_swapped; + when 1 => + lease_duration_next(1) <= data_in_swapped; + -- DONE + stage_next <= SKIP_PARAMETER; + when others => + null; + end case; end if; when RXO_RELIABILITY => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered >= requested, with BEST_EFFORT < RELIABLE + for i in 0 to MAX_ENDPOINTS-1 loop -- data-in is Subscriber-Requested if (is_subscriber = '1') then if (data_in_swapped > ENDPOINT_RELIABILITY(i)) then @@ -1296,32 +1483,19 @@ begin end if; end if; end loop; - -- Next Stage + -- NOTE: The max_blocking_time value is ignored + -- DONE stage_next <= SKIP_PARAMETER; end if; - when LATCH_LIFESPAN_1 => - if (empty = '0') then - rd_sig <= '1'; - -- Latch Lease Duration - lifespan_duration_next(1) <= data_in_swapped; - -- Next Stage - stage_next <= LATCH_LIFESPAN_2; - end if; - when LATCH_LIFESPAN_2 => - if (empty = '0') then - rd_sig <= '1'; - -- Latch Lease Duration - lifespan_duration_next(0) <= data_in_swapped; - -- Next Stage - stage_next <= SKIP_PARAMETER; - end if; when RXO_DESTINATION_ORDER => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered >= requested, with BY_RECEPTION_TIMESTAMP < BY_SOURCE_TIMESTAMP + for i in 0 to MAX_ENDPOINTS-1 loop -- data-in is Subscriber-Requested if (is_subscriber = '1') then if (data_in_swapped > ENDPOINT_DESTINATION_ORDER(i)) then @@ -1334,104 +1508,107 @@ begin end if; end if; end loop; - -- Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; when RXO_OWNERSHIP => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Check QoS Compatibility - if (data_in_swapped /= (data_in_swapped'reverse_range => '0')) then + + -- NOTE: Currently we only support Shared Ownership + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered = requested + if (data_in_swapped /= SHARED_OWNERSHIP_QOS) then endpoint_mask_next <= (others => '0'); end if; - -- Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; - when RXO_PRESENTATION_1 => + when RXO_PRESENTATION => + -- Input FIFO Guard if (empty = '0') then - rd_sig <= '1'; + rd_sig <= '1'; + cnt_next <= cnt + 1; - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop - -- data-in is Subscriber-Requested - if (is_subscriber = '1') then - if (data_in_swapped > ENDPOINT_PRESENTATION(i)) then - endpoint_mask_next(i) <= '0'; - end if; - -- data-in is Publisher-Offered - else - if (data_in_swapped < ENDPOINT_PRESENTATION(i)) then - endpoint_mask_next(i) <= '0'; - end if; - end if; - end loop; - -- Next Stage - stage_next <= RXO_PRESENTATION_2; - end if; - when RXO_PRESENTATION_2 => - if (empty = '0') then - rd_sig <= '1'; - - -- Check QoS Compatibility - for i in 0 to ENDPOINT_TOPIC'length-1 loop - -- data-in is Subscriber-Requested - if (is_subscriber = '1') then - if (data_in(23) = '1' and ENDPOINT_COHERENT_ACCESS(i) = '0') then - endpoint_mask_next(i) <= '0'; - end if; - if (data_in(15) = '1' and ENDPOINT_ORDERED_ACCESS(i) = '0') then - endpoint_mask_next(i) <= '0'; - end if; - end if; - end loop; - -- Next Stage - stage_next <= SKIP_PARAMETER; + case (cnt) is + when 0 => + -- Check QoS Compatibility (Unmark match on incompatibility) + -- COMPATIBLE (DDS v1.4): offered >= requested, with INSTANCE < TOPIC < GROUP + for i in 0 to MAX_ENDPOINTS-1 loop + -- data-in is Subscriber-Requested + if (is_subscriber = '1') then + if (data_in_swapped > ENDPOINT_PRESENTATION(i)) then + endpoint_mask_next(i) <= '0'; + end if; + -- data-in is Publisher-Offered + else + if (data_in_swapped < ENDPOINT_PRESENTATION(i)) then + endpoint_mask_next(i) <= '0'; + end if; + end if; + end loop; + when 1 => + -- Check QoS Compatibility (Unmark match on incompatibility) + for i in 0 to MAX_ENDPOINTS-1 loop + -- data-in is Subscriber-Requested + -- COMPATIBLE (DDS v1.4): requested=FALSE or requested=offered=TRUE + if (is_subscriber = '1') then + if (data_in(23) = '1' and ENDPOINT_COHERENT_ACCESS(i) = '0') then + endpoint_mask_next(i) <= '0'; + end if; + if (data_in(15) = '1' and ENDPOINT_ORDERED_ACCESS(i) = '0') then + endpoint_mask_next(i) <= '0'; + end if; + end if; + end loop; + -- DONE + stage_next <= SKIP_PARAMETER; + when others => + null; + end case; end if; when RXO_PARTITION => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- TODO: Implement full partition Name support? -- NOTE: Endpoints are only matched against the default empty partition. - - -- Check QoS Compatibility + -- Match Partition Names if (data_in_swapped /= (data_in_swapped'reverse_range => '0')) then endpoint_mask_next <= (others => '0'); end if; - - -- Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; when MATCH_DOMAIN_ID => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- DEAFULT Stage - stage_next <= SKIP_PARAMETER; - -- MATCH DOMAIN ID + + -- Match Domain ID if (data_in_swapped /= DOMAIN_ID) then - -- No Match participant_match_next <= '0'; end if; - -- Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; when MATCH_PROTOCOL_VERSION => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- DEAFULT Stage - stage_next <= SKIP_PARAMETER; - -- If RTPS Protocol Major Version is not 2, skip packet + + -- Match major Protocol Version if(data_in(31 downto 24) /= PROTOCOLVERSION_2_4(15 downto 8)) then - -- No Match participant_match_next <= '0'; end if; - -- Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; when LATCH_LOCATOR => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Increment Counter (Default) cnt_next <= cnt + 1; case (cnt) is @@ -1439,6 +1616,7 @@ begin when 0 => -- Check if UDPv4 Locator if (data_in_swapped /= LOCATOR_KIND_UDPv4) then + -- Skip stage_next <= SKIP_PARAMETER; end if; -- Locator Port @@ -1457,26 +1635,31 @@ begin else addr_latch_2 <= data_in_swapped; end if; - -- Exit Stage + -- DONE stage_next <= SKIP_PARAMETER; + when others => + null; end case; end if; when LATCH_EXPECTS_INLINE_QOS => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; -- Latch 'expectsInlineQoS' - expects_inline_qos_next <= data_in(24); - stage_next <= SKIP_PARAMETER; + extra_flags_next(EXPECTS_INLINE_QOS_FLAG) <= data_in(24); + expects_inline_qos_set_next <= '1'; + + -- DONE + stage_next <= SKIP_PARAMETER; end if; when LATCH_GUID => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Increment Counter (Default) cnt_next <= cnt + 1; - -- Check if GUID Prefix valid (Should be the same as the GUID Prefix of the Packet) - -- and update the Entity ID + -- Check if GUID Prefix valid (Should be the same as the GUID Prefix of the Packet) and update the Entity ID case (cnt) is when 0 => if (data_in /= guid(0)) then @@ -1492,31 +1675,30 @@ begin end if; when 3 => -- NOTE: Even though the mem_ctrl_prc is currently using the guid signal, it only uses the first - -- 3 bytes (GUIDPrefix) for the SEARCH_PARTICIPANT + -- 3 words (GUIDPrefix) for the SEARCH_PARTICIPANT guid_next(3) <= data_in; + -- DONE stage_next <= SKIP_PARAMETER; + when others => + null; end case; end if; when CHECK_REMOTE_BUILTIN_ENDPOINTS => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - -- Next Stage - stage_next <= SKIP_PARAMETER; - -- SANITY CHECK (Builtin Participant and Participant Message Endpoints have to be always available) if ( data_in_swapped(DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER) = '0' or data_in_swapped(DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR) = '0' or data_in_swapped(BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER) = '0' or data_in_swapped(BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER) = '0') then - -- No Match participant_match_next <= '0'; end if; -- Check for necessary Builtin Endpoints for Readers if (NUM_READERS > 0) then if ( data_in_swapped(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER) = '0' or data_in_swapped(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR) = '0') then - -- No Match participant_match_next <= '0'; end if; end if; @@ -1524,204 +1706,216 @@ begin if (NUM_WRITERS > 0) then if ( data_in_swapped(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER) = '0' or data_in_swapped(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR) = '0') then - -- No Match participant_match_next <= '0'; end if; end if; - end if; - when LATCH_BUILTIN_ENDPOINT_QOS => - if (empty = '0') then - rd_sig <= '1'; - -- Latch QoS - extra_flags_next <= data_in_swapped; - - -- DEFAULT Next Stage + -- DONE stage_next <= SKIP_PARAMETER; end if; - when PARTICIPANT_MATCH_STAGE_1 => - -- Wait for Participant Search and Sequence Number Process + when PARTICIPANT_MATCH_STAGE => + -- Wait for Participant Search to finish and Next Sequence Number to be set if (mem_op_done = '1' and seq_prc_done = '1') then - -- No Match in Buffer - if (addr_res = BUILTIN_BUFFER_SIZE) then + -- Participant not in Buffer + if (addr_res = MAX_ADDRESS) then -- Participant Match if (message_type = PDP and participant_match = '1') then -- Add participant in buffer deadline_next <= time + lease_duration; mem_opcode <= INSERT_PARTICIPANT; - start_mem_op <= '1'; + mem_op_start <= '1'; -- DONE stage_next <= SKIP_PACKET; else -- Ignore all other messages, since there is no corresponding participant in the buffer. stage_next <= SKIP_PACKET; end if; - -- Match in Buffer, Next Sequence Number - -- NOTE: We only process the Sequences in order. This may lead to more traffic being exchanged - -- (since all Data messages with a higher sequence number than the next expected will be ignored), - -- but keeps the logic simple. - elsif (next_seq_nr = seq_nr) - -- Participant + -- Participant in Buffer + else + -- Participant Announcement if (message_type = PDP) then - -- Participant Unmatch - if (participant_match = '0') then - -- Remove participant from buffer - mem_opcode <= REMOVE_PARTICIPANT; - start_mem_op <= '1'; - -- Find and delete all orphaned endpoints in Buffer - stage_next <= FIND_ORPHAN_ENDPOINT; + -- Newer Sequence Number + if (mem_seq_nr < seq_nr) then + -- Participant Unmatch + if (participant_match = '0') then + -- Remove participant from buffer + mem_opcode <= REMOVE_PARTICIPANT; + mem_op_start <= '1'; + -- Find and delete all orphaned endpoints in Buffer + stage_next <= FIND_ORPHAN_ENDPOINT; + -- Participant remains matched + else + -- Update Participant Data and Lease + mem_opcode <= UPDATE_PARTICIPANT; + deadline_next <= time + lease_duration; + update_participant_flags_next <= (PARTICIPANT_DATA_FLAG => '1', LEASE_DEADLINE_FLAG => '1', EXTRA_FLAGS_FLAG => '1', others => '0'); + mem_op_start <= '1'; + -- DONE + stage_next <= SKIP_PACKET; + end if; + -- Old Sequence Number else - -- Update Participant Data - mem_opcode <= UPDATE_PARTICIPANT; -- Update Lease + mem_opcode <= UPDATE_PARTICIPANT; deadline_next <= time + lease_duration; - update_participant_flags_next <= (PARTICIPANT_DATA_FLAG => '1', LEASE_DEADLINE_FLAG => '1', EXTRA_FLAGS_FLAG => '1', others => '0'); - start_mem_op <= '1'; + update_participant_flags_next <= (LEASE_DEADLINE_FLAG => '1', others => '0'); + mem_op_start <= '1'; -- DONE - stage_next <= SKIP_PACKET; + stage_next <= SKIP_PACKET; end if; - -- Endpoint - elsif (message_type = EDP) then - -- TODO: Should we renew the Participant Lease on Endpoint Activity? - No, it is clearly stated that a participant anouncement has to be received during the lease duration + -- NOTE: We only process the Sequences in order. This may lead to more traffic being exchanged + -- (since all Data messages with a higher sequence number than the next expected will be ignored), + -- but keeps the logic simple. + -- Endpoint (Next Expected Sequence Number) + elsif (message_type = EDP and next_seq_nr = seq_nr) then -- Store new Sequence Number mem_opcode <= UPDATE_PARTICIPANT; update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0'); - start_mem_op <= '1'; + mem_op_start <= '1'; + -- Search for Endpoint in Buffer stage_next <= INITIATE_ENDPOINT_SEARCH; else - -- Ignore + -- Ignore (Messages are handled in a dedicated stage) stage_next <= SKIP_PACKET; end if; - -- Old Sequence Number - else - -- If Participant Anouncement, renew lease deadline - if (message_type = PDP) then - -- Update Lease - mem_opcode <= UPDATE_PARTICIPANT; - deadline_next <= time + lease_duration; - update_participant_flags_next <= (LEASE_DEADLINE_FLAG => '1', others => '0'); - start_mem_op <= '1'; - end if; - -- Done - stage_next <= SKIP_PACKET; end if; end if; -- Help stage, because we need to do two consecutive memory operations when INITIATE_ENDPOINT_SEARCH => + -- Memory Operation Guard if (mem_op_done = '1') then -- Search Endpoint in Buffer mem_opcode <= SEARCH_ENDPOINT; - start_mem_op <= '1'; - -- DONE + mem_op_start <= '1'; + stage_next <= ENDPOINT_MATCH_STAGE; end if; when ENDPOINT_MATCH_STAGE => - -- Wait for Endpoint Search + -- Wait for Endpoint Search to finish if (mem_op_done = '1') then -- No Match in Buffer (New remote Endpoint) - if (addr_res = BUILTIN_BUFFER_SIZE) then - -- At least one local endpoint match + if (addr_res = MAX_ADDRESS) then + -- At least one local Endpoint match if (endpoint_mask /= (endpoint_mask'range => '0')) then - -- Add endpoint in buffer + -- Add Endpoint in buffer mem_opcode <= INSERT_ENDPOINT; - start_mem_op <= '1'; - -- Mark UNMATCHES + mem_op_start <= '1'; + -- Mark MATCHES endpoint_match_next <= endpoint_mask; endpoint_unmatch_next <= (others => '0'); - -- Propagate Match Changes to local Endpoints + -- Propagate Matches to local Endpoints stage_next <= INFORM_ENDPOINTS_MATCH; cnt_next <= 0; end if; -- Match in buffer (Existing Endpoint) else - -- At least one local endpoint match + -- At least one local Endpoint match if (endpoint_mask /= (endpoint_mask'range => '0')) then - tmp_endpoint_mask := convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS); -- Mark Endpoint match changes - tmp_endpoint_mask := tmp_endpoint_mask xor endpoint_mask; + tmp_endpoint_mask := convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS); + tmp_endpoint_mask := tmp_endpoint_mask xor endpoint_mask; -- Mark UNMATCHES endpoint_unmatch_next <= tmp_endpoint_mask xor endpoint_mask; -- Mark NEW MATCHES endpoint_match_next <= tmp_endpoint_mask and endpoint_mask; -- Update endpoint in buffer mem_opcode <= UPDATE_ENDPOINT; - start_mem_op <= '1'; + mem_op_start <= '1'; -- Propagate Match Changes to local Endpoints stage_next <= INFORM_ENDPOINTS_MATCH; cnt_next <= 0; + -- No local Endpoint match else -- Remove endpoint from buffer mem_opcode <= REMOVE_ENDPOINT; - start_mem_op <= '1'; + mem_op_start <= '1'; -- Mark UNMATCHES endpoint_match_next <= (others => '0'); endpoint_unmatch_next <= convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS); - -- Propagate Match Changes to local Endpoints + -- Propagate Unmatches to local Endpoints stage_next <= INFORM_ENDPOINTS_UNMATCH; cnt_next <= 0; end if; end if; end if; when FIND_ORPHAN_ENDPOINT => + -- Memory Operation Guard if (mem_op_done = '1') then + -- Initiate Endpoint Search is_orphan_search_next <= '1'; mem_opcode <= SEARCH_ENDPOINT; - start_mem_op <= '1'; + mem_op_start <= '1'; stage_next <= PURGE_ORPHAN_ENDPOINT; end if; when PURGE_ORPHAN_ENDPOINT => + -- Wait for Endpoint Search to finish if (mem_op_done = '1') then - -- Orphan Match - if (addr_res /= BUILTIN_BUFFER_SIZE) then - -- Remove orphaned endpoint from buffer + -- Found Orphan Endpoint + if (addr_res /= MAX_ADDRESS) then + -- Remove Orphaned Endpoint from Buffer mem_opcode <= REMOVE_ENDPOINT; - start_mem_op <= '1'; + mem_op_start <= '1'; -- Mark UNMATCHES endpoint_match_next <= (others => '0'); endpoint_unmatch_next <= convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS); - -- Propagate Match Changes to local Endpoints + -- Propagate Unmatches to local Endpoints stage_next <= INFORM_ENDPOINTS_UNMATCH; cnt_next <= 0; - -- Buffer has no more orphans + -- Buffer has no more Orphans else -- DONE stage_next <= SKIP_PACKET; end if; end if; when INFORM_ENDPOINTS_MATCH => + -- Output FIFO Guard if ((endpoint_match and endpoint_full) = (endpoint_full'range => '0')) then - -- Increment Counter - cnt_next <= cnt + 1; - -- Enable Write wr_sig <= '1'; + cnt_next <= cnt + 1; + case (cnt) is + -- Match Opcode when 0 => output_sig <= OPCODE_MATCH; + -- GUID Prefix 1/3 when 1 => output_sig <= guid(0); + -- GUID Prefix 2/3 when 2 => output_sig <= guid(1); + -- GUID Prefix 3/3 when 3 => output_sig <= guid(2); + -- Entity ID when 4 => output_sig <= guid(3); + -- IPv4 Address when 5 => - -- Use Address set by PID + -- If Endpoint did not set Address, use Participant Default if (addr_latch_1 /= (addr_latch_1'reverse_range => '0')) then output_sig <= addr_latch_1; - -- Else use the Default Address from Participant else - output_sig <= mem_def_addr; + output_sig <= mem_participant_data.def_addr; end if; + -- UDPv4 Port and ExpectsInlineQoSFlag when 6 => - -- Use Port set by PID + -- Default + output_sig <= (others => '0'); + + -- If Endpoint did not set Port, use Participant Default if (port_latch_1 /= (port_latch_1'reverse_range => '0')) then - output_sig <= port_latch_1 & mem_xflags; - -- Else use the Default Port from Participant + output_sig(31 downto 16) <= port_latch_1; else - output_sig <= mem_def_port & mem_xflags; + output_sig(31 downto 16) <= mem_participant_data.def_port; end if; - -- If there are endpoints to unmatch, inform them + -- If Endpoint did not set Flags, use Participant Default + if (expects_inline_qos_set = '1') then + output_sig(0) <= extra_flags(EXPECTS_INLINE_QOS_FLAG); + else + output_sig(0) <= mem_participant_data.extra_flags(EXPECTS_INLINE_QOS_FLAG); + end if; + + -- If there are Endpoints to unmatch, inform them if (endpoint_unmatch /= (endpoint_unmatch'range => '0')) then stage_next <= INFORM_ENDPOINTS_UNMATCH; cnt_next <= 0; @@ -1729,68 +1923,77 @@ begin -- DONE stage_next <= SKIP_PACKET; end if; + when others => + null; end case; end if; when INFORM_ENDPOINTS_UNMATCH => + -- Output FIFO Guard if ((endpoint_unmatch and endpoint_full) = (endpoint_full'range => '0')) then - -- Increment Counter - cnt_next <= cnt + 1; - -- Enable Write wr_sig <= '1'; + cnt_next <= cnt + 1; + case (cnt) is + -- Match Opcode when 0 => output_sig <= OPCODE_UNMATCH; + -- GUID Prefix 1/3 when 1 => output_sig <= guid(0); + -- GUID Prefix 2/3 when 2 => output_sig <= guid(1); + -- GUID Prefix 3/3 when 3 => output_sig <= guid(2); + -- Entity ID when 4 => output_sig <= guid(3); - -- If we are in the middle of an orphan purge process, return to the search stage + -- If we are in the middle of an Orphan Purge Process, return to the search stage if (is_orphan_search = '1') then stage_next <= FIND_ORPHAN_ENDPOINT; else -- DONE stage_next <= SKIP_PACKET; end if; + when others => + null; end case; end if; when STALE_CHECK => - -- Wait for memory OP + -- Wait for Stale Search to finish if (mem_op_done = '1') then -- Found Stale Entry - if (addr_res /= BUILTIN_BUFFER_SIZE) then + if (addr_res /= MAX_ADDRESS) then -- Participant Lease Expired -- NOTE: The mem_participant_data is zero initialized on lease expiration, so we check the default address for zero -- (since the default address should always be set) if (mem_participant_data.def_addr /= (mem_participant_data.def_addr'reverse_range => '0')) then -- Remove Participant mem_opcode <= REMOVE_PARTICIPANT; - start_mem_op <= '1'; - stage_next <= AUTO_PURGE; - -- Participant Response Time Reached + mem_op_start <= '1'; + stage_next <= LATCH_REMOVED_GUIDPREFIX; + -- Response Time Reached else -- Heartbeat Response if (is_heartbeat_res = '1') then -- If Suppression Delay passed, zero the time if(mem_participant_data.heartbeat_res_time(0) = '1') then - mem_opcode <= UPDATE_PARTICIPANT; -- Zero Heartbeat Response Time + mem_opcode <= UPDATE_PARTICIPANT; deadline_next <= (others => '0'); update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0'); - start_mem_op <= '1'; + mem_op_start <= '1'; -- DONE stage_next <= IDLE; -- If Response Delay Passed else -- Set Heartbeat Suppression Time mem_opcode <= UPDATE_PARTICIPANT; - if (TODO /= 0) then + if (PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY /= 0) then -- Set Heartbeat Suppression Time - deadline_next <= time + TODO; + deadline_next <= time + PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY; -- NOTE: Last Bit denotes if this is Response or Suppression Delay deadline_next(0) <= '1'; else @@ -1798,29 +2001,31 @@ begin deadline_next <= (others => '0'); end if; update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0'); - start_mem_op <= '1'; - -- Send Acknack + mem_op_start <= '1'; + -- Send ACKNACK + -- Increment Heartbeat/Acknack Counter + count_next <= count + 1; stage_next <= SEND_HEADER; return_stage_next <= SEND_ACKNACK; cnt_next <= 0; end if; - -- Acknack Response Time + -- Acknack Response else -- If Suppression Delay passed, zero the time if(mem_participant_data.acknack_res_time(0) = '1') then - mem_opcode <= UPDATE_PARTICIPANT; -- Zero Acknack Response Time + mem_opcode <= UPDATE_PARTICIPANT; deadline_next <= (others => '0'); update_participant_flags_next <= (ACKNACK_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; + mem_op_start <= '1'; -- DONE stage_next <= IDLE; -- If Response Delay Passed else mem_opcode <= UPDATE_PARTICIPANT; - if (TODO /= 0) then + if (PARTICIPANT_ACKNACK_SUPPRESSION_DELAY /= 0) then -- Set Acknack Suppression Time - deadline_next <= time + TODO; + deadline_next <= time + PARTICIPANT_ACKNACK_SUPPRESSION_DELAY; -- NOTE: Last Bit denotes if this is Response or Suppression Delay deadline_next(0) <= '1'; else @@ -1833,19 +2038,20 @@ begin extra_flags_next(SUB_DATA_FLAG) <= '0'; extra_flags_next(MES_DATA_FLAG) <= '0'; update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; + mem_op_start <= '1'; -- Send Requested Data stage_next <= SEND_DATA; cnt_next <= 0; end if; end if; end if; + -- No Stale Entry Found else - -- No Stale Entry Found, DONE + -- DONE stage_next <= IDLE; end if; end if; - when AUTO_PURGE => + when LATCH_REMOVED_GUIDPREFIX => if (mem_op_done = '1') then -- Help Stage needed to latch the GUID Prefix of the removed staled participant (Needed for the orphan search) guid_next(0) <= mem_guidprefix(0); @@ -1854,67 +2060,71 @@ begin stage_next <= FIND_ORPHAN_ENDPOINT; end if; when PROCESS_HEARTBEAT => + -- Input FIFO Guard if (empty = '0') then rd_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; - -- Latch Sequence Number + + -- Latch Sequence Numbers case (cnt) is when 0 => - first_seq_nr_next(0) <= data_in; + first_seq_nr_next(0) <= data_in_swapped; when 1 => - first_seq_nr_next(1) <= data_in; + first_seq_nr_next(1) <= data_in_swapped; when 2 => - last_seq_nr_next(0) <= data_in; + last_seq_nr_next(0) <= data_in_swapped; when 3 => - last_seq_nr_next(1) <= data_in; + last_seq_nr_next(1) <= data_in_swapped; stage_next <= PROCESS_HEARTBEAT_SEQUENCE_NUMBERS; + when others => + null; end case; end if; when PROCESS_HEARTBEAT_SEQUENCE_NUMBERS => - -- Wait for Sequence Number to be fetched from buffer - if (mem_done = '1' and seq_prc_done = '1') then - -- No scheduled Heartbeat Response - if (mem_participant_data.heartbeat_res_time /= (mem_participant_data.heartbeat_res_time'reverse_range => '0')) then - -- If current sequence number obsolete (removed from source history cache), - -- reset sequence number to expect the first available and request it - if (first_seq_nr > next_seq_nr) then - -- Store expected sequence number -1, since we process only stored sequence number +1 - seq_nr_next <= first_seq_nr - 1; - mem_opcode <= UPDATE_PARTICIPANT; - deadline_next <= time + TODO; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '0'; - update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', HEARTBEAT_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; - -- If new sequence number is available or Writer expects ACKNACK, send it - elsif (last_seq_nr > mem_seq_nr or final_flag = '0') then - mem_opcode <= UPDATE_PARTICIPANT; - deadline_next <= time + TODO; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '0'; - update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; - end if; - -- Currently in Heartbeat Response Delay - elsif (mem_participant_data.heartbeat_res_time(0) = '0') then - -- If current sequence number obsolete (removed from source history cache), - -- reset sequence number to expect the first available and request it - if (first_seq_nr > next_seq_nr) then - -- Store expected sequence number -1, since we process only stored sequence number +1 - seq_nr_next <= first_seq_nr - 1; - mem_opcode <= UPDATE_PARTICIPANT; - update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0'); - start_mem_op <= '1'; + -- Wait for Participant Search to finish and Next Sequence Number to be set + if (mem_op_done = '1' and seq_prc_done = '1') then + -- Participant in Buffer + if (addr_res /= MAX_ADDRESS) then + -- No scheduled Heartbeat Response + if (mem_participant_data.heartbeat_res_time /= 0) then + -- If current Sequence Number obsolete (removed from source history cache) + if (first_seq_nr > next_seq_nr) then + -- Store new expected Sequence Number -1 and set Response Dealy + seq_nr_next <= first_seq_nr - 1; + mem_opcode <= UPDATE_PARTICIPANT; + deadline_next <= time + PARTICIPANT_HEARTBEAT_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '0'; + update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', HEARTBEAT_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; + -- If new Sequence Number is available or Writer expects ACKNACK + elsif (last_seq_nr > mem_seq_nr or final_flag = '0') then + -- Set Response Delay + mem_opcode <= UPDATE_PARTICIPANT; + deadline_next <= time + PARTICIPANT_HEARTBEAT_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '0'; + update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; + -- Currently in Heartbeat Response Delay + elsif (mem_participant_data.heartbeat_res_time(0) = '0') then + -- If current Sequence Number obsolete (removed from source history cache) + if (first_seq_nr > next_seq_nr) then + -- Store new expected Sequence Number -1 + seq_nr_next <= first_seq_nr - 1; + mem_opcode <= UPDATE_PARTICIPANT; + update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; end if; end if; - -- Done + -- DONE stage_next <= SKIP_PACKET; end if; when SEND_ACKNACK => if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -1930,10 +2140,10 @@ begin output_sig <= ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER; -- Sequence Number Set (Bitmap Base 1/2) when 3 => - output_sig <= mem_participant_data.pub_seq_nr(0); + output_sig <= std_logic_vector(mem_participant_data.pub_seq_nr(0)); -- Sequence Number Set (Bitmap Base 2/2) when 4 => - output_sig <= mem_participant_data.pub_seq_nr(1); + output_sig <= std_logic_vector(mem_participant_data.pub_seq_nr(1)); -- Sequence Number Set (NumBits) when 5 => output_sig <= (others => '0'); @@ -1952,10 +2162,10 @@ begin output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER; -- Sequence Number Set (Bitmap Base 1/2) when 10 => - output_sig <= mem_participant_data.sub_seq_nr(0); + output_sig <= std_logic_vector(mem_participant_data.sub_seq_nr(0)); -- Sequence Number Set (Bitmap Base 2/2) when 11 => - output_sig <= mem_participant_data.sub_seq_nr(1); + output_sig <= std_logic_vector(mem_participant_data.sub_seq_nr(1)); -- Sequence Number Set (NumBits) when 12 => output_sig <= (others => '0'); @@ -1974,25 +2184,27 @@ begin output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER; -- Sequence Number Set (Bitmap Base 1/2) when 17 => - output_sig <= mem_participant_data.mes_seq_nr(0); + output_sig <= std_logic_vector(mem_participant_data.mes_seq_nr(0)); -- Sequence Number Set (Bitmap Base 2/2) when 18 => - output_sig <= mem_participant_data.mes_seq_nr(1); + output_sig <= std_logic_vector(mem_participant_data.mes_seq_nr(1)); -- Sequence Number Set (NumBits) when 19 => output_sig <= (others => '0'); -- Count when 20 => output_sig <= count; - -- Signal Last Word7 - first_seq_nr_next(1) <= data_in; - stage_next <= PROCESS_ACKNACK_SEQUENCE_NUMBERS + last_word_out <= '1'; + + -- DONE + stage_next <= IDLE; + when others => + null; end case; end if; when SEND_HEARTBEAT => if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -2008,16 +2220,16 @@ begin output_sig <= ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER; -- Sequence Number 1/2 when 3 => - output_sig <= SEQUENCE_NR_START(0); + output_sig <= std_logic_vector(SEQUENCE_NR_START(0)); -- Sequence Number 2/2 when 4 => - output_sig <= SEQUENCE_NR_START(1); + output_sig <= std_logic_vector(SEQUENCE_NR_START(1)); -- Sequence Number 1/2 when 5 => - output_sig <= PUB_SEQUENCE_NR(0); + output_sig <= std_logic_vector(PUB_SEQUENCE_NR(0)); -- Sequence Number 1/2 when 6 => - output_sig <= PUB_SEQUENCE_NR(1); + output_sig <= std_logic_vector(PUB_SEQUENCE_NR(1)); -- Count when 7 => output_sig <= count; @@ -2033,16 +2245,16 @@ begin output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER; -- Sequence Number 1/2 when 11 => - output_sig <= SEQUENCE_NR_START(0); + output_sig <= std_logic_vector(SEQUENCE_NR_START(0)); -- Sequence Number 2/2 when 12 => - output_sig <= SEQUENCE_NR_START(1); + output_sig <= std_logic_vector(SEQUENCE_NR_START(1)); -- Sequence Number 1/2 when 13 => - output_sig <= SUB_SEQUENCE_NR(0); + output_sig <= std_logic_vector(SUB_SEQUENCE_NR(0)); -- Sequence Number 1/2 when 14 => - output_sig <= SUB_SEQUENCE_NR(1); + output_sig <= std_logic_vector(SUB_SEQUENCE_NR(1)); -- Count when 15 => output_sig <= count; @@ -2058,16 +2270,16 @@ begin output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER; -- Sequence Number 1/2 when 19 => - output_sig <= man_live_seq_nr(0); + output_sig <= std_logic_vector(man_live_seq_nr(0)); -- Sequence Number 2/2 when 20 => - output_sig <= man_live_seq_nr(1); + output_sig <= std_logic_vector(man_live_seq_nr(1)); -- Sequence Number 1/2 when 21 => - output_sig <= auto_live_seq_nr(0); + output_sig <= std_logic_vector(auto_live_seq_nr(0)); -- Sequence Number 1/2 when 22 => - output_sig <= auto_live_seq_nr(1); + output_sig <= std_logic_vector(auto_live_seq_nr(1)); -- Count when 23 => output_sig <= count; @@ -2080,133 +2292,156 @@ begin stage_next <= SEND_MES_MAN_LIVE; cnt_next <= 0; end if; - if () + when others => + null; + end case; + end if; + when PROCESS_ACKNACK => + if (empty = '0') then + rd_sig <= '1'; + cnt_next <= cnt + 1; + + -- Latch Sequence Number + -- NOTE: Because we always sent the entire history cache, we only need to look at the SequenceNumberSetBase to determine if we need to sent data or not + case (cnt) is + when 1 => + first_seq_nr_next(0) <= data_in_swapped; + when 2 => + first_seq_nr_next(1) <= data_in_swapped; + + stage_next <= PROCESS_ACKNACK_SEQUENCE_NUMBERS + when others => + null; end case; end if; when PROCESS_ACKNACK_SEQUENCE_NUMBERS => - -- Wait for Memory Operation to finish - if (mem_done = '1') then - -- No scheduled Acknack Response - if (mem_participant_data.acknack_res_time /= (mem_participant_data.acknack_res_time'reverse_range => '0')) then - case (message_type) is - when EDP => - -- Subscriber Acknack - if (is_subscriber = '1') then - -- If reader has not acked all Publisher history cache, mark for send - if (first_seq_nr <= PUB_SEQUENCE_NR) then - mem_opcode <= UPDATE_PARTICIPANT; - -- Set Acknack Response Time - deadline_next <= time + TODO; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '0'; - -- Set Publisher Data as Acknack Response - extra_flags_next <= mem_participant_data.extra_flags; - extra_flags_next(PUB_DATA_FLAG) <= '1'; - update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; - end if; - -- Publisher Acknack - else - -- If reader has not acked all Subscriber history cache, mark for send - if (first_seq_nr <= SUB_SEQUENCE_NR) then - mem_opcode <= UPDATE_PARTICIPANT; - -- Set Acknack Response Time - deadline_next <= time + TODO; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '0'; - -- Set Subscriber Data as Acknack Response - extra_flags_next <= mem_participant_data.extra_flags; - extra_flags_next(SUB_DATA_FLAG) <= '1'; - update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; - end if; - end if; - -- Message Acknack - when MESSAGE => - -- NOTE: "auto_live_seq_nr" always has the higher sequence number by design, so we just need to - -- check against that - -- If reader has not acked all Message history cache, mark for send - if (first_seq_nr <= auto_live_seq_nr) then - mem_opcode <= UPDATE_PARTICIPANT; - -- Set Acknack Response Time - deadline_next <= time + TODO; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '0'; - -- Set Message Data as Acknack Response - extra_flags_next <= mem_participant_data.extra_flags; - extra_flags_next(MES_DATA_FLAG) <= '1'; - update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - start_mem_op <= '1'; - end if; - end case; - -- Currently in Acknack Response Delay - elsif (mem_participant_data.acknack_res_time(0) = '0') then - case (message_type) is - when EDP => - -- Subscriber Acknack - if (is_subscriber = '1') then - -- Publisher Data not scheduled for response - if (mem_participant_data.extra_flags(PUB_DATA_FLAG)) then - -- If reader has not acked all Publisher history cache, mark for send + -- Wait for Participant Search to finish + if (mem_op_done = '1') then + -- Participant in Buffer + if (addr_res /= MAX_ADDRESS) then + -- No scheduled Acknack Response + if (mem_participant_data.acknack_res_time /= 0) then + case (message_type) is + when EDP => + -- Subscriber Acknack + if (is_subscriber = '1') then + -- If Reader has not ACKed all Publisher History Cache if (first_seq_nr <= PUB_SEQUENCE_NR) then + -- Set Acknack Response Time and Publisher Data as Acknack Response mem_opcode <= UPDATE_PARTICIPANT; - -- Set Publisher Data as Acknack Response + deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '0'; extra_flags_next <= mem_participant_data.extra_flags; extra_flags_next(PUB_DATA_FLAG) <= '1'; - update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0'); - start_mem_op <= '1'; + update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; end if; - end if; - -- Publisher Acknack - else - -- Subscriber Data not scheduled for response - if (mem_participant_data.extra_flags(SUB_DATA_FLAG)) then - -- If reader has not acked all Subscriber history cache, mark for send + -- Publisher Acknack + else + -- If Reader has not ACKed all Subscriber History Cache if (first_seq_nr <= SUB_SEQUENCE_NR) then + -- Set Acknack Response Time and set Subscriber Data as Acknack Response mem_opcode <= UPDATE_PARTICIPANT; - -- Set Subscriber Data as Acknack Response + deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '0'; extra_flags_next <= mem_participant_data.extra_flags; extra_flags_next(SUB_DATA_FLAG) <= '1'; - update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0'); - start_mem_op <= '1'; + update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; end if; end if; - -- Message Acknack - when MESSAGE => - -- Message Data not scheduled for response - if (mem_participant_data.extra_flags(MES_DATA_FLAG)) then - -- NOTE: "auto_live_seq_nr" always has the higher sequence number by design, so we just need to - -- check against that - -- If reader has not acked all Message history cache, mark for send + -- Message Acknack + when MESSAGE => + -- NOTE: "auto_live_seq_nr" always has the higher sequence number by design, so we just need to check against that + -- If Reader has not ACKed all Message History Cache if (first_seq_nr <= auto_live_seq_nr) then + -- Set Acknack Response Time and set Message Data as Acknack Response mem_opcode <= UPDATE_PARTICIPANT; - -- Set Message Data as Acknack Response + deadline_next <= time + PARTICIPANT_ACKNACK_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '0'; extra_flags_next <= mem_participant_data.extra_flags; extra_flags_next(MES_DATA_FLAG) <= '1'; - update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0'); - start_mem_op <= '1'; + update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; end if; - end if; - end case; + when others => + null; + end case; + -- Currently in Acknack Response Delay + elsif (mem_participant_data.acknack_res_time(0) = '0') then + case (message_type) is + when EDP => + -- Subscriber Acknack + if (is_subscriber = '1') then + -- Publisher Data not scheduled for response + if (mem_participant_data.extra_flags(PUB_DATA_FLAG)) then + -- If Reader has not ACKed all Publisher History Cache + if (first_seq_nr <= PUB_SEQUENCE_NR) then + -- Set Publisher Data as Acknack Response + mem_opcode <= UPDATE_PARTICIPANT; + extra_flags_next <= mem_participant_data.extra_flags; + extra_flags_next(PUB_DATA_FLAG) <= '1'; + update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; + end if; + -- Publisher Acknack + else + -- Subscriber Data not scheduled for response + if (mem_participant_data.extra_flags(SUB_DATA_FLAG)) then + -- If Reader has not ACKed all Subscriber History Cache + if (first_seq_nr <= SUB_SEQUENCE_NR) then + -- Set Subscriber Data as Acknack Response + mem_opcode <= UPDATE_PARTICIPANT; + extra_flags_next <= mem_participant_data.extra_flags; + extra_flags_next(SUB_DATA_FLAG) <= '1'; + update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; + end if; + -- Message Acknack + when MESSAGE => + -- Message Data not scheduled for response + if (mem_participant_data.extra_flags(MES_DATA_FLAG)) then + -- NOTE: "auto_live_seq_nr" always has the higher sequence number by design, so we just need to + -- check against that + -- If Reader has not ACKed all Message History Cache + if (first_seq_nr <= auto_live_seq_nr) then + -- Set Message Data as Acknack Response + mem_opcode <= UPDATE_PARTICIPANT; + extra_flags_next <= mem_participant_data.extra_flags; + extra_flags_next(MES_DATA_FLAG) <= '1'; + update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; + end if; + when others => + null; + end case; + end if; end if; - -- Done + -- DONE stage_next <= SKIP_PACKET; end if; when FIND_PARTICIPANT_DEST => + -- Wait for Next Participant to be Fetched if (mem_op_done = '1') then - -- No Participant Found - if (addr_res = BUILTIN_BUFFER_SIZE) then + -- No more Participants + if (addr_res = MAX_ADDRESS) then + -- DONE stage_next <= IDLE; else - cnt_next <= 0; stage_next <= SEND_HEADER; return_stage_next <= SEND_HEARTBEAT; + cnt_next <= 0; end if end if; when SEND_HEADER => if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -2216,6 +2451,7 @@ begin output_sig <= DEFAULT_IPv4_MULTICAST_ADDRESS; -- Dest IPv4 Address when 1 => + -- Set Default Multicast Announce Address if Participant Announcement if (return_stage = SEND_PARTICIPANT_ANNOUNCEMENT) then output_sig <= DEFAULT_IPv4_MULTICAST_ADDRESS; else @@ -2223,6 +2459,7 @@ begin end if; -- Src and Dest UDPv4 Ports when 2 => + -- Set Default Multicast Announce Port if Participant Announcement if (return_stage = SEND_PARTICIPANT_ANNOUNCEMENT) then output_sig <= META_IPv4_UNICAST_PORT & META_IPv4_MULTICAST_PORT; else @@ -2239,20 +2476,25 @@ begin output_sig <= GUIDPREFIX(1); when 7 => output_sig <= GUIDPREFIX(2); - cnt_next <= 0; + -- Continue with respective RTPS Submessage stage_next <= return_stage; + cnt_next <= 0; + when others => + null; end case; end if; when SEND_PARTICIPANT_ANNOUNCEMENT => if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; - -- Send Data + + -- Send Participant Data output_sig <= PARTICIPANT_DATA.data(cnt); + -- Exit Condition if (cnt = (PARTICIPANT_DATA.length-1)) then last_word_out <= '1'; + -- DONE stage_next <= IDLE; end if; end if; @@ -2260,20 +2502,24 @@ begin -- If Publisher Data not scheduled for response or no Writers available, skip if (mem_participant_data.extra_flags(PUB_DATA_FLAG) = '0' or NUM_WRITERS = 0) then stage_next <= SEND_SUB_DATA; + -- Output FIFO Guard elsif (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; - -- Send Data + + -- Send Publisher Data output_sig <= WRITER_ENDPOINT_DATA.data(cnt); + -- Exit Condition if (cnt = (WRITER_ENDPOINT_DATA.length-1)) then last_word_out <= '1'; + -- If we still have Data to sent, continue if (mem_participant_data.extra_flags(SUB_DATA_FLAG) = '1' or mem_participant_data.extra_flags(MES_DATA_FLAG) = '1') then stage_next <= SEND_HEADER; return_stage_next <= SEND_SUB_DATA; cnt_next <= 0; else + -- DONE stage_next <= IDLE; end if; end if; @@ -2282,28 +2528,32 @@ begin -- If Subscriber Data not scheduled for response or no Readers available, skip if (mem_participant_data.extra_flags(PUB_DATA_FLAG) = '0' or NUM_READERS = 0) then stage_next <= SEND_MES_MAN_LIVE; + -- Output FIFO Guard elsif (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; - -- Send Data + + -- Send Subscriber Data output_sig <= READER_ENDPOINT_DATA.data(cnt); + -- Exit Condition if (cnt = (READER_ENDPOINT_DATA.length-1)) then last_word_out <= '1'; + -- If we still have Data to sent, continue if (mem_participant_data.extra_flags(MES_DATA_FLAG) = '1') then stage_next <= SEND_HEADER; return_stage_next <= SEND_MES_MAN_LIVE; cnt_next <= 0; else + -- DONE stage_next <= IDLE; end if; end if; end if; when SEND_MES_MAN_LIVE => + -- Output FIFO Guard if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -2322,10 +2572,10 @@ begin output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER; -- Sequence Number 1/2 when 4 => - output_sig <= man_live_seq_nr(0); + output_sig <= std_logic_vector(man_live_seq_nr(0)); -- Sequence Number 2/2 when 5 => - output_sig <= man_live_seq_nr(1); + output_sig <= std_logic_vector(man_live_seq_nr(1)); -- Serialized Payload Header when 6 => output_sig <= CDR_BE & x"0000"; @@ -2349,17 +2599,18 @@ begin if (live_gap_start /= auto_live_seq_nr) then stage_next <= SEND_MES_GAP; cnt_next <= 0; - -- Else Continue with Automatic Liveliness else stage_next <= SEND_MES_AUTO_LIVE; cnt_next <= 0; end if; + when others => + null; end case; end if; when SEND_MES_GAP => + -- Output FIFO Guard if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -2375,27 +2626,29 @@ begin output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER; -- GAP Start Sequence Number 1/2 when 3 => - output_sig <= live_gap_start(0); + output_sig <= std_logic_vector(live_gap_start(0)); -- GAP Start Sequence Number 2/2 when 4 => - output_sig <= live_gap_start(1); + output_sig <= std_logic_vector(live_gap_start(1)); -- GAP End Sequence Number Set (Bitmap Base 1/2) when 5 => - output_sig <= live_gap_end(0); + output_sig <= std_logic_vector(live_gap_end(0)); -- GAP End Sequence Number Set (Bitmap Base 2/2) when 6 => - output_sig <= live_gap_end(1); + output_sig <= std_logic_vector(live_gap_end(1)); -- GAP End Sequence Number Set (NumBits) when 7 => output_sig <= (others => '0'); stage_next <= SEND_MES_AUTO_LIVE; cnt_next <= 0; + when others => + null; end case; end if; when SEND_MES_AUTO_LIVE => + -- Output FIFO Guard if (rtps_full = '0') then wr_sig <= '1'; - --Increment Counter cnt_next <= cnt + 1; case (cnt) is @@ -2414,10 +2667,10 @@ begin output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER; -- Sequence Number 1/2 when 4 => - output_sig <= auto_live_seq_nr(0); + output_sig <= std_logic_vector(auto_live_seq_nr(0)); -- Sequence Number 2/2 when 5 => - output_sig <= auto_live_seq_nr(1); + output_sig <= std_logic_vector(auto_live_seq_nr(1)); -- Serialized Payload Header when 6 => output_sig <= CDR_BE & x"0000"; @@ -2438,61 +2691,82 @@ begin when 11 => output_sig <= (others => '0'); last_word_out <= '1'; - -- If we are in the middle of a liveliness assertion, find the next participant destination + -- If we are in the middle of a liveliness assertion, find the next Participant destination if (is_live_assert = '1') then stage_next <= FIND_PARTICIPANT_DEST; mem_opcode <= FIND_NEXT_PARTICIPANT; - start_mem_op <= '1'; + mem_op_start <= '1'; else -- DONE stage_next <= IDLE; end if; + when others => + null; end case; end if; when LIVELINESS_UPDATE => - -- If no endpoint interested for liveliness, skip + -- If no Endpoint interested for Liveliness Assertion, skip if (endpoint_mask = (endpoint_mask'range => '0')) then + -- DONE stage_next <= SKIP_PACKET; + -- Output FIFO Guard elsif ((endpoint_mask and endpoint_full) = (endpoint_full'range => '0')) then - -- Increment Counter - cnt_next <= cnt + 1; - -- Enable Write wr_sig <= '1'; + cnt_next <= cnt + 1; + case (cnt) is + -- Liveliness Assertion Opcode when 0 => output_sig <= OPCODE_LIVELINESS_UPDATE; + -- GUID Prefix 1/3 when 1 => output_sig <= guid(0); + -- GUID Prefix 2/3 when 2 => output_sig <= guid(1); + -- GUID Prefix 3/3 when 3 => output_sig <= guid(2); + -- DONE stage_next <= SKIP_PACKET; + when others => + null; end case; end if; - --############################# when SKIP_PARAMETER => -- End of Parameter if (read_cnt > parameter_end) then - -- Begin parsing of next parameter + -- Parse Next Parameter + -- NOTE: data_in is already showing the next parameter stage_next <= PROCESS_PL; + -- Input FIFO Guard elsif (empty = '0') then + -- Skip-Read rd_sig <= '1'; + -- End of Parameter if (read_cnt = parameter_end) then - -- Begin parsing of next parameter + -- Parse Next Parameter stage_next <= PROCESS_PL; end if; end if; when SKIP_PACKET => - if (last_word_in_latch = '1') then - -- Begin parsing of next parameter + -- NOTE: At the end of a Stale Entry Removal this stage is entered, without having started reading a Packet from input. + -- Stale Check Exit + if (stale_check = '1') then + -- DONE stage_next <= IDLE; + -- End of Packet + elsif (last_word_in_latch = '1') then + -- DONE + stage_next <= IDLE; + -- Input FIFO Guard elsif (empty = '0') then + -- Skip-Read rd_sig <= '1'; -- End of Packet if (last_word_in = '1') then - -- Continue parsing next packet + -- DONE stage_next <= IDLE; end if; end if; @@ -2501,12 +2775,12 @@ begin end case; end process; - mem_op_busy <= not mem_op_done; + -- TODO: add_res is still valid after removal. So we could continue searching the next orphan endpoint from that address on mem_ctrl_prc : process(all) - variable tmp : unsigned(mem_addr_base'range) := (others => '0'); - variable tmp2 : unsigned(mem_addr_base'range) := (others => '0'); - variable tmp3 : unsigned(mem_addr_base'range) := (others => '0'); + variable tmp : unsigned(mem_addr_base'range) := (others => '0'); + variable tmp2 : unsigned(mem_addr_base'range) := (others => '0'); + variable tmp3 : unsigned(mem_addr_base'range) := (others => '0'); begin -- DEFAULT mem_op_done <= '0'; @@ -2519,86 +2793,82 @@ begin mem_cnt_next <= mem_cnt; mem_seq_nr_next <= mem_seq_nr; orphan_entityid_next <= orphan_entityid; - mem_def_addr_next <= mem_def_addr; - mem_def_port_next <= mem_def_port; - mem_xflags_next <= mem_xflags; last_addr_next <= last_addr; mem_participant_data_next <= mem_participant_data; - is_heartbeat_res_next <= is_heartbeat_res; + is_heartbeat_res_next <= is_heartbeat_res; case (mem_stage) is when IDLE => mem_op_done <= '1'; reset_max_pointer_next <= '0'; - if (start_mem_op = '1') then + -- NOTE: Participant are stored in memory bottom up, while Endpoints top down. + + if (mem_op_start = '1') then case(mem_opcode) is when SEARCH_PARTICIPANT => + mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; + mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; mem_stage_next <= SEARCH_PARTICIPANT; - tmp := (others => '0'); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; + mem_cnt_next <= 0; when SEARCH_ENDPOINT => + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_stage_next <= SEARCH_ENDPOINT; - tmp := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, mem_addr_base'length); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; + mem_cnt_next <= 0; when REMOVE_PARTICIPANT => - mem_stage_next <= REMOVE_PARTICIPANT; mem_addr_next <= addr_res; + mem_stage_next <= REMOVE_PARTICIPANT; mem_cnt_next <= 0; when REMOVE_ENDPOINT => - mem_stage_next <= REMOVE_ENDPOINT; mem_addr_next <= addr_res; - when UPDATE_ENDPOINT => - mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= addr_res + 4; + mem_stage_next <= REMOVE_ENDPOINT; mem_cnt_next <= 0; + when UPDATE_ENDPOINT => + mem_addr_next <= addr_res + 4; endpoint_mask_array_next <= convert_to_bitmask_array(endpoint_mask); + mem_stage_next <= UPDATE_ENDPOINT; + mem_cnt_next <= 0; when INSERT_PARTICIPANT => + mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; + mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; mem_stage_next <= FIND_PARTICIPANT_SLOT; - tmp := (others => '0'); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; mem_cnt_next <= 0; when INSERT_ENDPOINT => + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_stage_next <= FIND_ENDPOINT_SLOT; - tmp := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, mem_addr_base'length); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; mem_cnt_next <= 0; when RESET_MAX_PARTICIPANT_POINTER => - mem_stage_next <= FIND_PARTICIPANT_SLOT; - tmp := (others => '0'); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; - mem_cnt_next <= 0; + mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; + mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; reset_max_pointer_next <= '1'; last_addr_next <= (others => '0'); - when RESET_MAX_ENDPOINT_POINTER => - mem_stage_next <= FIND_ENDPOINT_SLOT; - tmp := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, mem_addr_base'length); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; + mem_stage_next <= FIND_PARTICIPANT_SLOT; mem_cnt_next <= 0; + when RESET_MAX_ENDPOINT_POINTER => + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_addr_next <= FIRST_ENDPOINT_ADDRESS; reset_max_pointer_next <= '1'; - last_addr_next <= to_unsigned(BUILTIN_BUFFER_SIZE, mem_addr_base'length); + last_addr_next <= MAX_ADDRESS; + mem_stage_next <= FIND_ENDPOINT_SLOT; + mem_cnt_next <= 0; when FIND_STALE_PARTICIPANT => + mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; + mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; mem_stage_next <= FIND_STALE_PARTICIPANT; - tmp := (others => '0'); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; mem_cnt_next <= 0; when FIND_FIRST_PATICIPANT => + mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; + mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; mem_stage_next <= FIND_NEXT_PARTICIPANT; - tmp := (others => '0'); - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; mem_cnt_next <= 0; when FIND_NEXT_PARTICIPANT => + -- Next Participant Slot + tmp := addr_res + PARTICIPANT_FRAME_SIZE; + mem_addr_base_next <= tmp; + mem_addr_next <= tmp; mem_stage_next <= FIND_NEXT_PARTICIPANT; - mem_addr_base_next <= addr_res; - mem_addr_next <= addr_res; mem_cnt_next <= 0; when UPDATE_PARTICIPANT => mem_stage_next <= UPDATE_PARTICIPANT; @@ -2627,19 +2897,19 @@ begin end if; when SEARCH_PARTICIPANT => mem_rd <= '1'; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + -- Next Participant Frame Address - tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; + tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; case (mem_cnt) is when 0 => -- Preload -- Reached MAX Addr, No Match Found if (mem_addr_base = max_participant_addr) then - addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length); --No match + addr_res_next <= MAX_ADDRESS; --No match + -- DONE mem_stage_next <= IDLE; end if; when 1 => @@ -2672,111 +2942,113 @@ begin -- No preload needed mem_cnt_next <= 1; end if; + when others => + null; end case; when GET_PARTICIPANT_DATA => mem_rd <= '1'; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + case (mem_cnt) is + -- Memory Preload when 0 => - -- Memory Preload null; + -- Metatraffic IPv4 Address when 1 => - -- Metatraffic IPv4 Address mem_participant_data_next.meta_addr <= mem_read_data; + -- Default Endpoint IPv4 Address when 2 => - -- Default Endpoint IPv4 Address mem_participant_data_next.def_addr <= mem_read_data; + -- UDPv4 Ports when 3 => - -- UDPv4 Ports mem_participant_data_next.meta_port <= mem_read_data(31 downto 16); mem_participant_data_next.def_port <= mem_read_data(15 downto 0); + -- SPDP Sequence Number 1/2 when 4 => - -- SPDP Sequence Number 1/2 mem_participant_data_next.spdp_seq_nr(0) <= unsigned(mem_read_data); + -- SPDP Sequence Number 2/2 when 5 => - -- SPDP Sequence Number 2/2 mem_participant_data_next.spdp_seq_nr(1) <= unsigned(mem_read_data); + -- Lease Duration 1/2 when 6 => - -- Lease Duration 1/2 mem_participant_data_next.lease_duration(0) <= unsigned(mem_read_data); + -- Lease Duration 2/2 when 7 => - -- Lease Duration 2/2 mem_participant_data_next.lease_duration(1) <= unsigned(mem_read_data); + -- Lease Deadline 1/2 when 8 => - -- Lease Deadline 1/2 mem_participant_data_next.lease_deadline(0) <= unsigned(mem_read_data); + -- Lease Deadline 2/2 when 9 => - -- Lease Deadline 2/2 mem_participant_data_next.lease_deadline(1) <= unsigned(mem_read_data); + -- Extra Flags when 10 => - -- Extra Flags - mem_participant_data_next.extra_flags <= mem_read_data; + mem_participant_data_next.extra_flags <= mem_read_data(EXTRA_FLAGS_WIDTH-1 downto 0); + -- ACKNACK Response/Suppression Time 1/2 when 11 => - -- ACKNACK DEADLINE 1/2 mem_participant_data_next.acknack_res_time(0) <= unsigned(mem_read_data); + -- ACKNACK Response/Suppression Time 2/2 when 12 => - -- ACKNACK DEADLINE 2/2 mem_participant_data_next.acknack_res_time(1) <= unsigned(mem_read_data); + -- HEARTBEAT Response/Suppression Time 1/2 when 13 => - -- HEARTBEAT DEADLINE 1/2 mem_participant_data_next.heartbeat_res_time(0) <= unsigned(mem_read_data); + -- HEARTBEAT Response/Suppression Time 2/2 when 14 => - -- HEARTBEAT DEADLINE 2/2 mem_participant_data_next.heartbeat_res_time(1) <= unsigned(mem_read_data); + -- Publication Sequence Number 1/2 when 15 => - -- Publication Sequence Number 1/2 mem_participant_data_next.pub_seq_nr(0) <= unsigned(mem_read_data); + -- Publication Sequence Number 2/2 when 16 => - -- Publication Sequence Number 2/2 mem_participant_data_next.pub_seq_nr(1) <= unsigned(mem_read_data); + -- Subscription Sequence Number 1/2 when 17 => - -- Subscription Sequence Number 1/2 mem_participant_data_next.sub_seq_nr(0) <= unsigned(mem_read_data); + -- Subscription Sequence Number 2/2 when 18 => - -- Subscription Sequence Number 2/2 mem_participant_data_next.sub_seq_nr(1) <= unsigned(mem_read_data); + -- Participant Message Sequence Number 1/2 when 19 => - -- Participant Message Sequence Number 1/2 mem_participant_data_next.mes_seq_nr(0) <= unsigned(mem_read_data); + -- Participant Message Sequence Number 2/2 when 20 => - -- Participant Message Sequence Number 2/2 mem_participant_data_next.mes_seq_nr(1) <= unsigned(mem_read_data); -- DONE mem_stage_next <= IDLE; + when others => + null; end case; when SEARCH_ENDPOINT => mem_rd <= '1'; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + -- Next Endpoint Frame Address - tmp := mem_addr_base - ENDPOINT_FRAME_SIZE; + tmp := mem_addr_base - ENDPOINT_FRAME_SIZE; case (mem_cnt) is + -- Preload when 0 => -- Reached MAX Addr, No Match Found if (mem_addr_base = max_endpoint_addr) then - addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length);; -- No match + addr_res_next <= MAX_ADDRESS; -- No match + -- DONE mem_stage_next <= IDLE; end if; + -- NOTE: Endpoint GUID is stored with Entity ID first, and then the GUID Prefix + -- Entity ID when 1 => - -- If we search for orphan endpoint, ignore Entity id match and latch it for later use - if (is_orphan_search = '1') then - orphan_entityid_next <= mem_read_data; - else - -- No Match - -- NOTE: Endpoint GUID is stored with Entity ID first, and then the GUID Prefix - if (mem_read_data /= guid(3)) then - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base <= tmp; - mem_cnt_next <= 0; - end if; + -- No Match + -- Ignore Entity ID if Orphan Search + if (is_orphan_search = '0' and mem_read_data /= guid(3)) then + -- Continue Search + mem_addr_next <= tmp; + mem_addr_base <= tmp; + mem_cnt_next <= 0; end if; + -- GUID Prefix 1/3 when 2 => -- No Match if (mem_read_data /= guid(0)) then @@ -2785,6 +3057,7 @@ begin mem_addr_base <= tmp; mem_cnt_next <= 0; end if; + -- GUID Prefix 2/3 when 3 => -- No Match if (mem_read_data /= guid(1)) then @@ -2793,6 +3066,7 @@ begin mem_addr_base <= tmp; mem_cnt_next <= 0; end if; + -- GUID Prefix 3/3 when 4 => -- No Match if (mem_read_data /= guid(2)) then @@ -2805,52 +3079,58 @@ begin mem_stage_next <= GET_ENDPOINT_MASK; mem_cnt_next <= 0; end if; + when others => + null; end case; when GET_ENDPOINT_MASK => mem_rd <= '1'; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + -- Latch Endpoint Bitmask -- TODO: Use a different integer ranged in the smallest possible range? endpoint_mask_array_next(mem_cnt) <= mem_read_data; + -- Exit Condition if (mem_cnt = ENDPOINT_BITMASK_SIZE-1) then -- DONE mem_stage_next <= IDLE; end if; when REMOVE_PARTICIPANT => - -- Default Address Increment mem_addr_next <= mem_addr + 1; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Latch Participant GUID Prefix, and then overwrite with GUIDPREFIX_UNKNOWN to mark as empty + -- Latch Participant GUID Prefix, and then overwrite with GUIDPREFIX_UNKNOWN to mark slot empty case (mem_cnt) is + -- Preload when 0 => - -- Preload mem_rd <= '1'; + -- GUID Prefix 1/3 when 1 => mem_rd <= '1'; mem_guidprefix_next(0) <= mem_read_data; + -- GUID Prefix 2/3 when 2 => mem_rd <= '1'; mem_guidprefix_next(1) <= mem_read_data; + -- GUID Prefix 3/3 when 3 => mem_rd <= '1'; mem_guidprefix_next(2) <= mem_read_data; mem_addr_next <= addr_res; + -- GUID Prefix 1/3 when 4 => mem_wr <= '1'; mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(0); + -- GUID Prefix 2/3 when 5 => mem_wr <= '1'; mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(1); + -- GUID Prefix 3/3 when 6 => mem_wr <= '1'; mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(2); - -- DONE + -- Reset MAX Participant Pointer mem_stage_next <= RESET_MAX_PARTICIPANT_POINTER; when others => null; @@ -2858,17 +3138,19 @@ begin when REMOVE_ENDPOINT => mem_wr <= '1'; + -- Overtwrite EntityID with ENTITYID_UNKNOWN to mark slot as empty mem_write_data <= ENTITYID_UNKNOWN; - -- DONE + -- Reset MAX Participant Pointer mem_stage_next <= RESET_MAX_ENDPOINT_POINTER; when UPDATE_ENDPOINT => - mem_wr <= '1'; - -- Default Address Increment + mem_wr <= '1'; mem_addr_next <= mem_addr + 1; - -- Increment counter mem_cnt_next <= mem_cnt + 1; + -- TODO: Use dedicated counter + -- Store new Endpoint Bitmask mem_write_data <= endpoint_mask_array(mem_cnt); + -- Exit Condition if (mem_cnt = ENDPOINT_BITMASK_SIZE-1) then -- DONE @@ -2876,27 +3158,27 @@ begin end if; when FIND_PARTICIPANT_SLOT => mem_rd <= '1'; - -- Default Address Increment mem_addr_next <= mem_addr + 1; - -- Increment counter mem_cnt_next <= mem_cnt + 1; + -- Next Participant Frame Address - tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; + tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; case (mem_cnt) is + -- Preload when 0 => - -- Preload -- Reached MAX Addr if (mem_addr_base = max_participant_addr) then + -- We are in the middle of resetting the MAX Participant Pointer if (reset_max_pointer = '1') then - -- Reset "max_participant_addr" to first free slot after last occupied slot - if (last_addr /= (last_addr'reverse_range => '0')) then + -- Reset MAX Participant Pointer to first free slot after last occupied slot + if (last_addr /= 0) then max_participant_addr_next <= last_addr; end if; - -- DONE (reset pointer) + -- DONE mem_stage_next <= IDLE; -- MEMORY COLLISION - -- XXX: Posible worst case path (addition and comparison same clock) + -- XXX: Posible worst case path (addition and comparison on same clock) elsif (tmp > max_endpoint_addr) then -- Ignore Insertion mem_stage_next <= IDLE; @@ -2904,142 +3186,160 @@ begin -- Extend Participant Memory Area -- NOTE: "max_participant_addr" points to the first address after the last participant frame max_participant_addr_next <= tmp; - -- DONE + -- Populate Participant Slot mem_stage_next <= INSERT_PARTICIPANT; mem_cnt_next <= 0; end if; end if; + -- GUID Prefix 1/3 when 1 => + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(0)) then + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; + -- Reset Last Free Address last_addr_next <= (others => '0'); end if; + -- GUID Prefix 2/3 when 2 => + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(1)) then + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; + -- Reset Last Free Address last_addr_next <= (others => '0'); end if; + -- GUID Prefix 3/3 when 3 => + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(2)) then + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; + -- Reset Last Free Address last_addr_next <= (others => '0'); + -- Slot Empty else - -- If "reset_max_pointer" is set, go through all the participant memory area to reset the pointer + -- If we are in the middle of resetting the MAX Participant Pointer, go through all the Participant memory area to reset the pointer if (reset_max_pointer = '1') then - -- Max pointer reset logic - -- Store first free slot address after occupied slot - if (last_addr /= (last_addr'reverse_range => '0')) then + -- Store first Free Slot Address after occupied slot + if (last_addr = 0) then last_addr_next <= mem_addr_base; end if; else - -- Found Empty Slot, DONE + -- Populate Participant Slot mem_stage_next <= INSERT_PARTICIPANT; mem_cnt_next <= 0; end if; end if; + when others => + null; end case; when INSERT_PARTICIPANT => - mem_wr <= '1'; - -- Default Address Increment + mem_wr <= '1'; mem_addr_next <= mem_addr + 1; - -- Increment counter mem_cnt_next <= mem_cnt + 1; case (mem_cnt) is + -- GUIDPrefix 1/3 when 0 => - -- GUIDPrefix 1/3 mem_write_data <= guid(0); + -- GUIDPrefix 2/3 when 1 => - -- GUIDPrefix 2/3 mem_write_data <= guid(1); + -- GUIDPrefix 3/3 when 2 => - -- GUIDPrefix 3/3 mem_write_data <= guid(2); + -- Metatraffic IPv4 Address when 3 => - -- Metatraffic IPv4 Address mem_write_data <= addr_latch_2; + -- Default Endpoint IPv4 Address when 4 => - -- Default Endpoint IPv4 Address mem_write_data <= addr_latch_1; + -- UDPv4 Ports when 5 => - -- UDPv4 Ports mem_write_data <= port_latch_2 & port_latch_1; + -- SPDP Sequence Number 1/2 when 6 => - -- SPDP Sequence Number 1/2 mem_write_data <= std_logic_vector(seq_nr(0)); + -- SPDP Sequence Number 2/2 when 7 => - -- SPDP Sequence Number 2/2 mem_write_data <= std_logic_vector(seq_nr(1)); + -- Lease Duration 1/2 when 8 => - -- Lease Duration 1/2 mem_write_data <= std_logic_vector(lease_duration(0)); + -- Lease Duration 2/2 when 9 => - -- Lease Duration 2/2 mem_write_data <= std_logic_vector(lease_duration(1)); + -- Lease Deadline 1/2 when 10 => - -- Lease Deadline 1/2 mem_write_data <= std_logic_vector(lease_deadline(0)); + -- Lease Deadline 2/2 when 11 => - -- Lease Deadline 2/2 mem_write_data <= std_logic_vector(lease_deadline(1)); + -- Extra Flags when 12 => - -- Extra Flags - mem_write_data <= extra_flags; + mem_write_data <= (others => '0'); + mem_write_data(EXTRA_FLAGS_WIDTH-1 downto 0) <= extra_flags; + -- ACKNACK Response/Suppression Time 1/2 when 13 => - -- ACKNACK DEADLINE 1/2 mem_write_data <= (others => '0'); + -- ACKNACK Response/Suppression Time 2/2 when 14 => - -- ACKNACK DEADLINE 2/2 mem_write_data <= (others => '0'); + -- HEARTBEAT Response/Suppression Time 1/2 when 15 => - -- HEARTBEAT DEADLINE 1/2 mem_write_data <= (others => '0'); + -- HEARTBEAT Response/Suppression Time 2/2 when 16 => - -- HEARTBEAT DEADLINE 2/2 mem_write_data <= (others => '0'); + -- Publication Sequence Number 1/2 when 17 => - -- Publication Sequence Number 1/2 mem_write_data <= (others => '0'); + -- Publication Sequence Number 2/2 when 18 => - -- Publication Sequence Number 2/2 mem_write_data <= (others => '0'); + -- Subscription Sequence Number 1/2 when 19 => - -- Subscription Sequence Number 1/2 mem_write_data <= (others => '0'); + -- Subscription Sequence Number 2/2 when 20 => - -- Subscription Sequence Number 2/2 mem_write_data <= (others => '0'); + -- Participant Message Sequence Number 1/2 when 21 => - -- Participant Message Sequence Number 1/2 mem_write_data <= (others => '0'); + -- Participant Message Sequence Number 2/2 when 22 => - -- Participant Message Sequence Number 2/2 mem_write_data <= (others => '0'); + -- DONE + mem_stage_next <= IDLE; + when others => + null; end case; when FIND_ENDPOINT_SLOT => - mem_rd <= '1'; - -- Increment counter + mem_rd <= '1'; mem_cnt_next <= mem_cnt + 1; + -- Next Endpoint Frame Address - tmp := mem_addr_base - ENDPOINT_FRAME_SIZE; + tmp := mem_addr_base - ENDPOINT_FRAME_SIZE; case (mem_cnt) is + -- Preload when 0 => - -- Preload -- Exceeded MAX Addr if (mem_addr_base > max_endpoint_addr) then + -- We are in the middle of resetting the MAX Participant Pointer if (reset_max_pointer = '1') then - -- Reset "max_endpoint_addr" to last occupied slot + -- Reset MAX Endpoint Pointer to last occupied slot if (last_addr /= BUILTIN_BUFFER_SIZE) then max_endpoint_addr_next <= last_addr; end if; - -- DONE (reset pointer) + -- DONE mem_stage_next <= IDLE; -- MEMORY COLLISION elsif (mem_addr_base < max_participant_addr) then @@ -3049,361 +3349,404 @@ begin -- Extend Participant Memory Area -- NOTE: "max_endpoint_addr" points to the beginning of the last endpoint frame max_endpoint_addr <= mem_addr_base; - -- DONE - mem_stage_next <= INSERT_PARTICIPANT; + -- Populate Endpoint Slot + mem_stage_next <= INSERT_ENDPOINT; mem_cnt_next <= 0; end if; end if; + -- Entity ID when 1 => + -- Slot Occupied if (mem_read_data /= ENTITYID_UNKNOWN) then + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; -- Store last occupied endpoint slot last_addr_next <= mem_addr_base; + -- Slot Empty else - -- If "reset_max_pointer" is set, go through all the endpoint memory area to reset the pointer + -- If we are in the middle of resetting the MAX Participant Pointer, go through all the Endpoint memory area to reset the pointer if (reset_max_pointer = '0') then - -- Found Empty Slot, DONE + -- Populate Endpoint mem_stage_next <= INSERT_ENDPOINT; mem_cnt_next <= 0; end if; end if; + when others => + null; end case; when INSERT_ENDPOINT => - mem_wr <= '1'; - -- Default Address Increment + mem_wr <= '1'; mem_addr_next <= mem_addr + 1; - -- Increment counter mem_cnt_next <= mem_cnt + 1; case (mem_cnt) is + -- Entity ID when 0 => - -- Entity ID mem_write_data <= guid(3); + -- GUIDPrefix 1/3 when 1 => - -- GUIDPrefix 1/3 mem_write_data <= guid(0); + -- GUIDPrefix 2/3 when 2 => - -- GUIDPrefix 2/3 mem_write_data <= guid(1); + -- GUIDPrefix 3/3 when 3 => - -- GUIDPrefix 3/3 mem_write_data <= guid(2); - -- Write endpoint bitmask via update method + -- Write Endpoint bitmask via update method + endpoint_mask_array_next <= convert_to_bitmask_array(endpoint_mask); mem_stage_next <= UPDATE_ENDPOINT; mem_cnt_next <= 0; - endpoint_mask_array_next <= convert_to_bitmask_array(endpoint_mask); + when others => + null; end case; when FIND_NEXT_PARTICIPANT => mem_rd <= '1'; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + -- Next Participant Frame Address - tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; - tmp2 := mem_addr_base + 3; + tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; + -- Beginning of Participant Data + tmp2 := mem_addr_base + 3; case (mem_cnt) is + -- Preload when 0 => - -- Preload -- Reached MAX Addr, No Match Found if (mem_addr_base = max_participant_addr) then - addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length); --No match + addr_res_next <= MAX_ADDRESS; --No match + -- DONE mem_stage_next <= IDLE; end if; + -- GUID Prefix 1/3 when 1 => - -- If slot occupied, get participant data + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(0)) then + -- Get Participant Data mem_addr_next <= tmp2; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; addr_res_next <= mem_addr_base; + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; end if; when 2 => - -- If slot occupied, jump to stale check + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(1)) then + -- Get Participant Data mem_addr_next <= tmp2; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; addr_res_next <= mem_addr_base; + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; end if; when 3 => - -- If slot occupied, jump to stale check + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(2)) then + -- Get Participant Data mem_addr_next <= tmp2; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; addr_res_next <= mem_addr_base; - -- Slot empty, check next slot + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; + -- Slot Empty else + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; end if; + when others => + null; end case; when FIND_STALE_PARTICIPANT => mem_rd <= '1'; - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + -- Next Participant Frame Address tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE; - tmp2 := mem_addr_base + 11; + -- Beginning of Lease Deadline + tmp2 := mem_addr_base + 10; + -- Beginning of Participant Data tmp3 := mem_addr_base + 3; case (mem_cnt) is + -- Preload when 0 => - -- Preload -- Reached MAX Addr, No Match Found if (mem_addr_base = max_participant_addr) then - addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length); --No match + addr_res_next <= MAX_ADDRESS; --No match + -- DONE mem_stage_next <= IDLE; end if; + -- GUID Prefix 1/3 when 1 => - -- If slot occupied, jump to stale check + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(0)) then + -- Jumpt to Stale Check mem_addr_next <= tmp2; mem_cnt_next <= 4; end if; + -- GUID Prefix 2/3 when 2 => - -- If slot occupied, jump to stale check + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(1)) then + -- Jumpt to Stale Check mem_addr_next <= tmp2; mem_cnt_next <= 4; end if; + -- GUID Prefix 3/3 when 3 => - -- If slot occupied, jump to stale check + -- Slot Occupied if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(2)) then + -- Jumpt to Stale Check mem_addr_next <= tmp2; mem_cnt_next <= 4; - -- Slot empty, check next slot + -- Slot Empty else + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; end if; + -- Preload when 4 => - -- Preload null; + -- Lease Deadline 1/2 when 5 => - -- Lease Deadline passed, mark participant + -- Lease Deadline passed if (unsigned(mem_read_data) < time(0)) then + -- Mark Participant as stale addr_res_next <= mem_addr_base; - -- Mark that this is a stale participant mem_participant_data_next <= ZERO_PARTICIPANT_DATA; -- DONE mem_stage_next <= IDLE; end if; + -- Lease Deadline 2/2 when 6 => - -- Lease Deadline passed, mark participant + -- Lease Deadline passed if (unsigned(mem_read_data) < time(1)) then + -- Mark Participant as stale addr_res_next <= mem_addr_base; - -- Mark that this is a stale participant mem_participant_data_next <= ZERO_PARTICIPANT_DATA; -- DONE mem_stage_next <= IDLE; end if; + -- Extra Flags when 7 => - -- Heartbeat Deadline passed, mark participant - if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(0)) then - addr_res_next <= mem_addr_base; - -- Fetch Participant Data - mem_addr_next <= tmp3; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; - -- Mark as Heartbeat deadline miss - is_heartbeat_res_next <= '1'; - end if; + null; + -- ACKNACK Response/Suppression Time 1/2 when 8 => - -- Heartbeat Deadline passed, mark participant - if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(1)) then - addr_res_next <= mem_addr_base; - -- Fetch Participant Data - mem_addr_next <= tmp3; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; - -- Mark as Heartbeat deadline miss - is_heartbeat_res_next <= '1'; - end if; - when 9 => - -- Acknack Deadline passed, mark participant + -- Acknack Response/Suppression Time passed if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(0)) then - addr_res_next <= mem_addr_base; - -- Fetch Participant Data - mem_addr_next <= tmp3; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; - -- Mark as Acknack deadline miss - is_heartbeat_res_next <= '0'; + -- Mark Participant and get Participant Data + addr_res_next <= mem_addr_base; + mem_addr_next <= tmp3; + -- Mark as ACKNACK Trigger + is_heartbeat_res_next <= '0'; + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; end if; - when 10 => - -- Acknack Deadline passed, mark participant + -- ACKNACK Response/Suppression Time 2/2 + when 9 => + -- Acknack Response/Suppression Time passed if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(1)) then - addr_res_next <= mem_addr_base; - -- Fetch Participant Data - mem_addr_next <= tmp3; - mem_cnt_next <= 0; - mem_stage_next <= GET_PARTICIPANT_DATA; - -- Mark as Acknack deadline miss - is_heartbeat_res_next <= '0'; - -- No deadline expired, check next slot + -- Mark Participant and get Participant Data + addr_res_next <= mem_addr_base; + mem_addr_next <= tmp3; + -- Mark as ACKNACK Trigger + is_heartbeat_res_next <= '0'; + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; + end if; + -- HEARTBEAT Response/Suppression Time 1/2 + when 10 => + -- Heartbeat Response/Suppression Time passed + if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(0)) then + -- Mark Participant and get Participant Data + addr_res_next <= mem_addr_base; + mem_addr_next <= tmp3; + -- Mark as HEARTBEAT Trigger + is_heartbeat_res_next <= '1'; + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; + end if; + -- HEARTBEAT Response/Suppression Time 2/2 + when 11 => + -- Heartbeat Response/Suppression Time passed + if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(1)) then + -- Mark Participant and get Participant Data + addr_res_next <= mem_addr_base; + mem_addr_next <= tmp3; + -- Mark as HEARTBEAT Trigger + is_heartbeat_res_next <= '1'; + mem_stage_next <= GET_PARTICIPANT_DATA; + mem_cnt_next <= 0; + -- Participant not Stale else + -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; mem_cnt_next <= 0; end if; + when others => + null; end case; when UPDATE_PARTICIPANT => - -- Increment counter mem_cnt_next <= mem_cnt + 1; - -- Default Address Increment mem_addr_next <= mem_addr + 1; + case (mem_cnt) is + -- Metatraffic IPv4 Address when 0 => - -- Metatraffic IPv4 Address mem_write_data <= addr_latch_2; if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; + -- Default Endpoint IPv4 Address when 1 => - -- Default Endpoint IPv4 Address mem_write_data <= addr_latch_1; if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; + -- UDPv4 Ports when 2 => - -- UDPv4 Ports mem_write_data <= port_latch_2 & port_latch_1; if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; + -- SPDP Sequence Number 1/2 when 3 => - -- SPDP Sequence Number 1/2 mem_write_data <= std_logic_vector(seq_nr(0)); if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; + -- SPDP Sequence Number 2/2 when 4 => - -- SPDP Sequence Number 2/2 mem_write_data <= std_logic_vector(seq_nr(1)); if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; + -- Lease Duration 1/2 when 5 => - -- Lease Duration 1/2 mem_write_data <= std_logic_vector(lease_duration(0)); if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; + -- Lease Duration 2/2 when 6 => - -- Lease Duration 2/2 mem_write_data <= std_logic_vector(lease_duration(1)); if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; - -- If nothing else to update, skip + -- If nothing else to update if (update_participant_flags(5 downto 1) = (5 downto 1 => '0')) then + -- DONE mem_stage_next <= IDLE; end if; + -- Lease Deadline 1/2 when 7 => - -- Lease Deadline 1/2 mem_write_data <= std_logic_vector(lease_deadline(0)); if (update_participant_flags(LEASE_DEADLINE_FLAG) = '1') then mem_wr <= '1'; end if; + -- Lease Deadline 2/2 when 8 => - -- Lease Deadline 2/2 mem_write_data <= std_logic_vector(lease_deadline(1)); if (update_participant_flags(LEASE_DEADLINE_FLAG) = '1') then mem_wr <= '1'; end if; - -- If nothing else to update, skip + -- If nothing else to update if (update_participant_flags(5 downto 2) = (5 downto 2 => '0')) then + -- DONE mem_stage_next <= IDLE; end if; + -- Extra Flags when 9 => - -- Extra Flags - mem_write_data <= extra_flags; + mem_write_data <= (others => '0'); + mem_write_data(EXTRA_FLAGS_WIDTH-1 downto 0) <= extra_flags; if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then mem_wr <= '1'; end if; - -- If nothing else to update, skip + -- If nothing else to update if (update_participant_flags(5 downto 3) = (5 downto 3 => '0')) then + -- DONE mem_stage_next <= IDLE; end if; + -- ACKNACK DEADLINE 1/2 when 10 => - -- ACKNACK DEADLINE 1/2 mem_write_data <= std_logic_vector(acknack_res_time(0)); if (update_participant_flags(ACKNACK_RES_TIME_FLAG) = '1') then mem_wr <= '1'; end if; + -- ACKNACK DEADLINE 2/2 when 11 => - -- ACKNACK DEADLINE 2/2 mem_write_data <= std_logic_vector(acknack_res_time(1)); if (update_participant_flags(ACKNACK_RES_TIME_FLAG) = '1') then mem_wr <= '1'; end if; - -- If nothing else to update, skip + -- If nothing else to update if (update_participant_flags(5 downto 4) = (5 downto 4 => '0')) then + -- DONE mem_stage_next <= IDLE; end if; + -- HEARTBEAT DEADLINE 1/2 when 12 => - -- HEARTBEAT DEADLINE 1/2 mem_write_data <= std_logic_vector(heartbeat_res_time(0)); if (update_participant_flags(HEARTBEAT_RES_TIME_FLAG) = '1') then mem_wr <= '1'; end if; + -- HEARTBEAT DEADLINE 2/2 when 13 => - -- HEARTBEAT DEADLINE 2/2 mem_write_data <= std_logic_vector(heartbeat_res_time(1)); if (update_participant_flags(HEARTBEAT_RES_TIME_FLAG) = '1') then mem_wr <= '1'; end if; - -- If nothing else to update, skip + -- If nothing else to update if (update_participant_flags(5 downto 5) = (5 downto 5 => '0')) then + -- DONE mem_stage_next <= IDLE; end if; + -- Publication Sequence Number 1/2 when 14 => - -- Publication Sequence Number 1/2 mem_write_data <= std_logic_vector(seq_nr(0)); if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '0') then mem_wr <= '1'; end if; + -- Publication Sequence Number 2/2 when 15 => - -- Publication Sequence Number 2/2 mem_write_data <= std_logic_vector(seq_nr(1)); if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '0') then mem_wr <= '1'; end if; + -- Subscription Sequence Number 1/2 when 16 => - -- Subscription Sequence Number 1/2 mem_write_data <= std_logic_vector(seq_nr(0)); if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '1') then mem_wr <= '1'; end if; + -- Subscription Sequence Number 2/2 when 17 => - -- Subscription Sequence Number 2/2 mem_write_data <= std_logic_vector(seq_nr(1)); if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '1') then mem_wr <= '1'; end if; + -- Participant Message Sequence Number 1/2 when 18 => - -- Participant Message Sequence Number 1/2 mem_write_data <= std_logic_vector(seq_nr(0)); if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = MESSAGE) then mem_wr <= '1'; end if; + -- Participant Message Sequence Number 2/2 when 19 => - -- Participant Message Sequence Number 2/2 mem_write_data <= std_logic_vector(seq_nr(1)); if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = MESSAGE) then mem_wr <= '1'; end if; + -- DONE mem_stage_next <= IDLE; + when others => + null; end case; when others => null; diff --git a/src/rtps_package.vhd b/src/rtps_package.vhd index 2824a44..1c12934 100644 --- a/src/rtps_package.vhd +++ b/src/rtps_package.vhd @@ -95,6 +95,7 @@ package rtps_package is constant ENDPOINT_TYPE_STRING : ENDPOINT_STRING_TYPE := (0 => "Placeholder" & (12 to 256 => NUL)); constant ENDPOINT_TYPE : ENDPOINT_STRING_SLV_TYPE; -- Deferred to Package Body constant ENDPOINT_DURABILITY : QOS_TYPE := (0 => VOLATILE_DURABILITY_QOS); + -- TODO: Make sure GROUP is not selected constant ENDPOINT_PRESENTATION : QOS_TYPE := (0 => INSTANCE_PRESENTATION_QOS); constant ENDPOINT_COHERENT_ACCESS : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); constant ENDPOINT_ORDERED_ACCESS : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); @@ -114,11 +115,25 @@ package rtps_package is constant ENDPOINT_MAX_INSTANCES : QOS_SLV_TYPE := (0 => std_logic_vector(to_unsigned(0,32))); --TODO: Assert constant ENDPOINT_MAX_SAMP_PER_INST : QOS_SLV_TYPE := (0 => std_logic_vector(to_unsigned(0,32))); --TODO: Assert + constant ENDPOINT_HEARTBEAT_PERIOD : ENDPOINT_DURATION_TYPE := (0 => (to_unsigned(3,32),to_unsigned(0,32))); -- 3s + constant ENDPOINT_HEARTBEAT_RESPONSE_DELAY : ENDPOINT_DURATION_TYPE := (0 => (to_unsigned(0,32),to_unsigned(2147483648,32))); -- 500 ms + constant ENDPOINT_HEARTBEAT_SUPPRESSION_DELAY : ENDPOINT_DURATION_TYPE := (0 => (to_unsigned(0,32),to_unsigned(0,32))); + constant ENDPOINT_ACKNACK_RESPONSE_DELAY : ENDPOINT_DURATION_TYPE := (0 => (to_unsigned(0,32),to_unsigned(858993459,32))); -- 200 ms + constant ENDPOINT_ACKNACK_SUPPRESSION_DELAY : ENDPOINT_DURATION_TYPE := (0 => (to_unsigned(0,32),to_unsigned(0,32))); + + constant PARTICIPANT_HEARTBEAT_PERIOD : DURATION_TYPE := (to_unsigned(3,32),to_unsigned(0,32)); -- 3s + constant PARTICIPANT_HEARTBEAT_RESPONSE_DELAY : DURATION_TYPE := (to_unsigned(0,32),to_unsigned(2147483648,32)); -- 500 ms + constant PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY : DURATION_TYPE := (to_unsigned(0,32),to_unsigned(0,32)); + constant PARTICIPANT_ACKNACK_RESPONSE_DELAY : DURATION_TYPE := (to_unsigned(0,32),to_unsigned(858993459,32)); -- 200 ms + constant PARTICIPANT_ACKNACK_SUPPRESSION_DELAY : DURATION_TYPE := (to_unsigned(0,32),to_unsigned(0,32)); + + constant DURATION_DELTA : DURATION_TYPE := (to_unsigned(0,32),to_unsigned(429496730,32)); --100 ms + constant DEFAULT_PARTICIPANT_LEASE_DURATION : DOUBLE_WORD_ARRAY := (to_unsigned(100,32),to_unsigned(0,32); constant PARTICIPANT_LEASE_DURATION : DOUBLE_WORD_ARRAY := DEFAULT_PARTICIPANT_LEASE_DURATION; -- NOTE: The buffer will not only store participants, but also endpoint data - -- Used to determine the size of the built-inendpoint buffer + -- Used to determine the size of the builtin endpoint buffer constant MAX_REMOTE_PARTICIPANTS : natural := 50; --*****DDSI-RTPS 2.3***** @@ -358,11 +373,23 @@ package rtps_package is function convert_from_double_word (seq: DOUBLE_WORD_ARRAY) return unsigned; function convert_to_double_word (seq: unsigned(63 downto 0)) return DOUBLE_WORD_ARRAY; function ">" (L,R: DOUBLE_WORD_ARRAY) return boolean; + function ">" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean; + function ">" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean; function "<" (L,R: DOUBLE_WORD_ARRAY) return boolean; + function "<" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean; + function "<" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean; function ">=" (L,R: DOUBLE_WORD_ARRAY) return boolean; + function ">=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean; + function ">=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean; function "<=" (L,R: DOUBLE_WORD_ARRAY) return boolean; + function "<=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean; + function "<=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean; function "=" (L,R: DOUBLE_WORD_ARRAY) return boolean; + function "=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean; + function "=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean; function "/=" (L,R: DOUBLE_WORD_ARRAY) return boolean; + function "/=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean; + function "/=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean; function "+" (L,R: DOUBLE_WORD_ARRAY) return DOUBLE_WORD_ARRAY; function "+" (L: DOUBLE_WORD_ARRAY, R: natural) return DOUBLE_WORD_ARRAY; function "+" (L: natural, R: DOUBLE_WORD_ARRAY) return DOUBLE_WORD_ARRAY; @@ -431,7 +458,7 @@ package body rtps_package is 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)), 8)) & std_logic_vector(to_unsigned(character'POS(str(i+1)), 8)) & std_logic_vector(to_unsigned(character'POS(str(i+2)), 8)) & std_logic_vector(to_unsigned(character'POS(str(i+3)), 8)); + ret(i) := std_logic_vector(to_unsigned(character'POS(str(i*4)), 8)) & 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)); end loop; return ret; end function; @@ -960,31 +987,91 @@ package body rtps_package is return convert_from_double_word(L) > convert_from_double_word(R); end function; + function ">" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean is + begin + return convert_from_double_word(L) > R; + end function; + + function ">" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean is + begin + return L > convert_from_double_word(R); + end function; + function "<" (L,R: DOUBLE_WORD_ARRAY) return boolean is begin return convert_from_double_word(L) < convert_from_double_word(R); end function; + function "<" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean is + begin + return convert_from_double_word(L) < R; + end function; + + function "<" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean is + begin + return L < convert_from_double_word(R); + end function; + function ">=" (L,R: DOUBLE_WORD_ARRAY) return boolean is begin return convert_from_double_word(L) >= convert_from_double_word(R); end function; + function ">=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean is + begin + return convert_from_double_word(L) >= R; + end function; + + function ">=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean is + begin + return L >= convert_from_double_word(R); + end function; + function "<=" (L,R: DOUBLE_WORD_ARRAY) return boolean is begin return convert_from_double_word(L) <= convert_from_double_word(R); end function; + function "<=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean is + begin + return convert_from_double_word(L) <= R; + end function; + + function "<=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean is + begin + return L <= convert_from_double_word(R); + end function; + function "=" (L,R: DOUBLE_WORD_ARRAY) return boolean; begin return convert_from_double_word(L) = convert_from_double_word(R); end function; + function "=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean is + begin + return convert_from_double_word(L) = R; + end function; + + function "=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean is + begin + return L = convert_from_double_word(R); + end function; + function "/=" (L,R: DOUBLE_WORD_ARRAY) return boolean is begin return convert_from_double_word(L) /= convert_from_double_word(R); end function; + function "/=" (L: DOUBLE_WORD_ARRAY, R: natural) return boolean is + begin + return convert_from_double_word(L) /= R; + end function; + + function "/=" (L: natural, R: DOUBLE_WORD_ARRAY) return boolean is + begin + return L /= convert_from_double_word(R); + end function; + function "+" (L,R: DOUBLE_WORD_ARRAY) return DOUBLE_WORD_ARRAY is begin return convert_to_double_word(convert_from_double_word(L) + convert_from_double_word(R));