From 7e84a15d54129e8306def12134733b9013503de2 Mon Sep 17 00:00:00 2001 From: Greek Date: Sat, 16 Jan 2021 18:22:36 +0100 Subject: [PATCH] Redo Blind Implementation of READER side (RTPS Endpoint & History Cache) Redefined Sample Memory Format. The design decision was made to handle most (if not all) of the DDS QOS inside the History Cache, which allows storing needed information in a more efiicient way. A (dual port) Instance Memory was added into the HC, to support the QOS operations. This commit only implements the A side processes for the READER case. RESOURCE_LIMITS_QOS, TIME_BASED_FILTER_QOS, and HISTORY_QOS are handled. The inter-entity communication was changed to allow the HC to mark parsed changes as rejected, and allow future re-transmission (in the case of Reliable communication). --- src/REF.txt | 112 +-- src/TODO.txt | 2 + src/history_cache.vhd | 1368 +++++++++++++++++++++++++++++------ src/rtps_config_package.vhd | 37 +- src/rtps_endpoint.vhd | 567 ++++++++------- src/rtps_package.vhd | 13 +- 6 files changed, 1591 insertions(+), 508 deletions(-) diff --git a/src/REF.txt b/src/REF.txt index 7a3de94..9836731 100644 --- a/src/REF.txt +++ b/src/REF.txt @@ -340,41 +340,33 @@ READER 31............24..............16..............8...............0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------------------------------------------------------+ -00| STATUS_INFO | +00| STATUS_INFO | {A/B} +-------------------------------------------------------------+ 01| | + + 02| | - + KEY_HASH + + + KEY_HASH + {A} 03| | + + 04| | +-------------------------------------------------------------+ -05| ENTITYID | - +-------------------------------------------------------------+ +05| | + + TIMESTAMP + {A} 06| | - + + -07| GUIDPREFIX | - + + + +-------------------------------------------------------------+ +07| | + + LIFESPAN_DEADLINE + {A} 08| | +-------------------------------------------------------------+ -09| | - + SEQUENCE_NUMBER + -10| | +09| PAYLOAD_ADDRESS | {A} +-------------------------------------------------------------+ -11| | - + TIMESTAMP + -12| | +10| DISPOSED_GENERATION_COUNT | {A} [only GENERATION_COUNTERS] +-------------------------------------------------------------+ -13| | - + LIFESPAN_DEADLINE + -14| | +11| NO_WRITERS_GENERATION_COUNT | {A} [only GENERATION_COUNTERS] +-------------------------------------------------------------+ -15| PAYLOAD_ADDRESS | +12| PREV_ADDRESS | {A} +-------------------------------------------------------------+ -16| PREV_ADDRESS | - +-------------------------------------------------------------+ -17| NEXT_ADDRESS | +13| NEXT_ADDRESS | {A/B} +-------------------------------------------------------------+ @@ -383,12 +375,12 @@ STATUS INFO 31............24..............16..............8...............0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-------------------------------------------------+-+-+-+ -|R|K|P| UNUSED |F|U|D| +|R|P|K| UNUSED |F|U|D| +-+-+-+-------------------------------------------------+-+-+-+ R...Sample has been Read -K...Key Hash available P...Sample has associated Payload +K...Key Hash available F...FilteredFlag U...UnregisteredFlag @@ -398,9 +390,9 @@ PAYLOAD MEMORY ============== 31............24..............16..............8...............0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-----------------------------------------------------------+-+ -00| NEXT_ADDRESS |O| - +-----------------------------------------------------------+-+ + +-------------------------------------------------------------+ +00| NEXT_ADDRESS | + +-------------------------------------------------------------+ 01| | ~ PAYLOAD ~ **| | @@ -421,31 +413,67 @@ HISTORY CACHE INPUT + + 04| | +-------------------------------------------------------------+ -05| ENTITYID | - +-------------------------------------------------------------+ +05| | + + TIMESTAMP + 06| | - + + -07| GUIDPREFIX | - + + + +-------------------------------------------------------------+ +07| | + + LIFESPAN_DEADLINE + 08| | +-------------------------------------------------------------+ -09| | - + SEQUENCE_NUMBER + +09| ENDPOINT_POSITION | + +-------------------------------------------------------------+ 10| | - +-------------------------------------------------------------+ -11| | - + TIMESTAMP + -12| | - +-------------------------------------------------------------+ -13| | - + LIFESPAN_DEADLINE + -14| | - +-------------------------------------------------------------+ -15| | ~ PAYLOAD ~ **| | +-------------------------------------------------------------+ +INSTANCE MEMORY +=============== + 31............24..............16..............8...............0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-------------------------------------------------------------+ +00| NEXT_ADDRESS | {A/B} + +-------------------------------------------------------------+ +01| | + + + +02| | + + KEY_HASH + {A} +03| | + + + +04| | + +-------------------------------------------------------------+ +05| STATUS_INFO | {A/B} + +-------------------------------------------------------------+ +06| SAMPLE_COUNT | {A/B} [only MAX_SAMPLES_PER_INSTANCE/HISTORY] + +-------------------------------------------------------------+ +07| DISPOSED_GENERATION_COUNT | {A} [only GENERATION_COUNTERS] + +-------------------------------------------------------------+ +08| NO_WRITERS_GENERATION_COUNT | {A} [only GENERATION_COUNTERS] + +-------------------------------------------------------------+ +09| | + + IGNORE_DEADLINE + {A} [only TIME_BASED_FILTER] +10| | + +-------------------------------------------------------------+ +11| | + ~ WRITER_BITMAP ~ {A} +**| | + +-------------------------------------------------------------+ + + +STATUS INFO +----------- +31............24..............16..............8...............0 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++-----------------------------------------------------+-+-+-+-+ +| UNUSED |V|L|W|D| ++-----------------------------------------------------+-+-+-+-+ + +D...NOT_ALIVE_DISPOSED +W...NOT_ALIVE_NO_WRITERS +L...LIVELINESS FLAG +V...VIEW STATE + OUTPUT DATA =========== diff --git a/src/TODO.txt b/src/TODO.txt index 2e3dadf..ee12bde 100644 --- a/src/TODO.txt +++ b/src/TODO.txt @@ -95,6 +95,8 @@ 'This Submessage is invalid when the following is true: submessageLength in the Submessage header is too small' But if InvalidateFlag is set, Length can be Zero. Since the length is unsigned, there cannot be an invalid length. + - 8.7.3.2 Indicating to a Reader that a Sample has been filtered + Text refs 8.3.7.2.2 for DataFlag, but shoudl also ref 8.7.4 for FilteredFlag - 9.4.5.1.2 Flags Clarify from where the endianness begins. One might think it would begin after the Submessage Header, but the length is also endian dependent. diff --git a/src/history_cache.vhd b/src/history_cache.vhd index c5fc109..2f10f4c 100644 --- a/src/history_cache.vhd +++ b/src/history_cache.vhd @@ -4,7 +4,12 @@ use ieee.numeric_std.all; entity history_cache is generic ( - ORDER : boolean := TRUE + TIME_BASED_FILTER_QOS : DURATION_TYPE := DEFAULT_TIME_BASED_FILTER_QOS; + MAX_INSTANCES : natural := DEFAULT_MAX_INSTANCES; + MAX_SAMPLES_PER_INSTANCE : natural := DEFAULT_MAX_SAMPLES_PER_INSTANCE; + HISTORY_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_HISTORY_QOS; + RELIABILITY_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_RELIABILTY_QOS; + GENERATION_COUNTERS : boolean := TRUE; ); port ( clk : in std_logic; @@ -12,7 +17,7 @@ entity history_cache is start_a : in std_logic; opcode_a : in HISTORY_CACHE_OPCODE_TYPE; - ack_a : out std_logic; + res_a : out HISTORY_CACHE_RESPOSNE_TYPE; data_in_a : in std_logic_vector(WORD_WIDTH-1 downto 0); valid_in_a : in std_logic; ready_in_a : out std_logic; @@ -20,7 +25,7 @@ entity history_cache is start_b : in std_logic; opcode_b : in HISTORY_CACHE_OPCODE_TYPE; - ack_b : out std_logic; + res_b : out HISTORY_CACHE_RESPOSNE_TYPE; data_out_b : out std_logic_vector(WORD_WIDTH-1 downto 0); last_word_out_b : in std_logic; ); @@ -45,12 +50,93 @@ architecture arch of history_cache is -- Highest Payload Memory Address constant PAYLOAD_MEMORY_MAX_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(PAYLOAD_MEMORY_SIZE-1, PAYLOAD_MEMORY_ADDR_WIDTH); -- Highest Payload Frame Address - constant MAX_PAYLOAD_ADDRESS : unsigned(PAYLAOD_MEMORY_ADDR_WIDTH-1 downto 0) := PAYLOAD_MEMORY_MAX_ADDRESS - PAYLOAD_FRAME_SIZE + 1; + constant MAX_PAYLOAD_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := PAYLOAD_MEMORY_MAX_ADDRESS - PAYLOAD_FRAME_SIZE + 1; + -- Instance Memory Size in 4-Byte Words + constant INSTANCE_MEMORY_SIZE : natural := TODO; + -- Instance Memory Address Width + constant INSTANCE_MEMORY_ADDR_WIDTH : natural := log2c(INSTANCE_MEMORY_SIZE); + -- 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; + -- 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'); + + -- *UPDATE INSTANCE FLAG POSITIONS* + constant UPDATE_INSTANCE_FLAG_WIDTH : natural := 6; + constant STATUS_FLAG : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (0 => 1, others => '0'); + constant SAMPLE_CNT_FLAG : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (1 => 1, others => '0'); + constant DISPOSED_CNT_FLAG : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (2 => 1, others => '0'); + constant NO_WRITERS_CNT_FLAG : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (3 => 1, others => '0'); + constant IGNORE_DEADLINE_FLAG : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (4 => 1, others => '0'); + constant WRITER_BITMAP_FLAG : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (5 => 1, others => '0'); + + -- *SAMPLE MEMORY FRAME FORMAT* + constant SMF_STATUS_INFO_OFFSET : natural := 0; + constant SMF_KEY_HASH_OFFSET : natural := 1; + constant SMF_TIMESTAMP_OFFSET : natural := 5; + constant SMF_LIFESPAN_DEADLINE_OFFSET : natural := 7; + constant SMF_PAYLOAD_ADDR_OFFSET : natural := 9; + constant SMF_DISPOSED_GEN_CNT_OFFSET : natural := 10; + constant SMF_NO_WRITERS_GEN_CNT_OFFSET : natural := 11; + constant SMF_PREV_ADDR_OFFSET : natural := SMF_NO_WRITERS_GEN_CNT_OFFSET+1 when GENERATION_COUNTERS else SMF_NO_WRITERS_GEN_CNT_OFFSET+1; + constant SMF_NEXT_ADDR_OFFSET : natural := SMF_PREV_ADDR_OFFSET+1; + -- *PAYLOAD MEMORY FRAME FORMAT* + constant PMF_NEXT_ADDR_OFFSET : natural := 0; + constant PMF_PAYLOAD_OFFSET : natural := 1; + -- *INSTANCE MEMORY FRAME OFFSET* + constant IMF_NEXT_ADDR_OFFSET : natural := 0; + constant IMF_KEY_HASH_OFFSET : natural := 1; + constant IMF_STATUS_INFO_OFFSET : natural := 5; + constant IMF_SAMPLE_CNT_OFFSET : natural := 6; + constant IMF_DISPOSED_GEN_CNT_OFFSET : natural := IMF_SAMPLE_CNT_OFFSET+1 when (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) else IMF_STATUS_INFO_OFFSET+1; + constant IMF_NO_WRITERS_GEN_CNT_OFFSET : natural := IMF_DISPOSED_GEN_CNT_OFFSET+1; + constant IMF_IGNORE_DEADLINE_OFFSET : natural := IMF_NO_WRITERS_GEN_CNT_OFFSET+1 when (GENERATION_COUNTERS) else + IMF_SAMPLE_CNT_OFFSET+1 when (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) else IMF_STATUS_INFO_OFFSET+1; + constant IMF_WRITER_BITMAP_OFFSET : natural := IMF_IGNORE_DEADLINE_OFFSET+2 when (TIME_BASED_FILTER_QOS /= DURATION_ZERO) else + IMF_NO_WRITERS_GEN_CNT_OFFSET+1 when (GENERATION_COUNTERS) else + IMF_SAMPLE_CNT_OFFSET+1 when (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) else IMF_STATUS_INFO_OFFSET+1; --*****TYPE DECLARATION***** -- FSM states. Explained below in detail type STAGE_TYPE is (IDLE, TODO); + type INST_STAGE_TYPE is (IDLE, TODO); + type INSTANCE_OPCODE_TYPE is (NOP, TODO); + type INSTANCE_DATA_TYPE is record + status_info : std_logic_vector(WORD_WIDTH-1 downto 0); + sample_cnt : unsigned(WORD_WIDTH-1 downto 0); + disposed_gen_cnt : unsigned(WORD_WIDTH-1 downto 0); + no_writers_gen_cnt : unsigned(WORD_WIDTH-1 downto 0); + ignore_deadline : TIME_TYPE; + writer_bitmap : ENDPOINT_BITMAP_ARRAY_TYPE; + end record; + constant ZERO_INSTANCE_DATA : INSTANCE_DATA_TYPE := ( + status_info => (others => '0'), + sample_cnt => (others => '0'), + disposed_gen_cnt => (others => '0'), + no_writers_gen_cnt => (others => '0'), + ignore_deadline => TIME_INVALID, + writer_bitmap => (others => (others => '0')) + ); + type INST_LATCH_DATA_TYPE is record + key_hash : KEY_HASH_TYPE; + instance_state : INSTANCE_STATE_TYPE; + gen_cnt : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); + deadline : TIME_TYPE; + writer_bitmap : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1); + update_flags : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1); + release_lock : std_logic; + end record; + constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := ( + key_hash => (others => (others => '0')), + instance_state => ALIVE, + gen_cnt => (others => '0'), + deadline => TIME_INVALID, + writer_bitmap => (others => (others => '0')), + update_flags => (others => '0'), + release_lock => '0' + ); --*****SIGNAL DECLARATION signal stage_a, stage_a_next : STAGE_TYPE := IDLE; @@ -87,16 +173,49 @@ architecture arch of history_cache is signal ts_latch, ts_latch_next : TIME_TYPE := TIME_INVALID; signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); - signal has_data, has_data_next : std_logic := '0'; - signal has_key_hash, has_key_hash_next : std_logic := '0'; - signal khg_valid_in, khg_ready_in, khg_last_word_in, khg_valid_out, khg_ready_out, khg_last_word_out : std_logic := '0'; signal khg_data_in, khg_data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); - signal has_latched, has_latched_next : std_logic := '0'; signal payload_mem_full, payload_mem_full_next : std_logic := '0'; signal sample_mem_full, sample_mem_full_next : std_logic := '0'; + signal inst_addr_a, inst_addr_a_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_addr_b, inst_addr_b_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_wen_a, inst_wen_b : std_logic := '0'; + signal inst_ren_a, inst_ren_b : std_logic := '0'; + signal inst_read_data_a, inst_read_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal inst_write_data_a, inst_write_data_b : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + + signal inst_op_start_a : std_logic := '0'; + signal inst_op_done_a : std_logic := '0'; + signal inst_opcode_a : INSTANCE_OPCODE_TYPE := NOP; + signal inst_stage_a, inst_stage_a_next : INST_STAGE_TYPE := IDLE; + signal inst_addr_base_a, inst_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_addr_base_a, inst_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_next_addr_base_a, inst_next_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_prev_addr_base_a, inst_prev_addr_base_a_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_empty_head, inst_empty_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_occupied_tail, inst_occupied_tail_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_latch_data, inst_latch_data_next : INST_LATCH_DATA_TYPE := ZERO_INST_LATCH_DATA; + signal update_inst_flags_a : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0'); + signal inst_cnt_a, inst_cnt_a_next : natural range TODO := 0; + signal inst_mem_full, inst_mem_full_next : std_logic := '0'; + signal inst_delete_lock_a, inst_delete_lock_a_next : std_logic := '0'; + signal inst_atomic_lock_a : std_logic := '0'; + signal inst_long_latch_a, inst_long_latch_a_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + + signal writer_pos, writer_pos_next : natural range TODO := 0; + signal writer_bitmap : ENDPOINT_BITMAP_ARRAY_TYPE; + signal instance_state : INSTANCE_STATE_TYPE := ALIVE; + signal key_hash, key_hash_next : KEY_HASH_TYPE := (others => (others => '0')); + signal od_instance_sample_removal : std_logic := '0'; + signal od_oldest_sample_removal : std_logic := '0'; + signal od_sample_removal_done : std_logic := '0'; + signal sample_status_info, sample_status_info_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + signal gen_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + signal deadline : TIME_TYPE := TIME_INVALID; + signal release_inst_lock : std_logic := '0'; + --*****ALIAS DECLARATION***** alias prev_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1; alias prev_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1_next; @@ -104,10 +223,10 @@ architecture arch of history_cache is alias next_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2_next; alias cur_payload : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1; alias cur_payload_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1_next; - alias first_payload : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2; - alias first_payload_next: unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2_next; alias next_payload : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1; alias next_payload_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_1_next; + alias has_data : std_logic is sample_status_info(PAYLOAD_FLAG); + alias has_key_hash : std_logic is sample_status_info(KEY_HASH_FLAG); begin @@ -151,6 +270,26 @@ begin rd_data_b => payload_read_data_b ); + instance_ram_inst : entity work.true_dual_port_ram(arch) + generic map ( + ADDR_WIDTH => INSTANCE_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => INSTANCE_MEMORY_SIZE + ) + port map ( + clk => clk, + addr_a => inst_addr_a, + addr_b => inst_addr_b, + wen_a => inst_wen_a, + wen_b => inst_wen_b, + ren_a => inst_ren_a, + ren_b => inst_ren_b, + wr_data_a => inst_write_data_a, + wr_data_b => inst_write_data_b, + rd_data_a => inst_read_data_a, + rd_data_b => inst_read_data_b + ); + key_hash_generator_inst : entity work.key_hash_generator(arch) port ( clk => clk, @@ -168,10 +307,12 @@ begin parse_a_prc : process (all) variable tmp_opcode : HISTORY_CACHE_OPCODE_TYPE := NOP; variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0')); + variable tmp_bitmap : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1) := (others => '0'); + variable tmp_update : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0'); begin -- Default stage_a_next <= stage_a; - ack_a <= '0'; + res_a <= UNDEFINED; sample_addr_a_next <= sample_addr_a; sample_write_data_a <= (others => '0'); sample_ren_a <= '0'; @@ -184,40 +325,82 @@ begin newest_sample_next <= newest_sample; empty_payload_list_head_next <= empty_payload_list_head; empty_sample_list_head_next <= empty_sample_list_head; - has_data_next <= has_data; - has_key_hash_next <= has_key_hash; payload_addr_latch_1_next <= payload_addr_latch_1; payload_addr_latch_2_next <= payload_addr_latch_2; ts_latch_next <= ts_latch; long_latch_next <= long_latch; sample_addr_latch_1_next <= sample_addr_latch_1; sample_addr_latch_2_next <= sample_addr_latch_2; - has_latched_next <= has_latched; payload_mem_full_next <= payload_mem_full; sample_mem_full_next <= sample_mem_full; + writer_pos_next <= writer_pos; + inst_opcode_a <= NOP; + key_hash_next <= key_hash; + sample_status_info_next <= sample_status_info; + inst_op_start_a <= '0'; khg_last_word_in <= '0'; khg_data_in <= (others => '0'); khg_valid_in <= '0'; khg_ready_out <= '0'; + writer_bitmap <= (others => '0'); + od_instance_sample_removal <= '0'; + od_oldest_sample_removal <= '0'; + release_inst_lock <= '0'; + -- Reset Payload Memory Fullness Indicator + if (payload_mem_full = '1' and empty_payload_list_head /= empty_payload_list_tail) then + payload_mem_full_next <= '0'; + end if; + + -- Reset Sample Memory Fullness Indicator + if (sample_mem_full = '1' and empty_sample_list_head /= empty_sample_list_tail) then + sample_mem_full_next <= '0'; + end if; case (stage_a) is when IDLE => - -- No Memory left for ADD - if (payload_mem_full = '1' or sample_mem_full = '1') then - stage_a_next <= WAIT_FOR_REMOVE; - elsif (start_a = '1') then + -- Release Instance Memory Lock + if (inst_delete_lock_a = '1' and inst_op_done_a = '1') then + inst_op_start_a <= '1'; + inst_opcode_a <= RELEASE_LOCK; + end if; + + if (start_a = '1') then + ready_in_a <= '1'; + case (opcode_a) is when ADD_CHANGE => - stage_a_next <= ADD_SAMPLE_INFO; - sample_addr_a_next <= empty_sample_list_head; - cnt_a_next <= 0; - ack_a <= '1'; + -- This Operation does not accept input at this time + ready_in_a <= '0'; + + -- If memory Full + if (sample_mem_full = '1' or payload_mem_full = '1') then + stage_a_next <= WAIT_FOR_REMOVE; + res_a <= ACK; + else + stage_a_next <= ADD_SAMPLE_INFO; + sample_addr_a_next <= empty_sample_list_head; + cnt_a_next <= 0; + res_a <= ACK; + end if; + when REMOVE_WRITER => + -- Input and Memory Gurad + if (valid_in_a = '1' and inst_op_done_a = '1') then + -- Latch Writer Pos + writer_pos_next <= to_integer(unsigned(data_in_a)); + inst_op_start_a <= '1'; + inst_opcode_a <= GET_FIRST_INSTANCE; + stage_a_next <= REMOVE_WRITER; + res_a <= ACK; + end if; when others => null; end case; end if; + when ADD_SAMPLE_INFO => + -- Precondition: sample_addr_a (empty_sample_list_head) + ready_in_a <= '1'; -- Input Guard @@ -235,79 +418,107 @@ begin -- Initialize local status bits sample_write_data_a(READ_FLAG) <= '0'; -- Latch Status Info - has_data_next <= data_in_a(PAYLOAD_FLAG); - has_key_hash_next <= data_in_a(KEY_HASH_FLAG); + sample_status_info_next <= data_in_a; + sample_status_info_next(READ_FLAG) <= '0'; + -- Latch Key Hash + -- Key Hash 1/4 + when 1 => + key_hash_next(0) <= data_in_a; + -- Key Hash 2/4 + when 2 => + key_hash_next(1) <= data_in_a; + -- Key Hash 3/4 + when 3 => + key_hash_next(2) <= data_in_a; + -- Key Hash 4/4 + when 4 => + key_hash_next(3) <= data_in_a; -- Latch Timestamp for ordering -- Timestamp 1/2 - when 11 => + when 5 => ts_latch_next(0) <= data_in_a; -- Timestamp 2/2 - when 12 => + when 6 => ts_latch_next(1) <= data_in_a; - -- Last Sample Info word - when 14 => - -- NOTE: Until now correct operation of the requester is assumed (No check on last_word_in) - -- No further data - if (has_data = '0' and has_key_hash = '1') then - -- Signal Sucessfull Operation - ack_a <= '1'; - end if; - stage_a_next <= ADD_PAYLOAD_ADDRESS; + -- Lifespan Deadline 2/2 + when 9 => + -- Latch Input, but do not pass to Memory + writer_pos_next <= to_integer(unsigned(data_in_a)); + sample_wen_a <= '0'; + sample_addr_a_next <= sample_addr_a; + stage_a_next <= ADD_PAYLOAD_ADDRESS; when others => null; end case; end if; when ADD_PAYLOAD_ADDRESS => -- Precondition: sample_addr_a (Payload Address) + if (has_data = '1') then -- Store Payload Address sample_wen_a <= '1'; - sample_write_data_a <= empty_payload_list_tail; + sample_write_data_a <= empty_payload_list_head; - payload_addr_a_next <= empty_payload_list_tail + 1; - cur_payload_next <= empty_payload_list_tail; - first_payload_next <= empty_payload_list_tail; - stage_a_next <= ADD_PAYLOAD; - cnt_a_next <= 0; + payload_addr_a_next <= empty_payload_list_head + PMF_NEXT_ADDR_OFFSET; + cur_payload_next <= empty_payload_list_head; else + -- Mark Sample with no Payload sample_wen_a <= '1'; - sample_write_data_a <= MAX_PAYLOAD_ADDRESS; - - -- First Sample - if (newest_sample = MAX_SAMPLE_ADDRESS) then - stage_a_next <= FINALIZE_SAMPLE_INFO; - sample_addr_a_next <= empty_sample_list_head + 16; - next_sample_next <= MAX_SAMPLE_ADDRESS; - prev_sample_next <= MAX_SAMPLE_ADDRESS; - cnt_a_next <= 0; - else - stage_a_next <= FIND_POS; - prev_sample_next <= newest_sample; - sample_addr_a_next <= newest_sample + 11; - cnt_a_next <= 0; - end if; + sample_write_data_a <= PAYLOAD_MEMORY_MAX_ADDRESS; + end if; + + -- If key Hash is avialable, start the Instacne Search first + if (has_key_hash = '1') then + stage_a_next <= INITIATE_INSTANCE_SEARCH; + else + stage_a_next <= ADD_PAYLOAD; + cnt_a_next <= 0; end if; when ADD_PAYLOAD => - -- Precondition: cur_payload set (Current Slot), payload_addr_a (cur_payload+1) - ready_in_a <= '1'; - -- Input Guard - if (valid_in_a = '1') then + -- Precondition (if has_data = '1'): cur_payload set (Current Slot), payload_addr_a (Beginning of Payload Data of cur_payload) + + -- 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 + + if (has_key_hash = '0') then + ready_in_a <= khg_ready_in; + else + ready_in_a <= '1'; + end if; + + -- Flow Control Guard + if ((valid_in_a = '1' and has_key_hash = '0') or (valid_in_a = '1' and has_key_hash = '0' and khg_ready_in = '1')) then cnt_a_next <= cnt_a + 1; - payload_addr_a_next <= payload_addr_a + 1; + payload_addr_a_next <= payload_addr_a + PMF_NEXT_ADDR_OFFSET; - -- Write through - payload_write_data_a <= data_in_a; - payload_wen_a <= '1'; + -- Payload Write + if (has_data = '1') then + payload_write_data_a <= data_in_a; + payload_wen_a <= '1'; + end if; + + -- Key Hash Generator Write + if (has_key_hash = '0') then + khg_data_in <= data_in_a; + khg_valid_in <= '1'; + end if; -- End of Payload if (last_word_in_a = '1') then - -- Mark Operation as sucessfull - ack_a <= '1'; - stage_a_next <= FINALIZE_PAYLOAD; - payload_addr_a_next <= cur_payload; - cnt_a_next <= 0; + if (has_key_hash = '0') then + khg_last_word_in <= '1'; + sample_addr_a_next <= empty_sample_list_head + SMF_KEY_HASH_OFFSET; + stage_a_next <= GET_KEY_HASH; + cnt_a_next <= 0; + else + stage_a_next <= FILTER_STAGE; + end if; -- End of Payload Slot - elsif (cnt_a = PAYLOAD_FRAME_SIZE-2) then + elsif (has_data = '1' and cnt_a = PAYLOAD_FRAME_SIZE-2) then stage_a_next <= NEXT_PAYLOAD_SLOT; payload_addr_a_next <= cur_payload; cnt_a_next <= 0; @@ -315,6 +526,7 @@ begin end if; when NEXT_PAYLOAD_SLOT => -- Precondition: payload_addr_a (Beginning of current Slot) + cnt_a_next <= cnt_a + 1; case (cnt_a) is @@ -323,22 +535,214 @@ begin payload_ren_a <= '1'; when 1 => -- No Empty Payload Slots available - if (payload_read_data_a = MAX_PAYLOAD_ADDRESS) then - -- Skip Operation - stage_a_next <= SKIP_ADD; + if (payload_read_data_a = PAYLOAD_MEMORY_MAX_ADDRESS) then + -- TODO else - -- Latch next Payload Slot - cur_payload_next <= payload_read_data_a; - - -- Continue - payload_addr_a_next <= payload_read_data_a + 1; + -- Latch next Payload Slot and Continue + cur_payload_next <= payload_read_data_a; + payload_addr_a_next <= payload_read_data_a + PMF_NEXT_ADDR_OFFSET; stage_a_next <= ADD_PAYLOAD; end if; when others => null; end case; + when GET_KEY_HASH => + -- Precondition: sample_addr_a (KeyHash 1/4 of current sample) + + khg_ready_out <= '1'; + + if (khg_valid_out = '1') then + cnt_a_next <= cnt_a + 1; + sample_addr_a_next <= sample_addr_a + 1; + sample_wen_a <= '1'; + + sample_write_data_a <= khg_data_out; + -- Latch Key Hash + key_hash_next(cnt_a) <= khg_data_out; + + -- Exit Condition + if (khg_last_word_out = '1') then + -- DONE + stage_a_next <= INITIATE_INSTANCE_SEARCH; + end if; + end if; + when INITIATE_INSTANCE_SEARCH => + -- Memory Operation Guard + if (inst_op_done_a = '1') then + inst_opcode_a <= SEARCH_INSTANCE; + inst_op_start_a <= '1'; + + -- Payload not yet stored + if (has_data = '1') then + stage_a_next <= ADD_PAYLOAD; + cnt_a_next <= 0; + else + stage_a_next <= FILTER_STAGE; + end if; + end if; + when FILTER_STAGE => + -- Precondition: prev_sample set (empty_sample_list_tail) + + -- Wait for Instance Search to finish + if (inst_op_done_a = '1') then + -- Instance Found + if (inst_addr_base_a /= INSTANCE_MEMORY_MAX_ADDRESS) then + -- TIME_BASED_FILTER QOS + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time < inst_data.ignore_deadline) then + -- Reject Change + res_a <= REJECTED; + stage_a_next <= IDLE; + -- RESOURCE_LIMITS_QOS / HISTORY_QOS + elsif (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then + if (HISTORY_QOS = KEEP_LAST_HISTORY_QOS) then + -- Reject Change + res_a <= REJECTED; + stage_a_next <= IDLE; + else + od_instance_sample_removal <= '1'; + -- Wait until B process completes On-Demand Sample Removal + if (od_sample_removal_done = '1') then + -- Accept Change + res_a <= ACCEPTED; + stage_a_next <= UPDATE_INSTANCE; + end if; + end if; + else + -- Accept Change + res_a <= ACCEPTED; + stage_a_next <= UPDATE_INSTANCE; + end if; + else + -- MAX_INSTANCES Reached (Instance Memory Full) + if (inst_mem_full = '1') then + -- Reject Change + res_a <= REJECTED; + stage_a_next <= IDLE; + else + -- Accept Change + res_a <= ACCEPTED; + + -- Only Insert Sample/Instance if Instance is ALIVE + if (sample_status_info(DISPOSED_FLAG) /= '1' and sample_status_info(UNREGISTERED_FLAG) /= '1' and sample_status_info(FILTERED_FLAG) /= '1') then + -- Insert New Instance + inst_opcode_a <= INSERT_INSTANCE; + inst_op_start_a <= '1'; + release_inst_lock <= '1'; + + if (has_data = '1') then + payload_addr_a_next <= cur_payload; + stage_a_next <= FINALIZE_PAYLOAD; + cnt_a_next <= 0; + else + stage_a_next <= SAMPLE_PRE_FINISH; + sample_addr_a_next <= SMF_DISPOSED_GEN_CNT_OFFSET; + cnt_a_next <= 0 when GENERATION_COUNTERS else 2; + end if; + else + -- Ignore + stage_a_next <= IDLE; + end if; + end if; + end if; + end if; + when UPDATE_INSTANCE => + -- Memory Operation Guard + if (inst_op_done_a = '1') then + -- DEFAULT + tmp_update := (others => '0'); + + -- Instance DISPOSED + if (sample_status_info(DISPOSED_FLAG) = '1') then + -- ALIVE -> NOT_ALIVE_DISPOSED Transition + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) /= '1') then + -- STATUS INFO + tmp_update <= tmp_update or STATUS_FLAG; + instance_state <= NOT_ALIVE_DISPOSED; + end if; + -- WRITER BITMAP + -- Convert Writer Bitmap to SLV + tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + -- Remove Writer + tmp_bitmap(writer_pos) := '0'; + -- Convert Back + writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + tmp_update := tmp_update or WRITER_BITMAP_FLAG; + -- Instance UNREGISTERED + elsif (sample_status_info(UNREGISTERED_FLAG) = '1') then + -- WRITER BITMAP + -- Convert Writer Bitmap to SLV + tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + -- Remove Writer + tmp_bitmap(writer_pos) := '0'; + -- Convert Back + writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + tmp_update := tmp_update or WRITER_BITMAP_FLAG; + + -- ALIVE -> NOT_ALIVE_NO_WRITERS Transition + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) /= '1' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) /= '1' and tmp_bitmap = (tmp_bitmap => '0')) then + -- STATUS INFO + tmp_update <= tmp_update or STATUS_FLAG; + instance_state <= NOT_ALIVE_NO_WRITERS; + end if; + -- Instance ALIVE/FILTERED + else + -- STATUS INFO + tmp_update <= tmp_update or STATUS_FLAG; + instance_state <= ALIVE; + + -- GENERATION COUNTERS + if (GENERATION_COUNTERS) then + -- NOT_ALIVE_DISPOSED -> ALIVE Transition + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1') then + tmp_update := tmp_update or DISPOSED_CNT_FLAG; + gen_cnt <= inst_data.disposed_gen_cnt + 1; + -- NOT_ALIVE_NO_WRITERS -> ALIVE Transition + elsif (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then + tmp_update := tmp_update or NO_WRITERS_CNT_FLAG; + gen_cnt <= inst_data.no_writers_gen_cnt + 1; + end if; + end if; + + -- WRITER BITMAP + -- Convert Writer Bitmap to SLV + tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + -- Write if Writer New for Instance + if (tmp_bitmap(writer_pos) /= '1') then + -- Remove Writer + tmp_bitmap(writer_pos) := '0'; + -- Convert Back + writer_bitmap <= from_endpoint_bitmap(tmp_bitmap); + tmp_update := tmp_update or WRITER_BITMAP_FLAG; + end if; + end if; + + -- INSANCE SAMPLE COUNT + if (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED) then + tmp_update := tmp_update or SAMPLE_CNT_FLAG; + end if; + -- IGNORE DEADLINE + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + tmp_update := tmp_update or IGNORE_DEADLINE_FLAG; + deadline <= time + TIME_BASED_FILTER_QOS; + end if; + + inst_opcode_a <= UPDATE_INSTANCE; + inst_op_start_a <= '1'; + release_inst_lock <= '1'; + update_inst_flags_a <= tmp_update; + + if (has_data = '1') then + payload_addr_a_next <= cur_payload; + stage_a_next <= FINALIZE_PAYLOAD; + cnt_a_next <= 0; + else + stage_a_next <= SAMPLE_PRE_FINISH; + sample_addr_a_next <= SMF_DISPOSED_GEN_CNT_OFFSET; + cnt_a_next <= 0 when GENERATION_COUNTERS else 2; + end if; + end if; when FINALIZE_PAYLOAD => - -- Precondition: payload_addr_a (Beginning of Current Slot) + -- Precondition: payload_addr_a (Beginning of Last Added Payload Slot) cnt_a_next <= cnt_a + 1; @@ -348,29 +752,67 @@ begin payload_ren_a <= '1'; when 1 => -- No Empty Payload Slot available - if (payload_read_data_a = MAX_PAYLOAD_ADDRESS) then + if (payload_read_data_a = PAYLOAD_MEMORY_MAX_ADDRESS) then assert (cur_payload = empty_payload_list_tail) report "Payload List empty, but HEAD /= TAIL" severity FAILURE; - -- Signal No available slots by setting HEAD to MAX ADDRESS + -- Signal Sample Memory Full payload_mem_full_next <= '1'; else empty_payload_list_head_next <= payload_read_data_a; end if; -- Make current Slot the Tail - payload_write_data_a <= MAX_PAYLOAD_ADDRESS; + payload_write_data_a <= PAYLOAD_MEMORY_MAX_ADDRESS; payload_wen_a <= '1'; + stage_a_next <= SAMPLE_PRE_FINISH; + sample_addr_a_next <= SMF_DISPOSED_GEN_CNT_OFFSET; + cnt_a_next <= 0 when GENERATION_COUNTERS else 2; + when others => + null; + end case; + when SAMPLE_PRE_FINISH => + -- Precondition: sample_addr_a (Disposed generation Counter of New Sample) + + cnt_a_next <= cnt_a + 1; + + case (cnt_a) is + -- Disposed Generation Counter + when 0 => + if (GENERATION_COUNTERS) then + sample_addr_a_next <= sample_addr_a + 1; + sample_wen_a <= '1'; + + -- NOT_ALIVE_DISPOSED -> ALIVE Transition + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1' and sample_status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and sample_status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + sample_write_data_a <= gen_cnt + 1; + else + sample_write_data_a <= gen_cnt; + end if; + end if; + -- No Writer Generation Counter + when 1 => + if (GENERATION_COUNTERS) then + sample_wen_a <= '1'; + + -- NOT_ALIVE_NO_WRITERS -> ALIVE Transition + if (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1' and sample_status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and sample_status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + sample_write_data_a <= gen_cnt + 1; + else + sample_write_data_a <= gen_cnt; + end if; + end if; + when 2 => -- First Sample - if (newest_sample = MAX_SAMPLE_ADDRESS) then + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then stage_a_next <= FINALIZE_SAMPLE_INFO; - sample_addr_a_next <= empty_sample_list_head + 16; - next_sample_next <= MAX_SAMPLE_ADDRESS; - prev_sample_next <= MAX_SAMPLE_ADDRESS; + sample_addr_a_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; cnt_a_next <= 0; else stage_a_next <= FIND_POS; prev_sample_next <= newest_sample; - sample_addr_a_next <= newest_sample + 11; + sample_addr_a_next <= newest_sample + SMF_TIMESTAMP_OFFSET; cnt_a_next <= 0; end if; when others => @@ -388,7 +830,7 @@ begin sample_ren_a <= '1'; -- Timestamp 1/2 when 1 => - sample_addr_a_next <= sample_addr_a + 4; -- Prev Addr + sample_addr_a_next <= sample_addr_a + SMF_PREV_ADDR_OFFSET-(SMF_TIMESTAMP_OFFSET+1); -- Prev Addr sample_ren_a <= '1'; long_latch_next <= sample_read_data_a; -- Timestamp 2/2 @@ -397,7 +839,7 @@ begin tmp_dw := (0 => unsigned(long_latch), 1 => unsigned(sample_read_data_a)); - sample_addr_a_next <= sample_addr_a + 1; -- Next Addr + sample_addr_a_next <= sample_addr_a + SMF_NEXT_ADDR_OFFSET-SMF_PREV_ADDR_OFFSET; -- Next Addr -- Found position (After current slot) if (ts_latch >= tmp_dw) then @@ -407,14 +849,14 @@ begin -- Previous Address when 3 => -- No previous Slot (Oldest Sample) - if (sample_read_data_a = MAX_PAYLOAD_ADDRESS) then + if (sample_read_data_a = PAYLOAD_MEMORY_MAX_ADDRESS) then assert (prev_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but sample is not OLDEST (HEAD)" severity FAILURE; stage_a_next <= FIX_POINTERS; cnt_a_next <= 0; else prev_sample_next <= sample_read_data_a; - sample_addr_a_next <= sample_read_data_a + 11; + sample_addr_a_next <= sample_read_data_a + SMF_TIMESTAMP_OFFSET; cnt_a_next <= 0; end if; end case; @@ -434,18 +876,18 @@ begin sample_wen_a <= '1'; -- No next Slot (Newest Sample) - if (sample_read_data_a = MAX_SAMPLE_ADDRESS) then + if (sample_read_data_a = SAMPLE_MEMORY_MAX_ADDRESS) then assert (prev_sample = newest_sample) report "Next Sample is MAX_ADDRESS, but sample is not NEWEST (TAIL)" severity FAILURE; - next_sample_next <= MAX_SAMPLE_ADDRESS; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; stage_a_next <= FINALIZE_SAMPLE_INFO; - sample_addr_a_next <= empty_sample_list_head + 16; + sample_addr_a_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample cnt_a_next <= 0; else -- Latch Next Sample next_sample_next <= sample_read_data_a; - sample_addr_a_next <= sample_read_data_a + 16; -- Prev Addr of Next Sample + sample_addr_a_next <= sample_read_data_a + SMF_PREV_ADDR_OFFSET; -- Prev Addr of Next Sample end if; when 2 => -- Fix Previous Pointer @@ -453,7 +895,7 @@ begin sample_wen_a <= '1'; stage_a_next <= FINALIZE_SAMPLE_INFO; - sample_addr_a_next <= empty_sample_list_head + 16; + sample_addr_a_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample cnt_a_next <= 0; when others => null; @@ -464,19 +906,21 @@ begin cnt_a_next <= cnt_a + 1; case (cnt_a) is + -- Previous Address when 0 => - sample_addr_a_next <= sample_addr_a + 1; + sample_addr_a_next <= sample_addr_a + SMF_NEXT_ADDR_OFFSET-SMF_PREV_ADDR_OFFSET; -- Write Prev Addr sample_write_data_a <= prev_sample; sample_ren_a <= '1'; + -- Preload when 1 => - -- Preload sample_ren_a <= '1'; + -- Next Address when 2 => -- No empty Sample Slot Available - if (sample_read_data_a = MAX_SAMPLE_ADDRESS) then - -- Signal No available slots by setting HEAD to MAX ADDRESS + if (sample_read_data_a = SAMPLE_MEMORY_MAX_ADDRESS) then + -- Signal Smaple Memory Full sample_mem_full_next <= '1'; else empty_sample_list_head_next <= sample_read_data_a; @@ -491,129 +935,629 @@ begin newest_sample_next <= empty_sample_list_head; end if; - if (has_key_hash = '0') then - -- Key Hash needs Calculating - if (has_data = '1') then - stage_a_next <= GET_NEXT_PAYLOAD_SLOT; - sample_addr_a_next <= empty_sample_list_head + 1; -- Points to beginning of Key Hash - payload_addr_a_next <= first_payload; -- Points to first payload slot - cnt_a_next <= 0; - else - stage_a_next <= INITIATE_KEY_HASH_CALCULATION_IN; - sample_addr_a_next <= empty_sample_list_head + 1; -- Points to beginning of Key Hash - end if; - else - -- DONE - stage_a_next <= IDLE; - end if; - end case; - when GET_NEXT_PAYLOAD_SLOT => - -- Precondition: payload_addr_a (Beginning of payload slot) - cnt_a_next <= cnt_a + 1; - payload_addr_a_next <= payload_addr_a + 1; - payload_ren_a <= '1'; - - case (cnt_a) is - -- Preload - when 0 => - null; - when 1 => - -- Latch Next Slot - next_payload_next <= payload_read_data_a; - stage_a_next <= INITIATE_KEY_HASH_CALCULATION; - cnt_a_next <= 0; - has_latched_next <= '0'; - end case; - when INITIATE_KEY_HASH_CALCULATION_MEM => - -- Precondition: payload_addr_a (Current Beginning+2), payload_read_data_a (Current Beginning+1), next_payload set to next Slot (if available) or MAX_ADDRESS (if not availble) - -- Output Guard - if (khg_ready_in = '1') then - cnt_a_next <= cnt_a + 1; - payload_addr_a_next <= payload_addr_a + 1; - payload_ren_a <= '1'; - khg_valid_in <= '1'; - - if (has_latched = '0') then - -- Passthrough - khg_data_in <= payload_read_data_a; - else - -- Previously Latched - khg_data_in <= long_latch; - end if; - - -- Reset - has_latched_next <= '0'; - - if (cnt_a = PAYLOAD_FRAME_SIZE-2) then - -- Last Payload Slot - if (next_payload = MAX_PAYLOAD_ADDRESS) then - khg_last_word_in <= '1'; - stage_a_next <= GET_KEY_HASH; - else - stage_a_next <= GET_NEXT_PAYLOAD_SLOT; - payload_addr_a_next <= next_payload; - cnt_a_next <= 0; - end if; - end if; - else - khg_valid_in <= '0'; - -- Latch Read Data - if (has_latched = '0') then - long_latch_next <= payload_read_data_a; - has_latched_next <= '1'; - end if; - end if; - when INITIATE_KEY_HASH_CALCULATION_IN => - -- Input Passthrough - ready_in_a <= khg_ready_in; - khg_valid_in <= valid_in_a; - khg_data_in <= data_in_a; - khg_last_word_in<= last_word_in_a; - if (last_word_in_a = '1') then - stage_a_next <= GET_KEY_HASH; - end if; - when GET_KEY_HASH => - -- Precondition: sample_addr_a (KeyHash 1/4 of current sample) - khg_ready_out <= '1'; - if (khg_valid_out = '1') then - sample_addr_a_next <= sample_addr_a + 1; - sample_wen_a <= '1'; - - sample_write_data_a <= khg_data_out; - - -- XXX: Assumes the Key Hash Generator writes only KeyHash size - -- Exit Condition - if (khg_last_word_out = '1') then -- DONE stage_a_next <= IDLE; + end case; + when SKIP_ADD => + case (cnt_a) is + -- SKIP READ + when 0 => + ready_in_a <= '1'; + -- Wait until last word from input + if (last_word_in_a = '1') then + cnt_a_next <= 1; + end if; + -- REJECT SAMPLE + when 1 => + res_a <= REJECTED; + stage_a_next <= IDLE; + when others => + null; + end case; + when REMOVE_WRITER => + -- Memory Operation Guard + if (inst_op_done_a = '1') then + -- No More Instances + if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then + -- DONE + stage_a_next <= IDLE; + else + -- Convert Writer Bitmap to SLV + tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + + -- Remove Writer + tmp_bitmap(writer_pos) := '0'; + + -- 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); + + -- No More Writers for Instance + if (tmp_bitmap = (tmp_bitmap'range => '0')) then + inst_op_start_a <= '1'; + instance_state <= NOT_ALIVE_NO_WRITERS; + inst_opcode_a <= UPDATE_INSTANCE; + update_inst_flags_a <= STATUS_FLAG or WRITER_BITMAP_FLAG; + else + inst_op_start_a <= '1'; + inst_opcode_a <= UPDATE_INSTANCE; + update_inst_flags_a <= WRITER_BITMAP_FLAG; + end if; + + stage_a_next <= GET_NEXT_INSTANCE; end if; end if; - when SKIP_ADD => - ready_in_a <= '1'; - -- Wait until last word from input - -- NOTE: By not pulling ack_a high we are signaling that the operation failed - if (last_word_in_a = '1') then - -- NOTE: Because we did not yet change any pointer from the linked lists, we do not have to do any cleanup. - stage_a_next <= IDLE; + when GET_NEXT_INSTANCE => + -- Wait for Operation to Complete + if (inst_op_done_a = '1') then + inst_op_start_a <= '1'; + inst_opcode_a <= NEXT_INSTANCE; + stage_a_next <= REMOVE_WRITER; end if; when WAIT_FOR_REMOVE => - -- Exit Condition - if (payload_mem_full = '0' and sample_mem_full = '0') then - stage_a_next <= IDLE; - end if; + -- Stall Input + ready_in_a <= '0'; - -- Reset Payload Memory Fullness Indicator - if (payload_mem_full = '1' and empty_payload_list_head /= empty_payload_list_tail) then - payload_mem_full_next <= '0'; - end if; - - -- Reset Sample Memory Fullness Indicator - if (sample_mem_full = '1' and empty_sample_list_head /= empty_sample_list_tail) then - sample_mem_full_next <= '0'; + if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then + -- Reject Change + stage_a_next <= SKIP_ADD; + cnt_a_next <= 0; + else + od_oldest_sample_removal <= '1'; + + -- NOTE: We are ignoring the od_sample_removal_done signal of process B, because in this + -- case we can directly observe the status from the available signals. This cannot + -- be done in the MAX_SAMPLES_PER_INSTANCE removal case, since there we have to wait + -- until process B explicitly states that it has removed a sample of the offending instance. + -- In addition to that, the removal of the oldest sample is no guarantee that the payload + -- memory will also get freed (Since the oldest sample may be one without data). + -- Here we are keeping the od_oldest_sample_removal signal high (meaning process B will keep + -- removing samples) as long as it takes for both memories to get freed. + + -- Memory Available + if (sample_mem_full = '0' and payload_mem_full = '0') then + stage_a_next <= ADD_SAMPLE_INFO; + sample_addr_a_next <= empty_sample_list_head; + cnt_a_next <= 0; + end if; end if; when others => null; end case; end process; + inst_ctrl_prc : process(all) + begin + -- DEFAULT Registered + inst_stage_a_next <= inst_stage_a; + inst_addr_base_a_next <= inst_addr_base_a; + inst_addr_a_next <= inst_addr_a; + inst_empty_head_next <= inst_empty_head; + inst_occupied_tail_next <= inst_occupied_tail; + inst_latch_data_next <= inst_latch_data; + inst_next_addr_base_a_next <= inst_next_addr_base_a; + inst_prev_addr_base_a_next <= inst_prev_addr_base_a; + inst_cnt_a_next <= inst_cnt_a; + inst_mem_full_next <= inst_mem_full; + inst_delete_lock_a_next <= inst_delete_lock_a; + inst_data_next <= inst_data; + -- DEFAULT Unregistered + inst_write_data_a <= (others => '0'); + inst_op_done_a <= '0'; + inst_ren_a <= '0'; + inst_wen_a <= '0'; + inst_atomic_lock_a <= '0'; + + + case (mem_stage) is + when IDLE => + inst_op_done_a <= '1'; + + -- Lock Release + if (inst_delete_lock_a = '1' and inst_latch_data.release_lock = '1') then + inst_delete_lock_a_next <= '0'; + end if; + + if (inst_op_start_a = '1') then + -- Latch Signals needed for Mermory Operation (Use _next signals, because some signals are set in same clk) + inst_latch_data_next <= ( + key_hash => key_hash_next, + instance_state => instance_state, + gen_cnt => gen_cnt, + deadline => deadline, + writer_bitmap => writer_bitmap, + update_flags => update_inst_flags_a, + release_lock => release_inst_lock + ); + + -- Reset Memory Fullness Indicator + if (inst_mem_full = '1' and inst_empty_head /= inst_empty_tail) then + inst_mem_full_next <= '0'; + end if; + + case(inst_opcode_a) is + when SEARCH_INSTANCE => + -- Reset Data + inst_data_next <= ZERO_INSTANCE_DATA; + -- NOTE: This process gets the lock implicitly when the SEARCH_INSTANCE, or GET_FIRST_INSTANCE operation is called, and has to be released explicitly + -- by the main process. There are two ways to release the lock: 1) The man process explicitly calles the RELEASE_LOCK operation 2) The main + -- process pulls the release_inst_lock signal high during the issuing of the last memory operation (Lock will be release after the opration finishes) + -- Process B has lock + if (inst_delete_lock_b = '1') then + -- Wait until process B releases lock + inst_stage_a_next <= WAIT_FOR_LOCK_1; + else + -- NOTE: The case that both processes aqcuire the lock at the same time is handled by the B process in the next clock cycle. + -- Get Lock + inst_delete_lock_a_next <= '1'; + -- No Instances avialable + if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_prev_addr_base_a <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_a_next <= inst_occupied_head; + inst_addr_a_next <= inst_occupied_head; + inst_stage_a_next <= SEARCH_INSTANCE; + inst_cnt_a_next <= 0; + end if; + end if; + when INSERT_INSTANCE => + -- NOTE: Since this process has no way to communicate a failed insert to the main process, it has to be made sure + -- by the main process that the operation can succeed (Memory is available) + assert (inst_mem_full = '0') report "Instance Insertion while memory Full" severity FAILURE; + inst_prev_addr_base_a_next <= inst_occupied_tail; + inst_addr_base_a_next <= inst_occupied_tail; + inst_addr_a_next <= inst_occupied_tail; + inst_stage_a_next <= INSERT_PREPARATION; + inst_cnt_a_next <= 0; + when UPDATE_INSTANCE => + inst_addr_base_a_next <= inst_addr_base_a; + if ((update_inst_flags_a and STATUS_FLAG) = STATUS_FLAG) then + inst_stage_a_next <= UPDATE_INSTANCE; + inst_addr_a_next <= inst_addr_base_a + 5; + inst_cnt_a_next <= 0; + elsif ((update_inst_flags_a and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then + inst_stage_a_next <= UPDATE_INSTANCE; + inst_addr_a_next <= inst_addr_base_a + 6; + inst_cnt_a_next <= 3; + elsif ((update_inst_flags_a and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then + inst_stage_a_next <= UPDATE_INSTANCE; + inst_addr_a_next <= inst_addr_base_a + 7; + inst_cnt_a_next <= 6; + elsif ((update_inst_flags_a and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then + inst_stage_a_next <= UPDATE_INSTANCE; + inst_addr_a_next <= inst_addr_base_a + 8; + inst_cnt_a_next <= 7; + elsif ((update_inst_flags_a and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_stage_a_next <= UPDATE_INSTANCE; + inst_addr_a_next <= inst_addr_base_a + 9; + inst_cnt_a_next <= 8; + end if; + when GET_FIRST_INSTANCE => + -- NOTE: This process gets the lock implicitly when the SEARCH_INSTANCE, or GET_FIRST_INSTANCE operation is called, and has to be released explicitly + -- by the main process via the RELEASE_LOCK operation. + -- Process B has lock + if (inst_delete_lock_b = '1') then + -- Wait until process B releases lock + inst_stage_a_next <= WAIT_FOR_LOCK_2; + else + -- NOTE: The case that both processes aqcuire the lock at the same time is handled by the B process in the next clock cycle. + -- Get Lock + inst_delete_lock_a_next <= '1'; + -- No Instances avialable + if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_prev_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_a_next <= inst_occupied_head; + inst_addr_a_next <= inst_occupied_head + 5; + inst_stage_a_next <= GET_INSTANCE_DATA; + inst_cnt_a_next <= 0; + end if; + end if; + when GET_NEXT_INSTANCE => + inst_prev_addr_base_a_next <= inst_addr_base_a; + inst_addr_base_a_next <= inst_next_addr_base_a; + inst_addr_a_next <= inst_next_addr_base_a; + inst_stage_a_next <= GET_NEXT_INSTANCE; + inst_cnt_a_next <= 0; + when RELEASE_LOCK => + inst_delete_lock_a_next <= '0'; + when others => + null; + end case; + end if; + when WAIT_FOR_LOCK_1 => + -- Wait until B process releases lock + if (inst_delete_lock_b = '0') then + -- Get Lock + inst_delete_lock_a_next <= '1'; + if (inst_occupied_head /= INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= inst_occupied_head; + inst_addr_a_next <= inst_occupied_head; + inst_stage_a_next <= SEARCH_INSTANCE; + inst_cnt_a_next <= 0; + else + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; + end if; + end if; + when WAIT_FOR_LOCK_2 => + -- Wait until B process releases lock + if (inst_delete_lock_b = '0') then + -- Get Lock + inst_delete_lock_a_next <= '1'; + -- No Instances avialable + if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_prev_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_a_next <= inst_occupied_head; + inst_addr_a_next <= inst_occupied_head + 5; + inst_stage_a_next <= GET_INSTANCE_DATA; + inst_cnt_a_next <= 0; + end if; + end if; + when SEARCH_INSTANCE => + inst_ren_a <= '1'; + inst_cnt_a_next <= inst_cnt_a + 1; + inst_addr_a_next <= inst_addr_a + 1; + + case (inst_cnt_a) is + -- Preload + when 0 => + null; + -- Next Instance + when 1 => + inst_next_addr_base_a_next <= inst_read_data_a; + -- Key Hash 1/4 + when 2 => + -- No Match + if (inst_read_data_a /= inst_latch_data.key_hash(0)) then + -- Reached List Tail, No Match + if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_a_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_a_next <= inst_addr_base_a; + inst_addr_base_a_next <= inst_next_addr_base_a; + inst_addr_a_next <= inst_next_addr_base_a; + inst_cnt_a_next <= 0; + end if; + end if; + -- Key Hash 2/4 + when 3 => + -- No Match + if (inst_read_data_a /= inst_latch_data.key_hash(1)) then + -- Reached List Tail, No Match + if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_a_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_a_next <= inst_addr_base_a; + inst_addr_base_a_next <= inst_next_addr_base_a; + inst_addr_a_next <= inst_next_addr_base_a; + inst_cnt_a_next <= 0; + end if; + end if; + -- Key Hash 3/4 + when 4 => + -- No Match + if (inst_read_data_a /= inst_latch_data.key_hash(2)) then + -- Reached List Tail, No Match + if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_a_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_a_next <= inst_addr_base_a; + inst_addr_base_a_next <= inst_next_addr_base_a; + inst_addr_a_next <= inst_next_addr_base_a; + inst_cnt_a_next <= 0; + end if; + end if; + -- Key Hash 4/4 + when 5 => + -- No Match + if (inst_read_data_a /= inst_latch_data.key_hash(3)) then + -- Reached List Tail, No Match + if (inst_addr_base_a = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_a_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_a_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_a_next <= inst_addr_base_a; + inst_addr_base_a_next <= inst_next_addr_base_a; + inst_addr_a_next <= inst_next_addr_base_a; + inst_cnt_a_next <= 0; + end if; + -- Match + else + -- Fetch Instance Data + inst_stage_a_next <= GET_INSTANCE_DATA; + inst_cnt_a_next <= 1; -- No preload needed + end if; + when others => + null; + end case; + when GET_NEXT_INSTANCE => + case (inst_cnt_a) is + -- Preload + when 0 => + inst_wen_a <= '1'; + -- Next Instance + when 1 => + inst_addr_base_a_next <= inst_read_data_a; + inst_addr_a_next <= inst_read_data_a + 5; + inst_cnt_a_next <= 0; + inst_stage_a_next <= GET_INSTANCE_DATA; + end case; + when GET_INSTANCE_DATA => + inst_ren_a <= '1'; + inst_cnt_a_next <= inst_cnt_a + 1; + inst_addr_a_next <= inst_addr_a + 1; + + case (inst_cnt_a) is + -- Memory Preload + when 0 => + null; + -- Status Info + when 1 => + inst_data_next.status_info <= inst_read_data_a; + -- Sample Count + when 2 => + inst_data_next.sample_cnt <= inst_read_data_a; + -- Disposed Generation Count + when 3 => + inst_data_next.disposed_gen_cnt <= inst_read_data_a; + -- No Writers Generation Count + when 4 => + inst_data_next.no_writers_gen_cnt <= inst_read_data_a; + -- Ignore Deadline 1/2 + when 5 => + inst_data_next.ignore_deadline(0) <= unsigned(inst_read_data_a); + -- Ignore Deadline 2/2 + when 5 => + inst_data_next.ignore_deadline(1) <= unsigned(inst_read_data_a); + -- DONE + inst_stage_a_next <= GET_WRITER_BITMAP; + inst_cnt_a_next <= 0; + when others => + null; + end case; + when GET_WRITER_BITMAP => + inst_cnt_a_next <= inst_cnt_a + 1; + + inst_latch_data_next.writer_bitmap(inst_cnt_a) <= inst_read_data_a; + + if (inst_cnt_a = writer_bitmap'length-1) then + -- DONE + inst_stage_a_next <= IDLE; + end if; + when INSERT_PREPARATION => + inst_cnt_a_next <= inst_cnt_a + 1; + + case (inst_cnt_a) is + -- Next Payload Slot (Old Occupied Tail) + when 0 => + -- Point Old Occupied Tail to New Occupied Tail + inst_write_data_a <= inst_empty_head; + inst_wen_a <= '1'; + inst_occupied_tail_next <= inst_empty_head; + + inst_addr_a_next <= inst_empty_head; + inst_addr_base_a_next <= inst_empty_head; + -- Preload + when 1 => + inst_ren_a <= '1'; + -- Next Payload Slot (New Occupied Tail) + when 2 => + -- Instance Memory Full + if (inst_read_data_a = INSTANCE_MEMORY_MAX_ADDRESS) then + assert (inst_empty_head = inst_empty_tail) report "Instance empty list empty, but HEAD /= TAIL" severity FAILURE; + inst_mem_full_next <= '1'; + inst_next_addr_base_a_next <= inst_empty_head; -- Keep same tail + else + -- Latch new Empty Head + inst_next_addr_base_a_next <= inst_read_data_a; + end if; + inst_stage_a_next <= INSERT_INSTANCE; + inst_cnt_a_next <= 0; + when others => + null; + end case; + when INSERT_INSTANCE => + inst_wen_a <= '1'; + inst_addr_a_next <= inst_addr_a + 1; + inst_cnt_a_next <= inst_cnt_a + 1; + + case (inst_cnt_a) is + -- Next Instance Address + when 0 => + -- Mark as Tail + inst_write_data_a <= INSTANCE_MEMORY_MAX_ADDRESS; + -- Set New Empty List Head + inst_empty_head_next <= inst_next_addr_base_a; + -- Key Hash 1/4 + when 1 => + inst_write_data_a <= inst_latch_data.key_hash(0); + -- Key Hash 2/4 + when 2 => + inst_write_data_a <= inst_latch_data.key_hash(1); + -- Key Hash 3/4 + when 3 => + inst_write_data_a <= inst_latch_data.key_hash(2); + -- Key Hash 4/4 + when 4 => + inst_write_data_a <= inst_latch_data.key_hash(3); + -- Status Info + when 5 => + inst_write_data_a <= inst_latch_data.status_info; + -- Sample Count + when 6 => + inst_write_data_a <= std_logic_vector(to_unsigned(1, WORD_WIDTH)); + -- Disposed Generation Count + when 7 => + inst_write_data_a <= (others => '0'); + -- No Writers Generation Count + when 8 => + inst_write_data_a <= (others => '0'); + -- Ignore Deadline 1/2 + when 9 => + inst_write_data_a <= inst_latch_data.deadline(0); + -- Ignore Deadline 1/2 + when 10 => + inst_write_data_a <= inst_latch_data.deadline(0); + + inst_stage_a_next <= SET_WRITER_BITMAP; + inst_cnt_a_next <= 0; + when others => + null; + end case; + when SET_WRITER_BITMAP => + inst_wen_a <= '1'; + inst_addr_a_next <= inst_addr_a + 1; + inst_cnt_a_next <= inst_cnt_a + 1; + + inst_write_data_a <= inst_latch_data.writer_bitmap(inst_cnt_a); + + -- Exit Condition + if (inst_cnt_a = inst_latch_data.writer_bitmap'length-1) then + -- DONE + inst_stage_a_next <= IDLE; + end if; + when UPDATE_INSTANCE => + inst_cnt_a_next <= inst_cnt_a + 1; + + case (inst_cnt_a) is + -- *Status Info Begin* + -- Preload + when 0 => + if ((inst_latch_data.update_flags and STATUS_FLAG) = STATUS_FLAG) then + inst_ren_a <= '1'; + inst_atomic_lock_a <= '1'; + else + -- Skip + inst_addr_a_next <= inst_addr_a + 1; + inst_cnt_a_next <= 3; + end if; + -- Read + when 1 => + -- Latch Contents + inst_atomic_lock_a <= '1'; + inst_long_latch_a_next <= inst_read_data_a; + -- Write + when 2 => + inst_write_data_a <= inst_long_latch_a; + case (inst_latch_data.instance_state) is + when ALIVE => + inst_write_data_a(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + inst_write_data_a(NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; + inst_write_data_a(LIVELINESS_FLAG) <= '1'; + when NOT_ALIVE_DISPOSED => + inst_write_data_a(NOT_ALIVE_DISPOSED_FLAG) <= '1'; + inst_write_data_a(NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; + inst_write_data_a(LIVELINESS_FLAG) <= '1'; + when NOT_ALIVE_NO_WRITERS => + inst_write_data_a(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + inst_write_data_a(NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; + inst_write_data_a(LIVELINESS_FLAG) <= '1'; + end case; + inst_addr_a_next <= inst_addr_a + 1; + inst_wen_a <= '1'; + inst_atomic_lock_a <= '1'; + + -- If nothing else to update + if ((inst_latch_data.update_flags and (SAMPLE_CNT_FLAG or DISPOSED_CNT_FLAG or NO_WRITERS_CNT_FLAG or IGNORE_DEADLINE_FLAG or WRITER_BITMAP_FLAG)) = (inst_latch_data.update_flags'range => '0')) then + -- DONE + inst_stage_a_next <= IDLE; + end if; + -- *Status Info End* + -- *Sample Count Begin* + -- Preload + when 3 => + if ((inst_latch_data.update_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then + inst_ren_a <= '1'; + inst_atomic_lock_a <= '1'; + else + -- Skip + inst_addr_a_next <= inst_addr_a + 1; + inst_cnt_a_next <= 6; + end if; + -- Read + when 4 => + -- Latch Contents + inst_atomic_lock_a <= '1'; + inst_long_latch_a_next <= inst_read_data_a; + when 5 => + -- Increment Sample Count + inst_write_data_a <= std_logic_vector(unsigned(inst_long_latch_a) + 1); + inst_wen_a <= '1'; + inst_atomic_lock_a <= '1'; + + -- If nothing else to update + if ((inst_latch_data.update_flags and (DISPOSED_CNT_FLAG or NO_WRITERS_CNT_FLAG or IGNORE_DEADLINE_FLAG or WRITER_BITMAP_FLAG)) = (inst_latch_data.update_flags'range => '0')) then + -- DONE + inst_stage_a_next <= IDLE; + end if; + -- *Sample Count End* + -- Disposed Generation Count + when 6 => + inst_write_data_a <= inst_latch_data.gen_cnt; + if ((inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then + inst_wen_a <= '1'; + end if; + -- If nothing else to update + if ((inst_latch_data.update_flags and (NO_WRITERS_CNT_FLAG or IGNORE_DEADLINE_FLAG or WRITER_BITMAP_FLAG)) = (inst_latch_data.update_flags'range => '0')) then + -- DONE + inst_stage_a_next <= IDLE; + end if; + -- No Writers Generation Count + when 7 => + inst_write_data_a <= inst_latch_data.gen_cnt; + if ((inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then + inst_wen_a <= '1'; + end if; + -- If nothing else to update + if ((inst_latch_data.update_flags and (IGNORE_DEADLINE_FLAG or WRITER_BITMAP_FLAG)) = (inst_latch_data.update_flags'range => '0')) then + -- DONE + inst_stage_a_next <= IDLE; + end if; + -- Ignore Deadline 1/2 + when 8 => + inst_write_data_a <= std_logic_vector(inst_latch_data.ignore_deadline(0)); + if ((inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_wen_a <= '1'; + end if; + -- Ignore Deadline 2/2 + when 9 => + inst_write_data_a <= std_logic_vector(inst_latch_data.ignore_deadline(1)); + if ((inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_wen_a <= '1'; + end if; + -- If nothing else to update + if ((inst_latch_data.update_flags and (WRITER_BITMAP_FLAG)) = (inst_latch_data.update_flags'range => '0')) then + -- DONE + inst_stage_a_next <= IDLE; + else + inst_stage_a_next <= SET_WRITER_BITMAP; + inst_cnt_a_next <= 0; + end if; + when others => + null; + end case; + when others => + null; + end case; + when others => + null; + end case; + end process; + end architecture; \ No newline at end of file diff --git a/src/rtps_config_package.vhd b/src/rtps_config_package.vhd index cb10c3d..ede84e9 100644 --- a/src/rtps_config_package.vhd +++ b/src/rtps_config_package.vhd @@ -51,15 +51,22 @@ package rtps_config_package is type HISTORY_CACHE_OPCODE_TYPE is (NOP, ADD_CACHE_CHANGE); type KEY_GENERATOR_OPCODE_TYPE is (NOP, WRITE_PAYLOAD, READ_KEY, READ_SIZE); + type HISTORY_CACHE_RESPOSNE_TYPE is (UNDEFINED, ACK, ACCEPTED, REJECTED); + type INSTANCE_STATE_TYPE is (ALIVE, NOT_ALIVE_DISPOSED, NOT_ALIVE_NO_WRITERS); - -- Status Info Flags + -- Sample Status Info Flags constant DISPOSED_FLAG : natural := 0; constant UNREGISTERED_FLAG : natural := 1; constant FILTERED_FLAG : natural := 2; - constant PAYLOAD_FLAG : natural := 29; - constant KEY_HASH_FLAG : natural := 30; + constant KEY_HASH_FLAG : natural := 29; + constant PAYLOAD_FLAG : natural := 30; constant READ_FLAG : natural := 31; + constant NOT_ALIVE_DISPOSED_FLAG : natural := 0; + constant NOT_ALIVE_NO_WRITERS_FLAG : natural := 1; + constant LIVELINESS_FLAG : natural := 2; + constant VIEW_FLAG : natural := 3; + -- Marks the Reader Endpoint in the Endpoint Array constant ENDPOINT_READERS : std_logic_vector(0 to NUM_ENDPOINTS-1) := (0 to NUM_READERS-1 => '1', others => '0'); @@ -106,6 +113,12 @@ package rtps_config_package is type RTPS_OUT_DATA_TYPE is array (0 to NUM_ENDPOINTS) of std_logic_vector(WORD_WIDTH-1 downto 0); + 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); + + 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; + -- Swap "data" to Big Endian representation. function endian_swap(swap : std_logic; data : std_logic_vector) return std_logic_vector; function endian_swap(swap : std_logic; data : unsigned) return unsigned; @@ -1053,4 +1066,22 @@ package body rtps_config_package is return ret; end function; + function to_endpoint_bitmap (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 + ret(i*WORD_WIDTH to ((i+1)*WORD_WIDTH)-1) := input(i); + end loop; + return ret; + end function; + + function from_endpoint_bitmap (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 + ret(i) := input(i*WORD_WIDTH to ((i+1)*WORD_WIDTH)-1); + end loop; + return ret; + end function; + end package body; diff --git a/src/rtps_endpoint.vhd b/src/rtps_endpoint.vhd index 8a515aa..da6a322 100644 --- a/src/rtps_endpoint.vhd +++ b/src/rtps_endpoint.vhd @@ -10,7 +10,9 @@ use work.rtps_config_package.all; -- TODO: Check for special values of time/duration? -- TODO: Remove last_word flag from metattraffic operations -- TODO: Replace all ('range => 0) checks with defined constants, where possible --- TODO: Remove highest_seq_nr in stand alone git commit +-- TODO: Adding LIFESPAN Duration in the stored Endpoint Metatraffic Data would allow us to not expect in-line QoS (Which could be a significant overhead) +-- TODO: Is mem_addr_base needed? Isn't it a direct mirror of addr_mem_base? mem_addr_base is only used in the same clock cycle as mem_op_done is pulled high. + entity rtps_endpoint is generic ( @@ -38,11 +40,13 @@ entity rtps_endpoint is hc_start : out std_logic; hc_opcode : out HISTORY_CACHE_OPCODE_TYPE; - hc_ack : in std_logic; + hc_res : in HISTORY_CACHE_RESPOSNE_TYPE; + hc_data_out : in std_logic_vector(WORD_WIDTH-1 downto 0); hc_valid_out : in std_logic; hc_ready_out : out std_logic; hc_last_word_out: in std_logic; + hc_data_in : out std_logic_vector(WORD_WIDTH-1 downto 0); hc_valid_in : out std_logic; hc_ready_in : in std_logic; @@ -54,27 +58,26 @@ architecture arch of rtps_endpoint is --*****CONSTANT DECLARATION***** -- Endpoint Memory Size in 4-Byte Words - constant ENDPOINT_MEMORY_SIZE : natural := TODO; + constant ENDPOINT_MEMORY_SIZE : natural := TODO; -- Endpoint Memory Address Width - constant ENDPOINT_MEMORY_WIDTH : natural := log2c(ENDPOINT_MEMORY_SIZE); + constant ENDPOINT_MEMORY_ADDR_WIDTH : natural := log2c(ENDPOINT_MEMORY_SIZE); -- Highest Memory Address - constant MAX_ADDRESS : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := to_unsigned(ENDPOINT_MEMORY_SIZE-1, ENDPOINT_MEMORY_WIDTH); + constant MAX_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(ENDPOINT_MEMORY_SIZE-1, ENDPOINT_MEMORY_ADDR_WIDTH); -- Highest Endpoint Frame Address - constant MAX_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := MAX_ADDRESS - ENDPOINT_FRAME_SIZE + 1; + constant MAX_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := MAX_ADDRESS - ENDPOINT_FRAME_SIZE + 1; -- Address pointing to the beginning of the first Endpoint Data Frame - constant FIRST_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := (others => '0'); + constant FIRST_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); -- *UPDATE PARTICIPANT FLAG POSITIONS* constant UPDATE_ENDPOINT_FLAG_WIDTH : natural := 4; -- Signifies that the main Endpoint Data are updated - constant ENDPOINT_DATA_FLAG : std_logic_vector(UPDATE_ENDPOINT_FLAG_WIDTH-1 downto 0) := (0 => 1, others => '0'); + constant ENDPOINT_DATA_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (0 => 1, others => '0'); -- Signifies that the Lease Deadline of the Endpoint Data is updated - constant LEASE_DEADLINE_FLAG : std_logic_vector(UPDATE_ENDPOINT_FLAG_WIDTH-1 downto 0) := (1 => 1, others => '0'); + constant LEASE_DEADLINE_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (1 => 1, others => '0'); -- Signifies that the last Sequence Number of the Endpoint Data is updated - constant NEXT_SEQ_NR_FLAG : std_logic_vector(UPDATE_ENDPOINT_FLAG_WIDTH-1 downto 0) := (2 => 1, others => '0'); + constant NEXT_SEQ_NR_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (2 => 1, others => '0'); -- Signifies that the HEARTBEAT/ACKNACK Timeout Time of the Endpoint Data is updated - constant RES_TIME_FLAG : std_logic_vector(UPDATE_ENDPOINT_FLAG_WIDTH-1 downto 0) := (3 => 1, others => '0'); - constant BITMAP_BLOCK_SIZE : natural := 16; + constant RES_TIME_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (3 => 1, others => '0'); --*****TYPE DECLARATION***** -- FSM states. Explained below in detail @@ -106,8 +109,7 @@ architecture arch of rtps_endpoint is expects_inline_qos : std_logic; deadline : TIME_TYPE; next_seq_nr : SEQUENCENUMBER_TYPE; - update_flags : std_logic_vector(UPDATE_ENDPOINT_FLAG_WIDTH-1 downto 0); - mem_opcode : MEM_OPCODE_TYPE; + update_flags : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1); end record; constant ZERO_MEM_CTRL_DATA : MEM_CTRL_DATA_TYPE := ( guid => (others => (others => '0')), @@ -117,7 +119,6 @@ architecture arch of rtps_endpoint is deadline => TIME_INVALID, next_seq_nr => SEQUENCENUMBER_UNKNOWN, update_flags => (others => '0'), - mem_opcode => IDLE ); @@ -134,7 +135,7 @@ architecture arch of rtps_endpoint is signal portn, portn_next : std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := (others => '0'); signal expects_inline_qos, expects_inline_qos_next : std_logic := '0'; signal is_meta, is_meta_next : std_logic := '0'; - signal update_endpoint_flags : std_logic_vector(UPDATE_ENDPOINT_FLAG_WIDTH-1 downto 0) := (others => '0'); + signal update_endpoint_flags : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (others => '0'); signal opcode, opcode_next : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := (others => '0'); signal flags, flags_next : std_logic_vector(SUBMESSAGE_FLAGS_WIDTH-1 downto 0) := (others => '0'); signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; @@ -165,16 +166,18 @@ architecture arch of rtps_endpoint is signal mem_stage, mem_stage_next : MEM_STAGE_TYPE := IDLE; signal mem_wr, mem_rd : std_logic := '0'; signal mem_wr_data, mem_rd_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); - signal mem_addr, mem_addr_next : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := (others => '0'); - signal mem_addr_base, mem_addr_base_next : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := (others => '0'); - signal addr_res, addr_res_next : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := (others => '0'); - signal last_addr, last_addr_next : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := (others => '0'); - signal max_endpoint_addr, max_endpoint_addr_next : unsigned(ENDPOINT_MEMORY_WIDTH-1 downto 0) := (others => '0'); + signal mem_addr, mem_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal mem_addr_base, mem_addr_base_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal mem_addr_base, mem_addr_base_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal last_addr, last_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal max_endpoint_addr, max_endpoint_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); signal mem_cnt, mem_cnt_next : natural range TODO := 0; signal mem_endpoint_data, mem_endpoint_data_next : ENDPOINT_DATA_TYPE := ZERO_ENDPOINT_DATA; signal reset_max_pointer, reset_max_pointer_next : std_logic := '0'; signal mem_long_latch, mem_long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); signal mem_ctrl_data, mem_ctrl_data_next : MEM_CTRL_DATA_TYPE := ZERO_MEM_CTRL_DATA; + signal mem_pos, mem_pos_next : natural range TODO := 0; + signal is_psearch, is_psearch_next : std_logic := '0'; signal stale_check, stale_check_next : std_logic := '0'; signal count, count_next : unsigned(COUNT_WIDTH-1 downto 0) := (others => '0'); @@ -227,7 +230,7 @@ begin --*****COMPONENT INSTANTIATION***** ram_inst : single_port_ram generic map ( - ADDR_WIDTH => ENDPOINT_MEMORY_WIDTH, + ADDR_WIDTH => ENDPOINT_MEMORY_ADDR_WIDTH, DATA_WIDTH => WORD_WIDTH, MEMORY_DEPTH => ENDPOINT_MEMORY_SIZE ) @@ -386,7 +389,7 @@ begin if (is_meta = '1' and (meta_opcode = OPCODE_PARTICIPANT_UNMATCH or meta_opcode = OPCODE_LIVELINESS_UPDATE)) then -- DONE Parsing - stage_next <= METATRAFFIC_OPERATION; + stage_next <= INITIATE_ENDPOINT_SEARCH; else stage_next <= LATCH_ENTITYID; end if; @@ -398,19 +401,57 @@ begin if (is_meta = '1') then meta_rd <= '1'; guid_next(3) <= meta_data_in; - - if (mem_opcode = OPCODE_ENDPOINT_MATCH) then - stage_next <= LATCH_ENDPOINT_DATA; - cnt_next <= 0; - else - stage_next <= METATRAFFIC_OPERATION; - end if; -- Memory Operation Guard else rd_guard := '1'; guid_next(3) <= data_in; + end if; + stage_next <= INITIATE_ENDPOINT_SEARCH; + end if; + when INITIATE_ENDPOINT_SEARCH => + -- Memory Operation Guard + if (mem_op_done = '1') then + + if (is_meta = '1') then - stage_next <= INITIATE_ENDPOINT_SEARCH; + case (meta_opcode) is + when OPCODE_ENDPOINT_MATCH => + mem_op_start <= '1'; + mem_opcode <= SEARCH_ENDPOINT; + stage_next <= LATCH_ENDPOINT_DATA; + when OPCODE_ENDPOINT_UNMATCH => + mem_op_start <= '1'; + mem_opcode <= SEARCH_ENDPOINT; + stage_next <= METATRAFFIC_OPERATION; + when OPCODE_PARTICIPANT_UNMATCH => + mem_op_start <= '1'; + mem_opcode <= FIND_FIRST_PARTICIPANT_ENDPOINT; + stage_next <= METATRAFFIC_OPERATION; + when OPCODE_LIVELINESS_UPDATE => + mem_op_start <= '1'; + mem_opcode <= FIND_FIRST_PARTICIPANT_ENDPOINT; + stage_next <= METATRAFFIC_OPERATION; + when others => + assert FALSE report "Uknown metatraffic endpoint frame opcode." severity FAILURE; + null; + end case; + else + mem_op_start <= '1'; + mem_opcode <= SEARCH_ENDPOINT; + + case (opcode) is + when SID_DATA => + stage_next <= LATCH_EXTRA_DATA; + cnt_next <= 0; + when SID_HEARTBEAT => + stage_next <= LATCH_HEARTBEAT; + cnt_next <= 0; + when SID_GAP => + stage_next <= LATCH_GAP; + cnt_next <= 0; + when others => + stage_next <= SKIP_PACKET; + end case; end if; end if; when LATCH_ENDPOINT_DATA => @@ -441,28 +482,76 @@ begin case (meta_opcode) is when OPCODE_ENDPOINT_MATCH => - -- Insert Matched Remote Endpoint - -- NOTE: The Lease Duration is NOT updated in case of an update. That is the responsibility of the Liveliness Update - update_endpoint_flags <= ENDPOINT_DATA_FLAG; -- In case the Endpoint is already in the memory, we update the data - mem_opcode <= INSERT_ENDPOINT; - mem_op_start <= '1'; - stage_next <= IDLE; + -- Endpoint already in Memory + if (mem_addr_base /= MAX_ADDRESS) then + -- Update the Endpoint Data + -- NOTE: The Lease Duration is NOT updated in case of an update. That is the responsibility of the Liveliness Update + update_endpoint_flags <= ENDPOINT_DATA_FLAG; + mem_opcode <= UDPATE_ENDPOINT; + mem_op_start <= '1'; + stage_next <= IDLE; + else + -- Insert Matched Remote Endpoint + mem_opcode <= INSERT_ENDPOINT; + mem_op_start <= '1'; + stage_next <= IDLE; + end if; when OPCODE_ENDPOINT_UNMATCH => - -- Remove Unmatched Remote Endpoint - mem_opcode <= REMOVE_ENDPOINT; - mem_op_start <= '1'; - stage_next <= IDLE; + -- Endpoint not in Memory + if (mem_addr_base = MAX_ADDRESS) then + -- Ignore + stage_next <= IDLE; + else + -- Output Guard + if (hc_ready_in = '1') then + -- Propagate Removal + hc_start <= '1'; + hc_opcode <= REMOVE_WRITER; + hc_valid_in <= '1'; + hc_data_in <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); + -- Wait until HC Acknowledgement + if (hc_res = ACK) then + -- Remove Unmatched Remote Endpoint + mem_opcode <= REMOVE_ENDPOINT; + mem_op_start <= '1'; + stage_next <= IDLE; + end if; + end if; + end if; when OPCODE_PARTICIPANT_UNMATCH => - -- Remove All Endpoint of Remote Participant - mem_opcode <= REMOVE_PARTICIPANT; - mem_op_start <= '1'; - stage_next <= IDLE; + -- No matches in memory + if (mem_addr_base = MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Output Guard + if (hc_ready_in = '1') then + -- Propagate Removal + hc_start <= '1'; + hc_opcode <= REMOVE_WRITER; + hc_valid_in <= '1'; + hc_data_in <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); + -- Wait until HC Acknowledgement + if (hc_res = ACK) then + -- Remove Unmatched Remote Endpoint + mem_opcode <= REMOVE_ENDPOINT; + mem_op_start <= '1'; + stage_next <= INITIATE_NEXT_ENDPOINT_SEARCH; + end if; + end if; + end if; when OPCODE_LIVELINESS_UPDATE => - -- Renew Lease of Remote Endpoint - update_endpoint_flags <= LEASE_DEADLINE_FLAG; - mem_opcode <= UDPATE_ENDPOINT; - mem_op_start <= '1'; - stage_next <= IDLE; + -- No matches in memory + if (mem_addr_base = MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Renew Lease of Remote Endpoint + update_endpoint_flags <= LEASE_DEADLINE_FLAG; + mem_opcode <= UDPATE_ENDPOINT; + mem_op_start <= '1'; + stage_next <= INITIATE_NEXT_ENDPOINT_SEARCH; + end if; when others => assert FALSE report "Uknown metatraffic endpoint frame opcode." severity FAILURE; null; @@ -470,6 +559,13 @@ begin -- DONE stage_next <= SKIP_PACKET; end if; + when INITIATE_NEXT_ENDPOINT_SEARCH => + -- Memory Operation Guard + if (mem_op_done = '1') then + mem_opcode <= FIND_NEXT_PARTICIPANT_ENDPOINT; + mem_op_start <= '1'; + stage_next <= METATRAFFIC_OPERATION; + end if; when LATCH_SRC_ADDR => -- Input FIFO Guard if (empty = '0') then @@ -481,26 +577,6 @@ begin stage_next <= LATCH_GUIDPREFIX; cnt_next <= 0; end if; - when INITIATE_ENDPOINT_SEARCH => - -- Memory Operation Guard - if (mem_op_done = '1') then - mem_op_start <= '1'; - mem_opcode <= SEARCH_ENDPOINT; - - case (opcode) is - when SID_DATA => - stage_next <= LATCH_EXTRA_DATA; - cnt_next <= 0; - when SID_HEARTBEAT => - stage_next <= LATCH_HEARTBEAT; - cnt_next <= 0; - when SID_GAP => - stage_next <= LATCH_GAP; - cnt_next <= 0; - when others => - stage_next <= SKIP_PACKET; - end case; - end if; when LATCH_EXTRA_DATA => -- Input FIFO Guard if (empty = '0') then @@ -515,7 +591,7 @@ begin when 1 => seq_nr_next(1) <= unsigned(data_in); -- Store Next Sequence Number - tmp_dw := (0 => seq_nr(0), 1 => unsigned(data_in_swapped)); + tmp_dw := (0 => seq_nr(0), 1 => unsigned(data_in)); next_seq_nr_next <= tmp_dw + 1; -- Timestamp 1/2 when 2 => @@ -565,7 +641,7 @@ begin stage_next <= SKIP_PACKET; -- Endpoint in Buffer - if (addr_res /= MAX_ADDRESS) then + if (mem_addr_base /= MAX_ADDRESS) then -- No scheduled Heartbeat Response if (mem_endpoint_data.res_time = 0) then -- If current Sequence Number obsolete (removed from source history cache) @@ -651,7 +727,7 @@ begin stage_next <= SKIP_PACKET; -- Known Remote Endpoint - if (addr_res /= MAX_ADDRESS) then + if (mem_addr_base /= MAX_ADDRESS) then -- GAP is relevant if (gap_start <= mem_endpoint_data.next_seq_nr and mem_endpoint_data.next_seq_nr <= gap_list_end) then -- Next Expected is in GAP List @@ -794,10 +870,15 @@ begin case (cnt) is -- Lifespan 1/2 when 0 => - deadline_next(0) <= unsigned(data_in_swapped); + -- NOTE: We are misusing the sn_latch_1 as temporal CDR_LONG storage + sn_latch_1_next(0) <= unsigned(data_in_swapped); -- Lifespan 2/2 when 1 => - deadline_next(1) <= unsigned(data_in_swapped); + tmp_dw := (0 => sn_latch_1(0), 1 => unsigned(data_in_swapped)); + + -- TODO: Use source timestamp if clocks with remote synchronized + -- Calculate Sample Lifespan Deadline + deadline_next <= time + tmp_dw; -- DONE stage_next <= SKIP_PARAMETER; @@ -845,7 +926,7 @@ begin hc_start <= '1'; hc_opcode <= ADD_CACHE_CHANGE; -- Wait until History Cache acknowledges request - if (hc_ack = '1') then + if (hc_res = ACK) then stage_next <= ADD_CACHE_CHANGE; cnt_next <= 0; end if; @@ -872,51 +953,38 @@ begin -- Key hash 4/4 when 4 => hc_data_in <= key_hash(3); - -- Entity ID - when 5 => - hc_data_in <= guid(3); - -- GUID Prefix 1/3 - when 6 => - hc_data_in <= guid(0); - -- GUID Prefix 2/3 - when 7 => - hc_data_in <= guid(1); - -- GUID Prefix 3/3 - when 8 => - hc_data_in <= guid(2); - -- Sequence Number 1/2 - when 9 => - hc_data_in <= seq_nr(0); - -- Sequence Number 2/2 - when 10 => - hc_data_in <= seq_nr(1); -- Timestamp 1/2 - when 11 => + when 5 => hc_data_in <= ts(0); -- Timestamp 2/2 - when 12 => + when 6 => hc_data_in <= ts(1); -- Lifespan Deadline 1/2 - when 13 => + when 7 => hc_data_in <= deadline(0); -- Lifespan Deadline 2/2 - when 14 => + when 8 => hc_data_in <= deadline(1); - - -- Payload exists - if (data_flag = '1' or key_flag = '1') then - stage_next <= PUSH_PAYLOAD; - else - -- DONE - hc_last_word_in <= '1'; + -- Endpoint Memory Position + when 9 => + -- Wait for Endpoint Search + if (mem_op_done = '1') then - -- Operation Sucessfull - if (hc_ack = '1') then - stage_next <= FINALIZE_HISTORY_CACHE_REQUEST; + -- TODO: Assert mem_pos range fits in CDR_LONG + hc_data_in <= std_logic_vector(to_unsigned(mem_pos, CDR_LONG_WIDTH)); + + -- Payload exists + if (data_flag = '1' or key_flag = '1') then + stage_next <= PUSH_PAYLOAD; else - -- Operation Failed, Skip - stage_next <= SKIP_PACKET; + -- DONE + hc_last_word_in <= '1'; + stage_next <= FINALIZE_HISTORY_CACHE_REQUEST; end if; + else + -- Keep State + hc_valid_in <= '0'; + cnt_next <= cnt; end if; when others => null; @@ -933,34 +1001,33 @@ begin -- Exit Condition if (last_word_in = '1') then - hc_last_word_in <= '1'; - -- XXX: Possible worst case path (The hc_ack is set from last_word signal -> round trip delay between entities) - -- Change Add Sucessfull - if (hc_ack = '1') then - -- Update Endpoint Data - stage_next <= FINALIZE_HISTORY_CACHE_REQUEST; - else - -- Operation Failed, Skip - stage_next <= SKIP_PACKET; - end if; + hc_last_word_in <= '1'; + stage_next <= FINALIZE_HISTORY_CACHE_REQUEST; end if; end if; when FINALIZE_HISTORY_CACHE_REQUEST => - -- Memory Operation Guard - if (mem_op_done = '1') then - -- Update next sequence number and renew Lease - mem_op_start <= '1'; - mem_opcode <= UPDATE_ENDPOINT; - deadline_next <= time + ENDPOINT_LEASE_DURATION(ID); - update_endpoint_flags <= NEXT_SEQ_NR_FLAG or LEASE_DEADLINE_FLAG; + -- NOTE: Memory is already in done state from previous state (ADD_CACHE_CHANGE) + assert (mem_op_done = '1') report "FINALIZE_HISTORY_CACHE_REQUEST precondition not met. mem_op_done /= '1'" severity FAILURE; + -- Wai for History Cache Response + if (hc_res /= UNDEFINED) then + -- Operation was Accepted + if (hc_res = ACCEPTED) then + -- Update next sequence number and renew Lease + mem_op_start <= '1'; + mem_opcode <= UPDATE_ENDPOINT; + deadline_next <= time + ENDPOINT_LEASE_DURATION(ID); + update_endpoint_flags <= NEXT_SEQ_NR_FLAG or LEASE_DEADLINE_FLAG; + end if; + -- NOTE: In case the operation was unsucessfull (e.g. reached Resource Limits), the endpoint is not updated and the + -- Sequence Number is thus not "acknowledged". -- DONE - stage_next <= SKIP_PACKET; + stage_next <= SKIP_PACKET; end if; when ENDPOINT_STALE_CHECK => -- Wait for Stale Search to finish if (mem_op_done = '1') then -- Found Stale Entry - if (addr_res /= MAX_ADDRESS) then + if (mem_addr_base /= MAX_ADDRESS) then -- Endpoint Lease Expired -- NOTE: The mem_endpoint_data is zero initialized on lease expiration, so we check if the address is set if (mem_endpoint_data.addr = IPv4_ADDRESS_INVALID) then @@ -1169,7 +1236,6 @@ begin mem_stage_next <= mem_stage; mem_addr_base_next <= mem_addr_base; mem_addr_next <= mem_addr; - addr_res_next <= addr_res; mem_cnt_next <= mem_cnt; last_addr_next <= last_addr; mem_endpoint_data_next <= mem_endpoint_data; @@ -1178,6 +1244,7 @@ begin reset_max_pointer_next <= reset_max_pointer; mem_long_latch_next <= mem_long_latch; mem_ctrl_data_next <= mem_ctrl_data; + mem_pos_next <= mem_pos; -- DEFAULT Unregistered mem_write_data <= (others => '0'); mem_op_done <= '0'; @@ -1189,6 +1256,7 @@ begin when IDLE => mem_op_done <= '1'; reset_max_pointer_next <= '0'; + is_psearch_next <= '0'; if (mem_op_start = '1') then -- Latch Signals needed for Mermory Operation (Use _next signals, because some signals are set in same clk) @@ -1199,70 +1267,89 @@ begin expects_inline_qos => expects_inline_qos_next, deadline => deadline_next, next_seq_nr => next_seq_nr_next, - update_flags => update_endpoint_flags_next, - mem_opcode => mem_opcode_next + update_flags => update_endpoint_flags_next ); case(mem_opcode) is when SEARCH_ENDPOINT => mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; mem_addr_next <= FIRST_ENDPOINT_ADDRESS; + mem_pos_next <= 0; mem_stage_next <= SEARCH_ENDPOINT; mem_cnt_next <= 0; when INSERT_ENDPOINT => - -- NOTE: First check if Endpoint is already inserted. If yes, just update the data. mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_stage_next <= SEARCH_ENDPOINT; + mem_pos_next <= 0; + mem_stage_next <= FIND_ENDPOINT_SLOT; mem_cnt_next <= 0; when UPDATE_ENDPOINT => if ((update_endpoint_flags and ENDPOINT_DATA_FLAG) = ENDPOINT_DATA_FLAG) then mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= addr_res + 4; + mem_addr_next <= mem_addr_base + 4; mem_cnt_next <= 0; elsif ((update_endpoint_flags and LEASE_DEADLINE_FLAG) = LEASE_DEADLINE_FLAG) then mem_stage_next <= UPDATE_ENDPPOINT; - mem_addr_next <= addr_res + 6; + mem_addr_next <= mem_addr_base + 6; mem_cnt_next <= 2; elsif ((update_endpoint_flags and RES_TIME_FLAG) = RES_TIME_FLAG) then mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= addr_res + 8; + mem_addr_next <= mem_addr_base + 8; mem_cnt_next <= 4; elsif ((update_endpoint_flags and NEXT_SEQ_NR_FLAG) = NEXT_SEQ_NR_FLAG) then mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= addr_res + 10; + mem_addr_next <= mem_addr_base + 10; mem_cnt_next <= 6; end if; when REMOVE_ENDPOINT => - mem_addr_next <= addr_res; + mem_addr_next <= mem_addr_base; mem_stage_next <= REMOVE_ENDPOINT; mem_cnt_next <= 0; - when REMOVE_PARTICIPANT => - mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_stage_next <= SEARCH_ENDPOINT; - mem_cnt_next <= 0; when FIND_STALE_ENDPOINT => mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; mem_addr_next <= FIRST_ENDPOINT_ADDRESS; + mem_pos_next <= 0; mem_stage_next <= FIND_STALE_ENDPOINT; mem_cnt_next <= 0; - when FIND_FIRST_ENDPOINT => + when GET_FIRST_ENDPOINT => mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_stage_next <= FIND_NEXT_ENDPOINT; + mem_pos_next <= 0; + mem_stage_next <= GET_NEXT_ENDPOINT; mem_cnt_next <= 0; - when FIND_NEXT_ENDPOINT => + when GET_NEXT_ENDPOINT => -- Memory Bound Guard - if (addr_res /= max_endpoint_addr) then + if (mem_addr_base /= max_endpoint_addr) then -- Reached End of Memory, No match - tmp := addr_res + ENDPOINT_FRAME_SIZE; + tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; mem_addr_base_next <= tmp; mem_addr_next <= tmp; - mem_stage_next <= FIND_NEXT_ENDPOINT; + mem_pos_next <= mem_pos + 1; + mem_stage_next <= GET_NEXT_ENDPOINT; mem_cnt_next <= 0; else - addr_res_next <= MAX_ADDRESS; + mem_addr_base_next <= MAX_ADDRESS; + end if; + when FIND_FIRST_PARTICIPANT_ENDPOINT => + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_addr_next <= FIRST_ENDPOINT_ADDRESS; + mem_pos_next <= 0; + mem_stage_next <= SEARCH_ENDPOINT; + mem_cnt_next <= 0; + is_psearch_next <= '1'; + when FIND_NEXT_PARTICIPANT_ENDPOINT => + -- Memory Bound Guard + if (mem_addr_base /= max_endpoint_addr) then + -- Reached End of Memory, No match + tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_addr_base_next <= tmp; + mem_addr_next <= tmp; + mem_pos_next <= mem_pos + 1; + mem_stage_next <= SEARCH_ENDPOINT; + mem_cnt_next <= 0; + is_psearch_next <= '1'; + else + mem_addr_base_next <= MAX_ADDRESS; end if; when others => null; @@ -1282,84 +1369,77 @@ begin null; -- Entity ID when 1 => - -- No Match (Ignore Entity ID match on Participant Search, but skip empty Slot) - if ((mem_read_data /= guid(3) and mem_ctrl_data.mem_opcode /= REMOVE_PARTICIPANT) or (mem_read_data = ENTITYID_UNKNOWN)) then + -- No Match (Ignore Entity ID match on Participant Endpoint Search, but skip empty Slot) + if ((mem_read_data /= mem_ctrl_data.guid(3) and is_psearch = '0') or (mem_read_data = ENTITYID_UNKNOWN)) then -- Reached End of Memory, No Match if (mem_addr_base = max_endpoint_addr) then - case (mem_ctrl_data.mem_opcode) is - when INSERT_ENDPOINT => - -- Insert new Endpoint - mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_stage_next <= FIND_ENDPOINT_SLOT; - mem_cnt_next <= 0; - when REMOVE_PARTICIPANT => - -- 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 <= (others => '0'); - mem_stage_next <= FIND_ENDPOINT_SLOT; - mem_cnt_next <= 0; - when others => - addr_res_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; - end case; + mem_addr_base_next <= MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; else -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; end if; 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_next <= tmp; - mem_cnt_next <= 0; + if (mem_read_data /= mem_ctrl_data.guid(0)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_next <= tmp; + mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; 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_next <= tmp; - mem_cnt_next <= 0; + if (mem_read_data /= mem_ctrl_data.guid(1)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_next <= tmp; + mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; 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_next <= tmp; - mem_cnt_next <= 0; + if (mem_read_data /= mem_ctrl_data.guid(2)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_next <= tmp; + mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; -- Match else - case (mem_ctrl_data.mem_opcode) is - when REMOVE_PARTICIPANT => - addr_res_next <= mem_addr_base; - -- Remove Endpoint from remote Participant - mem_stage_next <= REMOVE_ENDPOINT; - mem_addr_next <= mem_addr_base; - mem_cnt_next <= 0; - when INSERT_ENDPOINT => - addr_res_next <= mem_addr_base; - -- Update Endpoint Data - mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= mem_addr_base + 4; - mem_cnt_next <= 0; - when others => - addr_res_next <= mem_addr_base; - -- Fetch Endpoint Data - mem_stage_next <= GET_ENDPOINT_DATA; - mem_cnt_next <= 1; -- No preload needed - end case; + mem_addr_base_next <= mem_addr_base; + -- Fetch Endpoint Data + mem_stage_next <= GET_ENDPOINT_DATA; + mem_cnt_next <= 1; -- No preload needed end if; when others => null; @@ -1528,21 +1608,14 @@ begin mem_wr <= '1'; mem_write_data <= ENTITYID_UNKNOWN; - if (mem_ctrl_data.mem_opcode = REMOVE_PARTICIPANT) then - -- Continue Participant Match Search - mem_addr_base_next <= addr_res; - mem_addr_next <= addr_res; - mem_stage_next <= SEARCH_ENDPOINT; - mem_cnt_next <= 0; - else - -- 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 <= (others => '0'); - mem_stage_next <= FIND_ENDPOINT_SLOT; - mem_cnt_next <= 0; - end if; + -- Reset MAX Endpoint Pointer + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_addr_next <= FIRST_ENDPOINT_ADDRESS; + mem_pos_next <= 0; + reset_max_pointer_next <= '1'; + last_addr_next <= (others => '0'); + mem_stage_next <= FIND_ENDPOINT_SLOT; + mem_cnt_next <= 0; when FIND_ENDPOINT_SLOT => mem_rd <= '1'; mem_addr_next <= mem_addr + 1; @@ -1570,16 +1643,18 @@ begin report "Memory Full, Ignoring Endpoint Data" severity NOTE; -- Ignore Insertion mem_stage_next <= IDLE; - addr_res_next <= MAX_ADDRESS; + mem_addr_base_next <= MAX_ADDRESS; else -- Extend Endpoint Memory Area -- NOTE: "max_endpoint_addr" points to the first address of last Endpoint Frame max_endpoint_addr_next <= tmp; -- Populate Endpoint Slot - mem_stage_next <= INSERT_ENDPOINT; - mem_addr_next <= tmp; - addr_res_next <= tmp; - mem_cnt_next <= 0; + mem_stage_next <= INSERT_ENDPOINT; + mem_addr_base_next <= tmp; + mem_addr_next <= tmp; + mem_pos_next <= mem_pos + 1; + mem_addr_base_next <= tmp; + mem_cnt_next <= 0; end if; else -- Latch last occupied Endpoint Slot @@ -1587,10 +1662,12 @@ begin -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; end if; -- Slot Empty else + -- We are in the middle of resetting the MAX Endpoint Pointer if (reset_max_pointer = '1') then -- Make sure to iterate through complete Endpoint Area if (mem_addr_base = max_endpoint_addr) then @@ -1602,20 +1679,20 @@ begin -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; end if; else -- Populate Endpoint Slot - mem_stage_next <= INSERT_ENDPOINT; - mem_addr_next <= mem_addr_base; - addr_res_next <= mem_addr_base; - mem_cnt_next <= 0; + mem_stage_next <= INSERT_ENDPOINT; + mem_addr_next <= mem_addr_base; + mem_cnt_next <= 0; end if; end if; when others => null; end case; - when FIND_NEXT_ENDPOINT => + when GET_NEXT_ENDPOINT => mem_rd <= '1'; mem_cnt_next <= mem_cnt + 1; mem_addr_next <= mem_addr + 1; @@ -1634,21 +1711,21 @@ begin -- Slot Occupied if (mem_read_data /= ENTITYID_UNKNOWN) then -- Get Endpoint Data - mem_addr_next <= tmp2; - addr_res_next <= mem_addr_base; - mem_stage_next <= GET_ENDPOINT_DATA; - mem_cnt_next <= 0; + mem_addr_next <= tmp2; + mem_stage_next <= GET_ENDPOINT_DATA; + mem_cnt_next <= 0; -- Slot Empty else -- Reached End of Memory, No Match if (mem_addr_base = max_endpoint_addr) then - addr_res_next <= MAX_ADDRESS; --No match + mem_addr_base_next <= MAX_ADDRESS; --No match -- DONE mem_stage_next <= IDLE; else -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; end if; end if; @@ -1682,13 +1759,14 @@ begin else -- Reached End of Memory, No Match if (mem_addr_base = max_endpoint_addr) then - addr_res_next <= MAX_ADDRESS; --No match + mem_addr_base_next <= MAX_ADDRESS; --No match -- DONE mem_stage_next <= IDLE; else -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; end if; end if; @@ -1704,7 +1782,6 @@ begin -- Lease Deadline passed if (tmp_dw < time) then -- Mark Endpoint as stale - addr_res_next <= mem_addr_base; mem_endpoint_data_next <= ZERO_ENDPOINT_DATA; -- DONE mem_stage_next <= IDLE; @@ -1718,21 +1795,21 @@ begin -- Response/Suppression Time passed if (tmp_dw /= 0 and tmp_dw < time) then -- Mark Endpoint and get Endpoint Data - addr_res_next <= mem_addr_base; - mem_addr_next <= tmp2; - mem_stage_next <= GET_ENDPOINT_DATA; - mem_cnt_next <= 0; + mem_addr_next <= tmp2; + mem_stage_next <= GET_ENDPOINT_DATA; + mem_cnt_next <= 0; -- Endpoint not Stale else -- Reached End of Memory, No Match if (mem_addr_base = max_endpoint_addr) then - addr_res_next <= MAX_ADDRESS; --No match + mem_addr_base_next <= MAX_ADDRESS; --No match -- DONE - mem_stage_next <= IDLE; + mem_stage_next <= IDLE; else -- Continue Search mem_addr_next <= tmp; mem_addr_base_next <= tmp; + mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; end if; end if; diff --git a/src/rtps_package.vhd b/src/rtps_package.vhd index 1640b32..6baed3f 100644 --- a/src/rtps_package.vhd +++ b/src/rtps_package.vhd @@ -85,6 +85,7 @@ package rtps_package is constant GUIDPREFIX_UNKNOWN : GUIDPREFIX_TYPE := (others => (others => '0')); constant UDP_PORT_INVALID : std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := (others => '0'); constant IPv4_ADDRESS_INVALID : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0) := (others => '0'); + constant LENGTH_UNLIMITED : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- *SUBMESSAGE IDs* constant SID_PAD : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"01"; @@ -279,9 +280,9 @@ package rtps_package is -- DEPTH (HISTORY) constant DEFAULT_HISTORY_DEPTH : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(1,CDR_LONG_WIDTH)); -- RESOURCE_LIMITS - constant DEFAULT_MAX_SAMPLES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- LENGTH_UNLIMITED - constant DEFAULT_MAX_INSTANCES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- LENGTH_UNLIMITED - constant DEFAULT_MAX_SAMPLES_PER_INSTANCE : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- LENGTH_UNLIMITED + constant DEFAULT_MAX_SAMPLES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := LENGTH_UNLIMITED; + constant DEFAULT_MAX_INSTANCES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := LENGTH_UNLIMITED; + constant DEFAULT_MAX_SAMPLES_PER_INSTANCE : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := LENGTH_UNLIMITED; -- WRITER_DATA_LIFECYCLE constant DEFAULT_AUTODISPOSE_UNREGISTERED_INSTANCES : boolean := TRUE; -- READER_DATA_LIFECYCLE @@ -294,9 +295,9 @@ package rtps_package is constant DEFAULT_DURABILITY_SERVICE_CLEANUP_DELAY : DURATION_TYPE := DURATION_ZERO; constant DEFAULT_DURABILITY_SERVICE_HISTORY : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := KEEP_LAST_HISTORY_QOS; constant DEFAULT_DURABILITY_SERVICE_HISTORY_DEPTH : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(1,CDR_LONG_WIDTH)); - constant DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- LENGTH_UNLIMITED - constant DEFAULT_DURABILITY_SERVICE_MAX_INSTANCES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- LENGTH_UNLIMITED - constant DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE: std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH)); -- LENGTH_UNLIMITED + constant DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := LENGTH_UNLIMITED; + constant DEFAULT_DURABILITY_SERVICE_MAX_INSTANCES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := LENGTH_UNLIMITED; + constant DEFAULT_DURABILITY_SERVICE_MAX_SAMPLES_PER_INSTANCE: std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := LENGTH_UNLIMITED; constant DEFAULT_PARTICIPANT_LEASE_DURATION : DURATION_TYPE; -- Deferred to package Body (100 s)