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)