From bdb397ae7db8db0d45507a1b2e5df6f40420c372 Mon Sep 17 00:00:00 2001 From: Greek Date: Thu, 21 Jan 2021 12:51:39 +0100 Subject: [PATCH] Major History Cache/DDS Endpoint Redesign It was decided to connect the DDS Endpoint directly to the RTPS Endpoint. The history_cache Entity will be converted to a generic History Cache acording to the RTPS Specification. Because of consistency requirements the implementation was changed to a single process/single port RAM design. This should fully (blindly) implement the RTPS Reader side of the DDS Entity. --- src/REF.txt | 26 +- src/TODO.txt | 17 +- src/dds_endpoint.vhd | 1837 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1877 insertions(+), 3 deletions(-) create mode 100644 src/dds_endpoint.vhd diff --git a/src/REF.txt b/src/REF.txt index 35bda0b..248c94e 100644 --- a/src/REF.txt +++ b/src/REF.txt @@ -439,7 +439,7 @@ INSTANCE MEMORY +-------------------------------------------------------------+ 05| STATUS_INFO | {A/B} +-------------------------------------------------------------+ -06| SAMPLE_COUNT | {A/B} [only MAX_SAMPLES_PER_INSTANCE/HISTORY] +06| SAMPLE_COUNT | {A/B} +-------------------------------------------------------------+ 07| DISPOSED_GENERATION_COUNT | {A} [only GENERATION_COUNTERS] +-------------------------------------------------------------+ @@ -576,6 +576,30 @@ Instead of blocking on the unresponsive Reader, the Writer should be allowed to and proceed in updating its queue. The Writer should determine the inactivity of a Reader by using a mechanism based on the rate and number of ACKNACKs received. +https://community.rti.com/content/forum-topic/instance-resources-dispose-and-unregister +Note that this means that with the default QoS settings RTI Connext DDS DataWriters do not release resources +of instances that have been "disposed" but are still registered. The reason is that there are various +scenarios under which "forgetting diposed instances" could lead to inconsistent or erroneous outcomes. +For example: +Scenario 1: With OWNERSHIP Qos Policy EXCLUSIVE and DURABILITY Qos Policy TRANSIENT_LOCAL, removing all +the DataWriter state associated with disposed (but still registered) instances would prevent the +DataWriter from maintaining Ownership of the instance in the presence of late-joining DataReaders. +Scenario 2: With OWNERSHIP Qos Policy SHARED, DURABILITY Qos Policy TRANSIENT_LOCAL, and DESTINATION_ORDER +Qos Policy BT_SOURCE_TIMESTAMP, removing all the DataWriter state associated with disposed (but still +registered) instances could lead to situations in which a late-joiner DataReader does not get notified +about the most recent state of an existing instance. + +https://community.rti.com/content/forum-topic/instance-resources-dispose-and-unregister +The reason RTI DDS DataReaders do not release resources of instances in the NOT_ALIVE_DISPOSED state is +that there various scenarios under which this could lead to inconsistent or erroneous outcomes. +For example: +Scenario 1: With EXCLUSIVE ownership, removing the resources associated with the instance would forget +which DataWriter "owns" the instance and if a new DataWriter which lower strength wrote the instance the +update would be incorrectly accepted. +Scenario 2: With SHARED ownership and destination order by SOURCE timestamp, removing the resources +associated with the instance would forget the source timestamp when the deletion occurs and if a different +DataWriter where to write the instance with an earlier timestamp the update would be incorrectly accepted. + INVALIDATION ============ diff --git a/src/TODO.txt b/src/TODO.txt index ee12bde..55a62f6 100644 --- a/src/TODO.txt +++ b/src/TODO.txt @@ -69,7 +69,8 @@ * Currently a RTPS Writer with DURABILITY TARNSIENT_LOCAL does send historical data to all matched readrs, not depensing if they are VOLATILE or TRANSIENT_LOCAL. * Assert Heartbeat period > Heartbeat Suppression Period * Can I request (NACK) SNs that were NOT announced by the writer (> last_sn in Heartbeat)? - +* As it currently works, if a new sample is received and the QOS is not KEEP_ALL/RELIABLE, the oldest sample is removed. + In case of DESTINATION_ORDER = BY_SOURCE_TIMESTAMP it could happen that we effectively removed a sample that had a source timestamp later than the one we received. * Fast-RTPS doen not follow DDSI-RTPS Specification - Open Github Issue @@ -185,7 +186,7 @@ DESIGN DECISIONS and is used for the insert operation to find a new empty slot. This in effect means that all frame sizes have to be a multiple of 2 (all frame addresses have to be aligned to 2). -* The History Cache (HC) is the interface between RTPS and DDS. The History Cache contains the Sample Info +* !REJECTED! The History Cache (HC) is the interface between RTPS and DDS. The History Cache contains the Sample Info and Payload memories. The HC has two input "sides", one is connected to the DDS and one to the RTPS entity. Housing the memories inside the HC entity and abstracting the direct memory address via opcode requests allows the memory interface to be replaced in future (e.g. AXI Lite). @@ -198,6 +199,18 @@ DESIGN DECISIONS empty slot address), since it is reset by the "adding" side, by set by the "removing" side. Because of this, it was decided against concurrent input handling in light of the fact that the history cache will be most commonly quite large in size, and iterating through all + +* Since most of the DDS QoS need information that is directly available to the History Cache (HC), + it makes sense to integrate most of the DDS functionality directly into the HC to save up space + and performance. Further more the needed stored information for a DDS Entity is different enough + from the generic HC defined in the RTPS Specification to warrant a seperate entity for both. + The DDS Entity will directly connect to the RTPS Endpoint. A separate generic HC will be + implemented, that follows the RTPS Specification. + The RTPS Endpoint will have to output multiple versions of Changes, depending on the connected + Entity, in order to facilitate this design decision. + +* Since the "reading" side needs to have consistent state during it's processing, it does not make + sense to implement dual port RAMs for the History Cache. PROTOCOL UNCOMPLIANCE diff --git a/src/dds_endpoint.vhd b/src/dds_endpoint.vhd new file mode 100644 index 0000000..a2c1515 --- /dev/null +++ b/src/dds_endpoint.vhd @@ -0,0 +1,1837 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- TODO: Cancel KHG operation on incomplete payload parsing + +entity history_cache is + generic ( + 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; + reset : in std_logic; + + start_a : in std_logic; + opcode_a : in HISTORY_CACHE_OPCODE_TYPE; + 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; + last_word_in_a : in std_logic; + + start_b : in std_logic; + opcode_b : in HISTORY_CACHE_OPCODE_TYPE; + 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; + ); +end entity; + +architecture arch of history_cache is + + --*****CONSTANT DECLARATION***** + -- Sample Info Memory Size in 4-Byte Words + constant SAMPLE_MEMORY_SIZE : natural := TODO; + -- Sample Info Memory Address Width + constant SAMPLE_MEMORY_ADDR_WIDTH : natural := log2c(SAMPLE_MEMORY_SIZE); + -- Highest Sample Info Memory Address + constant SAMPLE_MEMORY_MAX_ADDRESS : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(SAMPLE_MEMORY_SIZE-1, SAMPLE_MEMORY_ADDR_WIDTH); + -- Highest Sample Info Frame Address + constant MAX_SAMPLE_ADDRESS : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := SAMPLE_MEMORY_MAX_ADDRESS - SAMPLE_INFO_FRAME_SIZE + 1; + + -- Payload Memory Size in 4-Byte Words + constant PAYLOAD_MEMORY_SIZE : natural := TODO; + -- Payload Memory Address Width + constant PAYLOAD_MEMORY_ADDR_WIDTH : natural := log2c(PAYLOAD_MEMORY_SIZE); + -- 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(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_TIMESTAMP_OFFSET : natural := 1; + constant SMF_LIFESPAN_DEADLINE_OFFSET : natural := 3; + constant SMF_PAYLOAD_ADDR_OFFSET : natural := 5; + constant SMF_INSTANCE_ADDR_OFFSET : natural := 6; + constant SMF_DISPOSED_GEN_CNT_OFFSET : natural := 7; + constant SMF_NO_WRITERS_GEN_CNT_OFFSET : natural := 8; + constant SMF_PREV_ADDR_OFFSET : natural := SMF_NO_WRITERS_GEN_CNT_OFFSET+1 when GENERATION_COUNTERS else SMF_INSTANCE_ADDR_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; + sample_cnt : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); + 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); + addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); + end record; + constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := ( + key_hash => (others => (others => '0')), + instance_state => ALIVE, + sample_cnt => (others => '0'), + gen_cnt => (others => '0'), + deadline => TIME_INVALID, + writer_bitmap => (others => (others => '0')), + update_flags => (others => '0'), + addr => (others => '0') + ); + + --*****SIGNAL DECLARATION + signal sample_addr, sample_addr_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal sample_wen, sample_ren : std_logic := '0'; + signal sample_read_data, sample_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + + signal payload_addr, payload_addr_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal payload_wen, payload_ren : std_logic := '0'; + signal payload_read_data, payload_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + + signal inst_addr, inst_addr_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_wen, inst_ren : std_logic := '0'; + signal inst_read_data, inst_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '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 stage, stage_next : STAGE_TYPE := IDLE; + signal cnt, cnt_next : natural range TODO := 0; + signal empty_sample_list_head, empty_sample_list_head_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal empty_sample_list_tail, empty_sample_list_tail_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal empty_payload_list_head, empty_payload_list_head_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal oldest_sample, oldest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal newest_sample, newest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal first_unread_sample, first_unread_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal payload_addr_latch_1, payload_addr_latch_1_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal payload_addr_latch_2, payload_addr_latch_2_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal sample_addr_latch_1, sample_addr_latch_1_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal sample_addr_latch_2, sample_addr_latch_2_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal sample_addr_latch_3, sample_addr_latch_3_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + 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 payload_mem_full, payload_mem_full_next : std_logic := '0'; + signal sample_mem_full, sample_mem_full_next : std_logic := '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 remove_oldest_sample, remove_oldest_sample_next : std_logic := '0'; + signal remove_oldest_inst_sample, remove_oldest_inst_sample_next : std_logic := '0'; + signal added_new_instance, added_new_instance_next : 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 inst_addr_update : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal sample_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + + + signal inst_op_start : std_logic := '0'; + signal inst_op_done : std_logic := '0'; + signal inst_opcode : INSTANCE_OPCODE_TYPE := NOP; + signal inst_stage, inst_stage_next : INST_STAGE_TYPE := IDLE; + signal inst_addr_base, inst_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_next_addr_base, inst_next_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_prev_addr_base, inst_prev_addr_base_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 : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0'); + signal inst_cnt, inst_cnt_next : natural range TODO := 0; + signal inst_mem_full, inst_mem_full_next : std_logic := '0'; + signal inst_delete_lock, inst_delete_lock_next : std_logic := '0'; + signal inst_atomic_lock : std_logic := '0'; + signal inst_long_latch, inst_long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '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; + alias next_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2; + alias next_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2_next; + alias cur_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3; + alias cur_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3_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 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 + + sample_ram_inst : entity work.single_port_ram(arch) + generic map ( + ADDR_WIDTH => SAMPLE_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => SAMPLE_MEMORY_SIZE + ) + port map ( + clk => clk, + addr => sample_addr, + wen => sample_wen, + ren => sample_ren, + wr_data => sample_write_data, + rd_data => sample_read_data + ); + + payload_ram_inst : entity work.single_port_ram(arch) + generic map ( + ADDR_WIDTH => PAYLOAD_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => PAYLOAD_MEMORY_SIZE + ) + port map ( + clk => clk, + addr => payload_addr, + wen => payload_wen, + ren => payload_ren, + wr_data => payload_write_data, + rd_data => payload_read_data + ); + + instance_ram_inst : entity work.single_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 => inst_addr, + wen => inst_wen, + ren => inst_ren, + wr_data => inst_write_data, + rd_data => inst_read_data + ); + + key_hash_generator_inst : entity work.key_hash_generator(arch) + port ( + clk => clk, + reset => reset, + data_in => khg_data_in, + valid_in => khg_valid_in, + ready_in => khg_ready_in, + last_word_in => khg_last_word_in, + data_out => khg_data_out, + valid_out => khg_valid_out, + ready_out => khg_ready_out, + last_word_out => khg_last_word_out + ); + + parse_a_prc : process (all) + variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0')); + variable tmp_bitmap : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1) := (others => '0'); + variable tmp_update : std_logic_vector(0 to UPDATE_INSTANCE_FLAG_WIDTH-1) := (others => '0'); + begin + -- Default + stage_next <= stage; + res_a <= UNDEFINED; + sample_addr_next <= sample_addr; + sample_write_data <= (others => '0'); + sample_ren <= '0'; + sample_wen <= '0'; + payload_addr_next <= payload_addr; + payload_write_data <= (others => '0'); + payload_ren <= '0'; + payload_wen <= '0'; + ready_in_a <= '0'; + newest_sample_next <= newest_sample; + empty_payload_list_head_next <= empty_payload_list_head; + empty_sample_list_head_next <= empty_sample_list_head; + empty_sample_list_tail_next <= empty_sample_list_tail; + 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; + payload_mem_full_next <= payload_mem_full; + sample_mem_full_next <= sample_mem_full; + writer_pos_next <= writer_pos; + inst_opcode <= NOP; + key_hash_next <= key_hash; + sample_status_info_next <= sample_status_info; + inst_op_start <= '0'; + khg_last_word_in <= '0'; + khg_data_in <= (others => '0'); + khg_valid_in <= '0'; + khg_ready_out <= '0'; + writer_bitmap <= (others => '0'); + inst_addr_update <= (others => '0'); + remove_oldest_sample_next <= remove_oldest_sample; + remove_oldest_inst_sample_next <= remove_oldest_inst_sample; + added_new_instance_next <= added_new_instance; + + case (stage) is + when IDLE => + -- DEFAULT + ready_in_a <= '1'; + remove_oldest_inst_sample_next <= '0'; + remove_oldest_sample_next <= '0'; + added_new_instance_next <= '0'; + + if (start_a = '1') then + case (opcode_a) is + when ADD_CHANGE => + -- This Operation does not accept input at this time + ready_in_a <= '0'; + + res_a <= ACK; + stage_next <= ADD_SAMPLE_INFO; + cur_sample_next <= empty_sample_list_head; + sample_addr_next <= empty_sample_list_head; + cnt_next <= 0; + end if; + when REMOVE_WRITER => + -- Input and Memory Gurad + if (valid_in_a = '1' and inst_op_done = '1') then + -- Latch Writer Pos + writer_pos_next <= to_integer(unsigned(data_in_a)); + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + stage_next <= REMOVE_WRITER; + res_a <= ACK; + end if; + when others => + null; + end case; + elsif (start_b = '1') then + -- TODO + end if; + + when ADD_SAMPLE_INFO => + -- Precondition: sample_addr (empty_sample_list_head) + + ready_in_a <= '1'; + + -- Input Guard + if (valid_in_a = '1') then + cnt_next <= cnt + 1; + sample_addr_next <= sample_addr + 1; + + -- Write Through + sample_wen <= '1'; + sample_write_data <= data_in_a; + + case (cnt) is + -- Status Info + when 0 => + -- Initialize local status bits + sample_write_data(READ_FLAG) <= '0'; + -- Latch Status Info + sample_status_info_next <= data_in_a; + sample_status_info_next(READ_FLAG) <= '0'; + -- Latch Timestamp for ordering + -- Timestamp 1/2 + when 1 => + ts_latch_next(0) <= data_in_a; + -- Timestamp 2/2 + when 2 => + ts_latch_next(1) <= data_in_a; + -- Lifespan Deadline 2/2 + when 4 => + -- Skip Key Hash, if not available + if (has_key_hash = '0') then + cnt_next <= 9; + end if; + -- Latch Key Hash + -- Key Hash 1/4 + when 5 => + -- Latch Input, but do not pass to Memory + sample_wen <= '0'; + sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr) + key_hash_next(0) <= data_in_a; + -- Key Hash 2/4 + when 6 => + -- Latch Input, but do not pass to Memory + sample_wen <= '0'; + sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr) + key_hash_next(1) <= data_in_a; + -- Key Hash 3/4 + when 7 => + -- Latch Input, but do not pass to Memory + sample_wen <= '0'; + sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr) + key_hash_next(2) <= data_in_a; + -- Key Hash 4/4 + when 8 => + -- Latch Input, but do not pass to Memory + sample_wen <= '0'; + sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr) + key_hash_next(3) <= data_in_a; + when 9 => + -- Latch Input, but do not pass to Memory + writer_pos_next <= to_integer(unsigned(data_in_a)); + sample_wen <= '0'; + sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr) + stage_next <= ADD_PAYLOAD_ADDRESS; + when others => + null; + end case; + end if; + when ADD_PAYLOAD_ADDRESS => + -- Precondition: sample_addr (Payload Address) + + sample_addr_next <= sample_addr + 1; -- Instance Address + + if (has_data = '1') then + -- Store Payload Address + sample_wen <= '1'; + sample_write_data <= empty_payload_list_head; + + payload_addr_next <= empty_payload_list_head + PMF_NEXT_ADDR_OFFSET; + cur_payload_next <= empty_payload_list_head; + else + -- Mark Sample with no Payload + sample_wen <= '1'; + sample_write_data <= PAYLOAD_MEMORY_MAX_ADDRESS; + end if; + + -- If Key Hash is available, start the Instance Search first + if (has_key_hash = '1') then + stage_next <= INITIATE_INSTANCE_SEARCH; + else + stage_next <= ADD_PAYLOAD; + cnt_next <= 0; + end if; + when ADD_PAYLOAD => + -- Precondition (if has_data = '1'): cur_payload set (Current Slot), payload_addr (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_next <= cnt + 1; + payload_addr_next <= payload_addr + PMF_NEXT_ADDR_OFFSET; + + -- Payload Write + if (has_data = '1') then + payload_write_data <= data_in_a; + payload_wen <= '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 + if (has_key_hash = '0') then + khg_last_word_in <= '1'; + stage_next <= GET_KEY_HASH; + cnt_next <= 0; + else + stage_next <= FILTER_STAGE; + end if; + -- End of Payload Slot + elsif (has_data = '1' and cnt = PAYLOAD_FRAME_SIZE-2) then + stage_next <= NEXT_PAYLOAD_SLOT; + payload_addr_next <= cur_payload; + cnt_next <= 0; + end if; + end if; + when NEXT_PAYLOAD_SLOT => + -- Precondition: payload_addr (Beginning of current Slot) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + payload_ren <= '1'; + when 1 => + -- No Empty Payload Slots available + if (payload_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then + -- Reject Change + stage_next <= SKIP_ADD; + else + -- Latch next Payload Slot and Continue + cur_payload_next <= payload_read_data; + payload_addr_next <= payload_read_data + PMF_NEXT_ADDR_OFFSET; + stage_next <= ADD_PAYLOAD; + end if; + when others => + null; + end case; + when GET_KEY_HASH => + + khg_ready_out <= '1'; + + if (khg_valid_out = '1') then + cnt_next <= cnt + 1; + + -- Latch Key Hash + key_hash_next(cnt) <= khg_data_out; + + -- Exit Condition + if (khg_last_word_out = '1') then + -- DONE + stage_next <= INITIATE_INSTANCE_SEARCH; + end if; + end if; + when INITIATE_INSTANCE_SEARCH => + -- Memory Operation Guard + if (inst_op_done = '1') then + inst_opcode <= SEARCH_INSTANCE_HASH; + inst_op_start <= '1'; + + -- Payload not yet stored + if (has_data = '1') then + stage_next <= ADD_PAYLOAD; + cnt_next <= 0; + else + stage_next <= FILTER_STAGE; + end if; + end if; + when FILTER_STAGE => + -- Precondition: sample_addr (Instance Address of New Sample) + + -- Wait for Instance Search to finish + if (inst_op_done = '1') then + sample_addr_next <= sample_addr + 1; -- Disposed Gen Counter (Prev Address if GENERATION_COUNTERS=FALSE) + + -- Instance Found + if (inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then + -- Store Instance Address + sample_write_data <= inst_addr_base; + sample_wen <= '1'; + + -- TIME_BASED_FILTER QOS + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time <= inst_data.ignore_deadline) then + -- Drop Change + res_a <= ACCEPTED; + stage_next <= IDLE; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE) + elsif (MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then + if (HISTORY_QOS = KEEP_LAST_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then + -- Reject Change + res_a <= REJECTED; + stage_next <= IDLE; + else + -- Accept Change (Remove Oldest Instance Sample) + remove_oldest_inst_sample_next <= '1'; + res_a <= ACCEPTED; + stage_next <= UPDATE_INSTANCE; + end if; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) + elsif (empty_sample_list_head = empty_sample_list_tail) then + if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then + -- Reject Change + res_a <= REJECTED; + stage_next <= IDLE; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + res_a <= ACCEPTED; + stage_next <= UPDATE_INSTANCE; + end if; + else + -- Accept Change + res_a <= ACCEPTED; + stage_next <= UPDATE_INSTANCE; + end if; + else + -- Store Instance Address + sample_write_data <= inst_empty_head; + sample_wen <= '1'; + + -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) + if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- Reject Change + res_a <= REJECTED; + stage_next <= IDLE; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) + elsif (empty_sample_list_head = empty_sample_list_tail) then + if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then + -- Reject Change + res_a <= REJECTED; + stage_next <= IDLE; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + 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 <= INSERT_INSTANCE; + inst_op_start <= '1'; + + added_new_instance_next <= '1'; + + if (has_data = '1') then + payload_addr_next <= cur_payload; + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + else + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0 when GENERATION_COUNTERS else 2; + end if; + else + -- Drop Change + stage_next <= IDLE; + end if; + end if; + 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 <= INSERT_INSTANCE; + inst_op_start <= '1'; + + if (has_data = '1') then + payload_addr_next <= cur_payload; + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + else + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0 when GENERATION_COUNTERS else 2; + end if; + else + -- Drop Change + stage_next <= IDLE; + end if; + end if; + end if; + end if; + when UPDATE_INSTANCE => + -- Memory Operation Guard + if (inst_op_done = '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; + + -- INSTANCE SAMPLE COUNT + -- NOTE: Ignored when remove_oldest_inst_sample, since it will be decremented again. (Stays same) + if (remove_oldest_inst_sample = '0') then + 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 <= UPDATE_INSTANCE; + inst_op_start <= '1'; + update_inst_flags <= tmp_update; + + if (has_data = '1') then + payload_addr_next <= cur_payload; + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + else + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0 when GENERATION_COUNTERS else 2; + end if; + end if; + when FINALIZE_PAYLOAD => + -- Precondition: payload_addr (Beginning of Last Added Payload Slot) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + payload_ren <= '1'; + when 1 => + -- Fix New Empty List Head + empty_payload_list_head_next <= payload_read_data; + + -- Make current Slot the Tail + payload_write_data <= PAYLOAD_MEMORY_MAX_ADDRESS; + payload_wen <= '1'; + + stage_next <= PRE_SAMPLE_FINALIZE; + cnt_next <= 0 when GENERATION_COUNTERS else 2; + when others => + null; + end case; + when PRE_SAMPLE_FINALIZE => + -- Precondition: sample_addr (Disposed generation Counter of New Sample) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Disposed Generation Counter + when 0 => + if (GENERATION_COUNTERS) then + sample_addr_next <= sample_addr + 1; + sample_wen <= '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 <= gen_cnt + 1; + else + sample_write_data <= gen_cnt; + end if; + end if; + -- No Writer Generation Counter + when 1 => + if (GENERATION_COUNTERS) then + sample_wen <= '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 <= gen_cnt + 1; + else + sample_write_data <= gen_cnt; + end if; + end if; + when 2 => + -- First Sample + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= FINALIZE_SAMPLE_INFO; + sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + cnt_next <= 0; + else + stage_next <= FIND_POS; + prev_sample_next <= newest_sample; + sample_addr_next <= newest_sample + SMF_TIMESTAMP_OFFSET; + cnt_next <= 0; + end if; + when others => + null; + end case; + when FIND_POS => + -- Precondition: prev_sample set, sample_addr (Timestamp 1/2 Addr of prev_sample) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_addr_next <= sample_addr + 1; + sample_ren <= '1'; + -- Timestamp 1/2 + when 1 => + sample_addr_next <= sample_addr + SMF_PREV_ADDR_OFFSET-(SMF_TIMESTAMP_OFFSET+1); -- Prev Addr + sample_ren <= '1'; + long_latch_next <= sample_read_data; + -- Timestamp 2/2 + when 2 => + sample_ren <= '1'; + + tmp_dw := (0 => unsigned(long_latch), 1 => unsigned(sample_read_data)); + + sample_addr_next <= sample_addr + SMF_NEXT_ADDR_OFFSET-SMF_PREV_ADDR_OFFSET; -- Next Addr + + -- Found position (After current slot) + if (ts_latch >= tmp_dw) then + stage_next <= FIX_POINTERS; + cnt_next <= 0; + end if; + -- Previous Address + when 3 => + -- No previous Slot (Oldest Sample) + if (sample_read_data = 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_next <= FIX_POINTERS; + cnt_next <= 0; + else + prev_sample_next <= sample_read_data; + sample_addr_next <= sample_read_data + SMF_TIMESTAMP_OFFSET; + cnt_next <= 0; + end if; + end case; + when FIX_POINTERS => + -- Precondition: sample_addr (Next Addr of prev_sample) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_ren <= '1'; + when 1 => + + -- Fix Next Pointer + sample_write_data <= empty_sample_list_head; + sample_wen <= '1'; + + -- No next Slot (Newest Sample) + if (sample_read_data = 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 <= SAMPLE_MEMORY_MAX_ADDRESS; + stage_next <= FINALIZE_SAMPLE_INFO; + sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample + cnt_next <= 0; + else + -- Latch Next Sample + next_sample_next <= sample_read_data; + + sample_addr_next <= sample_read_data + SMF_PREV_ADDR_OFFSET; -- Prev Addr of Next Sample + end if; + when 2 => + -- Fix Previous Pointer + sample_write_data <= empty_sample_list_head; + sample_wen <= '1'; + + stage_next <= FINALIZE_SAMPLE_INFO; + sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample + cnt_next <= 0; + when others => + null; + end case; + when FINALIZE_SAMPLE_INFO => + -- Precondition: prev_sample set, next_sample set, sample_addr (Prev Addr of new sample) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Previous Sample Address + when 0 => + sample_addr_next <= sample_addr + 1; -- Next Sample + + -- Write Prev Addr + sample_write_data <= prev_sample; + sample_wen <= '1'; + -- Preload + when 1 => + sample_ren <= '1'; + -- Next Sample Address + when 2 => + empty_sample_list_head_next <= sample_read_data; + + -- Write Next Addr + sample_write_data <= next_sample; + sample_wen <= '1'; + + -- If newest Sample is now previous, select current sample as new newest + if (newest_sample = prev_sample) then + newest_sample_next <= empty_sample_list_head; + end if; + + -- New Instance was added, and Instance Memory is Full + if (added_new_instance = '1' and inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- Memory Operation Guard + if (inst_op_done = '1') then + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + + stage_next <= REMOVE_STALE_INSTANCE; + else + cnt_next <= cnt; -- Keep State + end if; + elsif (remove_oldest_inst_sample = '1') then + sample_addr_next <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + stage_next <= FIND_OLDEST_INST_SAMPLE; + elsif (remove_oldest_sample = '1') then + stage_next <= GET_OLDEST_SAMPLE_INSTANCE; + else + -- DONE + stage_next <= IDLE; + end if; + end case; + when GET_OLDEST_SAMPLE_INSTANCE => + -- Memory Operation Guard + if (inst_op_done = '1') then + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_ren <= '1'; + when 1 => + inst_op_start <= '1'; + inst_opcode <= SEARCH_INSTANCE_ADDR; + inst_addr_update <= sample_read_data; + + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_PREV_ADDR_OFFSET; + stage_next <= REMOVE_SAMPLE; + when others => + null; + end case; + end if; + when FIND_OLDEST_INST_SAMPLE => + -- Precondition: cur_sample set, sample_addr (Instance Address of cur_sample) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_ren <= '1'; + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; -- Next Addr + -- Instance Address + when 1 => + sample_ren <= '1'; + -- Oldest Instance Sample Found + if (sample_read_data = inst_addr_base) then + stage_next <= REMOVE_SAMPLE; + sample_addr_next <= cur_sample + SMF_PREV_ADDR_OFFSET; + end if; + -- Next Address + when 2 => + cur_sample_next <= sample_read_data; + sample_addr_next <= sample_read_data + SMF_INSTANCE_ADDR_OFFSET; -- Instance Addr + cnt_next <= 0; + when others => + null; + end case; + when REMOVE_SAMPLE => + -- Precondition: cur_sample set, sample_addr (Previous Address of cur_sample) + + -- Wait for Instance Search to finish + if (inst_op_done = '1') then + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_ren <= '1'; + sample_addr_next <= cur_sample + 1; -- Next Addr + -- Previous Addr (Current Sample) + when 1 => + sample_ren <= '1'; + prev_sample_next <= sample_read_data; + -- Next Addr (Current Sample) + when 2 => + next_sample_next <= sample_read_data; + + -- Make Current Sample Empty List Tail + sample_write_data <= INSTANCE_MEMORY_MAX_ADDRESS; + sample_wen <= '1'; + + -- Current Sample is Newest (Occupied List Tail) + if (sample_read_data = MAX_SAMPLE_ADDRESS) then + assert (cur_sample = newest_sample) report "Next Sample is MAX_ADDR, but cur_sample /= newest_sample" severity FAILURE; + + -- Fix Newest Pointer + newest_sample_next <= prev_sample; + + -- Current Sample is Oldest (List Head) + if (prev_sample = MAX_SAMPLE_ADDRESS) then + assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE; + assert (newest_sample = oldest_sample) report "Previous and Next Sample is MAX_ADDR, but cur_sample /= newest_sample /= oldest_sample" severity FAILURE; + + -- Fix Oldest Pointer + oldest_sample_next <= MAX_SAMPLE_ADDRESS; + -- NOTE: Sample Memory Empty (newest_sample also set to MAX_ADDR) + + -- Sample Memory Full + if (empty_sample_list_head = SAMPLE_MEMORY_MAX_ADDRESS) then + empty_sample_list_head_next <= cur_sample; + empty_sample_list_tail_next <= cur_sample; + + -- Skip to Payload Handling + cnt_next <= 6; + sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + else + -- Skip to Empty List Handling + cnt_next <= 5; + sample_addr_next <= empty_sample_list_tail + SMF_NEXT_ADDR_OFFSET; + end if; + else + -- Skip to Previous Handling + sample_addr_next <= prev_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 4; + end if; + else + sample_addr_next <= sample_read_data + SMF_PREV_ADDR_OFFSET; + end if; + -- Previous Address (Next Sample) + when 3 => + -- Remove link to cur_sample + sample_write_data <= prev_sample; + sample_wen <= '1'; + + -- Current Sample is oldest sample (List Head) + if (prev_sample = MAX_SAMPLE_ADDRESS) then + assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE; + + -- Fix Oldest Pointer + oldest_sample_next <= MAX_SAMPLE_ADDRESS; + + -- Sample Memory Full + if (empty_sample_list_head = SAMPLE_MEMORY_MAX_ADDRESS) then + empty_sample_list_head_next <= cur_sample; + empty_sample_list_tail_next <= cur_sample; + + -- Skip to Payload Handling + cnt_next <= 6; + sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + else + -- Skip to Empty List Handling + cnt_next <= 5; + sample_addr_next <= empty_sample_list_tail + SMF_NEXT_ADDR_OFFSET; + end if; + end if; + -- Next Address (Previous Sample) + when 4 => + -- Remove link to cur_sample + sample_write_data <= next_sample; + sample_wen <= '1'; + + sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + -- Next Address (Empty Tail) + when 5 => + sample_write_data <= cur_sample; + sample_wen <= '1'; + + -- Fix Empty List Pointers + empty_sample_list_tail_next <= cur_sample; + + sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + -- Preload + when 6 => + sample_ren <= '1'; + -- Payload Address + when 7 => + cur_payload_next <= sample_read_data; + -- Sample has no Data + if (sample_read_data = MAX_PAYLOAD_ADDRESS) then + stage_next <= POST_SAMPLE_REMOVE; + -- Payload Memory Full + elsif (empty_payload_list_head = MAX_PAYLOAD_ADDRESS) then + -- NOTE: Make the head of the Payload, the head of the Empty List + empty_payload_list_head_next <= sample_read_data; + + stage_next <= POST_SAMPLE_REMOVE; + else + payload_addr_next <= cur_payload + PMF_NEXT_ADDR_OFFSET; + end if; + -- Preload + when 8 => + payload_ren <= '1'; + -- Next Payload Addr + when 9 => + -- Found Empty List Tail + if (payload_read_data = MAX_PAYLOAD_ADDRESS) then + empty_payload_list_head_next <= cur_payload; + payload_write_data <= empty_payload_list_head; + payload_wen <= '1'; + + stage_next <= POST_SAMPLE_REMOVE; + else + payload_addr_next <= payload_read_data + PMF_NEXT_ADDR_OFFSET; + cnt_next <= 8; + end if; + when others => + null; + end case; + end if; + when POST_SAMPLE_REMOVE => + -- Memory Operation Guard + if (inst_op_done = '1') then + -- No Instance Change on remove_oldest_inst_sample + if (remove_oldest_inst_sample = '0') then + tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + -- Instance obsolete and Instance Memory Full + if (inst_data.sample_cnt = 1 and tmp_bitmap = (tmp_bitmap'range => '0') and inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_op_start <= '1'; + inst_opcode <= REMOVE_INSTANCE; + + -- DONE + stage_next <= IDLE; + else + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + update_inst_flags <= SAMPLE_CNT_FLAG; + sample_cnt <= inst_data.sample_cnt - 1; + + -- DONE + stage_next <= IDLE; + end if; + end if; + end if; + when SKIP_ADD => + case (cnt) is + -- SKIP READ + when 0 => + ready_in_a <= '1'; + -- Wait until last word from input + if (last_word_in_a = '1') then + cnt_next <= 1; + end if; + -- REJECT SAMPLE + when 1 => + res_a <= REJECTED; + stage_next <= IDLE; + when others => + null; + end case; + when REMOVE_WRITER => + -- Memory Operation Guard + if (inst_op_done = '1') then + -- No More Instances + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + -- DONE + stage_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 <= '1'; + instance_state <= NOT_ALIVE_NO_WRITERS; + inst_opcode <= UPDATE_INSTANCE; + update_inst_flags <= STATUS_FLAG or WRITER_BITMAP_FLAG; + else + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + update_inst_flags <= WRITER_BITMAP_FLAG; + end if; + + stage_next <= GET_NEXT_INSTANCE; + end if; + end if; + when GET_NEXT_INSTANCE => + -- Wait for Operation to Complete + if (inst_op_done = '1') then + inst_op_start <= '1'; + inst_opcode <= NEXT_INSTANCE; + stage_next <= REMOVE_WRITER; + end if; + when REMOVE_STALE_INSTANCE => + -- Wait for Instance Data + if (inst_op_done = '1') then + -- Iterated through all Instances + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Convert Writer Bitmap to SLV + tmp_bitmap := to_endpoint_bitmap(inst_data.writer_bitmap); + + -- Found Stale Instance (No Samples and No Active Writers) + if (inst_data.sample_cnt = 0 and tmp_bitmap = (tmp_bitmap'range => '0')) then + -- Remove Stale Instance + inst_op_start <= '1'; + inst_opcode <= REMOVE_INSTANCE; + + -- DONE + stage_next <= IDLE; + else + -- Continue Search + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + end if; + end if; + end if; + when others => + null; + end case; + end process; + + + inst_ctrl_prc : process(all) + begin + -- DEFAULT Registered + inst_stage_next <= inst_stage; + inst_addr_base_next <= inst_addr_base; + inst_addr_next <= inst_addr; + inst_empty_head_next <= inst_empty_head; + inst_occupied_head_next <= inst_occupied_head; + inst_latch_data_next <= inst_latch_data; + inst_next_addr_base_next <= inst_next_addr_base; + inst_prev_addr_base_next <= inst_prev_addr_base; + inst_cnt_next <= inst_cnt; + inst_mem_full_next <= inst_mem_full; + inst_data_next <= inst_data; + -- DEFAULT Unregistered + inst_write_data <= (others => '0'); + inst_op_done <= '0'; + inst_ren <= '0'; + inst_wen <= '0'; + + + case (mem_stage) is + when IDLE => + inst_op_done <= '1'; + + if (inst_op_start = '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, + sample_cnt => sample_cnt, + gen_cnt => gen_cnt, + deadline => deadline, + writer_bitmap => writer_bitmap, + update_flags => update_inst_flags, + addr => inst_addr_update + ); + + case(inst_opcode) is + when SEARCH_INSTANCE_HASH => + -- Reset Data + inst_data_next <= ZERO_INSTANCE_DATA; + + -- No Instances avialable + if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_prev_addr_base <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_next <= inst_occupied_head; + inst_addr_next <= inst_occupied_head; + inst_stage_next <= SEARCH_INSTANCE_HASH; + inst_cnt_next <= 0; + end if; + when SEARCH_INSTANCE_ADDR => + -- Reset Data + inst_data_next <= ZERO_INSTANCE_DATA; + + -- No Instances avialable + if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_prev_addr_base <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_next <= inst_occupied_head; + inst_addr_next <= inst_occupied_head; + inst_stage_next <= SEARCH_INSTANCE_ADDR; + inst_cnt_next <= 0; + 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_empty_head /= INSTANCE_MEMORY_MAX_ADDRESS) report "Instance Insertion while memory Full" severity FAILURE; + + inst_addr_next <= inst_empty_head; + inst_addr_base_next <= inst_empty_head; + inst_stage_next <= INSERT_INSTANCE; + inst_cnt_next <= 0; + when UPDATE_INSTANCE => + inst_addr_base_next <= inst_addr_update; + if ((update_inst_flags and STATUS_FLAG) = STATUS_FLAG) then + inst_stage_next <= UPDATE_INSTANCE; + inst_addr_next <= inst_addr_update + IMF_STATUS_INFO_OFFSET; + inst_cnt_next <= 0; + elsif ((update_inst_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then + inst_stage_next <= UPDATE_INSTANCE; + inst_addr_next <= inst_addr_update + IMF_SAMPLE_CNT_OFFSET; + inst_cnt_next <= 3; + elsif (GENERATION_COUNTERS and (update_inst_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then + inst_stage_next <= UPDATE_INSTANCE; + inst_addr_next <= inst_addr_update + IMF_DISPOSED_GEN_CNT_OFFSET; + inst_cnt_next <= 6; + elsif (GENERATION_COUNTERS and (update_inst_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then + inst_stage_next <= UPDATE_INSTANCE; + inst_addr_next <= inst_addr_update + IMF_NO_WRITERS_GEN_CNT_OFFSET; + inst_cnt_next <= 7; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (update_inst_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_stage_next <= UPDATE_INSTANCE; + inst_addr_next <= inst_addr_update + IMF_IGNORE_DEADLINE_OFFSET; + inst_cnt_next <= 8; + elsif ((update_inst_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then + inst_stage_next <= SET_WRITER_BITMAP; + inst_addr_next <= inst_addr_update + IMF_WRITER_BITMAP_OFFSET; + inst_cnt_next <= 0; + end if; + when GET_FIRST_INSTANCE => + -- No Instances avialable + if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_next <= inst_occupied_head; + inst_addr_next <= inst_occupied_head + IMF_STATUS_INFO_OFFSET; + inst_stage_next <= GET_INSTANCE_DATA; + inst_cnt_next <= 0; + end if; + when GET_NEXT_INSTANCE => + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + inst_addr_next <= inst_next_addr_base; + inst_stage_next <= GET_NEXT_INSTANCE; + inst_cnt_next <= 0; + when REMOVE_INSTANCE => + assert (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) report "Request Removal on empty memory" severity FAILURE; + + inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + inst_addr_base_next <= inst_occupied_head; + inst_addr_next <= inst_occupied_head; + inst_stage_next <= REMOVE_INSTANCE; + inst_cnt_next <= 0; + when others => + null; + end case; + end if; + when SEARCH_INSTANCE_HASH => + inst_ren <= '1'; + inst_cnt_next <= inst_cnt + 1; + inst_addr_next <= inst_addr + 1; + + case (inst_cnt) is + -- Preload + when 0 => + null; + -- Next Instance + when 1 => + inst_next_addr_base_next <= inst_read_data; + -- Key Hash 1/4 + when 2 => + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(0)) then + -- Reached List Tail, No Match + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + inst_addr_next <= inst_next_addr_base; + inst_cnt_next <= 0; + end if; + end if; + -- Key Hash 2/4 + when 3 => + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(1)) then + -- Reached List Tail, No Match + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + inst_addr_next <= inst_next_addr_base; + inst_cnt_next <= 0; + end if; + end if; + -- Key Hash 3/4 + when 4 => + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(2)) then + -- Reached List Tail, No Match + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + inst_addr_next <= inst_next_addr_base; + inst_cnt_next <= 0; + end if; + end if; + -- Key Hash 4/4 + when 5 => + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(3)) then + -- Reached List Tail, No Match + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_next <= IDLE; + else + -- Continue Search + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + inst_addr_next <= inst_next_addr_base; + inst_cnt_next <= 0; + end if; + -- Match + else + -- Fetch Instance Data + inst_stage_next <= GET_INSTANCE_DATA; + inst_cnt_next <= 1; -- No preload needed + end if; + when others => + null; + end case; + when SEARCH_INSTANCE_ADDR => + inst_cnt_next <= inst_cnt + 1; + inst_addr_next <= inst_addr + 1; + + case (inst_cnt) is + -- Preload + when 0 => + inst_ren <= '1'; + -- Next Instance + when 1 => + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_read_data; + + -- No Match + if (inst_read_data /= inst_latch_data.addr) then + -- Fetch Instance Data + inst_stage_next <= GET_INSTANCE_DATA; + inst_addr_next <= inst_read_data + IMF_STATUS_INFO_OFFSET; + inst_cnt_next <= 0; + -- Match + else + -- Reached List Tail, No Match + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_next <= IDLE; + else + -- Continue Search + inst_addr_next <= inst_read_data; + inst_cnt_next <= 0; + end if; + end if; + when others => + null; + end case; + when GET_NEXT_INSTANCE => + case (inst_cnt) is + -- Preload + when 0 => + inst_wen <= '1'; + -- Next Instance + when 1 => + -- Latch Next Instance + inst_next_addr_base_next <= inst_read_data; + + inst_addr_next <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_cnt_next <= 0; + inst_stage_next <= GET_INSTANCE_DATA; + end case; + when GET_INSTANCE_DATA => + -- Precondition: inst_addr (Status Info) + + inst_ren <= '1'; + inst_cnt_next <= inst_cnt + 1; + inst_addr_next <= inst_addr + 1; + + case (inst_cnt) is + -- Memory Preload + when 0 => + null; + -- Status Info + when 1 => + inst_data_next.status_info <= inst_read_data; + -- Sample Count + when 2 => + inst_data_next.sample_cnt <= inst_read_data; + -- Disposed Generation Count + when 3 => + inst_data_next.disposed_gen_cnt <= inst_read_data; + -- No Writers Generation Count + when 4 => + inst_data_next.no_writers_gen_cnt <= inst_read_data; + -- Ignore Deadline 1/2 + when 5 => + inst_data_next.ignore_deadline(0) <= unsigned(inst_read_data); + -- Ignore Deadline 2/2 + when 5 => + inst_data_next.ignore_deadline(1) <= unsigned(inst_read_data); + -- DONE + inst_stage_next <= GET_WRITER_BITMAP; + inst_cnt_next <= 0; + when others => + null; + end case; + when GET_WRITER_BITMAP => + inst_cnt_next <= inst_cnt + 1; + + inst_latch_data_next.writer_bitmap(inst_cnt) <= inst_read_data; + + if (inst_cnt = writer_bitmap'length-1) then + -- DONE + inst_stage_next <= IDLE; + end if; + when INSERT_INSTANCE => + + inst_wen <= '1'; + inst_addr_next <= inst_addr + 1; + inst_cnt_next <= inst_cnt + 1; + + case (inst_cnt) is + -- Preload + when 0 => + inst_ren <= '1'; + -- Next Instance Address + when 1 => + inst_empty_head_next <= inst_read_data; + -- Make New Occupied Head + inst_write_data <= inst_occupied_head; + inst_occupied_head_next <= inst_empty_head; + -- Key Hash 1/4 + when 2 => + inst_write_data <= inst_latch_data.key_hash(0); + -- Key Hash 2/4 + when 3 => + inst_write_data <= inst_latch_data.key_hash(1); + -- Key Hash 3/4 + when 4 => + inst_write_data <= inst_latch_data.key_hash(2); + -- Key Hash 4/4 + when 5 => + inst_write_data <= inst_latch_data.key_hash(3); + -- Status Info + when 6 => + inst_write_data <= inst_latch_data.status_info; + -- Sample Count + when 7 => + inst_write_data <= std_logic_vector(to_unsigned(1, WORD_WIDTH)); + + if (GENERATION_COUNTERS) then + inst_cnt <= 8; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + inst_cnt <= 10; + else + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + end if; + -- Disposed Generation Count + when 8 => + if (GENERATION_COUNTERS) then + inst_write_data <= (others => '0'); + end if; + -- No Writers Generation Count + when 9 => + if (GENERATION_COUNTERS) then + inst_write_data <= (others => '0'); + + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + inst_cnt <= 10; + else + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + end if; + end if; + -- Ignore Deadline 1/2 + when 10 => + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + inst_write_data <= inst_latch_data.deadline(0); + end if; + -- Ignore Deadline 1/2 + when 11 => + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + inst_write_data <= inst_latch_data.deadline(1); + + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + end if; + when others => + null; + end case; + when SET_WRITER_BITMAP => + inst_wen <= '1'; + inst_addr_next <= inst_addr + 1; + inst_cnt_next <= inst_cnt + 1; + + inst_write_data <= inst_latch_data.writer_bitmap(inst_cnt); + + -- Exit Condition + if (inst_cnt = inst_latch_data.writer_bitmap'length-1) then + -- DONE + inst_stage_next <= IDLE; + end if; + when UPDATE_INSTANCE => + inst_cnt_next <= inst_cnt + 1; + + case (inst_cnt) is + -- Status Info + when 0 => + inst_wen <= '1'; + inst_write_data <= inst_long_latch; + case (inst_latch_data.instance_state) is + when ALIVE => + inst_write_data(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + inst_write_data(NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; + inst_write_data(LIVELINESS_FLAG) <= '1'; + when NOT_ALIVE_DISPOSED => + inst_write_data(NOT_ALIVE_DISPOSED_FLAG) <= '1'; + inst_write_data(NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; + inst_write_data(LIVELINESS_FLAG) <= '1'; + when NOT_ALIVE_NO_WRITERS => + inst_write_data(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + inst_write_data(NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; + inst_write_data(LIVELINESS_FLAG) <= '1'; + end case; + + if ((inst_latch_data.update_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then + inst_addr_next <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_cnt_next <= 1; + elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then + inst_addr_next <= inst_addr_base + IMF_DISPOSED_GEN_CNT_OFFSET; + inst_cnt_next <= 2; + elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then + inst_addr_next <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET; + inst_cnt_next <= 3; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET; + inst_cnt_next <= 4; + elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then + inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET; + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + -- Sample Count + when 1 => + inst_wen <= '1'; + inst_write_data <= inst_latch_data.sample_cnt; + + if (GENERATION_COUNTERS and (inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then + inst_addr_next <= inst_addr_base + IMF_DISPOSED_GEN_CNT_OFFSET; + inst_cnt_next <= 2; + elsif (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then + inst_addr_next <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET; + inst_cnt_next <= 3; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET; + inst_cnt_next <= 4; + elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then + inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET; + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + -- Disposed Generation Count + when 2 => + if (GENERATION_COUNTERS) then + inst_wen <= '1'; + inst_write_data <= inst_latch_data.gen_cnt; + + if (GENERATION_COUNTERS and (inst_latch_data.update_flags and NO_WRITERS_CNT_FLAG) = NO_WRITERS_CNT_FLAG) then + inst_addr_next <= inst_addr_base + IMF_NO_WRITERS_GEN_CNT_OFFSET; + inst_cnt_next <= 3; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET; + inst_cnt_next <= 4; + elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then + inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET; + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- No Writers Generation Count + when 3 => + if (GENERATION_COUNTERS) then + inst_wen <= '1'; + inst_write_data <= inst_latch_data.gen_cnt; + + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then + inst_addr_next <= inst_addr_base + IMF_IGNORE_DEADLINE_OFFSET; + inst_cnt_next <= 4; + elsif ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then + inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET; + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- Ignore Deadline 1/2 + when 4 => + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + inst_wen <= '1'; + inst_write_data <= std_logic_vector(inst_latch_data.ignore_deadline(0)); + end if; + -- Ignore Deadline 2/2 + when 5 => + if (TIME_BASED_FILTER_QOS /= DURATION_ZERO) then + inst_wen <= '1'; + inst_write_data <= std_logic_vector(inst_latch_data.ignore_deadline(1)); + + if ((inst_latch_data.update_flags and WRITER_BITMAP_FLAG) = WRITER_BITMAP_FLAG) then + inst_addr_next <= inst_addr_base + IMF_WRITER_BITMAP_OFFSET; + inst_stage_next <= SET_WRITER_BITMAP; + inst_cnt_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + when others => + null; + end case; + when REMOVE_INSTANCE => + inst_cnt_next <= inst_cnt + 1; + + case (inst_cnt) is + -- Preload + when 0 => + inst_ren <= '1'; + inst_addr_next <= inst_prev_addr_base + IMF_NEXT_ADDR_OFFSET; + -- Next Instance (Previous Occupied Instance) + when 1 => + -- Fix Pointer + inst_write_data <= inst_read_data; + inst_wen <= '1'; + + inst_addr_next <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + -- Next Instance (Current Instance) + when 2 => + -- Fix Pointer + inst_write_data <= inst_empty_head; + inst_wen <= '1'; + -- Fix Empty List Head + inst_empty_head_next <= inst_addr_base; + + -- DONE + inst_stage_next <= IDLE; + when others => + null; + end case; + when others => + null; + end case; + end process; + +end architecture; \ No newline at end of file