-- altera vhdl_input_version vhdl_2008 -- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.math_pkg.all; use work.rtps_package.all; use work.user_config.all; use work.rtps_config_package.all; -- DDS WRITER -- This Entity is implementing the DDS writer endpoints. -- The entity represents multiple writer endpoints (configurable via the NUM_WRITERS generic). -- Similar to the DDS reader the HistoryCache is integrated into the DDS writer. -- This entity has 3 memories: an instance memory, a sample memory, and a payload memory. -- The instance memory contains instances (samples with the same key and topic form an instance) of received samples. -- The sample memory contains the sample(CacheChange) "meta" data, and the payload memory contains the respective data -- of the samples (if available). -- This entity receives operations from both the RTPS endpoint, and the downstream user endpoints using a start/done -- schema. -- The allowed RTPS operations are GET_CACHE_CHANGE, ACK_CACHE_CHANGE, NACK_CACHE_CHANGE, REMOVE_CACHE_CHANGE, -- GET_MIN_SN, GET_MAX_SN. See below for the data input formats. -- The GET_CACHE_CHANGE operation returns the requested CacheChange (All 'cc_*' signals are valid) based on the provided -- SequenceNumber, whereas the REMOVE_CACHE_CHANGE operation removes the CacheChange from memory. The ACK_CACHE_CHANGE -- operation marks the CacheChange based on the provided SequenceNumber as acknowledged, whereas the NACK_CACHE_CHANGE -- marks the CacheChange as not acknowledged. The GET_MIN_SN returns (in the 'cc_seq_nr' signal) the SequenceNumber of -- the oldest sample in the sample memory (list tail), whereas the GET_MAX_SN returns the SequenceNumber of the newest -- sample in the sample memory (list head). -- To start an operation the 'start' signal is asserted with the respective opcode in 'opcode' and waits until the -- operation is acknowledged by asserting the 'ack' signal. All operations except GET_MIN_SN and GET_MAX_SN need to also -- set the 'seq_nr_hc' along with the 'start_hc' signal (Denotes the SN for which the operation is relevant). After the -- operation is completed, the 'done' signal is asserted for one clock cycle, and the return status can be found in the -- 'ret' signal on the same clock cycle. On a GET_CACHE_CHANGE operation if the CacheChange also has data (determinable -- from the CacheChange kind), it can be requested by asserting the 'get_data_hc' signal on the same clock cycle the -- 'done' signal is asserted. Asserting 'get_data_hc' on a CacheChange with no data is silently ignored. The requested -- data is transferred using a valid/ready schema. The 'valid' signal is asserted whenever the data signal contains -- valid data, and if the 'ready' signal is asserted, the data is considered latched by the recipient. An asserted -- 'last_word' signal marks the last word of the transaction. The transferred data is the payload of the DATA RTPS -- Submessage. From the point the operation is done ('done' signal asserted) until the acknowledgement of the next -- operation ('ack' asserted), the 'cc_*' signals are valid and contain information on the CacheChange for the GET_* -- operations. -- The allowed DDS (user) operations are REGISTER_INSTANCE, WRITE, DISPOSE, UNREGISTER_INSTANCE, LOOKUP_INSTANCE, -- WAIT_FOR_ACKNOWLEDGEMENTS, GET_OFFERED_DEADLINE_MISSED_STATUS, ASSERT_LIVELINESS, GET_LIVELINESS_LOST_STATUS. -- The description of the operations, their inputs, and outputs can be taken directly from the DDS specification. -- Instances are added to the instance memory either directly through the REGISTER_INSTANCE operation, or indirectly -- through the WRITE operation with an HANDLE_NIL instance handle. For this reason a KEY HOLDER is instantiated for -- each DDS Writer, which is fed the payload and calculates the Key Hash of the instance. If the instance memory is -- full, the first stale instance is removed to make space for the new instance. An instance is stale if all the -- associated samples in the sample memory are acknowledged and the instance state is UNREGISTERED. If no stale instance -- is available, the operations are rejected. -- Samples are added with the WRITE, DISPOSE, and UNREGISTER_INSTANCE operations. -- Because these operations can be called with instance handle HANDLE_NIL, which means that the instance handle has to -- be calculated from the provided data before the ACCEPT/REJECT decision for the sample can be made, the sample and -- its associated payload has to be temporarily buffered. This is solved by extending both the sample memory and payload -- memory by one slot, that is not counted towards the RESOURCE_LIMITS QoS. -- Even though the meta-information stored in the sample memory is always the same size, the same can not be said for the -- payload, which can have (depending on the associated IDL type) a more dynamic size. Despite that, the payload memory -- also works with fixed-size slots. If a payload is bigger it just occupies multiple linked memory slots. If the end -- of the payload is not aligned with the end of the memory slot (which is always know due to the fixed-size nature), the -- end address of the payload is stored in the end of the memory slot. This dynamic nature of the payload arises the -- situation, that during a WRITE operation a sample memory slot is available, but all payload memory slots are -- occupied. In this situation (depending on the configured QoS) either the operation is directly rejected, or the -- oldest (ACKed) sample is removed from the memories. Note that since the oldest sample may have no associated payload, -- multiple sample removals may be triggered. Also note that this happens also when the sample to be added has no -- associated payload, since we cannot know this in advance. On the other hand, because this action is preliminary and -- before the actual decision based on the sample to be added (which again may reject the operation or remove a specific -- sample), a situation may arise were a single DDS operation may trigger multiple sample removals (one/multiple to make -- space for the payload, and one based on the sample to be added, like maximum number of samples per instance). -- Similar to the RTPS operations, the 'start' signal is asserted with the respective opcode in 'opcode' to start an -- operation until the 'ack' signal is asserted, and an asserted 'done' signal signifies the end of the operation with -- the return status found in the 'return_code' signal on the same clock cycle. The WRITE, DISPOSE, and -- UNREGISTER_INSTANCE operations also expect valid 'instance_handle_in' and 'source_ts' signals, whereas the -- WAIT_FOR_ACKNOWLEDGEMENTS operation expects a valid 'max_wait' signal (while the 'start' signal is asserted). -- The WRITE, DISPOSE, UNREGISTER_INSTANCE, REGISTER_INSTANCE, and LOOKUP_INSTANCE operation are followed by a data -- transfer of the actual sample payload (using the valid/ready schema) after the acknowledgment of the operations -- ('ack' signal asserted). After completion ('done' signal asserted), the GET_* operations initiate a data transfer -- (using valid/ready schema like for the RTPS operations) for the requested data (see below for output format). -- NOTE: The DISPOSE and UNREGISTER_INSTANCE DDS operations, unlike in the DDS specification, always need the sample -- data to be provided, not depending on if the provided instance_handle is HANDLE_NIL. -- NOTE: The 'max_wait' signal is only used for the WAIT_FOR_ACKNOWLEDGEMENTS operation. All other operations reject -- without delay. -- NOTE: This entity makes no special distinction on the configured RELIABILITY QoS, and thus depends on the RTPS -- Writer to also ACK CacheChanges when BEST_EFFORT RELIABILITY is used. -- NOTE: One could argue that the sample memory does not actually contain DDS samples, but RTPS CacheChanges. -- GET_OFFERED_DEADLINE_MISSED_STATUS DATA FORMAT -- ============================================== -- 31............24..............16..............8...............0 -- | | | | | -- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- +---------------------------------------------------------------+ -- 01| TOTAL_COUNT | -- +---------------------------------------------------------------+ -- 02| TOTAL_COUNT_CHANGE | -- +---------------------------------------------------------------+ -- 03| | -- + + -- 04| | -- + LAST_INSTANCE_HANDLE + -- 05| | -- + + -- 06| | -- +---------------------------------------------------------------+ -- -- GET_LIVELINESS_LOST_STATUS DATA FORMAT -- ====================================== -- 31............24..............16..............8...............0 -- | | | | | -- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- +---------------------------------------------------------------+ -- 01| TOTAL_COUNT | -- +---------------------------------------------------------------+ -- 02| TOTAL_COUNT_CHANGE | -- +---------------------------------------------------------------+ -- MEMORY LAYOUT -- This entity is using double linked lists of fixed-size memory frames for the sample and instance memories, while -- using single linked list for the payload memory. -- 2 lists of frames are kept for the sample and instance memories, one for the empty frames, and one for the occupied -- frames, whereas only one list for the empty frames is kept for the payload memory. -- The memory frames have following structure: -- SAMPLE DATA MEMORY FORMAT -- ========================= -- 31............24..............16..............8...............0 -- | | | | | -- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- +---------------------------------------------------------------+ -- 01| STATUS_INFO | -- +---------------------------------------------------------------+ -- 02| | -- + SEQ_NR + -- 03| | -- +---------------------------------------------------------------+ -- 04| | -- + TIMESTAMP + -- 05| | -- +---------------------------------------------------------------+ -- 06| | -- + LIFESPAN_DEADLINE + -- 07| [only if LIFESPAN /= INFINITE] | -- +---------------------------------------------------------------+ -- 08| PAYLOAD_ADDRESS | -- +---------------------------------------------------------------+ -- 09| INSTANCE_ADDRESS [only if WITH_KEY] | -- +---------------------------------------------------------------+ -- 10| PREV_ADDRESS | -- +---------------------------------------------------------------+ -- 11| 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 DATA Payload -- A...Associated Payload is aligned (Payload does extend until end of last Payload 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) -- INSTANCE DATA MEMORY FORMAT -- =========================== -- 31............24..............16..............8...............0 -- | | | | | -- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- +---------------------------------------------------------------+ -- 01| NEXT_ADDRESS | -- +---------------------------------------------------------------+ -- 02| PREV_ADDRESS | -- +---------------------------------------------------------------+ -- 03| | -- + + -- 04| | -- + KEY_HASH + -- 05| | -- + + -- 06| | -- +---------------------------------------------------------------+ -- 07| STATUS_INFO | -- +---------------------------------------------------------------+ -- 08| SAMPLE_COUNT | -- +---------------------------------------------------------------+ -- 09| ACK_COUNT | -- +---------------------------------------------------------------+ -- -- STATUS INFO -- ----------- -- 31............24..............16..............8...............0 -- | | | | | -- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- +---------------------------------------------------------+-+-+-+ -- | UNUSED |L|U|D| -- +---------------------------------------------------------+-+-+-+ -- D...DISPOSED -- W...UNREGISTERED -- L...LIVELINESS FLAG -- PAYLOAD DATA MEMORY FORMAT -- ========================== -- 31............24..............16..............8...............0 -- | | | | | -- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -- +---------------------------------------------------------------+ -- 01| NEXT_ADDRESS | -- +---------------------------------------------------------------+ -- 02| | -- ~ PAYLOAD ~ -- **| | -- +---------------------------------------------------------------+ entity dds_writer is generic ( NUM_WRITERS : natural; CONFIG_ARRAY : QUARTUS_CONFIG_ARRAY_TYPE -- HISTORY_QOS -- DEADLINE_QOS -- LIFESPAN_QOS -- LEASE_DURATION -- WITH_KEY -- MAX_SAMPLES -- MAX_INSTANCES -- MAX_SAMPLES_PER_INSTANCE -- MAX_PAYLOAD_SIZE ); port ( -- SYSTEM clk : in std_logic; reset : in std_logic; time : in TIME_TYPE; -- TO/FROM RTPS ENDPOINT start_rtps : in std_logic_vector(0 to NUM_WRITERS-1); opcode_rtps : in HISTORY_CACHE_OPCODE_ARRAY_TYPE(0 to NUM_WRITERS-1); ack_rtps : out std_logic_vector(0 to NUM_WRITERS-1); done_rtps : out std_logic_vector(0 to NUM_WRITERS-1); ret_rtps : out HISTORY_CACHE_RESPONSE_ARRAY_TYPE(0 to NUM_WRITERS-1); seq_nr_rtps : in SEQUENCENUMBER_ARRAY_TYPE(0 to NUM_WRITERS-1); get_data_rtps : in std_logic_vector(0 to NUM_WRITERS-1); data_out_rtps : out WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); valid_out_rtps : out std_logic_vector(0 to NUM_WRITERS-1); ready_out_rtps : in std_logic_vector(0 to NUM_WRITERS-1); last_word_out_rtps : out std_logic_vector(0 to NUM_WRITERS-1); liveliness_assertion : out std_logic_vector(0 to NUM_WRITERS-1); data_available : out std_logic_vector(0 to NUM_WRITERS-1); -- Cache Change cc_instance_handle : out INSTANCE_HANDLE_ARRAY_TYPE(0 to NUM_WRITERS-1); cc_kind : out CACHE_CHANGE_KIND_ARRAY_TYPE(0 to NUM_WRITERS-1); cc_source_timestamp : out TIME_ARRAY_TYPE(0 to NUM_WRITERS-1); cc_seq_nr : out SEQUENCENUMBER_ARRAY_TYPE(0 to NUM_WRITERS-1); -- TO/FROM USER ENTITY start_dds : in std_logic_vector(0 to NUM_WRITERS-1); ack_dds : out std_logic_vector(0 to NUM_WRITERS-1); opcode_dds : in DDS_WRITER_OPCODE_ARRAY_TYPE(0 to NUM_WRITERS-1); instance_handle_in_dds : in INSTANCE_HANDLE_ARRAY_TYPE(0 to NUM_WRITERS-1); source_ts_dds : in TIME_ARRAY_TYPE(0 to NUM_WRITERS-1); max_wait_dds : in DURATION_ARRAY_TYPE(0 to NUM_WRITERS-1); done_dds : out std_logic_vector(0 to NUM_WRITERS-1); return_code_dds : out RETURN_CODE_ARRAY_TYPE(0 to NUM_WRITERS-1); instance_handle_out_dds : out INSTANCE_HANDLE_ARRAY_TYPE(0 to NUM_WRITERS-1); valid_in_dds : in std_logic_vector(0 to NUM_WRITERS-1); ready_in_dds : out std_logic_vector(0 to NUM_WRITERS-1); data_in_dds : in WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); last_word_in_dds : in std_logic_vector(0 to NUM_WRITERS-1); valid_out_dds : out std_logic_vector(0 to NUM_WRITERS-1); ready_out_dds : in std_logic_vector(0 to NUM_WRITERS-1); data_out_dds : out WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); last_word_out_dds : out std_logic_vector(0 to NUM_WRITERS-1); -- Communication Status status : out STATUS_KIND_ARRAY_TYPE(0 to NUM_WRITERS-1) ); end entity; architecture arch of dds_writer is constant CONFIG_ARRAY_T : QUARTUS_CONFIG_ARRAY_TYPE(0 to NUM_WRITERS-1) := CONFIG_ARRAY; --*****COMPONENT DECLARATION***** component key_holder is port ( -- SYSTEM clk : in std_logic; reset : in std_logic; -- CONTROL start : in std_logic; opcode : in KEY_HOLDER_OPCODE_TYPE; ack : out std_logic; decode_error : out std_logic; abort : in std_logic; -- INPUT ready_in : out std_logic; valid_in : in std_logic; data_in : in std_logic_vector(WORD_WIDTH-1 downto 0); last_word_in : in std_logic; -- OUTPUT ready_out : in std_logic; valid_out : out std_logic; data_out : out std_logic_vector(WORD_WIDTH-1 downto 0); last_word_out : out std_logic ); end component; type NATURAL_ARRAY_TYPE is array (0 to NUM_WRITERS-1) of natural; function get_max_samples(qos : QUARTUS_CONFIG_ARRAY_TYPE) return natural is variable ret : natural := 0; begin assert (qos'length = NUM_WRITERS) severity FAILURE; for i in 0 to NUM_WRITERS-1 loop if (unsigned(qos(i).MAX_SAMPLES) > ret) then ret := to_integer(unsigned(qos(i).MAX_SAMPLES)); end if; end loop; return ret; end function; type MAX_SAMPLES_NATURAL_ARRAY_TYPE is array (0 to NUM_WRITERS-1) of natural range 0 to get_max_samples(CONFIG_ARRAY_T)+1; function get_max_instances(qos : QUARTUS_CONFIG_ARRAY_TYPE) return natural is variable ret : natural := 0; begin assert (qos'length = NUM_WRITERS) severity FAILURE; for i in 0 to NUM_WRITERS-1 loop if (unsigned(qos(i).MAX_INSTANCES) > ret) then ret := to_integer(unsigned(qos(i).MAX_INSTANCES)); end if; end loop; return ret; end function; type MAX_INSTANCES_NATURAL_ARRAY_TYPE is array (0 to NUM_WRITERS-1) of natural range 0 to get_max_instances(CONFIG_ARRAY_T); --*****CONSTANT DECLARATION***** -- NOTE: Because we need to first determine the Instance before making the ACCEPT/REJECT/DROP decision -- we need to latch the cache change first, calculate the Key Hash if necessary, fetch the associated -- Instance, and then decide on it. This in effect means that we always need an extra slot in sample and -- payload memory that is only used as a latch. -- *SAMPLE MEMORY* -- 4-Byte Word Size of a Sample Info Entry in Memory constant SAMPLE_FRAME_SIZE : natural := 11; -- Sample Info Memory Size in 4-Byte Words function gen_sample_memory_size(qos : QUARTUS_CONFIG_ARRAY_TYPE; size : natural) return NATURAL_ARRAY_TYPE is variable ret : NATURAL_ARRAY_TYPE; begin assert (qos'length = NUM_WRITERS) severity FAILURE; for i in 0 to NUM_WRITERS-1 loop ret(i) := to_integer(unsigned(qos(i).MAX_SAMPLES)+1) * size; end loop; return ret; end function; constant SAMPLE_MEMORY_SIZE : NATURAL_ARRAY_TYPE := gen_sample_memory_size(CONFIG_ARRAY_T,SAMPLE_FRAME_SIZE); -- Sample Info Memory Address Width function get_max_sample_memory_size(sizes : NATURAL_ARRAY_TYPE) return natural is variable ret : natural := 0; begin for i in 0 to NUM_WRITERS-1 loop if (sizes(i) > ret) then ret := sizes(i); end if; end loop; return ret; end function; constant SAMPLE_MEMORY_ADDR_WIDTH : natural := log2c(get_max_sample_memory_size(SAMPLE_MEMORY_SIZE)); type SAMPLE_MEMORY_ADDR_ARRAY_TYPE is array (0 to NUM_WRITERS-1) of unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0); -- Highest Sample Info Memory Address constant SAMPLE_MEMORY_MAX_ADDRESS : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(get_max_sample_memory_size(SAMPLE_MEMORY_SIZE)-1, SAMPLE_MEMORY_ADDR_WIDTH); -- Highest Sample Info Frame Address function gen_max_sample_address(sizes : NATURAL_ARRAY_TYPE; size : natural) return SAMPLE_MEMORY_ADDR_ARRAY_TYPE is variable ret : SAMPLE_MEMORY_ADDR_ARRAY_TYPE; begin for i in 0 to NUM_WRITERS-1 loop ret(i) := to_unsigned(sizes(i) - size, SAMPLE_MEMORY_ADDR_WIDTH); end loop; return ret; end function; constant MAX_SAMPLE_ADDRESS : SAMPLE_MEMORY_ADDR_ARRAY_TYPE := gen_max_sample_address(SAMPLE_MEMORY_SIZE, SAMPLE_FRAME_SIZE); -- Address pointing to the beginning of the first Sample Data Frame constant FIRST_SAMPLE_ADDRESS : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); -- *PAYLOAD MEMORY* function gen_payload_frame_size(qos : QUARTUS_CONFIG_ARRAY_TYPE) return NATURAL_ARRAY_TYPE is variable ret : NATURAL_ARRAY_TYPE; begin assert (qos'length = NUM_WRITERS) severity FAILURE; for i in 0 to NUM_WRITERS-1 loop ret(i) := round_div(qos(i).MAX_PAYLOAD_SIZE + 4, WORD_WIDTH/BYTE_WIDTH); -- (+ NEXT ADDR Field) end loop; return ret; end function; constant PAYLOAD_FRAME_SIZE : NATURAL_ARRAY_TYPE := gen_payload_frame_size(CONFIG_ARRAY_T); -- Payload Memory Size in 4-Byte Words function gen_payload_memory_size(qos : QUARTUS_CONFIG_ARRAY_TYPE; size : NATURAL_ARRAY_TYPE) return NATURAL_ARRAY_TYPE is variable ret : NATURAL_ARRAY_TYPE; begin assert (qos'length = NUM_WRITERS) severity FAILURE; for i in 0 to NUM_WRITERS-1 loop ret(i) := to_integer(unsigned(qos(i).MAX_SAMPLES)+1) * size(i); end loop; return ret; end function; constant PAYLOAD_MEMORY_SIZE : NATURAL_ARRAY_TYPE := gen_payload_memory_size(CONFIG_ARRAY_T, PAYLOAD_FRAME_SIZE); -- Payload Memory Address Width function get_max_payload_memory_size(sizes : NATURAL_ARRAY_TYPE) return natural is variable ret : natural := 0; begin for i in 0 to NUM_WRITERS-1 loop if (sizes(i) > ret) then ret := sizes(i); end if; end loop; return ret; end function; constant PAYLOAD_MEMORY_ADDR_WIDTH : natural := log2c(get_max_payload_memory_size(PAYLOAD_MEMORY_SIZE)); type PAYLOAD_MEMORY_ADDR_ARRAY_TYPE is array (0 to NUM_WRITERS-1) of unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0); -- Highest Payload Memory Address constant PAYLOAD_MEMORY_MAX_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(get_max_payload_memory_size(PAYLOAD_MEMORY_SIZE)-1, PAYLOAD_MEMORY_ADDR_WIDTH); -- Highest Payload Frame Address function gen_max_payload_address(sizes : NATURAL_ARRAY_TYPE; size : NATURAL_ARRAY_TYPE) return PAYLOAD_MEMORY_ADDR_ARRAY_TYPE is variable ret : PAYLOAD_MEMORY_ADDR_ARRAY_TYPE; begin for i in 0 to NUM_WRITERS-1 loop ret(i) := to_unsigned(sizes(i) - size(i), PAYLOAD_MEMORY_ADDR_WIDTH); end loop; return ret; end function; constant MAX_PAYLOAD_ADDRESS : PAYLOAD_MEMORY_ADDR_ARRAY_TYPE := gen_max_payload_address(PAYLOAD_MEMORY_SIZE, PAYLOAD_FRAME_SIZE); -- Address pointing to the beginning of the first Payload Data Frame constant FIRST_PAYLOAD_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); -- *INSTANCE MEMORY* -- 4-Byte Word Size of a Instance Entry in Memory constant INSTANCE_FRAME_SIZE : natural := 9; -- Instance Memory Size in 4-Byte Words function gen_instance_memory_size(qos : QUARTUS_CONFIG_ARRAY_TYPE; size : natural) return NATURAL_ARRAY_TYPE is variable ret : NATURAL_ARRAY_TYPE; begin assert (qos'length = NUM_WRITERS) severity FAILURE; for i in 0 to NUM_WRITERS-1 loop if (qos(i).WITH_KEY) then ret(i) := to_integer(unsigned(qos(i).MAX_INSTANCES)) * size; else ret(i) := size; end if; end loop; return ret; end function; constant INSTANCE_MEMORY_SIZE : NATURAL_ARRAY_TYPE := gen_instance_memory_size(CONFIG_ARRAY_T, INSTANCE_FRAME_SIZE); -- Instance Memory Address Width function get_max_instance_memory_size(sizes : NATURAL_ARRAY_TYPE) return natural is variable ret : natural := 0; begin for i in 0 to NUM_WRITERS-1 loop if (sizes(i) > ret) then ret := sizes(i); end if; end loop; return ret; end function; constant INSTANCE_MEMORY_ADDR_WIDTH : natural := log2c(get_max_instance_memory_size(INSTANCE_MEMORY_SIZE)); type INSTANCE_MEMORY_ADDR_ARRAY_TYPE is array (0 to NUM_WRITERS-1) of unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); -- Highest Instance Memory Address constant INSTANCE_MEMORY_MAX_ADDRESS: unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(get_max_instance_memory_size(INSTANCE_MEMORY_SIZE)-1, INSTANCE_MEMORY_ADDR_WIDTH); -- Highest Instance Frame Address function gen_max_instance_address(sizes : NATURAL_ARRAY_TYPE; size : natural) return INSTANCE_MEMORY_ADDR_ARRAY_TYPE is variable ret : INSTANCE_MEMORY_ADDR_ARRAY_TYPE; begin for i in 0 to NUM_WRITERS-1 loop ret(i) := to_unsigned(sizes(i) - size, INSTANCE_MEMORY_ADDR_WIDTH); end loop; return ret; end function; constant MAX_INSTANCE_ADDRESS : INSTANCE_MEMORY_ADDR_ARRAY_TYPE := gen_max_instance_address(INSTANCE_MEMORY_SIZE, INSTANCE_FRAME_SIZE); -- 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 FIELD OFFSETS* -- 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 := 7; constant SMF_INSTANCE_ADDR_OFFSET : natural := 8; constant SMF_PREV_ADDR_OFFSET : natural := 9; constant SMF_NEXT_ADDR_OFFSET : natural := 10; -- *PAYLOAD MEMORY FRAME FIELD OFFSETS* -- 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 FIELD OFFSETS* -- 4-Byte Word Offsets to Beginning of Respective Fields in the Endpoint Memory Frame constant IMF_NEXT_ADDR_OFFSET : natural := 0; constant IMF_PREV_ADDR_OFFSET : natural := 1; constant IMF_KEY_HASH_OFFSET : natural := 2; constant IMF_STATUS_INFO_OFFSET : natural := 6; constant IMF_SAMPLE_CNT_OFFSET : natural := 7; constant IMF_ACK_CNT_OFFSET : natural := 8; -- *INSTANCE MEMORY FRAME FIELD 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, PROCESS_INPUT, GET_SERIALIZED_KEY, NEXT_PAYLOAD_SLOT, ALIGN_PAYLOAD, GET_KEY_HASH, INITIATE_INSTANCE_SEARCH, REGISTER_OPERATION, LOOKUP_OPERATION, PUSH_KEY_HASH, FILTER_STAGE, UPDATE_INSTANCE, CHECK_ACK_WAIT, FINALIZE_PAYLOAD, FINALIZE_SAMPLE, GET_OLDEST_SAMPLE_INSTANCE, FIND_SAMPLE, REMOVE_ORPHAN_SAMPLES, REMOVE_SAMPLE, POST_SAMPLE_REMOVE, SKIP_AND_RETURN, SKIP, REMOVE_STALE_INSTANCE, GET_SEQ_NR, FIND_SEQ_NR, ACKNACK_SAMPLE, GET_SAMPLE, GET_PAYLOAD, CHECK_LIFESPAN, GET_LIVELINESS_LOST_STATUS, GET_OFFERED_DEADLINE_MISSED_STATUS, CHECK_DEADLINE, CHECK_LIVELINESS, RESET_SAMPLE_MEMORY, RESET_PAYLOAD_MEMORY); -- Instance Memory FSM states. Explained below in detail type INST_STAGE_TYPE is (IDLE, SEARCH_INSTANCE, GET_NEXT_INSTANCE, GET_INSTANCE_DATA, INSERT_INSTANCE, UPDATE_INSTANCE, REMOVE_INSTANCE, RESET_MEMORY); -- *Instance Memory Opcodes* -- OPCODE DESCRIPTION -- SEARCH_INSTANCE Search Instance based on Key Hash pointed by "inst_r.key_hash". -- Set "inst_data.addr" to Base Address of found Instance, or INSTANCE_MEMORY_MAX_ADDRESS if nothing found. -- "inst_data" contains Instance Data according to "inst_r.field_flags". -- INSERT_INSTANCE Insert Instance to memory. -- UPDATE_INSTANCE Update Instance Data pointed by "inst_data.addr" according to "inst_r.field_flags" -- GET_INSTANCE Get Data of Instance pointed by "inst_r.addr" according to "inst_r.field_flags". -- Already fetched Data of the Participant is not modified. -- GET_NEXT_INSTANCE Get Instance Data of next Instance (from the Instance pointed by "inst_data.addr") according to "inst_r.field_flags". -- Set "inst_data.addr" to Address of Instance or INSTANCE_MEMORY_MAX_ADDRESS if no other Instance in Memory. -- REMOVE_INSTANCE Remove Instance pointed by "inst_data.addr". -- "inst_data.addr" is set to the next Instance (or INSTANCE_MEMORY_MAX_ADDRESS if no next Instance exists) type INSTANCE_OPCODE_TYPE is (NOP, SEARCH_INSTANCE, INSERT_INSTANCE, UPDATE_INSTANCE, GET_INSTANCE, GET_NEXT_INSTANCE, REMOVE_INSTANCE); -- Record of Instance Data type INSTANCE_DATA_TYPE is record i : natural range 0 to NUM_WRITERS-1; addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); key_hash : KEY_HASH_TYPE; status_info : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); sample_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0); ack_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0); field_flags : std_logic_vector(0 to IMF_FLAG_WIDTH-1); end record; -- Zero initialized Endpoint Data constant ZERO_INSTANCE_DATA : INSTANCE_DATA_TYPE := ( i => 0, addr => INSTANCE_MEMORY_MAX_ADDRESS, key_hash => KEY_HASH_NIL, status_info => (others => '0'), sample_cnt => (others => '0'), ack_cnt => (others => '0'), field_flags => (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'; signal sample_addr_i : SAMPLE_MEMORY_ADDR_ARRAY_TYPE; signal sample_read_i : std_logic_vector(0 to NUM_WRITERS-1); signal sample_read_data_i, sample_write_data_i : WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); signal sample_ready_in_i, sample_valid_in_i : std_logic_vector(0 to NUM_WRITERS-1); signal sample_ready_out_i, sample_valid_out_i : std_logic_vector(0 to NUM_WRITERS-1); signal sample_abort_read_i : std_logic_vector(0 to NUM_WRITERS-1); -- *PAYLOAD MEMORY CONNECTION SIGNALS* signal payload_addr : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0); signal payload_read : std_logic; signal payload_read_data, payload_write_data : std_logic_vector(WORD_WIDTH-1 downto 0); signal payload_ready_in, payload_valid_in : std_logic; signal payload_ready_out, payload_valid_out : std_logic; signal payload_abort_read : std_logic; signal payload_addr_i : PAYLOAD_MEMORY_ADDR_ARRAY_TYPE; signal payload_read_i : std_logic_vector(0 to NUM_WRITERS-1); signal payload_read_data_i, payload_write_data_i : WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); signal payload_ready_in_i, payload_valid_in_i : std_logic_vector(0 to NUM_WRITERS-1); signal payload_ready_out_i, payload_valid_out_i : std_logic_vector(0 to NUM_WRITERS-1); signal payload_abort_read_i : std_logic_vector(0 to NUM_WRITERS-1); -- *INSTANCE MEMORY CONNECTION SIGNALS* signal inst_addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); signal inst_read : std_logic; signal inst_read_data, inst_write_data : std_logic_vector(WORD_WIDTH-1 downto 0); signal inst_ready_in, inst_valid_in : std_logic; signal inst_ready_out, inst_valid_out : std_logic; signal inst_abort_read : std_logic; signal inst_addr_i : INSTANCE_MEMORY_ADDR_ARRAY_TYPE; signal inst_read_i : std_logic_vector(0 to NUM_WRITERS-1); signal inst_read_data_i, inst_write_data_i : WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); signal inst_ready_in_i, inst_valid_in_i : std_logic_vector(0 to NUM_WRITERS-1); signal inst_ready_out_i, inst_valid_out_i : std_logic_vector(0 to NUM_WRITERS-1); signal inst_abort_read_i : std_logic_vector(0 to NUM_WRITERS-1); -- *KEY HOLDER CONNECTION SIGNALS* signal start_kh, ack_kh, valid_in_kh, ready_in_kh, last_word_in_kh, valid_out_kh, ready_out_kh, last_word_out_kh, abort_kh, decode_error_kh : std_logic_vector(0 to NUM_WRITERS-1); signal opcode_kh : KEY_HOLDER_OPCODE_ARRAY_TYPE(0 to NUM_WRITERS-1); signal data_in_kh, data_out_kh : WORD_ARRAY_TYPE(0 to NUM_WRITERS-1); -- *MAIN PROCESS* -- FSM state signal stage, stage_next : STAGE_TYPE; -- FSM state latch. Used to transition dynamically to different states from the same state. signal return_stage, return_stage_next : STAGE_TYPE; -- General Purpose Counter signal cnt, cnt_next : natural range 0 to 14; -- Counter used to read/write Payload Fames signal cnt2, cnt2_next : natural range 0 to max(get_max_payload_memory_size(PAYLOAD_FRAME_SIZE), INSTANCE_HANDLE_TYPE'length-1); -- Counter used to read/write Payload Fames signal cnt3, cnt3_next : natural range 0 to get_max_payload_memory_size(PAYLOAD_FRAME_SIZE); -- Head of Empty Sample List signal empty_sample_list_head, empty_sample_list_head_next : SAMPLE_MEMORY_ADDR_ARRAY_TYPE; -- Tail of Empty Sample List signal empty_sample_list_tail, empty_sample_list_tail_next : SAMPLE_MEMORY_ADDR_ARRAY_TYPE; -- Head of Empty Payload List signal empty_payload_list_head, empty_payload_list_head_next : PAYLOAD_MEMORY_ADDR_ARRAY_TYPE; -- Oldest Sample (Head of Occupied Sample List) signal oldest_sample, oldest_sample_next : SAMPLE_MEMORY_ADDR_ARRAY_TYPE; -- Newest Sample (Tail of Occupied Sample List) signal newest_sample, newest_sample_next : SAMPLE_MEMORY_ADDR_ARRAY_TYPE; -- Denotes if the oldest Sample should be removed signal remove_oldest_sample, remove_oldest_sample_next : std_logic; -- 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; -- Denotes if the Sample to be removed should be ACKed signal remove_ack_sample, remove_ack_sample_next : std_logic; -- Lifespan Latch signal lifespan, lifespan_next : TIME_TYPE; -- Key hash Latch signal key_hash, key_hash_next : KEY_HASH_TYPE; -- Return Code Latch signal return_code_latch, return_code_latch_next : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0); -- Instance Handle Latch signal instance_handle, instance_handle_next : INSTANCE_HANDLE_TYPE; -- Source Timestamp Latch signal source_ts, source_ts_next : TIME_TYPE; -- Sequence Number Latch signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE; -- Sample Status Info Latch signal sample_status_info, sample_status_info_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); -- General Purpose Payload Pointer signal payload_addr_latch_1, payload_addr_latch_1_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Payload Pointer signal payload_addr_latch_2, payload_addr_latch_2_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Sample Pointer signal sample_addr_latch_1, sample_addr_latch_1_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Sample Pointer signal sample_addr_latch_2, sample_addr_latch_2_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Sample Pointer signal sample_addr_latch_3, sample_addr_latch_3_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Sample Pointer signal sample_addr_latch_4, sample_addr_latch_4_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Instance Pointer signal inst_addr_latch_1, inst_addr_latch_1_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Instance Pointer signal inst_addr_latch_2, inst_addr_latch_2_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Long Latch signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); -- Signals start of Instance Memory Operation signal inst_op_start : std_logic; -- Opcode of Instance Memory Operation (Valid only when inst_op_start is high) signal inst_opcode : INSTANCE_OPCODE_TYPE; -- Signals the end of an Instance Memory Operation signal inst_op_done : std_logic; -- Signal used to pass data to instance memory process signal inst_r : INSTANCE_DATA_TYPE; -- Time of next Sample Lifespan Check signal lifespan_time, lifespan_time_next : TIME_TYPE; -- Signifies if a Lifespan Check is in progress signal is_lifespan_check, is_lifespan_check_next : std_logic; -- 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_ARRAY_TYPE(0 to NUM_WRITERS-1); -- Signal containing the current number of stored samples signal global_sample_cnt, global_sample_cnt_next : MAX_SAMPLES_NATURAL_ARRAY_TYPE; -- Signal containing the current number of ACKed stored samples signal global_ack_cnt, global_ack_cnt_next : MAX_SAMPLES_NATURAL_ARRAY_TYPE; -- Signal containing the number of currently stale Instances signal stale_inst_cnt, stale_inst_cnt_next : MAX_INSTANCES_NATURAL_ARRAY_TYPE; -- Signifies if a Instance Register Operation is in progress signal register_op, register_op_next : std_logic; -- Signifies if a Instance Lookup Operation is in progress signal lookup_op, lookup_op_next : std_logic; -- Signifies if a WAIT_FOR_ACKNOWLEDGEMENTS Operation is in progress signal ack_wait, ack_wait_next : std_logic_vector(0 to NUM_WRITERS-1); -- Triggers an ACK Wait Check signal ack_wait_check, ack_wait_check_next : std_logic; -- Time of next Timeout Check Trigger signal timeout_check_time, timeout_check_time_next : TIME_TYPE; -- Timeout time for DDS Operation signal timeout_time, timeout_time_next : TIME_ARRAY_TYPE(0 to NUM_WRITERS-1); -- Signal used to differentiate between ACK and NACK Operations signal is_ack, is_ack_next : std_logic; -- Signal used to differentiate between RTPS and DDS Operations signal is_rtps, is_rtps_next : std_logic; -- Signifies if new Samples are available for RTPS Writer signal data_available_sig, data_available_sig_next : std_logic_vector(0 to NUM_WRITERS-1); -- Denotes if Orphan Samples (of an removed stale instance) need to be removed signal orphan_samples, orphan_samples_next : std_logic; -- Signal used to index the writers signal ind, ind_next : natural range 0 to NUM_WRITERS-1; -- Denotes if payload from input is stored in payload memory signal store_payload, store_payload_next : std_logic; -- Denotes if calculated serialized key is stored in payload memory (Mutually Exclusive with 'store_payload') signal store_serialized_key, store_serialized_key_next : std_logic; -- Denotes if a Key Holder Operation is necessary, and thus if the input payload need to be pushed to the Key Holder. signal need_kh_op, need_kh_op_next : std_logic; -- Test signals used in testbenches signal idle_sig : std_logic; signal empty_inst_head_sig : NATURAL_ARRAY_TYPE; signal empty_sample_head_sig : NATURAL_ARRAY_TYPE; signal empty_payload_head_sig : NATURAL_ARRAY_TYPE; -- *COMMUNICATION STATUS* signal status_sig, status_sig_next : STATUS_KIND_ARRAY_TYPE(0 to NUM_WRITERS-1); -- LIVELINESS LOST STATUS -- Time of next Liveliness Deadline signal lease_check_time, lease_check_time_next : TIME_TYPE; signal lease_deadline, lease_deadline_next : TIME_ARRAY_TYPE(0 to NUM_WRITERS-1); signal liveliness_lost_cnt, liveliness_lost_cnt_next : LIVELINESS_LOST_STATUS_COUNT_ARRAY_TYPE(0 to NUM_WRITERS-1); signal liveliness_lost_cnt_change, liveliness_lost_cnt_change_next : LIVELINESS_LOST_STATUS_COUNT_ARRAY_TYPE(0 to NUM_WRITERS-1); -- SAMPLE REJECT STATUS signal sample_rej_cnt, sample_rej_cnt_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0); signal sample_rej_cnt_change, sample_rej_cnt_change_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0); signal sample_rej_last_reason, sample_rej_last_reason_next : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0); signal sample_rej_last_inst, sample_rej_last_inst_next : INSTANCE_HANDLE_TYPE; -- OFFERED DEADLINE MISSED STATUS -- Time of next Deadline Miss Check signal deadline_check_time , deadline_check_time_next : TIME_TYPE; signal deadline_time, deadline_time_next : TIME_ARRAY_TYPE(0 to NUM_WRITERS-1); signal deadline_miss_cnt, deadline_miss_cnt_next : OFFERED_DEADLINE_MISSED_STATUS_COUNT_ARRAY_TYPE(0 to NUM_WRITERS-1); signal deadline_miss_cnt_change, deadline_miss_cnt_change_next : OFFERED_DEADLINE_MISSED_STATUS_COUNT_ARRAY_TYPE(0 to NUM_WRITERS-1); signal deadline_miss_last_inst, deadline_miss_last_inst_next : INSTANCE_HANDLE_ARRAY_TYPE(0 to NUM_WRITERS-1); -- *CACHE CHANGE* signal cc_instance_handle_sig, cc_instance_handle_sig_next : INSTANCE_HANDLE_TYPE; signal cc_kind_sig, cc_kind_sig_next : CACHE_CHANGE_KIND_TYPE; signal cc_source_timestamp_sig, cc_source_timestamp_sig_next : TIME_TYPE; signal cc_seq_nr_sig, cc_seq_nr_sig_next : SEQUENCENUMBER_TYPE; -- *INSTANCE MEMORY PROCESS* -- Instance Memory FSM state signal inst_stage, inst_stage_next : INST_STAGE_TYPE; -- Pointer to current relevant Instance Memory Frame Address signal inst_addr_base, inst_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); -- General Purpose Instance Memory Address Latch signal inst_addr_latch, inst_addr_latch_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0); -- Head of Empty Instance List signal inst_empty_head, inst_empty_head_next : INSTANCE_MEMORY_ADDR_ARRAY_TYPE; -- Head of Occupied Instance List signal inst_occupied_head, inst_occupied_head_next : INSTANCE_MEMORY_ADDR_ARRAY_TYPE; -- Latch for Instance Data from main process signal inst_latch_data, inst_latch_data_next : INSTANCE_DATA_TYPE; -- Latch for Instance Data from memory signal inst_data, inst_data_next : INSTANCE_DATA_TYPE; -- General Purpose Counter signal inst_cnt, inst_cnt_next : natural range 0 to 13; -- General Purpose Long Latch signal inst_long_latch, inst_long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0); --*****ALIAS DECLARATION***** alias prev_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1; alias prev_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1_next; alias next_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2; alias next_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_2_next; alias cur_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3; alias cur_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_3_next; alias new_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_4; alias new_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 first_payload : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2; alias first_payload_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) is payload_addr_latch_2_next; alias 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) := unsigned(input(i)); end loop; return ret; end function; -- HACK: Due to delta cycle race condition some assertions trigger false positives, -- so we check the signals on the falling edge function stable(clk : std_logic; a : boolean) return boolean is begin if (clk = '0') then return a; else return TRUE; end if; end function; begin --*****COMPONENT INSTANTIATION***** key_holder_gen : for i in 0 to NUM_WRITERS-1 generate key_holder_inst : key_holder port map ( -- SYSTEM clk => clk, reset => reset, -- CONTROL start => start_kh(i), opcode => opcode_kh(i), ack => ack_kh(i), decode_error => decode_error_kh(i), abort => abort_kh(i), -- INPUT ready_in => ready_out_kh(i), valid_in => valid_out_kh(i), data_in => data_out_kh(i), last_word_in => last_word_out_kh(i), -- OUTPUT ready_out => ready_in_kh(i), valid_out => valid_in_kh(i), data_out => data_in_kh(i), last_word_out => last_word_in_kh(i) ); end generate; sample_mem_ctrl_gen : for i in 0 to NUM_WRITERS-1 generate 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(i), MAX_BURST_LENGTH => SAMPLE_FRAME_SIZE ) port map ( clk => clk, reset => reset or sample_abort_read_i(i), addr => std_logic_vector(sample_addr_i(i)), read => sample_read_i(i), ready_in => sample_ready_in_i(i), valid_in => sample_valid_in_i(i), data_in => sample_write_data_i(i), ready_out => sample_ready_out_i(i), valid_out => sample_valid_out_i(i), data_out => sample_read_data_i(i) ); end generate; payload_mem_ctrl_gen : for i in 0 to NUM_WRITERS-1 generate 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(i), MAX_BURST_LENGTH => PAYLOAD_FRAME_SIZE(i) ) port map ( clk => clk, reset => reset or payload_abort_read_i(i), addr => std_logic_vector(payload_addr_i(i)), read => payload_read_i(i), ready_in => payload_ready_in_i(i), valid_in => payload_valid_in_i(i), data_in => payload_write_data_i(i), ready_out => payload_ready_out_i(i), valid_out => payload_valid_out_i(i), data_out => payload_read_data_i(i) ); end generate; instance_mem_ctrl_gen : for i in 0 to NUM_WRITERS-1 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(i), MAX_BURST_LENGTH => INSTANCE_FRAME_SIZE ) port map ( clk => clk, reset => reset or inst_abort_read_i(i), addr => std_logic_vector(inst_addr_i(i)), read => inst_read_i(i), ready_in => inst_ready_in_i(i), valid_in => inst_valid_in_i(i), data_in => inst_write_data_i(i), ready_out => inst_ready_out_i(i), valid_out => inst_valid_out_i(i), data_out => inst_read_data_i(i) ); end generate; inst_memory_mux : process (all) begin inst_abort_read_i <= (others => '0'); inst_addr_i <= (others => (others => '0')); inst_read_i <= (others => '0'); inst_valid_in_i <= (others => '0'); inst_write_data_i <= (others => (others => '0')); inst_ready_out_i <= (others => '0'); inst_abort_read_i(inst_latch_data.i) <= inst_abort_read; inst_addr_i(inst_latch_data.i) <= inst_addr; inst_read_i(inst_latch_data.i) <= inst_read; inst_valid_in_i(inst_latch_data.i) <= inst_valid_in; inst_write_data_i(inst_latch_data.i) <= inst_write_data; inst_ready_out_i(inst_latch_data.i) <= inst_ready_out; inst_ready_in <= inst_ready_in_i(inst_latch_data.i); inst_valid_out <= inst_valid_out_i(inst_latch_data.i); inst_read_data <= inst_read_data_i(inst_latch_data.i); end process; sample_memory_mux : process (all) begin sample_abort_read_i <= (others => '0'); sample_addr_i <= (others => (others => '0')); sample_read_i <= (others => '0'); sample_valid_in_i <= (others => '0'); sample_write_data_i <= (others => (others => '0')); sample_ready_out_i <= (others => '0'); sample_abort_read_i(ind) <= sample_abort_read; sample_addr_i(ind) <= sample_addr; sample_read_i(ind) <= sample_read; sample_valid_in_i(ind) <= sample_valid_in; sample_write_data_i(ind) <= sample_write_data; sample_ready_out_i(ind) <= sample_ready_out; sample_ready_in <= sample_ready_in_i(ind); sample_valid_out <= sample_valid_out_i(ind); sample_read_data <= sample_read_data_i(ind); end process; payload_memory_mux : process (all) begin payload_abort_read_i <= (others => '0'); payload_addr_i <= (others => (others => '0')); payload_read_i <= (others => '0'); payload_valid_in_i <= (others => '0'); payload_write_data_i <= (others => (others => '0')); payload_ready_out_i <= (others => '0'); payload_abort_read_i(ind) <= payload_abort_read; payload_addr_i(ind) <= payload_addr; payload_read_i(ind) <= payload_read; payload_valid_in_i(ind) <= payload_valid_in; payload_write_data_i(ind) <= payload_write_data; payload_ready_out_i(ind) <= payload_ready_out; payload_ready_in <= payload_ready_in_i(ind); payload_valid_out <= payload_valid_out_i(ind); payload_read_data <= payload_read_data_i(ind); end process; status <= status_sig; data_available <= data_available_sig; cc_instance_handle <= (others => cc_instance_handle_sig); cc_kind <= (others => cc_kind_sig); cc_source_timestamp <= (others => cc_source_timestamp_sig); cc_seq_nr <= (others => cc_seq_nr_sig); -- *Main State Machine* -- STATE DESCRIPTION -- IDLE Idle State. Initiates Orphan Sample Check, Deadline Miss Checks, Liveliness Deadline Check, 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) -- PROCESS_INPUT Consume input and push to memory and/or Key Holder (as needed) -- GET_SERIALIZED_KEY Fetch calculated serialized key from the Key Holder -- 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 Holder -- 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 sample (Cache Change) -- FINALIZE_PAYLOAD Finalize the payload addition (Update pointers). -- 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. This is a sample pre-remove stage. -- FIND_SAMPLE Find the specified Sample (Oldest ACKed Sample, Oldest Sample of specific Instance, Oldest ACKed Sample of specific Instance) -- REMOVE_ORPHAN_SAMPLES Remove all Samples of the removed Instance (dead_inst) -- 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_AND_RETURN Skip DDS Input and return latched Return Code -- SKIP Skip DDS Input and return to latched stage. -- 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/Unacknowledged specified Sample -- GET_SAMPLE Push Sample Data to RTPS output -- GET_PAYLOAD Push linked Payload to output, or to the serialized key generator -- 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 -- CHECK_LIVELINESS Check liveliness status of all Writers -- CHECK_ACK_WAIT Check WAIT_FOR_ACKNOWLEDGEMENTS operation exit conditions -- 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; variable tmp_bool : boolean; begin -- DEFAULT Registered stage_next <= stage; oldest_sample_next <= oldest_sample; 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; remove_ack_sample_next <= remove_ack_sample; instance_handle_next <= instance_handle; 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_check_time_next <= deadline_check_time; 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; cnt_next <= cnt; cnt2_next <= cnt2; cnt3_next <= cnt3; 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; ack_wait_check_next <= ack_wait_check; timeout_check_time_next <= timeout_check_time; timeout_time_next <= timeout_time; lease_check_time_next <= lease_check_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; cc_seq_nr_sig_next <= cc_seq_nr_sig; is_ack_next <= is_ack; is_rtps_next <= is_rtps; data_available_sig_next <= data_available_sig; orphan_samples_next <= orphan_samples; key_hash_next <= key_hash; return_code_latch_next <= return_code_latch; ind_next <= ind; store_serialized_key_next <= store_serialized_key; store_payload_next <= store_payload; need_kh_op_next <= need_kh_op; -- DEFAULT Unregistered inst_opcode <= NOP; ret_rtps <= (others => ERROR); return_code_dds <= (others => RETCODE_UNSUPPORTED); opcode_kh <= (others => NOP); instance_handle_out_dds <= (others => HANDLE_NIL); ack_dds <= (others => '0'); done_dds <= (others => '0'); ack_rtps <= (others => '0'); done_rtps <= (others => '0'); inst_op_start <= '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 <= (others => '0'); liveliness_assertion <= (others => '0'); valid_out_rtps <= (others => '0'); last_word_out_rtps <= (others => '0'); valid_out_dds <= (others => '0'); last_word_out_dds <= (others => '0'); start_kh <= (others => '0'); ready_in_kh <= (others => '0'); valid_out_kh <= (others => '0'); last_word_out_kh <= (others => '0'); abort_kh <= (others => '0'); idle_sig <= '0'; data_out_kh <= (others => (others => '0')); sample_addr <= (others => '0'); sample_write_data <= (others => '0'); payload_addr <= (others => '0'); payload_write_data <= (others => '0'); data_out_rtps <= (others => (others => '0')); data_out_dds <= (others => (others => '0')); inst_r <= ZERO_INSTANCE_DATA; case (stage) is when IDLE => idle_sig <= '1'; -- Reset remove_oldest_sample_next <= '0'; remove_oldest_inst_sample_next <= '0'; remove_ack_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(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; cur_sample_next <= oldest_sample(ind); stage_next <= REMOVE_ORPHAN_SAMPLES; cnt_next <= 0; -- DEADLINE QoS elsif (deadline_check_time <= time) then -- Reset deadline_check_time_next <= TIME_INFINITE; ind_next <= 0; stage_next <= CHECK_DEADLINE; cnt_next <= 1; -- CHECK DEADLINE -- Liveliness Deadline elsif (lease_check_time <= time) then -- Reset lease_check_time_next <= TIME_INFINITE; ind_next <= 0; stage_next <= CHECK_LIVELINESS; cnt_next <= 1; -- CHECK LEASE -- WAIT_FOR_ACKNOWLEDGEMENTS Trigger elsif (ack_wait /= (ack_wait'range => '0') and (ack_wait_check = '1' or timeout_check_time <= time)) then ind_next <= 0; -- RESET timeout_check_time_next <= TIME_INFINITE; stage_next <= CHECK_ACK_WAIT; cnt_next <= 1; -- CHECK ACK STATE -- LIFESPAN QoS elsif (lifespan_time <= time) then -- Reset Timeout lifespan_time_next <= TIME_INFINITE; is_lifespan_check_next <= '1'; ind_next <= 0; stage_next <= CHECK_LIFESPAN; cnt_next <= 1; -- CHECK LIFESPAN -- RTPS Operation elsif (start_rtps /= (start_rtps'range => '0')) then if (start_rtps(ind) /= '1') then if (ind = NUM_WRITERS-1) then ind_next <= 0; else ind_next <= ind + 1; end if; else is_rtps_next <= '1'; -- Latch Input Signal seq_nr_next <= seq_nr_rtps(ind); -- Reset is_ack_next <= '0'; case (opcode_rtps(ind)) is when GET_MIN_SN => ack_rtps(ind) <= '1'; if (oldest_sample(ind) = 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; -- Return Code cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN; else cur_sample_next <= oldest_sample(ind); stage_next <= GET_SEQ_NR; cnt_next <= 0; end if; when GET_MAX_SN => ack_rtps(ind) <= '1'; -- Reset Data Availability data_available_sig_next(ind) <= '0'; if (newest_sample(ind) = 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; -- Return Code cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN; else cur_sample_next <= newest_sample(ind); stage_next <= GET_SEQ_NR; cnt_next <= 0; end if; when GET_CACHE_CHANGE => ack_rtps(ind) <= '1'; -- No Samples Available if (newest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then stage_next <= UNKNOWN_SEQ_NR; cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN; else cc_seq_nr_sig_next <= seq_nr_rtps(ind); cur_sample_next <= newest_sample(ind); stage_next <= FIND_SEQ_NR; cnt_next <= 0; return_stage_next <= GET_SAMPLE; end if; when ACK_CACHE_CHANGE => ack_rtps(ind) <= '1'; is_ack_next <= '1'; -- No Samples Available if (newest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then stage_next <= UNKNOWN_SEQ_NR; cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN; else cur_sample_next <= newest_sample(ind); stage_next <= FIND_SEQ_NR; cnt_next <= 0; return_stage_next <= ACKNACK_SAMPLE; end if; when NACK_CACHE_CHANGE => ack_rtps(ind) <= '1'; -- No Samples Available if (newest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then stage_next <= UNKNOWN_SEQ_NR; cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN; else cur_sample_next <= newest_sample(ind); stage_next <= FIND_SEQ_NR; cnt_next <= 0; return_stage_next <= ACKNACK_SAMPLE; end if; when REMOVE_CACHE_CHANGE => ack_rtps(ind) <= '1'; -- No Samples Available if (newest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then stage_next <= UNKNOWN_SEQ_NR; cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN; else cur_sample_next <= newest_sample(ind); stage_next <= FIND_SEQ_NR; cnt_next <= 0; return_stage_next <= REMOVE_SAMPLE; end if; when others => ack_rtps(ind) <= '1'; stage_next <= UNKNOWN_OPERATION_RTPS; end case; end if; -- DDS Operation (Stall DDS Operation if a wait Operation is in progress) elsif (((not ack_wait) and start_dds) /= (start_dds'range => '0')) then if not (ack_wait(ind) = '0' and start_dds(ind) = '1') then if (ind = NUM_WRITERS-1) then ind_next <= 0; else ind_next <= ind + 1; end if; else -- Reset register_op_next <= '0'; instance_handle_next <= HANDLE_NIL; source_ts_next <= TIME_INVALID; sample_status_info_next <= (others => '0'); key_hash_next <= KEY_HASH_NIL; new_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; return_code_latch_next <= RETCODE_UNSUPPORTED; store_serialized_key_next <= '0'; store_payload_next <= '0'; need_kh_op_next <= '0'; case (opcode_dds(ind)) is when REGISTER_INSTANCE => -- Synthesis Guard if (CONFIG_ARRAY_T(ind).WITH_KEY) then need_kh_op_next <= '1'; start_kh(ind) <= '1'; opcode_kh(ind) <= PUSH_DATA; if (ack_kh(ind) = '1') then ack_dds(ind) <= '1'; register_op_next <= '1'; stage_next <= PROCESS_INPUT; cnt_next <= 0; -- Process Input end if; else ack_dds(ind) <= '1'; key_hash_next <= KEY_HASH_NIL; stage_next <= SKIP; return_stage_next <= PUSH_KEY_HASH; end if; when WRITE => ack_dds(ind) <= '1'; -- Reset Liveliness lease_deadline_next(ind) <= time + CONFIG_ARRAY_T(ind).LEASE_DURATION; -- Latch Input Signals key_hash_next <= instance_handle_in_dds(ind); instance_handle_next <= instance_handle_in_dds(ind); source_ts_next <= source_ts_dds(ind); -- NOTE: The ALIGNED_FLAG is set by default. If actual Payload is not aligned, need to reset. sample_status_info_next <= (SSI_DATA_FLAG => '1', SSI_ALIGNED_FLAG => '1', others => '0'); cur_sample_next <= empty_sample_list_head(ind); store_payload_next <= '1'; if (CONFIG_ARRAY_T(ind).WITH_KEY and instance_handle_in_dds(ind) = HANDLE_NIL) then need_kh_op_next <= '1'; end if; -- NOTE: We have to explicitly check the Payload Memory, as it may be "unaligned" with our Sample Memory -- (Sample Memory has available Slot, but Payload Memory not) -- Payload Memory Full if (empty_payload_list_head(ind) = PAYLOAD_MEMORY_MAX_ADDRESS) then if (global_ack_cnt(ind) = 0 and CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- Reject Change stage_next <= SKIP_AND_RETURN; cnt_next <= 0; return_code_latch_next <= RETCODE_OUT_OF_RESOURCES; else assert (oldest_sample(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; -- Do not ACK Operation ack_dds(ind) <= '0'; if (global_ack_cnt(ind) /= 0) then -- Remove Oldest ACKed Sample remove_oldest_sample_next <= '1'; remove_ack_sample_next <= '1'; cur_sample_next <= oldest_sample(ind); stage_next <= FIND_SAMPLE; cnt_next <= 0; else stage_next <= GET_OLDEST_SAMPLE_INSTANCE; cnt_next <= 0; end if; end if; else stage_next <= ADD_SAMPLE_INFO; cnt_next <= 0; end if; when DISPOSE => ack_dds(ind) <= '1'; -- Reset Liveliness lease_deadline_next(ind) <= time + CONFIG_ARRAY_T(ind).LEASE_DURATION; -- Latch Input Signals key_hash_next <= instance_handle_in_dds(ind); instance_handle_next <= instance_handle_in_dds(ind); source_ts_next <= source_ts_dds(ind); -- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset. sample_status_info_next <= (SSI_DATA_FLAG => '1', SSI_ALIGNED_FLAG => '1', SSI_DISPOSED_FLAG => '1', others => '0'); cur_sample_next <= empty_sample_list_head(ind); if (CONFIG_ARRAY_T(ind).WITH_KEY) then store_serialized_key_next <= '1'; need_kh_op_next <= '1'; else -- For a key-less Topic payload=serialized_key store_payload_next <= '1'; end if; -- NOTE: We always expect a Serialized Key as Input of this Operation, so we also check the Payload memory -- Payload Memory Full if (empty_payload_list_head(ind) = PAYLOAD_MEMORY_MAX_ADDRESS) then if (global_ack_cnt(ind) = 0 and CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- Reject Change stage_next <= SKIP_AND_RETURN; cnt_next <= 0; return_code_latch_next <= RETCODE_OUT_OF_RESOURCES; else assert (oldest_sample(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; -- Do not ACK Operation ack_dds(ind) <= '0'; if (global_ack_cnt(ind) /= 0) then -- Remove Oldest ACKed Sample remove_oldest_sample_next <= '1'; remove_ack_sample_next <= '1'; cur_sample_next <= oldest_sample(ind); stage_next <= FIND_SAMPLE; cnt_next <= 0; else stage_next <= GET_OLDEST_SAMPLE_INSTANCE; cnt_next <= 0; end if; end if; else stage_next <= ADD_SAMPLE_INFO; cnt_next <= 0; end if; when UNREGISTER_INSTANCE => ack_dds(ind) <= '1'; -- Reset Liveliness lease_deadline_next(ind) <= time + CONFIG_ARRAY_T(ind).LEASE_DURATION; -- Latch Input Signals key_hash_next <= instance_handle_in_dds(ind); instance_handle_next <= instance_handle_in_dds(ind); source_ts_next <= source_ts_dds(ind); -- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset. sample_status_info_next <= (SSI_DATA_FLAG => '1', SSI_ALIGNED_FLAG => '1', SSI_UNREGISTERED_FLAG => '1', others => '0'); cur_sample_next <= empty_sample_list_head(ind); if (CONFIG_ARRAY_T(ind).WITH_KEY) then store_serialized_key_next <= '1'; need_kh_op_next <= '1'; else -- For a key-less Topic payload=serialized_key store_payload_next <= '1'; end if; -- NOTE: We always expect a Serialized Key as Input of this Operation, so we also check the Payload memory -- Payload Memory Full if (empty_payload_list_head(ind) = PAYLOAD_MEMORY_MAX_ADDRESS) then if (global_ack_cnt(ind) = 0 and CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- Reject Change stage_next <= SKIP_AND_RETURN; cnt_next <= 0; return_code_latch_next <= RETCODE_OUT_OF_RESOURCES; else assert (oldest_sample(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; -- Do not ACK Operation ack_dds(ind) <= '0'; if (global_ack_cnt(ind) /= 0) then -- Remove Oldest ACKed Sample remove_oldest_sample_next <= '1'; remove_ack_sample_next <= '1'; cur_sample_next <= oldest_sample(ind); stage_next <= FIND_SAMPLE; cnt_next <= 0; else stage_next <= GET_OLDEST_SAMPLE_INSTANCE; cnt_next <= 0; end if; end if; else stage_next <= ADD_SAMPLE_INFO; cnt_next <= 0; end if; when LOOKUP_INSTANCE => -- Synthesis Guard if (CONFIG_ARRAY_T(ind).WITH_KEY) then start_kh(ind) <= '1'; opcode_kh(ind) <= PUSH_DATA; need_kh_op_next <= '1'; if (ack_kh(ind) = '1') then ack_dds(ind) <= '1'; lookup_op_next <= '1'; stage_next <= PROCESS_INPUT; cnt_next <= 0; -- Process Input end if; else ack_dds(ind) <= '1'; key_hash_next <= KEY_HASH_NIL; stage_next <= SKIP; return_stage_next <= PUSH_KEY_HASH; 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(ind) <= '1'; ack_wait_next(ind) <= '1'; tmp_dw := time + max_wait_dds(ind); timeout_time_next(ind) <= tmp_dw; if (tmp_dw < timeout_check_time) then timeout_check_time_next <= tmp_dw; end if; when GET_OFFERED_DEADLINE_MISSED_STATUS => ack_dds(ind) <= '1'; stage_next <= GET_OFFERED_DEADLINE_MISSED_STATUS; cnt_next <= 0; when ASSERT_LIVELINESS => -- Reset Liveliness lease_deadline_next(ind) <= time + CONFIG_ARRAY_T(ind).LEASE_DURATION; ack_dds(ind) <= '1'; stage_next <= ASSERT_LIVELINESS; when GET_LIVELINESS_LOST_STATUS => ack_dds(ind) <= '1'; stage_next <= GET_LIVELINESS_LOST_STATUS; cnt_next <= 0; when others => ack_dds(ind) <= '1'; stage_next <= UNKNOWN_OPERATION_DDS; end case; end if; end if; when UNKNOWN_OPERATION_DDS => done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_ILLEGAL_OPERATION; -- DONE stage_next <= IDLE; when UNKNOWN_OPERATION_RTPS => done_rtps(ind) <= '1'; ret_rtps(ind) <= ERROR; -- DONE stage_next <= IDLE; when UNKNOWN_SEQ_NR => done_rtps(ind) <= '1'; ret_rtps(ind) <= INVALID; -- DONE stage_next <= IDLE; when ASSERT_LIVELINESS => -- Propagate Liveliness Assertion liveliness_assertion(ind) <= '1'; done_dds(ind) <= '1'; return_code_dds(ind) <= 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 <= std_logic_vector(global_seq_nr(ind)(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 <= std_logic_vector(global_seq_nr(ind)(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; if (source_ts /= TIME_INVALID) then sample_write_data <= std_logic_vector(source_ts(0)); else sample_write_data <= std_logic_vector(time(0)); end if; -- 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; if (source_ts /= TIME_INVALID) then sample_write_data <= std_logic_vector(source_ts(1)); else sample_write_data <= std_logic_vector(time(1)); end if; -- Memory Flow Control Guard if (sample_ready_in = '1') then if (CONFIG_ARRAY_T(ind).LIFESPAN_QOS /= DURATION_INFINITE) then lifespan_next <= time + CONFIG_ARRAY_T(ind).LIFESPAN_QOS; else lifespan_next <= TIME_INVALID; end if; cnt_next <= cnt + 1; end if; -- Lifespan Deadline 1/2 when 5 => sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET; sample_write_data <= std_logic_vector(lifespan(0)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- Lifespan Deadline 2/2 when 6 => sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET + 1; sample_write_data <= std_logic_vector(lifespan(1)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- Payload Address when 7 => assert (empty_payload_list_head(ind) /= PAYLOAD_MEMORY_MAX_ADDRESS) severity FAILURE; sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_PAYLOAD_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(empty_payload_list_head(ind), WORD_WIDTH)); cur_payload_next <= empty_payload_list_head(ind); -- Memory Flow Control Guard if (sample_ready_in = '1') then -- Key Holder needs data if (need_kh_op = '1') then cnt_next <= cnt + 1; else stage_next <= PROCESS_INPUT; cnt_next <= 0; -- Process Input cnt2_next <= 1; end if; end if; -- Initiate KH Operation when 8 => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; assert (need_kh_op = '1') severity FAILURE; start_kh(ind) <= '1'; opcode_kh(ind) <= PUSH_DATA; if (ack_kh(ind) = '1') then stage_next <= PROCESS_INPUT; cnt_next <= 0; -- Process Input cnt2_next <= 1; end if; when others => null; end case; when PROCESS_INPUT => -- Precondition (if store_payload = '1'): cur_payload set (Current Slot) case (cnt) is -- Process Input when 0 => -- Input Guard if (valid_in_dds(ind) = '1') then -- Payload Memory payload_addr <= cur_payload + cnt2; payload_write_data <= data_in_dds(ind); -- Key Holder data_out_kh(ind) <= data_in_dds(ind); last_word_out_kh(ind) <= last_word_in_dds(ind); -- Control Flow Guard if ((((not store_payload) or payload_ready_in) = '1') and (((not need_kh_op) or ready_out_kh(ind)) = '1')) then ready_in_dds(ind) <= '1'; if (store_payload = '1') then payload_valid_in <= '1'; -- End of Payload Slot if (cnt2 = PAYLOAD_FRAME_SIZE(ind)-1) then stage_next <= NEXT_PAYLOAD_SLOT; cnt_next <= 0; else -- Next Word cnt2_next <= cnt2 + 1; end if; end if; if (need_kh_op = '1') then valid_out_kh(ind) <= '1'; end if; -- End of Input if (last_word_in_dds(ind) = '1') then -- Overrule stage_next <= PROCESS_INPUT; cnt_next <= cnt + 1; cnt2_next <= cnt2; end if; end if; end if; -- Post Input Process when 1 => -- Payload Unaligned if (store_payload = '1' and cnt2 /= PAYLOAD_FRAME_SIZE(ind)-1) then stage_next <= ALIGN_PAYLOAD; cnt_next <= 0; -- Mark Payload as Unaligned elsif (store_serialized_key = '1') then assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; -- Fetch Serialized Key stage_next <= GET_SERIALIZED_KEY; cnt_next <= 0; -- Initiate READ Operation cnt2_next <= 1; elsif (CONFIG_ARRAY_T(ind).WITH_KEY and instance_handle = HANDLE_NIL) then assert (need_kh_op = '1') severity FAILURE; -- Fetch the Key Hash stage_next <= GET_KEY_HASH; cnt_next <= 0; -- Initiate READ Operation cnt2_next <= 0; else stage_next <= INITIATE_INSTANCE_SEARCH; end if; when others => null; end case; when GET_SERIALIZED_KEY => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; case (cnt) is -- Initiate READ Operation when 0 => -- Key Holder Decode Error if (decode_error_kh(ind) = '1') then done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_ERROR; -- DONE stage_next <= IDLE; else start_kh(ind) <= '1'; opcode_kh(ind) <= READ_SERIALIZED_KEY; if (ack_kh(ind) = '1') then cnt_next <= cnt + 1; end if; end if; -- READ Key Hash when 1 => -- Key Holder Control Flow Guard if (valid_in_kh(ind) = '1') then payload_addr <= cur_payload + cnt2; payload_write_data <= data_in_kh(ind); -- Memory Control Flow Guard if (payload_ready_in = '1') then payload_valid_in <= '1'; ready_in_kh(ind) <= '1'; -- End of Payload Slot if (cnt2 = PAYLOAD_FRAME_SIZE(ind)-1) then stage_next <= NEXT_PAYLOAD_SLOT; cnt_next <= 0; else -- Next Word cnt2_next <= cnt2 + 1; end if; -- Exit Condition if (last_word_in_kh(ind) = '1') then -- Overrule stage_next <= GET_SERIALIZED_KEY; cnt_next <= cnt + 1; cnt2_next <= cnt2; end if; end if; end if; -- Post READ Operation when 2 => -- Payload Unaligned if (cnt2 /= PAYLOAD_FRAME_SIZE(ind)-1) then stage_next <= ALIGN_PAYLOAD; cnt_next <= 0; elsif (instance_handle = HANDLE_NIL) then assert (need_kh_op = '1') severity FAILURE; -- Fetch the Key Hash stage_next <= GET_KEY_HASH; cnt_next <= 0; -- Initiate READ Operation cnt2_next <= 0; else -- Exit stage_next <= INITIATE_INSTANCE_SEARCH; 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 (unsigned(payload_read_data) = PAYLOAD_MEMORY_MAX_ADDRESS) then -- Reject Change stage_next <= SKIP_AND_RETURN; cnt_next <= 0; return_code_latch_next <= RETCODE_OUT_OF_RESOURCES; -- Abort Key Hash Generation abort_kh(ind) <= '1'; else -- Latch next Payload Slot and Continue cur_payload_next <= resize(unsigned(payload_read_data), PAYLOAD_MEMORY_ADDR_WIDTH); if (store_payload = '1') then stage_next <= PROCESS_INPUT; cnt_next <= 0; -- Process Input cnt2_next <= 1; else assert (store_serialized_key = '1') severity FAILURE; stage_next <= GET_SERIALIZED_KEY; cnt_next <= 1; -- Read Key Hash cnt2_next <= 1; end if; 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(ind)-1; payload_write_data <= std_logic_vector(to_unsigned(cnt2, WORD_WIDTH)); -- Memory Control Flow Guard if (payload_ready_in = '1') then if (CONFIG_ARRAY_T(ind).WITH_KEY and instance_handle = HANDLE_NIL) then assert (need_kh_op = '1') severity FAILURE; stage_next <= GET_KEY_HASH; cnt_next <= 0; -- Initiate READ Operation cnt2_next <= 0; else -- Exit stage_next <= INITIATE_INSTANCE_SEARCH; end if; end if; when others => null; end case; when GET_KEY_HASH => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; case (cnt) is -- Initiate READ Operation when 0 => -- Key Holder Decode Error if (decode_error_kh(ind) = '1') then done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_ERROR; -- DONE stage_next <= IDLE; else start_kh(ind) <= '1'; opcode_kh(ind) <= READ_KEY_HASH; if (ack_kh(ind) = '1') then cnt_next <= cnt + 1; end if; end if; -- READ Key Hash when 1 => ready_in_kh(ind) <= '1'; if (valid_in_kh(ind) = '1') then cnt2_next <= cnt2 + 1; -- Latch Key Hash key_hash_next(cnt2) <= data_in_kh(ind); -- Exit Condition if (last_word_in_kh(ind) = '1') then -- Exit stage_next <= INITIATE_INSTANCE_SEARCH; end if; end if; when others => null; end case; when INITIATE_INSTANCE_SEARCH => -- Memory Operation Guard if (inst_op_done = '1') then inst_op_start <= '1'; inst_opcode <= SEARCH_INSTANCE; inst_r.i <= ind; inst_r.key_hash <= key_hash; inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; -- Register Operation in Progress if (register_op = '1') then stage_next <= REGISTER_OPERATION; -- Lookup Operation in Progress elsif (lookup_op = '1') then stage_next <= LOOKUP_OPERATION; else stage_next <= FILTER_STAGE; end if; end if; when REGISTER_OPERATION => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; -- Wait for Instance Search to finish if (inst_op_done = '1') then -- Instance already in Memory if (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) then assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG)) severity FAILURE; -- Accept Registration 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_r.i <= ind; inst_r.addr <= inst_data.addr; inst_r.field_flags <= IMF_STATUS_FLAG; inst_r.status_info <= inst_data.status_info; inst_r.status_info(ISI_UNREGISTERED_FLAG) <= '0'; -- Update Stale Instance Count if (inst_data.sample_cnt = inst_data.ack_cnt) then stale_inst_cnt_next(ind) <= stale_inst_cnt(ind) - 1; end if; end if; else -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) if (inst_empty_head(ind) = INSTANCE_MEMORY_MAX_ADDRESS) then -- Stale Instances are available if (stale_inst_cnt(ind) /= 0) then -- Remove Stale and insert new Instance inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_occupied_head(ind); inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; stage_next <= REMOVE_STALE_INSTANCE; cnt_next <= 0; else -- Reject Registration key_hash_next <= KEY_HASH_NIL; stage_next <= PUSH_KEY_HASH; end if; else -- Accept Registration stage_next <= PUSH_KEY_HASH; -- Insert New Instance inst_op_start <= '1'; inst_opcode <= INSERT_INSTANCE; inst_r.i <= ind; inst_r.key_hash <= key_hash; end if; end if; end if; when LOOKUP_OPERATION => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; -- Wait for Instance Search to finish if (inst_op_done = '1') then -- Instance Found if (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) then stage_next <= PUSH_KEY_HASH; else -- Return Special Value key_hash_next <= KEY_HASH_NIL; stage_next <= PUSH_KEY_HASH; end if; end if; when PUSH_KEY_HASH => done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; instance_handle_out_dds(ind) <= key_hash; -- DONE stage_next <= IDLE; when FILTER_STAGE => -- Precondition: cur_sample set, inst_data set (IMF_SAMPLE_CNT_FLAG, IMF_ACK_CNT_FLAG) -- Wait for Instance Search to finish if (inst_op_done = '1') then -- Instance Found if (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) then assert (stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG))) severity FAILURE; -- Latch Instance Pointer cur_inst_next <= inst_data.addr; -- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE) if (CONFIG_ARRAY_T(ind).MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = unsigned(CONFIG_ARRAY_T(ind).MAX_SAMPLES_PER_INSTANCE)) then if (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- No ACKed Instance Samples exist if (inst_data.ack_cnt = 0) then -- Reject Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OUT_OF_RESOURCES; stage_next <= IDLE; else -- Accept Change (Remove Oldest ACKed Instance Sample) remove_oldest_inst_sample_next <= '1'; remove_ack_sample_next <= '1'; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; stage_next <= UPDATE_INSTANCE; end if; else assert (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_LAST_HISTORY_QOS) severity FAILURE; -- Accept Change (Remove Oldest (ACKed) Instance Sample) remove_oldest_inst_sample_next <= '1'; if (inst_data.ack_cnt /= 0) then remove_ack_sample_next <= '1'; else remove_ack_sample_next <= '0'; end if; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; stage_next <= UPDATE_INSTANCE; end if; -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) elsif (empty_sample_list_head(ind) = empty_sample_list_tail(ind)) then if (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- No ACKed Samples exist if (global_ack_cnt(ind) = 0) then -- Reject Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OUT_OF_RESOURCES; stage_next <= IDLE; else -- Accept Change (Remove Oldest ACKed Sample) remove_oldest_sample_next <= '1'; remove_ack_sample_next <= '1'; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; stage_next <= UPDATE_INSTANCE; end if; else assert (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_LAST_HISTORY_QOS) severity FAILURE; -- Accept Change (Remove Oldest (ACKed) Sample) remove_oldest_sample_next <= '1'; if (global_ack_cnt(ind) /= 0) then remove_ack_sample_next <= '1'; else remove_ack_sample_next <= '0'; end if; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; stage_next <= UPDATE_INSTANCE; end if; else -- Accept Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; stage_next <= UPDATE_INSTANCE; end if; else -- Latch Instance Pointer cur_inst_next <= inst_empty_head(ind); -- Provided Instance Handle Invalid if (instance_handle /= HANDLE_NIL) then -- Invalid Operation done_dds(ind) <= '1'; return_code_dds(ind) <= 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(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- DONE stage_next <= IDLE; -- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full) elsif (inst_empty_head(ind) = INSTANCE_MEMORY_MAX_ADDRESS) then assert (stable(clk,CONFIG_ARRAY_T(ind).WITH_KEY)) severity FAILURE; -- No Stale Instances available if (stale_inst_cnt(ind) = 0) then -- Reject Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OUT_OF_RESOURCES; stage_next <= IDLE; -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) elsif (empty_sample_list_head(ind) = empty_sample_list_tail(ind)) then if (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- No ACKed Samples exist if (global_ack_cnt(ind) = 0) then -- Reject Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OUT_OF_RESOURCES; stage_next <= IDLE; else -- Accept Change (Remove Oldest ACKed Sample) remove_oldest_sample_next <= '1'; remove_ack_sample_next <= '1'; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Remove Stale and insert new Instance inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_occupied_head(ind); inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; stage_next <= REMOVE_STALE_INSTANCE; cnt_next <= 0; end if; else assert (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_LAST_HISTORY_QOS) severity FAILURE; -- Accept Change (Remove Oldest (ACKed) Sample) remove_oldest_sample_next <= '1'; if (global_ack_cnt(ind) /= 0) then remove_ack_sample_next <= '1'; else remove_ack_sample_next <= '0'; end if; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Remove Stale and insert new Instance inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_occupied_head(ind); inst_r.field_flags <= 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(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Remove Stale and insert new Instance inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_occupied_head(ind); inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; stage_next <= REMOVE_STALE_INSTANCE; cnt_next <= 0; end if; else -- RESOURCE_LIMITS_QOS (MAX_SAMPLES) if (empty_sample_list_head(ind) = empty_sample_list_tail(ind)) then if (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then -- No ACKed Samples exist if (global_ack_cnt(ind) = 0) then -- Reject Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OUT_OF_RESOURCES; stage_next <= IDLE; else -- Accept Change (Remove Oldest ACKed Sample) remove_oldest_sample_next <= '1'; remove_ack_sample_next <= '1'; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Insert New Instance inst_op_start <= '1'; inst_opcode <= INSERT_INSTANCE; inst_r.i <= ind; inst_r.key_hash <= key_hash; inst_r.status_info <= (ISI_LIVELINESS_FLAG => '1', others => '0'); inst_r.sample_cnt <= to_unsigned(1, WORD_WIDTH); inst_r.ack_cnt <= (others => '0'); stage_next <= FINALIZE_PAYLOAD; cnt_next <= 0; end if; else assert (CONFIG_ARRAY_T(ind).HISTORY_QOS = KEEP_LAST_HISTORY_QOS) severity FAILURE; -- Accept Change (Remove Oldest (ACKed) Sample) remove_oldest_sample_next <= '1'; if (global_ack_cnt(ind) /= 0) then remove_ack_sample_next <= '1'; else remove_ack_sample_next <= '0'; end if; done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Insert New Instance inst_op_start <= '1'; inst_opcode <= INSERT_INSTANCE; inst_r.i <= ind; inst_r.key_hash <= key_hash; inst_r.status_info <= (ISI_LIVELINESS_FLAG => '1', others => '0'); inst_r.sample_cnt <= to_unsigned(1, WORD_WIDTH); inst_r.ack_cnt <= (others => '0'); stage_next <= FINALIZE_PAYLOAD; cnt_next <= 0; end if; else -- Accept Change done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Insert New Instance inst_op_start <= '1'; inst_opcode <= INSERT_INSTANCE; inst_r.i <= ind; inst_r.key_hash <= key_hash; inst_r.status_info <= (ISI_LIVELINESS_FLAG => '1', others => '0'); inst_r.sample_cnt <= to_unsigned(1, WORD_WIDTH); inst_r.ack_cnt <= (others => '0'); stage_next <= FINALIZE_PAYLOAD; cnt_next <= 0; end if; end if; end if; end if; when UPDATE_INSTANCE => -- Precondition: inst_data set (IMF_STATUS_FLAG, IMF_SAMPLE_CNT_FLAG, IMF_ACK_CNT_FLAG) -- Memory Operation Guard if (inst_op_done = '1') then assert (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) severity FAILURE; assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG)) severity FAILURE; inst_op_start <= '1'; inst_opcode <= UPDATE_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_data.addr; inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG; inst_r.status_info <= inst_data.status_info; inst_r.status_info(ISI_LIVELINESS_FLAG) <= '1'; if (sample_status_info(SSI_DISPOSED_FLAG) = '0' and sample_status_info(SSI_UNREGISTERED_FLAG) = '0') then inst_r.status_info(ISI_DISPOSED_FLAG) <= '0'; inst_r.status_info(ISI_UNREGISTERED_FLAG) <= '0'; elsif (sample_status_info(SSI_DISPOSED_FLAG) = '1') then inst_r.status_info(ISI_DISPOSED_FLAG) <= '1'; elsif (sample_status_info(SSI_UNREGISTERED_FLAG) = '1') then inst_r.status_info(ISI_UNREGISTERED_FLAG) <= '1'; end if; inst_r.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(ind) <= stale_inst_cnt(ind) - 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 <= std_logic_vector(resize(PAYLOAD_MEMORY_MAX_ADDRESS, WORD_WIDTH)); -- 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(ind) <= resize(unsigned(payload_read_data), PAYLOAD_MEMORY_ADDR_WIDTH); stage_next <= FINALIZE_SAMPLE; cur_sample_next <= empty_sample_list_head(ind); cnt_next <= 0; end if; when others => null; end case; when FINALIZE_SAMPLE => -- Precondition: cur_sample set, cur_inst set case (cnt) is -- GET Next Pointer 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 -- Sample Memory Empty (No previous Sample) if (newest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then assert (oldest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; cnt_next <= cnt + 2; -- SET INSTANCE POINTER else cnt_next <= cnt + 1; end if; end if; -- SET Next Pointer (Previous Sample) when 1 => sample_valid_in <= '1'; sample_addr <= newest_sample(ind) + SMF_NEXT_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(cur_sample, WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- SET Instance Pointer when 2 => sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_INSTANCE_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(cur_inst, WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- SET Previous Pointer when 3 => sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(newest_sample(ind), WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- SET Next Pointer when 4 => -- Write Next Pointer sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(SAMPLE_MEMORY_MAX_ADDRESS, WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- READ Next Pointer when 5 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then -- Fix new Empty List Head empty_sample_list_head_next(ind) <= resize(unsigned(sample_read_data), SAMPLE_MEMORY_ADDR_WIDTH); -- Fix List Pointers newest_sample_next(ind) <= cur_sample; if (oldest_sample(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then oldest_sample_next(ind) <= cur_sample; end if; -- Increment Global Sequence Number global_seq_nr_next(ind) <= global_seq_nr(ind) + 1; -- Increment Global Sample Count global_sample_cnt_next(ind) <= global_sample_cnt(ind) + 1; -- Trigger ACK Wait Check ack_wait_check_next <= '1'; -- Signal Data Available data_available_sig_next(ind) <= '1'; -- NOTE: This is needed to prevent the new Sample from being selected during an Orphan Sample -- Search, since the Dead Instance Address is the same as the new Sample Instance Address. -- Latch Sample Address new_sample_next <= cur_sample; -- Update Lifespan Check Time if (CONFIG_ARRAY_T(ind).LIFESPAN_QOS /= DURATION_INFINITE and lifespan < lifespan_time) then lifespan_time_next <= lifespan; end if; if (remove_oldest_inst_sample = '1' or (remove_oldest_sample = '1' and remove_ack_sample = '1')) then assert (oldest_sample(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; cur_sample_next <= oldest_sample(ind); stage_next <= FIND_SAMPLE; cnt_next <= 0; elsif (remove_oldest_sample = '1') then assert (oldest_sample(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE; stage_next <= GET_OLDEST_SAMPLE_INSTANCE; cnt_next <= 0; else -- DONE stage_next <= IDLE; end if; end if; when others => null; end case; when GET_OLDEST_SAMPLE_INSTANCE => case (cnt) is -- GET Instance Pointer (Oldest Sample) when 0 => sample_valid_in <= '1'; sample_addr <= oldest_sample(ind) + 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 inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= resize(unsigned(sample_read_data), INSTANCE_MEMORY_ADDR_WIDTH); inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; cur_sample_next <= oldest_sample(ind); stage_next <= REMOVE_SAMPLE; cnt_next <= 0; end if; end if; when others => null; end case; when FIND_SAMPLE => -- 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 Flow Control Guard if (sample_ready_in = '1') then if (remove_ack_sample = '1') then cnt_next <= cnt + 1; else assert(remove_oldest_inst_sample = '1') severity FAILURE; cnt_next <= cnt + 2; -- GET INSTANCE POINTER end if; end if; -- GET Status Info when 1 => 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 Instance Pointer when 2 => 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 Next Sample when 3 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then next_sample_next <= resize(unsigned(sample_read_data), SAMPLE_MEMORY_ADDR_WIDTH); if (remove_ack_sample = '1') then cnt_next <= cnt + 1; else assert(remove_oldest_inst_sample = '1') severity FAILURE; cnt_next <= cnt + 2; -- READ INSTANCE POINTER end if; end if; -- READ Status Info when 4 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then -- Sample is ACKed if (sample_read_data(SSI_ACK_FLAG) = '1') then cnt_next <= cnt + 1; else -- Continue sample_abort_read <= '1'; cur_sample_next <= next_sample; cnt_next <= 0; end if; end if; -- READ Instance Pointer when 5 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then if (remove_oldest_sample = '1') then inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= resize(unsigned(sample_read_data), INSTANCE_MEMORY_ADDR_WIDTH); inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; stage_next <= REMOVE_SAMPLE; cnt_next <= 0; -- Oldest Instance Sample Found elsif (resize(unsigned(sample_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = cur_inst) then -- NOTE: Instance Data already valid stage_next <= REMOVE_SAMPLE; cnt_next <= 0; else -- Continue cur_sample_next <= next_sample; cnt_next <= 0; end if; end if; when others => null; end case; when REMOVE_ORPHAN_SAMPLES => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; 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 (And not newly added sample of new instance) if (resize(unsigned(sample_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = dead_inst and cur_sample /= new_sample) 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 (resize(unsigned(sample_read_data),SAMPLE_MEMORY_ADDR_WIDTH) = SAMPLE_MEMORY_MAX_ADDRESS) then -- DONE orphan_samples_next <= '0'; stage_next <= IDLE; else -- Continue cur_sample_next <= resize(unsigned(sample_read_data),SAMPLE_MEMORY_ADDR_WIDTH); cnt_next <= 0; end if; end if; when others => null; end case; when REMOVE_SAMPLE => -- Precondition: cur_sample set 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 Pointer 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 Pointer 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 Pointer when 5 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then prev_sample_next <= resize(unsigned(sample_read_data),SAMPLE_MEMORY_ADDR_WIDTH); cnt_next <= cnt + 1; end if; -- READ Next Pointer when 6 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then next_sample_next <= resize(unsigned(sample_read_data),SAMPLE_MEMORY_ADDR_WIDTH); -- Sample Memory Full if (empty_sample_list_head(ind) = SAMPLE_MEMORY_MAX_ADDRESS) then empty_sample_list_head_next(ind) <= cur_sample; empty_sample_list_tail_next(ind) <= cur_sample; cnt_next <= cnt + 2; -- SET NEXT POINTER else cnt_next <= cnt + 1; end if; end if; -- SET Next Pointer (Empty List Tail) when 7 => -- Add Current Sample after Empty List Tail sample_valid_in <= '1'; sample_addr <= empty_sample_list_tail(ind) + SMF_NEXT_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(cur_sample,WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- SET Next Pointer when 8 => -- Make Current Sample Empty List Tail sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(SAMPLE_MEMORY_MAX_ADDRESS,WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then -- Fix Empty List Pointers empty_sample_list_tail_next(ind) <= cur_sample; -- Current Sample is Newest (Occupied List Tail) if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then assert (cur_sample = newest_sample(ind)) severity FAILURE; -- Fix Newest Pointer newest_sample_next(ind) <= prev_sample; -- Current Sample is Oldest (List Head) if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then assert (cur_sample = oldest_sample(ind)) severity FAILURE; assert (newest_sample(ind) = oldest_sample(ind)) severity FAILURE; -- NOTE: Sample Memory Empty (newest_sample also set to MAX_ADDR) -- Fix Oldest Pointer oldest_sample_next(ind) <= SAMPLE_MEMORY_MAX_ADDRESS; cnt_next <= cnt + 3; -- READ PAYLOAD POINTER else cnt_next <= cnt + 2; -- SET NEXT POINTER (Previous Sample) end if; else cnt_next <= cnt + 1; end if; end if; -- SET Previous Pointer (Next Sample) when 9 => -- Remove link to cur_sample sample_valid_in <= '1'; sample_addr <= next_sample + SMF_PREV_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(prev_sample,WORD_WIDTH)); -- 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(ind)) severity FAILURE; -- Fix Oldest Pointer oldest_sample_next(ind) <= next_sample; cnt_next <= cnt + 2; -- READ PAYLOAD POINTER else cnt_next <= cnt + 1; end if; end if; -- SET Next Pointer (Previous Sample) when 10 => -- Remove link to cur_sample sample_valid_in <= '1'; sample_addr <= prev_sample + SMF_NEXT_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(next_sample,WORD_WIDTH)); -- 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 -- Update Global Sample Count global_sample_cnt_next(ind) <= global_sample_cnt(ind) - 1; -- Trigger ACK Wait Check ack_wait_check_next <= '1'; -- Update Global ACK Count -- Sample was ACKed if (sample_status_info(SSI_ACK_FLAG) = '1') then global_ack_cnt_next(ind) <= global_ack_cnt(ind) - 1; end if; cur_payload_next <= resize(unsigned(sample_read_data),PAYLOAD_MEMORY_ADDR_WIDTH); -- Sample has no Data if (resize(unsigned(sample_read_data),PAYLOAD_MEMORY_ADDR_WIDTH) = PAYLOAD_MEMORY_MAX_ADDRESS) 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; -- Payload Memory Full elsif (empty_payload_list_head(ind) = PAYLOAD_MEMORY_MAX_ADDRESS) then -- Fix Empty List Head empty_payload_list_head_next(ind) <= resize(unsigned(sample_read_data),PAYLOAD_MEMORY_ADDR_WIDTH); -- 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; else -- Latch First Payload Slot for later use first_payload_next <= resize(unsigned(sample_read_data),PAYLOAD_MEMORY_ADDR_WIDTH); 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 (resize(unsigned(payload_read_data),PAYLOAD_MEMORY_ADDR_WIDTH) = PAYLOAD_MEMORY_MAX_ADDRESS) then cnt_next <= cnt + 1; else cur_payload_next <= resize(unsigned(payload_read_data),PAYLOAD_MEMORY_ADDR_WIDTH); cnt_next <= 12; -- GET NEXT PAYLOAD end if; end if; -- SET Next Payload Pointer (Last Payload Slot of Current Sample) when 14 => payload_valid_in <= '1'; payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; payload_write_data <= std_logic_vector(resize(empty_payload_list_head(ind),WORD_WIDTH)); -- Fix Empty List Head empty_payload_list_head_next(ind) <= first_payload; -- 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; when POST_SAMPLE_REMOVE => -- Precondition: inst_data set (IMF_STATUS_FLAG, IMF_SAMPLE_CNT_FLAG, IMF_ACK_CNT_FLAG) -- Memory Operation Guard if (inst_op_done = '1') then assert (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) severity FAILURE; assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG)) severity FAILURE; inst_op_start <= '1'; inst_opcode <= UPDATE_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_data.addr; inst_r.field_flags <= IMF_SAMPLE_CNT_FLAG; inst_r.sample_cnt <= inst_data.sample_cnt - 1; -- Sample was ACKed if (sample_status_info(SSI_ACK_FLAG) = '1') then inst_r.field_flags <= IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; inst_r.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(ind) <= stale_inst_cnt(ind) + 1; end if; end if; if (is_rtps = '1') then -- DONE done_rtps(ind) <= '1'; ret_rtps(ind) <= OK; stage_next <= IDLE; elsif (is_lifespan_check = '1') then -- Reached End of Samples if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then -- Continue stage_next <= CHECK_LIFESPAN; cnt_next <= 0; -- GET NEXT WRITER else -- Continue Search cur_sample_next <= next_sample; stage_next <= CHECK_LIFESPAN; cnt_next <= 2; -- GET NEXT SAMPLE end if; else -- DONE stage_next <= IDLE; end if; end if; when SKIP_AND_RETURN => case (cnt) is -- SKIP READ when 0 => ready_in_dds(ind) <= '1'; -- Wait until last word from input if (last_word_in_dds(ind) = '1') then cnt_next <= cnt + 1; end if; -- Return Code when 1 => done_dds(ind) <= '1'; return_code_dds(ind) <= return_code_latch; -- DONE stage_next <= IDLE; when others => null; end case; when SKIP => ready_in_dds(ind) <= '1'; -- Wait until last word from input if (last_word_in_dds(ind) = '1') then stage_next <= return_stage; cnt_next <= 0; end if; when REMOVE_STALE_INSTANCE => assert (CONFIG_ARRAY_T(ind).WITH_KEY) severity FAILURE; -- 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_data.addr = 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 stable(clk,FALSE) severity FAILURE; stage_next <= IDLE; else assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG)) severity FAILURE; -- 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; inst_r.i <= ind; inst_r.addr <= inst_data.addr; -- Update Stale Instance Count stale_inst_cnt_next(ind) <= stale_inst_cnt(ind) - 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_data.addr; end if; cnt_next <= cnt + 1; else -- Continue Search inst_op_start <= '1'; inst_opcode <= GET_NEXT_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_data.addr; inst_r.field_flags <= 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; inst_r.i <= ind; inst_r.key_hash <= key_hash; inst_r.ack_cnt <= (others => '0'); if (register_op = '1') then inst_r.status_info <= (others => '0'); inst_r.sample_cnt <= (others => '0'); else inst_r.status_info <= (ISI_LIVELINESS_FLAG => '1', others => '0'); inst_r.sample_cnt <= to_unsigned(1, WORD_WIDTH); end if; -- Latch Instance Pointer cur_inst_next <= inst_empty_head(ind); -- Register Operation in progress if (register_op = '1') then -- DONE stage_next <= PUSH_KEY_HASH; else stage_next <= FINALIZE_PAYLOAD; cnt_next <= 0; end if; when others => null; end case; 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 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then cc_seq_nr_sig_next(0) <= unsigned(sample_read_data); cnt_next <= cnt + 1; end if; -- READ Sequence Number 2/2 when 3 => sample_ready_out <= '1'; -- Memory Flow Control Guard if (sample_valid_out = '1') then cc_seq_nr_sig_next(1) <= unsigned(sample_read_data); cnt_next <= cnt + 1; end if; -- Return Code when 4 => done_rtps(ind) <= '1'; ret_rtps(ind) <= 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 <= resize(unsigned(sample_read_data),SAMPLE_MEMORY_ADDR_WIDTH); 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 (unsigned(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 (unsigned(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 <= resize(unsigned(sample_read_data),INSTANCE_MEMORY_ADDR_WIDTH); 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(ind) <= '1'; ret_rtps(ind) <= 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_r.i <= ind; inst_r.addr <= cur_inst; inst_r.field_flags <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; stage_next <= return_stage; cnt_next <= 0; end if; end if; when others => null; end case; when ACKNACK_SAMPLE => -- Precondition: inst_data set (IMF_ACK_CNT_FLAG, IMF_STATUS_FLAG, IMF_SAMPLE_CNT_FLAG) 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(ind) <= '1'; ret_rtps(ind) <= 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; if (is_ack = '1') then sample_write_data(SSI_ACK_FLAG) <= '1'; else sample_write_data(SSI_ACK_FLAG) <= '0'; end if; -- Memory Flow Control Guard if (sample_ready_in = '1') then -- Trigger ACK Wait Check ack_wait_check_next <= '1'; if (is_ack = '1') then global_ack_cnt_next(ind) <= global_ack_cnt(ind) + 1; else global_ack_cnt_next(ind) <= global_ack_cnt(ind) - 1; end if; cnt_next <= cnt + 1; end if; -- SET Instance Data when 3 => -- Wait for Instance Data if (inst_op_done = '1') then assert (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) severity FAILURE; assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG)) severity FAILURE; -- Update inst_op_start <= '1'; inst_opcode <= UPDATE_INSTANCE; inst_r.i <= ind; inst_r.addr <= cur_inst; inst_r.field_flags <= IMF_ACK_CNT_FLAG; if (is_ack = '1') then inst_r.ack_cnt <= inst_data.ack_cnt + 1; else inst_r.ack_cnt <= inst_data.ack_cnt - 1; end if; -- 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(ind) <= stale_inst_cnt(ind) + 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(ind) <= stale_inst_cnt(ind) - 1; end if; -- DONE done_rtps(ind) <= '1'; ret_rtps(ind) <= OK; stage_next <= IDLE; end if; when others => null; end case; when GET_SAMPLE => -- Precondition: inst_data set (IMF_KEY_HASH_FLAG) 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') then 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) <= unsigned(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) <= unsigned(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 <= resize(unsigned(sample_read_data),PAYLOAD_MEMORY_ADDR_WIDTH); cnt_next <= cnt + 1; end if; -- Instance Handle when 8 => -- Wait for Instance Data if (inst_op_done = '1') then assert (inst_data.addr /= INSTANCE_MEMORY_MAX_ADDRESS) severity FAILURE; assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_KEY_HASH_FLAG)) severity FAILURE; cc_instance_handle_sig_next <= inst_data.key_hash; cnt_next <= cnt + 1; end if; -- Present Sample when 9 => done_rtps(ind) <= '1'; ret_rtps(ind) <= OK; -- RTPS requests Payload if (get_data_rtps(ind) = '1') then if (cur_payload /= PAYLOAD_MEMORY_MAX_ADDRESS) then -- Get Payload stage_next <= GET_PAYLOAD; cnt_next <= 0; cnt2_next <= 0; cnt3_next <= 0; else assert FALSE report "Payload Requested, while no Payload available" severity FAILURE; stage_next <= IDLE; end if; 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 => -- NOTE: We have to make sure that no pending Reads are in the Memory Controller Buffer, -- else the Next Payload Pointer cannot be read. -- No Pending Reads if (cnt3 = 0) then 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; end if; -- READ Next Pointer when 1 => payload_ready_out <= '1'; -- Memory Flow Control Guard if (payload_valid_out = '1') then next_payload_next <= resize(unsigned(payload_read_data),PAYLOAD_MEMORY_ADDR_WIDTH); cnt2_next <= 1; -- Last Payload Slot is unaligned if (resize(unsigned(payload_read_data),PAYLOAD_MEMORY_ADDR_WIDTH) = 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 <= std_logic_vector(to_unsigned(PAYLOAD_FRAME_SIZE(ind)-1,CDR_LONG_WIDTH)); end if; end if; -- GET Payload Offset when 2 => payload_valid_in <= '1'; payload_addr <= cur_payload + PAYLOAD_FRAME_SIZE(ind)-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 finish 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; -- Data available for Output if (cnt3 /= 0) then -- Memory Flow Control Guard if (payload_valid_out = '1') then valid_out_rtps(ind) <= '1'; data_out_rtps(ind) <= payload_read_data; -- End of Payload if (cnt3 = 1 and cnt = 5) then last_word_out_rtps(ind) <= '1'; end if; -- DDS Read if (ready_out_rtps(ind) = '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 = 5) then assert (cnt3 = 0) severity FAILURE; -- DONE stage_next <= IDLE; end if; when CHECK_LIFESPAN => -- Precondition: cur_sample set, case (cnt) is -- GET NEXT WRITER when 0 => if (ind = NUM_WRITERS-1) then -- Reset is_lifespan_check_next <= '0'; -- DONE stage_next <= IDLE; else -- Next Writer ind_next <= ind + 1; cnt_next <= cnt + 1; end if; -- CHECK LIFESPAN when 1 => -- Samples Available (And Writer has Lifespan enabled) if (CONFIG_ARRAY_T(ind).LIFESPAN_QOS /= DURATION_INFINITE and oldest_sample(ind) /= SAMPLE_MEMORY_MAX_ADDRESS) then cur_sample_next <= oldest_sample(ind); cnt_next <= cnt + 1; else -- Continue cnt_next <= 0; -- GET NEXT WRITER end if; -- GET NEXT Sample when 2 => 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 3 => 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 4 => 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 5 => 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 6 => sample_ready_out <= '1'; -- Memory Control Flow Guard if (sample_valid_out = '1') then next_sample_next <= resize(unsigned(sample_read_data),SAMPLE_MEMORY_ADDR_WIDTH); cnt_next <= cnt + 1; end if; -- READ Lifespan 1/2 when 7 => 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 8 => 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 -- Continue cnt_next <= 0; -- GET NEXT WRITER else -- Continue Search cur_sample_next <= next_sample; cnt_next <= 2; -- GET NEXT SAMPLE end if; end if; end if; -- READ Instance Pointer when 9 => -- 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_r.i <= ind; inst_r.addr <= resize(unsigned(sample_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_r.field_flags <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG; -- 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 -- Return Code when 0 => done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; cnt_next <= cnt + 1; -- Total Count when 1 => data_out_dds(ind) <= std_logic_vector(liveliness_lost_cnt(ind)); valid_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then cnt_next <= cnt + 1; end if; -- Total Count Change when 2 => data_out_dds(ind) <= std_logic_vector(liveliness_lost_cnt_change(ind)); valid_out_dds(ind) <= '1'; last_word_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then -- Reset liveliness_lost_cnt_change_next(ind) <= (others => '0'); status_sig_next(ind) <= status_sig(ind) and (not LIVELINESS_LOST_STATUS); -- DONE stage_next <= IDLE; end if; when others => null; end case; when GET_OFFERED_DEADLINE_MISSED_STATUS => case (cnt) is -- Return Code when 0 => done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; cnt_next <= cnt + 1; -- Total Count when 1 => data_out_dds(ind) <= std_logic_vector(deadline_miss_cnt(ind)); valid_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then cnt_next <= cnt + 1; end if; -- Total Count Change when 2 => data_out_dds(ind) <= std_logic_vector(deadline_miss_cnt_change(ind)); valid_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then -- Reset deadline_miss_cnt_change_next(ind) <= (others => '0'); cnt_next <= cnt + 1; end if; -- Last Instance Handle 1/4 when 3 => data_out_dds(ind) <= deadline_miss_last_inst(ind)(0); valid_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then cnt_next <= cnt + 1; end if; -- Last Instance Handle 2/4 when 4 => data_out_dds(ind) <= deadline_miss_last_inst(ind)(1); valid_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then cnt_next <= cnt + 1; end if; -- Last Instance Handle 3/4 when 5 => data_out_dds(ind) <= deadline_miss_last_inst(ind)(2); valid_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then cnt_next <= cnt + 1; end if; -- Last Instance Handle 4/4 when 6 => data_out_dds(ind) <= deadline_miss_last_inst(ind)(3); valid_out_dds(ind) <= '1'; last_word_out_dds(ind) <= '1'; if (ready_out_dds(ind) = '1') then -- Reset deadline_miss_last_inst_next(ind) <= HANDLE_NIL; status_sig_next(ind) <= status_sig(ind) and (not OFFERED_DEADLINE_MISSED_STATUS); -- DONE stage_next <= IDLE; end if; when others => null; end case; when CHECK_DEADLINE => -- Memory Operation Guard if (inst_op_done = '1') then case (cnt) is -- GET NEXT WRITER when 0 => if (ind = NUM_WRITERS-1) then -- DONE stage_next <= IDLE; else -- Next Writer ind_next <= ind + 1; cnt_next <= cnt + 1; end if; -- CHECK DEADLINE when 1 => -- Deadline Check Trigger if (CONFIG_ARRAY_T(ind).DEADLINE_QOS /= DURATION_INFINITE and deadline_time(ind) <= time) then tmp_dw := deadline_time(ind) + CONFIG_ARRAY_T(ind).DEADLINE_QOS; deadline_time_next(ind) <= tmp_dw; -- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock) -- Update Check Time if (tmp_dw < deadline_check_time) then deadline_check_time_next <= tmp_dw; end if; cnt_next <= cnt + 1; else if (CONFIG_ARRAY_T(ind).DEADLINE_QOS /= DURATION_INFINITE and deadline_time(ind) <= deadline_check_time) then deadline_check_time_next <= deadline_time(ind); end if; -- Continue cnt_next <= 0; -- GET NEXT WRITER end if; -- GET FIRST Instance when 2 => inst_op_start <= '1'; inst_opcode <= GET_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_occupied_head(ind); inst_r.field_flags <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG; cnt_next <= 4; -- CHECK INSTANCE -- GET NEXT Instance when 3 => inst_op_start <= '1'; inst_opcode <= GET_NEXT_INSTANCE; inst_r.i <= ind; inst_r.addr <= inst_data.addr; inst_r.field_flags <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG; cnt_next <= 4; -- CHECK INSTANCE -- CHECK Instance when 4 => -- Reached End of Instances if (inst_data.addr = INSTANCE_MEMORY_MAX_ADDRESS) then -- Continue cnt_next <= 0; -- GET NEXT WRITER else assert stable(clk, inst_data.i = ind and check_mask(inst_data.field_flags, IMF_STATUS_FLAG or IMF_KEY_HASH_FLAG)) severity FAILURE; -- 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_r.i <= ind; inst_r.addr <= inst_data.addr; inst_r.field_flags <= IMF_STATUS_FLAG; inst_r.status_info <= inst_data.status_info; inst_r.status_info(ISI_LIVELINESS_FLAG) <= '0'; cnt_next <= 3; -- GET NEXT INSTANCE else -- Update Requested Deadline Missed Status status_sig_next(ind) <= status_sig(ind) or OFFERED_DEADLINE_MISSED_STATUS; deadline_miss_cnt_next(ind) <= std_logic_vector(unsigned(deadline_miss_cnt(ind)) + 1); deadline_miss_cnt_change_next(ind) <= std_logic_vector(unsigned(deadline_miss_cnt_change(ind)) + 1); deadline_miss_last_inst_next(ind) <= inst_data.key_hash; cnt_next <= 3; -- GET NEXT INSTANCE end if; end if; when others => null; end case; end if; when CHECK_LIVELINESS => -- Memory Operation Guard if (inst_op_done = '1') then case (cnt) is -- GET NEXT WRITER when 0 => if (ind = NUM_WRITERS-1) then -- DONE stage_next <= IDLE; else -- Next Writer ind_next <= ind + 1; cnt_next <= cnt + 1; end if; -- CHECK LEASE when 1 => -- Deadline Check Trigger if (CONFIG_ARRAY_T(ind).LEASE_DURATION /= DURATION_INFINITE and lease_deadline(ind) <= time) then tmp_dw := lease_deadline(ind) + CONFIG_ARRAY_T(ind).LEASE_DURATION; lease_deadline_next(ind) <= tmp_dw; -- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock) -- Update Check Time if (tmp_dw < lease_check_time) then lease_check_time_next <= tmp_dw; end if; status_sig_next(ind) <= status_sig(ind) or LIVELINESS_LOST_STATUS; liveliness_lost_cnt_next(ind) <= std_logic_vector(unsigned(liveliness_lost_cnt(ind)) + 1); liveliness_lost_cnt_change_next(ind) <= std_logic_vector(unsigned(liveliness_lost_cnt_change(ind)) + 1); -- Continue cnt_next <= 0; -- GET NEXT WRITER else if (CONFIG_ARRAY_T(ind).LEASE_DURATION /= DURATION_INFINITE and lease_deadline(ind) <= lease_check_time) then lease_check_time_next <= lease_deadline(ind); end if; -- Continue cnt_next <= 0; -- GET NEXT WRITER end if; when others => null; end case; end if; when CHECK_ACK_WAIT => case (cnt) is -- GET NEXT WRITER when 0 => if (ind = NUM_WRITERS-1) then -- Reset ack_wait_check_next <= '0'; -- DONE stage_next <= IDLE; else -- Next Writer ind_next <= ind + 1; cnt_next <= cnt + 1; end if; -- CHECK ACK STATE when 1 => -- Writer in WAIT_FOR_ACKNOWLEDGEMENTS Operation if(ack_wait(ind) = '1') then -- All Writer Samples are ACKed if (global_ack_cnt(ind) = global_sample_cnt(ind)) then -- Reset ack_wait_next(ind) <= '0'; -- DONE done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_OK; -- Continue cnt_next <= 0; -- GET NEXT WRITER else cnt_next <= cnt + 1; end if; else -- Continue cnt_next <= 0; -- GET NEXT WRITER end if; -- CHECK OPERATION TIMEOUT when 2 => assert (ack_wait(ind) = '1') severity FAILURE; -- WAIT_FOR_ACKNOWLEDGEMENTS Operation Timeout if (timeout_time(ind) <= time) then -- Reset ack_wait_next(ind) <= '0'; -- DONE done_dds(ind) <= '1'; return_code_dds(ind) <= RETCODE_TIMEOUT; -- Continue cnt_next <= 0; -- GET NEXT WRITER else if (timeout_time(ind) <= timeout_check_time) then timeout_check_time_next <= timeout_time(ind); end if; -- Continue cnt_next <= 0; -- GET NEXT WRITER end if; when others => null; end case; when RESET_SAMPLE_MEMORY => case (cnt) is -- SET Previous Pointer when 0 => sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET; sample_write_data <= std_logic_vector(resize(prev_sample,WORD_WIDTH)); -- Memory Flow Control Guard if (sample_ready_in = '1') then cnt_next <= cnt + 1; end if; -- SET Next Pointer when 1 => sample_valid_in <= '1'; sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET; if (cur_sample = MAX_SAMPLE_ADDRESS(ind)) then sample_write_data <= std_logic_vector(resize(SAMPLE_MEMORY_MAX_ADDRESS,WORD_WIDTH)); else sample_write_data <= std_logic_vector(resize(cur_sample + SAMPLE_FRAME_SIZE,WORD_WIDTH)); end if; -- Memory Flow Control Guard if (sample_ready_in = '1') then if (cur_sample = MAX_SAMPLE_ADDRESS(ind)) then empty_sample_list_head_next(ind) <= FIRST_SAMPLE_ADDRESS; empty_sample_list_tail_next(ind) <= MAX_SAMPLE_ADDRESS(ind); -- DONE cur_payload_next <= FIRST_PAYLOAD_ADDRESS; stage_next <= RESET_PAYLOAD_MEMORY; else -- Continue cur_sample_next <= cur_sample + SAMPLE_FRAME_SIZE; prev_sample_next <= cur_sample; cnt_next <= 0; -- SET Previous Pointer end if; end if; when others => null; end case; when RESET_PAYLOAD_MEMORY => -- SET Next Pointer payload_valid_in <= '1'; payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET; if (cur_payload = MAX_PAYLOAD_ADDRESS(ind)) then payload_write_data <= std_logic_vector(resize(PAYLOAD_MEMORY_MAX_ADDRESS,WORD_WIDTH)); else payload_write_data <= std_logic_vector(resize(cur_payload + PAYLOAD_FRAME_SIZE(ind),WORD_WIDTH)); end if; -- Memory Flow Control Guard if (payload_ready_in = '1') then if (cur_payload = MAX_PAYLOAD_ADDRESS(ind)) then empty_payload_list_head_next(ind) <= FIRST_PAYLOAD_ADDRESS; if (ind = NUM_WRITERS-1) then -- DONE stage_next <= IDLE; else -- Continue (Next Writer) ind_next <= ind + 1; prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS; cur_sample_next <= FIRST_SAMPLE_ADDRESS; stage_next <= RESET_SAMPLE_MEMORY; cnt_next <= 0; end if; else cur_payload_next <= cur_payload + PAYLOAD_FRAME_SIZE(ind); end if; end if; end case; end process; empty_head_sig_prc : process(all) begin for i in 0 to NUM_WRITERS-1 loop empty_inst_head_sig(i) <= to_integer(inst_empty_head(i)); empty_sample_head_sig(i) <= to_integer(empty_sample_list_head(i)); empty_payload_head_sig(i) <= to_integer(empty_payload_list_head(i)); end loop; end process; -- *Instance Memory Process* -- STATE DESCRIPTION -- IDLE Idle State. Done Signal is pulled high and Memory FSM accepts new memory operations -- SEARCH_INSTANCE See Memory OPCODE Description -- GET_NEXT_INSTANCE See Memory OPCODE Description -- GET_INSTANCE_DATA Latch specified Instance Data for use by main process -- 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_addr_latch_next <= inst_addr_latch; inst_empty_head_next <= inst_empty_head; inst_occupied_head_next <= inst_occupied_head; inst_latch_data_next <= inst_latch_data; inst_cnt_next <= inst_cnt; 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_abort_read <= '0'; inst_addr <= (others => '0'); inst_write_data <= (others => '0'); case (inst_stage) is when IDLE => inst_op_done <= '1'; if (inst_op_start = '1') then inst_latch_data_next <= inst_r; case(inst_opcode) is when SEARCH_INSTANCE => -- Reset Data inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; -- No Instances available if (inst_occupied_head(inst_r.i) /= INSTANCE_MEMORY_MAX_ADDRESS) then inst_addr_base_next <= inst_occupied_head(inst_r.i); inst_stage_next <= SEARCH_INSTANCE; inst_cnt_next <= 0; end if; when INSERT_INSTANCE => assert (inst_empty_head(inst_r.i) /= INSTANCE_MEMORY_MAX_ADDRESS) severity FAILURE; inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; inst_data_next.addr <= inst_empty_head(inst_r.i); inst_addr_base_next <= inst_empty_head(inst_r.i); inst_stage_next <= INSERT_INSTANCE; inst_cnt_next <= 0; when UPDATE_INSTANCE => if (inst_r.addr = INSTANCE_MEMORY_MAX_ADDRESS) then inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; else if (inst_r.i /= inst_data.i or inst_r.addr /= inst_data.addr) then inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; end if; inst_data_next.addr <= inst_r.addr; inst_addr_base_next <= inst_r.addr; inst_stage_next <= UPDATE_INSTANCE; if check_mask(inst_r.field_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_r.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 1; elsif check_mask(inst_r.field_flags,IMF_ACK_CNT_FLAG) then inst_cnt_next <= 2; else -- DONE inst_stage_next <= IDLE; end if; end if; when REMOVE_INSTANCE => inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; if (inst_r.addr /= INSTANCE_MEMORY_MAX_ADDRESS) then inst_addr_base_next <= inst_r.addr; inst_stage_next <= REMOVE_INSTANCE; inst_cnt_next <= 0; end if; when GET_NEXT_INSTANCE => inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; -- No Instances available if (inst_r.addr /= INSTANCE_MEMORY_MAX_ADDRESS) then inst_addr_base_next <= inst_r.addr; inst_stage_next <= GET_NEXT_INSTANCE; inst_cnt_next <= 0; end if; when GET_INSTANCE => if (inst_r.addr = INSTANCE_MEMORY_MAX_ADDRESS) then inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; else if (inst_r.i /= inst_data.i or inst_r.addr /= inst_data.addr) then inst_data_next <= ZERO_INSTANCE_DATA; inst_data_next.i <= inst_r.i; end if; inst_data_next.addr <= inst_r.addr; inst_addr_base_next <= inst_r.addr; inst_stage_next <= GET_INSTANCE_DATA; if check_mask(inst_r.field_flags,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_r.field_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 4; elsif check_mask(inst_r.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 5; elsif check_mask(inst_r.field_flags,IMF_ACK_CNT_FLAG) then inst_cnt_next <= 6; else -- DONE inst_stage_next <= IDLE; end if; end if; when others => null; end case; end if; when SEARCH_INSTANCE => 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 inst_cnt_next <= inst_cnt + 1; end if; -- READ Key Hash 1/4 when 4 => 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 inst_abort_read <= '1'; inst_cnt_next <= 8; -- GET NEXT INSTANCE else inst_cnt_next <= inst_cnt + 1; end if; end if; -- READ Key Hash 2/4 when 5 => 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 inst_abort_read <= '1'; inst_cnt_next <= 8; -- GET NEXT INSTANCE else inst_cnt_next <= inst_cnt + 1; end if; end if; -- READ Key Hash 3/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(2)) then inst_abort_read <= '1'; inst_cnt_next <= 8; -- GET NEXT INSTANCE else inst_cnt_next <= inst_cnt + 1; end if; end if; -- READ Key Hash 4/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(3)) then inst_cnt_next <= 8; -- GET NEXT INSTANCE else inst_data_next.addr <= inst_addr_base; -- Get Instance Data inst_stage_next <= GET_INSTANCE_DATA; if check_mask(inst_latch_data.field_flags,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_latch_data.field_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 4; elsif check_mask(inst_latch_data.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 5; elsif check_mask(inst_latch_data.field_flags,IMF_ACK_CNT_FLAG) then inst_cnt_next <= 6; else -- DONE inst_stage_next <= IDLE; end if; end if; end if; -- GET Next Instance when 8 => 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 9 => inst_ready_out <= '1'; -- Memory Flow Control Guard if (inst_valid_out = '1') then -- No more Endpoints if (resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = INSTANCE_MEMORY_MAX_ADDRESS) then inst_data_next.addr <= INSTANCE_MEMORY_MAX_ADDRESS; --No match -- DONE inst_stage_next <= IDLE; else -- Continue inst_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_cnt_next <= 0; 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 if (resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = INSTANCE_MEMORY_MAX_ADDRESS) then inst_data_next.addr <= INSTANCE_MEMORY_MAX_ADDRESS; -- DONE inst_stage_next <= IDLE; else inst_data_next.addr <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); -- Get Instance Data inst_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_stage_next <= GET_INSTANCE_DATA; if check_mask(inst_latch_data.field_flags,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 0; elsif check_mask(inst_latch_data.field_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 4; elsif check_mask(inst_latch_data.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 5; elsif check_mask(inst_latch_data.field_flags,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 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_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 4; elsif check_mask(inst_latch_data.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 5; elsif check_mask(inst_latch_data.field_flags,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_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 5; elsif check_mask(inst_latch_data.field_flags,IMF_ACK_CNT_FLAG) then inst_cnt_next <= 6; else if check_mask(inst_latch_data.field_flags,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_flags,IMF_ACK_CNT_FLAG) then inst_cnt_next <= 6; else if check_mask(inst_latch_data.field_flags,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 7; elsif check_mask(inst_latch_data.field_flags,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_flags,IMF_KEY_HASH_FLAG) then inst_cnt_next <= 7; elsif check_mask(inst_latch_data.field_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 11; elsif check_mask(inst_latch_data.field_flags,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_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_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_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_data_next.key_hash(3) <= inst_read_data; inst_data_next.field_flags <= inst_data.field_flags or IMF_KEY_HASH_FLAG; if check_mask(inst_latch_data.field_flags,IMF_STATUS_FLAG) then inst_cnt_next <= 11; elsif check_mask(inst_latch_data.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 12; elsif check_mask(inst_latch_data.field_flags,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_data_next.status_info <= inst_read_data; inst_data_next.field_flags <= inst_data.field_flags or IMF_STATUS_FLAG; if check_mask(inst_latch_data.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 12; elsif check_mask(inst_latch_data.field_flags,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_data_next.sample_cnt <= unsigned(inst_read_data); inst_data_next.field_flags <= inst_data.field_flags or IMF_SAMPLE_CNT_FLAG; if check_mask(inst_latch_data.field_flags,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_data_next.ack_cnt <= unsigned(inst_read_data); inst_data_next.field_flags <= inst_data.field_flags or IMF_ACK_CNT_FLAG; -- DONE inst_stage_next <= IDLE; end if; end case; when INSERT_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; -- SET Key Hash 1/4 when 1 => 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; -- SET Key Hash 2/4 when 2 => 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; -- SET Key Hash 3/4 when 3 => 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; -- SET Key Hash 4/4 when 4 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3; inst_write_data <= inst_latch_data.key_hash(3); inst_data_next.field_flags <= inst_data.field_flags or IMF_KEY_HASH_FLAG; -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET Status Info when 5 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET; inst_write_data <= inst_latch_data.status_info; inst_data_next.field_flags <= inst_data.field_flags or IMF_STATUS_FLAG; -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET Sample Count when 6 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET; inst_write_data <= std_logic_vector(inst_latch_data.sample_cnt); inst_data_next.field_flags <= inst_data.field_flags or IMF_SAMPLE_CNT_FLAG; -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET ACK Count when 7 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_ACK_CNT_OFFSET; inst_write_data <= std_logic_vector(inst_latch_data.ack_cnt); inst_data_next.field_flags <= inst_data.field_flags or IMF_ACK_CNT_FLAG; -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET Next Addr when 8 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(inst_occupied_head(inst_latch_data.i),WORD_WIDTH)); -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET Prev Addr when 9 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_PREV_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(INSTANCE_MEMORY_MAX_ADDRESS,WORD_WIDTH)); -- Memory Flow Control Guard if (inst_ready_in = '1') then if (inst_occupied_head(inst_latch_data.i) = INSTANCE_MEMORY_MAX_ADDRESS) then inst_cnt_next <= inst_cnt + 2; -- Skip Next Step else inst_cnt_next <= inst_cnt + 1; end if; end if; -- SET Prev Addr (Occupied Head) when 10 => inst_valid_in <= '1'; inst_addr <= inst_occupied_head(inst_latch_data.i) + IMF_PREV_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(inst_addr_base,WORD_WIDTH)); -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- READ Next Addr when 11 => inst_ready_out <= '1'; -- Memory Flow Control Guard if (inst_valid_out = '1') then -- Update List Heads inst_empty_head_next(inst_latch_data.i) <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_occupied_head_next(inst_latch_data.i) <= inst_addr_base; -- 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; inst_data_next.field_flags <= inst_data.field_flags or IMF_STATUS_FLAG; -- Memory Flow Control Guard if (inst_ready_in = '1') then if check_mask(inst_latch_data.field_flags,IMF_SAMPLE_CNT_FLAG) then inst_cnt_next <= 1; elsif check_mask(inst_latch_data.field_flags,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 <= std_logic_vector(inst_latch_data.sample_cnt); inst_data_next.sample_cnt <= inst_latch_data.sample_cnt; inst_data_next.field_flags <= inst_data.field_flags or IMF_SAMPLE_CNT_FLAG; -- Memory Flow Control Guard if (inst_ready_in = '1') then if check_mask(inst_latch_data.field_flags,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 <= std_logic_vector(inst_latch_data.ack_cnt); inst_data_next.ack_cnt <= inst_latch_data.ack_cnt; inst_data_next.field_flags <= inst_data.field_flags or IMF_ACK_CNT_FLAG; -- 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 => case (inst_cnt) is -- GET Next Addr 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 Prev Addr when 1 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_PREV_ADDR_OFFSET; inst_read <= '1'; -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET Next Addr when 2 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(inst_empty_head(inst_latch_data.i),WORD_WIDTH)); if (inst_ready_in = '1') then -- Set New Empty Head inst_empty_head_next(inst_latch_data.i) <= inst_addr_base; inst_cnt_next <= inst_cnt + 1; end if; -- READ Next Addr when 3 => inst_ready_out <= '1'; -- Memory Flow Control Guard if (inst_valid_out = '1') then inst_addr_latch_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_cnt_next <= inst_cnt + 1; end if; -- READ Prev Addr when 4 => inst_ready_out <= '1'; -- Memory Flow Control Guard if (inst_valid_out = '1') then if (inst_addr_latch = INSTANCE_MEMORY_MAX_ADDRESS) then if (resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = INSTANCE_MEMORY_MAX_ADDRESS) then -- RESET Occupied List Head inst_occupied_head_next(inst_latch_data.i) <= INSTANCE_MEMORY_MAX_ADDRESS; inst_data_next.addr <= INSTANCE_MEMORY_MAX_ADDRESS; -- DONE inst_stage_next <= IDLE; else inst_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_cnt_next <= inst_cnt + 2; -- Skip Next Step end if; else inst_addr_base_next <= inst_addr_latch; inst_addr_latch_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH); inst_cnt_next <= inst_cnt + 1; end if; end if; -- SET Prev Addr (Next Slot) when 5 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_PREV_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(inst_addr_latch,WORD_WIDTH)); if (inst_ready_in = '1') then if (inst_addr_latch = INSTANCE_MEMORY_MAX_ADDRESS) then -- Set New Occupied List Head inst_occupied_head_next(inst_latch_data.i) <= inst_addr_base; inst_data_next.addr <= inst_addr_base; -- DONE inst_stage_next <= IDLE; else inst_addr_base_next <= inst_addr_latch; inst_addr_latch_next <= inst_addr_base; inst_cnt_next <= inst_cnt + 1; end if; end if; -- SET Next Addr (Previous Slot) when 6 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(inst_addr_latch,WORD_WIDTH)); if (inst_ready_in = '1') then inst_data_next.addr <= inst_addr_latch; -- DONE inst_stage_next <= IDLE; end if; when others => null; end case; when RESET_MEMORY => case (inst_cnt) is -- SET Next Pointer when 0 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET; if (inst_addr_base = MAX_INSTANCE_ADDRESS(inst_latch_data.i)) then inst_write_data <= std_logic_vector(resize(INSTANCE_MEMORY_MAX_ADDRESS,WORD_WIDTH)); else inst_write_data <= std_logic_vector(resize(inst_addr_base + INSTANCE_FRAME_SIZE,WORD_WIDTH)); end if; -- Memory Flow Control Guard if (inst_ready_in = '1') then inst_cnt_next <= inst_cnt + 1; end if; -- SET Previous Pointer when 1 => inst_valid_in <= '1'; inst_addr <= inst_addr_base + IMF_PREV_ADDR_OFFSET; inst_write_data <= std_logic_vector(resize(inst_addr_latch,WORD_WIDTH)); -- Memory Flow Control Guard if (inst_ready_in = '1') then if (inst_addr_base = MAX_INSTANCE_ADDRESS(inst_latch_data.i)) then -- Initialize Empty and Occupied Heads inst_empty_head_next(inst_latch_data.i) <= FIRST_INSTANCE_ADDRESS; inst_occupied_head_next(inst_latch_data.i) <= INSTANCE_MEMORY_MAX_ADDRESS; if (inst_latch_data.i = NUM_WRITERS-1) then -- DONE inst_stage_next <= IDLE; else -- NEXT MEMORY inst_latch_data_next.i <= inst_latch_data.i + 1; inst_addr_base_next <= FIRST_INSTANCE_ADDRESS; inst_addr_latch_next <= INSTANCE_MEMORY_MAX_ADDRESS; inst_cnt_next <= 0; end if; else inst_addr_latch_next <= inst_addr_base; inst_addr_base_next <= inst_addr_base + INSTANCE_FRAME_SIZE; inst_cnt_next <= 0; end if; end if; when others => null; end case; end case; end process; sync_prc : process(clk) begin if rising_edge(clk) then if (reset = '1') then stage <= RESET_SAMPLE_MEMORY; return_stage <= IDLE; inst_stage <= RESET_MEMORY; instance_handle <= HANDLE_NIL; cc_instance_handle_sig <= HANDLE_NIL; sample_rej_last_inst <= HANDLE_NIL; deadline_miss_last_inst <= (others => HANDLE_NIL); key_hash <= KEY_HASH_NIL; deadline_check_time <= TIME_ZERO; for i in 0 to NUM_WRITERS-1 loop deadline_time(i) <= time + CONFIG_ARRAY_T(i).DEADLINE_QOS; lease_deadline(i) <= time + CONFIG_ARRAY_T(i).LEASE_DURATION; end loop; lifespan_time <= TIME_INFINITE; source_ts <= TIME_INVALID; timeout_check_time <= TIME_INVALID; timeout_time <= (others => TIME_INVALID); lease_check_time <= TIME_ZERO; cc_source_timestamp_sig <= TIME_INVALID; lifespan <= DURATION_INFINITE; global_seq_nr <= (others => FIRST_SEQUENCENUMBER); seq_nr <= SEQUENCENUMBER_UNKNOWN; cc_seq_nr_sig <= SEQUENCENUMBER_UNKNOWN; cc_kind_sig <= ALIVE; inst_data <= ZERO_INSTANCE_DATA; inst_latch_data <= ZERO_INSTANCE_DATA; ind <= 0; cnt <= 0; cnt2 <= 0; cnt3 <= 0; global_sample_cnt <= (others => 0); global_ack_cnt <= (others => 0); stale_inst_cnt <= (others => 0); inst_cnt <= 0; store_payload <= '0'; store_serialized_key <= '0'; need_kh_op <= '0'; remove_oldest_sample <= '0'; remove_oldest_inst_sample <= '0'; remove_ack_sample <= '0'; is_lifespan_check <= '0'; register_op <= '0'; lookup_op <= '0'; ack_wait <= (others => '0'); ack_wait_check <= '0'; is_ack <= '0'; is_rtps <= '0'; data_available_sig <= (others => '0'); orphan_samples <= '0'; newest_sample <= (others => SAMPLE_MEMORY_MAX_ADDRESS); oldest_sample <= (others => SAMPLE_MEMORY_MAX_ADDRESS); empty_payload_list_head <= (others => PAYLOAD_MEMORY_MAX_ADDRESS); empty_sample_list_head <= (others => SAMPLE_MEMORY_MAX_ADDRESS); empty_sample_list_tail <= (others => SAMPLE_MEMORY_MAX_ADDRESS); payload_addr_latch_1 <= (others => '0'); payload_addr_latch_2 <= (others => '0'); long_latch <= (others => '0'); sample_addr_latch_1 <= SAMPLE_MEMORY_MAX_ADDRESS; sample_addr_latch_2 <= (others => '0'); sample_addr_latch_3 <= FIRST_SAMPLE_ADDRESS; sample_addr_latch_4 <= (others => '0'); inst_addr_latch_1 <= (others => '0'); inst_addr_latch_2 <= (others => '0'); sample_status_info <= (others => '0'); sample_rej_cnt <= (others => '0'); sample_rej_cnt_change <= (others => '0'); sample_rej_last_reason <= (others => '0'); deadline_miss_cnt <= (others => (others => '0')); deadline_miss_cnt_change <= (others => (others => '0')); liveliness_lost_cnt <= (others => (others => '0')); liveliness_lost_cnt_change <= (others => (others => '0')); status_sig <= (others => (others => '0')); inst_addr_base <= FIRST_INSTANCE_ADDRESS; inst_empty_head <= (others => INSTANCE_MEMORY_MAX_ADDRESS); inst_occupied_head <= (others => INSTANCE_MEMORY_MAX_ADDRESS); inst_addr_latch <= INSTANCE_MEMORY_MAX_ADDRESS; inst_long_latch <= (others => '0'); return_code_latch <= RETCODE_UNSUPPORTED; else stage <= stage_next; return_stage <= return_stage_next; inst_stage <= inst_stage_next; instance_handle <= instance_handle_next; cc_instance_handle_sig <= cc_instance_handle_sig_next; sample_rej_last_inst <= sample_rej_last_inst_next; deadline_miss_last_inst <= deadline_miss_last_inst_next; key_hash <= key_hash_next; deadline_check_time <= deadline_check_time_next; deadline_time <= deadline_time_next; lifespan_time <= lifespan_time_next; source_ts <= source_ts_next; timeout_check_time <= timeout_check_time_next; timeout_time <= timeout_time_next; lease_check_time <= lease_check_time_next; lease_deadline <= lease_deadline_next; cc_source_timestamp_sig <= cc_source_timestamp_sig_next; lifespan <= lifespan_next; global_seq_nr <= global_seq_nr_next; seq_nr <= seq_nr_next; cc_seq_nr_sig <= cc_seq_nr_sig_next; cc_kind_sig <= cc_kind_sig_next; inst_data <= inst_data_next; inst_latch_data <= inst_latch_data_next; ind <= ind_next; cnt <= cnt_next; cnt2 <= cnt2_next; cnt3 <= cnt3_next; global_sample_cnt <= global_sample_cnt_next; global_ack_cnt <= global_ack_cnt_next; stale_inst_cnt <= stale_inst_cnt_next; inst_cnt <= inst_cnt_next; store_payload <= store_payload_next; store_serialized_key <= store_serialized_key_next; need_kh_op <= need_kh_op_next; remove_oldest_sample <= remove_oldest_sample_next; remove_oldest_inst_sample <= remove_oldest_inst_sample_next; remove_ack_sample <= remove_ack_sample_next; is_lifespan_check <= is_lifespan_check_next; register_op <= register_op_next; lookup_op <= lookup_op_next; ack_wait <= ack_wait_next; ack_wait_check <= ack_wait_check_next; is_ack <= is_ack_next; is_rtps <= is_rtps_next; data_available_sig <= data_available_sig_next; orphan_samples <= orphan_samples_next; newest_sample <= newest_sample_next; oldest_sample <= oldest_sample_next; empty_payload_list_head <= empty_payload_list_head_next; empty_sample_list_head <= empty_sample_list_head_next; empty_sample_list_tail <= empty_sample_list_tail_next; payload_addr_latch_1 <= payload_addr_latch_1_next; payload_addr_latch_2 <= payload_addr_latch_2_next; long_latch <= long_latch_next; sample_addr_latch_1 <= sample_addr_latch_1_next; sample_addr_latch_2 <= sample_addr_latch_2_next; sample_addr_latch_3 <= sample_addr_latch_3_next; sample_addr_latch_4 <= sample_addr_latch_4_next; inst_addr_latch_1 <= inst_addr_latch_1_next; inst_addr_latch_2 <= inst_addr_latch_2_next; sample_status_info <= sample_status_info_next; sample_rej_cnt <= sample_rej_cnt_next; sample_rej_cnt_change <= sample_rej_cnt_change_next; sample_rej_last_reason <= sample_rej_last_reason_next; deadline_miss_cnt <= deadline_miss_cnt_next; deadline_miss_cnt_change <= deadline_miss_cnt_change_next; liveliness_lost_cnt <= liveliness_lost_cnt_next; liveliness_lost_cnt_change <= liveliness_lost_cnt_change_next; status_sig <= status_sig_next; inst_addr_base <= inst_addr_base_next; inst_empty_head <= inst_empty_head_next; inst_occupied_head <= inst_occupied_head_next; inst_addr_latch <= inst_addr_latch_next; inst_long_latch <= inst_long_latch_next; return_code_latch <= return_code_latch_next; end if; end if; end process; end architecture;