rtps-fpga/src/dds_writer.vhd
John Daktylidis c318b3c560 Re-design Key Holder interaction of DDS Reader/Writer
The DDS Writer was expecting the user to provide the serialized key
on DISPOSE/UNREGISTER operations. The user should have no direct
interaction with the serialized key.
The operation flow was changed to expect the normal payload from the
user, push it to the Key Holder, and the calculate the serialized key.
The stage that was responsible for simutanously pushing the input to
payload memory and/or the Key Holder was simplified, and the decode
error signal of the Key Holder is now handled.

The last two changes (simplified stage and decode error handling)
were also ported to the DDS Reader.
2023-06-22 20:11:17 +02:00

5145 lines
283 KiB
VHDL

-- 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;