From 63c8c8dccc5d4d85cb98b5aba46423c091f80674 Mon Sep 17 00:00:00 2001 From: Greek Date: Sun, 25 Oct 2020 19:42:51 +0100 Subject: [PATCH] * Restructure, cleaning and final documentation in builtin_endpoint --- VHDL-2008.txt | 5 + src/math_pkg.vhd | 2 + src/rtps_builtin_endpoint.vhd | 2498 +++++++++++++++++++-------------- src/rtps_package.vhd | 2 +- src/test.vhd | 32 +- syn/DE10-Nano/top.qsf | 1 + 6 files changed, 1454 insertions(+), 1086 deletions(-) create mode 100644 VHDL-2008.txt diff --git a/VHDL-2008.txt b/VHDL-2008.txt new file mode 100644 index 0000000..e289d24 --- /dev/null +++ b/VHDL-2008.txt @@ -0,0 +1,5 @@ +Quartus 18.1 Unsupported +======================== +* Unconstrained arrays in records (Supported in Pro) +* Vectors in aggregate statements + e.g. V := ("0000", others => '1'); diff --git a/src/math_pkg.vhd b/src/math_pkg.vhd index 434a8b7..fed84f2 100644 --- a/src/math_pkg.vhd +++ b/src/math_pkg.vhd @@ -8,6 +8,8 @@ package math_pkg is function max(constant value1, value2, value3 : in integer) return integer; -- returns the minimum of the two operands function min(constant value1, value2 : in integer) return integer; + + function round_div(constant divident, divisor : in integer) return integer; end package; diff --git a/src/rtps_builtin_endpoint.vhd b/src/rtps_builtin_endpoint.vhd index 1da6921..04151bb 100644 --- a/src/rtps_builtin_endpoint.vhd +++ b/src/rtps_builtin_endpoint.vhd @@ -6,7 +6,7 @@ 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 +-- TODO: add_res is still valid after removal. So we could continue searching the next orphan endpoint from that address on entity rtps_builtin_endpoint is port ( @@ -31,6 +31,9 @@ end entity; architecture arch of rtps_builtin_endpoint is --*****COMPONENT DECLARATION****** + -- The RAM is used for storing remote Participant and Endpoint Data. + -- Participant Data is stored from low to high and Endpoint Data is stored from high to low. + -- The RAM should have a READ and WRITE latency of 1 clock cycle. component single_port_ram is generic ( ADDR_WIDTH : natural := 8; @@ -48,15 +51,58 @@ architecture arch of rtps_builtin_endpoint is ); end component; + --*****CONSTANT DECLARATION***** + -- Width of extra_flags signal 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 MEM_OPCODE_TYPE is (NOP, SEARCH_PARTICIPANT, SEARCH_ENDPOINT); - type MESSAGE_TYPE_TYPE is (PDP, EDP, MESSAGE, NONE); + type STAGE_TYPE is (IDLE, PACKET_HEADER, PACKET_SRC_ADDR, PACKET_SRC_ENTITYID, PACKET_SRC_GUIDPREFIX, PACKET_DEST_ENTITYID, + CHECK_SRC_ENTITYID, LATCH_SEQ_NR, PROCESS_DATA, PROCESS_MESSAGE, PROCESS_GAP, PROCESS_GAP_SEQUENCE_NUMBERS, PROCESS_PL, + LATCH_STRING_LENGTH, COMPARE_STRING, RXO_DURABILITY, RXO_DEADLINE, RXO_LIVELINESS, RXO_LEASE_DURATION, LATCH_LEASE_DURATION, + RXO_RELIABILITY, RXO_DESTINATION_ORDER, RXO_OWNERSHIP, RXO_PRESENTATION, RXO_PARTITION, MATCH_DOMAIN_ID, MATCH_PROTOCOL_VERSION, + LATCH_LOCATOR, LATCH_EXPECTS_INLINE_QOS, LATCH_GUID, CHECK_REMOTE_BUILTIN_ENDPOINTS, PARTICIPANT_MATCH_STAGE, + INITIATE_ENDPOINT_SEARCH, ENDPOINT_MATCH_STAGE, FIND_ORPHAN_ENDPOINT, PURGE_ORPHAN_ENDPOINT, INFORM_ENDPOINTS_MATCH, + INFORM_ENDPOINTS_UNMATCH, STALE_CHECK, LATCH_REMOVED_GUIDPREFIX, PROCESS_HEARTBEAT, PROCESS_HEARTBEAT_SEQUENCE_NUMBERS, + SEND_ACKNACK, SEND_HEARTBEAT, PROCESS_ACKNACK, PROCESS_ACKNACK_SEQUENCE_NUMBERS, FIND_PARTICIPANT_DEST, SEND_HEADER, + SEND_PARTICIPANT_ANNOUNCEMENT, SEND_PUB_DATA, SEND_SUB_DATA, SEND_MES_MAN_LIVE, SEND_MES_GAP, SEND_MES_AUTO_LIVE, + LIVELINESS_UPDATE, SKIP_PARAMETER, SKIP_PACKET); + -- Memory FSM states. Explained below in detail + type MEM_STAGE_TYPE is (IDLE, SEARCH_PARTICIPANT, GET_PARTICIPANT_DATA, SEARCH_ENDPOINT, GET_ENDPOINT_MASK, REMOVE_PARTICIPANT, + REMOVE_ENDPOINT, UPDATE_ENDPOINT, FIND_PARTICIPANT_SLOT, INSERT_PARTICIPANT, FIND_ENDPOINT_SLOT, INSERT_ENDPOINT, + FIND_NEXT_PARTICIPANT, FIND_STALE_PARTICIPANT, UPDATE_PARTICIPANT); + -- Memory FSM Opcodes + -- OPCODE DESCRIPTION + -- SEARCH_PARTICIPANT Search memory for Participant Entry with GUID Prefix equal to "guid" signal. + -- Set "addr_res" signal to Base Address of found Participant Entry or MAX Address if nothing found. + -- "mem_participant_data" contains memory Participant Data. + -- SEARCH_ENDPOINT Search memory for Endpoint Entry with GUID equal to "guid" signal. + -- Set "add_res" signal to Base Address of found Endpoint Entry or MAX Address if nothing found. + -- "endpoint_mask_array" contains memory Endpoint Data. + -- INSERT_PARTICIPANT Write Participant Data (contained in latches) to first empty Participant Slot. + -- MAX Participant Pointer follows the highest Address Participant Entry. On collision with Endpoint memory area, insert is ignored. + -- INSERT_ENDPOINT Write Endpoint Data (contained in latches) to the first empty Endpoint Entry. + -- MAX Endpoint Pointer follows the lowest Address Endpoint Entry. On collision with Participant memory area, insert is ignored. + -- UPDATE_PARTICIPANT Update the Participant Data of the Participant Entry pointed in "addr_res" according to the "update_participant_flags" flags. + -- UPDATE_ENDPOINT Update the Endpoint Data of the Endpoint Entry pointed in "addr_res". + -- REMOVE_PARTICIPANT Remove the Participant Entry pointed in "addr_res". (MAX Participant Pointer is adjusted) + -- REMOVE_ENDPOINT Remove the Endpoint Entry pointed in "addr_res". (MAX Endpoint Pointer is adjusted) + -- FIND_STALE_PARTICIPANT Find first Participant Entry with expired times (Lease Deadline, HEARTBEAT/ACKNACK Response/Suppression Timeout). + -- Set "addr_res" signal to Base Address of found Participant Entry or MAX Address if nothing found. + -- FIND_FIRST_PATICIPANT Find first occupied Participant Entry in memory. + -- Set "addr_res" signal to Base Address of found Participant Entry or MAX Address if nothing found. + -- FIND_NEXT_PARTICIPANT Find next occupied Participant Entry in memory from the Participant Entry pointed by "addr_res". + -- Set "addr_res" signal to Base Address of found Participant Entry or MAX Address if nothing found. + type MEM_OPCODE_TYPE is (NOP, SEARCH_PARTICIPANT, SEARCH_ENDPOINT, INSERT_PARTICIPANT, INSERT_ENDPOINT, UPDATE_PARTICIPANT, + UPDATE_ENDPOINT, REMOVE_PARTICIPANT, REMOVE_ENDPOINT, FIND_STALE_PARTICIPANT, FIND_FIRST_PATICIPANT, FIND_NEXT_PARTICIPANT); + -- RTPS Data Submessage Content: + -- * PDP Simple Participant Discovery Protocol Data + -- * EDP Simple Endpoint Discovery Protocol Data + -- * MESSAGE Participant Message Data + type MESSAGE_TYPE_TYPE is (NONE, PDP, EDP, MESSAGE); + -- String Content type STRING_CONTENT_TYPE is (TOPIC_NAME, TYPE_NAME, DOMAIN_TAG); + -- Record of all Participant Data stored in memory type PARTICIPANT_DATA_TYPE is record meta_addr : std_logic_vector(31 downto 0); def_addr : std_logic_vector(31 downto 0); @@ -74,25 +120,45 @@ architecture arch of rtps_builtin_endpoint is end record; --*****CONSTANT DECLARATION***** - constant BUILTIN_BUFFER_SIZE : natural := MAX_REMOTE_PARTICIPANTS*PARTICIPANT_FRAME_SIZE; + -- Memory Size in Bytes + constant BUILTIN_BUFFER_SIZE : natural := MAX_REMOTE_PARTICIPANTS*PARTICIPANT_FRAME_SIZE*4; + -- Memory Address Width constant BUILTIN_BUFFER_ADDR_WIDTH : natural := log2c(BUILTIN_BUFFER_SIZE); + -- Highest Memory Address constant MAX_ADDRESS : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := to_unsigned(BUILTIN_BUFFER_SIZE, BUILTIN_BUFFER_ADDR_WIDTH); + -- Address pointing to the beginning of the first Participant Data Frame constant FIRST_PARTICIPANT_ADDRESS : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Address pointing to the beginning of the first Endpoint Data Frame constant FIRST_ENDPOINT_ADDRESS : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, BUILTIN_BUFFER_ADDR_WIDTH); + -- *UPDATE PARTICIPANT FLAG POSITIONS* + -- Signifies that the main Participant Data are updated constant PARTICIPANT_DATA_FLAG : natural := 0; + -- Signifies that the Lease Deadline of the Participant Data is updated constant LEASE_DEADLINE_FLAG : natural := 1; + -- Signifies that the Extra Flags of the Participant Data are updated constant EXTRA_FLAGS_FLAG : natural := 2; + -- Signifies that the ACKNACK Timeout Time of the Participant Data is updated constant ACKNACK_RES_TIME_FLAG : natural := 3; + -- Signifies that the HEARTBEAT Timeout Time of the Participant Data is updated constant HEARTBEAT_RES_TIME_FLAG : natural := 4; + -- Signifies that the remote Endpoint (Publisher/Subscriber/Message) Sequence Number of the Participant Data is updated constant EDP_SEQ_NR_FLAG : natural := 5; - -- Extra Flags Positions + -- *EXTRA FLAG POSITIONS* + -- Signifies that the Publisher Data should be sent constant PUB_DATA_FLAG : natural := 3; + -- Signifies that the Subscriber Data should be sent constant SUB_DATA_FLAG : natural := 2; + -- Signifies that the Message Data (Liveliness) should be sent constant MES_DATA_FLAG : natural := 1; + -- Signifies if the Reader Endpoint expects in-line QoS constant EXPECTS_INLINE_QOS_FLAG : natural := 0; + -- Highest Sequence Number of Publisher Data constant PUB_SEQUENCE_NR : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(NUM_WRITERS, 64)); + -- Highest Sequence Number of Subscriber Data constant SUB_SEQUENCE_NR : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(NUM_READERS, 64)); + -- Constant for Sequence Number 1 constant SEQUENCE_NR_START : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(1, 64)); + -- Constant for zero Participant Data constant ZERO_PARTICIPANT_DATA : PARTICIPANT_DATA_TYPE := ( meta_addr => (others => '0'), def_addr => (others => '0'), @@ -113,120 +179,185 @@ architecture arch of rtps_builtin_endpoint is --*****SIGNAL DECLARATION***** -- FSM state signal stage, stage_next : STAGE_TYPE := IDLE; + -- FSM state latch. Used to transition dynamically to different states from the same state. signal return_stage, return_stage_next : STAGE_TYPE := IDLE; - signal mem_stage, mem_stage_next : MEM_STAGE_TYPE := TODO; + -- Memory FSM State + signal mem_stage, mem_stage_next : MEM_STAGE_TYPE := IDLE; -- Intermediate input read signal. (Read from output port not allowed) signal rd_sig : std_logic := '0'; -- Signal used to reset the word counter signal reset_read_cnt : std_logic; - -- 32-bit Word counter (Counts words read from input fifo) + -- Word (32-bit) counter (Counts words read from input fifo) signal read_cnt : unsigned(13 downto 0) := (others => '0'); - signal opcode, opcode_next : std_logic_vector(7 downto 0) := (others => '0'); + -- RTPS Submessage ID Latch + signal opcode, opcode_next : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := (others => '0'); + -- RTPS Submessage Flags Latch signal flags, flags_next : std_logic_vector(7 downto 0) := (others => '0'); + -- UDPv4 Source Port Latch signal src_port, src_port_next : std_logic_vector(15 downto 0) := (others => '0'); + -- IPv4 Source Address Latch signal src_addr, src_addr_next : std_logic_vector(31 downto 0) := (others => '0'); - -- TODO: Initialise metatraffic with default locator, since it may not be in the message (Take src Locator?) - -- TODO: Default locator should always be in the message - signal addr_latch_1, addr_latch_1_next, addr_latch_2, addr_latch_2_next : std_logic_vector(31 downto 0) := (others => '0'); - signal port_latch_1, port_latch_1_next, port_latch_2, port_latch_2_next : std_logic_vector(15 downto 0) := (others => '0'); + -- Source Entity ID Latch signal src_entityid, src_entityid_next : std_logic_vector(31 downto 0) := (others => '0'); + -- Destination Entity ID Latch signal dest_entityid, dest_entityid_next : std_logic_vector(31 downto 0) := (others => '0'); - signal parameter_end, parameter_end_next : unsigned(13 downto 0) := (others => '0'); - signal message_type, message_type_next : MESSAGE_TYPE_TYPE := PDP; - 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(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'); - signal endpoint_mask_array, endpoint_mask_array_next : ENDPOINT_BITMASK_ARRAY_TYPE := (others => (others => '0')); - signal participant_match, participant_match_next : std_logic := '0'; - 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 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_set, expects_inline_qos_set_next : std_logic := '0'; + -- Source GUID Latch signal guid, guid_next : GUID_ARRAY_TYPE := (others => (others => '0')); - signal mem_op_start, mem_op_done : std_logic := '0'; - signal mem_opcode : MEM_OPCODE_TYPE := NOP; - 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 : std_logic := '0'; - -- TODO: Re-check range - signal mem_cnt, mem_cnt_next : natural range 0 to 3 := 0; + -- RTPS DATA Submessage Sequence Number Latch signal seq_nr, seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Word aligned End of Parameter + signal parameter_end, parameter_end_next : unsigned(15 downto 0) := (others => '0'); + -- RTPS DATA Submessage Content Type + signal message_type, message_type_next : MESSAGE_TYPE_TYPE := NONE; + -- Data in represented in Big Endian + signal data_in_swapped : std_logic_vector(31 downto 0) := (others => '0'); + -- Byte Length of string + signal string_length, string_length_next : unsigned(31 downto 0) := (others => '0'); + -- Counter of compared string words (32-bit) + signal compare_length, compare_length_next : unsigned(29 downto 0) := (others => '0'); + -- Bitmask of local Endpoint Matches + signal endpoint_mask, endpoint_mask_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); + -- Bitmask of new local Endpoint Matches + signal endpoint_match, endpoint_match_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); + -- Bitmask of local Endpoint unmatches + signal endpoint_unmatch, endpoint_unmatch_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); + -- Bitmask of local Endpoint Matches stored in Memory + signal endpoint_mask_array, endpoint_mask_array_next : ENDPOINT_BITMASK_ARRAY_TYPE := (others => (others => '0')); + -- Signifies if the source of the Participant Data is compatible with our Participant + signal participant_match, participant_match_next : std_logic := '0'; + -- Signifies if the Packet is comming from a Subscriber Endpoint + signal is_subscriber, is_subscriber_next : std_logic := '0'; + -- Signal storing times for memory operations (Participant Lease Deadline, HEARTBEAT/ACKNACK Response/Suppression Time) + signal deadline, deadline_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Signifies that the read Locator is a Metatraffic Locator + signal is_meta_addr, is_meta_addr_next : std_logic := '0'; + -- General Purpose counter + signal cnt, cnt_next : natural range 0 to 23 := 0; + -- NOTE: In order to avoid synthesizing indexing for the full range of the OUTPUT_DATA_TYPE, we explicitly use counters constrained to the actual size + -- Counter used to index the Participant Data + signal participant_data_cnt, participant_data_cnt_next : natural range 0 to PARTICIPANT_DATA.length-1 := 0; + -- Counter used to index the Publisher Data + signal publisher_data_cnt, publisher_data_cnt_next : natural range 0 to WRITER_ENDPOINT_DATA.length-1 := 0; + -- Counter used to index the Subscriber Data + signal subscriber_data_cnt, subscriber_data_cnt_next : natural range 0 to READER_ENDPOINT_DATA.length-1 := 0; + -- Signals the start of a Memory Operation (Should be pulled high only when mem_op_done is high) + signal mem_op_start : std_logic := '0'; + -- Signals the end of a Memory Operation + signal mem_op_done : std_logic := '0'; + -- Opcode of the Memory Operation (Valid only when mem_op_start is high) + signal mem_opcode : MEM_OPCODE_TYPE := NOP; + -- Current Memory Address + signal mem_addr, mem_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Base Memory Address of current Participant/Endpoint Frame + signal mem_addr_base, mem_addr_base_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Result Base Memory Address of Memory Operation + signal addr_res, addr_res_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Help signal used to reset the MAX Participant/Endpoint Memory Pointers + signal last_addr, last_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Highest Participant Memory Address (Points to first Word after last occupied Participant Frame) + signal max_participant_addr, max_participant_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Lowest Endpoint Memory Address (Points to first Word of last occupied Endpoint Frame) + signal max_endpoint_addr, max_endpoint_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Memory Data Read and Write Signals + signal mem_read_data, mem_write_data : std_logic_vector(31 downto 0) := (others => '0'); + -- Memory Read and Write Enable Signals + signal mem_rd, mem_wr : std_logic := '0'; + -- General Purpose Counter (Memory FSM) + signal mem_cnt, mem_cnt_next : natural range 0 to max(22, ENDPOINT_BITMASK_SIZE-1) := 0; + -- Contains the Sequence Number stored in the Buffer of the current relevant Message Type (Participant/Publisher/Subscriber/Message Data) signal mem_seq_nr, mem_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Signifies the next expected Sequence Number of the current relevant Message Type (Participant/Publisher/Subscriber/Message Data) signal next_seq_nr, next_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Latch used to store the first Sequence Number in ACKNACK/HEARTBEAT/GAP Messages signal first_seq_nr, first_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Latch used to store the last Sequence Number in HEARTBEAT/GAP Messages signal last_seq_nr, last_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Signifies if we currently do a Orphan Endpoint Search (Endpoint whose parent Participant was removed) signal is_orphan_search, is_orphan_search_next : std_logic := '0'; - signal orphan_entityid, orphan_entityid_next : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (others => '0'); + -- Intermediate Output Signal signal output_sig : std_logic_vector(31 downto 0) := (others => '0'); + -- Signifies if we currently are resetting the MAX Participant/Endpoint Pointer signal reset_max_pointer, reset_max_pointer_next : std_logic := '0'; + -- Signifies if we currently are doing a Participant Stale Entry Check (Used to start Stale Checks between packet handling) signal stale_check, stale_check_next : std_logic := '0'; + -- Latch containing the GUID Prefix of the removed Participant from the memory signal mem_guidprefix, mem_guidprefix_next : GUIDPREFIX_ARRAY_TYPE : (others => (others => '0')); + -- Toggle latching the "last_word_in" signal until reset signal last_word_in_latch, last_word_in_latch_next : std_logic := '0'; + -- Flags signifying which parts of the participant Data stored in memory to update signal update_participant_flags, update_participant_flags_next : std_logic_vector(5 downto 0) := (others => '0'); + -- Latch for the Participant Data stored in memory signal mem_participant_data, mem_participant_data_next : PARTICIPANT_DATA_TYPE := ZERO_PARTICIPANT_DATA; + -- Signifies if the marked Stale Participant had a Hertbeat Response/Suppression Delay Timeout signal is_heartbeat_res, is_heartbeat_res_next : std_logic := '0'; + -- Signifies when "mem_seq_nr" and "next_seq_nr" signals are valid signal seq_prc_done, seq_prc_done_next : std_logic := '0'; + -- Signal containing the HEARTBEAT/ACKNACK count of all built-in Endpoints signal count, count_next : unsigned(31 downto 0) := (others => '0'); + -- Toggle set when at least one Endpoint has asserted the "alive" signal, until reset signal endpoint_alive : std_logic := '0'; + -- Resets the "endpoint_alive" signal signal reset_endpoint_alive : std_logic := '0'; + -- NOTE: The "auto_live_seq_nr" is always higher than "man_live_seq_nr" + -- Contains the highest Sequence Number for automatic liveliness updates -- TODO: Make sure sequences are initialized correctly signal auto_live_seq_nr, auto_live_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Contains the highest Sequence Number for manual by participant liveliness updates signal man_live_seq_nr, man_live_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Points to the first Sequence Number after "man_live_seq_nr" (Signifies the start of the GAP between "man_live_seq_nr" and "auto_live_seq_nr") signal live_gap_start, live_gap_start_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Points to the first Sequence Number before "auto_live_seq_nr" (Signifies the end of the GAP between "man_live_seq_nr" and "auto_live_seq_nr") signal live_gap_end, live_gap_end_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); - signal extra_flags, extra_flags_next : std_logic_vector(EXTRA_FLAGS_WIDTH-1 downto 0) := (others => '0'); + -- Participant Announcement Timeout Time signal announcement_time, announcement_time_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Heartbeat/Liveliness Assertion Timeout Time signal heartbeat_time, heartbeat_time_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Signifies if we are currently in a Liveliness Assertion signal is_live_assert, is_live_assert_next : std_logic := '0'; + -- Signifies the content of the string read from input signal string_content, string_content_next : STRING_CONTENT_TYPE := TOPIC_NAME; + -- Signifies that the expects_inline_qos Flag was explicitly set via a Parameter ID + signal expects_inline_qos_set, expects_inline_qos_set_next : std_logic := '0'; + -- Endpoint Locator IPv4 Address Latch + signal def_addr, def_addr_next : std_logic_vector(31 downto 0) := (others => '0'); + -- Metatraffic Locator IPv4 Address Latch + signal meta_addr, meta_addr_next : std_logic_vector(31 downto 0) := (others => '0'); + -- Endpoint UDPv4 Port Latch + signal def_port, def_port_next : std_logic_vector(15 downto 0) := (others => '0'); + -- Metatraffic UDPv4 Port Latch + signal meta_port, meta_port_next : std_logic_vector(15 downto 0) := (others => '0'); + -- Participant Lease Duration Latch + signal lease_duration, lease_duration_next : DOUBLE_WORD_ARRAY := (others => (others => '0')); + -- Extra Flags Latch + signal extra_flags, extra_flags_next : std_logic_vector(EXTRA_FLAGS_WIDTH-1 downto 0) := (others => '0'); --*****ALIAS DEFINATION***** + -- ENDPOINT FRAME HEADER alias header_opcode : std_logic_vector(7 downto 0) is data_in(31 downto 24); alias header_flags : std_logic_vector(7 downto 0) is data_in(23 downto 16); alias header_udp_port : std_logic_vector(15 downto 0) is data_in(15 downto 0); + -- RTPS PARAMETER LIST HEADER alias parameter_id : std_logic_vector(15 downto 0) is data_in(31 downto 16); alias parameter_length : std_logic_vector(15 downto 0) is data_in(15 downto 0); + alias must_undersand : std_logic is parameter_id(14); + -- RTPS DATA PAYLOAD HEADER alias representation_id : std_logic_vector(15 downto 0) is data_in(31 downto 16); alias representation_options : std_logic_vector(15 downto 0) is data_in(15 downto 0); -- RTPS SUBMESSAGE FLAGS - alias endian_flag : std_logic is flags(0); - alias endian_flag_next : std_logic is flags_next(0); - alias qos_flag : std_logic is flags(1); - alias qos_flag_next : std_logic is flags_next(1); - alias data_flag : std_logic is flags(2); - alias key_flag : std_logic is flags(3); - alias final_flag : std_logic is flags(1); - alias payload_flag : std_logic is header_flags(4); - alias must_undersand : std_logic is parameter_id(14); + alias endian_flag : std_logic is flags(0); + alias endian_flag_next : std_logic is flags_next(0); + alias qos_flag : std_logic is flags(1); + alias qos_flag_next : std_logic is flags_next(1); + alias data_flag : std_logic is flags(2); + alias key_flag : std_logic is flags(3); + alias final_flag : std_logic is flags(1); + alias payload_flag : std_logic is flags(4); --*****FUNCTION DECLARATION***** - -- Truncates the lower 2 bits of the input, and if they are not equal zero, adds one to the result. - -- This is used to round the byte length to 32-bit word length. - function normalize_length (len : std_logic_vector(15 downto 0)) return std_logic_vector is - variable tmp : std_logic_vector(13 downto 0) := (others => '0'); - begin - tmp := len(15 downto 2); - if(len(1 downto 0) /= "00") then - tmp := std_logic_vector(unsigned(tmp) + 1); - end if; - return tmp; - end function; - + -- Converts std_logic_vector to ENDPOINT_BITMASK_ARRAY function convert_to_bitmask_array (bitmask : std_logic_vector) return ENDPOINT_BITMASK_ARRAY is variable ret : ENDPOINT_BITMASK_ARRAY := (others => (others => '0')); begin @@ -241,6 +372,7 @@ architecture arch of rtps_builtin_endpoint is return ret; end function; + -- Converts ENDPOINT_BITMASK_ARRAY to std_logic_vector function convert_from_bitmask_array (bitmask : ENDPOINT_BITMASK_ARRAY, len : natural) return std_logic_vector is variable ret : std_logic_vector(0 to len-1) := (others => '0'); begin @@ -273,21 +405,30 @@ begin rd_data => mem_read_data ); + rd <= rd_sig; + -- This process swaps the input signal "data_in" to Big Endian Representation endian_swap_prc: process(all) begin + -- DEFAULT data_in_swapped <= data_in; + + -- If in Little Endian Representation if (endian_flag = '1') then + -- Endian Swap for i in 0 to 3 loop data_in_swapped(i*8+8-1 downto i*8) <= data((3-i)*8+8-1 downto (3-i)*8); end loop; end if; end process; + -- This process is responsible for toggling the "endpoint_alive" signal + -- The signal is set high when at least one bit of the "alive" signal is high for at least one clock cycle, + -- and is set low when "reset_endpoint_alive" signal is high for at least one clock cycle. endpoint_alive_prc: process(all) begin - if (rising_edge(clk)) then + if rising_edge(clk) then -- Reset Endpoint Alive Signal if (reset = '1' or reset_endpoint_alive = '1') then endpoint_alive <= '0'; @@ -299,6 +440,9 @@ begin end if; end process; + -- This process is responsible for setting the "mem_seq_nr" and "next_seq_nr" signals + -- The signals are valid as long as "seq_prc_done" is held high. + -- It takes one clock cycle after "mem_op_done" is high to set-up the signals seq_nr_prc: process(all) begin -- DEFAULT @@ -306,26 +450,33 @@ begin mem_seq_nr_next <= mem_seq_nr; next_seq_nr_next <= next_seq_nr; + -- Memory Operation Finished if (mem_op_done = '1') then seq_prc_done_next <= '1'; + case (message_type) is + -- Participant Data Sequence Number when PDP => mem_seq_nr_next <= mem_participant_data.spdp_seq_nr; next_seq_nr_next <= mem_participant_data.spdp_seq_nr + 1; when EDP => + -- Subscriber Data Sequence Number if (is_subscriber = '1') then mem_seq_nr_next <= mem_participant_data.sub_seq_nr; next_seq_nr_next <= mem_participant_data.sub_seq_nr + 1; + -- Publisher Data Sequence Number else mem_seq_nr_next <= mem_participant_data.pub_seq_nr; next_seq_nr_next <= mem_participant_data.pub_seq_nr + 1; end if; + -- Participant Message Data Sequence Number when MESSAGE => mem_seq_nr_next <= mem_participant_data.mes_seq_nr; next_seq_nr_next <= mem_participant_data.mes_seq_nr + 1; when others => null; end case; + -- Memory Operation in progress else seq_prc_done_next <= '0'; mem_seq_nr_next <= (others => '0'); @@ -344,6 +495,7 @@ begin --Write Enable Signal endpoint_wr <= (others => '0'); + rtps_wr <= '0'; case (stage) is when INFORM_ENDPOINTS_MATCH => if (wr_sig = '1') then @@ -362,14 +514,72 @@ begin end case; end process; + -- Main State Machine + -- STATE DESCRIPTION + -- IDLE Idle state. Initiates Participant Announcements, Heartbeat/Liveliness Assertions, Stale Participant Entry Checks ,and Packet Processing, in that priority order. + -- PACKET_HEADER Read the Endpoint FIFO Packet Format Header (RTPS Submessage ID/Opcode, Submessage Flags, Source UDPv4 Port) + -- PACKET_SRC_ADDR Read Source IPv4 Address + -- PACKET_SRC_ENTITYID Read Source Entity ID + -- PACKET_SRC_GUIDPREFIX Read Source GUID Prefix + -- PACKET_DEST_ENTITYID Read Destination Entity ID. Determine content of Packet (Participant Data, Publisher/Subscriber/Message Data/GAP/HEARTBEAT/ACKNACK) and initiate processing. + -- CHECK_SRC_ENTITYID Read Source Entity ID. Determine content of Packet (Participant Data, Publisher/Subscriber/Message Data/GAP/HEARTBEAT/ACKNACK) and initiate processing. + -- This state is taken if the Packet content could not be determined in the PACKET_DEST_ENTITYID state. + -- LATCH_SEQ_NR Store RTPS Data Submessage Sequence Number + -- PROCESS_DATA Parse RTPS Data Submessage Payload Header. Determine content of Data (Parameter List, Participant Message CDR Data) or if Data Message contains in-line QoS and initiate respective handling. + -- PROCESS_MESSAGE Parse Participant Data Message and extract liveliness assertion of remote Participant + -- LIVELINESS_UPDATE Propagate Liveliness Assertion of remote Participant to respective local Reader Endpoints + -- PROCESS_GAP Parse RTPS GAP Submessage + -- PROCESS_GAP_SEQUENCE_NUMBERS Process GAP Sequence Numbers. Update stored Sequence Numbers if necessary + -- PROCESS_HEARTBEAT Parse RTPS HEARTBEAT Submessage + -- PROCESS_HEARTBEAT_SEQUENCE_NUMBERS Process HEARTBEAT Sequence Numbers. Update stored Sequence Numbers if necessary. Set HEARTBEAT response timeout accordingly. + -- PROCESS_ACKNACK Parse RTPS ACKNACK Submessage + -- PROCESS_ACKNACK_SEQUENCE_NUMBERS Process ACKNACK Sequence Numbers. Update stored Sequence Numbers if necessary. Set ACKNACK response timeout accordingly. + -- FIND_PARTICIPANT_DEST Find next stored Participant to send Participant Announcement and Liveliness Assertion to. + -- STALE_CHECK Check memory for remote stale Participant Entries (Lease Duration Exceeded, HEARTBEAT/ACKNACK timeout passed) + -- LATCH_REMOVED_GUIDPREFIX Store Participant GUID Prefix of removed Participant for Orphan Endpoint Search + -- FIND_ORPHAN_ENDPOINT Search for Orphan (whose parent Participant was removed) Endpoints in memory + -- PURGE_ORPHAN_ENDPOINT Remove Orphan Endpoint from memory + -- PROCESS_PL Parse RTPS Parameter List + -- LATCH_STRING_LENGTH Store String Length + -- COMPARE_STRING Compare string to constants depending on string contents. + -- MATCH_GUID Compare GUID Prefix to source GUID Prefix of Packet + -- MATCH_DOMAIN_ID Compare Domain ID + -- MATCH_PROTOCOL_VERSION Compare RTPS Protocol Version + -- LATCH_LOCATOR Store Locator. NOTE: Only Metatraffic and User Locators are differentiated. Unicast and Multicast are overwriting each other and the last parsed is the one to be used. + -- LATCH_EXPECTS_INLINE_QOS Store 'expectsInlineQoS' Flag + -- LATCH_LEASE_DURATION Store remote Participant Lease Duration + -- CHECK_REMOTE_BUILTIN_ENDPOINTS Check if the remote Participant has the required built-in Endpoints + -- RXO_DURABILITY Check Compatibility of Durability QoS + -- RXO_DEADLINE Check Compatibility of Deadline QoS + -- RXO_LIVELINESS Check Compatibility of Liveliness QoS + -- RXO_LEASE_DURATION Check Compatibility of Liveliness QoS + -- RXO_RELIABILITY Check Compatibility of Reliability QoS + -- RXO_DESTINATION_ORDER Check Compatibility of Destination Order QoS + -- RXO_OWNERSHIP Check Compatibility of Ownership QoS + -- RXO_PRESENTATION Check Compatibility of Presentation QoS + -- RXO_PARTITION Check Compatibility of Partition QoS + -- PARTICIPANT_MATCH_STAGE Add compatible remote and remove incompatible remote Participants to and from memory. Update stored Sequence Numbers respectively + -- INITIATE_ENDPOINT_SEARCH Search for remote Endpoint in memory + -- ENDPOINT_MATCH_STAGE Add compatible remote and remove incompatible remote Participants to and from memory. Mark compatibility changes to local Endpoints. + -- INFORM_ENDPOINTS_MATCH Propagate new local Endpoint matches + -- INFORM_ENDPOINTS_UNMATCH Propagate local Endpoint unmatches + -- SEND_HEADER Send Output Data Header and RTPS Message Header + -- SEND_PARTICIPANT_ANNOUNCEMENT Send Participant Announcement Data Submessage + -- SEND_ACKNACK Send ACKNACK Submessages + -- SEND_HEARTBEAT Send HEARTBEAT Submessages + -- SEND_PUB_DATA Send Endpoint Discovery Publication Data Submessage + -- SEND_SUB_DATA Send Endpoint Discovery Subscriber Data Submessage + -- SEND_MES_MAN_LIVE Send Participant Message Automatic Liveliness Assertion Data Submessage + -- SEND_MES_GAP Send Participant Message GAP Submessages + -- SEND_MES_AUTO_LIVE Send Participant Message Manual-by-Participant Liveliness Assertion Data Submessage + -- SKIP_PARAMETER Skip rest of Parameter + -- SKIP_PACKET Skip rest of Packet parse_prc: process(all) variable tmp_endpoint_mask : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0'); begin - --DEFAULT + --DEFAULT Registered stage_next <= stage; return_stage_next <= return_stage; - rd_sig <= '0'; - reset_read_cnt <= '0'; opcode_next <= opcode; flags_next <= flags; src_port_next <= src_port; @@ -385,27 +595,20 @@ begin participant_match_next <= participant_match_next; is_subscriber_next <= is_subscriber; lease_duration_next <= lease_duration; - lifespan_duration_next <= lifespan_duration; - addr_latch_1_next <= addr_latch_1; - addr_latch_2_next <= addr_latch_2; - port_latch_1_next <= port_latch_1; - port_latch_2_next <= port_latch_2; - addr_latch_index_next <= addr_latch_index; + def_addr_next <= def_addr; + meta_addr_next <= meta_addr; + def_port_next <= def_port; + meta_port_next <= meta_port; + is_meta_addr_next <= is_meta_addr; cnt_next <= cnt; - expects_inline_qos_next <= expects_inline_qos; - mem_opcode <= NOP; - mem_op_start <= '0'; + expects_inline_qos_set_next <= expects_inline_qos_set; is_orphan_search_next <= is_orphan_search; extra_flags_next <= extra_flags; - output_sig <= (others => '0'); - wr_sig <= '0'; stale_check_next <= stale_check; first_seq_nr_next <= first_seq_nr; last_seq_nr_next <= last_seq_nr; update_participant_flags_next <= update_participant_flags; deadline_next <= deadline; - last_word_out <= '0'; - reset_endpoint_alive <= '0'; auto_live_seq_nr_next <= auto_live_seq_nr; man_live_seq_nr_next <= man_live_seq_nr; live_gap_start_next <= live_gap_start; @@ -414,6 +617,18 @@ begin heartbeat_time_next <= heartbeat_time; is_live_assert_next <= is_live_assert; string_content_next <= string_content; + participant_data_cnt_next <= participant_data_cnt; + publisher_data_cnt_next <= publisher_data_cnt; + subscriber_data_cnt_next <= subscriber_data_cnt; + -- DEFAULT Unregistered + rd_sig <= '0'; + reset_read_cnt <= '0'; + wr_sig <= '0'; + mem_opcode <= NOP; + mem_op_start <= '0'; + last_word_out <= '0'; + reset_endpoint_alive <= '0'; + output_sig <= (others => '0'); -- Last Word Latch Setter if (last_word_in = '1') then @@ -479,12 +694,17 @@ begin stale_check_next <= '0'; stage_next <= PACKET_HEADER; - -- TODO: Reset Latches + -- Reset Latches + def_addr_next <= (others => '0'); + meta_addr_next <= DEFAULT_IPv4_MULTICAST_ADDRESS; + def_port_next <= (others => '0'); + meta_port_next <= META_IPv4_MULTICAST_PORT; + lease_duration_next <= (others => (others => '0')); + expects_inline_qos_set_next <= '0'; + extra_flags_next <= (others => '0'); -- 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'); + participant_match_next <= '1'; + endpoint_mask_next <= (others => '1'); end if; when PACKET_HEADER => -- Input FIFO Guard @@ -913,6 +1133,36 @@ begin null; end case; end if; + when LIVELINESS_UPDATE => + -- 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 + 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 PROCESS_GAP => -- Input FIFO Guard if (empty = '0') then @@ -954,6 +1204,339 @@ begin -- DONE stage_next <= SKIP_PACKET; end if; + when PROCESS_HEARTBEAT => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + cnt_next <= cnt + 1; + + -- Latch Sequence Numbers + case (cnt) is + when 0 => + first_seq_nr_next(0) <= data_in_swapped; + when 1 => + first_seq_nr_next(1) <= data_in_swapped; + when 2 => + last_seq_nr_next(0) <= data_in_swapped; + when 3 => + 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 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 + stage_next <= SKIP_PACKET; + 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 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; + 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', ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; + -- 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; + 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', ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '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 + if (first_seq_nr <= auto_live_seq_nr) then + -- Set Acknack Response Time and set Message Data as Acknack Response + mem_opcode <= UPDATE_PARTICIPANT; + 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', ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; + end if; + 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 + stage_next <= SKIP_PACKET; + end if; + when FIND_PARTICIPANT_DEST => + -- Wait for Next Participant to be Fetched + if (mem_op_done = '1') then + -- No more Participants + if (addr_res = MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + stage_next <= SEND_HEADER; + return_stage_next <= SEND_HEARTBEAT; + cnt_next <= 0; + end if + end if; + when STALE_CHECK => + -- Wait for Stale Search to finish + if (mem_op_done = '1') then + -- Found Stale Entry + 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; + 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 + -- Zero Heartbeat Response Time + mem_opcode <= UPDATE_PARTICIPANT; + deadline_next <= (others => '0'); + update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0'); + mem_op_start <= '1'; + -- DONE + stage_next <= IDLE; + -- If Response Delay Passed + else + -- Set Heartbeat Suppression Time + mem_opcode <= UPDATE_PARTICIPANT; + if (PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY /= 0) then + -- Set Heartbeat Suppression Time + deadline_next <= time + PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '1'; + else + -- Zero Heartbeat Response Time + deadline_next <= (others => '0'); + end if; + update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0'); + 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 + else + -- If Suppression Delay passed, zero the time + if(mem_participant_data.acknack_res_time(0) = '1') then + -- Zero Acknack Response Time + mem_opcode <= UPDATE_PARTICIPANT; + deadline_next <= (others => '0'); + update_participant_flags_next <= (ACKNACK_RES_TIME_FLAG => '1', others => '0'); + mem_op_start <= '1'; + -- DONE + stage_next <= IDLE; + -- If Response Delay Passed + else + mem_opcode <= UPDATE_PARTICIPANT; + if (PARTICIPANT_ACKNACK_SUPPRESSION_DELAY /= 0) then + -- Set Acknack Suppression Time + deadline_next <= time + PARTICIPANT_ACKNACK_SUPPRESSION_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline_next(0) <= '1'; + else + -- Zero Acknack Response Time + deadline_next <= (others => '0'); + end if; + -- Zero Data Response Flags + extra_flags_next <= mem_participant_data.extra_flags; + extra_flags_next(PUB_DATA_FLAG) <= '0'; + 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'); + 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 + -- DONE + stage_next <= IDLE; + end if; + end if; + 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); + guid_next(1) <= mem_guidprefix(1); + guid_next(2) <= mem_guidprefix(2); + stage_next <= FIND_ORPHAN_ENDPOINT; + 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; + 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 + -- Found Orphan Endpoint + if (addr_res /= MAX_ADDRESS) then + -- Remove Orphaned Endpoint from Buffer + mem_opcode <= REMOVE_ENDPOINT; + mem_op_start <= '1'; + -- Mark UNMATCHES + endpoint_match_next <= (others => '0'); + endpoint_unmatch_next <= convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS); + -- Propagate Unmatches to local Endpoints + stage_next <= INFORM_ENDPOINTS_UNMATCH; + cnt_next <= 0; + -- Buffer has no more Orphans + else + -- DONE + stage_next <= SKIP_PACKET; + end if; + end if; when PROCESS_PL => -- Input FIFO Guard if (empty = '0') then @@ -961,11 +1544,10 @@ begin -- Reset Word Counter reset_read_cnt <= '1'; -- Latch Parameter End (In order to skip parameters) - parameter_end_next <= unsigned(normalize_length(endian_swap(endian_flag,parameter_length))); + parameter_end_next <= unsigned(endian_swap(endian_flag,parameter_length)); -- 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 @@ -975,7 +1557,7 @@ begin -- Ignore in-line QoS -- Only relevant for Participant Discovery Protocol if(qos_flag = '0' and message_type = PDP) then - stage_next <= LATCH_GUID; + stage_next <= MATCH_GUID; cnt_next <= 0; end if; when PID_DOMAIN_ID => @@ -1004,7 +1586,7 @@ begin if(qos_flag = '0' and message_type = PDP) then stage_next <= LATCH_LOCATOR; cnt_next <= 0; - addr_latch_index_next <= '0'; + is_meta_addr_next <= '0'; end if; when PID_DEFAULT_MULTICAST_LOCATOR => -- Ignore in-line QoS @@ -1012,8 +1594,7 @@ begin 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'; + is_meta_addr_next <= '0'; end if; when PID_METATRAFFIC_UNICAST_LOCATOR => -- Ignore in-line QoS @@ -1021,8 +1602,7 @@ begin 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'; + is_meta_addr_next <= '1'; end if; when PID_METATRAFFIC_MULTICAST_LOCATOR => -- Ignore in-line QoS @@ -1030,8 +1610,7 @@ begin 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'; + is_meta_addr_next <= '1'; end if; when PID_PARTICIPANT_LEASE_DURATION => -- Ignore in-line QoS @@ -1125,7 +1704,7 @@ begin stage_next <= LATCH_LOCATOR; cnt_next <= 0; -- Mark Latch 1 for storing - addr_latch_index_next <= '0'; + is_meta_addr_next <= '0'; end if; when PID_MULTICAST_LOCATOR => -- Ignore in-line QoS @@ -1134,13 +1713,13 @@ begin stage_next <= LATCH_LOCATOR; cnt_next <= 0; -- Mark Latch 1 for storing - addr_latch_index_next <= '0'; + is_meta_addr_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; + stage_next <= MATCH_GUID; cnt_next <= 0; end if; when PID_EXPECTS_INLINE_QOS => @@ -1308,6 +1887,155 @@ begin stage_next => SKIP_PARAMETER; end if; end if; + when MATCH_GUID => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + 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 + case (cnt) is + when 0 => + if (data_in /= guid(0)) then + stage_next <= SKIP_PACKET; + end if; + when 1 => + if (data_in /= guid(1)) then + stage_next <= SKIP_PACKET; + end if; + when 2 => + if (data_in /= guid(2)) then + stage_next <= SKIP_PACKET; + end if; + when 3 => + -- NOTE: Even though the mem_ctrl_prc is currently using the guid signal, it only uses the first + -- 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 MATCH_DOMAIN_ID => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + + -- Match Domain ID + if (data_in_swapped /= DOMAIN_ID) then + participant_match_next <= '0'; + end if; + -- DONE + stage_next <= SKIP_PARAMETER; + end if; + when MATCH_PROTOCOL_VERSION => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + + -- Match major Protocol Version + if(data_in(31 downto 24) /= PROTOCOLVERSION_2_4(15 downto 8)) then + participant_match_next <= '0'; + end if; + -- DONE + stage_next <= SKIP_PARAMETER; + end if; + when LATCH_LOCATOR => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + cnt_next <= cnt + 1; + + case (cnt) is + -- Locator Kind + when 0 => + -- Check if UDPv4 Locator + if (data_in_swapped /= LOCATOR_KIND_UDPv4) then + -- Skip + stage_next <= SKIP_PARAMETER; + end if; + -- Locator Port + when 1 => + -- Latch Source Port + if (is_meta_addr = '0') then + def_port <= data_in_swapped(def_port'length-1 downto 0); + else + meta_port <= data_in_swapped(meta_port'length-1 downto 0); + end if; + -- Locator Addr (IPv4) + when 5 => + -- Latch Src Addr + if (is_meta_addr = '0') then + def_addr <= data_in_swapped; + else + meta_addr <= data_in_swapped; + end if; + -- 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' + 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_LEASE_DURATION => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + cnt_next <= cnt + 1; + + -- Latch Lease Duration + 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 CHECK_REMOTE_BUILTIN_ENDPOINTS => + -- Input FIFO Guard + if (empty = '0') then + rd_sig <= '1'; + + -- 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 + 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 + participant_match_next <= '0'; + end if; + end if; + -- Check for necessary Builtin Endpoints for Writers + 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 + participant_match_next <= '0'; + end if; + end if; + -- DONE + stage_next <= SKIP_PARAMETER; + end if; when RXO_DURABILITY => -- Input FIFO Guard if (empty = '0') then @@ -1445,24 +2173,6 @@ begin null; end case; end if; - when LATCH_LEASE_DURATION => - -- Input FIFO Guard - if (empty = '0') then - rd_sig <= '1'; - cnt_next <= cnt + 1; - - -- Latch Lease Duration - 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 @@ -1581,137 +2291,6 @@ begin -- DONE stage_next <= SKIP_PARAMETER; end if; - when MATCH_DOMAIN_ID => - -- Input FIFO Guard - if (empty = '0') then - rd_sig <= '1'; - - -- Match Domain ID - if (data_in_swapped /= DOMAIN_ID) then - participant_match_next <= '0'; - end if; - -- DONE - stage_next <= SKIP_PARAMETER; - end if; - when MATCH_PROTOCOL_VERSION => - -- Input FIFO Guard - if (empty = '0') then - rd_sig <= '1'; - - -- Match major Protocol Version - if(data_in(31 downto 24) /= PROTOCOLVERSION_2_4(15 downto 8)) then - participant_match_next <= '0'; - end if; - -- DONE - stage_next <= SKIP_PARAMETER; - end if; - when LATCH_LOCATOR => - -- Input FIFO Guard - if (empty = '0') then - rd_sig <= '1'; - cnt_next <= cnt + 1; - - case (cnt) is - -- Locator Kind - when 0 => - -- Check if UDPv4 Locator - if (data_in_swapped /= LOCATOR_KIND_UDPv4) then - -- Skip - stage_next <= SKIP_PARAMETER; - end if; - -- Locator Port - when 1 => - -- Latch Source Port - if (addr_latch_index = '0') then - port_latch_1 <= data_in_swapped(port_latch_1'length-1 downto 0); - else - port_latch_2 <= data_in_swapped(port_latch_2'length-1 downto 0); - end if; - -- Locator Addr (IPv4) - when 5 => - -- Latch Src Addr - if (addr_latch_index = '0') then - addr_latch_1 <= data_in_swapped; - else - addr_latch_2 <= data_in_swapped; - end if; - -- 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' - 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'; - 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 - case (cnt) is - when 0 => - if (data_in /= guid(0)) then - stage_next <= SKIP_PACKET; - end if; - when 1 => - if (data_in /= guid(1)) then - stage_next <= SKIP_PACKET; - end if; - when 2 => - if (data_in /= guid(2)) then - stage_next <= SKIP_PACKET; - end if; - when 3 => - -- NOTE: Even though the mem_ctrl_prc is currently using the guid signal, it only uses the first - -- 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'; - - -- 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 - 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 - participant_match_next <= '0'; - end if; - end if; - -- Check for necessary Builtin Endpoints for Writers - 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 - participant_match_next <= '0'; - end if; - end if; - -- DONE - stage_next <= SKIP_PARAMETER; - end if; 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 @@ -1837,35 +2416,6 @@ begin 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; - 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 - -- Found Orphan Endpoint - if (addr_res /= MAX_ADDRESS) then - -- Remove Orphaned Endpoint from Buffer - mem_opcode <= REMOVE_ENDPOINT; - mem_op_start <= '1'; - -- Mark UNMATCHES - endpoint_match_next <= (others => '0'); - endpoint_unmatch_next <= convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS); - -- Propagate Unmatches to local Endpoints - stage_next <= INFORM_ENDPOINTS_UNMATCH; - cnt_next <= 0; - -- 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 @@ -1891,8 +2441,8 @@ begin -- IPv4 Address when 5 => -- 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; + if (def_addr /= (def_addr'reverse_range => '0')) then + output_sig <= def_addr; else output_sig <= mem_participant_data.def_addr; end if; @@ -1902,8 +2452,8 @@ begin 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(31 downto 16) <= port_latch_1; + if (def_port /= (def_port'reverse_range => '0')) then + output_sig(31 downto 16) <= def_port; else output_sig(31 downto 16) <= mem_participant_data.def_port; end if; @@ -1961,166 +2511,67 @@ begin null; end case; end if; - when STALE_CHECK => - -- Wait for Stale Search to finish - if (mem_op_done = '1') then - -- Found Stale Entry - 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; - 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 - -- Zero Heartbeat Response Time - mem_opcode <= UPDATE_PARTICIPANT; - deadline_next <= (others => '0'); - update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0'); - mem_op_start <= '1'; - -- DONE - stage_next <= IDLE; - -- If Response Delay Passed - else - -- Set Heartbeat Suppression Time - mem_opcode <= UPDATE_PARTICIPANT; - if (PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY /= 0) then - -- Set Heartbeat Suppression Time - deadline_next <= time + PARTICIPANT_HEARTBEAT_SUPPRESSION_DELAY; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '1'; - else - -- Zero Heartbeat Response Time - deadline_next <= (others => '0'); - end if; - update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0'); - 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 - else - -- If Suppression Delay passed, zero the time - if(mem_participant_data.acknack_res_time(0) = '1') then - -- Zero Acknack Response Time - mem_opcode <= UPDATE_PARTICIPANT; - deadline_next <= (others => '0'); - update_participant_flags_next <= (ACKNACK_RES_TIME_FLAG => '1', others => '0'); - mem_op_start <= '1'; - -- DONE - stage_next <= IDLE; - -- If Response Delay Passed - else - mem_opcode <= UPDATE_PARTICIPANT; - if (PARTICIPANT_ACKNACK_SUPPRESSION_DELAY /= 0) then - -- Set Acknack Suppression Time - deadline_next <= time + PARTICIPANT_ACKNACK_SUPPRESSION_DELAY; - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(0) <= '1'; - else - -- Zero Acknack Response Time - deadline_next <= (others => '0'); - end if; - -- Zero Data Response Flags - extra_flags_next <= mem_participant_data.extra_flags; - extra_flags_next(PUB_DATA_FLAG) <= '0'; - 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'); - 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 - -- DONE - stage_next <= IDLE; - end if; - end if; - 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); - guid_next(1) <= mem_guidprefix(1); - guid_next(2) <= mem_guidprefix(2); - stage_next <= FIND_ORPHAN_ENDPOINT; - end if; - when PROCESS_HEARTBEAT => - -- Input FIFO Guard - if (empty = '0') then - rd_sig <= '1'; + when SEND_HEADER => + if (rtps_full = '0') then + wr_sig <= '1'; cnt_next <= cnt + 1; - -- Latch Sequence Numbers case (cnt) is + -- OUTPUT HEADER + -- Src IPv4 Address when 0 => - first_seq_nr_next(0) <= data_in_swapped; + output_sig <= DEFAULT_IPv4_MULTICAST_ADDRESS; + -- Dest IPv4 Address when 1 => - first_seq_nr_next(1) <= data_in_swapped; + -- Set Default Multicast Announce Address if Participant Announcement + if (return_stage = SEND_PARTICIPANT_ANNOUNCEMENT) then + output_sig <= DEFAULT_IPv4_MULTICAST_ADDRESS; + else + output_sig <= mem_participant_data.meta_addr; + end if; + -- Src and Dest UDPv4 Ports when 2 => - last_seq_nr_next(0) <= data_in_swapped; + -- 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 + output_sig <= META_IPv4_UNICAST_PORT & mem_participant_data.meta_port; + end if; + -- RTPS MESSAGE HEADER when 3 => - last_seq_nr_next(1) <= data_in_swapped; - stage_next <= PROCESS_HEARTBEAT_SEQUENCE_NUMBERS; + output_sig <= PROTOCOL_RTPS; + when 4 => + output_sig <= PROTOCOLVERSION_2_4 & VENDORID; + when 5 => + output_sig <= GUIDPREFIX(0); + when 6 => + output_sig <= GUIDPREFIX(1); + when 7 => + output_sig <= GUIDPREFIX(2); + -- Continue with respective RTPS Submessage + stage_next <= return_stage; + cnt_next <= 0; + participant_data_cnt_next <= 0; + publisher_data_cnt_next <= 0; + subscriber_data_cnt <= 0; when others => null; end case; end if; - when PROCESS_HEARTBEAT_SEQUENCE_NUMBERS => - -- 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; + when SEND_PARTICIPANT_ANNOUNCEMENT => + if (rtps_full = '0') then + wr_sig <= '1'; + participant_data_cnt_next <= participant_data_cnt + 1; + + -- Send Participant Data + output_sig <= PARTICIPANT_DATA.data(participant_data_cnt); + + -- Exit Condition + if (participant_data_cnt = (PARTICIPANT_DATA.length-1)) then + last_word_out <= '1'; + -- DONE + stage_next <= IDLE; end if; - -- DONE - stage_next <= SKIP_PACKET; end if; when SEND_ACKNACK => if (rtps_full = '0') then @@ -2296,222 +2747,20 @@ begin 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 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; - 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', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - mem_op_start <= '1'; - end if; - -- 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; - 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', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - mem_op_start <= '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 - if (first_seq_nr <= auto_live_seq_nr) then - -- Set Acknack Response Time and set Message Data as Acknack Response - mem_opcode <= UPDATE_PARTICIPANT; - 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', ACKNACK_RES_TIME_FLAG => '1', others => '0'); - mem_op_start <= '1'; - end if; - 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 - stage_next <= SKIP_PACKET; - end if; - when FIND_PARTICIPANT_DEST => - -- Wait for Next Participant to be Fetched - if (mem_op_done = '1') then - -- No more Participants - if (addr_res = MAX_ADDRESS) then - -- DONE - stage_next <= IDLE; - else - 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'; - cnt_next <= cnt + 1; - - case (cnt) is - -- OUTPUT HEADER - -- Src IPv4 Address - when 0 => - 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 - output_sig <= mem_participant_data.meta_addr; - 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 - output_sig <= META_IPv4_UNICAST_PORT & mem_participant_data.meta_port; - end if; - -- RTPS MESSAGE HEADER - when 3 => - output_sig <= PROTOCOL_RTPS; - when 4 => - output_sig <= PROTOCOLVERSION_2_4 & VENDORID; - when 5 => - output_sig <= GUIDPREFIX(0); - when 6 => - output_sig <= GUIDPREFIX(1); - when 7 => - output_sig <= GUIDPREFIX(2); - -- 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'; - cnt_next <= cnt + 1; - - -- 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; when SEND_PUB_DATA => -- 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'; - cnt_next <= cnt + 1; + wr_sig <= '1'; + publisher_data_cnt_next <= publisher_data_cnt + 1; -- Send Publisher Data - output_sig <= WRITER_ENDPOINT_DATA.data(cnt); + output_sig <= WRITER_ENDPOINT_DATA.data(publisher_data_cnt); -- Exit Condition - if (cnt = (WRITER_ENDPOINT_DATA.length-1)) then + if (publisher_data_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 @@ -2530,14 +2779,14 @@ begin stage_next <= SEND_MES_MAN_LIVE; -- Output FIFO Guard elsif (rtps_full = '0') then - wr_sig <= '1'; - cnt_next <= cnt + 1; + wr_sig <= '1'; + subscriber_data_cnt_next <= subscriber_data_cnt + 1; -- Send Subscriber Data - output_sig <= READER_ENDPOINT_DATA.data(cnt); + output_sig <= READER_ENDPOINT_DATA.data(subscriber_data_cnt); -- Exit Condition - if (cnt = (READER_ENDPOINT_DATA.length-1)) then + if (subscriber_data_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 @@ -2704,39 +2953,9 @@ begin null; end case; end if; - when LIVELINESS_UPDATE => - -- 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 - 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 + if ((read_cnt & "00" ) >= parameter_end) then -- Parse Next Parameter -- NOTE: data_in is already showing the next parameter stage_next <= PROCESS_PL; @@ -2744,11 +2963,6 @@ begin elsif (empty = '0') then -- Skip-Read rd_sig <= '1'; - -- End of Parameter - if (read_cnt = parameter_end) then - -- Parse Next Parameter - stage_next <= PROCESS_PL; - end if; end if; when SKIP_PACKET => -- NOTE: At the end of a Stale Entry Removal this stage is entered, without having started reading a Packet from input. @@ -2775,35 +2989,51 @@ begin end case; end process; - -- TODO: add_res is still valid after removal. So we could continue searching the next orphan endpoint from that address on + + -- Main State Machine + -- STATE DESCRIPTION + -- IDLE Idle state. Done Signal is pulled high and Memory FSM accepts new memory operations + -- SEARCH_PARTICIPANT See Memory OPCODE Description + -- SEARCH_ENDPOINT See Memory OPCODE Description + -- GET_PARTICIPANT_DATA Latch the contents of the Participant Entry for use in the main FSM + -- GET_ENDPOINT_MASK Latch the contents of the Endpoint Entry for use in the main FSM + -- INSERT_PARTICIPANT See Memory OPCODE Description + -- INSERT_ENDPOINT See Memory OPCODE Description + -- UPDATE_PARTICIPANT See Memory OPCODE Description + -- UPDATE_ENDPOINT See Memory OPCODE Description + -- REMOVE_PARTICIPANT See Memory OPCODE Description + -- REMOVE_ENDPOINT See Memory OPCODE Description + -- FIND_PARTICIPANT_SLOT Find first empty Participant Slot in memory + -- FIND_ENDPOINT_SLOT Find first empty Endpoint Slot in memory + -- FIND_NEXT_PARTICIPANT See Memory OPCODE Description + -- FIND_STALE_PARTICIPANT See Memory OPCODE Description 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'); begin - -- DEFAULT - mem_op_done <= '0'; + -- DEFAULT Registered mem_stage_next <= mem_stage; mem_addr_base_next <= mem_addr_base; mem_addr_next <= mem_addr; - mem_rd <= '0'; - mem_wr <= '0'; addr_res_next <= addr_res; mem_cnt_next <= mem_cnt; - mem_seq_nr_next <= mem_seq_nr; - orphan_entityid_next <= orphan_entityid; last_addr_next <= last_addr; mem_participant_data_next <= mem_participant_data; is_heartbeat_res_next <= is_heartbeat_res; + endpoint_mask_array_next <= endpoint_mask_array; + -- DEFAULT Unregistered + mem_op_done <= '0'; + mem_rd <= '0'; + mem_wr <= '0'; + case (mem_stage) is when IDLE => mem_op_done <= '1'; reset_max_pointer_next <= '0'; - -- 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 => @@ -2816,19 +3046,6 @@ begin mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_stage_next <= SEARCH_ENDPOINT; mem_cnt_next <= 0; - when REMOVE_PARTICIPANT => - mem_addr_next <= addr_res; - mem_stage_next <= REMOVE_PARTICIPANT; - mem_cnt_next <= 0; - when REMOVE_ENDPOINT => - mem_addr_next <= addr_res; - 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; @@ -2839,37 +3056,6 @@ begin mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_stage_next <= FIND_ENDPOINT_SLOT; mem_cnt_next <= 0; - when RESET_MAX_PARTICIPANT_POINTER => - mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; - mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; - reset_max_pointer_next <= '1'; - last_addr_next <= (others => '0'); - 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 <= 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; - 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; - 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_cnt_next <= 0; when UPDATE_PARTICIPANT => mem_stage_next <= UPDATE_PARTICIPANT; if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then @@ -2891,6 +3077,36 @@ begin mem_addr_next <= addr_res + 17; mem_cnt_next <= 14; end if; + 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 REMOVE_PARTICIPANT => + mem_addr_next <= addr_res; + mem_stage_next <= REMOVE_PARTICIPANT; + mem_cnt_next <= 0; + when REMOVE_ENDPOINT => + mem_addr_next <= addr_res; + mem_stage_next <= REMOVE_ENDPOINT; + 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; + 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; + 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_cnt_next <= 0; when others => null; end case; @@ -2945,6 +3161,68 @@ begin when others => null; end case; + when SEARCH_ENDPOINT => + mem_rd <= '1'; + mem_cnt_next <= mem_cnt + 1; + mem_addr_next <= mem_addr + 1; + + -- Next Endpoint Frame Address + 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 <= 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 => + -- 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 + -- Continue Search + mem_addr_next <= tmp; + 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 + -- Continue Search + mem_addr_next <= tmp; + 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 + -- Continue Search + mem_addr_next <= tmp; + mem_addr_base <= tmp; + mem_cnt_next <= 0; + -- Match Found + else + mem_stage_next <= GET_ENDPOINT_MASK; + mem_cnt_next <= 0; + end if; + when others => + null; + end case; when GET_PARTICIPANT_DATA => mem_rd <= '1'; mem_cnt_next <= mem_cnt + 1; @@ -3020,77 +3298,291 @@ begin when others => null; end case; - when SEARCH_ENDPOINT => - mem_rd <= '1'; - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; - - -- Next Endpoint Frame Address - 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 <= 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 => - -- 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 - -- Continue Search - mem_addr_next <= tmp; - 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 - -- Continue Search - mem_addr_next <= tmp; - 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 - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base <= tmp; - mem_cnt_next <= 0; - -- Match Found - else - mem_stage_next <= GET_ENDPOINT_MASK; - mem_cnt_next <= 0; - end if; - when others => - null; - end case; when GET_ENDPOINT_MASK => mem_rd <= '1'; mem_cnt_next <= mem_cnt + 1; 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 INSERT_PARTICIPANT => + mem_wr <= '1'; + mem_addr_next <= mem_addr + 1; + mem_cnt_next <= mem_cnt + 1; + + case (mem_cnt) is + -- GUIDPrefix 1/3 + when 0 => + mem_write_data <= guid(0); + -- GUIDPrefix 2/3 + when 1 => + mem_write_data <= guid(1); + -- GUIDPrefix 3/3 + when 2 => + mem_write_data <= guid(2); + -- Metatraffic IPv4 Address + when 3 => + mem_write_data <= meta_addr; + -- Default Endpoint IPv4 Address + when 4 => + mem_write_data <= def_addr; + -- UDPv4 Ports + when 5 => + mem_write_data <= meta_port & def_port; + -- SPDP Sequence Number 1/2 + when 6 => + mem_write_data <= std_logic_vector(seq_nr(0)); + -- SPDP Sequence Number 2/2 + when 7 => + mem_write_data <= std_logic_vector(seq_nr(1)); + -- Lease Duration 1/2 + when 8 => + mem_write_data <= std_logic_vector(lease_duration(0)); + -- Lease Duration 2/2 + when 9 => + mem_write_data <= std_logic_vector(lease_duration(1)); + -- Lease Deadline 1/2 + when 10 => + mem_write_data <= std_logic_vector(lease_deadline(0)); + -- Lease Deadline 2/2 + when 11 => + mem_write_data <= std_logic_vector(lease_deadline(1)); + -- Extra Flags + when 12 => + mem_write_data <= (others => '0'); + mem_write_data(EXTRA_FLAGS_WIDTH-1 downto 0) <= extra_flags; + -- ACKNACK Response/Suppression Time 1/2 + when 13 => + mem_write_data <= (others => '0'); + -- ACKNACK Response/Suppression Time 2/2 + when 14 => + mem_write_data <= (others => '0'); + -- HEARTBEAT Response/Suppression Time 1/2 + when 15 => + mem_write_data <= (others => '0'); + -- HEARTBEAT Response/Suppression Time 2/2 + when 16 => + mem_write_data <= (others => '0'); + -- Publication Sequence Number 1/2 + when 17 => + mem_write_data <= (others => '0'); + -- Publication Sequence Number 2/2 + when 18 => + mem_write_data <= (others => '0'); + -- Subscription Sequence Number 1/2 + when 19 => + mem_write_data <= (others => '0'); + -- Subscription Sequence Number 2/2 + when 20 => + mem_write_data <= (others => '0'); + -- Participant Message Sequence Number 1/2 + when 21 => + mem_write_data <= (others => '0'); + -- Participant Message Sequence Number 2/2 + when 22 => + mem_write_data <= (others => '0'); + -- DONE + mem_stage_next <= IDLE; + when others => + null; + end case; + when INSERT_ENDPOINT => + mem_wr <= '1'; + mem_addr_next <= mem_addr + 1; + mem_cnt_next <= mem_cnt + 1; + + case (mem_cnt) is + -- Entity ID + when 0 => + mem_write_data <= guid(3); + -- GUIDPrefix 1/3 + when 1 => + mem_write_data <= guid(0); + -- GUIDPrefix 2/3 + when 2 => + mem_write_data <= guid(1); + -- GUIDPrefix 3/3 + when 3 => + mem_write_data <= guid(2); + + -- 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; + when others => + null; + end case; + when UPDATE_PARTICIPANT => + mem_cnt_next <= mem_cnt + 1; + mem_addr_next <= mem_addr + 1; + + case (mem_cnt) is + -- Metatraffic IPv4 Address + when 0 => + mem_write_data <= meta_addr; + if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then + mem_wr <= '1'; + end if; + -- Default Endpoint IPv4 Address + when 1 => + mem_write_data <= def_addr; + if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then + mem_wr <= '1'; + end if; + -- UDPv4 Ports + when 2 => + mem_write_data <= meta_port & def_port; + if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then + mem_wr <= '1'; + end if; + -- SPDP Sequence Number 1/2 + when 3 => + 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 => + 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 => + 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 => + 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 + 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 => + 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 => + 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 + if (update_participant_flags(5 downto 2) = (5 downto 2 => '0')) then + -- DONE + mem_stage_next <= IDLE; + end if; + -- Extra Flags + when 9 => + 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 + 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 => + 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 => + 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 + 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 => + 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 => + 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 + 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 => + 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 => + 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 => + 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 => + 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 => + 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 => + 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 UPDATE_ENDPOINT => + mem_wr <= '1'; + mem_addr_next <= mem_addr + 1; + 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 @@ -3115,23 +3607,28 @@ begin mem_guidprefix_next(1) <= mem_read_data; -- GUID Prefix 3/3 when 3 => - mem_rd <= '1'; + 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_wr <= '1'; mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(0); -- GUID Prefix 2/3 when 5 => - mem_wr <= '1'; + mem_wr <= '1'; mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(1); -- GUID Prefix 3/3 when 6 => - mem_wr <= '1'; + mem_wr <= '1'; mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(2); -- Reset MAX Participant Pointer - mem_stage_next <= RESET_MAX_PARTICIPANT_POINTER; + mem_addr_base_next <= FIRST_PARTICIPANT_ADDRESS; + mem_addr_next <= FIRST_PARTICIPANT_ADDRESS; + reset_max_pointer_next <= '1'; + last_addr_next <= (others => '0'); + mem_stage_next <= FIND_PARTICIPANT_SLOT; + mem_cnt_next <= 0; when others => null; end case; @@ -3141,21 +3638,12 @@ begin -- Overtwrite EntityID with ENTITYID_UNKNOWN to mark slot as empty mem_write_data <= ENTITYID_UNKNOWN; -- Reset MAX Participant Pointer - mem_stage_next <= RESET_MAX_ENDPOINT_POINTER; - when UPDATE_ENDPOINT => - mem_wr <= '1'; - mem_addr_next <= mem_addr + 1; - 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 - mem_stage_next <= IDLE; - end if; + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_addr_next <= FIRST_ENDPOINT_ADDRESS; + reset_max_pointer_next <= '1'; + last_addr_next <= MAX_ADDRESS; + mem_stage_next <= FIND_ENDPOINT_SLOT; + mem_cnt_next <= 0; when FIND_PARTICIPANT_SLOT => mem_rd <= '1'; mem_addr_next <= mem_addr + 1; @@ -3240,87 +3728,6 @@ begin when others => null; end case; - when INSERT_PARTICIPANT => - mem_wr <= '1'; - mem_addr_next <= mem_addr + 1; - mem_cnt_next <= mem_cnt + 1; - - case (mem_cnt) is - -- GUIDPrefix 1/3 - when 0 => - mem_write_data <= guid(0); - -- GUIDPrefix 2/3 - when 1 => - mem_write_data <= guid(1); - -- GUIDPrefix 3/3 - when 2 => - mem_write_data <= guid(2); - -- Metatraffic IPv4 Address - when 3 => - mem_write_data <= addr_latch_2; - -- Default Endpoint IPv4 Address - when 4 => - mem_write_data <= addr_latch_1; - -- UDPv4 Ports - when 5 => - mem_write_data <= port_latch_2 & port_latch_1; - -- SPDP Sequence Number 1/2 - when 6 => - mem_write_data <= std_logic_vector(seq_nr(0)); - -- SPDP Sequence Number 2/2 - when 7 => - mem_write_data <= std_logic_vector(seq_nr(1)); - -- Lease Duration 1/2 - when 8 => - mem_write_data <= std_logic_vector(lease_duration(0)); - -- Lease Duration 2/2 - when 9 => - mem_write_data <= std_logic_vector(lease_duration(1)); - -- Lease Deadline 1/2 - when 10 => - mem_write_data <= std_logic_vector(lease_deadline(0)); - -- Lease Deadline 2/2 - when 11 => - mem_write_data <= std_logic_vector(lease_deadline(1)); - -- Extra Flags - when 12 => - mem_write_data <= (others => '0'); - mem_write_data(EXTRA_FLAGS_WIDTH-1 downto 0) <= extra_flags; - -- ACKNACK Response/Suppression Time 1/2 - when 13 => - mem_write_data <= (others => '0'); - -- ACKNACK Response/Suppression Time 2/2 - when 14 => - mem_write_data <= (others => '0'); - -- HEARTBEAT Response/Suppression Time 1/2 - when 15 => - mem_write_data <= (others => '0'); - -- HEARTBEAT Response/Suppression Time 2/2 - when 16 => - mem_write_data <= (others => '0'); - -- Publication Sequence Number 1/2 - when 17 => - mem_write_data <= (others => '0'); - -- Publication Sequence Number 2/2 - when 18 => - mem_write_data <= (others => '0'); - -- Subscription Sequence Number 1/2 - when 19 => - mem_write_data <= (others => '0'); - -- Subscription Sequence Number 2/2 - when 20 => - mem_write_data <= (others => '0'); - -- Participant Message Sequence Number 1/2 - when 21 => - mem_write_data <= (others => '0'); - -- Participant Message Sequence Number 2/2 - when 22 => - mem_write_data <= (others => '0'); - -- DONE - mem_stage_next <= IDLE; - when others => - null; - end case; when FIND_ENDPOINT_SLOT => mem_rd <= '1'; mem_cnt_next <= mem_cnt + 1; @@ -3376,32 +3783,6 @@ begin when others => null; end case; - when INSERT_ENDPOINT => - mem_wr <= '1'; - mem_addr_next <= mem_addr + 1; - mem_cnt_next <= mem_cnt + 1; - - case (mem_cnt) is - -- Entity ID - when 0 => - mem_write_data <= guid(3); - -- GUIDPrefix 1/3 - when 1 => - mem_write_data <= guid(0); - -- GUIDPrefix 2/3 - when 2 => - mem_write_data <= guid(1); - -- GUIDPrefix 3/3 - when 3 => - mem_write_data <= guid(2); - - -- 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; - when others => - null; - end case; when FIND_NEXT_PARTICIPANT => mem_rd <= '1'; mem_cnt_next <= mem_cnt + 1; @@ -3592,162 +3973,6 @@ begin when others => null; end case; - when UPDATE_PARTICIPANT => - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; - - case (mem_cnt) is - -- Metatraffic IPv4 Address - when 0 => - 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 => - mem_write_data <= addr_latch_1; - if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then - mem_wr <= '1'; - end if; - -- UDPv4 Ports - when 2 => - 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 => - 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 => - 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 => - 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 => - 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 - 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 => - 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 => - 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 - if (update_participant_flags(5 downto 2) = (5 downto 2 => '0')) then - -- DONE - mem_stage_next <= IDLE; - end if; - -- Extra Flags - when 9 => - 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 - 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 => - 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 => - 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 - 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 => - 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 => - 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 - 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 => - 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 => - 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 => - 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 => - 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 => - 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 => - 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; end case; @@ -3768,4 +3993,121 @@ begin end if; end process; -end architecture; \ No newline at end of file + sync: process(clk) + begin + if rising_edge(clk) then + if (reset = '1') then + stage <= IDLE; + return_stage <= IDLE; + opcode <= NOP; + message_type <= NONE; + string_content <= DOMAIN_TAG; + mem_stage <= IDLE; + flags <= (others => '0'); + src_port <= (others => '0'); + src_addr <= (others => '0'); + src_entityid <= (others => '0'); + dest_entityid <= (others => '0'); + parameter_end <= (others => '0'); + string_length <= (others => '0'); + endpoint_mask <= (others => '0'); + endpoint_match <= (others => '0'); + endpoint_unmatch <= (others => '0'); + def_addr <= (others => '0'); + meta_addr <= (others => '0'); + def_port <= (others => '0'); + meta_port <= (others => '0'); + extra_flags <= (others => '0'); + mem_addr_base <= (others => '0'); + mem_addr <= (others => '0'); + addr_res <= (others => '0'); + last_addr <= (others => '0'); + update_participant_flags <= (others => '0'); + endpoint_mask_array <= (others => (others => '0')); + lease_duration <= (others => (others => '0')); + deadline <= (others => (others => '0')); + announcement_time <= (others => (others => '0')); + heartbeat_time <= (others => (others => '0')); + mem_seq_nr <= (others => (others => '0')); + next_seq_nr <= (others => (others => '0')); + first_seq_nr <= (others => (others => '0')); + last_seq_nr <= (others => (others => '0')); + auto_live_seq_nr <= convert_to_double_word(to_unsigned(2, 64)); + man_live_seq_nr <= convert_to_double_word(to_unsigned(1, 64)); + live_gap_start <= convert_to_double_word(to_unsigned(2, 64)); + live_gap_end <= convert_to_double_word(to_unsigned(1, 64)); + mem_participant_data <= ZERO_PARTICIPANT_DATA; + cnt <= 0; + participant_data_cnt <= 0; + publisher_data_cnt <= 0; + subscriber_data_cnt <= 0; + mem_cnt <= 0; + seq_prc_done <= '0'; + participant_match <= '0'; + is_subscriber <= '0'; + is_meta_addr <= '0'; + expects_inline_qos_set <= '0'; + is_orphan_search <= '0'; + stale_check <= '0'; + is_live_assert <= '0'; + is_heartbeat_res <= '0'; + else + stage <= stage_next; + return_stage <= return_stage_next; + opcode <= opcode_next; + message_type <= message_type_next; + string_content <= string_content_next; + mem_stage <= mem_stage_next; + flags <= flags_next; + src_port <= src_port_next; + src_addr <= src_addr_next; + src_entityid <= src_entityid_next; + dest_entityid <= dest_entityid_next; + parameter_end <= parameter_end_next; + string_length <= string_length_next; + endpoint_mask <= endpoint_mask_next; + endpoint_match <= endpoint_match_next; + endpoint_unmatch <= endpoint_unmatch_next; + def_addr <= def_addr_next; + meta_addr <= meta_addr_next; + def_port <= def_port_next; + meta_port <= meta_port_next; + extra_flags <= extra_flags_next; + mem_addr_base <= mem_addr_base_next; + mem_addr <= mem_addr_next; + addr_res <= addr_res_next; + last_addr <= last_addr_next; + update_participant_flags <= update_participant_flags_next; + endpoint_mask_array <= endpoint_mask_array_next; + lease_duration <= lease_duration_next; + deadline <= deadline_next; + announcement_time <= announcement_time_next; + heartbeat_time <= heartbeat_time_next; + mem_seq_nr <= mem_seq_nr_next; + next_seq_nr <= next_seq_nr_next; + first_seq_nr <= first_seq_nr_next; + last_seq_nr <= last_seq_nr_next; + auto_live_seq_nr <= auto_live_seq_nr_next; + man_live_seq_nr <= man_live_seq_nr_next; + live_gap_start <= live_gap_start_next; + live_gap_end <= live_gap_end_next; + mem_participant_data <= mem_participant_data_next; + cnt <= cnt_next; + participant_data_cnt <= participant_data_cnt_next; + publisher_data_cnt <= publisher_data_cnt_next; + subscriber_data_cnt <= subscriber_data_cnt_next; + mem_cnt <= mem_cnt_next; + seq_prc_done <= seq_prc_done_next; + participant_match <= participant_match_next; + is_subscriber <= is_subscriber_next; + is_meta_addr <= is_meta_addr_next; + expects_inline_qos_set <= expects_inline_qos_set_next; + is_orphan_search <= is_orphan_search_next; + stale_check <= stale_check_next; + is_live_assert <= is_live_assert_next; + is_heartbeat_res <= is_heartbeat_res_next; + end if; + end if; + end process; + +end architecture; diff --git a/src/rtps_package.vhd b/src/rtps_package.vhd index f9c80e8..96ff24f 100644 --- a/src/rtps_package.vhd +++ b/src/rtps_package.vhd @@ -343,7 +343,7 @@ package rtps_package is constant PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE : std_logic_vector(PARTICIPANT_MESSAGE_KIND_WIDTH-1 downto 0) := x"00000002"; --*****CUSTOM***** - constant PARTICIPANT_FRAME_SIZE : natural := 19; + constant PARTICIPANT_FRAME_SIZE : natural := 23; constant ENDPOINT_BITMASK_SIZE : natural := round_div(MAX_ENDPOINTS, 32); constant ENDPOINT_FRAME_SIZE : natural := 4 + ENDPOINT_BITMASK_SIZE; -- Limit Buffer to 32 bit Addresses diff --git a/src/test.vhd b/src/test.vhd index 991db65..ece6a91 100644 --- a/src/test.vhd +++ b/src/test.vhd @@ -4,6 +4,7 @@ use ieee.numeric_std.all; use work.math_pkg.all; use work.test_package.all; +use work.rtps_package.all; -- TODO: Remove alignment logic for RTPS Submessages, since all Submessages are 32-bit aligned -- Checksum has to be checked before @@ -12,26 +13,43 @@ entity test is port ( clk : in std_logic; -- Input Clock reset : in std_logic; -- Synchronous Reset - cnt : in natural; - output : out unsigned(31 downto 0) + input : in std_logic_vector(1 downto 0); + cnt : in natural range 0 to 12; + output : out unsigned(5 downto 0) ); end entity; architecture arch of test is + constant BUILD : std_logic := '0'; - signal output_sig : unsigned(31 downto 0) := (others => '0'); + signal output_sig : unsigned(5 downto 0) := (others => '0'); begin output <= output_sig; - bitmap: process(all) + process(all) begin output_sig <= (others => '0'); - for i in 0 to cnt loop - output_sig(i) <= '1'; - end loop; + if (cnt < PARTICIPANT_DATA.length) then + output_sig <= unsigned(PARTICIPANT_DATA.data(cnt))(5 downto 0); + end if; + +-- case (input) is +-- when "00" => +-- output_sig <= to_unsigned(1,6); +-- when "01" => +-- output_sig <= to_unsigned(2,6); +-- when "10" => +-- output_sig <= to_unsigned(3,6); +-- when "11" => +-- if (BUILD = '1') then +-- output_sig <= to_unsigned(1,6) + cnt; +-- end if; +-- end case; end process; + + end architecture; diff --git a/syn/DE10-Nano/top.qsf b/syn/DE10-Nano/top.qsf index 57a8d30..092a3b9 100644 --- a/syn/DE10-Nano/top.qsf +++ b/syn/DE10-Nano/top.qsf @@ -51,6 +51,7 @@ set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top +set_global_assignment -name VHDL_FILE ../../src/rtps_package.vhd -hdl_version VHDL_2008 set_global_assignment -name VHDL_FILE ../../src/test_package.vhd -hdl_version VHDL_2008 set_global_assignment -name VHDL_FILE ../../src/test.vhd -hdl_version VHDL_2008 set_global_assignment -name VHDL_FILE ../../src/math_pkg.vhd -hdl_version VHDL_2008