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.
5145 lines
283 KiB
VHDL
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;
|