diff --git a/src/REF.txt b/src/REF.txt index 09e112a..8c6eb5b 100644 --- a/src/REF.txt +++ b/src/REF.txt @@ -412,34 +412,6 @@ READER 10| NEXT_ADDRESS | +-------------------------------------------------------------+ -WRITER ------- - 31............24..............16..............8...............0 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-------------------------------------------------------------+ -00| STATUS_INFO | - +-------------------------------------------------------------+ -01| | - + TIMESTAMP + -02| | - +-------------------------------------------------------------+ -03| | - + LIFESPAN_DEADLINE + -04| | - +-------------------------------------------------------------+ -05| PAYLOAD_ADDRESS | - +-------------------------------------------------------------+ -06| INSTANCE_ADDRESS | - +-------------------------------------------------------------+ -07| | - ~ ACK_BITMAP ~ -**| | - +-------------------------------------------------------------+ -**| PREV_ADDRESS | - +-------------------------------------------------------------+ -**| NEXT_ADDRESS | - +-------------------------------------------------------------+ - STATUS INFO ----------- 31............24..............16..............8...............0 @@ -452,10 +424,56 @@ R...Sample has been Read P...Sample has associated Payload A...Associated Payload is aligned (Payload does extend until end of last Palyload Slot) K...Key Hash available +F...FilteredFlag (1:1 PID_STATUS_INFO Mapping) +U...UnregisteredFlag (1:1 PID_STATUS_INFO Mapping) +D...DisposedFlag (1:1 PID_STATUS_INFO Mapping) + +NOTE: The Key Hash Flag is actually only needed during the ADD_CACHE_CHANGE process. + Later on it is obsolete, since we always calculate the Key Hash. + +WRITER +------ + 31............24..............16..............8...............0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-------------------------------------------------------------+ +00| STATUS_INFO | + +-------------------------------------------------------------+ +01| | + + SEQ_NR + +02| | + +-------------------------------------------------------------+ +03| | + + TIMESTAMP + +04| | + +-------------------------------------------------------------+ +05| | + + LIFESPAN_DEADLINE + [only if LIFESPAN /= INFINITE] +06| | + +-------------------------------------------------------------+ +07| PAYLOAD_ADDRESS | + +-------------------------------------------------------------+ +08| INSTANCE_ADDRESS | + +-------------------------------------------------------------+ +09| PREV_ADDRESS | + +-------------------------------------------------------------+ +10| NEXT_ADDRESS | + +-------------------------------------------------------------+ + +STATUS INFO +----------- +31............24..............16..............8...............0 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++-+-+-+-------------------------------------------------+-+-+-+ +|R|P|A| UNUSED |F|U|D| ++-+-+-+-------------------------------------------------+-+-+-+ + +R...Sample has been ACKed +P...Sample has associated Payload +A...Associated Payload is aligned (Payload does extend until end of last Palyload Slot) +F...FilteredFlag (1:1 PID_STATUS_INFO Mapping) +U...UnregisteredFlag (1:1 PID_STATUS_INFO Mapping) +D...DisposedFlag (1:1 PID_STATUS_INFO Mapping) -F...FilteredFlag -U...UnregisteredFlag -D...DisposedFlag PAYLOAD MEMORY ============== @@ -536,6 +554,20 @@ READER **| | +-------------------------------------------------------------+ +STATUS INFO +----------- +31............24..............16..............8...............0 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++---------------------------------------------------+-+-+-+-+-+ +| UNUSED |M|V|L|W|D| ++---------------------------------------------------+-+-+-+-+-+ + +D...NOT_ALIVE_DISPOSED +W...NOT_ALIVE_NO_WRITERS +L...LIVELINESS FLAG +V...VIEW STATE +M...MARK + WRITER ------ 31............24..............16..............8...............0 @@ -563,16 +595,13 @@ STATUS INFO ----------- 31............24..............16..............8...............0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -+---------------------------------------------------+-+-+-+-+-+ -| UNUSED |M|V|L|W|D| -+---------------------------------------------------+-+-+-+-+-+ ++-------------------------------------------------------+-+-+-+ +| UNUSED |L|U|D| ++-------------------------------------------------------+-+-+-+ -D...NOT_ALIVE_DISPOSED -W...NOT_ALIVE_NO_WRITERS +D...DISPOSED +W...UNREGISTERED L...LIVELINESS FLAG -V...VIEW STATE -M...MARK - OUTPUT DATA =========== @@ -719,6 +748,11 @@ with a source timestamp earlier than the source timestamp of the last data deliv be dropped. This ordering therefore works best when system clocks are relatively synchronized among writing machines. +2.2.2.4.2.22 assert_liveliness (DDS) +NOTE: Writing data via the write operation on a DataWriter asserts liveliness on the DataWriter itself +and its DomainParticipant. Consequently the use of assert_liveliness is only needed if the application +is not writing data regularly. + INVALIDATION ============ diff --git a/src/TODO.txt b/src/TODO.txt index b990c2a..24783b4 100644 --- a/src/TODO.txt +++ b/src/TODO.txt @@ -63,6 +63,8 @@ * 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 + - opendds sends Payload Encapsulation with a Key Holder Object (As defined in XType 7.6.8) + - opensplice seems todo the same as opendds * 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 readers, not depending if they are VOLATILE or TRANSIENT_LOCAL. @@ -74,19 +76,27 @@ * Is a Writer that is Disposing a Instance also Unregistering that instance? (Currently only Unregistering removes the remote Writer) - No * Since Lifespan is a duration, there is an inherent difference in the expiration time between writer and reader. This in addition to the fact that the reader may use the Reception time for the expiration time calculation could lead to an actual expiration duration almost double in length (If sent right before expiring locally in the writer). +* The current implementation will sent a second unregister/dispose Sample, if the user does the unregister/dispose operation a second time. Should we handle that specially? -* Fast-RTPS doen not follow DDSI-RTPS Specification + + +* Fast-RTPS does not follow DDSI-RTPS Specification - Open Github Issue https://github.com/eProsima/Fast-RTPS/issues/1221 - Seems that Fast-RTPS is also not checking the Validity of Submessages according to Spec * DDSI-RTPS 2.3 ISSUES + - 8.2.2 The History Cache + The 'get_change()' operation depicted in 8.3 is not documented. - 8.2.2.4 get_seq_num_min 8.2.2.5 get_seq_num_max - This asume a history cache with duplicate-free sequence numbers, but because sequence number are generated per writer, and a reader can be matched with mutliple writers, we can get duplicate sequence numbers of different changes from different writers. + This asume a history cache with duplicate-free sequence numbers, but because sequence number are + generated per writer, and a reader can be matched with mutliple writers, we can get duplicate + sequence numbers of different changes from different writers. Ergo the functions are non-deterministic. - 8.3.7.7 InfoDestination - 'This message is sent from an RTPS Writer to an RTPS Reader to modify the GuidPrefix used to interpret the Reader entityIds appearing in the Submessages that follow it.' + 'This message is sent from an RTPS Writer to an RTPS Reader to modify the GuidPrefix used to + interpret the Reader entityIds appearing in the Submessages that follow it.' But state is changed as follows 'Receiver.destGuidPrefix = InfoDestination.guidPrefix'. Isn't Reader -> Writer also valid? Does it have a specific direction? - 9.4.5.3 Data Submessage @@ -101,9 +111,24 @@ 'This Submessage is invalid when the following is true: submessageLength in the Submessage header is too small' But if InvalidateFlag is set, Length can be Zero. Since the length is unsigned, there cannot be an invalid length. + - 8.4.7 RTPS Writer Reference Implementation + According to 8.2.2 the History Cache (HC) is the interface between RTPS nad DDS, and can be invoked + by both RTPS and DDS Entities. + 8.2.9 further states 'A DDS DataWriter, for example, passes data to its matching RTPS Writer through + the common HistoryCache.', implying that a DDS Writer adds changes directly to the HC, which is then + read by the RTPS writer and handled accordingly. This means that the DDS Writer is responsible for + assigning Sequence Numbers. + This goes against 8.4.7, which states that the RTPS Writer is adding the Cache Changes to the HC + and is responsible for assigning Sequence Numbers. - 8.7.2.2.1 DURABILITY 'While volatile and transient-local durability do not affect the RTPS protocol' But in case of Durability TRANSIENT_LOCAL the writer has to send historical Data. + - 8.7.2.2.3 LIVELINESS + 'If the Participant has any MANUAL_BY_PARTICIPANT Writers, implementations must check periodically + to see if write(), assert_liveliness(), dispose(), or unregister_instance() was called for any of + them.' + Elaborate if "any of them" does specify all Writers of the Participant, or only the Writers with + MANUAL_BY_PARTICIPANT Liveliness. - 8.7.3.2 Indicating to a Reader that a Sample has been filtered Text refs 8.3.7.2.2 for DataFlag, but shoudl also ref 8.7.4 for FilteredFlag - 9.4.5.1.2 Flags @@ -122,6 +147,7 @@ the ParticipantProxy::builtinEndpointQos is not included then the BuiltinParticipantMessageWriter shall treat the BuiltinParticipantMessageReader as if it is configured with RELIABLE_RELIABILITY_QOS. which means that the default value is 0. + * DDS 1.4 ISSUES - 2.2.3 Supported QoS @@ -236,6 +262,7 @@ DESIGN DECISIONS PROTOCOL UNCOMPLIANCE ===================== * Partition QoS +* Coherent Sets * Built-in Endpoint is NOT the same as a normal Endpoint -> No User access to Data * Known but unused Submessage IDs are treated as uknown @@ -243,6 +270,7 @@ PROTOCOL UNCOMPLIANCE * Inline QoS validated in Endpoint -> Cannot invalidate Rest of Message/Packet * RESOURCE_LIMITS applies also to "empty" samples (Samples with no valid data). +* Write/Dispose/Untergister Operation do not return (TIMEOUT). I.e. the MAX_BLOCKING_TIME is not used. RTPS ENDPOINT diff --git a/src/dds_writer.vhd b/src/dds_writer.vhd new file mode 100644 index 0000000..bc3f269 --- /dev/null +++ b/src/dds_writer.vhd @@ -0,0 +1,4228 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- TODO: Check if sample_cnt is always maintained (also with MAX_SAMPLES_PER_INSTANCE = LENGTH_UNLIMITED) + +entity dds_writer 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; + PRESENTATION_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_PRESENTATION_QOS; + DESTINATION_ORDER_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := DEFAULT_DESTINATION_ORDER_QOS; + COHERENT_ACCESS : boolean := DEFAULT_COHERENT_ACCESS; + ORDERED_ACCESS : boolean := DEFAULT_ORDERED_ACCESS; + WITH_KEY : boolean := FALSE; -- TODO: Default + LIFESPAN_QOS : DURATION_TYPE := DEFAULT_LIFESPAN_QOS; + LEASE_DURATION : DURATION_TYPE := DEFAULT_LEASE_DURATION; + ); + port ( + -- SYSTEM + clk : in std_logic; + reset : in std_logic; + time : in TIME_TYPE; + + -- TO RTPS ENDPOINT + start_rtps : in std_logic; + opcode_rtps : in HISTORY_CACHE_OPCODE_TYPE; + ack_rtps : out std_logic; + done_rtps : out std_logic; + ret_rtps : out HISTORY_CACHE_RESPOSNE_TYPE; + seq_nr_rtps : in SEQUENCENUMBER_TYPE; + get_data_rtps : in std_logic; + data_out_rtps : out std_logic_vector(WORD_WIDTH-1 downto 0); + valid_out_rtps : out std_logic; + ready_out_rtps : in std_logic; + last_word_out_rtps : out std_logic; + assert_liveliness : out std_logic; + data_available : out std_logic; + -- Cache Change + cc_instance_handle : out INSTANCE_HANDLE_TYPE; + cc_kind : out CACHE_CHANGE_KIND_TYPE; + cc_source_timestamp : out TIME_TYPE; + + -- FROM USER ENTITY + start_dds : in std_logic; + ack_dds : out std_logic; + opcode_dds : in HISTORY_CACHE_OPCODE_TYPE; + instance_handle_dds : in INSTANCE_HANDLE_TYPE; + source_ts_dds : in TIME_TYPE; + max_wait_dds : in DURATION_TYPE; + done_dds : out std_logic; + return_code_dds : out std_logic_vector(RETURN_CODE_WIDTH-1 downto 0); + ready_in_dds : out std_logic; + valid_in_dds : in std_logic; + data_in_dds : in std_logic_vector(WORD_WIDTH-1 downto 0); + last_word_in_dds : in 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; + + -- COMMUNICATION STATUS + status : out std_logic_vector(STATUS_KIND_WIDTH-1 downto 0); + ); +end entity; + +architecture arch of dds_writer is + + --*****CONSTANT DECLARATION***** + -- *SAMPLE MEMORY* + -- 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_FRAME_SIZE + 1; + + -- *PAYLOAD MEMORY* + -- 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* + -- 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'); + + -- *SAMPLE MEMORY FRAME FORMAT* + -- 4-Byte Word Offsets to Beginning of Respective Fields in the Endpoint Memory Frame + constant SMF_STATUS_INFO_OFFSET : natural := 0; + constant SMF_SEQ_NR_OFFSET : natural := 1; + constant SMF_TIMESTAMP_OFFSET : natural := 3; + constant SMF_LIFESPAN_DEADLINE_OFFSET : natural := 5; + constant SMF_PAYLOAD_ADDR_OFFSET : natural := (SMF_LIFESPAN_DEADLINE_OFFSET + 2) when (LIFESPAN_QOS /= DURATION_INFINITE) else (SMF_TIMESTAMP_OFFSET + 2); + constant SMF_INSTANCE_ADDR_OFFSET : natural := SMF_PAYLOAD_ADDR_OFFSET + 1; + constant SMF_PREV_ADDR_OFFSET : natural := SMF_INSTANCE_ADDR_OFFSET + 1; + constant SMF_NEXT_ADDR_OFFSET : natural := SMF_PREV_ADDR_OFFSET + 1; + + -- *PAYLOAD MEMORY FRAME FORMAT* + -- 4-Byte Word Offsets to Beginning of Respective Fields in the Endpoint Memory Frame + constant PMF_NEXT_ADDR_OFFSET : natural := 0; + constant PMF_PAYLOAD_OFFSET : natural := 1; + + -- *INSTANCE MEMORY FRAME OFFSET* + -- 4-Byte Word Offsets to Beginning of Respective Fields in the Endpoint Memory Frame + 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_ACK_CNT_OFFSET : natural := 7; + + -- *INSTANCE MEMORY FRAME FORMAT FLAGS* + -- Flags mapping to the respective Endpoint Memory Frame Fields + constant IMF_FLAG_WIDTH : natural := 4; + constant IMF_KEY_HASH_FLAG : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (0 => 1, others => '0'); + constant IMF_STATUS_FLAG : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (1 => 1, others => '0'); + constant IMF_SAMPLE_CNT_FLAG : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (2 => 1, others => '0'); + constant IMF_ACK_CNT_FLAG : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (3 => 1, others => '0'); + + --*****TYPE DECLARATION***** + -- FSM states. Explained below in detail + type STAGE_TYPE is (IDLE, UNKNOWN_OPERATION_DDS, UNKNOWN_OPERATION_RTPS, UNKNOWN_SEQ_NR, ASSERT_LIVELINESS, ADD_SAMPLE_INFO, ADD_PAYLOAD, NEXT_PAYLOAD_SLOT, + ALIGN_PAYLOAD, GET_KEY_HASH, INITIATE_INSTANCE_SEARCH, REGISTER_OPERATION, LOOKUP_OPERATION, PUSH_KEY_HASH, FILTER_STAGE, UPDATE_INSTANCE, + FINALIZE_PAYLOAD, FIX_POINTERS, FINALIZE_SAMPLE, GET_OLDEST_SAMPLE_INSTANCE, FIND_OLDEST_INST_SAMPLE, REMOVE_SAMPLE, POST_SAMPLE_REMOVE, SKIP_ADD_REJECT, + REMOVE_STALE_INSTANCE, GET_SEQ_NR, FIND_SEQ_NR, ACKNACK_SAMPLE, GET_SAMPLE, GET_PAYLOAD, GET_SERIALIZED_KEY, CHECK_LIFESPAN, GET_LIVELINESS_LOST_STATUS, + GET_OFFERED_DEADLINE_MISSED_STATUS, CHECK_DEADLINE, RESET_SAMPLE_MEMORY, RESET_PAYLOAD_MEMORY); + -- Instance Memory FSM states. Explained below in detail + type INST_STAGE_TYPE is (IDLE, SEARCH_INSTANCE_HASH, SEARCH_INSTANCE_ADDR, GET_NEXT_INSTANCE, GET_INSTANCE_DATA, FIND_POS, INSERT_INSTANCE, UPDATE_INSTANCE, + REMOVE_INSTANCE); + -- *Instance Memory Opcodes* + -- OPCODE DESCRIPTION + -- SEARCH_INSTANCE_HASH Search Instance based on Key Hash pointed by key_hash. + -- SEARCH_INSTANCE_ADDR Search Instance based on Instance Pointer pointed by inst_addr_update. [This is needed to mark the previous Instance for Instance Removal] + -- INSERT_INSTANCE Insert Instance to memory. The Instance is inserted in Key Hash Numerical Order. + -- UPDATE_INSTANCE Update Instance Data pointed by inst_addr_base. (inst_mem_fields specifies which Fields to update) + -- GET_FIRST_INSTANCE Get Instance Data of first Instance (Instance with smallest Key Hash Numerical Order). (inst_mem_fields specifies which Fields to get) + -- GET_NEXT_INSTANCE Get Instance Data of next Instance (from the Instance pointed by inst_addr_base) (inst_mem_fields specifies which Fields to get) + -- REMOVE_INSTANCE Remove Instance pointed by inst_addr_base + -- GET_INSTANCE Get Data of Instance pointed by inst_addr_update. (inst_mem_fields specifies which Fields to get) + type INSTANCE_OPCODE_TYPE is (SEARCH_INSTANCE_HASH, SEARCH_INSTANCE_ADDR, INSERT_INSTANCE, UPDATE_INSTANCE, GET_FIRST_INSTANCE, GET_NEXT_INSTANCE, REMOVE_INSTANCE, + GET_INSTANCE); + -- Record of Instance Data + 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); + ack_cnt : unsigned(WORD_WIDTH-1 downto 0); + end record; + -- Zero initialized Endpoint Data + constant ZERO_INSTANCE_DATA : INSTANCE_DATA_TYPE := ( + key_hash => (others => (others => '0')), + status_info => (others => '0'), + sample_cnt => (others => '0'), + ack_cnt => (others => '0') + ); + -- Instance Data Latch used as temporal cache by Instance Memory FSM + type INST_LATCH_DATA_TYPE is record + key_hash : KEY_HASH_TYPE; + status_info : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); + sample_cnt : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); + ack_cnt : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); + field_flags : std_logic_vector(0 to IMF_FLAG_WIDTH-1); + addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); + end record; + -- Zero initialized Instance Data Latch + constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := ( + key_hash => (others => (others => '0')), + status_info => (others => '0'), + sample_cnt => (others => '0'), + ack_cnt => (others => '0'), + field_flags => (others => '0'), + addr => (others => '0') + ); + + --*****SIGNAL DECLARATION + -- *SAMPLE MEMORY CONNECTION SIGNALS* + signal sample_addr : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal sample_read : std_logic := '0'; + signal sample_read_data, sample_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal sample_ready_in, sample_valid_in : std_logic := '0'; + signal sample_ready_out, sample_valid_out : std_logic := '0'; + signal sample_abort_read : std_logic := '0'; + + -- *PAYLOAD MEMORY CONNECTION SIGNALS* + signal payload_addr : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal payload_read : std_logic := '0'; + signal payload_read_data, payload_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal payload_ready_in, payload_valid_in : std_logic := '0'; + signal payload_ready_out, payload_valid_out : std_logic := '0'; + signal payload_abort_read : std_logic := '0'; + + -- *INSTANCE MEMORY CONNECTION SIGNALS* + signal inst_addr : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal inst_read : std_logic := '0'; + signal inst_read_data, inst_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal inst_ready_in, inst_valid_in : std_logic := '0'; + signal inst_ready_out, inst_valid_out : std_logic := '0'; + signal inst_abort_read : std_logic := '0'; + + -- *KEY HASH GENERATOR CONNECTION SIGNALS* + 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 khg_abort : std_logic := '0'; + + -- *SERIALIZED KEY GENERATOR CONNECTION SIGNALS* + signal skg_valid_in, skg_ready_in, skg_last_word_in, skg_valid_out, skg_ready_out, skg_last_word_out : std_logic := '0'; + signal skg_data_in, skg_data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal skg_abort : std_logic := '0'; + + -- *MAIN PROCESS* + -- FSM state + signal stage, stage_next : STAGE_TYPE := IDLE; + -- FSM state latch. Used to transition dynamically to different states from the same state. + signal return_stage, return_stage_next : STAGE_TYPE := IDLE; + -- General Purpose Counter + signal cnt, cnt_next : natural range TODO := 0; + -- Counter used to read/write Payload Fames + signal cnt2, cnt2_next : natural range 0 to PAYLOAD_FRAME_SIZE := 0; + -- Counter used to read/write Payload Fames + signal cnt3, cnt3_next : natural range 0 to PAYLOAD_FRAME_SIZE := 0; + -- Head of Empty Sample List + signal empty_sample_list_head, empty_sample_list_head_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Tail of Empty Sample List + signal empty_sample_list_tail, empty_sample_list_tail_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Head of Empty Payload List + signal empty_payload_list_head, empty_payload_list_head_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Oldest Sample (Head of Occupied Sample List) + signal oldest_sample, oldest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Newest Sample (Tail of Occupied Sample List) + signal newest_sample, newest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Denotes if the oldest Sample should be removed + signal remove_oldest_sample, remove_oldest_sample_next : std_logic := '0'; + -- Denotes if the oldest sample of the Instance with 'key_hash' should be removed + signal remove_oldest_inst_sample, remove_oldest_inst_sample_next : std_logic := '0'; + -- Lifespan Latch + signal lifespan, lifespan_next : TIME_TYPE := TIME_INVALID; + -- Key hash Latch + signal key_hash, key_hash_next : KEY_HASH_TYPE := (others => (others => '0')); + -- Instance Handle Latch + signal instance_handle, instance_handle_next : INSTANCE_HANDLE_TYPE := (others => '0'); + -- Source Timestamp Latch + signal source_ts, source_ts_next : TIME_TYPE := TIME_INVALID; + -- Sequence Number Latch + signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; + -- Sample Status Info Latch + signal sample_status_info, sample_status_info_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Payload Pointer + signal payload_addr_latch_1, payload_addr_latch_1_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Payload Pointer + signal payload_addr_latch_2, payload_addr_latch_2_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Sample Pointer + signal sample_addr_latch_1, sample_addr_latch_1_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Sample Pointer + signal sample_addr_latch_2, sample_addr_latch_2_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Sample Pointer + signal sample_addr_latch_3, sample_addr_latch_3_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Sample Pointer + signal sample_addr_latch_4, sample_addr_latch_4_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Instance Pointer + signal inst_addr_latch_1, inst_addr_latch_1_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Instance Pointer + signal inst_addr_latch_2, inst_addr_latch_2_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- General Purpose Long Latch + signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + -- Signal used to pass Sample Status Infos to Instance Memory Process + signal status_info_update : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + -- Signal used to pass TIMEs to the Instance Memory Process + signal deadline : TIME_TYPE := TIME_INVALID; + -- Signal containing the relevant Instance Memory Frame Fields of the Instance Memory Operation + signal inst_mem_fields : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (others => '0'); + -- Signal used to pass Instance Pointers to the Instance Memory Process + signal inst_addr_update : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Signal used to pass Sample Counts to the Instance Memory Process + signal sample_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); + -- Signals start of Instance Memory Operation + signal inst_op_start : std_logic := '0'; + -- Opcode of Instance Memory Operation (Valid only when inst_op_start is high) + signal inst_opcode : INSTANCE_OPCODE_TYPE := NOP; + -- Signals the end of an Instance Memory Operation + signal inst_op_done : std_logic := '0'; + -- Time of next Sample Lifespan Check + signal lifespan_time, lifespan_time_next : TIME_TYPE := TIME_ZERO; + -- Signifies if a Lifespan Check is in progress + signal is_lifespan_check, is_lifespan_check_next : std_logic := '0'; + -- Signal used to generate the monotonically rising Sequence Numbers + -- It contains the next applicable Sequence Number + signal global_seq_nr, global_seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; + -- Signal containing the current number of stored samples + signal global_sample_cnt, global_sample_cnt_next : natural range TODO := 0; + -- Signal containing the current number of ACKed stored samples + signal global_ack_cnt, global_ack_cnt_next : natural range TODO := 0; + -- Signal containing the number of currently stale Instances + signal stale_inst_cnt, stale_inst_cnt_next : natural range 0 to MAX_INSTANCES := 0; + -- Signifies if a Instance Register Operation is in progress + signal register_op, register_op_next : std_logic := '0'; + -- Signifies if a Instance Lookup Operation is in progress + signal lookup_op, lookup_op_next : std_logic := '0'; + -- Signifies if a WAIT_FOR_ACKNOWLEDGEMENT Operation is in progress + signal ack_wait, ack_wait_next : std_logic := '0'; + -- Timout time for DDS Operation + signal timeout_time, timeout_time_next : TIME_TYPE := TIME_INVALID; + -- Signal used to differentiate between ACK and NACK Operations + signal is_ack, is_ack_next : std_logic := '0'; + -- Signal used to differentiate between RTPS and DDS Operations + signal is_rtps, is_rtps_next : std_logic := '0'; + -- Signifies if new Samples are available for RTPS Writer + signal data_available_sig, data_available_sig_next : std_logic := '0'; + -- Denotes if Orphan Samples (of an removed stale instance) need to be removed + signal orphan_samples, orphan_samples_next : std_logic := '0'; + + + -- *COMMUNICATION STATUS* + signal status_sig, status_sig_next : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := (others => '0'); + -- LIVELINESS LOST STATUS + -- Time of next Liveliness Deadline + signal lease_deadline, lease_deadline_next : TIME_TYPE := TIME_INVALID; + signal liveliness_lost_cnt, liveliness_lost_cnt_next : unsigned(LIVELINESS_LOST_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal liveliness_lost_cnt_change, liveliness_lost_cnt_change_next : unsigned(LIVELINESS_LOST_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0'); + -- SAMPLE REJECT STATUS + signal sample_rej_cnt, sample_rej_cnt_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal sample_rej_cnt_change, sample_rej_cnt_change_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal sample_rej_last_reason, sample_rej_last_reason_next : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := (others =>'0'); + signal sample_rej_last_inst, sample_rej_last_inst_next : INSTANCE_HANDLE_TYPE := (others => (others => '0')); + -- OFFERED DEADLINE MISSED STATUS + -- Time of next Deadline Miss Check + signal deadline_time, deadline_time_next : TIME_TYPE := TIME_ZERO; + signal deadline_miss_cnt, deadline_miss_cnt_next : unsigned(REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal deadline_miss_cnt_change, deadline_miss_cnt_change_next : unsigned(REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0'); + signal deadline_miss_last_inst, deadline_miss_last_inst_next : INSTANCE_HANDLE_TYPE := (others => (others => '0')); + + -- *CACHE CHANGE* + signal cc_instance_handle_sig, cc_instance_handle_sig_next : INSTANCE_HANDLE_TYPE := HANDLE_NIL; + signal cc_kind_sig, cc_kind_sig_next : CACHE_CHANGE_KIND_TYPE := ALIVE; + signal cc_source_timestamp_sig, cc_source_timestamp_sig_next : TIME_TYPE := TIME_INVALID; + + -- *INSTANCE MEMORY PROCESS* + -- Instance Memory FSM state + signal inst_stage, inst_stage_next : INST_STAGE_TYPE := IDLE; + -- Pointer to current relevant Instance Memory Frame Address + signal inst_addr_base, inst_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Pointer to next Instance Memory Frame Address + signal inst_next_addr_base, inst_next_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Pointer to previous Instacne Memory Address + signal inst_prev_addr_base, inst_prev_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Head of Empty Instance List + signal inst_empty_head, inst_empty_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Head of Occupied Instance List + signal inst_occupied_head, inst_occupied_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + -- Latch for Instance Data from main process + signal inst_latch_data, inst_latch_data_next : INST_LATCH_DATA_TYPE := ZERO_INST_LATCH_DATA; + -- Latch for Instance Data from memory + signal inst_data, inst_data_next : INSTANCE_DATA_TYPE := ZERO_INSTANCE_DATA; + -- General Purpose Counter + signal inst_cnt, inst_cnt_next : natural range TODO := 0; + -- Counter used to read/write the Writer Bitmap + signal inst_cnt2, inst_cnt2_next : natural 0 to ENDPOINT_BITMAP_ARRAY_TYPE'length := 0; + -- General Purpose Long Latch + 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 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; + alias cur_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3_next; + alias second_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_4; + alias second_sample_next: unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_4_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_2; + alias next_payload_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2_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 dead_inst : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) is inst_addr_latch_2; + alias dead_inst_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) is inst_addr_latch_2_next; + + -- *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 + + --*****COMPONENT INSTANTIATION***** + + sample_mem_ctrl_inst : entity work.mem_ctrl(arch) + generic map ( + ADDR_WIDTH => SAMPLE_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => SAMPLE_MEMORY_SIZE, + MAX_BURST_LENGTH => SAMPLE_FRAME_SIZE + ) + port map ( + clk => clk, + reset => reset or sample_abort_read, + addr => std_logic_vector(sample_addr), + read => sample_read, + ready_in => sample_ready_in, + valid_in => sample_valid_in, + data_in => sample_write_data, + ready_out => sample_ready_out, + valid_out => sample_valid_out, + data_out => sample_read_data + ); + + payload_mem_ctrl_inst : entity work.mem_ctrl(arch) + generic map ( + ADDR_WIDTH => PAYLOAD_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => PAYLOAD_MEMORY_SIZE, + MAX_BURST_LENGTH => PAYLOAD_FRAME_SIZE + ) + port map ( + clk => clk, + reset => reset or sample_abort_read, + addr => std_logic_vector(sample_addr), + read => payload_read, + ready_in => payload_ready_in, + valid_in => payload_valid_in, + data_in => payload_write_data, + ready_out => payload_ready_out, + valid_out => payload_valid_out, + data_out => payload_read_data + ); + + gen_instance_mem_ctrl_inst : if WITH_KEY generate + instance_mem_ctrl_inst : entity work.mem_ctrl(arch) + generic map ( + ADDR_WIDTH => INSTANCE_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => INSTANCE_MEMORY_SIZE, + MAX_BURST_LENGTH => INSTANCE_FRAME_SIZE + ) + port map ( + clk => clk, + reset => reset or sample_abort_read, + addr => std_logic_vector(sample_addr), + read => instance_read, + ready_in => instance_ready_in, + valid_in => instance_valid_in, + data_in => instance_write_data, + ready_out => instance_ready_out, + valid_out => instance_valid_out, + data_out => instance_read_data + ); + + key_hash_generator_inst : entity work.key_hash_generator(arch) + port ( + clk => clk, + reset => reset or khg_abort, + 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 + ); + + serialized_key_generator_inst : entity work.serialized_key_generator(arch) + port ( + clk => clk, + reset => reset or skg_abort, + data_in => skg_data_in, + valid_in => skg_valid_in, + ready_in => skg_ready_in, + last_word_in => skg_last_word_in, + data_out => skg_data_out, + valid_out => skg_valid_out, + ready_out => skg_ready_out, + last_word_out => skg_last_word_out + ); + + end generate; + + status <= status_sig; + data_available <= data_available_sig; + cc_instance_handle <= cc_instance_handle_sig; + cc_kind <= cc_kind_sig; + cc_source_timestamp <= cc_source_timestamp_sig; + + -- *Main State Machine* + -- STATE DESCRIPTION + -- IDLE Idle State. Initiates Deadline Miss Checks, Lifespan Expiry Checks, RTPS Operation handling, and DDS Operation handling, in that priority order. + -- UNKNOWN_OPERATION_DDS Dummy State for not supported/unknown DDS Operations + -- UNKNOWN_OPERATION_RTPS Dummy State for not supported/unknown RTPS Operations + -- UNKNOWN_SEQ_NR Dummy State for RTPS Operation with unknown Sequence Number + -- ASSERT_LIVELINESS Propagate Liveliness Assertion to RTPS + -- ADD_SAMPLE_INFO Latch and store Cache Change (pre-payload) + -- ADD_PAYLOAD Push payload to memory and key hash generator (as needed) + -- NEXT_PAYLOAD_SLOT Get pointer to next empty payload slot + -- ALIGN_PAYLOAD Store the offset of the actual payload in the last address of the last payload slot. + -- GET_KEY_HASH Fetch the calculated key hash from the Key Hash Generator + -- INITIATE_INSTANCE_SEARCH Initiate Instance Search Memory Operation. This state is used to start the Search operation as soon as the required data is available + -- REGISTER_OPERATION Insert new Instance into Memory, or Re-register an existing Unregistered Instance + -- LOOKUP_OPERATION Check Instance lookup results and return special value in case Instance was not found. + -- PUSH_KEY_HASH Push stored Instance Handle/Key hash to DDS output + -- FILTER_STAGE This state decides if the Cache Change is accepted, or rejected. It also decides what sample (if any) has to be removed. + -- UPDATE_INSTANCE Update the Data of the Instance of the received saample (Cache Change) + -- FINALIZE_PAYLOAD Finalize the payload addition (Update pointers). + -- FIX_POINTERS Update the List Pointers of the inserted Sample neighbours (First Step of Sample Addition Finalization) + -- FINALIZE_SAMPLE Update inserted sample and list pointers. (Second Step of Sample Addition Finalization) + -- GET_OLDEST_SAMPLE_INSTANCE Fetch the Instance Data of the oldest sample + -- FIND_OLDEST_INST_SAMPLE Find the oldest sample of a specific Instance + -- REMOVE_SAMPLE Remove sample and linked payload + -- POST_SAMPLE_REMOVE Update Instance Data of removed sample. If Instance Memory is full, and Instance is now eligible for removal, it is removed. + -- SKIP_ADD_REJECT Skip RTPS Cache Change and signal rejection to RTPS. + -- REMOVE_STALE_INSTANCE Find and remove the first eligible Instance in the memory + -- GET_SEQ_NR Push Sequence Number of specified Sample to RTPS output. + -- FIND_SEQ_NR Find Sample with specified Sequence Number. + -- ACKNACK_SAMPLE Acknowledge/Unacknowledge specied Sample + -- GET_SAMPLE Push Sample Data to RTPS output + -- GET_PAYLOAD Push linked Payload to output, or to the serialized key generator + -- GET_SERIALIZED_KEY Push serialized key to output + -- CHECK_LIFESPAN Check and remove samples with expired Lifespans + -- GET_LIVELINESS_LOST_STATUS Return Liveliness Loss Status + -- GET_OFFERED_DEADLINE_MISSED_STATUS Return Offered Deadline Missed Status + -- CHECK_DEADLINE Check and Mark Instances with missed Deadlines + -- RESET_SAMPLE_MEMORY Reset Sample Memory to Empty State + -- RESET_PAYLOAD_MEMORY Reset Payload Memory to Empty State + parse_a_prc : process (all) + variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0')); + variable tmp_bitmap : std_logic_vector(0 to ENDPOINT_BITMAP_WIDTH-1) := (others => '0'); + variable tmp_update : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (others => '0'); + variable tmp_bool : boolean := FALSE; + variable valid_out_tmp, last_word_out_tmp, ready_out_tmp : std_logic := '0'; + begin + -- DEFAULT Registered + stage_next <= stage; + 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; + long_latch_next <= long_latch; + sample_addr_latch_1_next <= sample_addr_latch_1; + sample_addr_latch_2_next <= sample_addr_latch_2; + sample_addr_latch_3_next <= sample_addr_latch_3; + sample_addr_latch_4_next <= sample_addr_latch_4; + inst_addr_latch_1_next <= inst_addr_latch_1; + inst_addr_latch_2_next <= inst_addr_latch_2; + sample_status_info_next <= sample_status_info; + remove_oldest_sample_next <= remove_oldest_sample; + remove_oldest_inst_sample_next <= remove_oldest_inst_sample; + added_new_instance_next <= added_new_instance; + instance_handle_next <= instance_handle; + is_first_instance_sample_next <= is_first_instance_sample; + sample_rej_cnt_next <= sample_rej_cnt; + sample_rej_cnt_change_next <= sample_rej_cnt_change; + sample_rej_last_reason_next <= sample_rej_last_reason; + sample_rej_last_inst_next <= sample_rej_last_inst; + deadline_time_next <= deadline_time; + deadline_miss_cnt_next <= deadline_miss_cnt; + deadline_miss_cnt_change_next <= deadline_miss_cnt_change; + deadline_miss_last_inst_next <= deadline_miss_last_inst; + liveliness_lost_cnt_next <= liveliness_lost_cnt; + liveliness_lost_cnt_change_next <= liveliness_lost_cnt_change; + lifespan_time_next <= lifespan_time; + is_lifespan_check_next <= is_lifespan_check; + status_sig_next <= status_sig; + cnt2_next <= cnt2; + source_ts_next <= source_ts; + global_seq_nr_next <= global_seq_nr; + global_sample_cnt_next <= global_sample_cnt; + global_ack_cnt_next <= global_ack_cnt; + stale_inst_cnt_next <= stale_inst_cnt; + lifespan_next <= lifespan; + register_op_next <= register_op; + lookup_op_next <= lookup_op; + ack_wait_next <= ack_wait; + timeout_time_next <= timeout_time; + lease_deadline_next <= lease_deadline; + seq_nr_next <= seq_nr; + return_stage_next <= return_stage; + cc_instance_handle_sig_next <= cc_instance_handle_sig; + cc_kind_sig_next <= cc_kind_sig; + cc_source_timestamp_sig_next <= cc_source_timestamp_sig; + is_ack_next <= is_ack; + is_rtps_next <= is_rtps; + data_available_sig_next <= data_available_sig; + orphan_samples_next <= orphan_samples; + -- DEFAULT Unregistered + inst_opcode <= NOP; + ret_rtps <= ERROR; + return_code_dds <= RETCODE_UNSUPPORTED; + ack_dds <= '0'; + done_dds <= '0'; + ack_rtps <= '0'; + done_rtps <= '0'; + khg_abort <= '0'; + inst_op_start <= '0'; + khg_last_word_in <= '0'; + khg_valid_in <= '0'; + khg_ready_out <= '0'; + skg_last_word_in <= '0'; + skg_valid_in <= '0'; + skg_ready_out <= '0'; + sample_read <= '0'; + sample_ready_out <= '0'; + sample_valid_in <= '0'; + sample_abort_read <= '0'; + payload_read <= '0'; + payload_ready_out <= '0'; + payload_valid_in <= '0'; + payload_abort_read <= '0'; + ready_in_dds <= '0'; + assert_liveliness <= '0'; + valid_out_rtps <= '0'; + last_word_out_rtps <= '0'; + valid_out_dds <= '0'; + last_word_out_dds <= '0'; + khg_data_in <= (others => '0'); + skg_data_in <= (others => '0'); + writer_bitmap <= (others => '0'); + inst_addr_update <= (others => '0'); + sample_addr <= (others => '0'); + sample_write_data <= (others => '0'); + payload_addr <= (others => '0'); + payload_write_data <= (others => '0'); + data_out_rtps <= (others => '0'); + data_out_dds <= (others => '0'); + + + case (stage) is + when IDLE => + -- Reset + remove_oldest_inst_sample_next <= '0'; + remove_oldest_sample_next <= '0'; + lookup_op_next <= '0'; + register_op_next <= '0'; + is_rtps_next <= '0'; + + + -- Orphan Samples Available + if (orphan_samples = '1') then + assert (oldest_sample /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; + cur_sample_next <= oldest_sample; + stage_next <= REMOVE_ORPHAN_SAMPLES; + cnt_next <= 0; + -- DEADLINE QoS + elsif (DEADLINE_QOS /= DURATION_INFINITE and deadline_time <= time) then + -- Reset Timeout + deadline_time_next <= deadline_time + DEADLINE_QOS; + + -- Synthesis Guard + if (WITH_KEY) then + stage_next <= CHECK_DEADLINE; + cnt_next <= 0; + else + if (inst_data.status_info(ISI_LIVELINESS_FLAG) = '1') then + -- Reset Liveliness Flag + inst_data_next.status_info(ISI_LIVELINESS_FLAG) <= '0'; + else + -- Update Requested Deadline Missed Status + status_sig_next(REQUESTED_DEADLINE_MISSED_STATUS) <= '1'; + deadline_miss_cnt_next <= deadline_miss_cnt + 1; + deadline_miss_cnt_change_next <= deadline_miss_cnt_change + 1; + end if; + end if; + -- Liveliness Deadline + elsif (LEASE_DURATION /= DURATION_INFINITE and lease_deadline <= time) then + liveliness_lost_cnt_next <= liveliness_lost_cnt + 1; + liveliness_lost_cnt_change_next <= liveliness_lost_cnt_change + 1; + status_sig_next(LIVELINESS_LOST_STATUS) <= '1'; + + -- Reset + lease_deadline_next <= time + LEASE_DURATION; + -- WAIT_FOR_ACKNOWLEDGEMENT Done + elsif (ack_wait and global_ack_cnt = global_sample_cnt) then + -- Reset + ack_wait_next <= '0'; + + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + -- WAIT_FOR_ACKNOWLEDGEMENT Timeout + elsif (ack_wait and timeout_time <= time) then + -- Reset + ack_wait_next <= '0'; + + -- DONE + done_dds <= '1'; + return_code_dds <= RETCODE_TIMEOUT; + -- LIFESPAN QoS + elsif (lifespan_time <= time) then + -- Reset Timeout + lifespan_time_next <= TIME_INFINITE; + + -- Samples Available + if (oldest_sample /= SAMPLE_MEMORY_MAX_ADDRESS) then + cur_sample <= oldest_sample; + stage_next <= CHECK_LIFESPAN; + cnt_next <= 0; + end if; + -- RTPS Operation + elsif (start_rtps = '1') then + is_rtps_next <= '1'; + -- Reset + is_ack_next <= '0'; + + case (opcode_rtps) is + when GET_MIN_SN => + ack_rtps <= '1'; + if (oldest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- NOTE: If the HC is empty we return the Special value SEQUENCENUMBER_UNKNOWN + stage_next <= GET_SEQ_NR; + cnt_next <= 4; + else + cur_sample_next <= oldest_sample; + stage_next <= GET_SEQ_NR; + cnt_next <= 0; + end if; + when GET_MAX_SN => + ack_rtps <= '1'; + + -- Reset Data Availability + data_available_sig_next <= '0'; + + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- NOTE: If the HC is empty we return the Special value SEQUENCENUMBER_UNKNOWN + stage_next <= GET_SEQ_NR; + cnt_next <= 4; + else + cur_sample_next <= newest_sample; + stage_next <= GET_SEQ_NR; + cnt_next <= 0; + end if; + when GET_CACHE_CHANGE => + ack_rtps <= '1'; + + -- No Samples Available + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= UNKNOWN_SEQ_NR; + else + cur_sample_next <= newest_sample; + stage_next <= FIND_SEQ_NR; + cnt_next <= 0; + return_stage_next <= GET_SAMPLE; + end if; + when ACK_CACHE_CHANGE => + ack_rtps <= '1'; + is_ack_next <= '1'; + + -- No Samples Available + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= UNKNOWN_SEQ_NR; + else + cur_sample_next <= newest_sample; + stage_next <= FIND_SEQ_NR; + cnt_next <= 0; + return_stage_next <= ACKNACK_SAMPLE; + end if; + when NACK_CACHE_CHANGE => + ack_rtps <= '1'; + + -- No Samples Available + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= UNKNOWN_SEQ_NR; + else + cur_sample_next <= newest_sample; + stage_next <= FIND_SEQ_NR; + cnt_next <= 0; + return_stage_next <= ACKNACK_SAMPLE; + end if; + when REMOVE_CACHE_CHANGE => + ack_rtps <= '1'; + + -- No Samples Available + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= UNKNOWN_SEQ_NR; + else + cur_sample_next <= newest_sample; + stage_next <= FIND_SEQ_NR; + cnt_next <= 0; + return_stage_next <= REMOVE_SAMPLE; + end if; + when others => + ack_rtps <= '1'; + + stage_next <= UNKNOWN_OPERATION_RTPS; + end case; + -- DDS Operation + elsif (ack_wait = '0' and start_dds = '1') then + case (opcode_dds) is + when REGISTER_INSTANCE => + ack_dds <= '1'; + -- Synthesis Guard + if (WITH_KEY) then + register_op_next <= '1'; + stage_next <= ADD_PAYLOAD; + cnt_next <= 1; + else + stage_next <= UNKNOWN_OPERATION_DDS; + end if; + when WRITE => + ack_dds <= '1'; + + -- Reset Liveliness + lease_deadline_next <= time + LEASE_DURATION; + + -- Latch Input Signals + instance_handle_next <= instance_handle_dds; + source_ts_next <= source_ts_dds; + + -- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset. + sample_status_info_next <= (SSI_PAYLOAD_FLAG => '1', SSI_ALIGNED_FLAG => '1', others => '0'); + cur_sample_next <= empty_sample_list_head; + + -- Instance Handle provided + if (WITH_KEY and instance_handle_dds /= HANDLE_NIL) then + key_hash_next <= instance_handle_dds; + stage_next <= INITIATE_INSTANCE_SEARCH; + cnt_next <= 0; + else + stage_next <= ADD_SAMPLE_INFO; + cnt_next <= 0; + end if; + when DISPOSE => + ack_dds <= '1'; + + -- Reset Liveliness + lease_deadline_next <= time + LEASE_DURATION; + + -- Latch Input Signals + instance_handle_next <= instance_handle_dds; + source_ts_next <= source_ts_dds; + + -- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset. + sample_status_info_next <= (SSI_PAYLOAD_FLAG => '1', SSI_ALIGNED_FLAG => '1', SSI_DISPOSED_FLAG => '1', others => '0'); + cur_sample_next <= empty_sample_list_head; + + -- Instance Handle provided + if (WITH_KEY and instance_handle_dds /= HANDLE_NIL) then + key_hash_next <= instance_handle_dds; + stage_next <= INITIATE_INSTANCE_SEARCH; + cnt_next <= 0; + else + stage_next <= ADD_SAMPLE_INFO; + cnt_next <= 0; + end if; + when UNREGISTER_INSTANCE => + ack_dds <= '1'; + + -- Reset Liveliness + lease_deadline_next <= time + LEASE_DURATION; + + -- Latch Input Signals + instance_handle_next <= instance_handle_dds; + source_ts_next <= source_ts_dds; + + -- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset. + sample_status_info_next <= (SSI_PAYLOAD_FLAG => '1', SSI_ALIGNED_FLAG => '1', SSI_UNREGISTERED_FLAG => '1', others => '0'); + cur_sample_next <= empty_sample_list_head; + + -- Instance Handle provided + if (WITH_KEY and instance_handle_dds /= HANDLE_NIL) then + key_hash_next <= instance_handle_dds; + stage_next <= INITIATE_INSTANCE_SEARCH; + cnt_next <= 0; + else + stage_next <= ADD_SAMPLE_INFO; + cnt_next <= 0; + end if; + when LOOKUP_INSTANCE => + ack_dds <= '1'; + -- Synthesis Guard + if (WITH_KEY) then + lookup_op_next <= '1'; + stage_next <= ADD_PAYLOAD; + cnt_next <= 1; + else + stage_next <= UNKNOWN_OPERATION_DDS; + end if; + when WAIT_FOR_ACKNOWLEDGEMENTS => + -- NOTE: In case of BEST_EFFORT the RTPS Writer still manually ACKs the Samples, so we do not handle this case differently here. + ack_dds <= '1'; + ack_wait_next <= '1'; + timeout_time_next <= time + max_wait_dds; + when GET_OFFERED_DEADLINE_MISSED_STATUS => + ack_dds <= '1'; + stage_next <= GET_OFFERED_DEADLINE_MISSED_STATUS; + cnt_next <= 0; + when ASSERT_LIVELINESS => + -- Reset Liveliness + lease_deadline_next <= time + LEASE_DURATION; + + ack_dds <== '1'; + stage_next <= ASSERT_LIVELINESS; + when GET_LIVELINESS_LOST_STATUS => + ack_dds <= '1'; + stage_next <= GET_LIVELINESS_LOST_STATUS; + cnt_next <= 0; + when others => + ack_dds <= '1'; + stage_next <= UNKNOWN_OPERATION_DDS; + end case; + end if; + when UNKNOWN_OPERATION_DDS => + done_dds <= '1'; + return_code_dds <= RETCODE_ILLEGAL_OPERATION; + + -- DONE + stage_next <= IDLE; + when UNKNOWN_OPERATION_RTPS => + done_rtps <= '1'; + ret_rtps <= ERROR; + + -- DONE + stage_next <= IDLE; + when UNKNOWN_SEQ_NR => + done_rtps <= '1'; + ret_rtps <= INVALID; + + -- DONE + stage_next <= ILDE; + + when ASSERT_LIVELINESS => + -- Propagate Liveliness Assertion + assert_liveliness <= '1'; + + done_dds <= '0'; + return_code_dds <= RETCODE_OK; + + -- DONE + stage_next <= IDLE; + when ADD_SAMPLE_INFO => + -- Precondition: cur_sample set + + case (cnt) is + -- Status Info + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET; + sample_write_data <= sample_status_info; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Sequence Number 1/2 + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET; + sample_write_data <= global_seq_nr(0); + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Sequence Number 2/2 + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET + 1; + sample_write_data <= global_seq_nr(1); + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Timestamp 1/2 + when 3 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET; + sample_write_data <= source_ts(0) when source_ts /= TIME_INVALID else time(0); + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Timestamp 2/2 + when 4 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET + 1; + sample_write_data <= source_ts(1) when source_ts /= TIME_INVALID else time(1); + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + -- Synthesis Guard + if (LIFESPAN_QOS /= DURATION_INFINITE) then + cnt_next <= cnt + 1; + lifespan_next <= time + LIFESPAN_QOS; + else + cnt_next <= cnt + 3; -- Skip + end if; + end if; + -- Lifespan Deadline 1/2 + when 5 => + -- Synthesis Guard + if (LIFESPAN_QOS /= DURATION_INFINITE) then + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET; + sample_write_data <= lifespan(0); + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + end if; + -- Lifespan Deadline 2/2 + when 6 => + -- Synthesis Guard + if (LIFESPAN_QOS /= DURATION_INFINITE) then + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET; + sample_write_data <= lifespan(1); + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + end if; + -- Payload Address + when 7 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + sample_write_data <= empty_payload_list_head; + cur_payload_next <= empty_payload_list_head; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + stage_next <= ADD_PAYLOAD; + cnt_next <= 0; + end if; + when others => + null; + end case; + when ADD_PAYLOAD => + -- Precondition: cur_payload set + + case (cnt) is + -- Push to memory + when 0 => + -- Input Guard + if (valid_in_dds = '1') then + payload_valid_in <= '1'; + payload_addr <= cur_payload + cnt2; + payload_write_data <= data_in_rtps; + -- Memory Control Flow Guard + if (payload_ready_in = '1') then + -- Key Hash needs to be calculated + if (WITH_KEY and instance_handle = HANDLE_NIL) then + cnt_next <= cnt + 1; + else + ready_in_dds <= '1'; + -- End of Payload + if (last_word_in_dds = '1') then + -- End of Payload Slot + if (cnt2 = PAYLOAD_FRAME_SIZE-1) then + stage_next <= FILTER_STAGE; + else + stage_next <= ALIGN_PAYLOAD; + end if; + else + -- End of Payload Slot + if (cnt2 = PAYLOAD_FRAME_SIZE-1) then + stage_next <= NEXT_PAYLOAD_SLOT; + cnt_next <= 0; + else + -- Next Word + cnt2_next <= cnt2 + 1; + end if; + end if; + end if; + end if; + end if; + -- Push to KHG + when 1 => + -- Synthesis Guard + if (WITH_KEY) then + -- Input Guard + if (valid_in_dds = '1') then + + khg_valid_in <= '1'; + khg_data_in <= data_in_rtps; + + -- Output Guard + if (khg_ready_in = '1') then + ready_in_dds <= '1'; + -- Register/Lookup Operation in progress + if (WITH_KEY and (register_op = '1' or lookup_op = '1')) then + -- End of Payload + if (last_word_in_dds = '1') then + -- Fetch the Key Hash + stage_next <= GET_KEY_HASH; + cnt_next <= 0; + else + -- Next Word + cnt_next <= 1; -- Same Sub-state + end if; + else + -- End of Payload + if (last_word_in_dds = '1') then + -- End of Payload Slot + if (cnt2 = PAYLOAD_FRAME_SIZE) then + -- Fetch the Key Hash + stage_next <= GET_KEY_HASH; + cnt_next <= 0; + else + stage_next <= ALIGN_PAYLOAD; + end if; + else + -- End of Payload Slot + if (cnt2 = PAYLOAD_FRAME_SIZE) then + stage_next <= NEXT_PAYLOAD_SLOT; + cnt_next <= 0; + else + -- Next Word + cnt_next <= 0; + cnt2_next <= cnt2 + 1; + end if; + end if; + end if; + end if; + end if; + end if; + when others => + null; + end case; + when NEXT_PAYLOAD_SLOT => + -- Precondition: cur_payload set + + case (cnt) is + -- GET Next Pointer + when 0 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + payload_read <= '1'; + + -- Memory Control Flow Guard + if (payload_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Next Pointer + when 1 => + payload_ready_out <= '1'; + + -- Memory Control Flow Guard + if (payload_valid_out = '1') then + -- No Empty Payload Slots available + if (payload_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then + -- Reject Change + stage_next <= SKIP_ADD_REJECT; + -- Abort Key Hash Generation + khg_abort <= '1'; + else + -- Latch next Payload Slot and Continue + cur_payload_next <= payload_read_data; + stage_next <= ADD_PAYLOAD; + cnt_next <= 0; + cnt2_next <= 1; + end if; + end if; + when others => + null; + end case; + when ALIGN_PAYLOAD => + case (cnt) is + -- Mark Payload as unaligned + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET; + sample_write_data <= sample_status_info; + sample_write_data(SSI_ALIGNED_FLAG) <= '0'; + + -- Memory Control Flow Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Store Payload End Offset + when 1 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PAYLOAD_FRAME_SIZE-1; + payload_write_data <= to_unsigned(cnt2, WORD_WIDTH); + + -- Memory Control Flow Guard + if (payload_ready_in = '1') then + if (WITH_KEY and instance_handle = HANDLE_NIL) then + stage_next <= GET_KEY_HASH; + cnt_next <= 0; + else + stage_next <= FILTER_STAGE; + end if; + end if; + when others => + null; + end case; + when GET_KEY_HASH => + -- Synthesis Guard + if (WITH_KEY) then + 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; + end if; + when INITIATE_INSTANCE_SEARCH => + -- Synthesis Guard + if (WITH_KEY) then + -- Memory Operation Guard + if (inst_op_done = '1') then + inst_op_start <= '1'; + inst_opcode <= SEARCH_INSTANCE_HASH; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + + -- Register Operation in Progress + if (WITH_KEY and register_op = '1') then + stage_next <= REGISTER_OPERATION; + -- Lookup Operation in Progress + elsif (WITH_KEY and lookup_op = '1') then + stage_next <= LOOKUP_OPERATION; + -- Cache Change not yet Stored + elsif (instance_handle /= HANDLE_NIL) then + stage_next <= ADD_SAMPLE_INFO; + cnt_next <= 0; + else + stage_next <= FILTER_STAGE; + end if; + end if; + end if; + when REGISTER_OPERATION => + -- Synthesis Guard + if (WITH_KEY) then + -- Wait for Instance Search to finish + if (inst_op_done = '1') then + -- Instance already in Memory + if (inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then + -- Accept Change + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + stage_next <= PUSH_KEY_HASH; + + -- Instance is Unregistered + if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1') then + -- Re-register Instance + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG; + status_info_update <= inst_data.status_info; + status_info_update(ISI_UNREGISTERED_FLAG) <= '0'; + + -- Update Stale Instance Count + if (inst_data.sample_cnt = inst_data.ack_cnt) then + stale_inst_cnt_next <= stale_inst_cnt - 1; + end if; + end if; + else + -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) + if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- Stale Instances are available + if (stale_inst_cnt /= 0) then + -- Remove Stale and insert new Instance + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + stage_next <= REMOVE_STALE_INSTANCE; + cnt_next <= 0; + else + -- Reject Change + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + stage_next <= IDLE; + end if; + else + -- Accept Change + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + stage_next <= PUSH_KEY_HASH; + + -- Insert New Instance + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (others => '0'); + sample_cnt <= (others => '0'); + ack_cnt <= (others => '0'); + end if; + end if; + end if; + end if; + when LOOKUP_OPERATION => + -- Synthesis Guard + if (WITH_KEY) then + -- Wait for Instance Search to finish + if (inst_op_done = '1') then + -- Instance Found + if (inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then + stage_next <= PUSH_KEY_HASH; + cnt_next <= 0; + else + -- Return Special Value + key_hash_next <= HANDLE_NIL; + stage_next <= PUSH_KEY_HASH; + cnt_next <= 0; + end if; + end if; + end if; + when PUSH_KEY_HASH => + -- Synthesis Guard + if (WITH_KEY) then + case (cnt) is + -- Key Hash 1/4 + when 0 => + valid_out_dds <= '1'; + data_out_dds <= key_hash(0); + + -- Output Guard + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Key Hash 2/4 + when 1 => + valid_out_dds <= '1'; + data_out_dds <= key_hash(1); + + -- Output Guard + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Key Hash 3/4 + when 2 => + valid_out_dds <= '1'; + data_out_dds <= key_hash(2); + + -- Output Guard + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Key Hash 4/4 + when 3 => + valid_out_dds <= '1'; + data_out_dds <= key_hash(3); + + -- Output Guard + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + when 4 => + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + + -- DONE + stage_next <= IDLE; + when others => + null; + end case; + end if; + when FILTER_STAGE => + -- Precondition: cur_sample set + + -- Wait for Instance Search to finish + if (not WITH_KEY or inst_op_done = '1') then + + -- Instance Found + if (not WITH_KEY or inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then + -- Latch Instance Pointer + cur_inst_next <= inst_addr_base; + + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE) + if (WITH_KEY and MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = MAX_SAMPLES_PER_INSTANCE) then + if (inst_data.ack_cnt = 0 and HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then + -- Reject Change + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + stage_next <= IDLE; + else + -- Accept Change (Remove Oldest ACKed Instance Sample) + remove_oldest_inst_sample_next <= '1'; + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + stage_next <= UPDATE_INSTANCE; + end if; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) + elsif (empty_sample_list_head = empty_sample_list_tail) then + if (global_ack_cnt = 0 and HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then + -- Reject Change + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + stage_next <= IDLE; + else + -- Accept Change (Remove Oldest ACKed Sample) + remove_oldest_sample_next <= '1'; + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + stage_next <= UPDATE_INSTANCE; + end if; + else + -- Accept Change + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + stage_next <= UPDATE_INSTANCE; + end if; + else -- (WITH_KEY) + -- Latch Instance Pointer + cur_inst_next <= inst_empty_head; + + -- Provided Instance Handle Invalid + if (instance_handle /= HANDLE_NIL) then + -- Invalid Operation + done_dds <= '1'; + return_code_dds <= RETCODE_BAD_PARAMETER; + -- DONE + stage_next <= IDLE; + -- Ignore Unregister Operation on Unknown Instance + elsif (sample_status_info(SSI_UNREGISTERED_FLAG) /= '1') then + -- Drop Change + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + -- DONE + stage_next <= IDLE; + -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) + elsif (empty_sample_list_head = empty_sample_list_tail) then + -- ACKed Samples exist + if (global_ack_cnt = 0 and HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then + -- Reject Change + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + stage_next <= IDLE; + else + -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) + if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- No Stale Instances available + if (stale_inst_cnt = 0) then + -- Reject Change + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + stage_next <= IDLE; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + + -- Remove Stale and insert new Instance + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + stage_next <= REMOVE_STALE_INSTANCE; + cnt_next <= 0; + end if; + else + -- Accept Change (Remove Oldest Sample) + remove_oldest_sample_next <= '1'; + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + + -- Insert New Instance + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + ack_cnt <= (others => '0'); + + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + end if; + end if; + else + -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) + if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then + -- No Stale Instances available + if (stale_inst_cnt = 0) then + -- Reject Change + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + stage_next <= IDLE; + else + -- Accept Change + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + + -- Remove Stale and insert new Instance + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + stage_next <= REMOVE_STALE_INSTANCE; + cnt_next <= 0; + end if; + else + -- Accept Change + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + + -- Insert New Instance + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + ack_cnt <= (others => '0'); + + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + end if; + end if; + end if; + end if; + when UPDATE_INSTANCE => + -- Memory Operation Guard + if (not WITH_KEY or inst_op_done = '1') then + -- Synthesis Guard + if (WITH_KEY) then + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG; + status_info_update <= inst_data.status_info; + status_info_update(ISI_DISPOSED_FLAG) <= sample_status_info(SSI_DISPOSED_FLAG); + status_info_update(ISI_UNREGISTERED_FLAG) <= sample_status_info(SSI_UNREGISTERED_FLAG); + status_info_update(ISI_LIVELINESS_FLAG) <= '1'; + sample_cnt <= inst_data.sample_cnt + 1; + + -- Update Stale Instance Count + -- NOTE: We enter this state only when we have a new sample, so an instance cannot turn stale, but only + -- become relevant again. + if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.sample_cnt = inst_data.ack_cnt) then + stale_inst_cnt_next <= stale_inst_cnt - 1; + end if; + else + inst_data_next.status_info(ISI_DISPOSED_FLAG) <= sample_status_info(SSI_DISPOSED_FLAG); + inst_data_next.status_info(ISI_UNREGISTERED_FLAG) <= sample_status_info(SSI_UNREGISTERED_FLAG); + inst_data_next.status_info(ISI_LIVELINESS_FLAG) <= '1'; + inst_data_next.sample_cnt <= inst_data.sample_cnt + 1; + end if; + + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + end if; + when FINALIZE_PAYLOAD => + -- Precondition: cur_payload set + + case (cnt) is + -- GET Next Pointer + when 0 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + payload_read <= '1'; + + -- Memory Control Flow Guard + if (payload_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Next Pointer + when 1 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + -- Make current Slot the Tail + payload_write_data <= PAYLOAD_MEMORY_MAX_ADDRESS; + + -- Memory Control Flow Guard + if (payload_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Next Pointer + when 2 => + payload_ready_out <= '1'; + + -- Memory Control Flow Guard + if (payload_valid_out = '1') then + -- Fix New Empty List Head + empty_payload_list_head_next <= payload_read_data; + + -- First Sample + if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + stage_next <= FINALIZE_SAMPLE; + cur_sample_next <= empty_sample_list_head; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + cnt_next <= 0; + else + stage_next <= FIX_POINTERS; + next_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + prev_sample_next <= newest_sample; + cur_sample_next <= newest_sample; + cnt_next <= 0; + end if; + end if; + when others => + null; + end case; + when FIX_POINTERS => + -- Precondition: prev_sample set, next_sample set + + case (cnt) is + -- Next Pointer (Previous Sample) + when 0 => + -- Fix Next Pointer + sample_valid_in <= '1'; + sample_addr <= prev_sample + SMF_NEXT_ADDR_OFFSET; + sample_write_data <= empty_sample_list_head; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + -- No next Slot (Newest Sample) + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + assert (prev_sample = newest_sample) report "Next Sample is MAX_ADDRESS, but sample is not NEWEST (TAIL)" severity FAILURE; + + stage_next <= FINALIZE_SAMPLE; + cur_sample_next <= empty_sample_list_head; + cnt_next <= 0; + else + cnt_next <= 1; + end if; + end if; + -- Previous Pointer (Next Sample) + when 1 => + -- Fix Previous Pointer + sample_valid_in <= '1'; + sample_addr <= next_sample + SMF_PREV_ADDR_OFFSET; + sample_write_data <= empty_sample_list_head; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + stage_next <= FINALIZE_SAMPLE; + cur_sample_next <= empty_sample_list_head; + cnt_next <= 0; + end if; + when others => + null; + end case; + when FINALIZE_SAMPLE => + -- Precondition: prev_sample set, next_sample set, cur_sample set + + case (cnt) is + -- GET Next (Empty) Sample + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_read <= '1'; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Instance Pointer + when 1 => + -- Write Instance Pointer + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_write_data <= cur_inst; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Previous Pointer + when 2 => + -- Write Previous Pointer + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; + sample_write_data <= prev_sample; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Next Pointer + when 3 => + -- Write Next Pointer + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_write_data <= next_sample; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + + -- READ Next (Empty) Sample + when 4 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + + -- Fix new Empty List Head + empty_sample_list_head_next <= sample_read_data; + + -- If newest Sample is now previous, select current sample as new newest + if (newest_sample = prev_sample) then + newest_sample_next <= cur_sample; + end if; + + -- Increment Global Sequence Number + global_seq_nr_next <= global_seq_nr + 1; + + -- Increment Global Sample Count + global_sample_cnt_next <= global_sample_cnt + 1; + + -- Signal Data Available + data_available_sig_next <= '1'; + + -- Update Lifespan Check Time + if (LIFESPAN_QOS /= DURATION_INFINITE and lifespan < lifespan_time) then + lifespan_next <= lifespan; + end if; + + if (WITH_KEY and remove_oldest_inst_sample = '1') then + cur_sample <= oldest_sample; + stage_next <= FIND_OLDEST_INST_SAMPLE; + elsif (remove_oldest_sample = '1') then + -- Synthesis Guard + if (WITH_KEY) then + stage_next <= GET_OLDEST_SAMPLE_INSTANCE; + else + cur_sample_next <= oldest_sample; + stage_next <= REMOVE_SAMPLE; + end if; + else + -- DONE + stage_next <= IDLE; + end if; + end if; + when others => + null; + end case; + when GET_OLDEST_SAMPLE_INSTANCE => + -- Synthesis Guard + if (WITH_KEY) then + case (cnt) is + -- GET Instance Pointer (Oldest Sample) + when 0 => + sample_valid_in <= '1'; + sample_addr <= oldest_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Instance Pointer (Oldest Sample) + when 1 => + -- Memory Operation Guard + if (inst_op_done = '1') then + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- 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_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + inst_addr_update <= sample_read_data; + + cur_sample_next <= oldest_sample; + stage_next <= REMOVE_SAMPLE; + end if; + end if; + when others => + null; + end case; + end if; + when FIND_OLDEST_INST_SAMPLE => + -- Precondition: cur_sample set + + -- Synthesis Guard + if (WITH_KEY) then + case (cnt) is + -- GET Instance Pointer + when 0 => + sample_ready_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Next Sample + when 1 => + sample_ready_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Instance Pointer + when 1 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- Oldest Instance Sample Found + if (sample_read_data = cur_inst) then + stage_next <= REMOVE_SAMPLE; + sample_abort_read <= '1'; + else + cnt_next <= cnt + 1; + end if; + end if; + -- READ Next Sample + when 2 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + cur_sample_next <= sample_read_data; + cnt_next <= 0; + end if; + when others => + null; + end case; + end if; + when REMOVE_ORPHAN_SAMPLES => + case (cnt) is + -- GET Instance Pointer + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_read <= '1'; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Next Sample + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_read <= '1'; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Instance Pointer + when 2 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- Sample is Orphan + if (sample_read_data = dead_inst) then + -- Remove Orphan Sample + stage_next <= REMOVE_SAMPLE; + cnt_next <= 0; + sample_abort_read <= '1'; + else + cnt_next <= cnt + 1; + end if; + end if; + -- READ Next Sample + when 3 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- End of Samples + if (sample_read_data = SAMPLE_MEMORY_MAX_ADDRESS) then + -- DONE + orphan_samples_next <= '0'; + stage_next <= IDLE; + else + -- Continue + cur_sample_next <= sample_read_data; + cnt_next <= 0; + end if; + end if; + when others => + null; + end case; + when REMOVE_SAMPLE => + -- Precondition: cur_sample set + + -- Wait for Instance Search to finish + if (not WITH_KEY or inst_op_done = '1') then + + case (cnt) is + -- GET Status Info + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Previous Sample + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Next Sample + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Payload Pointer + when 3 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Status Info + when 4 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- Latch Sample Status Info (For POST_SAMPLE_REMOVE State) + sample_status_info_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + -- READ Previous Sample + when 5 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + prev_sample_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + -- READ Next Sample + when 6 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + next_sample_next <= sample_read_data; + + -- 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; + cnt_next <= cnt + 2; --Skip Next Step + else + cnt_next <= cnt + 1; + end if; + end if; + -- Next Pointer (Empty List Tail) + when 7 => + -- Add Current Sample after Empty List Tail + sample_valid_in <= '1'; + sample_addr <= empty_sample_list_tail + SMF_NEXT_ADDR_OFFSET; + sample_write_data <= cur_sample; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Next Pointer (Current Sample) + when 8 => + -- Make Current Sample Empty List Tail + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_write_data <= INSTANCE_MEMORY_MAX_ADDRESS; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + -- Fix Empty List Pointers + empty_sample_list_tail_next <= cur_sample; + + -- Current Sample is Newest (Occupied List Tail) + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + assert (cur_sample = newest_sample) report "Next Sample is MAX_ADDR, but cur_sample /= newest_sample" severity FAILURE; + + -- Fix Newest Pointer + newest_sample_next <= prev_sample; + + -- Current Sample is Oldest (List Head) + if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE; + assert (newest_sample = oldest_sample) report "Previous and Next Sample is MAX_ADDR, but cur_sample /= newest_sample /= oldest_sample" severity FAILURE; + + -- Fix Oldest Pointer + oldest_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + -- NOTE: Sample Memory Empty (newest_sample also set to MAX_ADDR) + + cnt_next <= cnt + 3; -- Skip next 2 steps + else + cnt_next <= cnt + 2; -- Skip next step + end if; + else + cnt_next <= cnt + 1; + end if; + end if; + -- Previous Address (Next Sample) + when 9 => + -- Remove link to cur_sample + sample_valid_in <= '1'; + sample_addr <= next_sample + SMF_PREV_ADDR_OFFSET; + sample_write_data <= prev_sample; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + -- Current Sample is oldest sample (List Head) + if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + assert (cur_sample = oldest_sample) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE; + + -- Fix Oldest Pointer + oldest_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + + cnt_next <= cnt + 2; -- Skip next step + else + cnt_next <= cnt + 1; + end if; + end if; + -- Next Address (Previous Sample) + when 10 => + -- Remove link to cur_sample + sample_valid_in <= '1'; + sample_addr <= prev_sample + SMF_NEXT_ADDR_OFFSET; + sample_write_data <= next_sample; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Payload Pointer + when 11 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + cur_payload_next <= sample_read_data; + -- Sample has no Data + if (sample_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then + stage_next <= POST_SAMPLE_REMOVE; + -- Payload Memory Full + elsif (empty_payload_list_head = PAYLOAD_MEMORY_MAX_ADDRESS) then + empty_payload_list_head_next <= sample_read_data; + + stage_next <= POST_SAMPLE_REMOVE; + else + empty_payload_list_head_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + end if; + -- GET Next Payload + when 12 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + payload_read <= '1'; + + -- Memory Flow Control Guard + if (payload_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Next Payload + when 13 => + payload_ready_out <= '1'; + + -- Memory Flow Control Guard + if (payload_valid_out = '1') then + -- Found Empty List Tail + if (payload_read_data = PAYLOAD_MEMORY_MAX_ADDRESS) then + cnt_next <= cnt + 1; + else + cur_payload_next <= payload_read_data; + cnt_next <= cnt - 1; + end if; + end if; + -- Next Payload Pointer (Last Payload of Current Sample) + when 14 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + payload_write_data <= empty_payload_list_head; + + -- Memory Flow Control Guard + if (payload_ready_in = '1') then + -- Orphan Sample Removal in progress + if (orphan_samples = '1') then + -- End of Samples + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- DONE + orphan_samples_next <= '0'; + stage_next <= IDLE; + else + -- Continue + stage_next <= REMOVE_ORPHAN_SAMPLES; + cur_sample_next <= next_sample; + cnt_next <= 0; + end if; + else + stage_next <= POST_SAMPLE_REMOVE; + end if; + end if; + when others => + null; + end case; + end if; + when POST_SAMPLE_REMOVE => + -- Precondition: inst_data set (Status Info, Sample Count, ACK Count) + + -- Memory Operation Guard + if (not WITH_KEY or inst_op_done = '1') then + -- Synthesis Guard + if (WITH_KEY) then + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + inst_mem_fields <= IMF_SAMPLE_CNT_FLAG; + sample_cnt <= inst_data.sample_cnt - 1; + -- Sample was ACKed + if (sample_status_info(SSI_ACK_FLAG) = '1') then + inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + ack_cnt <= inst_data.ack_cnt - 1; + else + -- Update Stale Instance Count + -- Instance is Unregistered and last NACKed sample is removed + if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.sample_cnt = 1) then + stale_inst_cnt_next <= stale_inst_cnt + 1; + end if; + end if; + else + inst_data_next.sample_cnt <= inst_data.sample_cnt - 1; + -- Sample was ACKed + if (sample_status_info(SSI_ACK_FLAG) = '1') then + inst_data_next.ack_cnt <= inst_data.ack_cnt - 1; + end if; + end if; + + -- Update Global Sample Count + global_sample_cnt_next <= global_sample_cnt - 1; + + -- Update Global ACK Count + -- Sample was ACKed + if (sample_status_info(SSI_ACK_FLAG) = '1') then + global_ack_cnt_next <= global_ack_cnt - 1; + end if; + + if (is_rtps = '1') then + -- DONE + done_rtps <= '1'; + ret_rtps <= OK; + stage_next <= IDLE; + elsif (is_lifespan_check = '1') then + -- Reached End of Samples + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Continue Search + cur_sample_next <= next_sample; + stage_next <= CHECK_LIFESPAN; + cnt_next <= 0; + end if; + else + -- DONE + stage_next <= IDLE; + end if; + end if; + when SKIP_ADD_REJECT => + case (cnt) is + -- SKIP READ + when 0 => + ready_in_dds <= '1'; + -- Wait until last word from input + if (last_word_in_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- REJECT SAMPLE + when 1 => + done_dds <= '1'; + return_code_dds <= RETCODE_OUT_OF_RESOURCES; + + -- DONE + stage_next <= IDLE; + when others => + null; + end case; + when REMOVE_STALE_INSTANCE => + -- Synthesis Guard + if (WITH_KEY) then + -- Wait for Instance Data + if (inst_op_done = '1') then + case (cnt) is + -- Find and Remove First Stale Instance + when 0 => + -- Iterated through all Instances + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + -- NOTE: We should enter this state only if there is at least one stale Instance to be removed, so we should never enter this branch. + assert FALSE severity FAILURE; + stage_next <= IDLE; + else + -- Found Stale Instance (Unregistered and all Samples ACKed) + if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.sample_cnt = inst_data.ack_cnt) then + -- Remove Stale Instance + inst_op_start <= '1'; + inst_opcode <= REMOVE_INSTANCE; + -- Update Stale Instance Count + stale_inst_cnt_next <= stale_inst_cnt - 1; + + -- Instance has Samples + if (inst_data.sample_cnt /= 0) then + -- NOTE: The Stale Instance has Samples that need to be removed, but we cannot do that now, + -- because that would mess with our current Sample that is currently in "limbo" until + -- finalized. So we postpone the Sample removal until after the finalization of the + -- current sample. + orphan_samples_next <= '1'; + dead_inst_next <= inst_addr_base; + end if; + + cnt_next <= cnt + 1; + else + -- Continue Search + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + end if; + end if; + -- Insert New Instance + when 1 => + inst_op_start <= '1'; + inst_opcode <= INSERT_INSTANCE; + ack_cnt <= (others => '0'); + if (register_op = '1') then + status_info_update <= (others => '0'); + sample_cnt <= (others => '0'); + else + status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0'); + sample_cnt <= to_unsigned(1, WORD_WIDTH); + end if; + + -- Latch Instance Pointer + cur_inst_next <= inst_empty_head; + + -- Register Operation in progress + if (register_op = '1') then + -- DONE + stage_next <= PUSH_KEY_HASH; + cnt_next <= 0; + else + stage_next <= FINALIZE_PAYLOAD; + cnt_next <= 0; + end if; + when others => + null; + end case; + end if; + end if; + when GET_SEQ_NR => + -- Precondition: cur_sample set + + case (cnt) is + -- GET Sequence Number 1/2 + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Sequence Number 2/2 + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET + 1; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Sequence Number 1/2 + when 2 => + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + data_out_rtps <= sample_read_data; + valid_out_rtps <= '1'; + -- Input Guard + if (ready_out_rtps = '1') then + sample_ready_out <= '1'; + cnt_next <= cnt + 1; + end if; + end if; + -- READ Sequence Number 2/2 + when 3 => + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + data_out_rtps <= sample_read_data; + valid_out_rtps <= '1'; + -- Input Guard + if (ready_out_rtps = '1') then + sample_ready_out <= '1'; + cnt_next <= cnt + 3; -- Skip Special Sequence Number + end if; + end if; + -- Special Sequence Number 1/2 + when 4 => + data_out_rtps <= SEQUENCENUMBER_UNKNOWN(0); + valid_out_rtps <= '1'; + -- Input Guard + if (ready_out_rtps = '1') then + sample_ready_out <= '1'; + cnt_next <= cnt + 1; + end if; + -- Special Sequence Number 2/2 + when 5 => + data_out_rtps <= SEQUENCENUMBER_UNKNOWN(1); + valid_out_rtps <= '1'; + -- Input Guard + if (ready_out_rtps = '1') then + sample_ready_out <= '1'; + cnt_next <= cnt + 1; + end if; + -- Return Code + when 6 => + done_rtps <= '1'; + ret_rtps <= OK; + + -- DONE + stage_next <= IDLE; + when others => + null; + end case; + when FIND_SEQ_NR => + -- NOTE: We are searching in backwards order, since it is more likely that newer Sequence Numbers are polled + case (cnt) is + -- GET Previous Sample + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Sequence Number 1/2 + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Sequence Number 2/2 + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET + 1; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Instance Pointer + when 3 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Previous Sample + when 4 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + prev_sample_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + -- READ Sequence Number 1/2 + when 5 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- No Match + if (sample_read_data /= seq_nr(0)) then + sample_abort_read <= '1'; + -- End of Samples + if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- No Sample with SN found + cur_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + cnt_next <= 8; + else + -- Continue + cur_sample_next <= prev_sample; + cnt_next <= 0; + end if; + else + cnt_next <= cnt + 1; + end if; + end if; + -- READ Sequence Number 2/2 + when 6 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- No Match + if (sample_read_data /= seq_nr(1)) then + sample_abort_read <= '1'; + -- End of Samples + if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- No Sample with SN found + cur_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + cnt_next <= 8; + else + -- Continue + cur_sample_next <= prev_sample; + cnt_next <= 0; + end if; + else + cnt_next <= cnt + 1; + end if; + end if; + -- READ Instance Pointer + when 7 => + sample_ready_out <= '1'; + + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + cur_inst_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + -- Check Result + when 8 => + -- No Sample with Requested Sequence Number found + if (cur_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + done_rtps <= '1'; + ret_rtps <= INVALID; + + -- DONE + stage_next <= IDLE; + else + -- Memory Operation Guard + if (inst_op_done = '1') then + -- Fetch Instance Data + inst_op_start <= '1'; + inst_opcode <= GET_INSTANCE; + inst_mem_fields <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + inst_addr_update <= cur_inst; + + stage_next <= return_stage; + cnt_next <= 0; + end if; + end if; + when others => + null; + end case; + when ACKNACK_SAMPLE => + case (cnt) is + -- GET Status Info + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET; + sample_read <= '1'; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Status Info + when 1 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + sample_status_info_next <= sample_read_data; + + -- Sample Already ACKed/NACKed + if ((is_ack = '1' and sample_read_data(SSI_ACK_FLAG) = '1') or (is_ack = '0' and sample_read_data(SSI_ACK_FLAG) = '0')) then + done_rtps <= '1'; + ret_rtps <= OK; + -- DONE + stage_next <= IDLE; + else + cnt_next <= cnt + 1; + end if; + end if; + -- Set Status Info + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET; + sample_write_data <= sample_status_info; + sample_write_data(SSI_ACK_FLAG) <= '1' when (is_ack = '1') else '0'; + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + global_ack_cnt_next <= (global_ack_cnt + 1) when (is_ack = '1') else (global_ack_cnt - 1); + cnt_next <= cnt + 1; + end if; + -- Set Instance Data + when 3 => + -- Wait for Instance Data + if (inst_op_done = '1') then + -- Update + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + inst_mem_fields <= IMF_ACK_CNT_FLAG; + inst_addr_update <= cur_inst; + ack_cnt <= (inst_data.ack_cnt + 1) when (is_ack = '1') else (inst_data.ack_cnt - 1); + + -- Update Stale Instance Count + -- XXX: Possible Worst Case Path (Addition and Comparison in same clock) + if (is_ack = '1' and inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and (inst_data.ack_cnt+1) = inst_data.sample_cnt) then + stale_inst_cnt_next <= stale_inst_cnt + 1; + elsif (is_ack = '0' and inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.ack_cnt = inst_data.sample_cnt) then + stale_inst_cnt_next <= stale_inst_cnt - 1; + end if; + + -- DONE + done_rtps <= '1'; + ret_rtps <= OK; + stage_next <= IDLE; + end if; + when others => + null; + end case; + when GET_SAMPLE => + case (cnt) is + -- GET Status Info + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Timestamp 1/2 + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Timestamp 2/2 + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET + 1; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Payload Pointer + when 3 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Status Info + when 4 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + -- NOTE: SSI_UNREGISTERED_FLAG takes precedence over SSI_DISPOSED_FLAG, because a Disposed Instance + -- can still be Unregistered, but not the other way around. + if (sample_read_data(SSI_UNREGISTERED_FLAG) = '1') then + cc_kind_sig_next <= NOT_ALIVE_UNREGISTERED; + elsif (sample_read_data(SSI_DISPOSED_FLAG) = '1') + cc_kind_sig_next <= NOT_ALIVE_DISPOSED; + else + cc_kind_sig_next <= ALIVE; + end if; + -- Latch Status Info (For GET_PAYLOAD State) + sample_status_info_next <= sample_read_data; + + cnt_next <= cnt + 1; + end if; + -- READ Timestamp 1/2 + when 5 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + cc_source_timestamp_sig_next(0) <= sample_read_data; + + cnt_next <= cnt + 1; + end if; + -- READ Timestamp 2/2 + when 6 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + cc_source_timestamp_sig_next(1) <= sample_read_data; + + cnt_next <= cnt + 1; + end if; + -- READ Payload Pointer + when 7 => + sample_ready_out <= '1'; + -- Memory Flow Control Guard + if (sample_valid_out = '1') then + cur_payload_next <= sample_read_data; + + cnt_next <= cnt + 1; + end if; + -- Instance Handle + when 8 => + -- Wait for Instance Data + if (inst_op_done = '1') then + cc_instance_handle_sig_next <= inst_data.key_hash; + + cnt_next <= cnt + 1; + end if; + -- Present Sample + when 9 => + done_rtps <= '1'; + ret_rtps <= OK; + + -- RTPS Requestes Payload + if (get_data_rtps = '1') then + -- Get Payload + stage_next <= GET_PAYLOAD; + else + -- DONE + stage_next <= IDLE; + end if; + when others => + null; + end case; + when GET_PAYLOAD => + -- Precondition: cur_payload set, sample_status_info set + + -- NOTE: We are using the Burst Capability of the Memory Controller as a FIFO which we + -- fill and the output is directly reading. cnt is switching the memory reading states, + -- cnt2 signals the offset of the payload read, and cnt3 signals how many Bytes have been + -- requested but not yet claimed (i.e. how many Bytes are in the FIFO). + + -- DEFAULT + tmp_bool := FALSE; + + case (cnt) is + -- GET Next Pointer + when 0 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + payload_read <= '1'; + + -- Memory Flow Control Guard + if (payload_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Next Pointer + when 1 => + payload_ready_out <= '1'; + + -- Memory Flow Control Guard + if (payload_valid_out = '1') then + next_payload_next <= payload_read_data; + cnt2 <= 1; + + -- Last Payload Slot is unaligned + if (payload_read_data = PAYLOAD_MEMORY_MAX_ADDRESS and sample_status_info(SSI_ALIGNED_FLAG) = '0') then + cnt_next <= cnt + 1 + else + cnt_next <= cnt + 3; + long_latch_next <= PAYLOAD_FRAME_SIZE-1; + end if; + end if; + -- GET Payload Offset + when 2 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PAYLOAD_FRAME_SIZE-1; + payload_read <= '1'; + + -- Memory Flow Control Guard + if (payload_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Payload Offset + when 3 => + payload_ready_out <= '1'; + + -- Memory Flow Control Guard + if (payload_valid_out = '1') then + long_latch_next <= payload_read_data; + cnt_next <= cnt + 1; + end if; + -- GET PAYLOAD + when 4 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + cnt2; + payload_read <= '1'; + + -- Memory Flow Control Guard + if (payload_ready_in = '1') then + cnt3_next <= cnt3 + 1; + tmp_bool := TRUE; + -- End of Payload Slot + if (cnt2 = unsigned(long_latch)) then + -- End of Payload + if (next_payload = PAYLOAD_MEMORY_MAX_ADDRESS) then + -- DONE (Wait for Output to finidh reading) + cnt_next <= cnt + 1; + else + -- Next Payload Slot + cur_payload_next <= next_payload; + cnt_next <= 0; + end if; + else + cnt2_next <= cnt2 + 1; + end if; + end if; + when others => + null; + end case; + + -- Placeholder Pre-Mapping + ready_out_tmp := skg_ready_in when (cc_kind_sig /= ALIVE) else ready_out_rtps; + + -- Data available for Output + if (cnt3 /= 0) then + -- Memory Flow Control Guard + if (payload_valid_out = '1') then + valid_out_tmp := '1'; + + -- End of Payload + if (cnt3 = 1 and cnt = 4) then + last_word_out_tmp := '1'; + end if; + + -- DDS Read + if (ready_out_tmp = '1') then + payload_ready_out <= '1'; + -- NOTE: We are using the tmp_bool variable to signal if there is an increment + -- on the same clock cycle. + -- Increment in same clock cycle + if (tmp_bool) then + cnt3_next <= cnt3; -- Override increment + else + cnt3_next <= cnt3 - 1; + end if; + end if; + end if; + -- Finished Reading + elsif (cnt = 4) then + assert (cnt3 = 0) severity FAILURE; + -- Need to push Serialized Key + if (cc_kind_sig /= ALIVE) then + stage_next <= GET_SERIALIZED_KEY; + else + -- DONE + stage_next <= IDLE; + end if; + end if; + + -- Placeholder Post-Mapping + if (cc_kind_sig /= ALIVE) then + skg_valid_out <= valid_out_tmp; + skg_last_word_out <= last_word_out_tmp; + else + valid_out_rtps <= valid_out_tmp; + last_word_out_rtps <= last_word_out_tmp; + end if; + when GET_SERIALIZED_KEY => + if (skg_valid_out = '1') then + valid_out_rtps <= '1'; + data_out_rtps <= skg_data_out; + last_word_out_rtps <= skg_last_word_out; + -- Output Guard + if (ready_out_rtps = '1') then + skg_ready_out <= '1'; + + -- Exit Condition + if (skg_last_word_out = '1') then + -- DONE + stage_next <= IDLE; + end if; + end if; + end if; + when CHECK_LIFESPAN => + -- Precondition: cur_sample set, + + case (cnt) is + -- GET Next Sample + when 0 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Control Flow Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Lifespan 1/2 + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET; + sample_read <= '1'; + + -- Memory Control Flow Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Lifespan 2/2 + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET + 1; + sample_read <= '1'; + + -- Memory Control Flow Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- GET Instance Pointer + when 3 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; + sample_read <= '1'; + + -- Memory Control Flow Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- READ Next Sample + when 4 => + sample_ready_out <= '1'; + + -- Memory Control Flow Guard + if (sample_valid_out = '1') then + next_sample_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + -- READ Lifespan 1/2 + when 5 => + sample_ready_out <= '1'; + + -- Memory Control Flow Guard + if (sample_valid_out = '1') then + long_latch_next <= sample_read_data; + cnt_next <= cnt + 1; + end if; + -- READ Lifespan 2/2 + when 6 => + sample_ready_out <= '1'; + + -- Memory Control Flow Guard + if (sample_valid_out = '1') then + tmp_dw := (0 => unsigned(long_latch), 1 => unsigned(sample_read_data)); + + -- Sample Lifespan Expired + if (tmp_dw /= TIME_INVALID and time >= tmp_dw) then + cnt_next <= cnt + 1; + else + sample_abort_read <= '1'; + + -- Update Check Time + if (tmp_dw /= TIME_INVALID and tmp_dw < lifespan_time) then + lifespan_time_next <= tmp_dw; + end if; + + -- Reached End of Samples + if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Continue Search + cur_sample_next <= next_sample; + cnt_next <= 0; + end if; + end if; + end if; + -- READ Instance Pointer + when 7 => + -- Memory Operation Guard + if (inst_op_done = '1') then + sample_ready_out <= '1'; + + -- Memory Control Flow Guard + if (sample_valid_out = '1') then + -- Fetch Instance Data + inst_op_start <= '1'; + inst_opcode <= GET_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; + inst_addr_update <= sample_read_data; + + -- Remove Sample + stage_next <= REMOVE_SAMPLE; + cnt_next <= 0; + end if; + end if; + when others => + null; + end case; + when GET_LIVELINESS_LOST_STATUS => + case (cnt) is + -- Total Count + when 0 => + data_out_dds <= liveliness_lost_cnt; + valid_out_dds <= '1'; + + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Total Count Change + when 1 => + data_out_dds <= liveliness_lost_cnt_change; + valid_out_dds <= '1'; + + if (ready_out_dds = '1') then + -- Reset + liveliness_lost_cnt_change_next <= (others => '0'); + + cnt_next <= cnt + 1; + end if; + -- Return Code + when 2 => + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + + if (ready_out_dds = '1') then + -- Reset + status_sig_next(LIVELINESS_LOST_STATUS) <= '0'; + + -- DONE + stage_next <= IDLE; + end if; + when others => + null; + end case; + when GET_OFFERED_DEADLINE_MISSED_STATUS => + case (cnt) is + -- Total Count + when 0 => + data_out_dds <= deadline_miss_cnt; + valid_out_dds <= '1'; + + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Total Count Change + when 1 => + data_out_dds <= deadline_miss_cnt_change; + valid_out_dds <= '1'; + + if (ready_out_dds = '1') then + -- Reset + deadline_miss_cnt_change_next <= (others => '0'); + + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 1/4 + when 2 => + data_out_dds <= deadline_miss_last_inst(0); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 2/4 + when 3 => + data_out_dds <= deadline_miss_last_inst(1); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 3/4 + when 4 => + data_out_dds <= deadline_miss_last_inst(2); + valid_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Last Instance Handle 4/4 + when 5 => + data_out_dds <= deadline_miss_last_inst(3); + valid_out_dds <= '1'; + last_word_out_dds <= '1'; + if (ready_out_dds = '1') then + cnt_next <= cnt + 1; + end if; + -- Return Code + when 6 => + done_dds <= '1'; + return_code_dds <= RETCODE_OK; + if (ready_out_dds = '1') then + -- Reset + status_sig_next(OFFERED_DEADLINE_MISSED_STATUS) <= '0'; + + -- DONE + stage_next <= IDLE; + end if; + when others => + null; + end case; + when CHECK_DEADLINE => + -- Synthesis Guard + if (WITH_KEY) then + -- Memory Operation Guard + if (inst_op_done = '1') then + case (cnt) is + -- Get First Instance + when 0 => + inst_op_start <= '1'; + inst_opcode <= GET_FIRST_INSTANCE; + inst_mem_fields <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG; + cnt_next <= 2; + -- Get Next Instance + when 1 => + inst_op_start <= '1'; + inst_opcode <= GET_NEXT_INSTANCE; + inst_mem_fields <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG; + cnt_next <= 2; + -- Check Instance + when 2 => + -- Reached End of Instances + if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Instance received Sample + if (inst_data.status_info(ISI_LIVELINESS_FLAG) = '1') then + -- Reset Liveliness Flag + inst_op_start <= '1'; + inst_opcode <= UPDATE_INSTANCE; + inst_mem_fields <= IMF_STATUS_FLAG; + status_info_update <= inst_data.status_info; + status_info_update(ISI_LIVELINESS_FLAG) <= '0'; + cnt_next <= 1; + else + -- Update Requested Deadline Missed Status + status_sig_next(OFFERED_DEADLINE_MISSED_STATUS) <= '1'; + deadline_miss_cnt_next <= deadline_miss_cnt + 1; + deadline_miss_cnt_change_next <= deadline_miss_cnt_change + 1; + deadline_miss_last_inst_next <= inst_data.key_hash; + cnt_next <= 1; + end if; + end if; + when others => + null; + end case; + end if; + end if; + when RESET_SAMPLE_MEMORY => + case (cnt) is + -- Initialize + when 0 => + prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; + cur_sample_next <= (others => '0'); + cnt_next <= cnt + 1; + -- Set Previous Pointer + when 1 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; + sample_write_data <= prev_sample; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + cnt_next <= cnt + 1; + end if; + -- Set Next Pointer + when 2 => + sample_valid_in <= '1'; + sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; + if (cur_sample = MAX_SAMPLE_ADDRESS) then + sample_write_data <= SAMPLE_MEMORY_MAX_ADDRESS; + else + sample_write_data <= cur_sample + SAMPLE_FRAME_SIZE; + end if; + + -- Memory Flow Control Guard + if (sample_ready_in = '1') then + if (cur_sample = MAX_SAMPLE_ADDRESS) then + -- DONE + stage_next <= RESET_PAYLOAD_MEMORY; + cnt_next <= 0; + else + -- Continue + cur_sample_next <= cur_sample + SAMPLE_FRAME_SIZE; + prev_sample_next <= cur_sample; + cnt_next <= 1; + end if; + end if; + when others => + null; + end case; + when RESET_PAYLOAD_MEMORY => + case (inst_cnt) is + -- Initialize + when 0 => + cur_payload_next <= (others => '0'); + cnt_next <= cnt + 1; + -- Set Next Pointer + when 1 => + payload_valid_in <= '1'; + payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; + if (cur_payload = MAX_PAYLOAD_ADDRESS) then + payload_write_data <= PAYLOAD_MEMORY_MAX_ADDRESS; + else + payload_write_data <= cur_payload + PAYLOAD_FRAME_SIZE; + end if; + + -- Memory Flow Control Guard + if (payload_ready_in = '1') then + if (cur_payload = MAX_PAYLOAD_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + cur_payload_next <= cur_payload + PAYLOAD_FRAME_SIZE; + end if; + end if; + when others => + null; + end case; + when others => + null; + end case; + end process; + + gen_inst_ctrl_prc : if WITH_KEY generate + + -- *Instance Memory Process* + -- STATE DESCRIPTION + -- IDLE Idle State. Done Signal is pulled high and Memory FSM accepts new memory operations + -- SEARCH_INSTANCE_HASH See Memory OPCODE Description + -- SEARCH_INSTANCE_ADDR See Memory OPCODE Description + -- GET_NEXT_INSTANCE See Memory OPCODE Description + -- GET_INSTANCE_DATA Latch specified Instance Data for use by main process + -- FIND_POS Find List position of Instance to be added + -- INSERT_INSTANCE See Memory OPCODE Description + -- UPDATE_INSTANCE See Memory OPCODE Description + -- REMOVE_INSTANCE See Memory OPCODE Description + -- RESET_MEMORY Reset Endpoint Memory to Empty State + inst_ctrl_prc : process(all) + begin + -- DEFAULT Registered + inst_stage_next <= inst_stage; + inst_addr_base_next <= inst_addr_base; + 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_cnt2_next <= inst_cnt2; + inst_data_next <= inst_data; + inst_long_latch_next <= inst_long_latch; + -- DEFAULT Unregistered + inst_ready_out <= '0'; + inst_valid_in <= '0'; + inst_read <= '0'; + inst_op_done <= '0'; + inst_addr <= (others => '0'); + inst_write_data <= (others => '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, + status_info => status_info_update, + sample_cnt => sample_cnt, + ack_cnt => ack_cnt, + field_flags => inst_mem_fields, + 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_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_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_base_next <= inst_occupied_head; + inst_stage_next <= FIND_POS; + inst_cnt_next <= 0; + when UPDATE_INSTANCE => + inst_stage_next <= UPDATE_INSTANCE; + if check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 0; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 1; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 2; + else + -- DONE + inst_stage_next <= IDLE; + 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; + -- Get Instance Data + inst_data_next <= ZERO_INSTANCE_DATA; + inst_stage_next <= GET_INSTANCE_DATA; + if check_mask(inst_mem_fields.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 0; + elsif check_mask(inst_mem_fields.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 4; + elsif check_mask(inst_mem_fields.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_mem_fields.field_flag,IMF_DISPOSED_CNT_FLAG) then + inst_cnt_next <= 6; + elsif check_mask(inst_mem_fields.field_flag,IMF_NO_WRITERS_CNT_FLAG) then + inst_cnt_next <= 7; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and check_mask(inst_mem_fields.field_flag,IMF_IGNORE_DEADLINE_FLAG)) then + inst_cnt_next <= 8; + elsif check_mask(inst_mem_fields.field_flag,IMF_WRITER_BITMAP_FLAG) then + inst_cnt_next <= 10; + inst_cnt2_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + when GET_NEXT_INSTANCE => + -- 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_stage_next <= GET_NEXT_INSTANCE; + inst_cnt_next <= 0; + end if; + when REMOVE_INSTANCE => + inst_stage_next <= REMOVE_INSTANCE; + inst_cnt_next <= 0; + when GET_INSTANCE => + inst_addr_base_next <= inst_addr_update; + -- Get Instance Data + inst_data_next <= ZERO_INSTANCE_DATA; + inst_stage_next <= GET_INSTANCE_DATA; + if check_mask(inst_mem_fields.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 0; + elsif check_mask(inst_mem_fields.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 4; + elsif check_mask(inst_mem_fields.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_mem_fields.field_flag,IMF_DISPOSED_CNT_FLAG) then + inst_cnt_next <= 6; + elsif check_mask(inst_mem_fields.field_flag,IMF_NO_WRITERS_CNT_FLAG) then + inst_cnt_next <= 7; + elsif (TIME_BASED_FILTER_QOS /= DURATION_ZERO and check_mask(inst_mem_fields.field_flag,IMF_IGNORE_DEADLINE_FLAG)) then + inst_cnt_next <= 8; + elsif check_mask(inst_mem_fields.field_flag,IMF_WRITER_BITMAP_FLAG) then + inst_cnt_next <= 10; + inst_cnt2_next <= 0; + else + -- DONE + inst_stage_next <= IDLE; + end if; + when UNMARK_INSTANCES => + -- Empty Memory Guard + if (inst_occupied_head /= INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= inst_occupied_head; + inst_stage_next <= UNMARK_INSTANCES; + inst_cnt_next <= 0; + end if; + when others => + null; + end case; + end if; + when SEARCH_INSTANCE_HASH => + + case (inst_cnt) is + -- GET Next Instance + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 1/4 + when 1 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 2/4 + when 2 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 1; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 3/4 + when 3 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 2; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 4/4 + when 4 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Next Instance + when 5 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_next_addr_base_next <= inst_read_data; + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Key Hash 1/4 + when 6 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(0)) then + -- Reached List Tail, No Match + if (inst_next_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_cnt_next <= 0; + inst_abort_read <= '1'; + end if; + else + inst_cnt_next <= inst_cnt + 1; + end if; + end if; + -- READ Key Hash 2/4 + when 7 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(1)) then + -- Reached List Tail, No Match + if (inst_next_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_cnt_next <= 0; + inst_abort_read <= '1'; + end if; + else + inst_cnt_next <= inst_cnt + 1; + end if; + end if; + -- READ Key Hash 3/4 + when 8 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(2)) then + -- Reached List Tail, No Match + if (inst_next_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_cnt_next <= 0; + inst_abort_read <= '1'; + end if; + else + inst_cnt_next <= inst_cnt + 1; + end if; + end if; + -- READ Key Hash 4/4 + when 9 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- No Match + if (inst_read_data /= inst_latch_data.key_hash(3)) then + -- Reached List Tail, No Match + if (inst_next_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_cnt_next <= 0; + inst_abort_read <= '1'; + end if; + else + -- Get Instance Data + inst_data_next <= ZERO_INSTANCE_DATA; + inst_stage_next <= GET_INSTANCE_DATA; + if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 0; + elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 4; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 6; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + end if; + when others => + null; + end case; + when SEARCH_INSTANCE_ADDR => + + case (inst_cnt) is + -- GET Next Instance + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Next Instance + when 1 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_read_data; + + -- Match + if (inst_read_data = inst_latch_data.addr) then + -- Get Instance Data + inst_stage_next <= GET_INSTANCE_DATA; + inst_data_next <= ZERO_INSTANCE_DATA; + if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 0; + elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 4; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 6; + else + -- DONE + inst_stage_next <= IDLE; + end if; + -- No Match + else + -- Reached List Tail, No Match + if (inst_read_data = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match + -- DONE + inst_stage_next <= IDLE; + else + -- Continue Search + inst_cnt_next <= 0; + end if; + end if; + end if; + when others => + null; + end case; + when GET_NEXT_INSTANCE => + case (inst_cnt) is + -- GET next Instance + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Next Instance + when 1 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_next_addr_base_next <= inst_read_data; + -- Get Instance Data + inst_data_next <= ZERO_INSTANCE_DATA; + inst_stage_next <= GET_INSTANCE_DATA; + if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 0; + elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 4; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 6; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + when others => + null; + end case; + when GET_INSTANCE_DATA => + case (inst_cnt) is + -- GET Key Hash 1/4 + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 2/4 + when 1 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 1; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 3/4 + when 2 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 2; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 4/4 + when 3 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 4; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 6; + else + inst_cnt_next <= 7; + end if; + end if; + -- GET Status Info + when 4 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 5; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 6; + else + if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 7; + else + inst_cnt_next <= 11; + end if; + end if; + end if; + -- GET Sample Count + when 5 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 6; + else + if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 7; + elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 11; + else + inst_cnt_next <= 12; + end if; + end if; + end if; + -- GET ACK Count + when 6 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_ACK_CNT_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if check_mask(inst_latch_data.field_flag,IMF_KEY_HASH_FLAG) then + inst_cnt_next <= 7; + elsif check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 11; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 12; + else + inst_cnt_next <= 13; + end if; + end if; + -- READ Key Hash 1/4 + when 7 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.key_hash(0) <= inst_read_data; + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Key Hash 2/4 + when 8 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.key_hash(1) <= inst_read_data; + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Key Hash 3/4 + when 9 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.key_hash(2) <= inst_read_data; + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Key Hash 4/4 + when 10 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.key_hash(3) <= inst_read_data; + + if check_mask(inst_latch_data.field_flag,IMF_STATUS_FLAG) then + inst_cnt_next <= 11; + elsif check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 12; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 13; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- READ Status Info + when 11 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.status_info <= inst_read_data; + + if check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 12; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 13; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- READ Sample Count + when 12 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.sample_cnt <= inst_read_data; + + if check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 13; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- READ ACK Count + when 13 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_latch_data_next.ack_cnt <= inst_read_data; + + -- DONE + inst_stage_next <= IDLE; + end if; + end case; + when FIND_POS => + -- NOTE: Instances are inserted in KEY_HASH numerical order. + + -- TODO: Handle inst_next_addr_base = MAX_ADDR + + case (inst_cnt) is + -- GET Next Instance + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 1/4 + when 1 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 2/4 + when 2 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 1; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 3/4 + when 3 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 2; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- GET Key Hash 4/4 + when 4 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Next Instance + when 5 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_next_addr_base_next <= inst_read_data; + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Key Hash 1/4 + when 6 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- Found Position (Before Current Instance) + if (inst_latch_data.key_hash(0) < 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 + assert (inst_addr_base = inst_occupied_head) + inst_occupied_head_next <= inst_empty_head; + + inst_addr_base_next <= inst_empty_head; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 1; -- Skip First Step + else + inst_addr_base_next <= inst_prev_addr_base; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 0; + end if; + -- BIGGER-THAN + elsif (inst_latch_data.key_hash(0) /= inst_read_data) then + -- Continue + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + cnt_next <= 0; + inst_abort_read <= '1'; + end if; + end if; + -- READ Key Hash 2/4 + when 7 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- Found Position (Before Current Instance) + 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 + assert (inst_addr_base = inst_occupied_head) + inst_occupied_head_next <= inst_empty_head; + + inst_addr_base_next <= inst_empty_head; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 1; -- Skip First Step + else + inst_addr_base_next <= inst_prev_addr_base; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 0; + end if; + -- BIGGER-THAN + elsif (inst_latch_data.key_hash(1) /= inst_read_data) then + -- Continue + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + cnt_next <= 0; + inst_abort_read <= '1'; + end if; + end if; + -- READ Key Hash 3/4 + when 8 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- Found Position (Before Current Instance) + if (inst_latch_data.key_hash(2) < 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 + assert (inst_addr_base = inst_occupied_head) + inst_occupied_head_next <= inst_empty_head; + + inst_addr_base_next <= inst_empty_head; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 1; -- Skip First Step + else + inst_addr_base_next <= inst_prev_addr_base; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 0; + end if; + -- BIGGER-THAN + elsif (inst_latch_data.key_hash(2) /= inst_read_data) then + -- Continue + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + cnt_next <= 0; + inst_abort_read <= '1'; + end if; + end if; + -- Key Hash 4/4 + when 5 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- Found Position + if (inst_latch_data.key_hash(3) < 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 + assert (inst_addr_base = inst_occupied_head) + inst_occupied_head_next <= inst_empty_head; + + inst_addr_base_next <= inst_empty_head; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 1; -- Skip First Step + else + inst_addr_base_next <= inst_prev_addr_base; + inst_stage_next <= INSERT_INSTANCE; + cnt_next <= 0; + end if; + else + assert (inst_latch_data.key_hash(3) /= inst_read_data) report "Doublicate Instance Detected" severity FAILURE; + + -- Continue + inst_prev_addr_base_next <= inst_addr_base; + inst_addr_base_next <= inst_next_addr_base; + cnt_next <= 0; + end if; + end if; + when others => + null; + end case; + when INSERT_INSTANCE => + -- Precondition: inst_addr_base set, inst_prev_addr_base set + + case (inst_cnt) is + -- GET Next Pointer + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + -- Insert to Occupied List Head + if (inst_prev_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then + inst_cnt_next <= inst_cnt + 2; + else + inst_cnt_next <= inst_cnt + 1; + end if; + end if; + -- Next Pointer (Previous Instance) + when 1 => + inst_valid_in <= '1'; + inst_addr <= inst_prev_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_write_data <= inst_addr_base; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Next Pointer + when 2 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + -- Fix Empty List Head + inst_empty_head_next <= inst_read_data; + + -- TODO + end if; + -- Key Hash 1/4 + when 3 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET; + inst_write_data <= inst_latch_data.key_hash(0); + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- Key Hash 2/4 + when 4 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 1; + inst_write_data <= inst_latch_data.key_hash(1); + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- Key Hash 3/4 + when 5 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 2; + inst_write_data <= inst_latch_data.key_hash(2); + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- Key Hash 4/4 + when 6 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3; + inst_write_data <= inst_latch_data.key_hash(3); + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- Status Info + when 7 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_write_data <= inst_latch_data.status_info; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- Sample Count + when 8 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_write_data <= inst_latch_data.sample_cnt; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- ACK Count + when 9 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_ACK_CNT_OFFSET; + inst_write_data <= inst_latch_data.ack_cnt; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + -- DONE + inst_stage_next <= IDLE; + end if; + when others => + null; + end case; + when UPDATE_INSTANCE => + case (inst_cnt) is + -- Status Info + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET; + inst_write_data <= inst_latch_data.status_info; + inst_data_next.status_info <= inst_latch_data.status_info; + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if check_mask(inst_latch_data.field_flag,IMF_SAMPLE_CNT_FLAG) then + inst_cnt_next <= 1; + elsif check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 2; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- Sample Count + when 1 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; + inst_write_data <= inst_latch_data.sample_cnt; + inst_data_next.sample_cnt <= inst_latch_data.sample_cnt; + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if check_mask(inst_latch_data.field_flag,IMF_ACK_CNT_FLAG) then + inst_cnt_next <= 2; + else + -- DONE + inst_stage_next <= IDLE; + end if; + end if; + -- ACK Count + when 2 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_ACK_CNT_OFFSET; + inst_write_data <= inst_latch_data.ack_cnt; + inst_data_next.ack_cnt <= inst_latch_data.ack_cnt; + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + -- DONE + inst_stage_next <= IDLE; + end if; + when others => + null; + end case; + when REMOVE_INSTANCE => + -- Precondition: inst_addr_base set, inst_prev_addr_base set + + case (inst_cnt) is + -- GET Next Instance + when 0 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_read <= '1'; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- READ Next Instance + when 1 => + inst_ready_out <= '1'; + + -- Memory Flow Control Guard + if (inst_valid_out = '1') then + inst_next_addr_base_next <= inst_read_data; + inst_cnt_next <= inst_cnt + 1; + end if; + -- Next Pointer (Previous Instance) + when 2 => + -- Point Previous instance to Next Instance (Remove current Instance from inbetween) + inst_valid_in <= '1'; + inst_addr <= inst_prev_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_write_data <= inst_next_addr_base; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + inst_cnt_next <= inst_cnt + 1; + end if; + -- Next Pointer (Current/Removed Instance) + when 3 => + -- Point Current Instance to Empty List Head (Make Removed Instance Head of the Empty List) + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + inst_write_data <= inst_empty_head; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + -- 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; + end if; + when others => + null; + end case; + when RESET_MEMORY => + case (inst_cnt) is + -- Initialize + when 0 => + inst_addr_base_next <= FIRST_INSTANCE_ADDRESS; + inst_cnt_next <= inst_cnt + 1; + -- Set Next Pointer + when 1 => + inst_valid_in <= '1'; + inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; + if (inst_addr_base = MAX_INSTANCE_ADDRESS) then + inst_write_data <= INSTANCE_MEMORY_MAX_ADDRESS; + else + inst_write_data <= inst_addr_base + INSTANCE_FRAME_SIZE; + end if; + + -- Memory Flow Control Guard + if (inst_ready_in = '1') then + if (inst_addr_base = MAX_INSTANCE_ADDRESS) then + -- DONE + inst_stage_next <= IDLE; + else + inst_addr_base_next <= inst_addr_base + INSTANCE_FRAME_SIZE; + end if; + end if; + when others => + null; + end case; + when others => + null; + end case; + end process; + end generate; +end architecture; \ No newline at end of file diff --git a/src/serialized_key_generator.vhd b/src/serialized_key_generator.vhd new file mode 100644 index 0000000..a4cf608 --- /dev/null +++ b/src/serialized_key_generator.vhd @@ -0,0 +1,24 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity serialized_key_generator is + port ( + clk : in std_logic; + reset : in std_logic; + + start : in std_logic; + opcode : in KEY_GENERATOR_OPCODE_TYPE; + busy : out std_logic; + + data_in : in std_logic_vector(WORD_WIDTH-1 downto 0); + valid_in : in std_logic; + ready_in : out std_logic; + last_word_in : in std_logic; + + data_out : out std_logic_vector(WORD_WIDTH-1 downto 0); + valid_out : out std_logic; + ready_out : in std_logic; + last_word_out : out std_logic + ); +end entity; \ No newline at end of file