diff --git a/src/dds_reader.vhd b/src/dds_reader.vhd index bfa969f..3c9659a 100644 --- a/src/dds_reader.vhd +++ b/src/dds_reader.vhd @@ -26,7 +26,9 @@ entity dds_reader is -- FROM RTPS ENDPOINT start_rtps : in std_logic; opcode_rtps : in HISTORY_CACHE_OPCODE_TYPE; - res_rtps : out HISTORY_CACHE_RESPOSNE_TYPE; + ack_rtps : out std_logic; + done_rtps : out std_logic; + ret_rtps : out HISTORY_CACHE_RESPOSNE_TYPE; data_in_rtps : in std_logic_vector(WORD_WIDTH-1 downto 0); valid_in_rtps : in std_logic; ready_in_rtps : out std_logic; @@ -98,7 +100,7 @@ architecture arch of dds_reader is -- Highest Instance Memory Address constant INSTANCE_MEMORY_MAX_ADDRESS: unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(INSTANCE_MEMORY_SIZE-1, INSTANCE_MEMORY_ADDR_WIDTH); -- Highest Instance Frame Address - constant MAX_INSTANCE_ADDRESS : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := INSTANCE_MEMORY_MAX_ADDRESS - INSTANCE_FRAME_SIZE + 1; + constant MAX_INSTANCE_ADDRESS : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := INSTANCE_MEMORY_MAX_ADDRESS - INSTANCE_FRAME_SIZE + 1; -- Address pointing to the beginning of the first Instance Data Frame constant FIRST_INSTANCE_ADDRESS : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); @@ -146,7 +148,8 @@ architecture arch of dds_reader is type STAGE_TYPE is (IDLE, UNKNOWN_OPERATION, ADD_SAMPLE_INFO, ADD_PAYLOAD_ADDRESS, ADD_PAYLOAD, NEXT_PAYLOAD_SLOT, ALIGN_PAYLOAD, GET_KEY_HASH, INITIATE_INSTANCE_SEARCH, FILTER_STAGE, UPDATE_INSTANCE, FINALIZE_PAYLOAD, PRE_SAMPLE_FINALIZE, FIND_POS, FIX_POINTERS, FINALIZE_SAMPLE, GET_OLDEST_SAMPLE_INSTANCE, FIND_OLDEST_INST_SAMPLE, REMOVE_SAMPLE, POST_SAMPLE_REMOVE, SKIP_ADD_REJECT, SKIP_ADD_DROP, REMOVE_WRITER, REMOVE_STALE_INSTANCE, GET_NEXT_SAMPLE, PRE_CALCULATE, FINALIZE_SAMPLE_INFO, - GET_PAYLOAD, FIND_NEXT_INSTANCE, CHECK_INSTANCE, CHECK_LIFESPAN, GET_SAMPLE_REJECTED_STATUS, GET_REQUESTED_DEADLINE_MISSED_STATUS, CHECK_DEADLINE); + GET_PAYLOAD, FIND_NEXT_INSTANCE, CHECK_INSTANCE, CHECK_LIFESPAN, GET_SAMPLE_REJECTED_STATUS, GET_REQUESTED_DEADLINE_MISSED_STATUS, CHECK_DEADLINE, RESET_SAMPLE_MEMORY, + RESET_PAYLOAD_MEMORY); -- Instance Memory FSM states. Explained below in detail type INST_STAGE_TYPE is (IDLE, SEARCH_INSTANCE_HASH, SEARCH_INSTANCE_ADDR, GET_NEXT_INSTANCE, GET_INSTANCE_DATA, FIND_POS, INSERT_INSTANCE, UPDATE_INSTANCE, REMOVE_INSTANCE, UNMARK_INTANCES); @@ -261,8 +264,6 @@ architecture arch of dds_reader is signal remove_oldest_sample, remove_oldest_sample_next : std_logic := '0'; -- Denotes if the oldest sample of the Instance with 'key_hash' should be removed signal remove_oldest_inst_sample, remove_oldest_inst_sample_next : std_logic := '0'; - -- Denotes if a new Instance was inserted in the Instance Memory - signal added_new_instance, added_new_instance_next : std_logic := '0'; -- Remote Writer Endpoint Bitmap Position signal writer_pos, writer_pos_next : natural range TODO := 0; -- Key Hash Latch @@ -285,6 +286,10 @@ architecture arch of dds_reader is signal sample_addr_latch_3, sample_addr_latch_3_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); -- General Purpose Sample Pointer signal sample_addr_latch_4, sample_addr_latch_4_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Instance Pointer + signal inst_addr_latch_1, inst_addr_latch_1_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Instance Pointer + signal inst_addr_latch_2, inst_addr_latch_2_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); -- General Purpose Long Latch signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); -- Signal used to pass Writer Bitmaps to Instance Memory Process @@ -321,8 +326,6 @@ architecture arch of dds_reader is signal instance_handle, instance_handle_next : INSTANCE_HANDLE_TYPE := (others => '0'); -- Max Samples Latch signal max_samples, max_samples_next : unsigned(MAX_SAMPLES_WIDTH-1 downto 0) := (others => '0'); - -- General Purpose Instance Pointer - signal inst_addr_latch, inst_addr_latch_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); -- Denotes the current length of the Collection signal collection_cnt, collection_cnt_next : unsigned(MAX_SAMPLES_WIDTH-1 downto 0) := (others => '0'); -- Denotes the current pre-calculated length of the Collection @@ -343,6 +346,8 @@ architecture arch of dds_reader is signal unmark_instances, unmark_instances_next : std_logic := '0'; -- Denotes if the READ/TAKE operation does not apply to a specific Instance signal dynamic_next_instance, dynamic_next_instance_next : std_logic := '0'; + -- Signal containing the number of currently stale Instances + signal stale_inst_cnt, stale_inst_cnt_next : natural range 0 to MAX_INSTANCES := 0; -- *COMMUNICATION STATUS* signal status_sig, status_sig_next : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := (others => '0'); @@ -560,6 +565,8 @@ begin -- GET_SAMPLE_REJECTED_STATUS Return Sample Rejected Status -- GET_REQUESTED_DEADLINE_MISSED_STATUS Return Requested Deadline Missed Status -- CHECK_DEADLINE Check and Mark Instances with missed Deadlines + -- RESET_SAMPLE_MEMORY Reset Sample Memory to Empty State + -- RESET_PAYLOAD_MEMORY Reset Payload Memory to Empty State parse_a_prc : process (all) variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0')); variable tmp_bitmap : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1) := (others => '0'); @@ -585,7 +592,6 @@ begin sample_status_info_next <= sample_status_info; remove_oldest_sample_next <= remove_oldest_sample; remove_oldest_inst_sample_next <= remove_oldest_inst_sample; - added_new_instance_next <= added_new_instance; si_sample_state_sig_next <= si_sample_state; si_view_state_sig_next <= si_view_state_sig; si_instance_state_sig_next <= si_instance_state_sig; @@ -630,12 +636,15 @@ begin status_sig_next <= status_sig; cnt2_next <= cnt2; lifespan_next <= lifespan; + stale_inst_cnt_next <= stale_inst_cnt; -- DEFAULT Unregistered inst_opcode <= NOP; - res_rtps <= UNDEFINED; + ret_rtps <= ERROR; return_code_dds <= RETCODE_UNSUPPORTED; ack_dds <= '0'; done_dds <= '0'; + ack_rtps <= '0'; + done_rtps <= '0'; khg_abort <= '0'; inst_op_start <= '0'; khg_last_word_in <= '0'; @@ -664,7 +673,6 @@ begin -- Reset remove_oldest_inst_sample_next <= '0'; remove_oldest_sample_next <= '0'; - added_new_instance_next <= '0'; is_take_next <= '0'; @@ -703,14 +711,17 @@ begin elsif (start_rtps = '1') then case (opcode_rtps) is when ADD_CHANGE => - - res_rtps <= ACK; + -- NOTE: Because we need to first determine the Instance before making the ACCEPT/REJECT/DROP decision + -- we need to latch the cache change first, calculate the Key Hash if necessary, fetch the associated + -- Instance, and then decide on it. This in effect means that we always need an extra slot in sample and + -- payload memory that is only used as a latch. + ack_rtps <= '1'; stage_next <= ADD_SAMPLE_INFO; cur_sample_next <= empty_sample_list_head; cnt_next <= 0; end if; when REMOVE_WRITER => - res_rtps <= ACK; + ack_rtps <= '1'; -- Synthesis Guard if (WITH_KEY) then @@ -720,13 +731,13 @@ begin cnt_next <= 2; else -- Convert Writer Bitmap to SLV - tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + tmp_bitmap := from_endpoint_bitmap_array(inst_data.writer_bitmap); -- Remove Writer tmp_bitmap(to_integer(unsigned(data_in_rtps))) := '0'; -- Convert Back - inst_data_next.writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + inst_data_next.writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); -- NOT_ALIVE_NO_WRITERS Transition if (tmp_bitmap = (tmp_bitmap'range => '0') and inst_data.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) = '0') then @@ -1023,13 +1034,14 @@ begin -- If Key Hash is available, start the Instance Search first if (WITH_KEY and has_key_hash = '1') then stage_next <= INITIATE_INSTANCE_SEARCH; - else - if (has_data = '1' or (WITH_KEY and has_key_hash = '0')) then - stage_next <= ADD_PAYLOAD; - cnt_next <= 0; - else - stage_next <= FILTER_STAGE; - end if; + elsif (has_data = '1') then + stage_next <= ADD_PAYLOAD; + cnt_next <= 0; + elsif (has_data = '0' and (WITH_KEY and has_key_hash = '0')) then + stage_next <= ADD_PAYLOAD; + cnt_next <= 1; + else -- has_data = '0' and (not WITH_KEY) + stage_next <= FILTER_STAGE; end if; end if; when ADD_PAYLOAD => @@ -1038,9 +1050,9 @@ begin -- NOTE: This state is responsible for reading the payload and writing it through to the local payload memory -- and key hash generator (KHG). This state is taken on following cases: -- has_data has_key_hash - -- 1 1 The payload is written to memory - -- 1 0 The payload is written to memory and the KHG at the same time (KHG controls the flow) - -- 0 0 There is no payload to write, but the input contains the key for the KHG + -- 1 1 The payload is written to memory [Entered from INITIATE_INSTANCE_SEARCH] + -- 1 0 The payload is written to memory and the KHG at the same time (KHG controls the flow) [Entered from ADD_PAYLOAD_ADDRESS] + -- 0 0 There is no payload to write, but the input contains the key for the KHG [Entered from ADD_PAYLOAD_ADDRESS] case (cnt) is -- Push to memory @@ -1082,46 +1094,47 @@ begin when 1 => -- Synthesis Guard if (WITH_KEY) then - assert (valid_in_rtps = '1') severity FAILURE; - - khg_valid_in <= '1'; - khg_data_in <= data_in_rtps; - - -- Output Guard - if (khg_ready_in = '1') then - ready_in_rtps <= '1'; - if (has_data = '1') then - -- End of Payload - if (last_word_in_rtps = '1') then - -- End of Payload Slot - if (cnt2 = PAYLOAD_FRAME_SIZE) then + -- Input Guard + if (valid_in_rtps = '1') then + khg_valid_in <= '1'; + khg_data_in <= data_in_rtps; + + -- Output Guard + if (khg_ready_in = '1') then + ready_in_rtps <= '1'; + if (has_data = '1') then + -- End of Payload + if (last_word_in_rtps = '1') then + -- End of Payload Slot + if (cnt2 = PAYLOAD_FRAME_SIZE) then + -- Fetch the Key Hash + stage_next <= GET_KEY_HASH; + cnt_next <= 0; + else + stage_next <= ALIGN_PAYLOAD; + end if; + else + -- End of Payload Slot + if (cnt2 = PAYLOAD_FRAME_SIZE) then + stage_next <= NEXT_PAYLOAD_SLOT; + cnt_next <= 0; + else + -- Next Word + cnt_next <= 0; + cnt2_next <= cnt2 + 1; + end if; + end if; + else + -- End of Payload + if (last_word_in_rtps = '1') then -- Fetch the Key Hash stage_next <= GET_KEY_HASH; cnt_next <= 0; - else - stage_next <= ALIGN_PAYLOAD; - end if; - else - -- End of Payload Slot - if (cnt2 = PAYLOAD_FRAME_SIZE) then - stage_next <= NEXT_PAYLOAD_SLOT; - cnt_next <= 0; else -- Next Word - cnt_next <= 0; - cnt2_next <= cnt2 + 1; + cnt_next <= 1; -- Same Sub-state end if; end if; - else - -- End of Payload - if (last_word_in_rtps = '1') then - -- Fetch the Key Hash - stage_next <= GET_KEY_HASH; - cnt_next <= 0; - else - -- Next Word - cnt_next <= 1; -- Same Sub-state - end if; end if; end if; end if; @@ -1187,10 +1200,10 @@ begin -- Memory Control Flow Guard if (payload_ready_in = '1') then if (WITH_KEY and has_key_hash = '0') then - stage_next <= GET_KEY_HASH; - cnt_next <= 0; + stage_next <= GET_KEY_HASH; + cnt_next <= 0; else - stage_next <= FILTER_STAGE; + stage_next <= FILTER_STAGE; end if; end if; when others => @@ -1224,7 +1237,7 @@ begin inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_DISPOSED_CNT_FLAG or IMF_NO_WRITERS_CNT_FLAG or IMF_IGNORE_DEADLINE_FLAG or IMF_WRITER_BITMAP_FLAG; -- Payload not yet stored - if (has_data = '1') then + if (has_data = '1' and WITH_KEY and has_key_hash = '1') then stage_next <= ADD_PAYLOAD; cnt_next <= 0; else @@ -1237,138 +1250,200 @@ begin -- Wait for Instance Search to finish if (not WITH_KEY or inst_op_done = '1') then - sample_valid_in <= '1'; - sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; - cur_inst_next <= inst_addr_base; -- Instance Found if (not WITH_KEY or inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then - -- Store Instance Address - sample_write_data <= inst_addr_base; - - -- Memory Flow Control Guard - if (sample_ready_in = '1') then - -- TIME_BASED_FILTER QOS - if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time <= inst_data.ignore_deadline) then - -- Drop Change - res_rtps <= ACCEPTED; - stage_next <= IDLE; - -- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE) - elsif (WITH_KEY and MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then - if (HISTORY_QOS = KEEP_LAST_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then - -- Reject Change - res_rtps <= REJECTED; - stage_next <= IDLE; - -- Update Sample Reject Status - status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; - sample_rej_cnt_next <= sample_rej_cnt + 1; - sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; - sample_rej_last_reason_next <= REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT; - sample_rej_last_inst_next <= key_hash; - else - -- Accept Change (Remove Oldest Instance Sample) - remove_oldest_inst_sample_next <= '1'; - res_rtps <= ACCEPTED; - stage_next <= UPDATE_INSTANCE; - end if; - -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) - elsif (empty_sample_list_head = empty_sample_list_tail) then - if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then - -- Reject Change - res_rtps <= REJECTED; - stage_next <= IDLE; - -- Update Sample Reject Status - status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; - sample_rej_cnt_next <= sample_rej_cnt + 1; - sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; - sample_rej_last_reason_next <= REJECTED_BY_SAMPLES_LIMIT; - sample_rej_last_inst_next <= key_hash; - else - -- Accept Change (Remove Oldest Sample) - remove_oldest_sample_next <= '1'; - res_rtps <= ACCEPTED; - stage_next <= UPDATE_INSTANCE; - end if; - else - -- Accept Change - res_rtps <= ACCEPTED; - stage_next <= UPDATE_INSTANCE; - end if; - end if; - else - -- Store Instance Address - sample_write_data <= inst_empty_head; - - -- Memory Flow Control Guard - if (sample_ready_in = '1') then - -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) - if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- Latch Instance Pointer + cur_inst_next <= inst_addr_base; + + -- TIME_BASED_FILTER QOS + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time <= inst_data.ignore_deadline) then + -- Drop Change + done_rtps <= '1'; + ret_rtps <= OK; + stage_next <= IDLE; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE) + elsif (WITH_KEY and MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then + if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then -- Reject Change - res_rtps <= REJECTED; + done_rtps <= '1'; + ret_rtps <= REJECTED; stage_next <= IDLE; -- Update Sample Reject Status status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; sample_rej_cnt_next <= sample_rej_cnt + 1; sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; - sample_rej_last_reason_next <= REJECTED_BY_INSTANCES_LIMIT; + sample_rej_last_reason_next <= REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT; sample_rej_last_inst_next <= key_hash; - -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) - elsif (empty_sample_list_head = empty_sample_list_tail) then - if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then - -- Reject Change - res_rtps <= REJECTED; + else + -- Accept Change (Remove Oldest Instance Sample) + remove_oldest_inst_sample_next <= '1'; + done_rtps <= '1'; + ret_rtps <= OK; + stage_next <= UPDATE_INSTANCE; + end if; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) + elsif (empty_sample_list_head = empty_sample_list_tail) then + if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then + -- Reject Change + done_rtps <= '1'; + ret_rtps <= REJECTED; + stage_next <= IDLE; + -- Update Sample Reject Status + status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; + sample_rej_cnt_next <= sample_rej_cnt + 1; + sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; + sample_rej_last_reason_next <= REJECTED_BY_SAMPLES_LIMIT; + sample_rej_last_inst_next <= key_hash; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + done_rtps <= '1'; + ret_rtps <= OK; + stage_next <= UPDATE_INSTANCE; + end if; + else + -- Accept Change + done_rtps <= '1'; + ret_rtps <= OK; + stage_next <= UPDATE_INSTANCE; + end if; + else -- (only WITH_KEY) + -- Latch Instance Pointer + cur_inst_next <= inst_empty_head; + + -- Only Insert Sample/Instance if Instance is ALIVE + if (sample_status_info(SSI_DISPOSED_FLAG) /= '1' and sample_status_info(SSI_UNREGISTERED_FLAG) /= '1' and sample_status_info(SSI_FILTERED_FLAG) /= '1') then + -- NOTE: Ignore Sample if Sample unregisters/disposes an instance that we do not have + -- Drop Change + done_rtps <= '1'; + ret_rtps <= OK; + -- DONE + stage_next <= IDLE; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) + elsif (empty_sample_list_head = empty_sample_list_tail) then + if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then + -- Reject Change + done_rtps <= '1'; + ret_rtps <= REJECTED; + stage_next <= IDLE; + -- Update Sample Reject Status + status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; + sample_rej_cnt_next <= sample_rej_cnt + 1; + sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; + sample_rej_last_reason_next <= REJECTED_BY_SAMPLES_LIMIT; + sample_rej_last_inst_next <= key_hash; + else + -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) + if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- No Stale Instances available + if (stale_inst_cnt = 0) then + -- Reject Change + done_rtps <= '1'; + ret_rtps <= REJECTED; + -- DONE + stage_next <= IDLE; + -- Update Sample Reject Status + status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; + sample_rej_cnt_next <= sample_rej_cnt + 1; + sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; + sample_rej_last_reason_next <= REJECTED_BY_INSTANCES_LIMIT; + sample_rej_last_inst_next <= key_hash; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + done_rtps <= '1'; + ret_rtps <= OK; + + -- Remove Stale Instance and Insert Instance + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; + stage_next <= REMOVE_STALE_INSTANCE; + cnt_next <= 0; + end if; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + done_rtps <= '1'; + ret_rtps <= OK; + + -- Insert New Instance + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + deadline <= (time + TIME_BASED_FILTER_QOS) when (TIME_BASED_FILTER_QOS /= DURATION_ZERO) else TIME_INVALID; + tmp_bitmap := (writer_pos => '1', others => '0'); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); + + if (has_data = '1') then + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + else + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0; + end if; + end if; + end if; + else + -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) + if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- No Stale Instances available + if (stale_inst_cnt = 0) then + -- Reject Change + done_rtps <= '1'; + ret_rtps <= REJECTED; + -- DONE stage_next <= IDLE; -- Update Sample Reject Status status_sig_next(SAMPLE_REJECTED_STATUS) <= '1'; sample_rej_cnt_next <= sample_rej_cnt + 1; sample_rej_cnt_change_next <= sample_rej_cnt_change + 1; - sample_rej_last_reason_next <= REJECTED_BY_SAMPLES_LIMIT; + sample_rej_last_reason_next <= REJECTED_BY_INSTANCES_LIMIT; sample_rej_last_inst_next <= key_hash; else - -- Accept Change (Remove Oldest Sample) - remove_oldest_sample_next <= '1'; - res_rtps <= ACCEPTED; + -- Accept Change + done_rtps <= '1'; + ret_rtps <= OK; - -- Only Insert Sample/Instance if Instance is ALIVE - if (sample_status_info(SSI_DISPOSED_FLAG) /= '1' and sample_status_info(SSI_UNREGISTERED_FLAG) /= '1' and sample_status_info(SSI_FILTERED_FLAG) /= '1') then - -- Insert New Instance - inst_op_start <= '1'; - inst_opcode <= INSERT_INSTANCE; - - added_new_instance_next <= '1'; - - if (has_data = '1') then - stage_next <= FINALIZE_PAYLOAD; - cnt_next <= 0; - else - stage_next <= PRE_SAMPLE_FINALIZE; - cnt_next <= 0; - end if; + -- Insert New Instance + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others = '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + deadline <= (time + TIME_BASED_FILTER_QOS) when (TIME_BASED_FILTER_QOS /= DURATION_ZERO) else TIME_INVALID; + tmp_bitmap := (writer_pos => '1', others => '0'); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); + + if (has_data = '1') then + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; else - -- Drop Change - stage_next <= IDLE; + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0; end if; end if; else -- Accept Change - res_rtps <= ACCEPTED; + done_rtps <= '1'; + ret_rtps <= OK; - -- Only Insert Sample/Instance if Instance is ALIVE - if (sample_status_info(SSI_DISPOSED_FLAG) /= '1' and sample_status_info(SSI_UNREGISTERED_FLAG) /= '1' and sample_status_info(SSI_FILTERED_FLAG) /= '1') then - -- Insert New Instance - inst_op_start <= '1'; - inst_opcode <= INSERT_INSTANCE; - - if (has_data = '1') then - stage_next <= FINALIZE_PAYLOAD; - cnt_next <= 0; - else - stage_next <= PRE_SAMPLE_FINALIZE; - cnt_next <= 0; - end if; + -- Insert New Instance + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + deadline <= (time + TIME_BASED_FILTER_QOS) when (TIME_BASED_FILTER_QOS /= DURATION_ZERO) else TIME_INVALID; + tmp_bitmap := (writer_pos => '1', others => '0'); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); + + if (has_data = '1') then + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; else - -- Drop Change - stage_next <= IDLE; + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0; end if; end if; end if; @@ -1378,53 +1453,53 @@ begin -- Memory Operation Guard if (not WITH_KEY or inst_op_done = '1') then -- DEFAULT - tmp_update := (others => '0'); + -- STATUS INFO (LIVELINESS) + if (WITH_KEY) then + tmp_update := IMF_STATUS_FLAG; + status_info_update <= inst_data.status_info; + status_info_update(ISI_LIVELINESS_FLAG) <= '1'; + else + inst_data_next.status_info(ISI_LIVELINESS_FLAG) <= '1'; + end if; + -- Instance DISPOSED if (sample_status_info(SSI_DISPOSED_FLAG) = '1') then -- ALIVE -> NOT_ALIVE_DISPOSED Transition if (inst_data.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) /= '1') then - -- STATUS INFO + -- STATUS INFO (INSTANCE STATE) -- Synthesis Guard if (WITH_KEY) then - tmp_update <= tmp_update or IMF_STATUS_FLAG; - status_info_update <= inst_data.status_info; - status_info_update(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '1'; - status_info_update(ISI_LIVELINESS_FLAG) <= '1'; + status_info_update(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '1'; else - inst_data_next.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '1'; - inst_data_next.status_info(ISI_LIVELINESS_FLAG) <= '1'; + inst_data_next.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '1'; end if; end if; -- Instance UNREGISTERED elsif (sample_status_info(SSI_UNREGISTERED_FLAG) = '1') then -- WRITER BITMAP -- Convert Writer Bitmap to SLV - tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + tmp_bitmap := from_endpoint_bitmap_array(inst_data.writer_bitmap); -- Remove Writer tmp_bitmap(writer_pos) := '0'; -- Convert Back -- Synthesis Guard if (WITH_KEY) then - writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); tmp_update := tmp_update or IMF_WRITER_BITMAP_FLAG; else - inst_data_next.writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + inst_data_next.writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); end if; -- ALIVE -> NOT_ALIVE_NO_WRITERS Transition - if (inst_data.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) /= '1' and tmp_bitmap = (tmp_bitmap => '0')) then - -- STATUS INFO + if (inst_data.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) /= '1' and tmp_bitmap = (tmp_bitmap'range => '0')) then + -- STATUS INFO (INSTANCE STATE) -- Synthesis Guard if (WITH_KEY) then - tmp_update <= tmp_update or IMF_STATUS_FLAG; - status_info_update <= inst_data.status_info; - status_info_update(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; - status_info_update(ISI_LIVELINESS_FLAG) <= '1'; + status_info_update(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; else inst_data_next.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; - inst_data_next.status_info(ISI_LIVELINESS_FLAG) <= '1'; end if; end if; -- Instance ALIVE/FILTERED @@ -1432,27 +1507,25 @@ begin -- STATUS INFO -- Synthesis Guard if (WITH_KEY) then - tmp_update <= tmp_update or IMF_STATUS_FLAG; - status_info_update <= inst_data.status_info; - status_info_update(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '0'; - status_info_update(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; - status_info_update(ISI_LIVELINESS_FLAG) <= '1'; + status_info_update(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '0'; + status_info_update(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; else - inst_data_next.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '0'; - inst_data_next.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; - inst_data_next.status_info(ISI_LIVELINESS_FLAG) <= '1'; + inst_data_next.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) <= '0'; + inst_data_next.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; end if; - -- GENERATION COUNTERS + -- GENERATION COUNTERS / VIEW STATE -- NOT_ALIVE_DISPOSED -> ALIVE Transition if (inst_data.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) = '1') then -- Synthesis Guard if (WITH_KEY) then tmp_update := tmp_update or IMF_DISPOSED_CNT_FLAG; gen_cnt <= inst_data.disposed_gen_cnt + 1; + status_info_update(ISI_VIEW_FLAG) <= '0'; else inst_data_next.disposed_gen_cnt <= inst_data.disposed_gen_cnt + 1; + inst_data_next.status_info(ISI_VIEW_FLAG) <= '0'; end if; -- NOT_ALIVE_NO_WRITERS -> ALIVE Transition elsif (inst_data.status_info(ISI_NOT_ALIVE_NO_WRITERS_FLAG) = '1') then @@ -1460,14 +1533,16 @@ begin if (WITH_KEY) then tmp_update := tmp_update or IMF_NO_WRITERS_CNT_FLAG; gen_cnt <= inst_data.no_writers_gen_cnt + 1; + status_info_update(ISI_VIEW_FLAG) <= '0'; else inst_data_next.no_writers_gen_cnt <= inst_data.no_writers_gen_cnt + 1; + inst_data_next.status_info(ISI_VIEW_FLAG) <= '0'; end if; end if; -- WRITER BITMAP -- Convert Writer Bitmap to SLV - tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + tmp_bitmap := from_endpoint_bitmap_array(inst_data.writer_bitmap); -- Write if Writer New for Instance if (tmp_bitmap(writer_pos) /= '1') then -- Insert Writer @@ -1475,24 +1550,21 @@ begin -- Convert Back -- Synthesis Guard if (WITH_KEY) then - writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); tmp_update := tmp_update or IMF_WRITER_BITMAP_FLAG; else - inst_data_next.writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + inst_data_next.writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); end if; end if; end if; -- INSTANCE SAMPLE COUNT - -- NOTE: Ignored when remove_oldest_inst_sample, since it will be decremented again. (Stays same) - if (remove_oldest_inst_sample = '0') then - -- Synthesis Guard - if (WITH_KEY) then - tmp_update := tmp_update or IMF_SAMPLE_CNT_FLAG; - sample_cnt <= inst_data.sample_cnt + 1; - else - inst_data_next.sample_cnt <= inst_data.sample_cnt + 1; - end if; + -- Synthesis Guard + if (WITH_KEY) then + tmp_update := tmp_update or IMF_SAMPLE_CNT_FLAG; + sample_cnt <= inst_data.sample_cnt + 1; + else + inst_data_next.sample_cnt <= inst_data.sample_cnt + 1; end if; -- IGNORE DEADLINE @@ -1508,6 +1580,15 @@ begin -- Synthesis Guard if (WITH_KEY) then + -- STALE INSTANCE COUNT + -- Instance was Stale + if (inst_data.sample_cnt = 0 and inst_data.writer_bitmap = ZERO_ENDPOINT_BITMAP_ARRAY) then + assert (stale_inst_cnt /= 0) severity FAILURE; + -- NOTE: The UPDATE_INSTANCE state is only taken if a new Sample is added to an existing Instance. + -- Since Instances with Samples are not stale, we have to unmark the Instance. + stale_inst_cnt_next <= stale_inst_cnt - 1; + end if; + inst_op_start <= '1'; inst_opcode <= UPDATE_INSTANCE; inst_mem_fields <= tmp_update; @@ -1600,11 +1681,13 @@ begin cnt_next <= 0; elsif (DESTINATION_ORDER_QOS = BY_RECEPTION_TIMESTAMP_DESTINATION_ORDER_QOS) then stage_next <= FIX_POINTERS; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; prev_sample_next <= newest_sample; cur_sample_next <= newest_sample; cnt_next <= 0; else stage_next <= FIND_POS; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; prev_sample_next <= newest_sample; cur_sample_next <= newest_sample; cnt_next <= 0; @@ -1753,8 +1836,19 @@ begin if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; - -- Previous Pointer + -- Instance Pointer when 1 => + -- Write Instance Pointer + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_write_data <= cur_inst; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Previous Pointer + when 2 => -- Write Previous Pointer sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; @@ -1765,7 +1859,7 @@ begin cnt_next <= cnt + 1; end if; -- Next Pointer - when 2 => + when 3 => -- Write Next Pointer sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; @@ -1777,7 +1871,7 @@ begin end if; -- READ Next (Empty) Sample - when 3 => + when 4 => sample_ready_out <= '1'; -- Memory Flow Control Guard @@ -1799,27 +1893,7 @@ begin lifespan_next <= lifespan; end if; - -- NOTE: added_new_instance and remove_oldest_sample are NOT mutual exclusive, but Instance Removal takes precedence. - - -- New Instance was added, and Instance Memory is Full - if (WITH_KEY and added_new_instance = '1' and inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then - -- Memory Operation Guard - if (inst_op_done = '1') then - inst_op_start <= '1'; - inst_opcode <= GET_FIRST_INSTANCE; - inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; - - -- NOTE: Instances are only removed in two occasions: - -- * A new instance is added, and the instance memory gets full - -- * A Sample is removed, making an instance eligible for deletion, while the - -- instance memory is full. - -- The combination of both cases allows to search and remove instances only when needed. - - stage_next <= REMOVE_STALE_INSTANCE; - else - cnt_next <= cnt; -- Keep State - end if; - elsif (WITH_KEY and remove_oldest_inst_sample = '1') then + if (WITH_KEY and remove_oldest_inst_sample = '1') then cur_sample <= oldest_sample; stage_next <= FIND_OLDEST_INST_SAMPLE; elsif (remove_oldest_sample = '1') then @@ -2012,19 +2086,19 @@ begin empty_sample_list_tail_next <= cur_sample; -- Current Sample is Newest (Occupied List Tail) - if (next_sample = MAX_SAMPLE_ADDRESS) then + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then assert (cur_sample = newest_sample) report "Next Sample is MAX_ADDR, but cur_sample /= newest_sample" severity FAILURE; -- Fix Newest Pointer newest_sample_next <= prev_sample; -- Current Sample is Oldest (List Head) - if (prev_sample = MAX_SAMPLE_ADDRESS) then + if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE; assert (newest_sample = oldest_sample) report "Previous and Next Sample is MAX_ADDR, but cur_sample /= newest_sample /= oldest_sample" severity FAILURE; -- Fix Oldest Pointer - oldest_sample_next <= MAX_SAMPLE_ADDRESS; + oldest_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; -- NOTE: Sample Memory Empty (newest_sample also set to MAX_ADDR) cnt_next <= cnt + 3; -- Skip next 2 steps @@ -2045,11 +2119,11 @@ begin -- Memory Flow Control Guard if (sample_ready_in = '1') then -- Current Sample is oldest sample (List Head) - if (prev_sample = MAX_SAMPLE_ADDRESS) then + if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE; -- Fix Oldest Pointer - oldest_sample_next <= MAX_SAMPLE_ADDRESS; + oldest_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; cnt_next <= cnt + 2; -- Skip next step else @@ -2075,10 +2149,10 @@ begin if (sample_valid_out = '1') then cur_payload_next <= sample_read_data; -- Sample has no Data - if (sample_read_data = MAX_PAYLOAD_ADDRESS) then + if (sample_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then stage_next <= POST_SAMPLE_REMOVE; -- Payload Memory Full - elsif (empty_payload_list_head = MAX_PAYLOAD_ADDRESS) then + elsif (empty_payload_list_head = PAYLOAD_MEMORY_MAX_ADDRESS) then empty_payload_list_head_next <= sample_read_data; stage_next <= POST_SAMPLE_REMOVE; @@ -2104,7 +2178,7 @@ begin -- Memory Flow Control Guard if (payload_valid_out = '1') then -- Found Empty List Tail - if (payload_read_data = MAX_PAYLOAD_ADDRESS) then + if (payload_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then cnt_next <= cnt + 1; else cur_payload_next <= payload_read_data; @@ -2128,24 +2202,19 @@ begin when POST_SAMPLE_REMOVE => -- Memory Operation Guard if (not WITH_KEY or inst_op_done = '1') then - -- No Instance Change on remove_oldest_inst_sample - if (not WITH_KEY or remove_oldest_inst_sample /= '1') then - tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); - -- Instance obsolete and Instance Memory Full - if (WITH_KEY and inst_data.sample_cnt = 1 and tmp_bitmap = (tmp_bitmap'range => '0') and inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then - inst_op_start <= '1'; - inst_opcode <= REMOVE_INSTANCE; - else - -- Synthesis Guard - if (WITH_KEY) then - inst_op_start <= '1'; - inst_opcode <= UPDATE_INSTANCE; - inst_mem_fields <= IMF_SAMPLE_CNT_FLAG; - sample_cnt <= inst_data.sample_cnt - 1; - else - inst_data_nextsample_cnt <= inst_data.sample_cnt - 1; - end if; + -- Synthesis Guard + if (WITH_KEY) then + -- Stale Instance Update + if (inst_data.sample_cnt = 1 and inst_data.writer_bitmap = ZERO_ENDPOINT_BITMAP_ARRAY) then + stale_inst_cnt_next <= stale_inst_cnt - 1; end if; + + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + inst_mem_fields <= IMF_SAMPLE_CNT_FLAG; + sample_cnt <= inst_data.sample_cnt - 1; + else + inst_data_next.sample_cnt <= inst_data.sample_cnt - 1; end if; if (is_take = '1') then @@ -2180,7 +2249,8 @@ begin end if; -- REJECT SAMPLE when 1 => - res_rtps <= REJECTED; + done_rtps <= '1'; + ret_rtps <= REJECTED; stage_next <= IDLE; -- TODO: Add a new Reject Status? (E.g. REJECTED_BY_PAYLOAD_LIMIT?, or UNSPECIFIED REJECT?) -- Update Sample Reject Status @@ -2202,8 +2272,9 @@ begin cnt_next <= 1; end if; -- DROP SAMPLE - when 1 => - res_rtps <= ACCEPTED; + when 1 => + done_rtps <= '1'; + ret_rtps <= OK; stage_next <= IDLE; when others => null; @@ -2221,7 +2292,7 @@ begin stage_next <= IDLE; else -- Convert Writer Bitmap to SLV - tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + tmp_bitmap := from_endpoint_bitmap_array(inst_data.writer_bitmap); -- Remove Writer tmp_bitmap(writer_pos) := '0'; @@ -2229,12 +2300,12 @@ begin -- NOTE: writer_bitmap is not latched, since the memory process is latching it at the -- same clock cycle. -- Convert Back - writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); -- NOT_ALIVE_NO_WRITERS Transition if (tmp_bitmap = (tmp_bitmap'range => '0') and inst_data.status_info(ISI_NOT_ALIVE_DISPOSED_FLAG) = '0') then - status_info_update <= inst_data.status_info; - status_info_update(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; + status_info_update <= inst_data.status_info; + status_info_update(ISI_NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; inst_op_start <= '1'; inst_opcode <= UPDATE_INSTANCE; inst_mem_fields <= IMF_STATUS_FLAG or IMF_WRITER_BITMAP_FLAG; @@ -2244,19 +2315,24 @@ begin inst_mem_fields <= IMF_WRITER_BITMAP_FLAG; end if; + -- Update Stale Instance Count + if (tmp_bitmap = (tmp_bitmap'range => '0') and inst_data.sample_cnt = 0) then + stale_inst_cnt_next <= stale_inst_cnt + 1; + end if; + -- Continue cnt_next <= 1; end if; when 1 => inst_op_start <= '1'; inst_opcode <= GET_NEXT_INSTANCE; - inst_mem_fields <= IMF_STATUS_FLAG or IMF_WRITER_BITMAP_FLAG; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; stage_next <= REMOVE_WRITER; cnt_next <= 0; when 2 => inst_op_start <= '1'; inst_opcode <= GET_FIRST_INSTANCE; - inst_mem_fields <= IMF_STATUS_FLAG or IMF_WRITER_BITMAP_FLAG; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; stage_next <= REMOVE_WRITER; cnt_next <= 0; when others => @@ -2269,39 +2345,55 @@ begin if (WITH_KEY) then -- Wait for Instance Data if (inst_op_done = '1') then - -- Iterated through all Instances - if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then - if (remove_oldest_inst_sample = '1') then - cur_sample <= oldest_sample; - stage_next <= FIND_OLDEST_INST_SAMPLE; - else - -- DONE - stage_next <= IDLE; - end if; - else - -- Convert Writer Bitmap to SLV - tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); - - -- Found Stale Instance (No Samples and No Active Writers) - if (inst_data.sample_cnt = 0 and tmp_bitmap = (tmp_bitmap'range => '0')) then - -- Remove Stale Instance - inst_op_start <= '1'; - inst_opcode <= REMOVE_INSTANCE; - - if (remove_oldest_inst_sample = '1') then - cur_sample <= oldest_sample; - stage_next <= FIND_OLDEST_INST_SAMPLE; - else - -- DONE + case (cnt) is + -- Find and Remove First Stale Instance + when 0 => + -- Iterated through all Instances + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + -- NOTE: We should enter this state only if there is at least one stale Instance to be removed, so we should never enter this branch. + assert FALSE severity FAILURE; stage_next <= IDLE; + else + -- Found Stale Instance (No Samples and No Active Writers) + if (inst_data.sample_cnt = 0 and inst_data.writer_bitmap = ZERO_ENDPOINT_BITMAP_ARRAY) then + -- Remove Stale Instance + inst_op_start <= '1'; + inst_opcode <= REMOVE_INSTANCE; + -- Update Stale Instance Count + stale_inst_cnt_next <= stale_inst_cnt - 1; + + cnt_next <= cnt + 1; + + else + -- Continue Search + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; + end if; end if; - else - -- Continue Search - inst_op_start <= '1'; - inst_opcode <= GET_NEXT_INSTANCE; - inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; - end if; - end if; + -- Insert New Instance + when 1 => + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + deadline <= (time + TIME_BASED_FILTER_QOS) when (TIME_BASED_FILTER_QOS /= DURATION_ZERO) else TIME_INVALID; + tmp_bitmap := (writer_pos => '1', others => '0'); + writer_bitmap <= to_endpoint_bitmap_array(tmp_bitmap); + + -- Latch Instance Pointer + cur_inst_next <= inst_empty_head; + + if (has_data = '1') then + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + else + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0; + end if; + when others => + null; + end case; end if; end if; when GET_NEXT_SAMPLE => @@ -2852,7 +2944,7 @@ begin -- Memory Operation Guard if (inst_op_done = '1') then inst_op_start <= '1'; - inst_opcode <= GET_INSTANCE_DATA_2; + inst_opcode <= GET_INSTANCE; inst_mem_fields <= IMF_STATUS_FLAG; inst_addr_update <= next_inst; cnt_next <= cnt + 1; @@ -3108,6 +3200,11 @@ begin when GET_PAYLOAD => -- Precondition: cur_payload set, sample_status_info set + -- NOTE: We are using the Burst Capability of the Memory Controller as a FIFO which we + -- fill and the output is directly reading. cnt is switching the memory reading states, + -- cnt2 signals the offset of the payload read, and cnt3 signals how many Bytes have been + -- requested but not yet claimed (i.e. how many Bytes are in the FIFO). + -- DEFAULT tmp_bool := FALSE; @@ -3201,7 +3298,7 @@ begin -- DDS Read if (ready_out_dds = '1') then payload_ready_out <= '1'; - -- NOTE: We are using the temp Bool variable to denote if there is an increment + -- NOTE: We are using the tmp_bool variable to signal if there is an increment -- on the same clock cycle. -- Increment in same clock cycle if (tmp_bool) then @@ -3424,8 +3521,18 @@ begin if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; - -- READ Next Sample + -- GET Instance Pointer when 3 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Control Flow Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Next Sample + when 4 => sample_ready_out <= '1'; -- Memory Control Flow Guard @@ -3434,7 +3541,7 @@ begin cnt_next <= cnt + 1; end if; -- READ Lifespan 1/2 - when 4 => + when 5 => sample_ready_out <= '1'; -- Memory Control Flow Guard @@ -3443,7 +3550,7 @@ begin cnt_next <= cnt + 1; end if; -- READ Lifespan 2/2 - when 3 => + when 6 => sample_ready_out <= '1'; -- Memory Control Flow Guard @@ -3452,10 +3559,9 @@ begin -- Sample Lifespan Expired if (tmp_dw /= TIME_INVALID and time >= tmp_dw) then - -- Remove Sample - stage_next <= REMOVE_SAMPLE; - cnt_next <= 0; + cnt_next <= cnt + 1; else + sample_abort_read <= '1'; -- Update Check Time if (tmp_dw /= TIME_INVALID and tmp_dw < lifespan_time) then @@ -3473,94 +3579,159 @@ begin end if; end if; end if; + -- READ Instance Pointer + when 7 => + -- Memory Operation Guard + if (inst_op_done = '1') then + sample_ready_out <= '1'; + + -- Memory Control Flow Guard + if (sample_valid_out = '1') then + -- Fetch Instance Data + inst_op_start <= '1'; + inst_opcode <= GET_INSTANCE; + inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_WRITER_BITMAP_FLAG; + inst_addr_update <= sample_read_data; + + -- Remove Sample + stage_next <= REMOVE_SAMPLE; + cnt_next <= 0; + end if; + end if; when others => null; end case; when GET_SAMPLE_REJECTED_STATUS => - if (ready_out_dds = '1') then - cnt_next <= cnt + 1; - valid_out_dds <= '1'; - - case (cnt) is - -- Total Count - when 0 => - data_out_dds <= sample_rej_cnt; - -- Total Count Change - when 1 => - data_out_dds <= sample_rej_cnt_change; + case (cnt) is + -- Total Count + when 0 => + data_out_dds <= sample_rej_cnt; + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Total Count Change + when 1 => + data_out_dds <= sample_rej_cnt_change; + valid_out_dds <= '1'; + if (ready_out_dds = '1') then -- Reset sample_rej_cnt_change_next <= (others => '0'); - -- Last Reason - when 2 => - data_out_dds <= sample_rej_last_reason; + cnt_next <= cnt + 1; + end if; + -- Last Reason + when 2 => + data_out_dds <= sample_rej_last_reason; + valid_out_dds <= '1'; + if (ready_out_dds = '1') then -- Reset sample_rej_last_reason <= NOT_REJECTED; - -- Last Instance Handle 1/4 - when 3 => - data_out_dds <= sample_rej_last_inst(0); - -- Last Instance Handle 2/4 - when 4 => - data_out_dds <= sample_rej_last_inst(1); - -- Last Instance Handle 3/4 - when 5 => - data_out_dds <= sample_rej_last_inst(2); - -- Last Instance Handle 4/4 - when 6 => - data_out_dds <= sample_rej_last_inst(3); - last_word_out_dds <= '1'; - -- Return Code - when 7 => - done_dds <= '1'; - return_code_dds <= RETCODE_OK; + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 1/4 + when 3 => + data_out_dds <= sample_rej_last_inst(0); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 2/4 + when 4 => + data_out_dds <= sample_rej_last_inst(1); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 3/4 + when 5 => + data_out_dds <= sample_rej_last_inst(2); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 4/4 + when 6 => + data_out_dds <= sample_rej_last_inst(3); + valid_out_dds <= '1'; + last_word_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Return Code + when 7 => + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + if (ready_out_dds = '1') then -- Reset status_sig_next(SAMPLE_REJECTED_STATUS) <= '0'; -- DONE stage_next <= IDLE; - when others => - null; - end case; - end if; + end if; + when others => + null; + end case; when GET_REQUESTED_DEADLINE_MISSED_STATUS => - if (ready_out_dds = '1') then - cnt_next <= cnt + 1; - valid_out_dds <= '1'; - - case (cnt) is - -- Total Count - when 0 => - data_out_dds <= deadline_miss_cnt; - -- Total Count Change - when 1 => - data_out_dds <= deadline_miss_cnt_change; + case (cnt) is + -- Total Count + when 0 => + data_out_dds <= deadline_miss_cnt; + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Total Count Change + when 1 => + data_out_dds <= deadline_miss_cnt_change; + valid_out_dds <= '1'; + if (ready_out_dds = '1') then -- Reset deadline_miss_cnt_change_next <= (others => '0'); - -- Last Instance Handle 1/4 - when 2 => - data_out_dds <= deadline_miss_last_inst(0); - -- Last Instance Handle 2/4 - when 3 => - data_out_dds <= deadline_miss_last_inst(1); - -- Last Instance Handle 3/4 - when 4 => - data_out_dds <= deadline_miss_last_inst(2); - -- Last Instance Handle 4/4 - when 5 => - data_out_dds <= deadline_miss_last_inst(3); - last_word_out_dds <= '1'; - -- Return Code - when 6 => - done_dds <= '1'; - return_code_dds <= RETCODE_OK; + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 1/4 + when 2 => + data_out_dds <= deadline_miss_last_inst(0); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 2/4 + when 3 => + data_out_dds <= deadline_miss_last_inst(1); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 3/4 + when 4 => + data_out_dds <= deadline_miss_last_inst(2); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 4/4 + when 5 => + data_out_dds <= deadline_miss_last_inst(3); + valid_out_dds <= '1'; + last_word_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Return Code + when 6 => + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + if (ready_out_dds = '1') then -- Reset status_sig_next(REQUESTED_DEADLINE_MISSED_STATUS) <= '0'; -- DONE stage_next <= IDLE; - when others => - null; - end case; - end if; + end if; + when others => + null; + end case; when CHECK_DEADLINE => -- Synthesis Guard if (WITH_KEY) then @@ -3699,6 +3870,7 @@ begin -- UPDATE_INSTANCE See Memory OPCODE Description -- REMOVE_INSTANCE See Memory OPCODE Description -- UNMARK_INTANCES See Memory OPCODE Description + -- RESET_MEMORY Reset Endpoint Memory to Empty State inst_ctrl_prc : process(all) begin -- DEFAULT Registered @@ -3802,6 +3974,7 @@ begin inst_addr_base_next <= inst_occupied_head; -- Get Instance Data inst_stage_next <= GET_INSTANCE_DATA; + inst_data_next <= ZERO_INSTANCE_DATA; if check_mask(inst_mem_fields.field_flag,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_mem_fields.field_flag,IMF_STATUS_FLAG) then @@ -3839,6 +4012,7 @@ begin inst_addr_base_next <= inst_addr_update; -- Get Instance Data inst_stage_next <= GET_INSTANCE_DATA; + inst_data_next <= ZERO_INSTANCE_DATA; if check_mask(inst_mem_fields.field_flag,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_mem_fields.field_flag,IMF_STATUS_FLAG) then @@ -4026,6 +4200,7 @@ begin else -- Get Instance Data inst_stage_next <= GET_INSTANCE_DATA; + inst_data_next <= ZERO_INSTANCE_DATA; if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then @@ -4076,6 +4251,7 @@ begin if (inst_read_data = inst_latch_data.addr) then -- Get Instance Data inst_stage_next <= GET_INSTANCE_DATA; + inst_data_next <= ZERO_INSTANCE_DATA; if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then @@ -4132,6 +4308,7 @@ begin inst_next_addr_base_next <= inst_read_data; -- Get Instance Data inst_stage_next <= GET_INSTANCE_DATA; + inst_data_next <= ZERO_INSTANCE_DATA; if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then @@ -4859,7 +5036,7 @@ begin when 8 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; - inst_write_data <= std_logic_vector(to_unsigned(1, WORD_WIDTH)); + inst_write_data <= inst_latch_data.sample_cnt; -- Memory Flow Control Guard if (inst_ready_in = '1') then @@ -4868,7 +5045,7 @@ begin -- Disposed Generation Count when 9 => inst_valid_in <= '1'; - inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_addr <= inst_addr_base + IMF_DISPOSED_GEN_CNT_OFFSET; inst_write_data <= (others => '0'); -- Memory Flow Control Guard @@ -4878,7 +5055,7 @@ begin -- No Writers Generation Count when 10 => inst_valid_in <= '1'; - inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_addr <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET; inst_write_data <= (others => '0'); -- Memory Flow Control Guard @@ -4896,7 +5073,7 @@ begin -- Synthesis Guard if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then inst_valid_in <= '1'; - inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_addr <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET; inst_write_data <= inst_latch_data.deadline(0); -- Memory Flow Control Guard @@ -4909,7 +5086,7 @@ begin -- Synthesis Guard if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then inst_valid_in <= '1'; - inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_addr <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET + 1; inst_write_data <= inst_latch_data.deadline(1); -- Memory Flow Control Guard @@ -4967,7 +5144,7 @@ begin -- Sample Count when 1 => inst_valid_in <= '1'; - inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; inst_write_data <= inst_latch_data.sample_cnt; inst_data_next.sample_cnt <= inst_latch_data.sample_cnt; -- Memory Flow Control Guard diff --git a/src/rtps_config_package.vhd b/src/rtps_config_package.vhd index 7d3399d..486f7bc 100644 --- a/src/rtps_config_package.vhd +++ b/src/rtps_config_package.vhd @@ -51,23 +51,26 @@ package rtps_config_package is type HISTORY_CACHE_OPCODE_TYPE is (NOP, ADD_CACHE_CHANGE, GET_CACHE_CHANGE, ACK_CACHE_CHANGE, NACK_CACHE_CHANGE); type KEY_GENERATOR_OPCODE_TYPE is (NOP, WRITE_PAYLOAD, READ_KEY, READ_SIZE); - type HISTORY_CACHE_RESPONSE_TYPE is (UNDEFINED, ACK, ACCEPTED, REJECTED, INVALID); + type HISTORY_CACHE_RESPONSE_TYPE is (OK, REJECTED, INVALID, ERROR); -- Sample Status Info Flags constant SSI_DISPOSED_FLAG : natural := STATUS_INFO_DISPOSED_FLAG; constant SSI_UNREGISTERED_FLAG : natural := STATUS_INFO_UNREGISTERED_FLAG; constant SSI_FILTERED_FLAG : natural := STATUS_INFO_FILTERED_FLAG; - constant SSI_KEY_HASH_FLAG : natural := 28; + constant SSI_KEY_HASH_FLAG : natural := 28; -- Reader Only constant SSI_ALIGNED_FLAG : natural := 29; constant SSI_PAYLOAD_FLAG : natural := 30; - constant SSI_READ_FLAG : natural := 31; + constant SSI_READ_FLAG : natural := 31; -- Reader Only + constant SSI_ACK_FLAG : natural := 31; -- Writer Only -- Instance Status Info Flags - constant ISI_NOT_ALIVE_DISPOSED_FLAG : natural := 0; - constant ISI_NOT_ALIVE_NO_WRITERS_FLAG : natural := 1; + constant ISI_NOT_ALIVE_DISPOSED_FLAG : natural := 0; -- Reader Only + constant ISI_DISPOSED_FLAG : natural := 0; -- Writer Only + constant ISI_NOT_ALIVE_NO_WRITERS_FLAG : natural := 1; -- Reader Only + constant ISI_UNREGISTERED_FLAG : natural := 1; -- Writer Only constant ISI_LIVELINESS_FLAG : natural := 2; - constant ISI_VIEW_FLAG : natural := 3; - constant ISI_MARK_FLAG : natural := 4; + constant ISI_VIEW_FLAG : natural := 3; -- Reader Only + constant ISI_MARK_FLAG : natural := 4; -- Reader Only -- TODO: Prefix the Flags with something that differntiates between them -- Remote Endpoint Flags @@ -123,9 +126,10 @@ package rtps_config_package is constant ENDPOINT_BITMAP_WIDTH : natural := 1; -- TODO type ENDPOINT_BITMAP_ARRAY_TYPE is array (0 to round_div(ENDPOINT_BITMAP_WIDTH, WORD_WIDTH)-1) of std_logic_vector(0 to WORD_WIDTH-1); + constant ZERO_ENDPOINT_BITMAP_ARRAY : ENDPOINT_BITMAP_ARRAY_TYPE := (others => (others => '0')); - function to_endpoint_bitmap (input : ENDPOINT_BITMAP_ARRAY_TYPE) return std_logic_vector; - function from_endpoint_bitmap (input : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1)) return ENDPOINT_BITMAP_ARRAY_TYPE; + function from_endpoint_bitmap_array (input : ENDPOINT_BITMAP_ARRAY_TYPE) return std_logic_vector; + function to_endpoint_bitmap_array (input : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1)) return ENDPOINT_BITMAP_ARRAY_TYPE; -- Swap "data" to Big Endian representation. function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector; @@ -1193,7 +1197,7 @@ package body rtps_config_package is return ret; end function; - function to_endpoint_bitmap (input : ENDPOINT_BITMAP_ARRAY_TYPE) return std_logic_vector is + function from_endpoint_bitmap_array (input : ENDPOINT_BITMAP_ARRAY_TYPE) return std_logic_vector is variable ret : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1) := (others => '0'); begin for i in 0 to input'length-1 loop @@ -1202,7 +1206,7 @@ package body rtps_config_package is return ret; end function; - function from_endpoint_bitmap (input : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1)) return ENDPOINT_BITMAP_ARRAY_TYPE is + function to_endpoint_bitmap_array (input : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1)) return ENDPOINT_BITMAP_ARRAY_TYPE is variable ret : ENDPOINT_BITMAP_ARRAY_TYPE := (others => (others => '0')); begin for i in 0 to ret'length-1 loop diff --git a/src/rtps_reader.vhd b/src/rtps_reader.vhd index dd49710..5b5c98e 100644 --- a/src/rtps_reader.vhd +++ b/src/rtps_reader.vhd @@ -12,6 +12,7 @@ use work.rtps_config_package.all; entity rtps_reader is generic ( RELIABILTY_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_RELIABILTY_QOS; + LIVELINESS_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_LIVELINESS_QOS; HEARTBEAT_RESPONSE_DELAY : DURATION_TYPE := TODO; HEARTBEAT_SUPPRESSION_DELAY : DURATION_TYPE := TODO; LEASE_DURATION : DURATION_TYPE := DEFAULT_LEASE_DURATION; @@ -38,14 +39,16 @@ entity rtps_reader is full_rtps : in std_logic; last_word_out_rtps : out std_logic; data_out_rtps : out std_logic_vector(WORD_WIDTH-1 downto 0); - -- TO DDS READER - start_dds : out std_logic; - opcode_dds : out HISTORY_CACHE_OPCODE_TYPE; - res_dds : in HISTORY_CACHE_RESPOSNE_TYPE; - data_out_dds : out std_logic_vector(WORD_WIDTH-1 downto 0); - valid_out_dds : out std_logic; - ready_out_dds : in std_logic; - last_word_out_dds : out std_logic + -- TO HISTORY CACHE + start_hc : out std_logic; + opcode_hc : out HISTORY_CACHE_OPCODE_TYPE; + ack_hc : in std_logic; + done_hc : in std_logic; + ret_hc : in HISTORY_CACHE_RESPOSNE_TYPE; + data_out_hc : out std_logic_vector(WORD_WIDTH-1 downto 0); + valid_out_hc : out std_logic; + ready_out_hc : in std_logic; + last_word_out_hc : out std_logic ); end entity; @@ -389,18 +392,18 @@ begin lifespan_next <= lifespan; -- DEFAULT Unregistered mem_opcode <= NOP; - opcode_dds <= ADD_CACHE_CHANGE; + opcode_hc <= NOP; lease_deadline <= TIME_INVALID; res_time <= TIME_INVALID; rd_meta <= '0'; rd_user <= '0'; mem_op_start <= '0'; - start_dds <= '0'; - valid_out_dds <= '0'; - last_word_out_dds <= '0'; + start_hc <= '0'; + valid_out_hc <= '0'; + last_word_out_hc <= '0'; rd_guard := '0'; mem_field_flags <= (others => '0'); - data_out_dds <= (others => '0'); + data_out_hc <= (others => '0'); @@ -453,8 +456,13 @@ begin stage_next <= LATCH_GUIDPREFIX; cnt_next <= 0; when OPCODE_LIVELINESS_UPDATE => - stage_next <= LATCH_GUIDPREFIX; - cnt_next <= 0; + -- Synthesis Guard + if (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then + stage_next <= LATCH_GUIDPREFIX; + cnt_next <= 0; + else + stage_next <= SKIP_META_OPERATION; + end if; when others => stage_next <= SKIP_META_OPERATION; end case; @@ -508,7 +516,7 @@ begin guid_next(2) <= data_in_user; end if; - if (is_meta = '1' and (meta_opcode = OPCODE_PARTICIPANT_UNMATCH or meta_opcode = OPCODE_LIVELINESS_UPDATE)) then + if (is_meta = '1' and (meta_opcode = OPCODE_PARTICIPANT_UNMATCH or (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS and meta_opcode = OPCODE_LIVELINESS_UPDATE))) then assert (last_word_in_meta = '1') report "last_word_in_meta not set" severity FAILURE; -- DONE Parsing stage_next <= INITIATE_ENDPOINT_SEARCH; @@ -561,11 +569,14 @@ begin stage_next <= METATRAFFIC_OPERATION; cnt_next <= 0; when OPCODE_LIVELINESS_UPDATE => - mem_op_start <= '1'; - mem_opcode <= GET_FIRST_ENDPOINT; - mem_field_flags <= (others => '0'); - stage_next <= METATRAFFIC_OPERATION; - cnt_next <= 0; + -- Synthesis Guard + if (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then + mem_op_start <= '1'; + mem_opcode <= GET_FIRST_ENDPOINT; + mem_field_flags <= (others => '0'); + stage_next <= METATRAFFIC_OPERATION; + cnt_next <= 0; + end if; when others => null; end case; @@ -657,11 +668,11 @@ begin stage_next <= IDLE; else -- Propagate Removal - start_dds <= '1'; - opcode_dds <= REMOVE_WRITER; - data_out_dds <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); + start_hc <= '1'; + opcode_hc <= REMOVE_WRITER; + data_out_hc <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); -- Wait for Operation Acknowledgement - if (res_dds = ACK) then + if (ack_hc = '1') then -- Remove Unmatched Remote Endpoint mem_op_start <= '1'; mem_opcode <= REMOVE_ENDPOINT; @@ -680,11 +691,11 @@ begin -- Participant Match if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then -- Propagate Removal - start_dds <= '1'; - opcode_dds <= REMOVE_WRITER; - data_out_dds <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); + start_hc <= '1'; + opcode_hc <= REMOVE_WRITER; + data_out_hc <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); -- Wait for Operation Acknowledgement - if (res_dds = ACK) then + if (ack_hc = '1') then -- Remove Unmatched Remote Endpoint mem_op_start <= '1'; mem_opcode <= REMOVE_ENDPOINT; @@ -701,41 +712,44 @@ begin null; end case; when OPCODE_LIVELINESS_UPDATE => - case (cnt) is - when 0 => - -- No matches in memory - if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then - -- DONE - stage_next <= IDLE; - else - -- Participant Match - if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then - -- Renew Lease of Remote Endpoint - mem_op_start <= '1'; - mem_opcode <= UDPATE_ENDPOINT; - mem_field_flags <= EMF_LEASE_DEADLINE_FLAG; - if (LEASE_DURATION /= DURATION_INFINITE) then - lease_deadline <= time + LEASE_DURATION; - - -- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock) - -- Update Check Time - if ((time + LEASE_DURATION) < check_time) then - check_time_next <= time + LEASE_DURATION; + -- Synthesis Guard + if (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then + case (cnt) is + when 0 => + -- No matches in memory + if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Participant Match + if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then + -- Renew Lease of Remote Endpoint + mem_op_start <= '1'; + mem_opcode <= UDPATE_ENDPOINT; + mem_field_flags <= EMF_LEASE_DEADLINE_FLAG; + if (LEASE_DURATION /= DURATION_INFINITE) then + lease_deadline <= time + LEASE_DURATION; + + -- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock) + -- Update Check Time + if ((time + LEASE_DURATION) < check_time) then + check_time_next <= time + LEASE_DURATION; + end if; + else + lease_deadline <= TIME_INVALID; end if; - else - lease_deadline <= TIME_INVALID; end if; + cnt_next <= 1; end if; - cnt_next <= 1; - end if; - when 1 => - -- Continue Search - mem_op_start <= '1'; - mem_opcode <= GET_NEXT_ENDPOINT; - cnt_next <= 0; - when others => - null; - end case; + when 1 => + -- Continue Search + mem_op_start <= '1'; + mem_opcode <= GET_NEXT_ENDPOINT; + cnt_next <= 0; + when others => + null; + end case; + end if; when others => null; end case; @@ -1136,10 +1150,10 @@ begin if (WITH_KEY and key_hash_rcvd = '0' and data_flag = '0' and key_flag = '0') then stage_next <= SKIP_PACKET; else - start_dds <= '1'; - opcode_dds <= ADD_CACHE_CHANGE; + start_hc <= '1'; + opcode_hc <= ADD_CACHE_CHANGE; -- Wait until History Cache acknowledges request - if (res_dds = ACK) then + if (ack_hc = '1') then stage_next <= ADD_CACHE_CHANGE; cnt_next <= 0; end if; @@ -1148,45 +1162,45 @@ begin case (cnt) is -- Status Info when 0 => - valid_out_dds <= '1'; - data_out_dds <= status_info; - data_out_dds(SSI_KEY_HASH_FLAG) <= key_hash_rcvd; - data_out_dds(SSI_PAYLOAD_FLAG) <= data_flag; - data_out_dds(SSI_ALIGNED_FLAG) <= data_flag; + valid_out_hc <= '1'; + data_out_hc <= status_info; + data_out_hc(SSI_KEY_HASH_FLAG) <= key_hash_rcvd; + data_out_hc(SSI_PAYLOAD_FLAG) <= data_flag; + data_out_hc(SSI_ALIGNED_FLAG) <= data_flag; -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Timestamp 1/2 when 1 => - valid_out_dds <= '1'; - data_out_dds <= ts(0); + valid_out_hc <= '1'; + data_out_hc <= ts(0); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Timestamp 2/2 when 2 => - valid_out_dds <= '1'; - data_out_dds <= ts(1); + valid_out_hc <= '1'; + data_out_hc <= ts(1); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Lifespan Deadline 1/2 when 3 => - valid_out_dds <= '1'; - data_out_dds <= lifespan(0); + valid_out_hc <= '1'; + data_out_hc <= lifespan(0); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Lifespan Deadline 2/2 when 4 => - valid_out_dds <= '1'; - data_out_dds <= lifespan(1); + valid_out_hc <= '1'; + data_out_hc <= lifespan(1); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then -- Skip Key Hash, if not received if (not WITH_KEY or key_hash_rcvd = '0') then cnt_next <= cnt + 5; @@ -1196,46 +1210,46 @@ begin end if; -- Key hash 1/4 when 5 => - valid_out_dds <= '1'; - data_out_dds <= key_hash(0); + valid_out_hc <= '1'; + data_out_hc <= key_hash(0); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Key Hash 2/4 when 6 => - valid_out_dds <= '1'; - data_out_dds <= key_hash(1); + valid_out_hc <= '1'; + data_out_hc <= key_hash(1); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Key Hash 3/4 when 7 => - valid_out_dds <= '1'; - data_out_dds <= key_hash(2); + valid_out_hc <= '1'; + data_out_hc <= key_hash(2); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Key hash 4/4 when 8 => - valid_out_dds <= '1'; - data_out_dds <= key_hash(3); + valid_out_hc <= '1'; + data_out_hc <= key_hash(3); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then cnt_next <= cnt + 1; end if; -- Endpoint Memory Position when 9 => -- Wait for Endpoint Search if (mem_op_done = '1') then - valid_out_dds <= '1'; + valid_out_hc <= '1'; -- TODO: Assert mem_pos range fits in CDR_LONG - data_out_dds <= std_logic_vector(to_unsigned(mem_pos, CDR_LONG_WIDTH)); + data_out_hc <= std_logic_vector(to_unsigned(mem_pos, CDR_LONG_WIDTH)); -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then -- NOTE: We only push the Payload if there is Data, or if the Key Hash was not received and we need to push -- the serialized Key. -- Payload exists @@ -1243,7 +1257,7 @@ begin stage_next <= PUSH_PAYLOAD; else -- DONE - last_word_out_dds <= '1'; + last_word_out_hc <= '1'; stage_next <= FINALIZE_ADD_CACHE_CHANGE_REQUEST; end if; end if; @@ -1254,13 +1268,13 @@ begin when PUSH_PAYLOAD => -- Input Guard if (empty_user = '0') then - valid_out_dds <= '1'; + valid_out_hc <= '1'; -- Push Payload to History Cache - data_out_dds <= data_in_user; - last_word_out_dds <= last_word_in_user; + data_out_hc <= data_in_user; + last_word_out_hc <= last_word_in_user; -- Output Guard - if (ready_out_dds = '1') then + if (ready_out_hc = '1') then rd_guard := '1'; -- Exit Condition @@ -1273,7 +1287,7 @@ begin -- NOTE: Memory is already in done state from previous state (ADD_CACHE_CHANGE) assert (mem_op_done = '1') report "FINALIZE_ADD_CACHE_CHANGE_REQUEST precondition not met. mem_op_done /= '1'" severity FAILURE; -- Wait for History Cache Response - if (res_dds /= UNDEFINED) then + if (done_hc = '1') then -- NOTE: The Lease Duration is also updated if the Cache Change is not accepted. This in effect "skews" the -- "correctness" of the Writer Liveliness Protocol until the reader has no pending request from the Writer. @@ -1281,7 +1295,7 @@ begin -- Update Endpoint mem_op_start <= '1'; mem_opcode <= UPDATE_ENDPOINT; - mem_field_flags <= LEASE_DEADLINE_FLAG; + mem_field_flags <= EMF_LEASE_DEADLINE_FLAG; if (LEASE_DURATION /= DURATION_INFINITE) then lease_deadline <= time + LEASE_DURATION; @@ -1297,9 +1311,9 @@ begin -- NOTE: In case the operation was unsucessfull (e.g. reached Resource Limits), the Sequence Number is not updated -- and thus not "acknowledged". -- Operation was Accepted - if (res_dds = ACCEPTED) then + if (ret_hc = OK) then -- Update also next sequence number - mem_field_flags <= NEXT_SEQ_NR_FLAG or LEASE_DEADLINE_FLAG; + mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG or EMF_LEASE_DEADLINE_FLAG; end if; -- DONE diff --git a/src/rtps_writer.vhd b/src/rtps_writer.vhd index f9602ac..9f7b3ce 100644 --- a/src/rtps_writer.vhd +++ b/src/rtps_writer.vhd @@ -294,24 +294,18 @@ architecture arch of rtps_writer is --*****ALIAS DECLARATION***** -- ENDPOINT FRAME HEADER - alias header_opcode : std_logic_vector(7 downto 0) is data_in_user(31 downto 24); - alias header_flags : std_logic_vector(7 downto 0) is data_in_user(23 downto 16); - alias header_udp_port : std_logic_vector(15 downto 0) is data_in_user(15 downto 0); - -- RTPS PARAMETER LIST HEADER - alias parameter_id : std_logic_vector(15 downto 0) is data_in_user(31 downto 16); - alias parameter_length : std_logic_vector(15 downto 0) is data_in_user(15 downto 0); - alias must_understand : std_logic is parameter_id(14); - -- RTPS DATA PAYLOAD HEADER - alias representation_id : std_logic_vector(15 downto 0) is data_in_user(31 downto 16); - alias representation_options : std_logic_vector(15 downto 0) is data_in_user(15 downto 0); + alias header_opcode : std_logic_vector(7 downto 0) is data_in_user(31 downto 24); + alias header_flags : std_logic_vector(7 downto 0) is data_in_user(23 downto 16); + alias header_udp_port : std_logic_vector(15 downto 0) is data_in_user(15 downto 0); -- RTPS SUBMESSAGE FLAGS - alias endian_flag : std_logic is rtps_flags(0); - alias qos_flag : std_logic is rtps_flags(1); - alias data_flag : std_logic is rtps_flags(2); - alias key_flag : std_logic is rtps_flags(3); - alias final_flag : std_logic is rtps_flags(1); - alias payload_flag : std_logic is rtps_flags(4); - alias liveliness_flag : std_logic is rtps_flags(2); + alias endian_flag : std_logic is rtps_flags(0); + alias final_flag : std_logic is rtps_flags(1); + alias liveliness_flag : std_logic is rtps_flags(2); + -- RTPS OUT DATA SUBMESSAGE FLAGS + alias qos_flag : std_logic is data_out_rtps(17); + alias data_flag : std_logic is data_out_rtps(18); + alias key_flag : std_logic is data_out_rtps(19); + alias payload_flag : std_logic is data_out_rtps(20); -- ACKNACK alias nack_base : SEQUENCENUMBER_TYPE is sn_latch_1; alias nack_base_next : SEQUENCENUMBER_TYPE is sn_latch_1_next; @@ -362,9 +356,6 @@ begin data_out => mem_read_data ); - -- Propagate Liveliness Assertion - alive <= assert_liveliness when (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) else '0'; - -- *Main State Machine* -- STATE DESCRIPTION -- IDLE Idle State. Initiates Stale Endpoint Checks, Metatraffic Packet Processing, and User Packet Processing, in that priority order. @@ -438,7 +429,7 @@ begin assert_liveliness_latch_next<= assert_liveliness_latch; -- DEFAULT Unregistered mem_opcode <= NOP; - opcode_hc <= ADD_CACHE_CHANGE; + opcode_hc <= NOP; lease_deadline <= TIME_INVALID; res_time <= TIME_INVALID; rd_meta <= '0'; @@ -449,6 +440,7 @@ begin get_data_hc <= '0'; wr_rtps <= '1'; rd_guard := '0'; + alive <= '0'; mem_field_flags <= (others => '0'); data_out_dds <= (others => '0'); @@ -471,12 +463,28 @@ begin -- New Cache Change in HC if (data_available = '1') then + -- Propagate Liveliness + alive <= '1'; + new_push_next <= '1'; stage_next <= GET_MAX_SN; cnt_next <= 0; + -- Manual Liveliness Assertion + elsif (LIVELINESS_QOS = MANUAL_BY_TOPIC_LIVELINESS_QOS and assert_liveliness_latch = '1') then + -- Propagate Liveliness + alive <= '1'; + + -- Reset + heartbeat_time_next <= time + HEARTBEAT_PERIOD; + + -- Increment Heartbeat Count + count_next <= count + 1; + + stage_next <= GET_MIN_SN; + cnt_next <= 0; -- Heartbeat Timeout - elsif ((RELIABILTY_QOS = RELIABLE_RELIABILITY_QOS and time >= heartbeat_time) or (LIVELINESS_QOS = MANUAL_BY_TOPIC_LIVELINESS_QOS and assert_liveliness_latch = '1')) then + elsif (RELIABILTY_QOS = RELIABLE_RELIABILITY_QOS and time >= heartbeat_time) then -- Reset heartbeat_time_next <= time + HEARTBEAT_PERIOD; @@ -722,25 +730,18 @@ begin -- Ignore stage_next <= IDLE; else - -- Propagate Removal - start_hc <= '1'; - opcode_hc <= REMOVE_WRITER; - data_out_dds <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); - -- Wait for Operation Acknowledgement - if (res_hc = ACK) then - -- Remove Unmatched Remote Endpoint - mem_op_start <= '1'; - mem_opcode <= REMOVE_ENDPOINT; - - -- Global ACK SN possibly changed - if (RELIABILTY_QOS = RELIABLE_RELIABILITY_QOS and global_ack_seq_nr_base /= SEQUENCENUMBER_UNKNOWN and global_ack_seq_nr_base = mem_endpoint_data.ack_seq_nr_base) then - -- Update Global ACK - stage_next <= UPDATE_GLOBAL_ACK; - cnt_next <= 0; - else - -- DONE - stage_next <= IDLE; - end if; + -- Remove Unmatched Remote Endpoint + mem_op_start <= '1'; + mem_opcode <= REMOVE_ENDPOINT; + + -- Global ACK SN possibly changed + if (RELIABILTY_QOS = RELIABLE_RELIABILITY_QOS and global_ack_seq_nr_base /= SEQUENCENUMBER_UNKNOWN and global_ack_seq_nr_base = mem_endpoint_data.ack_seq_nr_base) then + -- Update Global ACK + stage_next <= UPDATE_GLOBAL_ACK; + cnt_next <= 0; + else + -- DONE + stage_next <= IDLE; end if; end if; when OPCODE_PARTICIPANT_UNMATCH => @@ -750,6 +751,8 @@ begin if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then -- Global ACK SN possibly changed if (RELIABILTY_QOS = RELIABLE_RELIABILITY_QOS and global_ack_seq_nr_base /= SEQUENCENUMBER_UNKNOWN) then + -- NOTE: We are triggering an Global ACK SN Update on each Participant Removal. This should not happen as often, and is therefore acceptable. + -- Otherwise we need to check the ack_seq_nr_base in the other substate and mark when equal to current Global ACK SN. -- Update Global ACK stage_next <= UPDATE_GLOBAL_ACK; cnt_next <= 0; @@ -770,6 +773,7 @@ begin -- Continue Search mem_op_start <= '1'; mem_opcode <= GET_NEXT_ENDPOINT; + mem_field_flags <= EMF_GUIDPREFIX_FLAG; cnt_next <= 0; when others => null; @@ -1333,7 +1337,7 @@ begin -- Wait until Operation Response if (done_hc = '1') then -- Wait for Operation Response - if (ret_hc = ACK) then + if (ret_hc = OK) then get_data_hc <= '1'; if (gap_in_progress = '1') then -- Close GAP and send DATA @@ -1384,7 +1388,7 @@ begin mem_opcode <= GET_NEXT_ENDPOINT; mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG; cnt_next <= cnt + 1; - -- Initiate Hertbeat Sending + -- Initiate Heartbeat Sending when 2 => -- End of Endpoint if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then @@ -1418,49 +1422,17 @@ begin last_seq_nr_next <= last_seq_nr + 1; cnt_next <= cnt + 1; end if; - -- GET SN - when 1 => - start_hc <= '1'; - opcode_hc <= GET_CACHE_CHANGE; - seq_nr_hc <= last_seq_nr; - - -- Wait until Operation Acknowledgement - if (ack_hc = '1') then - cnt_next <= cnt + 1; - end if; - -- READ SN - when 2 => - -- Wait until Operation Response - if (done_hc = '1') then - -- Cache Change Available - if (ret_hc = ACK) then - cnt_next <= cnt + 1; - -- Cache Change Unavailable - else - report "New Cache Change unavailable" severity ERROR; - cnt_next <= 0; - end if; - end if; -- Get First Reader - when 3 => + when 1 => -- Memory Operation Guard if (mem_op_done = '1') then mem_op_start <= '1'; mem_opcode <= GET_FIRST_ENDPOINT; mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG; - cnt_next <= cnt + 2; - end if; - -- Get Next Reader - when 4 => - -- Memory Operation Guard - if (mem_op_done = '1') then - mem_op_start <= '1'; - mem_opcode <= GET_NEXT_ENDPOINT; - mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG; cnt_next <= cnt + 1; end if; - -- Initiate Send - when 5 => + -- GET SN + when 2 => -- Wait for Endpoint Data if (mem_op_done = '1') then -- End of Endpoints @@ -1484,11 +1456,46 @@ begin cnt_next <= 0; end if; else - stage_next <= SEND_HEADER; - return_stage_next <= SEND_DATA_A; - cnt_next <= 0; + start_hc <= '1'; + opcode_hc <= GET_CACHE_CHANGE; + seq_nr_hc <= last_seq_nr; + + -- Wait until Operation Acknowledgement + if (ack_hc = '1') then + cnt_next <= cnt + 1; + end if; end if; end if; + -- READ SN + when 3 => + -- Wait until Operation Response + if (done_hc = '1') then + -- Cache Change Available + if (ret_hc = OK) then + -- Only request Payload if necessary (Contains DATA or Serialized Key) + if (cc_kind = ALIVE or (WITH_KEY and cc_kind /= ALIVE)) then + get_data_hc <= '1'; + end if; + + stage_next <= SEND_HEADER; + return_stage_next <= SEND_INFO_TS when (DESTINATION_ORDER_QOS = BY_SOURCE_TIMESTAMP_DESTINATION_ORDER_QOS) else SEND_DATA_A; + cnt_next <= 0; + -- Cache Change Unavailable + else + report "New Cache Change unavailable" severity WARNING; + cnt_next <= 0; + end if; + end if; + -- Get Next Reader + when 4 => + -- Memory Operation Guard + if (mem_op_done = '1') then + mem_op_start <= '1'; + mem_opcode <= GET_NEXT_ENDPOINT; + mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG; + -- Loop + cnt_next <= 2; + end if; when others => null; end case; @@ -1548,8 +1555,12 @@ begin -- Wait until Operation Response if (done_hc = '1') then -- Wait for Operation Response - if (ret_hc = ACK) then - get_data_hc <= '1'; + if (ret_hc = OK) then + -- Only request Payload if necessary (Contains DATA or Serialized Key) + if (cc_kind = ALIVE or (WITH_KEY and cc_kind /= ALIVE)) then + get_data_hc <= '1'; + end if; + if (gap_in_progress = '1') then -- Close GAP and send DATA gap_in_progress_next <= '0'; @@ -1658,16 +1669,10 @@ begin -- DATA RTPS SUBMESSAGE -- RTPS Submessage Header when 0 => - -- Operation has no Data - if (cc_kind /= ALIVE) then - -- Set KEY Flag - data_out_rtps <= SID_DATA & "00001010" & std_logic_vector(to_unsigned(0, SUBMESSAGE_LENGTH_WIDTH)); - wr_sig <= '1'; - else - -- Set DATA Flag - data_out_rtps <= SID_DATA & "00000110" & std_logic_vector(to_unsigned(0, SUBMESSAGE_LENGTH_WIDTH)); - wr_sig <= '1'; - end if; + data_out_rtps <= SID_DATA & "00000000" & std_logic_vector(to_unsigned(0, SUBMESSAGE_LENGTH_WIDTH)); + data_flag <= '1' when (cc_kind = ALIVE) else '0'; + key_flag <= '1' when (WITH_KEY and cc_kind /= ALIVE) else '0'; + qos_flag <= '1' when (cc_kind /= ALIVE or WITH_KEY or mem_endpoint_data.flags(EXPECTS_INLINE_QOS_FLAG) = '1') else '0'; cnt_next <= cnt + 1; -- extraFlags, octetsToInlineQoS when 1 => @@ -1693,13 +1698,82 @@ begin when 5 => data_out_rtps <= std_logic_vector(next_seq_nr(1)); wr_sig <= '1'; - if (cc_kind /= ALIVE) then - cnt_next <= cnt + 1; + + -- Need to send Key Hash + if (WITH_KEY) then + cnt_next <= cnt + 1; + -- Need to send Status Info + elsif (cc_kind /= ALIVE) then + cnt_next <= cnt + 5; + -- Reader expect in-line QoS + elsif(mem_endpoint_data.flags(EXPECTS_INLINE_QOS_FLAG) = '1') then + stage_next <= SEND_INLINE_QOS; + cnt3_next <= 0; + -- Payload Available (DATA or Serialized Key) + elsif (cc_kind = ALIVE or (WITH_KEY and cc_kind /= ALIVE)) then + stage_next <= SEND_DATA_B; + cnt_next <= 0; else - cnt_next <= cnt + 2; + -- Continue + if (stale_check = '1') then + stage_next <= HANDLE_REQUESTS; + cnt_next <= 0; + req_bitmap_pos_next <= req_bitmap_pos + 1; + next_seq_nr_next <= next_seq_nr + 1; + elsif (new_push = '1') then + stage_next <= HANDLE_NEW; + cnt_next <= 4; + elsif (historical_push = '1') then + stage_next <= HANDLE_HISTORICAL; + cnt_next <= 0; + else + assert FALSE severity FAILURE; + end if; + end if; + -- Key Hash 1/4 + when 6 => + -- Synthesis Guard + if (WITH_KEY) then + data_out_rtps <= std_logic_vector(cc_instance_handle(0)); + wr_sig <= '1'; + cnt_next <= cnt + 1; + end if; + -- Key Hash 2/4 + when 7 => + -- Synthesis Guard + if (WITH_KEY) then + data_out_rtps <= std_logic_vector(cc_instance_handle(1)); + wr_sig <= '1'; + cnt_next <= cnt + 1; + end if; + -- Key Hash 3/4 + when 8 => + -- Synthesis Guard + if (WITH_KEY) then + data_out_rtps <= std_logic_vector(cc_instance_handle(2)); + wr_sig <= '1'; + cnt_next <= cnt + 1; + end if; + -- Key Hash 4/4 + when 9 => + -- Synthesis Guard + if (WITH_KEY) then + data_out_rtps <= std_logic_vector(cc_instance_handle(3)); + wr_sig <= '1'; + + -- Need to send Status Info + if (cc_kind /= ALIVE) then + cnt_next <= cnt + 1; + -- Reader expects in-line QoS + elsif (mem_endpoint_data.flags(EXPECTS_INLINE_QOS_FLAG) = '1') then + stage_next <= SEND_INLINE_QOS; + cnt3_next <= 0; + else + cnt_next <= cnt + 2; + end if; end if; -- Status Info - when 6 => + when 10 => data_out_rtps <= (others => '0'); wr_sig <= '1'; case (cc_kind) is @@ -1712,26 +1786,8 @@ begin when others => null; end case; - cnt_next <= cnt + 1; - -- Key Hash 1/4 - when 7 => - data_out_rtps <= std_logic_vector(cc_instance_handle(0)); - wr_sig <= '1'; - cnt_next <= cnt + 1; - -- Key Hash 2/4 - when 8 => - data_out_rtps <= std_logic_vector(cc_instance_handle(1)); - wr_sig <= '1'; - cnt_next <= cnt + 1; - -- Key Hash 3/4 - when 9 => - data_out_rtps <= std_logic_vector(cc_instance_handle(2)); - wr_sig <= '1'; - cnt_next <= cnt + 1; - -- Key Hash 4/4 - when 10 => - data_out_rtps <= std_logic_vector(cc_instance_handle(3)); - wr_sig <= '1'; + + -- Reader expects in-line QoS if (mem_endpoint_data.flags(EXPECTS_INLINE_QOS_FLAG) = '1') then stage_next <= SEND_INLINE_QOS; cnt3_next <= 0; @@ -1742,7 +1798,27 @@ begin when 11 => data_out_rtps <= PID_SENTINEL & std_logic_vector(to_unsigned(0, 16)); wr_sig <= '1'; - stage_next <= SEND_DATA_B; + + -- Payload Available (DATA or Serialized Key) + if (cc_kind = ALIVE or (WITH_KEY and cc_kind /= ALIVE)) then + stage_next <= SEND_DATA_B; + else + -- Continue + if (stale_check = '1') then + stage_next <= HANDLE_REQUESTS; + cnt_next <= 0; + req_bitmap_pos_next <= req_bitmap_pos + 1; + next_seq_nr_next <= next_seq_nr + 1; + elsif (new_push = '1') then + stage_next <= HANDLE_NEW; + cnt_next <= 4; + elsif (historical_push = '1') then + stage_next <= HANDLE_HISTORICAL; + cnt_next <= 0; + else + assert FALSE severity FAILURE; + end if; + end if; when others => null; end case; @@ -1756,7 +1832,26 @@ begin -- Exit Condition if (cnt3 = INLINE_QOS.length-1) then - stage_next <= SEND_DATA_B; + -- Payload Available (DATA or Serialized Key) + if (cc_kind = ALIVE or (WITH_KEY and cc_kind /= ALIVE)) then + stage_next <= SEND_DATA_B; + else + -- Continue + if (stale_check = '1') then + stage_next <= HANDLE_REQUESTS; + cnt_next <= 0; + req_bitmap_pos_next <= req_bitmap_pos + 1; + next_seq_nr_next <= next_seq_nr + 1; + elsif (new_push = '1') then + stage_next <= HANDLE_NEW; + cnt_next <= 4; + elsif (historical_push = '1') then + stage_next <= HANDLE_HISTORICAL; + cnt_next <= 0; + else + assert FALSE severity FAILURE; + end if; + end if; end if; end if; when SEND_DATA_B => @@ -1958,6 +2053,7 @@ begin -- FIND_EMPTY_SLOT Find first empty_user slot in memory. -- RESET_MAX_POINTER Reset the max_endpoint_addr pointer to last occupied slot in memory. -- GET_NEXT_ENDPOINT See Memory OPCODE Description + -- RESET_MEMORY Reset Endpoint Memory to Empty State mem_ctrl_prc : process(all) begin -- DEFAULT Registered