From 164bd508c1b98bd3e516abd8d5f4d470480fb021 Mon Sep 17 00:00:00 2001 From: Greek Date: Mon, 25 Jan 2021 20:01:03 +0100 Subject: [PATCH] Blind implementation of READ/TAKE DDS READER operations Finalized DDS Reader interface. Implemented read/take, read_next_sample/take_next_sample, read_instance/take_instance, read_next_instance/take_next_instance operations. Instance Get operations were made generic to allow returning 2 variants of instance data. --- src/REF.txt | 13 +- src/TODO.txt | 78 +- src/dds_endpoint.vhd | 1483 +++++++++++++++++++++++++++++++---- src/rtps_config_package.vhd | 3 + src/rtps_package.vhd | 112 +++ 5 files changed, 1502 insertions(+), 187 deletions(-) diff --git a/src/REF.txt b/src/REF.txt index 180e227..3407e34 100644 --- a/src/REF.txt +++ b/src/REF.txt @@ -459,14 +459,15 @@ STATUS INFO ----------- 31............24..............16..............8...............0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -+-----------------------------------------------------+-+-+-+-+ -| UNUSED |V|L|W|D| -+-----------------------------------------------------+-+-+-+-+ ++---------------------------------------------------+-+-+-+-+-+ +| UNUSED |M|V|L|W|D| ++---------------------------------------------------+-+-+-+-+-+ D...NOT_ALIVE_DISPOSED W...NOT_ALIVE_NO_WRITERS L...LIVELINESS FLAG V...VIEW STATE +M...MARK OUTPUT DATA @@ -608,6 +609,12 @@ The act of reading a sample sets its sample_state to READ. If the sample belongs generation of the instance, it will also set the view_state of the instance to NOT_NEW. It will not affect the instance_state of the instance. +https://community.rti.com/static/documentation/connext-dds/5.2.0/doc/manuals/connext_dds/html_files/RTI_ConnextDDS_CoreLibraries_UsersManual/Content/UsersManual/DESTINATION_ORDER_QosPolicy.htm#sending_2410472787_644578 +Data will be delivered by a DataReader in the order in which it was sent. If data arrives on the network +with a source timestamp earlier than the source timestamp of the last data delivered, the new data will +be dropped. This ordering therefore works best when system clocks are relatively synchronized among +writing machines. + INVALIDATION ============ diff --git a/src/TODO.txt b/src/TODO.txt index 55a62f6..05b9e4f 100644 --- a/src/TODO.txt +++ b/src/TODO.txt @@ -63,14 +63,11 @@ * What happens if we get a sample with a source timestamp earlier than the last sample that was accessed by the DataReader when using DESTINATION ORDER BY_SOURCE_TIMESTAMP? Is the smaple dropped? * The spec does not define the serialized Key (KEY=1 DATA MESSAGE) - fast-rtps assumes it is the Key Hash - - * Currently the builtin-endpoint does only acknowledge SN, but does not negatively acknowledge any SN (Bitamp is always empty). A writer usually responds with repqirs only to negative acknowledgements. -* 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. +* Currently a RTPS Writer with DURABILITY TARNSIENT_LOCAL does send historical data to all matched readers, not depending 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 @@ -149,20 +146,23 @@ DESIGN DECISIONS Use the lowest bit of the Heartbeat/Acknack Deadline stored in the Participant Data to differentiate between Delay and Suppression. This reduces the resolution from 0.23 ns to 0.47 ns -* Originally we stored the mask of local matching endpoints in the memory frame of the remote endpoint in order - to be able to send MATCH frames only to new matches, and UNMATCH frames only to previously matched local endpoints. - This decision was reverted, and we just sent MATCH frames to the currently matched local endpoints (non depending on if they are already matched) - and UNMATCH frames to the rest of the local endpoints (non depending on if they were previously matched). - So we basically push the responsibility to the local endpoints, which have to handle this situations accordingly. - Since META traffic is not supposed to be generated as often , this should not produce any significant overhead. - As optimization, on new matched remote endpoints UNMATCH frames can be ignored. +* Originally we stored the mask of local matching endpoints in the memory frame of the remote endpoint + in order to be able to send MATCH frames only to new matches, and UNMATCH frames only to previously + matched local endpoints. This decision was reverted, and we just sent MATCH frames to the currently + matched local endpoints (non depending on if they are already matched) and UNMATCH frames to the + rest of the local endpoints (non depending on if they were previously matched). + So we basically push the responsibility to the local endpoints, which have to handle this situations + accordingly. Since META traffic is not supposed to be generated as often, this should not produce + any significant overhead. As optimization, on new matched remote endpoints UNMATCH frames can be + ignored. -* The HEARTBEATs are sent out together with the liveliness assertions. This adds a 96-Byte overhead to the output RTPS Message. - This was done to prevent having to loop through the memory to find remote participant destination more than once. +* The HEARTBEATs are sent out together with the liveliness assertions. This adds a 96-Byte overhead + to the output RTPS Message. This was done to prevent having to loop through the memory to find + remote participant destination more than once. * The Publisher, Subscriber, and Message Data is written on separate RTPS Messages, even though they are sent simutanously. This decision was made to support as many local Endpoints as possible. We could - make a compile-time if check and sent them in the same RTPS Message/UDP Packet, but the overhead is + make a compile-time check and sent them in the same RTPS Message/UDP Packet, but the overhead is quite small and not worth the hassle. * Even though the Reader does not need to keep track of received SN with respect to each Writer with @@ -176,29 +176,31 @@ DESIGN DECISIONS In order to acoomodate for that, we could store the lowest (and possibly highest) SN of a requested lost SN and always send ALL GAPs in that range. -* The meta_data (sample info) of a cache change is fixed size, and a cache change may be connected to data (payload), - which may be variable in size. For this reason, we store the cache change and payload in separate memories. - The payload size may either be fixed (in which case the memory frame sizes are adjusted according to that), - or may be variable, in which case the payload is stored in a linked list of predefined sized memory frames. - The first word of a payload contains the address of the next linked memory frame. If this is the last frame - (or if the payload is static and there are no linked frames), the address is MAX_ADDRESS. - The last bit of this address is the "occupied" bit. This bit signifies if the memory frame is used or free, - 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 meta_data (sample info) of a cache change is fixed size, and a cache change may be connected to + data (payload), which may be variable in size. For this reason, we store the cache change and + payload in separate memories. The payload size may either be fixed (in which case the memory frame + sizes are adjusted according to that), or may be variable, in which case the payload is stored in + a linked list of predefined sized memory frames. The first word of a payload contains the address + of the next linked memory frame. If this is the last frame (or if the payload is static and there + are no linked frames), the address is MAX_ADDRESS. The last bit of this address is the "occupied" + bit. This bit signifies if the memory frame is used or free, 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). -* !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). - Since all memory operations are handled by the same entity, this allows some state keeping to improve - memory bandwidth. More specifically the "linked list" paradigm can be extended to also reference empty - slots (and next unread slots), to allow selecting empty slots without iterating through the whole memory. - Originally the memory was to be implemented in a true dual port fashion, and two seperate procoesses - would each satisfy the requests from one input side. This would allow concurrent RTPS and DDS requests - to be handled. The write concurrency (add and remove change) does not allow for state keeping (first - 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 +* !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). Since all memory operations are handled by the same entity, this allows some state keeping + to improve memory bandwidth. More specifically the "linked list" paradigm can be extended to also + reference empty slots (and next unread slots), to allow selecting empty slots without iterating + through the whole memory. Originally the memory was to be implemented in a true dual port fashion, + and two seperate procoesses would each satisfy the requests from one input side. This would allow + concurrent RTPS and DDS requests to be handled. The write concurrency (add and remove change) does + not allow for state keeping (first 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 @@ -222,10 +224,8 @@ PROTOCOL UNCOMPLIANCE -> No validity check * Inline QoS validated in Endpoint -> Cannot invalidate Rest of Message/Packet +* RESOURCE_LIMITS applies also to "empty" samples (Samples with no valid data). --- Input FIFO Guard --- Output FIFO Guard --- Deferred to package Body RTPS ENDPOINT ============= diff --git a/src/dds_endpoint.vhd b/src/dds_endpoint.vhd index 4a1cada..6df0cd8 100644 --- a/src/dds_endpoint.vhd +++ b/src/dds_endpoint.vhd @@ -3,6 +3,7 @@ use ieee.std_logic_1164.all; use ieee.numeric_std.all; -- TODO: Cancel KHG operation on incomplete payload parsing +-- TODO: Make sure rest of Payload slot is zero initialized entity history_cache is generic ( @@ -11,27 +12,57 @@ entity history_cache is 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; + PRESENTATION_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_PRESENTATION_QOS; + COHERENT_ACCESS : boolean := DEFAULT_COHERENT_ACCESS; + ORDERED_ACCESS : boolean := DEFAULT_ORDERED_ACCESS; ); 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_rtps : in std_logic; + opcode_rtps : in HISTORY_CACHE_OPCODE_TYPE; + res_rtps : out HISTORY_CACHE_RESPOSNE_TYPE; + data_in_rtps : in std_logic_vector(WORD_WIDTH-1 downto 0); + valid_in_rtps : in std_logic; + ready_in_rtps : out std_logic; + last_word_in_rtps : 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; - instance_state : in INSTANCE_STATE_TYPE; - view_state : in VIEW_STATE_TYPE; - sample_state : in SAMPLE_STATE; + -- + start_dds : in std_logic; + ack_dds : out std_logic; + opcode_dds : in HISTORY_CACHE_OPCODE_TYPE; + instance_state_in : in std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); + view_state_in : in std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0); + sample_state_in : in std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0); + instance_handle_in : in INSTANCE_HANDLE_TYPE; + max_samples_in : in std_logic_vector(MAX_SAMPLES_WIDTH-1 downto 0); + next_sample : in std_logic; + get_data : in std_logic; + done_dds : out std_logic; + return_code_dds : out std_logic_vector(RETURN_CODE_WIDTH-1 downto 0); + + -- Sample Info + si_sample_state : out std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0); + si_view_state : out std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0); + si_instance_state : out std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0); + si_source_timestamp : out TIME_TYPE; + si_instance_handle : out INSTANCE_HANDLE_TYPE; + si_publication_handle : out PUBLICATION_HANDLE_TYPE; + si_disposed_generation_count : out std_logic_vector(DISPOSED_GENERATION_COUNT_WIDTH-1 downto 0); + si_no_writers_generation_count : out std_logic_vector(NO_WRITERS_GENERATION_COUNT_WIDTH-1 downto 0); + si_sample_rank : out std_logic_vector(SAMPLE_RANK_WIDTH-1 downto 0); + si_generation_rank : out std_logic_vector(GENERATION_RANK_WIDTH-1 downto 0); + si_absolute_generation_count : out std_logic_vector(ABSOLUTE_GENERATION_COUNT_WIDTH-1 downto 0); + si_valid_data : out std_logic; + si_valid : out std_logic; + + ready_out_dds : in std_logic; + valid_out_dds : out std_logic; + data_out_dds : out std_logic_vector(WORD_WIDTH-1 downto 0); + last_word_out_dds : out std_logic; + + status : out std_logic_vector(STATUS_KIND_WIDTH-1 downto 0); ); end entity; @@ -105,6 +136,7 @@ architecture arch of history_cache is type INST_STAGE_TYPE is (IDLE, TODO); type INSTANCE_OPCODE_TYPE is (NOP, TODO); type INSTANCE_DATA_TYPE is record + key_hash : KEY_HASH_TYPE; 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); @@ -113,6 +145,7 @@ architecture arch of history_cache is writer_bitmap : ENDPOINT_BITMAP_ARRAY_TYPE; end record; constant ZERO_INSTANCE_DATA : INSTANCE_DATA_TYPE := ( + key_hash => (others => (others => '0')), status_info => (others => '0'), sample_cnt => (others => '0'), disposed_gen_cnt => (others => '0'), @@ -121,8 +154,9 @@ architecture arch of history_cache is writer_bitmap => (others => (others => '0')) ); type INST_LATCH_DATA_TYPE is record + variant : std_logic; key_hash : KEY_HASH_TYPE; - instance_state : INSTANCE_STATE_TYPE; + status_info : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); 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; @@ -131,8 +165,9 @@ architecture arch of history_cache is addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); end record; constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := ( + variant => '1', key_hash => (others => (others => '0')), - instance_state => ALIVE, + status_info => (others => '0'), sample_cnt => (others => '0'), gen_cnt => (others => '0'), deadline => TIME_INVALID, @@ -176,7 +211,7 @@ architecture arch of history_cache is 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_update : INSTANCE_STATE_TYPE := ALIVE; + signal status_info_update : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); 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'; @@ -187,7 +222,6 @@ architecture arch of history_cache is 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; @@ -203,11 +237,48 @@ architecture arch of history_cache is 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'); + signal inst_long_latch_1, inst_long_latch_1_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + signal inst_long_latch_2, inst_long_latch_2_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + + signal si_sample_state_sig, si_sample_state_sig_next : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := (others => '0'); + signal si_view_state_sig, si_view_state_sig_next : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0) := (others => '0'); + signal si_instance_state_sig, si_instance_state_sig_next : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0) := (others => '0'); + signal si_source_timestamp_sig, si_source_timestamp_sig_next : TIME_TYPE := TIME_INVALID; + signal si_instance_handle_sig, si_instance_handle_sig_next : INSTANCE_HANDLE_TYPE := (others => (others => '0')); + signal si_publication_handle_sig, si_publication_handle_sig_next : PUBLICATION_HANDLE_TYPE := (others => (others => '0')); + signal si_disposed_generation_count_sig, si_disposed_generation_count_sig_next : unsigned(DISPOSED_GENERATION_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal si_no_writers_generation_count_sig, si_no_writers_generation_count_sig_next : unsigned(NO_WRITERS_GENERATION_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal si_sample_rank_sig, si_sample_rank_sig_next : unsigned(SAMPLE_RANK_WIDTH-1 downto 0) := (others => '0'); + signal si_generation_rank_sig, si_generation_rank_sig_next : unsigned(GENERATION_RANK_WIDTH-1 downto 0) := (others => '0'); + signal si_absolute_generation_count_sig, si_absolute_generation_count_sig_next : unsigned(ABSOLUTE_GENERATION_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal si_valid_data_sig, si_valid_data_sig_next : std_logic := '0'; + signal si_valid_sig, si_valid_sig_next : std_logic := '0'; + + signal sample_state, sample_state_next : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := (others => '0'); + signal view_state, view_state_next : std_logic_vector(VIEW_STATE_KIND_WIDTH-1 downto 0) := (others => '0'); + signal instance_state, instance_state_next : std_logic_vector(INSTANCE_STATE_KIND_WIDTH-1 downto 0) := (others => '0'); + signal instance_handle, instance_handle_next : INSTANCE_HANDLE_TYPE := (others => '0'); + signal max_samples, max_samples_next : unsigned(MAX_SAMPLES_WIDTH-1 downto 0) := (others => '0'); + signal inst_addr_latch, inst_addr_latch_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal collection_cnt, collection_cnt_next : unsigned(MAX_SAMPLES_WIDTH-1 downto 0) := (others => '0'); + signal collection_cnt_max, collection_cnt_max_next : unsigned(MAX_SAMPLES_WIDTH-1 downto 0) := (others => '0'); + signal collection_generation_rank, collection_generation_rank_next : unsigned(GENERATION_RANK_WIDTH-1 downto 0) := (others => '0'); + signal cur_generation_rank, cur_generation_rank_next : unsigned(GENERATION_RANK_WIDTH-1 downto 0) := (others => '0'); + signal is_take, is_take_next : std_logic := '0'; + signal has_latched, has_lacthed_next : std_logic := '0'; + signal single_instance, single_instance_next : std_logic := '0'; + -- NOTE: We use this signal to prevent the costly Instance Marking in the case that we only need to ouptput next sample. + -- I.e. make READ_NEXT/TAKE_NEXT the fastest commands. + signal single_sample, single_sample_next : std_logic := '0'; + signal unmark_instances, unmark_instances_next : std_logic := '0'; + signal dynamic_next_instance, dynamic_next_instance_next : std_logic := '0'; + signal inst_data_variant : 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; + alias first_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1; + alias first_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; @@ -216,9 +287,23 @@ architecture arch of history_cache is 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 cur_inst : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) is inst_addr_latch_1; + alias cur_inst_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) is inst_addr_latch_1_next; + alias next_inst : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) is inst_addr_latch_2; + alias next_inst_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) is inst_addr_latch_2_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); + -- *FUNCTION DECLARATION* + function to_unsigned(input : KEY_HASH_TYPE) return unsigned is + variable ret : unsigned((KEY_HASH_WIDTH*WORD_WIDTH)-1 downto 0) := (others => '0'); + begin + for i in 0 to KEY_HASH_WIDTH-1 loop + ret(((KEY_HASH_WIDTH-i)*WORD_WIDTH)-1 downto (KEY_HASH_WIDTH-1-i)*WORD_WIDTH) := input(i); + end loop; + return ret; + end function; + begin sample_ram_inst : entity work.single_port_ram(arch) @@ -284,10 +369,11 @@ begin 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'); + variable tmp_bool : boolean := FALSE; begin -- Default stage_next <= stage; - res_a <= UNDEFINED; + res_rtps <= UNDEFINED; sample_addr_next <= sample_addr; sample_write_data <= (others => '0'); sample_ren <= '0'; @@ -296,7 +382,7 @@ begin payload_write_data <= (others => '0'); payload_ren <= '0'; payload_wen <= '0'; - ready_in_a <= '0'; + ready_in_rtps <= '0'; newest_sample_next <= newest_sample; empty_payload_list_head_next <= empty_payload_list_head; empty_sample_list_head_next <= empty_sample_list_head; @@ -323,22 +409,61 @@ begin remove_oldest_sample_next <= remove_oldest_sample; remove_oldest_inst_sample_next <= remove_oldest_inst_sample; added_new_instance_next <= added_new_instance; + si_sample_state_sig_next <= si_sample_state; + si_view_state_sig_next <= si_view_state_sig; + si_instance_state_sig_next <= si_instance_state_sig; + si_source_timestamp_sig_next <= si_source_timestamp_sig; + si_instance_handle_sig_next <= si_instance_handle_sig; + si_publication_handle_sig_next <= si_publication_handle_sig; + si_disposed_generation_count_sig_next <= si_disposed_generation_count_sig; + si_no_writers_generation_count_sig_next <= si_no_writers_generation_count_sig; + si_sample_rank_sig_next <= si_sample_rank_sig; + si_generation_rank_sig_next <= si_generation_rank_sig; + si_absolute_generation_count_sig_next <= si_absolute_generation_count_sig; + si_valid_data_sig_next <= si_valid_data_sig; + si_valid_sig_next <= si_valid_sig_next; + sample_state_next <= sample_state; + view_state_next <= view_state; + instance_state_next <= instance_state; + instance_handle_next <= instance_handle; + max_samples_next <= max_samples; + inst_addr_latch_1_next <= inst_addr_latch_1; + inst_addr_latch_2_next <= inst_addr_latch_2; + collection_cnt_next <= collection_cnt; + collection_cnt_max_next <= collection_cnt_max; + collection_generation_rank_next <= collection_generation_rank; + cur_generation_rank_next <= cur_generation_rank; + is_take_next <= is_take; + has_lacthed_next <= has_latched; + single_instance_next <= single_instance; + single_sample_next <= single_sample; + unmark_instances_next <= unmark_instances; + is_first_instance_sample_next <= is_first_instance_sample; + dynamic_next_instance_next <= dynamic_next_instance; + ack_dds <= '0'; + inst_data_variant <= '0'; + done_dds <= '0'; + return_code_dds <= RETCODE_UNSUPPORTED; case (stage) is when IDLE => -- DEFAULT - ready_in_a <= '1'; + ready_in_rtps <= '1'; + + -- Reset remove_oldest_inst_sample_next <= '0'; remove_oldest_sample_next <= '0'; added_new_instance_next <= '0'; + is_take_next <= '0'; - if (start_a = '1') then - case (opcode_a) is + + if (start_rtps = '1') then + case (opcode_rtps) is when ADD_CHANGE => -- This Operation does not accept input at this time - ready_in_a <= '0'; + ready_in_rtps <= '0'; - res_a <= ACK; + res_rtps <= ACK; stage_next <= ADD_SAMPLE_INFO; cur_sample_next <= empty_sample_list_head; sample_addr_next <= empty_sample_list_head; @@ -346,34 +471,153 @@ begin end if; when REMOVE_WRITER => -- Input and Memory Gurad - if (valid_in_a = '1' and inst_op_done = '1') then + if (valid_in_rtps = '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; + writer_pos_next <= to_integer(unsigned(data_in_rtps)); + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_data_variant <= '0'; + stage_next <= REMOVE_WRITER; + res_rtps <= ACK; end if; when others => null; end case; - elsif (start_b = '1') then - -- TODO + elsif (unmark_instances = '1') then + -- Memory Operation Guard + if (inst_op_done = '1') then + inst_op_start <= '1'; + inst_opcode <= UNMARK_INTANCES; + unmark_instances_next <= '0'; + end if; + elsif (start_dds = '1') then + -- Latch Input Signals + sample_state_next <= sample_state_in; + view_state_next <= view_state_in; + instance_state_next <= instance_state; + max_samples_next <= unsigned(max_samples_in); + + -- Reset + single_instance_next <= '0'; + single_instance_next <= '0'; + collection_cnt_next <= 0; + collection_cnt_max_next <= 0; + is_first_instance_sample_next <= '1'; + si_sample_state_sig_next <= (others => '0'); + si_view_state_sig_next <= (others => '0'); + si_instance_state_sig_next <= (others => '0'); + si_source_timestamp_sig_next <= TIME_ZERO; + si_instance_handle_sig_next <= (others => (others => '0')); + si_publication_handle_sig_next <= (others => (others => '0')); + si_sample_rank_sig_next <= (others => '0'); + si_generation_rank_sig_next <= (others => '0'); + si_valid_data_sig_next <= '0'; + si_valid_sig_next <= '0'; + si_absolute_generation_count_sig_next <= (others => '0'); + si_disposed_generation_count_sig_next <= (others => '0'); + si_no_writers_generation_count_sig_next <= (others => '0'); + + case (opcode_dds) is + when READ => + ack_dds <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + cur_inst_next <= INSTANCE_MEMORY_MAX_ADDRESS; + stage_next <= GET_NEXT_SAMPLE; + cnt_next <= 0; + when TAKE => + is_take_next <= '1'; + ack_dds <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + cur_inst_next <= INSTANCE_MEMORY_MAX_ADDRESS; + stage_next <= GET_NEXT_SAMPLE; + cnt_next <= 0; + when READ_NEXT_SAMPLE => + ack_dds <= '1'; + single_sample_next <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + cur_inst_next <= INSTANCE_MEMORY_MAX_ADDRESS; + sample_state_next <= NOT_READ_SAMPLE_STATE; + view_state_next <= ANY_VIEW_STATE; + instance_state_next <= ALIVE_INSTANCE_STATE; + max_samples_next <= to_unsigned(1, max_samples'length); + stage_next <= GET_NEXT_SAMPLE; + cnt_next <= 0; + when TAKE_NEXT_SAMPLE => + ack_dds <= '1'; + is_take_next <= '1'; + single_sample_next <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + cur_inst_next <= INSTANCE_MEMORY_MAX_ADDRESS; + sample_state_next <= NOT_READ_SAMPLE_STATE; + view_state_next <= ANY_VIEW_STATE; + instance_state_next <= ALIVE_INSTANCE_STATE; + max_samples_next <= to_unsigned(1, max_samples'length); + stage_next <= GET_NEXT_SAMPLE; + cnt_next <= 0; + when READ_INSTANCE => + ack_dds <= '1'; + single_instance_next <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + key_hash_next <= instance_handle_in; + stage_next <= CHECK_INSTANCE; + cnt_next <= 0; + when TAKE_INSTANCE => + ack_dds <= '1'; + is_take_next <= '1'; + single_instance_next <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + key_hash_next <= instance_handle_in; + stage_next <= CHECK_INSTANCE; + cnt_next <= 0; + when READ_NEXT_INSTANCE => + ack_dds <= '1'; + single_instance_next <= '1'; + dynamic_next_instance_next <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + key_hash_next <= instance_handle_in; + stage_next <= FIND_NEXT_INSTANCE; + cnt_next <= 0; + when TAKE_NEXT_INSTANCE => + ack_dds <= '1'; + is_take_next <= '1'; + single_instance_next <= '1'; + dynamic_next_instance_next <= '1'; + cur_sample_next <= oldest_sample; + sample_addr_next <= oldest_sample + SMF_STATUS_INFO_OFFSET; + key_hash_next <= instance_handle_in; + stage_next <= FIND_NEXT_INSTANCE; + cnt_next <= 0; + when others => + ack_dds <= '1'; + stage_next <= UNKNOWN_OPERATION; + end case; end if; - + when UNKNOWN_OPERATION => + done_dds <= '1'; + return_code_dds <= RETCODE_UNSUPPORTED; + + -- DONE + stage_next <= IDLE; when ADD_SAMPLE_INFO => -- Precondition: sample_addr (empty_sample_list_head) - ready_in_a <= '1'; + ready_in_rtps <= '1'; -- Input Guard - if (valid_in_a = '1') then + if (valid_in_rtps = '1') then cnt_next <= cnt + 1; sample_addr_next <= sample_addr + 1; -- Write Through sample_wen <= '1'; - sample_write_data <= data_in_a; + sample_write_data <= data_in_rtps; case (cnt) is -- Status Info @@ -381,15 +625,15 @@ begin -- Initialize local status bits sample_write_data(READ_FLAG) <= '0'; -- Latch Status Info - sample_status_info_next <= data_in_a; + sample_status_info_next <= data_in_rtps; sample_status_info_next(READ_FLAG) <= '0'; -- Latch Timestamp for ordering -- Timestamp 1/2 when 1 => - ts_latch_next(0) <= data_in_a; + ts_latch_next(0) <= data_in_rtps; -- Timestamp 2/2 when 2 => - ts_latch_next(1) <= data_in_a; + ts_latch_next(1) <= data_in_rtps; -- Lifespan Deadline 2/2 when 4 => -- Skip Key Hash, if not available @@ -402,28 +646,28 @@ begin -- 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_next(0) <= data_in_rtps; -- 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_next(1) <= data_in_rtps; -- 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_next(2) <= data_in_rtps; -- 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; + key_hash_next(3) <= data_in_rtps; when 9 => -- Latch Input, but do not pass to Memory - writer_pos_next <= to_integer(unsigned(data_in_a)); + writer_pos_next <= to_integer(unsigned(data_in_rtps)); sample_wen <= '0'; sample_addr_next <= sample_addr; -- Keep Addr (Payload Addr) stage_next <= ADD_PAYLOAD_ADDRESS; @@ -467,30 +711,30 @@ begin -- 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; + ready_in_rtps <= khg_ready_in; else - ready_in_a <= '1'; + ready_in_rtps <= '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 + if ((valid_in_rtps = '1' and has_key_hash = '0') or (valid_in_rtps = '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_write_data <= data_in_rtps; payload_wen <= '1'; end if; -- Key Hash Generator Write if (has_key_hash = '0') then - khg_data_in <= data_in_a; + khg_data_in <= data_in_rtps; khg_valid_in <= '1'; end if; -- End of Payload - if (last_word_in_a = '1') then + if (last_word_in_rtps = '1') then if (has_key_hash = '0') then khg_last_word_in <= '1'; stage_next <= GET_KEY_HASH; @@ -547,8 +791,9 @@ begin when INITIATE_INSTANCE_SEARCH => -- Memory Operation Guard if (inst_op_done = '1') then - inst_opcode <= SEARCH_INSTANCE_HASH; - inst_op_start <= '1'; + inst_opcode <= SEARCH_INSTANCE_HASH; + inst_op_start <= '1'; + inst_data_variant <= '0'; -- Payload not yet stored if (has_data = '1') then @@ -574,35 +819,35 @@ begin -- TIME_BASED_FILTER QOS if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and time <= inst_data.ignore_deadline) then -- Drop Change - res_a <= ACCEPTED; + res_rtps <= 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; + res_rtps <= REJECTED; stage_next <= IDLE; else -- Accept Change (Remove Oldest Instance Sample) remove_oldest_inst_sample_next <= '1'; - res_a <= ACCEPTED; + res_rtps <= ACCEPTED; stage_next <= UPDATE_INSTANCE; end if; -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) elsif (empty_sample_list_head = empty_sample_list_tail) then if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS and RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then -- Reject Change - res_a <= REJECTED; + res_rtps <= REJECTED; stage_next <= IDLE; else -- Accept Change (Remove Oldest Sample) remove_oldest_sample_next <= '1'; - res_a <= ACCEPTED; + res_rtps <= ACCEPTED; stage_next <= UPDATE_INSTANCE; end if; else -- Accept Change - res_a <= ACCEPTED; + res_rtps <= ACCEPTED; stage_next <= UPDATE_INSTANCE; end if; else @@ -613,18 +858,18 @@ begin -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then -- Reject Change - res_a <= REJECTED; + res_rtps <= 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; + res_rtps <= REJECTED; stage_next <= IDLE; else -- Accept Change (Remove Oldest Sample) remove_oldest_sample_next <= '1'; - res_a <= ACCEPTED; + res_rtps <= 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 @@ -649,7 +894,7 @@ begin end if; else -- Accept Change - res_a <= ACCEPTED; + res_rtps <= 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 @@ -684,7 +929,10 @@ begin 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_update <= NOT_ALIVE_DISPOSED; + status_info_update <= inst_data.status; + status_info_update(NOT_ALIVE_DISPOSED_FLAG) <= '1'; + status_info_update(NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; + status_info_update(LIVELINESS_FLAG) <= '1'; end if; -- WRITER BITMAP -- Convert Writer Bitmap to SLV @@ -709,13 +957,20 @@ begin 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_update <= NOT_ALIVE_NO_WRITERS; + status_info_update <= inst_data.status; + status_info_update(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + status_info_update(NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; + status_info_update(LIVELINESS_FLAG) <= '1'; end if; -- Instance ALIVE/FILTERED else -- STATUS INFO tmp_update <= tmp_update or STATUS_FLAG; - instance_state_update <= ALIVE; + status_info_update <= inst_data.status; + status_info_update(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + status_info_update(NOT_ALIVE_NO_WRITERS_FLAG) <= '0'; + status_info_update(LIVELINESS_FLAG) <= '1'; + -- GENERATION COUNTERS -- NOT_ALIVE_DISPOSED -> ALIVE Transition @@ -817,7 +1072,7 @@ begin when 2 => -- First Sample if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then - stage_next <= FINALIZE_SAMPLE_INFO; + stage_next <= FINALIZE_SAMPLE; 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; @@ -893,7 +1148,7 @@ begin 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; + stage_next <= FINALIZE_SAMPLE; sample_addr_next <= empty_sample_list_head + SMF_PREV_ADDR_OFFSET; -- Prev Addr of New Sample cnt_next <= 0; else @@ -907,13 +1162,13 @@ begin sample_write_data <= empty_sample_list_head; sample_wen <= '1'; - stage_next <= FINALIZE_SAMPLE_INFO; + stage_next <= FINALIZE_SAMPLE; 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 => + when FINALIZE_SAMPLE => -- Precondition: prev_sample set, next_sample set, sample_addr (Prev Addr of new sample) cnt_next <= cnt + 1; @@ -946,8 +1201,9 @@ begin 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; + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_data_variant <= '0'; stage_next <= REMOVE_STALE_INSTANCE; else @@ -973,8 +1229,12 @@ begin when 0 => sample_ren <= '1'; when 1 => + -- NOTE: We have to initiate an instance "search" despite having direct access to the instance + -- in order to set up the 'previous' instance pointer required by the removal procedure + -- (Since we do not store previous pointers in the memory frame format) inst_op_start <= '1'; inst_opcode <= SEARCH_INSTANCE_ADDR; + inst_data_variant <= '0'; inst_addr_update <= sample_read_data; cur_sample_next <= oldest_sample; @@ -1011,7 +1271,7 @@ begin null; end case; when REMOVE_SAMPLE => - -- Precondition: cur_sample set, sample_addr (Previous Address of cur_sample) + -- Precondition: cur_sample set, sample_addr (Previous Pointer of cur_sample) -- Wait for Instance Search to finish if (inst_op_done = '1') then @@ -1022,11 +1282,11 @@ begin when 0 => sample_ren <= '1'; sample_addr_next <= cur_sample + 1; -- Next Addr - -- Previous Addr (Current Sample) + -- Previous Pointer (Current Sample) when 1 => sample_ren <= '1'; prev_sample_next <= sample_read_data; - -- Next Addr (Current Sample) + -- Next Pointer (Current Sample) when 2 => next_sample_next <= sample_read_data; @@ -1162,32 +1422,35 @@ begin 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; + + if (is_take = '1') then + -- Continue Processing + stage_next <= GET_NEXT_SAMPLE; + cnt_next <= 0; + else + -- DONE + stage_next <= IDLE; + end if; end if; when SKIP_ADD => case (cnt) is -- SKIP READ when 0 => - ready_in_a <= '1'; + ready_in_rtps <= '1'; -- Wait until last word from input - if (last_word_in_a = '1') then + if (last_word_in_rtps = '1') then cnt_next <= 1; end if; -- REJECT SAMPLE when 1 => - res_a <= REJECTED; + res_rtps <= REJECTED; stage_next <= IDLE; when others => null; @@ -1213,8 +1476,11 @@ begin -- No More Writers for Instance if (tmp_bitmap = (tmp_bitmap'range => '0')) then + status_info_update <= inst_data.status; + status_info_update(NOT_ALIVE_DISPOSED_FLAG) <= '0'; + status_info_update(NOT_ALIVE_NO_WRITERS_FLAG) <= '1'; + status_info_update(LIVELINESS_FLAG) <= '1'; inst_op_start <= '1'; - instance_state_update <= NOT_ALIVE_NO_WRITERS; inst_opcode <= UPDATE_INSTANCE; update_inst_flags <= STATUS_FLAG or WRITER_BITMAP_FLAG; else @@ -1229,9 +1495,10 @@ begin 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; + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_data_variant <= '0'; + stage_next <= REMOVE_WRITER; end if; when REMOVE_STALE_INSTANCE => -- Wait for Instance Data @@ -1254,11 +1521,818 @@ begin stage_next <= IDLE; else -- Continue Search - inst_op_start <= '1'; - inst_opcode <= GET_NEXT_INSTANCE; + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_data_variant <= '0'; end if; end if; end if; + when GET_NEXT_SAMPLE => + -- Precondition: cur_sample set, sample_addr (Status Info of cur_sample), cur_inst set, si_sample_rank_sig set + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_addr_next <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_ren <= '1'; + -- Status Info + when 1 => + sample_addr_next <= cur_sample + SMF_TIMESTAMP_OFFSET; + sample_ren <= '1'; + + -- Latch Sample Status Info + sample_status_info_next <= sample_read_data; + + -- Check Sample State + case (sample_state) is + when READ_SAMPLE_STATE => + if (sample_read_data(READ_FLAG) /= '1') then + -- Sample not in collection, Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 13; + end if; + when NOT_READ_SAMPLE_STATE => + if (sample_read_data(READ_FLAG) /= '0') then + -- Sample not in collection, Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 13; + end if; + when ANY_SAMPLE_STATE => + null; + -- Uknown Sample State + when others => + -- Sample not in collection, Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 13; + end case; + + if (sample_read_data(READ_FLAG) = '1') then + si_sample_state_sig_next <= READ_SAMPLE_STATE; + else + si_sample_state_sig_next <= NOT_READ_SAMPLE_STATE; + end if; + -- Instance Pointer + when 2 => + -- Instance pre-selected + if (cur_inst /= INSTANCE_MEMORY_MAX_ADDRESS) then + -- Sample has different Instance + if (cur_inst /= sample_read_data) then + -- Consecutive Instance Sample Order + if (not ORDERED_ACCESS or PRESENTATION_QOS = INSTANCE_PRESENTATION_QOS) then + -- Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 13; + else + -- Get Instance Data + next_inst_next <= sample_read_data; + end if; + else + -- Select Sample + collection_cnt_next <= collection_cnt + 1; + first_sample_next <= cur_sample; + + -- First Instance Sample + -- NOTE: This state only enters with a sample rank of 0 and cur_inst set, when the + -- first sample of the instance has not yet been selected + if (si_sample_rank_sig = 0) then + -- Reset + collection_cnt_max_next <= collection_cnt + 1; + else + si_sample_rank_sig <= si_sample_rank_sig - 1; + end if; + + sample_addr_next <= sample_addr + 1; -- Timestamp 2/2 + sample_ren <= '1'; + cnt_next <= 5; -- Skip Instance Operation + end if; + else + -- Get Instance Data + next_inst_next <= sample_read_data; + end if; + -- Get Instance + when 3 => + -- Memory Operation Guard + if (inst_op_done = '1') then + inst_op_start <= '1'; + inst_opcode <= GET_INSTANCE; + inst_data_variant <= '1'; + inst_addr_update <= next_inst; + else + cnt_next <= cnt; -- Keep sub-state + end if; + -- Check Instance Data + when 4 => + -- Wait for Instance Data + if (inst_op_done = '1') then + sample_addr_next <= sample_addr + 1; -- Timestamp 2/2 + sample_ren <= '1'; + -- DEFAULT + tmp_bool := TRUE; + + -- Check Instance State + case (instance_state) is + when ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1' or inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_DISPOSED_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when ANY_INSTANCE_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Check View State + case (view_state) is + when NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when ANY_VIEW_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Check Instance Mark + if (inst_data.status_info(MARK_FLAG) = '1') then + -- Skip Marked Instance + tmp_bool := FALSE; + end if; + + -- Instance Passes Checks + if (tmp_bool) then + -- Select Sample + collection_cnt_next <= collection_cnt + 1; + collection_cnt_max_next <= collection_cnt + 1; + si_sample_rank_sig <= (others => '0'); + cur_inst_next <= next_inst; + first_sample_next <= cur_sample; + else + -- Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 13; + end if; + else + cnt_next <= cnt; -- Keep sub-state + end if; + -- Timestamp 1/2 + when 5 => + sample_addr_next <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + sample_ren <= '1'; + + si_source_timestamp_sig_next(0) <= sample_read_data; + -- Timestamp 2/2 + when 6 => + sample_addr_next <= cur_sample + SMF_DISPOSED_GEN_CNT_OFFSET; + sample_ren <= '1'; + + si_source_timestamp_sig_next(1) <= sample_read_data; + -- Payload Pointer + when 10 => + sample_addr_next <= cur_sample + SMF_NO_WRITERS_GEN_CNT_OFFSET; + sample_ren <= '1'; + + -- Latch Payload Address + cur_payload_next <= sample_read_data; + -- Disposed Generation Count + when 11 => + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_ren <= '1'; + + si_disposed_generation_count_sig_next <= sample_read_data; + -- No Writers Generation Count + when 12 => + sample_ren <= '1'; + + si_no_writers_generation_count_sig_next <= sample_read_data; + cur_generation_rank_next <= si_disposed_generation_count_sig + sample_read_data; + -- Calculate highest collection generation rank + collection_generation_rank_next <= si_disposed_generation_count_sig + sample_read_data; + + cnt_next <= 14; -- Skip Preload + -- Preload + when 13 => + sample_ren <= '1'; + -- Next Pointer + when 14 => + -- Reached End of Samples + if (sample_read_data = SAMPLE_MEMORY_MAX_ADDRESS) then + -- Exit Condition (Sample Selected) + if (first_sample = cur_sample) then + stage_next <= FINALIZE_SAMPLE_INFO; + cnt_next <= 0; + else + -- Collection Empty + if (collection_cnt = 0) then + -- READ_NEXT_INSTANCE/TAKE_NEXT_INSTANCE Operation + if (dynamic_next_instance = '1') then + -- NOTE: We selected a compatible instance, but the instance has no compatible samples. + -- Find next compatible instance. + stage_next <= FIND_NEXT_INSTANCE; + cnt_next <= 1; + else + done_dds <= '1'; + return_code_dds <= RETCODE_NO_DATA; + stage_next <= IDLE; + end if; + else + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + stage_next <= IDLE; + end if; + end if; + else + -- Next Sample + cur_sample_next <= sample_read_data; + sample_addr_next <= sample_read_data + SMF_STATUS_INFO_OFFSET; + cnt_next <= 0; + + -- Exit Condition (Sample Selected) + if (first_sample = cur_sample) then + -- Pre-Calculation already done for selected Instance + if (si_sample_rank_sig /= 0) then + stage_next <= FINALIZE_SAMPLE_INFO; + cnt_next <= 0; + else + -- Latch Next Sample (For resume purposes) + next_sample_next <= sample_read_data; + -- Calculate Instance Sample Ranks + stage_next <= PRE_CALCULATE; + end if; + end if; + end if; + when others => + null; + end case; + when PRE_CALCULATE => + -- Precondition: cur_sample set, sample_addr_next (Status Info of cur_sample) + + cnt_next <= cnt + 1; + + case (cnt) is + -- Preload + when 0 => + sample_addr_next <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_ren <= '1'; + + -- Exit Condition (Reached Collection Limit) + if (collection_cnt_max = max_samples) then + stage_next <= FINALIZE_SAMPLE_INFO; + cnt_next <= 0; + end if; + -- Status Info + when 1 => + sample_addr_next <= cur_sample + SMF_DISPOSED_GEN_CNT_OFFSET; + sample_ren <= '1'; + + -- Check Sample State + case (sample_state) is + when READ_SAMPLE_STATE => + if (sample_read_data(READ_FLAG) /= '1') then + -- Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 7; + end if; + when NOT_READ_SAMPLE_STATE => + if (sample_read_data(READ_FLAG) /= '0') then + -- Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 7; + end if; + when ANY_SAMPLE_STATE => + null; + -- Uknown Sample State + when others => + -- Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 7; + end case; + -- Instance Pointer + when 2 => + sample_addr_next <= cur_sample + SMF_NO_WRITERS_GEN_CNT_OFFSET; + sample_ren <= '1'; + + -- Same Instance + if (sample_read_data = cur_inst) then + -- Count Sample (No need to check Instance) + collection_cnt_max_next <= collection_cnt_max + 1; + si_sample_rank_sig_next <= si_sample_rank_sig + 1; + else + -- Consecutive Instance Sample Order + if (not ORDERED_ACCESS or PRESENTATION_QOS = INSTANCE_PRESENTATION_QOS or single_instance = '1') then + -- Skip Sample + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 7; + else + -- Check New Instance + next_inst_next <= sample_read_data; + cnt_next <= 5; + end if; + end if; + -- Disposed Generation Count + when 3 => + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_ren <= '1'; + + -- Calculate highest collection generation rank + collection_generation_rank_next <= sample_read_data; + -- No Writers Generation Count + when 4 => + sample_ren <= '1'; + + -- Calculate highest collection generation rank + collection_generation_rank_next <= collection_generation_rank + sample_read_data; + + cnt_next <= 8; + -- Initiate Get Memory Operation + when 5 => + -- Memory Operation Guard + if (inst_op_done = '1') then + inst_op_start <= '1'; + inst_opcode <= GET_INSTANCE_DATA_2; + inst_data_variant <= '1'; + inst_addr_update <= next_inst; + else + cnt_next <= cnt; -- Keep State + end if; + -- State Check + when 6 => + -- Wait for Instance Data + if (inst_op_done = '1') then + -- DEFAULT + tmp_bool := TRUE; + + -- Check Instance State + case (instance_state) is + when ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1' or inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_DISPOSED_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when ANY_INSTANCE_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Check View State + case (view_state) is + when NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when ANY_VIEW_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Check Instance Mark + if (inst_data.status_info(MARK_FLAG) = '1') then + -- Skip Marked Instance + tmp_bool := FALSE; + end if; + + -- Instance passes Checks + if (tmp_bool) then + -- Count Sample + collection_cnt_max_next <= collection_cnt_max + 1; + end if; + -- Done + sample_addr_next <= cur_sample + SMF_NEXT_ADDR_OFFSET; + cnt_next <= 7; + else + cnt_next <= cnt; -- Keep sub-state + end if; + -- Preload + when 7 => + sample_ren <= '1'; + -- Next Pointer + when 8 => + -- Exit Condition (Reached End of Samples) + if (sample_read_data = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= FINALIZE_SAMPLE_INFO; + cnt_next <= 0; + else + -- Continue with next Sample + cur_sample_next <= sample_read_data; + sample_addr_next <= sample_read_data + SMF_STATUS_INFO_OFFSET; + cnt_next <= 0; + end if; + when others => + null; + end case; + when FINALIZE_SAMPLE_INFO => + -- Precondition: cur_inst set + + case (cnt) is + -- Finalize Sample Info Data + when 0 => + sample_addr_next <= first_sample + SMF_STATUS_INFO_OFFSET; + + -- Wait for Instance Data + if (inst_op_done = '1') then + -- Instance Data valid + if (inst_addr_base = cur_inst) then + -- Sample Info View State + if (inst_data.status_info(VIEW_FLAG) = '1') then + si_view_state_sig_next <= NEW_VIEW_STATE; + else + si_view_state_sig_next <= NOT_NEW_VIEW_STATE; + end if; + + -- Sample Info Instance State + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1') then + si_instance_state_sig_next <= NOT_ALIVE_DISPOSED_INSTANCE_STATE; + elsif (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then + si_instance_state_sig_next <= NOT_ALIVE_NO_WRITERS_INSTANCE_STATE; + else + si_instance_state_sig_next <= ALIVE_INSTANCE_STATE; + end if; + + -- Sample Info Instance Handle + si_instance_handle_sig_next <= inst_data.key_hash; + + -- Sample Info Generation Rank + si_generation_rank_sig_next <= collection_generation_rank - cur_generation_rank; + + -- Sample Info Absolut Generation Rank + -- XXX: Possible Worst Case Path (2 32-bit Operations in same clock) + si_generation_rank_sig_next <= (inst_data.disposed_gen_cnt + inst_data.no_writers_gen_cnt) - cur_generation_rank; + + -- Sample Info Valid Data + if (cur_payload /= PAYLOAD_MEMORY_MAX_ADDRESS) then + si_valid_data_sig_next <= '1'; + else + si_valid_data_sig_next <= '0'; + end if; + + si_valid_sig_next <= '1'; + cnt_next <= 1; + else + -- Get Instance Data + inst_op_start <= '1'; + inst_opcode <= GET_INSTANCE; + inst_data_variant <= '1'; + inst_addr_update <= cur_inst; + end if; + end if; + -- Present Data + when 1 => + -- Invalidate Data + si_valid_sig_next <= '0'; + + -- Sample not marked as Read + if (sample_status_info(READ_FLAG) /= '1') then + -- Mark Sample as Read + sample_write_data <= sample_status_info; + sample_write_data(READ_FLAG) <= '1'; + sample_wen <= '1'; + end if; + + -- Sample Data Request + if (get_data = '1') then + stage_next <= GET_PAYLOAD; + cnt_next <= 0; + payload_addr_next <= cur_payload; + else + cnt_next <= 2; + end if; + -- Post-Present Data + when 2 => + -- Memory Operation Guard + if (inst_op_done = '1') then + -- NOTE: If we have a presentation of consecutive same instance samples of multiple instances, we have to + -- mark the instances we have already handled, in order to prevent the GET_NEXT_SAMPLE state to + -- re-process them. + -- Last Sample of Instance in Collection + if (si_sample_rank_sig = 1) then + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + update_inst_flags <= STATUS_FLAG; + status_info_update <= inst_data.status_info; + + -- Consecutive Instance Sample Order of multiple Instances + if ((not ORDERED_ACCESS or PRESENTATION_QOS = INSTANCE_PRESENTATION_QOS) and single_instance = '0' and single_sample = '0') then + -- Completed Collection + if (collection_cnt = max_samples) then + -- Unmark Instances + unmark_instances_next <= '1'; + else + -- Mark Instance + status_info_update(MARK_FLAG) <= '1'; + end if; + end if; + + -- Instance is NOT_VIEWED and sample is from last generation of Instance + if (inst_data.status_info(VIEW_FLAG) = '0' and si_absolute_generation_count_sig = 0) then + -- Mark Instance as VIEWED + status_info_update(VIEW_FLAG) <= '1'; + end if; + end if; + + -- Collection Completed + if (collection_cnt = max_samples) then + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + is_take_next <= '0'; -- Return to IDLE from REMOVE + + if (is_take = '1') then + stage_next <= REMOVE_SAMPLE; + cur_sample_next <= first_sample; + sample_addr_next <= first_sample + SMF_PREV_ADDR_OFFSET; + else + -- DONE + stage_next <= IDLE; + end if; + else + cur_sample <= next_sample; + cnt_next <= 0; + + -- Reached End of Samples + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + is_take_next <= '0'; -- Return to IDLE from REMOVE + end if; + + -- cur_inst has no more samples in collection + if (si_sample_rank_sig = 0) then + -- Present only single Instance + if (single_instance = '1') then + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + is_take_next <= '0'; -- Return to IDLE from REMOVE + else + cur_inst_next <= INSTANCE_MEMORY_MAX_ADDRESS; + end if; + end if; + + if (is_take = '1') then + -- Remove Sample + stage_next <= REMOVE_SAMPLE; + cur_sample_next <= first_sample; + sample_addr_next <= first_sample + SMF_PREV_ADDR_OFFSET; + else + -- Continue Processing + stage_next <= GET_NEXT_SAMPLE; + end if; + end if; + end if; + when others => + null; + end case; + when GET_PAYLOAD => + -- Precondition: payload_addr (Beginning of cur_payload) + + case (cnt) is + -- Preload + when 0 => + payload_addr_next <= payload_addr + 1; + payload_ren <= '1'; + cnt_next <= cnt + 1; + -- Next Pointer + when 1 => + payload_addr_next <= payload_addr + 1; + payload_ren <= '1'; + cnt_next <= cnt + 1; + + next_payload_next <= payload_read_data; + -- Payload + when others => + if (ready_out_dds = '1') then + payload_addr_next <= payload_addr + 1; + payload_ren <= '1'; + cnt_next <= cnt + 1; + + valid_out_dds <= '1'; + if (has_latched = '0') then + data_out_dds <= payload_read_data; + else + -- Previously Latched + data_out_dds <= long_latch; + end if; + + -- Reset + has_lacthed_next <= '0'; + + -- End of Payload Frame + if (cnt = PAYLOAD_FRAME_SIZE) then + -- Last Payload Frame + if (next_payload = PAYLOAD_MEMORY_MAX_ADDRESS) then + last_word_out_dds <= '1'; + + stage_next <= FINALIZE_SAMPLE_INFO; + cnt_next <= 2; + else + -- Continue with next payload Slot + payload_addr_next <= next_payload; + cnt_next <= 0; + end if; + end if; + else + long_latch_next <= payload_read_data; + has_lacthed_next <= '1'; + end if; + + end case; + when FIND_NEXT_INSTANCE => + -- Wait for Instance Data + if (inst_op_done = '1') then + case (cnt) is + when 0 => + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_data_variant <= '1'; + cnt_next <= 2; + when 1 => + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_data_variant <= '1'; + cnt_next <= 2; + when 2 => + -- Instance Found + if (inst_addr_base /= SAMPLE_MEMORY_MAX_ADDRESS) then + -- DEFAULT + tmp_bool := TRUE; + + -- Check Instance Handle (Key Hash) + -- XXX: Posible Worst Case Path (128-bit Comparison) + if (to_unsigned(inst_data.key_hash) =< to_unsigned(key_hash)) then + tmp_bool := FALSE; + end if; + + -- Check Instance State + case (instance_state) is + when ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1' or inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_DISPOSED_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when ANY_INSTANCE_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Check View State + case (view_state) is + when NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when ANY_VIEW_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Instance Passes Checks + if (tmp_bool) then + cur_inst <= inst_addr_base; + stage_next <= GET_NEXT_SAMPLE; + else + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_data_variant <= '1'; + end if; + else + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_NO_DATA; + stage_next <= IDLE; + end if; + when others => + null; + end case; + end if; + when CHECK_INSTANCE => + -- Wait for Instance Data + if (inst_op_done = '1') then + case (cnt) is + when 0 => + inst_op_start <= '1'; + inst_opcode <= SEARCH_INSTANCE_HASH; + inst_data_variant <= '1'; + cnt_next <= 1; + when 1 => + -- Instance Found + if (inst_addr_base /= SAMPLE_MEMORY_MAX_ADDRESS) then + -- DEFAULT + tmp_bool := TRUE; + + -- Check Instance State + case (instance_state) is + when ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '1' or inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_DISPOSED_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_NO_WRITERS_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_ALIVE_INSTANCE_STATE => + if (inst_data.status_info(NOT_ALIVE_DISPOSED_FLAG) = '0' and inst_data.status_info(NOT_ALIVE_NO_WRITERS_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when ANY_INSTANCE_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Check View State + case (view_state) is + when NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '0') then + tmp_bool := FALSE; + end if; + when NOT_NEW_VIEW_STATE => + if (inst_data.status_info(VIEW_FLAG) = '1') then + tmp_bool := FALSE; + end if; + when ANY_VIEW_STATE => + null; + when others => + tmp_bool := FALSE; + end case; + + -- Instance Passes Checks + if (tmp_bool) then + -- Get Instance Samples + cur_inst <= inst_addr_base; + stage_next <= GET_NEXT_SAMPLE; + else + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_NO_DATA; + stage_next <= IDLE; + end if; + else + -- Given Instance does not exist + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_BAD_PARAMETER; + stage_next <= IDLE; + end if; + when others => + null; + end case; + end if; when others => null; end case; @@ -1293,8 +2367,9 @@ begin 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 <= ( + variant => inst_data_variant, key_hash => key_hash_next, - instance_state => instance_state_update, + status_info => status_info_update, sample_cnt => sample_cnt, gen_cnt => gen_cnt, deadline => deadline, @@ -1376,15 +2451,24 @@ begin 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; + if (inst_data_variant = '0') then + inst_stage_next <= GET_INSTANCE_DATA_1; + else + inst_stage_next <= GET_INSTANCE_DATA_2; + end if; 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; + -- No Instances avialable + if (inst_next_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + else + 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; + end if; when REMOVE_INSTANCE => assert (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) report "Request Removal on empty memory" severity FAILURE; @@ -1393,6 +2477,23 @@ begin inst_addr_next <= inst_occupied_head; inst_stage_next <= REMOVE_INSTANCE; inst_cnt_next <= 0; + when GET_INSTANCE => + inst_addr_base_next <= inst_addr_update; + inst_addr_next <= inst_addr_update + IMF_KEY_HASH_OFFSET; + if (inst_data_variant = '0') then + inst_stage_next <= GET_INSTANCE_DATA_1; + else + inst_stage_next <= GET_INSTANCE_DATA_2; + end if; + inst_cnt_next <= 0; + when UNMARK_INTANCES => + -- Empty Memory Guard + if (inst_occupied_head /= INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= inst_occupied_head; + inst_addr_next <= inst_occupied_head + IMF_NEXT_ADDR_OFFSET; + inst_stage_next <= UNMARK_INTANCES; + inst_cnt_next <= 0; + end if; when others => null; end case; @@ -1479,8 +2580,14 @@ begin -- Match else -- Fetch Instance Data - inst_stage_next <= GET_INSTANCE_DATA; - inst_cnt_next <= 1; -- No preload needed + if (inst_data_variant = '0') then + inst_stage_next <= GET_INSTANCE_DATA_1; + inst_cnt_next <= 1; -- No preload needed + else + inst_addr_next <= inst_addr_base + IMF_KEY_HASH_OFFSET; + inst_stage_next <= GET_INSTANCE_DATA_2; + inst_cnt_next <= 0; + end if; end if; when others => null; @@ -1492,22 +2599,29 @@ begin case (inst_cnt) is -- Preload when 0 => - inst_ren <= '1'; + 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 + if (inst_read_data = inst_latch_data.addr) then + -- Fetch Instance Data + if (inst_data_variant = '0') then + inst_addr_next <= inst_read_data + IMF_STATUS_INFO_OFFSET; + inst_stage_next <= GET_INSTANCE_DATA_1; + inst_cnt_next <= 0; + else + inst_addr_next <= inst_read_data + IMF_KEY_HASH_OFFSET; + inst_stage_next <= GET_INSTANCE_DATA_2; + -- TODO: Skip Preload? + inst_cnt_next <= 0; + end if; + -- No Match else -- Reached List Tail, No Match - if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + if (inst_read_data = INSTANCE_MEMORY_MAX_ADDRESS) then inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match -- DONE inst_stage_next <= IDLE; @@ -1530,11 +2644,61 @@ begin -- 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; + + -- Fetch Instance Data + if (inst_data_variant = '0') then + inst_addr_next <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_stage_next <= GET_INSTANCE_DATA_1; + inst_cnt_next <= 0; + else + inst_addr_next <= inst_addr_base + IMF_KEY_HASH_OFFSET; + inst_stage_next <= GET_INSTANCE_DATA_2; + -- TODO: Skip Preload? + inst_cnt_next <= 0; + end if; end case; - when GET_INSTANCE_DATA => + when GET_INSTANCE_DATA_2 => + -- 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; + -- Key Hash 1/4 + when 1 => + inst_data_next.key_hash(0) <= inst_read_data; + -- Key Hash 2/4 + when 2 => + inst_data_next.key_hash(1) <= inst_read_data; + -- Key Hash 3/4 + when 3 => + inst_data_next.key_hash(2) <= inst_read_data; + -- Key Hash 4/4 + when 4 => + inst_data_next.key_hash(3) <= inst_read_data; + -- Status Info + when 5 => + inst_data_next.status_info <= inst_read_data; + -- Sample Count + when 6 => + inst_data_next.sample_cnt <= inst_read_data; + -- Disposed Generation Count + when 7 => + inst_data_next.disposed_gen_cnt <= inst_read_data; + -- No Writers Generation Count + when 8 => + inst_data_next.no_writers_gen_cnt <= inst_read_data; + + -- DONE + inst_stage_next <= IDLE; + when others => + null; + end case; + when GET_INSTANCE_DATA_1 => -- Precondition: inst_addr (Status Info) inst_ren <= '1'; @@ -1614,7 +2778,7 @@ begin cnt_next <= 0; end if; -- BIGGER-THAN - elsif (inst_latch_data.key_hash /= inst_read_data) then + elsif (inst_latch_data.key_hash(0) /= inst_read_data) then -- Continue inst_prev_addr_base_next <= inst_addr_base; inst_addr_next <= inst_next_addr_base; @@ -1624,7 +2788,7 @@ begin -- Key Hash 2/4 when 3 => -- Found Position - if (inst_latch_data.key_hash < inst_read_data) then + if (inst_latch_data.key_hash(1) < inst_read_data) then inst_next_addr_base_next <= inst_addr_base; -- Occupied List Head if (inst_prev_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then @@ -1670,7 +2834,7 @@ begin cnt_next <= 0; end if; -- BIGGER-THAN - elsif (inst_latch_data.key_hash /= inst_read_data) then + elsif (inst_latch_data.key_hash(2) /= inst_read_data) then -- Continue inst_prev_addr_base_next <= inst_addr_base; inst_addr_next <= inst_next_addr_base; @@ -1806,22 +2970,9 @@ begin 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; + inst_wen <= '1'; + inst_write_data <= inst_latch_data.status_info; + inst_data_next.status_info <= inst_latch_data.status_info; if ((inst_latch_data.update_flags and SAMPLE_CNT_FLAG) = SAMPLE_CNT_FLAG) then inst_addr_next <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; @@ -1845,8 +2996,9 @@ begin end if; -- Sample Count when 1 => - inst_wen <= '1'; - inst_write_data <= inst_latch_data.sample_cnt; + inst_wen <= '1'; + inst_write_data <= inst_latch_data.sample_cnt; + inst_data_next.sample_cnt <= inst_latch_data.sample_cnt; if ((inst_latch_data.update_flags and DISPOSED_CNT_FLAG) = DISPOSED_CNT_FLAG) then inst_addr_next <= inst_addr_base + IMF_DISPOSED_GEN_CNT_OFFSET; @@ -1867,8 +3019,9 @@ begin end if; -- Disposed Generation Count when 2 => - inst_wen <= '1'; - inst_write_data <= inst_latch_data.gen_cnt; + inst_wen <= '1'; + inst_write_data <= inst_latch_data.gen_cnt; + inst_data_next.disposed_gen_cnt <= inst_latch_data.gen_cnt; -- NOTE: Both Generation Counters cannot be updated on the same update procedure if (TIME_BASED_FILTER_QOS /= DURATION_ZERO and (inst_latch_data.update_flags and IGNORE_DEADLINE_FLAG) = IGNORE_DEADLINE_FLAG) then @@ -1884,8 +3037,9 @@ begin end if; -- No Writers Generation Count when 3 => - inst_wen <= '1'; - inst_write_data <= inst_latch_data.gen_cnt; + inst_wen <= '1'; + inst_write_data <= inst_latch_data.gen_cnt; + inst_data_next.no_writers_gen_cnt <= 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; @@ -1901,14 +3055,16 @@ begin -- 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)); + inst_wen <= '1'; + inst_write_data <= std_logic_vector(inst_latch_data.ignore_deadline(0)); + inst_data_next.deadline <= 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)); + inst_wen <= '1'; + inst_write_data <= std_logic_vector(inst_latch_data.ignore_deadline(1)); + inst_data_next.deadline <= 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; @@ -1930,14 +3086,14 @@ begin when 0 => inst_ren <= '1'; inst_addr_next <= inst_prev_addr_base + IMF_NEXT_ADDR_OFFSET; - -- Next Instance (Previous Occupied Instance) + -- Next Pointer (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) + -- Next Pointer (Current Instance) when 2 => -- Fix Pointer inst_write_data <= inst_empty_head; @@ -1945,8 +3101,45 @@ begin -- Fix Empty List Head inst_empty_head_next <= inst_addr_base; + -- Reset + inst_data_next <= ZERO_INSTANCE_DATA; + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; + -- DONE - inst_stage_next <= IDLE; + inst_stage_next <= IDLE; + when others => + null; + end case; + when UNMARK_INTANCES => + -- Precondition: + + inst_cnt_next <= inst_cnt + 1; + + case (inst_cnt) is + -- Preload + when 0 => + inst_addr_next <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_ren <= '1'; + -- Next Pointer + when 1 => + inst_ren <= '1'; + + next_inst_next <= inst_read_data; + -- Instance Status Info + when 2 => + inst_write_data <= inst_read_data; + inst_write_data(MARK_FLAG) <= '0'; + inst_wen <= '1'; + + -- Reached End of Instances + if (next_inst = INSTANCE_MEMORY_MAX_ADDRESS) then + -- DONE + inst_stage_next <= IDLE; + else + inst_addr_base_next <= next_inst; + inst_addr_next <= next_inst + IMF_NEXT_ADDR_OFFSET; + inst_cnt_next <= 0; + end if; when others => null; end case; diff --git a/src/rtps_config_package.vhd b/src/rtps_config_package.vhd index ede84e9..81c8c35 100644 --- a/src/rtps_config_package.vhd +++ b/src/rtps_config_package.vhd @@ -53,6 +53,8 @@ package rtps_config_package is 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); + type VIEW_STATE_TYPE is (NEW_INSTANCE, NOT_NEW_INSTANCE); + type SAMPLE_STATE is (READ, NOT_READ); -- Sample Status Info Flags constant DISPOSED_FLAG : natural := 0; @@ -66,6 +68,7 @@ package rtps_config_package is constant NOT_ALIVE_NO_WRITERS_FLAG : natural := 1; constant LIVELINESS_FLAG : natural := 2; constant VIEW_FLAG : natural := 3; + constant MARK_FLAG : natural := 4; -- 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'); diff --git a/src/rtps_package.vhd b/src/rtps_package.vhd index 6baed3f..35a3043 100644 --- a/src/rtps_package.vhd +++ b/src/rtps_package.vhd @@ -49,6 +49,35 @@ package rtps_package is constant MAX_BITMAP_WIDTH : natural := 256; constant KEY_HASH_WIDTH : natural := 128; constant STATUS_INFO_WIDTH : natural := 32; + -- DDS + constant RETURN_CODE_WIDTH : natural := CDR_LONG_WIDTH; + constant STATUS_KIND_WIDTH : natural := CDR_LONG_WIDTH; + constant SAMPLE_STATE_KIND_WIDTH : natural := CDR_LONG_WIDTH; + constant VIEW_STATE_KIND_WIDTH : natural := CDR_LONG_WIDTH; + constant INSTANCE_STATE_KIND_WIDTH : natural := CDR_LONG_WIDTH; + constant QOS_POLICY_ID_WIDTH : natural := CDR_LONG_WIDTH; + constant MAX_SAMPLES_WIDTH : natural := CDR_LONG_WIDTH; + + constant DISPOSED_GENERATION_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant NO_WRITERS_GENERATION_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant SAMPLE_RANK_WIDTH : natural := CDR_LONG_WIDTH; + constant GENERATION_RANK_WIDTH : natural := CDR_LONG_WIDTH; + constant ABSOLUTE_GENERATION_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + + constant INCONSISTENT_TOPIC_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant SAMPLE_LOST_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant SAMPLE_REJECTED_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant LIVELINESS_LOST_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant LIVELINESS_CHANGED_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant OFFERED_DEADLINE_MISSED_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant OFFERED_INCOMPATIBLE_QOS_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant REQUESTED_INCOMPATIBLE_QOS_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant PUBLICATION_MATCHED_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + constant SUBSCRIPTION_MATCHED_STATUS_COUNT_WIDTH : natural := CDR_LONG_WIDTH; + + + -- *TYPES DEFINITION* -- Generic Types @@ -62,6 +91,9 @@ package rtps_package is type GUID_TYPE is array (0 to (GUID_WIDTH/WORD_WIDTH)-1) of std_logic_vector(WORD_WIDTH-1 downto 0); type BITMAP_TYPE is array (0 to (MAX_BITMAP_WIDTH/WORD_WIDTH)-1) of std_logic_vector(0 to WORD_WIDTH-1); type KEY_HASH_TYPE is array (0 to (KEY_HASH_WIDTH/WORD_WIDTH)-1) of std_logic_vector(WORD_WIDTH-1 downto 0); + -- DDS + subtype INSTANCE_HANDLE_TYPE is KEY_HASH_TYPE; + subtype PUBLICATION_HANDLE_TYPE is GUID_TYPE; -- Helper Function function gen_duration(s,ns : integer) return DURATION_TYPE; @@ -86,6 +118,86 @@ package rtps_package is 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)); + -- DDS + constant HANDLE_NIL : INSTANCE_HANDLE_TYPE := (others => (others => '0')); + + -- *RETURN CODES* (DDS) + constant RETCODE_OK : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(0,RETURN_CODE_WIDTH)); + constant RETCODE_ERROR : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(1,RETURN_CODE_WIDTH)); + constant RETCODE_UNSUPPORTED : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(2,RETURN_CODE_WIDTH)); + constant RETCODE_BAD_PARAMETER : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(3,RETURN_CODE_WIDTH)); + constant RETCODE_PRECONDITION_NOT_MET : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(4,RETURN_CODE_WIDTH)); + constant RETCODE_OUT_OF_RESOURCES : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(5,RETURN_CODE_WIDTH)); + constant RETCODE_NOT_ENABLED : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(6,RETURN_CODE_WIDTH)); + constant RETCODE_IMMUTABLE_POLICY : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(7,RETURN_CODE_WIDTH)); + constant RETCODE_INCONSISTENT_POLICY : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(8,RETURN_CODE_WIDTH)); + constant RETCODE_ALREADY_DELETED : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(9,RETURN_CODE_WIDTH)); + constant RETCODE_TIMEOUT : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(10,RETURN_CODE_WIDTH)); + constant RETCODE_NO_DATA : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(11,RETURN_CODE_WIDTH)); + constant RETCODE_ILLEGAL_OPERATION : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(12,RETURN_CODE_WIDTH)); + + -- *STATUS KIND* (DDS) + constant INCONSISTENT_TOPIC_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000001"; + constant OFFERED_DEADLINE_MISSED_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000002"; + constant REQUESTED_DEADLINE_MISSED_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000004"; + constant OFFERED_INCOMPATIBLE_QOS_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000020"; + constant REQUESTED_INCOMPATIBLE_QOS_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000040"; + constant SAMPLE_LOST_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000080"; + constant SAMPLE_REJECTED_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000100"; + constant DATA_ON_READERS_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000200"; + constant DATA_AVAILABLE_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000400"; + constant LIVELINESS_LOST_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00000800"; + constant LIVELINESS_CHANGED_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00001000"; + constant PUBLICATION_MATCHED_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00002000"; + constant SUBSCRIPTION_MATCHED_STATUS : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := x"00004000"; + + -- *SAMPLE STATE KIND* (DDS) + constant READ_SAMPLE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000001"; + constant NOT_READ_SAMPLE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000002"; + constant ANY_SAMPLE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"FFFFFFFF"; + + -- *VIEW STATE KIND* (DDS) + constant NEW_VIEW_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000001"; + constant NOT_NEW_VIEW_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000002"; + constant ANY_VIEW_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"FFFFFFFF"; + + -- *INSTANCE STATE KIND* (DDS) + constant ALIVE_INSTANCE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000001"; + constant NOT_ALIVE_DISPOSED_INSTANCE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000002"; + constant NOT_ALIVE_NO_WRITERS_INSTANCE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000004"; + constant NOT_ALIVE_INSTANCE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"00000006"; + constant ANY_INSTANCE_STATE : std_logic_vector(SAMPLE_STATE_KIND_WIDTH-1 downto 0) := x"FFFFFFFF"; + + -- *SAMPLE REJECTED STATUS KIND* (DDS) + constant NOT_REJECTED : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(0,CDR_ENUMERATION_WIDTH)); + constant REJECTED_BY_INSTANCES_LIMIT : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(1,CDR_ENUMERATION_WIDTH)); + constant REJECTED_BY_SAMPLES_LIMIT : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(2,CDR_ENUMERATION_WIDTH)); + constant REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(3,CDR_ENUMERATION_WIDTH)); + + -- *QOS POLICY ID* (DDS) + constant INVALID_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(0,QOS_POLICY_ID_WIDTH)); + constant USERDATA_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(1,QOS_POLICY_ID_WIDTH)); + constant DURABILITY_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(2,QOS_POLICY_ID_WIDTH)); + constant PRESENTATION_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(3,QOS_POLICY_ID_WIDTH)); + constant DEADLINE_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(4,QOS_POLICY_ID_WIDTH)); + constant LATENCYBUDGET_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(5,QOS_POLICY_ID_WIDTH)); + constant OWNERSHIP_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(6,QOS_POLICY_ID_WIDTH)); + constant OWNERSHIPSTRENGTH_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(7,QOS_POLICY_ID_WIDTH)); + constant LIVELINESS_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(8,QOS_POLICY_ID_WIDTH)); + constant TIMEBASEDFILTER_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(9,QOS_POLICY_ID_WIDTH)); + constant PARTITION_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(10,QOS_POLICY_ID_WIDTH)); + constant RELIABILITY_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(11,QOS_POLICY_ID_WIDTH)); + constant DESTINATIONORDER_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(12,QOS_POLICY_ID_WIDTH)); + constant HISTORY_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(13,QOS_POLICY_ID_WIDTH)); + constant RESOURCELIMITS_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(14,QOS_POLICY_ID_WIDTH)); + constant ENTITYFACTORY_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(15,QOS_POLICY_ID_WIDTH)); + constant WRITERDATALIFECYCLE_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(16,QOS_POLICY_ID_WIDTH)); + constant READERDATALIFECYCLE_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(17,QOS_POLICY_ID_WIDTH)); + constant TOPICDATA_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(18,QOS_POLICY_ID_WIDTH)); + constant GROUPDATA_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(19,QOS_POLICY_ID_WIDTH)); + constant TRANSPORTPRIORITY_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(20,QOS_POLICY_ID_WIDTH)); + constant LIFESPAN_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(21,QOS_POLICY_ID_WIDTH)); + constant DURABILITYSERVICE_QOS_POLICY_ID : std_logic_vector(QOS_POLICY_ID_WIDTH-1 downto 0) := std_logic_vector(to_unsigned(22,QOS_POLICY_ID_WIDTH)); -- *SUBMESSAGE IDs* constant SID_PAD : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"01";