Using seperately compiled Libraries we interconnect two systems, and test their communication and interaction. A bug in rtps_builtin_endpoint was fixed (were if only the SUB data was to be sent, it was never actually sent).
4588 lines
252 KiB
VHDL
4588 lines
252 KiB
VHDL
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;
|
|
|
|
-- TODO: Check if sample_cnt is always maintained (also with MAX_SAMPLES_PER_INSTANCE = LENGTH_UNLIMITED)
|
|
|
|
entity dds_writer is
|
|
generic (
|
|
ID : ID_TYPE := 0;
|
|
HISTORY_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := ENDPOINT_HISTORY_QOS(ID);
|
|
DEADLINE_QOS : DURATION_TYPE := ENDPOINT_DEADLINE_QOS(ID);
|
|
LIFESPAN_QOS : DURATION_TYPE := ENDPOINT_LIFESPAN_QOS(ID);
|
|
LEASE_DURATION : DURATION_TYPE := ENDPOINT_LEASE_DURATION(ID);
|
|
WITH_KEY : boolean := ENDPOINT_WITH_KEY(ID);
|
|
MAX_SAMPLES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := ENDPOINT_MAX_SAMPLES(ID);
|
|
MAX_INSTANCES : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := ENDPOINT_MAX_INSTANCES(ID);
|
|
MAX_SAMPLES_PER_INSTANCE : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := ENDPOINT_MAX_SAMPLES_PER_INSTANCE(ID);
|
|
PAYLOAD_FRAME_SIZE : natural
|
|
);
|
|
port (
|
|
-- SYSTEM
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
time : in TIME_TYPE;
|
|
-- TO/FROM RTPS ENDPOINT
|
|
start_rtps : in std_logic;
|
|
opcode_rtps : in HISTORY_CACHE_OPCODE_TYPE;
|
|
ack_rtps : out std_logic;
|
|
done_rtps : out std_logic;
|
|
ret_rtps : out HISTORY_CACHE_RESPONSE_TYPE;
|
|
seq_nr_rtps : in SEQUENCENUMBER_TYPE;
|
|
get_data_rtps : in std_logic;
|
|
data_out_rtps : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
valid_out_rtps : out std_logic;
|
|
ready_out_rtps : in std_logic;
|
|
last_word_out_rtps : out std_logic;
|
|
liveliness_assertion : out std_logic;
|
|
data_available : out std_logic;
|
|
-- Cache Change
|
|
cc_instance_handle : out INSTANCE_HANDLE_TYPE;
|
|
cc_kind : out CACHE_CHANGE_KIND_TYPE;
|
|
cc_source_timestamp : out TIME_TYPE;
|
|
cc_seq_nr : out SEQUENCENUMBER_TYPE;
|
|
-- TO/FROM KEY_HOLDER
|
|
start_kh : out std_logic;
|
|
opcode_kh : out KEY_HOLDER_OPCODE_TYPE;
|
|
ack_kh : in std_logic;
|
|
data_in_kh : in std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
valid_in_kh : in std_logic;
|
|
ready_in_kh : out std_logic;
|
|
last_word_in_kh : in std_logic;
|
|
data_out_kh : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
valid_out_kh : out std_logic;
|
|
ready_out_kh : in std_logic;
|
|
last_word_out_kh : out std_logic;
|
|
abort_kh : out std_logic;
|
|
-- TO/FROM USER ENTITY
|
|
start_dds : in std_logic;
|
|
ack_dds : out std_logic;
|
|
opcode_dds : in DDS_WRITER_OPCODE_TYPE;
|
|
instance_handle_dds : in INSTANCE_HANDLE_TYPE;
|
|
source_ts_dds : in TIME_TYPE;
|
|
max_wait_dds : in DURATION_TYPE;
|
|
done_dds : out std_logic;
|
|
return_code_dds : out std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
|
|
ready_in_dds : out std_logic;
|
|
valid_in_dds : in std_logic;
|
|
data_in_dds : in std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
last_word_in_dds : in std_logic;
|
|
ready_out_dds : in std_logic;
|
|
valid_out_dds : out std_logic;
|
|
data_out_dds : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
last_word_out_dds : out std_logic;
|
|
-- Communication Status
|
|
status : out std_logic_vector(STATUS_KIND_WIDTH-1 downto 0)
|
|
);
|
|
end entity;
|
|
|
|
architecture arch of dds_writer is
|
|
|
|
--*****CONSTANT DECLARATION*****
|
|
-- *SAMPLE MEMORY*
|
|
-- 4-Byte Word Size of a Sample Info Entry in Memory
|
|
function gen_frame_size(lifespan : DURATION_TYPE; WITH_KEY : boolean) return natural is
|
|
variable ret : natural := 0;
|
|
begin
|
|
if (lifespan /= DURATION_INFINITE and WITH_KEY) then
|
|
return 11;
|
|
elsif (lifespan /= DURATION_INFINITE and (not WITH_KEY)) then
|
|
return 10;
|
|
elsif (lifespan = DURATION_INFINITE and WITH_KEY) then
|
|
return 9;
|
|
else --lifespan = DURATION_INFINITE and (not WITH_KEY)
|
|
return 8;
|
|
end if;
|
|
end function;
|
|
constant SAMPLE_FRAME_SIZE : natural := gen_frame_size(LIFESPAN_QOS,WITH_KEY);
|
|
-- Sample Info Memory Size in 4-Byte Words
|
|
constant SAMPLE_MEMORY_SIZE : natural := to_integer(unsigned(MAX_SAMPLES)+1) * SAMPLE_FRAME_SIZE;
|
|
-- Sample Info Memory Address Width
|
|
constant SAMPLE_MEMORY_ADDR_WIDTH : natural := log2c(SAMPLE_MEMORY_SIZE);
|
|
-- Highest Sample Info Memory Address
|
|
constant SAMPLE_MEMORY_MAX_ADDRESS : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(SAMPLE_MEMORY_SIZE-1, SAMPLE_MEMORY_ADDR_WIDTH);
|
|
-- Highest Sample Info Frame Address
|
|
constant MAX_SAMPLE_ADDRESS : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := SAMPLE_MEMORY_MAX_ADDRESS - SAMPLE_FRAME_SIZE + 1;
|
|
-- 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*
|
|
-- Payload Memory Size in 4-Byte Words
|
|
constant PAYLOAD_MEMORY_SIZE : natural := to_integer(unsigned(MAX_SAMPLES)+1) * PAYLOAD_FRAME_SIZE;
|
|
-- Payload Memory Address Width
|
|
constant PAYLOAD_MEMORY_ADDR_WIDTH : natural := log2c(PAYLOAD_MEMORY_SIZE);
|
|
-- Highest Payload Memory Address
|
|
constant PAYLOAD_MEMORY_MAX_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(PAYLOAD_MEMORY_SIZE-1, PAYLOAD_MEMORY_ADDR_WIDTH);
|
|
-- Highest Payload Frame Address
|
|
constant MAX_PAYLOAD_ADDRESS : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := PAYLOAD_MEMORY_MAX_ADDRESS - PAYLOAD_FRAME_SIZE + 1;
|
|
-- 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 := 8;
|
|
-- Instance Memory Size in 4-Byte Words
|
|
constant INSTANCE_MEMORY_SIZE : natural := to_integer(unsigned(MAX_INSTANCES)) * INSTANCE_FRAME_SIZE;
|
|
-- Instance Memory Address Width
|
|
constant INSTANCE_MEMORY_ADDR_WIDTH : natural := log2c(INSTANCE_MEMORY_SIZE);
|
|
-- Highest Instance Memory Address
|
|
constant INSTANCE_MEMORY_MAX_ADDRESS: unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(INSTANCE_MEMORY_SIZE-1, INSTANCE_MEMORY_ADDR_WIDTH);
|
|
-- Highest Instance Frame Address
|
|
constant MAX_INSTANCE_ADDRESS : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := INSTANCE_MEMORY_MAX_ADDRESS - INSTANCE_FRAME_SIZE + 1;
|
|
-- Address pointing to the beginning of the first Instance Data Frame
|
|
constant FIRST_INSTANCE_ADDRESS : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
|
|
-- *SAMPLE MEMORY FRAME 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;
|
|
function gen_smf_payload_addr_offset(lifespan : DURATION_TYPE) return natural is
|
|
variable ret : natural := 0;
|
|
begin
|
|
ret := (SMF_LIFESPAN_DEADLINE_OFFSET + 2) when (lifespan /= DURATION_INFINITE) else SMF_LIFESPAN_DEADLINE_OFFSET;
|
|
return ret;
|
|
end function;
|
|
constant SMF_PAYLOAD_ADDR_OFFSET : natural := gen_smf_payload_addr_offset(LIFESPAN_QOS);
|
|
constant SMF_INSTANCE_ADDR_OFFSET : natural := SMF_PAYLOAD_ADDR_OFFSET + 1;
|
|
function gen_smf_prev_addr_offset(WITH_KEY : boolean) return natural is
|
|
variable ret : natural := 0;
|
|
begin
|
|
ret := (SMF_INSTANCE_ADDR_OFFSET + 1) when WITH_KEY else SMF_INSTANCE_ADDR_OFFSET;
|
|
return ret;
|
|
end function;
|
|
constant SMF_PREV_ADDR_OFFSET : natural := gen_smf_prev_addr_offset(WITH_KEY);
|
|
constant SMF_NEXT_ADDR_OFFSET : natural := SMF_PREV_ADDR_OFFSET + 1;
|
|
|
|
-- *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_KEY_HASH_OFFSET : natural := 1;
|
|
constant IMF_STATUS_INFO_OFFSET : natural := 5;
|
|
constant IMF_SAMPLE_CNT_OFFSET : natural := 6;
|
|
constant IMF_ACK_CNT_OFFSET : natural := 7;
|
|
|
|
-- *INSTANCE MEMORY FRAME 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, ADD_PAYLOAD, NEXT_PAYLOAD_SLOT,
|
|
ALIGN_PAYLOAD, GET_KEY_HASH, INITIATE_INSTANCE_SEARCH, REGISTER_OPERATION, LOOKUP_OPERATION, PUSH_KEY_HASH, FILTER_STAGE, UPDATE_INSTANCE,
|
|
FINALIZE_PAYLOAD, 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, GET_SERIALIZED_KEY,
|
|
CHECK_LIFESPAN, GET_LIVELINESS_LOST_STATUS, GET_OFFERED_DEADLINE_MISSED_STATUS, CHECK_DEADLINE, RESET_SAMPLE_MEMORY, RESET_PAYLOAD_MEMORY);
|
|
-- Instance Memory FSM states. Explained below in detail
|
|
type INST_STAGE_TYPE is (IDLE, SEARCH_INSTANCE_HASH, SEARCH_INSTANCE_ADDR, GET_NEXT_INSTANCE, GET_INSTANCE_DATA, INSERT_INSTANCE, UPDATE_INSTANCE,
|
|
REMOVE_INSTANCE, RESET_MEMORY);
|
|
-- *Instance Memory Opcodes*
|
|
-- OPCODE DESCRIPTION
|
|
-- SEARCH_INSTANCE_HASH Search Instance based on Key Hash pointed by "key_hash".
|
|
-- Set "inst_addr_base" to Base Address of found Instance, of INSTANCE_MEMORY_MAX_ADDRESS if nothing found.
|
|
-- "inst_data" contains Instance Data according to "inst_mem_fields".
|
|
-- SEARCH_INSTANCE_ADDR Search Instance based on Instance Pointer pointed by "inst_addr_update".
|
|
-- Set "inst_addr_base" to "inst_addr_update"
|
|
-- "inst_data" contains Instance Data according to "inst_mem_fields".
|
|
-- INSERT_INSTANCE Insert Instance to memory.
|
|
-- UPDATE_INSTANCE Update Instance Data pointed by "inst_addr_base" according to "inst_mem_fields"
|
|
-- GET_FIRST_INSTANCE Get Instance Data of first Instance according to "inst_mem_fields".
|
|
-- Set "inst_addr_base" to Address of Instance or INSTANCE_MEMORY_MAX_ADDRESS if no Instance in Memory.
|
|
-- GET_NEXT_INSTANCE Get Instance Data of next Instance (from the Instance pointed by "inst_addr_base") according to "inst_mem_fields".
|
|
-- Set "inst_addr_base" to Address of Instance or INSTANCE_MEMORY_MAX_ADDRESS if no other Instance in Memory.
|
|
-- REMOVE_INSTANCE Remove Instance pointed by "inst_addr_base".
|
|
-- GET_INSTANCE Get Data of Instance pointed by "inst_addr_update" according to "inst_mem_fields".
|
|
-- Already fetched Data of the Participant is not modified.
|
|
type INSTANCE_OPCODE_TYPE is (NOP, SEARCH_INSTANCE_HASH, SEARCH_INSTANCE_ADDR, INSERT_INSTANCE, UPDATE_INSTANCE, GET_FIRST_INSTANCE, GET_NEXT_INSTANCE, REMOVE_INSTANCE,
|
|
GET_INSTANCE);
|
|
-- Record of Instance Data
|
|
type INSTANCE_DATA_TYPE is record
|
|
key_hash : KEY_HASH_TYPE;
|
|
status_info : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
sample_cnt : unsigned(WORD_WIDTH-1 downto 0);
|
|
ack_cnt : unsigned(WORD_WIDTH-1 downto 0);
|
|
end record;
|
|
-- Zero initialized Endpoint Data
|
|
constant ZERO_INSTANCE_DATA : INSTANCE_DATA_TYPE := (
|
|
key_hash => (others => (others => '0')),
|
|
status_info => (others => '0'),
|
|
sample_cnt => (others => '0'),
|
|
ack_cnt => (others => '0')
|
|
);
|
|
-- Instance Data Latch used as temporal cache by Instance Memory FSM
|
|
type INST_LATCH_DATA_TYPE is record
|
|
key_hash : KEY_HASH_TYPE;
|
|
status_info : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
|
|
sample_cnt : 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);
|
|
addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
end record;
|
|
-- Zero initialized Instance Data Latch
|
|
constant ZERO_INST_LATCH_DATA : INST_LATCH_DATA_TYPE := (
|
|
key_hash => (others => (others => '0')),
|
|
status_info => (others => '0'),
|
|
sample_cnt => (others => '0'),
|
|
ack_cnt => (others => '0'),
|
|
field_flags => (others => '0'),
|
|
addr => (others => '0')
|
|
);
|
|
|
|
--*****SIGNAL DECLARATION
|
|
-- *SAMPLE MEMORY CONNECTION SIGNALS*
|
|
signal sample_addr : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal sample_read : std_logic := '0';
|
|
signal sample_read_data, sample_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
|
|
signal sample_ready_in, sample_valid_in : std_logic := '0';
|
|
signal sample_ready_out, sample_valid_out : std_logic := '0';
|
|
signal sample_abort_read : std_logic := '0';
|
|
|
|
-- *PAYLOAD MEMORY CONNECTION SIGNALS*
|
|
signal payload_addr : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal payload_read : std_logic := '0';
|
|
signal payload_read_data, payload_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
|
|
signal payload_ready_in, payload_valid_in : std_logic := '0';
|
|
signal payload_ready_out, payload_valid_out : std_logic := '0';
|
|
signal payload_abort_read : std_logic := '0';
|
|
|
|
-- *INSTANCE MEMORY CONNECTION SIGNALS*
|
|
signal inst_addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
signal inst_read : std_logic := '0';
|
|
signal inst_read_data, inst_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0');
|
|
signal inst_ready_in, inst_valid_in : std_logic := '0';
|
|
signal inst_ready_out, inst_valid_out : std_logic := '0';
|
|
signal inst_abort_read : std_logic := '0';
|
|
|
|
-- *MAIN PROCESS*
|
|
-- FSM state
|
|
signal stage, stage_next : STAGE_TYPE := IDLE;
|
|
-- FSM state latch. Used to transition dynamically to different states from the same state.
|
|
signal return_stage, return_stage_next : STAGE_TYPE := IDLE;
|
|
-- General Purpose Counter
|
|
signal cnt, cnt_next : natural range 0 to 14 := 0;
|
|
-- Counter used to read/write Payload Fames
|
|
signal cnt2, cnt2_next : natural range 0 to max(PAYLOAD_FRAME_SIZE, INSTANCE_HANDLE_TYPE'length-1) := 0;
|
|
-- Counter used to read/write Payload Fames
|
|
signal cnt3, cnt3_next : natural range 0 to PAYLOAD_FRAME_SIZE := 0;
|
|
-- Head of Empty Sample List
|
|
signal empty_sample_list_head, empty_sample_list_head_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Tail of Empty Sample List
|
|
signal empty_sample_list_tail, empty_sample_list_tail_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Head of Empty Payload List
|
|
signal empty_payload_list_head, empty_payload_list_head_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Oldest Sample (Head of Occupied Sample List)
|
|
signal oldest_sample, oldest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Newest Sample (Tail of Occupied Sample List)
|
|
signal newest_sample, newest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Denotes if the oldest Sample should be removed
|
|
signal remove_oldest_sample, remove_oldest_sample_next : std_logic := '0';
|
|
-- Denotes if the oldest sample of the Instance with 'key_hash' should be removed
|
|
signal remove_oldest_inst_sample, remove_oldest_inst_sample_next : std_logic := '0';
|
|
-- Denotes if the Sample tobe removed should be ACKed
|
|
signal remove_ack_sample, remove_ack_sample_next : std_logic := '0';
|
|
-- Lifespan Latch
|
|
signal lifespan, lifespan_next : TIME_TYPE := TIME_INVALID;
|
|
-- Key hash Latch
|
|
signal key_hash, key_hash_next : KEY_HASH_TYPE := (others => (others => '0'));
|
|
-- Return Code Latch
|
|
signal return_code_latch, return_code_latch_next : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0) := (others => '0');
|
|
-- Instance Handle Latch
|
|
signal instance_handle, instance_handle_next : INSTANCE_HANDLE_TYPE := HANDLE_NIL;
|
|
-- Source Timestamp Latch
|
|
signal source_ts, source_ts_next : TIME_TYPE := TIME_INVALID;
|
|
-- Sequence Number Latch
|
|
signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN;
|
|
-- Sample Status Info Latch
|
|
signal sample_status_info, sample_status_info_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Payload Pointer
|
|
signal payload_addr_latch_1, payload_addr_latch_1_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Payload Pointer
|
|
signal payload_addr_latch_2, payload_addr_latch_2_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_1, sample_addr_latch_1_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_2, sample_addr_latch_2_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_3, sample_addr_latch_3_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_4, sample_addr_latch_4_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Instance Pointer
|
|
signal inst_addr_latch_1, inst_addr_latch_1_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Instance Pointer
|
|
signal inst_addr_latch_2, inst_addr_latch_2_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- General Purpose Long Latch
|
|
signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
-- Signal used to pass Sample Status Infos to Instance Memory Process
|
|
signal status_info_update : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
-- Signal used to pass TIMEs to the Instance Memory Process
|
|
signal deadline : TIME_TYPE := TIME_INVALID;
|
|
-- Signal containing the relevant Instance Memory Frame Fields of the Instance Memory Operation
|
|
signal inst_mem_fields : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (others => '0');
|
|
-- Signal used to pass Instance Pointers to the Instance Memory Process
|
|
signal inst_addr_update : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Signal used to pass Sample Counts to the Instance Memory Process
|
|
signal sample_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
-- Signal used to pass ACK Counts to the Instance Memory Process
|
|
signal ack_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
-- Signals start of Instance Memory Operation
|
|
signal inst_op_start : std_logic := '0';
|
|
-- Opcode of Instance Memory Operation (Valid only when inst_op_start is high)
|
|
signal inst_opcode : INSTANCE_OPCODE_TYPE := NOP;
|
|
-- Signals the end of an Instance Memory Operation
|
|
signal inst_op_done : std_logic := '0';
|
|
-- Time of next Sample Lifespan Check
|
|
signal lifespan_time, lifespan_time_next : TIME_TYPE := TIME_ZERO;
|
|
-- Signifies if a Lifespan Check is in progress
|
|
signal is_lifespan_check, is_lifespan_check_next : std_logic := '0';
|
|
-- Signal used to generate the monotonically rising Sequence Numbers
|
|
-- It contains the next applicable Sequence Number
|
|
signal global_seq_nr, global_seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN;
|
|
-- Signal containing the current number of stored samples
|
|
signal global_sample_cnt, global_sample_cnt_next : natural range 0 to to_integer(unsigned(MAX_SAMPLES)+1) := 0;
|
|
-- Signal containing the current number of ACKed stored samples
|
|
signal global_ack_cnt, global_ack_cnt_next : natural range 0 to to_integer(unsigned(MAX_SAMPLES)+1) := 0;
|
|
-- Signal containing the number of currently stale Instances
|
|
signal stale_inst_cnt, stale_inst_cnt_next : natural range 0 to to_integer(unsigned(MAX_INSTANCES)) := 0;
|
|
-- Signifies if a Instance Register Operation is in progress
|
|
signal register_op, register_op_next : std_logic := '0';
|
|
-- Signifies if a Instance Lookup Operation is in progress
|
|
signal lookup_op, lookup_op_next : std_logic := '0';
|
|
-- Signifies if a WAIT_FOR_ACKNOWLEDGEMENT Operation is in progress
|
|
signal ack_wait, ack_wait_next : std_logic := '0';
|
|
-- Timout time for DDS Operation
|
|
signal timeout_time, timeout_time_next : TIME_TYPE := TIME_INVALID;
|
|
-- Signal used to differentiate between ACK and NACK Operations
|
|
signal is_ack, is_ack_next : std_logic := '0';
|
|
-- Signal used to differentiate between RTPS and DDS Operations
|
|
signal is_rtps, is_rtps_next : std_logic := '0';
|
|
-- Signifies if new Samples are available for RTPS Writer
|
|
signal data_available_sig, data_available_sig_next : std_logic := '0';
|
|
-- Denotes if Orphan Samples (of an removed stale instance) need to be removed
|
|
signal orphan_samples, orphan_samples_next : std_logic := '0';
|
|
-- Test signal used for testbench synchronisation
|
|
signal idle_sig : std_logic := '0';
|
|
|
|
|
|
-- *COMMUNICATION STATUS*
|
|
signal status_sig, status_sig_next : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0) := (others => '0');
|
|
-- LIVELINESS LOST STATUS
|
|
-- Time of next Liveliness Deadline
|
|
signal lease_deadline, lease_deadline_next : TIME_TYPE := TIME_INVALID;
|
|
signal liveliness_lost_cnt, liveliness_lost_cnt_next : unsigned(LIVELINESS_LOST_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0');
|
|
signal liveliness_lost_cnt_change, liveliness_lost_cnt_change_next : unsigned(LIVELINESS_LOST_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0');
|
|
-- SAMPLE REJECT STATUS
|
|
signal sample_rej_cnt, sample_rej_cnt_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0');
|
|
signal sample_rej_cnt_change, sample_rej_cnt_change_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0');
|
|
signal sample_rej_last_reason, sample_rej_last_reason_next : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0) := (others =>'0');
|
|
signal sample_rej_last_inst, sample_rej_last_inst_next : INSTANCE_HANDLE_TYPE := (others => (others => '0'));
|
|
-- OFFERED DEADLINE MISSED STATUS
|
|
-- Time of next Deadline Miss Check
|
|
signal deadline_time, deadline_time_next : TIME_TYPE := TIME_ZERO;
|
|
signal deadline_miss_cnt, deadline_miss_cnt_next : unsigned(REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0');
|
|
signal deadline_miss_cnt_change, deadline_miss_cnt_change_next : unsigned(REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH-1 downto 0) := (others => '0');
|
|
signal deadline_miss_last_inst, deadline_miss_last_inst_next : INSTANCE_HANDLE_TYPE := (others => (others => '0'));
|
|
|
|
-- *CACHE CHANGE*
|
|
signal cc_instance_handle_sig, cc_instance_handle_sig_next : INSTANCE_HANDLE_TYPE := HANDLE_NIL;
|
|
signal cc_kind_sig, cc_kind_sig_next : CACHE_CHANGE_KIND_TYPE := ALIVE;
|
|
signal cc_source_timestamp_sig, cc_source_timestamp_sig_next : TIME_TYPE := TIME_INVALID;
|
|
signal cc_seq_nr_sig, cc_seq_nr_sig_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN;
|
|
|
|
-- *INSTANCE MEMORY PROCESS*
|
|
-- Instance Memory FSM state
|
|
signal inst_stage, inst_stage_next : INST_STAGE_TYPE := IDLE;
|
|
-- Pointer to current relevant Instance Memory Frame Address
|
|
signal inst_addr_base, inst_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Pointer to next Instance Memory Frame Address
|
|
signal inst_next_addr_base, inst_next_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Pointer to previous Instacne Memory Address
|
|
signal inst_prev_addr_base, inst_prev_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Head of Empty Instance List
|
|
signal inst_empty_head, inst_empty_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Head of Occupied Instance List
|
|
signal inst_occupied_head, inst_occupied_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
|
|
-- Latch for Instance Data from main process
|
|
signal inst_latch_data, inst_latch_data_next : INST_LATCH_DATA_TYPE := ZERO_INST_LATCH_DATA;
|
|
-- NOTE: The next signal is driven by the inst_ctrl_prc. In case WITH_KEY is FALSE, no inst_ctrl_prc is generated and the inst_data is
|
|
-- set by the main process directly by drivng the next2 signal. The sync_prc is responsible for latching the corrct next signal.
|
|
-- Latch for Instance Data from memory
|
|
signal inst_data, inst_data_next, inst_data_next2 : INSTANCE_DATA_TYPE := ZERO_INSTANCE_DATA;
|
|
-- General Purpose Counter
|
|
signal inst_cnt, inst_cnt_next : natural range 0 to 13 := 0;
|
|
-- General Purpose Long Latch
|
|
signal inst_long_latch, inst_long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0');
|
|
-- Instance Memory Flag Array denoting which inst_data Fields are up-to-date with the respective fields of the Instance (Pointed by inst_addr_base)
|
|
signal current_imf, current_imf_next : std_logic_vector(0 to IMF_FLAG_WIDTH-1) := (others => '0');
|
|
|
|
--*****ALIAS DECLARATION*****
|
|
alias prev_sample : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1;
|
|
alias prev_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0) is sample_addr_latch_1_next;
|
|
alias 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;
|
|
|
|
begin
|
|
|
|
--*****COMPONENT INSTANTIATION*****
|
|
|
|
sample_mem_ctrl_inst : entity work.mem_ctrl(arch)
|
|
generic map (
|
|
ADDR_WIDTH => SAMPLE_MEMORY_ADDR_WIDTH,
|
|
DATA_WIDTH => WORD_WIDTH,
|
|
MEMORY_DEPTH => SAMPLE_MEMORY_SIZE,
|
|
MAX_BURST_LENGTH => SAMPLE_FRAME_SIZE
|
|
)
|
|
port map (
|
|
clk => clk,
|
|
reset => reset or sample_abort_read,
|
|
addr => std_logic_vector(sample_addr),
|
|
read => sample_read,
|
|
ready_in => sample_ready_in,
|
|
valid_in => sample_valid_in,
|
|
data_in => sample_write_data,
|
|
ready_out => sample_ready_out,
|
|
valid_out => sample_valid_out,
|
|
data_out => sample_read_data
|
|
);
|
|
|
|
payload_mem_ctrl_inst : entity work.mem_ctrl(arch)
|
|
generic map (
|
|
ADDR_WIDTH => PAYLOAD_MEMORY_ADDR_WIDTH,
|
|
DATA_WIDTH => WORD_WIDTH,
|
|
MEMORY_DEPTH => PAYLOAD_MEMORY_SIZE,
|
|
MAX_BURST_LENGTH => PAYLOAD_FRAME_SIZE
|
|
)
|
|
port map (
|
|
clk => clk,
|
|
reset => reset or payload_abort_read,
|
|
addr => std_logic_vector(payload_addr),
|
|
read => payload_read,
|
|
ready_in => payload_ready_in,
|
|
valid_in => payload_valid_in,
|
|
data_in => payload_write_data,
|
|
ready_out => payload_ready_out,
|
|
valid_out => payload_valid_out,
|
|
data_out => payload_read_data
|
|
);
|
|
|
|
gen_instance_mem_ctrl_inst : if WITH_KEY generate
|
|
instance_mem_ctrl_inst : entity work.mem_ctrl(arch)
|
|
generic map (
|
|
ADDR_WIDTH => INSTANCE_MEMORY_ADDR_WIDTH,
|
|
DATA_WIDTH => WORD_WIDTH,
|
|
MEMORY_DEPTH => INSTANCE_MEMORY_SIZE,
|
|
MAX_BURST_LENGTH => INSTANCE_FRAME_SIZE
|
|
)
|
|
port map (
|
|
clk => clk,
|
|
reset => reset or inst_abort_read,
|
|
addr => std_logic_vector(inst_addr),
|
|
read => inst_read,
|
|
ready_in => inst_ready_in,
|
|
valid_in => inst_valid_in,
|
|
data_in => inst_write_data,
|
|
ready_out => inst_ready_out,
|
|
valid_out => inst_valid_out,
|
|
data_out => inst_read_data
|
|
);
|
|
|
|
end generate;
|
|
|
|
status <= status_sig;
|
|
data_available <= data_available_sig;
|
|
cc_instance_handle <= cc_instance_handle_sig;
|
|
cc_kind <= cc_kind_sig;
|
|
cc_source_timestamp <= cc_source_timestamp_sig;
|
|
cc_seq_nr <= cc_seq_nr_sig;
|
|
|
|
-- *Main State Machine*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle State. Initiates Deadline Miss Checks, Lifespan Expiry Checks, RTPS Operation handling, and DDS Operation handling, in that priority order.
|
|
-- UNKNOWN_OPERATION_DDS Dummy State for not supported/unknown DDS Operations
|
|
-- UNKNOWN_OPERATION_RTPS Dummy State for not supported/unknown RTPS Operations
|
|
-- UNKNOWN_SEQ_NR Dummy State for RTPS Operation with unknown Sequence Number
|
|
-- ASSERT_LIVELINESS Propagate Liveliness Assertion to RTPS
|
|
-- ADD_SAMPLE_INFO Latch and store Cache Change (pre-payload)
|
|
-- ADD_PAYLOAD Push payload to memory and key hash generator (as needed)
|
|
-- NEXT_PAYLOAD_SLOT Get pointer to next empty payload slot
|
|
-- ALIGN_PAYLOAD Store the offset of the actual payload in the last address of the last payload slot.
|
|
-- GET_KEY_HASH Fetch the calculated key hash from the Key Hash Generator
|
|
-- INITIATE_INSTANCE_SEARCH Initiate Instance Search Memory Operation. This state is used to start the Search operation as soon as the required data is available
|
|
-- REGISTER_OPERATION Insert new Instance into Memory, or Re-register an existing Unregistered Instance
|
|
-- LOOKUP_OPERATION Check Instance lookup results and return special value in case Instance was not found.
|
|
-- PUSH_KEY_HASH Push stored Instance Handle/Key hash to DDS output
|
|
-- FILTER_STAGE This state decides if the Cache Change is accepted, or rejected. It also decides what sample (if any) has to be removed.
|
|
-- UPDATE_INSTANCE Update the Data of the Instance of the received saample (Cache Change)
|
|
-- FINALIZE_PAYLOAD Finalize the payload addition (Update pointers).
|
|
-- FINALIZE_SAMPLE Update inserted sample and list pointers. (Second Step of Sample Addition Finalization)
|
|
-- GET_OLDEST_SAMPLE_INSTANCE Fetch the Instance Data of the oldest sample
|
|
-- FIND_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/Unacknowledge specied Sample
|
|
-- GET_SAMPLE Push Sample Data to RTPS output
|
|
-- GET_PAYLOAD Push linked Payload to output, or to the serialized key generator
|
|
-- GET_SERIALIZED_KEY Push serialized key to output
|
|
-- CHECK_LIFESPAN Check and remove samples with expired Lifespans
|
|
-- GET_LIVELINESS_LOST_STATUS Return Liveliness Loss Status
|
|
-- GET_OFFERED_DEADLINE_MISSED_STATUS Return Offered Deadline Missed Status
|
|
-- CHECK_DEADLINE Check and Mark Instances with missed Deadlines
|
|
-- RESET_SAMPLE_MEMORY Reset Sample Memory to Empty State
|
|
-- RESET_PAYLOAD_MEMORY Reset Payload Memory to Empty State
|
|
parse_a_prc : process (all)
|
|
variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0'));
|
|
variable tmp_bool : boolean := FALSE;
|
|
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_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;
|
|
timeout_time_next <= timeout_time;
|
|
lease_deadline_next <= lease_deadline;
|
|
seq_nr_next <= seq_nr;
|
|
return_stage_next <= return_stage;
|
|
cc_instance_handle_sig_next <= cc_instance_handle_sig;
|
|
cc_kind_sig_next <= cc_kind_sig;
|
|
cc_source_timestamp_sig_next <= cc_source_timestamp_sig;
|
|
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;
|
|
inst_data_next2 <= inst_data;
|
|
return_code_latch_next <= return_code_latch;
|
|
-- DEFAULT Unregistered
|
|
inst_opcode <= NOP;
|
|
ret_rtps <= ERROR;
|
|
return_code_dds <= RETCODE_UNSUPPORTED;
|
|
opcode_kh <= NOP;
|
|
ack_dds <= '0';
|
|
done_dds <= '0';
|
|
ack_rtps <= '0';
|
|
done_rtps <= '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 <= '0';
|
|
liveliness_assertion <= '0';
|
|
valid_out_rtps <= '0';
|
|
last_word_out_rtps <= '0';
|
|
valid_out_dds <= '0';
|
|
last_word_out_dds <= '0';
|
|
start_kh <= '0';
|
|
ready_in_kh <= '0';
|
|
valid_out_kh <= '0';
|
|
last_word_out_kh <= '0';
|
|
abort_kh <= '0';
|
|
idle_sig <= '0';
|
|
data_out_kh <= (others => '0');
|
|
inst_addr_update <= (others => '0');
|
|
sample_addr <= (others => '0');
|
|
sample_write_data <= (others => '0');
|
|
payload_addr <= (others => '0');
|
|
payload_write_data <= (others => '0');
|
|
data_out_rtps <= (others => '0');
|
|
data_out_dds <= (others => '0');
|
|
|
|
|
|
case (stage) is
|
|
when IDLE =>
|
|
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 /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= REMOVE_ORPHAN_SAMPLES;
|
|
cnt_next <= 0;
|
|
-- DEADLINE QoS
|
|
elsif (DEADLINE_QOS /= DURATION_INFINITE and deadline_time <= time) then
|
|
-- Reset Timeout
|
|
deadline_time_next <= deadline_time + DEADLINE_QOS;
|
|
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
stage_next <= CHECK_DEADLINE;
|
|
cnt_next <= 0;
|
|
else
|
|
if (inst_data.status_info(ISI_LIVELINESS_FLAG) = '1') then
|
|
-- Reset Liveliness Flag
|
|
inst_data_next2.status_info(ISI_LIVELINESS_FLAG) <= '0';
|
|
else
|
|
-- Update Requested Deadline Missed Status
|
|
status_sig_next <= status_sig or OFFERED_DEADLINE_MISSED_STATUS;
|
|
deadline_miss_cnt_next <= deadline_miss_cnt + 1;
|
|
deadline_miss_cnt_change_next <= deadline_miss_cnt_change + 1;
|
|
end if;
|
|
end if;
|
|
-- Liveliness Deadline
|
|
elsif (LEASE_DURATION /= DURATION_INFINITE and lease_deadline <= time) then
|
|
liveliness_lost_cnt_next <= liveliness_lost_cnt + 1;
|
|
liveliness_lost_cnt_change_next <= liveliness_lost_cnt_change + 1;
|
|
status_sig_next <= status_sig or LIVELINESS_LOST_STATUS;
|
|
|
|
-- Reset
|
|
lease_deadline_next <= time + LEASE_DURATION;
|
|
-- WAIT_FOR_ACKNOWLEDGEMENT Done
|
|
elsif (ack_wait = '1' and global_ack_cnt = global_sample_cnt) then
|
|
-- Reset
|
|
ack_wait_next <= '0';
|
|
|
|
-- DONE
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
-- WAIT_FOR_ACKNOWLEDGEMENT Timeout
|
|
elsif (ack_wait = '1' and timeout_time <= time) then
|
|
-- Reset
|
|
ack_wait_next <= '0';
|
|
|
|
-- DONE
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_TIMEOUT;
|
|
-- LIFESPAN QoS
|
|
elsif (lifespan_time <= time) then
|
|
-- Reset Timeout
|
|
lifespan_time_next <= TIME_INFINITE;
|
|
|
|
-- Samples Available
|
|
if (oldest_sample /= SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
is_lifespan_check_next <= '1';
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= CHECK_LIFESPAN;
|
|
cnt_next <= 0;
|
|
end if;
|
|
-- RTPS Operation
|
|
elsif (start_rtps = '1') then
|
|
is_rtps_next <= '1';
|
|
-- Latch Input Signal
|
|
seq_nr_next <= seq_nr_rtps;
|
|
-- Reset
|
|
is_ack_next <= '0';
|
|
|
|
case (opcode_rtps) is
|
|
when GET_MIN_SN =>
|
|
ack_rtps <= '1';
|
|
if (oldest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
-- NOTE: If the HC is empty we return the Special value SEQUENCENUMBER_UNKNOWN
|
|
stage_next <= GET_SEQ_NR;
|
|
cnt_next <= 4;
|
|
cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN;
|
|
else
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= GET_SEQ_NR;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when GET_MAX_SN =>
|
|
ack_rtps <= '1';
|
|
|
|
-- Reset Data Availability
|
|
data_available_sig_next <= '0';
|
|
|
|
if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
-- NOTE: If the HC is empty we return the Special value SEQUENCENUMBER_UNKNOWN
|
|
stage_next <= GET_SEQ_NR;
|
|
cnt_next <= 4;
|
|
cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN;
|
|
else
|
|
cur_sample_next <= newest_sample;
|
|
stage_next <= GET_SEQ_NR;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when GET_CACHE_CHANGE =>
|
|
ack_rtps <= '1';
|
|
|
|
-- No Samples Available
|
|
if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
stage_next <= UNKNOWN_SEQ_NR;
|
|
cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN;
|
|
else
|
|
cc_seq_nr_sig_next <= seq_nr_rtps;
|
|
cur_sample_next <= newest_sample;
|
|
stage_next <= FIND_SEQ_NR;
|
|
cnt_next <= 0;
|
|
return_stage_next <= GET_SAMPLE;
|
|
end if;
|
|
when ACK_CACHE_CHANGE =>
|
|
ack_rtps <= '1';
|
|
is_ack_next <= '1';
|
|
|
|
-- No Samples Available
|
|
if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
stage_next <= UNKNOWN_SEQ_NR;
|
|
cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN;
|
|
else
|
|
cur_sample_next <= newest_sample;
|
|
stage_next <= FIND_SEQ_NR;
|
|
cnt_next <= 0;
|
|
return_stage_next <= ACKNACK_SAMPLE;
|
|
end if;
|
|
when NACK_CACHE_CHANGE =>
|
|
ack_rtps <= '1';
|
|
|
|
-- No Samples Available
|
|
if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
stage_next <= UNKNOWN_SEQ_NR;
|
|
cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN;
|
|
else
|
|
cur_sample_next <= newest_sample;
|
|
stage_next <= FIND_SEQ_NR;
|
|
cnt_next <= 0;
|
|
return_stage_next <= ACKNACK_SAMPLE;
|
|
end if;
|
|
when REMOVE_CACHE_CHANGE =>
|
|
ack_rtps <= '1';
|
|
|
|
-- No Samples Available
|
|
if (newest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
stage_next <= UNKNOWN_SEQ_NR;
|
|
cc_seq_nr_sig_next <= SEQUENCENUMBER_UNKNOWN;
|
|
else
|
|
cur_sample_next <= newest_sample;
|
|
stage_next <= FIND_SEQ_NR;
|
|
cnt_next <= 0;
|
|
return_stage_next <= REMOVE_SAMPLE;
|
|
end if;
|
|
when others =>
|
|
ack_rtps <= '1';
|
|
|
|
stage_next <= UNKNOWN_OPERATION_RTPS;
|
|
end case;
|
|
-- DDS Operation (Stall DDS Operation if a wait Operation is in progress)
|
|
elsif (ack_wait = '0' and start_dds = '1') then
|
|
-- Reset
|
|
register_op_next <= '0';
|
|
instance_handle_next <= HANDLE_NIL;
|
|
source_ts_next <= TIME_INVALID;
|
|
sample_status_info_next <= (others => '0');
|
|
key_hash_next <= HANDLE_NIL;
|
|
new_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
return_code_latch_next <= RETCODE_UNSUPPORTED;
|
|
|
|
case (opcode_dds) is
|
|
when REGISTER_INSTANCE =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
start_kh <= '1';
|
|
opcode_kh <= PUSH_DATA;
|
|
|
|
if (ack_kh = '1') then
|
|
ack_dds <= '1';
|
|
register_op_next <= '1';
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 1;
|
|
end if;
|
|
else
|
|
ack_dds <= '1';
|
|
key_hash_next <= HANDLE_NIL;
|
|
stage_next <= SKIP;
|
|
return_stage_next <= PUSH_KEY_HASH;
|
|
end if;
|
|
when WRITE =>
|
|
ack_dds <= '1';
|
|
|
|
-- Reset Liveliness
|
|
lease_deadline_next <= time + LEASE_DURATION;
|
|
|
|
-- Latch Input Signals
|
|
instance_handle_next <= instance_handle_dds;
|
|
source_ts_next <= source_ts_dds;
|
|
|
|
-- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset.
|
|
sample_status_info_next <= (SSI_DATA_FLAG => '1', SSI_ALIGNED_FLAG => '1', others => '0');
|
|
cur_sample_next <= empty_sample_list_head;
|
|
|
|
-- 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 = PAYLOAD_MEMORY_MAX_ADDRESS) then
|
|
if (global_ack_cnt = 0 and 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 /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
-- Do not ACK Operation
|
|
ack_dds <= '0';
|
|
|
|
|
|
if (global_ack_cnt /= 0) then
|
|
-- Remove Oldest ACKed Sample
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= FIND_SAMPLE;
|
|
cnt_next <= 0;
|
|
elsif (WITH_KEY) then
|
|
stage_next <= GET_OLDEST_SAMPLE_INSTANCE;
|
|
cnt_next <= 0;
|
|
else
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- Instance Handle provided
|
|
if (WITH_KEY and instance_handle_dds /= HANDLE_NIL) then
|
|
key_hash_next <= instance_handle_dds;
|
|
stage_next <= INITIATE_INSTANCE_SEARCH;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= ADD_SAMPLE_INFO;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when DISPOSE =>
|
|
ack_dds <= '1';
|
|
|
|
-- Reset Liveliness
|
|
lease_deadline_next <= time + LEASE_DURATION;
|
|
|
|
-- Latch Input Signals
|
|
instance_handle_next <= instance_handle_dds;
|
|
source_ts_next <= source_ts_dds;
|
|
|
|
-- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset.
|
|
sample_status_info_next <= (SSI_DATA_FLAG => '1', SSI_ALIGNED_FLAG => '1', SSI_DISPOSED_FLAG => '1', others => '0');
|
|
cur_sample_next <= empty_sample_list_head;
|
|
|
|
-- NOTE: We always expect a Serialized Key as Input of this Opration, so we also check the Payload memory
|
|
-- Payload Memory Full
|
|
if (empty_payload_list_head = PAYLOAD_MEMORY_MAX_ADDRESS) then
|
|
if (global_ack_cnt = 0 and 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 /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
-- Do not ACK Operation
|
|
ack_dds <= '0';
|
|
|
|
if (global_ack_cnt /= 0) then
|
|
-- Remove Oldest ACKed Sample
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= FIND_SAMPLE;
|
|
cnt_next <= 0;
|
|
elsif (WITH_KEY) then
|
|
stage_next <= GET_OLDEST_SAMPLE_INSTANCE;
|
|
cnt_next <= 0;
|
|
else
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- Instance Handle provided
|
|
if (WITH_KEY and instance_handle_dds /= HANDLE_NIL) then
|
|
key_hash_next <= instance_handle_dds;
|
|
stage_next <= INITIATE_INSTANCE_SEARCH;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= ADD_SAMPLE_INFO;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when UNREGISTER_INSTANCE =>
|
|
ack_dds <= '1';
|
|
|
|
-- Reset Liveliness
|
|
lease_deadline_next <= time + LEASE_DURATION;
|
|
|
|
-- Latch Input Signals
|
|
instance_handle_next <= instance_handle_dds;
|
|
source_ts_next <= source_ts_dds;
|
|
|
|
-- NOTE: The ALIGNED_FLAG is set by default. if actual Payload is not aligned, need to reset.
|
|
sample_status_info_next <= (SSI_DATA_FLAG => '1', SSI_ALIGNED_FLAG => '1', SSI_UNREGISTERED_FLAG => '1', others => '0');
|
|
cur_sample_next <= empty_sample_list_head;
|
|
|
|
-- NOTE: We always expect a Serialized Key as Input of this Opration, so we also check the Payload memory
|
|
-- Payload Memory Full
|
|
if (empty_payload_list_head = PAYLOAD_MEMORY_MAX_ADDRESS) then
|
|
if (global_ack_cnt = 0 and 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 /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
-- Do not ACK Operation
|
|
ack_dds <= '0';
|
|
|
|
if (global_ack_cnt /= 0) then
|
|
-- Remove Oldest ACKed Sample
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= FIND_SAMPLE;
|
|
cnt_next <= 0;
|
|
elsif (WITH_KEY) then
|
|
stage_next <= GET_OLDEST_SAMPLE_INSTANCE;
|
|
cnt_next <= 0;
|
|
else
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- Instance Handle provided
|
|
if (WITH_KEY and instance_handle_dds /= HANDLE_NIL) then
|
|
key_hash_next <= instance_handle_dds;
|
|
stage_next <= INITIATE_INSTANCE_SEARCH;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= ADD_SAMPLE_INFO;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when LOOKUP_INSTANCE =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
start_kh <= '1';
|
|
opcode_kh <= PUSH_DATA;
|
|
|
|
if (ack_kh = '1') then
|
|
ack_dds <= '1';
|
|
lookup_op_next <= '1';
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 1;
|
|
end if;
|
|
else
|
|
ack_dds <= '1';
|
|
key_hash_next <= HANDLE_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 <= '1';
|
|
ack_wait_next <= '1';
|
|
timeout_time_next <= time + max_wait_dds;
|
|
when GET_OFFERED_DEADLINE_MISSED_STATUS =>
|
|
ack_dds <= '1';
|
|
stage_next <= GET_OFFERED_DEADLINE_MISSED_STATUS;
|
|
cnt_next <= 0;
|
|
when ASSERT_LIVELINESS =>
|
|
-- Reset Liveliness
|
|
lease_deadline_next <= time + LEASE_DURATION;
|
|
|
|
ack_dds <= '1';
|
|
stage_next <= ASSERT_LIVELINESS;
|
|
when GET_LIVELINESS_LOST_STATUS =>
|
|
ack_dds <= '1';
|
|
stage_next <= GET_LIVELINESS_LOST_STATUS;
|
|
cnt_next <= 0;
|
|
when others =>
|
|
ack_dds <= '1';
|
|
stage_next <= UNKNOWN_OPERATION_DDS;
|
|
end case;
|
|
end if;
|
|
when UNKNOWN_OPERATION_DDS =>
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_ILLEGAL_OPERATION;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
when UNKNOWN_OPERATION_RTPS =>
|
|
done_rtps <= '1';
|
|
ret_rtps <= ERROR;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
when UNKNOWN_SEQ_NR =>
|
|
done_rtps <= '1';
|
|
ret_rtps <= INVALID;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
|
|
when ASSERT_LIVELINESS =>
|
|
-- Propagate Liveliness Assertion
|
|
liveliness_assertion <= '1';
|
|
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
when ADD_SAMPLE_INFO =>
|
|
-- Precondition: cur_sample set
|
|
|
|
case (cnt) is
|
|
-- Status Info
|
|
when 0 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET;
|
|
sample_write_data <= sample_status_info;
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Sequence Number 1/2
|
|
when 1 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET;
|
|
sample_write_data <= std_logic_vector(global_seq_nr(0));
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Sequence Number 2/2
|
|
when 2 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET + 1;
|
|
sample_write_data <= std_logic_vector(global_seq_nr(1));
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Timestamp 1/2
|
|
when 3 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET;
|
|
sample_write_data <= std_logic_vector(source_ts(0)) when source_ts /= TIME_INVALID else std_logic_vector(time(0));
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Timestamp 2/2
|
|
when 4 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET + 1;
|
|
sample_write_data <= std_logic_vector(source_ts(1)) when source_ts /= TIME_INVALID else std_logic_vector(time(1));
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
-- Synthesis Guard
|
|
if (LIFESPAN_QOS /= DURATION_INFINITE) then
|
|
cnt_next <= cnt + 1;
|
|
lifespan_next <= time + LIFESPAN_QOS;
|
|
else
|
|
cnt_next <= cnt + 3; -- Skip
|
|
end if;
|
|
end if;
|
|
-- Lifespan Deadline 1/2
|
|
when 5 =>
|
|
-- Synthesis Guard
|
|
if (LIFESPAN_QOS /= DURATION_INFINITE) then
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET;
|
|
sample_write_data <= std_logic_vector(lifespan(0));
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- Lifespan Deadline 2/2
|
|
when 6 =>
|
|
-- Synthesis Guard
|
|
if (LIFESPAN_QOS /= DURATION_INFINITE) then
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET + 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;
|
|
end if;
|
|
-- Payload Address
|
|
when 7 =>
|
|
assert (empty_payload_list_head /= 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, WORD_WIDTH));
|
|
cur_payload_next <= empty_payload_list_head;
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
-- Key Hash needs to be calculated
|
|
if (WITH_KEY and instance_handle = HANDLE_NIL) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 0;
|
|
cnt2_next <= 1;
|
|
end if;
|
|
end if;
|
|
-- Initiate KH Operation
|
|
when 8 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
start_kh <= '1';
|
|
-- Payload is Serialized Key
|
|
if (sample_status_info(SSI_DISPOSED_FLAG) = '1' or sample_status_info(SSI_UNREGISTERED_FLAG) = '1' or sample_status_info(SSI_FILTERED_FLAG) = '1') then
|
|
opcode_kh <= PUSH_SERIALIZED_KEY;
|
|
else
|
|
opcode_kh <= PUSH_DATA;
|
|
end if;
|
|
|
|
if (ack_kh = '1') then
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 0;
|
|
cnt2_next <= 1;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when ADD_PAYLOAD =>
|
|
-- Precondition: cur_payload set
|
|
|
|
case (cnt) is
|
|
-- Push to memory
|
|
when 0 =>
|
|
-- Input Guard
|
|
if (valid_in_dds = '1') then
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + cnt2;
|
|
payload_write_data <= data_in_dds;
|
|
-- Memory Control Flow Guard
|
|
if (payload_ready_in = '1') then
|
|
-- Key Hash needs to be calculated
|
|
if (WITH_KEY and instance_handle = HANDLE_NIL) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
ready_in_dds <= '1';
|
|
-- End of Payload
|
|
if (last_word_in_dds = '1') then
|
|
-- End of Payload Slot
|
|
if (cnt2 = PAYLOAD_FRAME_SIZE-1) then
|
|
stage_next <= FILTER_STAGE;
|
|
else
|
|
stage_next <= ALIGN_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- End of Payload Slot
|
|
if (cnt2 = PAYLOAD_FRAME_SIZE-1) then
|
|
stage_next <= NEXT_PAYLOAD_SLOT;
|
|
cnt_next <= 0;
|
|
else
|
|
-- Next Word
|
|
cnt2_next <= cnt2 + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- Push to KH
|
|
when 1 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Input Guard
|
|
if (valid_in_dds = '1') then
|
|
|
|
valid_out_kh <= '1';
|
|
data_out_kh <= data_in_dds;
|
|
|
|
-- Output Guard
|
|
if (ready_out_kh = '1') then
|
|
ready_in_dds <= '1';
|
|
-- Operation does not have Payload to store
|
|
if (sample_status_info(SSI_DATA_FLAG) = '0') then
|
|
-- End of Payload
|
|
if (last_word_in_dds = '1') then
|
|
last_word_out_kh <= '1';
|
|
-- Fetch the Key Hash
|
|
stage_next <= GET_KEY_HASH;
|
|
cnt_next <= 0;
|
|
cnt2_next <= 0;
|
|
else
|
|
-- Next Word
|
|
cnt_next <= 1; -- Same Sub-state
|
|
end if;
|
|
else
|
|
-- End of Payload
|
|
if (last_word_in_dds = '1') then
|
|
last_word_out_kh <= '1';
|
|
-- End of Payload Slot
|
|
if (cnt2 = PAYLOAD_FRAME_SIZE-1) then
|
|
-- Fetch the Key Hash
|
|
stage_next <= GET_KEY_HASH;
|
|
cnt_next <= 0;
|
|
cnt2_next <= 0;
|
|
else
|
|
stage_next <= ALIGN_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- End of Payload Slot
|
|
if (cnt2 = PAYLOAD_FRAME_SIZE-1) then
|
|
stage_next <= NEXT_PAYLOAD_SLOT;
|
|
cnt_next <= 0;
|
|
else
|
|
-- Next Word
|
|
cnt_next <= 0;
|
|
cnt2_next <= cnt2 + 1;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when NEXT_PAYLOAD_SLOT =>
|
|
-- Precondition: cur_payload set
|
|
|
|
case (cnt) is
|
|
-- GET Next Pointer
|
|
when 0 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET;
|
|
payload_read <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (payload_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Next Pointer
|
|
when 1 =>
|
|
payload_ready_out <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (payload_valid_out = '1') then
|
|
-- No Empty Payload Slots available
|
|
if (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 <= '1';
|
|
else
|
|
-- Latch next Payload Slot and Continue
|
|
cur_payload_next <= resize(unsigned(payload_read_data), PAYLOAD_MEMORY_ADDR_WIDTH);
|
|
stage_next <= ADD_PAYLOAD;
|
|
cnt_next <= 0;
|
|
cnt2_next <= 1;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when ALIGN_PAYLOAD =>
|
|
case (cnt) is
|
|
-- Mark Payload as unaligned
|
|
when 0 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET;
|
|
sample_write_data <= sample_status_info;
|
|
sample_write_data(SSI_ALIGNED_FLAG) <= '0';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Store Payload End Offset
|
|
when 1 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PAYLOAD_FRAME_SIZE-1;
|
|
payload_write_data <= std_logic_vector(to_unsigned(cnt2, WORD_WIDTH));
|
|
|
|
-- Memory Control Flow Guard
|
|
if (payload_ready_in = '1') then
|
|
if (WITH_KEY and instance_handle = HANDLE_NIL) then
|
|
stage_next <= GET_KEY_HASH;
|
|
cnt_next <= 0;
|
|
cnt2_next <= 0;
|
|
else
|
|
stage_next <= FILTER_STAGE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_KEY_HASH =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
case (cnt) is
|
|
-- Initiate READ Operation
|
|
when 0 =>
|
|
start_kh <= '1';
|
|
opcode_kh <= READ_KEY_HASH;
|
|
|
|
if (ack_kh = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Key Hash
|
|
when 1 =>
|
|
ready_in_kh <= '1';
|
|
|
|
if (valid_in_kh = '1') then
|
|
cnt2_next <= cnt2 + 1;
|
|
|
|
-- Latch Key Hash
|
|
key_hash_next(cnt2) <= data_in_kh;
|
|
|
|
-- Exit Condition
|
|
if (last_word_in_kh = '1') then
|
|
-- DONE
|
|
stage_next <= INITIATE_INSTANCE_SEARCH;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when INITIATE_INSTANCE_SEARCH =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= SEARCH_INSTANCE_HASH;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
|
|
-- Register Operation in Progress
|
|
if (WITH_KEY and register_op = '1') then
|
|
stage_next <= REGISTER_OPERATION;
|
|
-- Lookup Operation in Progress
|
|
elsif (WITH_KEY and lookup_op = '1') then
|
|
stage_next <= LOOKUP_OPERATION;
|
|
-- Cache Change not yet Stored
|
|
elsif (instance_handle /= HANDLE_NIL) then
|
|
stage_next <= ADD_SAMPLE_INFO;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= FILTER_STAGE;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when REGISTER_OPERATION =>
|
|
-- Precondition: inst_data set (IMF_STATUS_FLAG, IMF_SAMPLE_CNT_FLAG, IMF_ACK_CNT_FLAG)
|
|
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Wait for Instance Search to finish
|
|
if (inst_op_done = '1') then
|
|
assert check_mask(current_imf, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG) severity FAILURE;
|
|
|
|
-- Instance already in Memory
|
|
if (inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- Accept Registration
|
|
stage_next <= PUSH_KEY_HASH;
|
|
cnt_next <= 0;
|
|
|
|
-- Instance is Unregistered
|
|
if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1') then
|
|
-- Re-register Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG;
|
|
status_info_update <= inst_data.status_info;
|
|
status_info_update(ISI_UNREGISTERED_FLAG) <= '0';
|
|
|
|
-- Update Stale Instance Count
|
|
if (inst_data.sample_cnt = inst_data.ack_cnt) then
|
|
stale_inst_cnt_next <= stale_inst_cnt - 1;
|
|
end if;
|
|
end if;
|
|
else
|
|
-- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full)
|
|
if (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- Stale Instances are available
|
|
if (stale_inst_cnt /= 0) then
|
|
-- Remove Stale and insert new Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
stage_next <= REMOVE_STALE_INSTANCE;
|
|
cnt_next <= 0;
|
|
else
|
|
-- Reject Registration
|
|
key_hash_next <= HANDLE_NIL;
|
|
stage_next <= PUSH_KEY_HASH;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- Accept Registration
|
|
stage_next <= PUSH_KEY_HASH;
|
|
cnt_next <= 0;
|
|
|
|
-- Insert New Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= INSERT_INSTANCE;
|
|
status_info_update <= (others => '0');
|
|
sample_cnt <= (others => '0');
|
|
ack_cnt <= (others => '0');
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when LOOKUP_OPERATION =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Wait for Instance Search to finish
|
|
if (inst_op_done = '1') then
|
|
-- Instance Found
|
|
if (inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
stage_next <= PUSH_KEY_HASH;
|
|
cnt_next <= 0;
|
|
else
|
|
-- Return Special Value
|
|
key_hash_next <= HANDLE_NIL;
|
|
stage_next <= PUSH_KEY_HASH;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when PUSH_KEY_HASH =>
|
|
case (cnt) is
|
|
-- Key Hash 1/4
|
|
when 0 =>
|
|
valid_out_dds <= '1';
|
|
data_out_dds <= key_hash(0);
|
|
|
|
-- Output Guard
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Key Hash 2/4
|
|
when 1 =>
|
|
valid_out_dds <= '1';
|
|
data_out_dds <= key_hash(1);
|
|
|
|
-- Output Guard
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Key Hash 3/4
|
|
when 2 =>
|
|
valid_out_dds <= '1';
|
|
data_out_dds <= key_hash(2);
|
|
|
|
-- Output Guard
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Key Hash 4/4
|
|
when 3 =>
|
|
valid_out_dds <= '1';
|
|
data_out_dds <= key_hash(3);
|
|
last_word_out_dds <= '1';
|
|
|
|
-- Output Guard
|
|
if (ready_out_dds = '1') then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
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 (not WITH_KEY or inst_op_done = '1') then
|
|
assert check_mask(current_imf, IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG) severity FAILURE;
|
|
|
|
-- Instance Found
|
|
if (not WITH_KEY or inst_addr_base /= INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- Latch Instance Pointer
|
|
cur_inst_next <= inst_addr_base;
|
|
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES_PER_INSTANCE)
|
|
if (WITH_KEY and MAX_SAMPLES_PER_INSTANCE /= LENGTH_UNLIMITED and inst_data.sample_cnt = unsigned(MAX_SAMPLES_PER_INSTANCE)) then
|
|
-- Synthesis Guard
|
|
if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then
|
|
-- No ACKed Instance Samples exist
|
|
if (inst_data.ack_cnt = 0) then
|
|
-- Reject Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OUT_OF_RESOURCES;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest ACKed Instance Sample)
|
|
remove_oldest_inst_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
else -- HISTORY_QOS = KEEP_LAST_HISTORY_QOS
|
|
-- Accept Change (Remove Oldest (ACKed) Instance Sample)
|
|
remove_oldest_inst_sample_next <= '1';
|
|
remove_ack_sample_next <= '1' when (inst_data.ack_cnt /= 0) else '0';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES)
|
|
elsif (empty_sample_list_head = empty_sample_list_tail) then
|
|
-- Synthesis Guard
|
|
if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then
|
|
-- No ACKed Samples exist
|
|
if (global_ack_cnt = 0) then
|
|
-- Reject Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OUT_OF_RESOURCES;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest ACKed Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
else -- HISTORY_QOS = KEEP_LAST_HISTORY_QOS
|
|
-- Accept Change (Remove Oldest (ACKed) Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1' when (global_ack_cnt /= 0) else '0';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
else
|
|
-- Accept Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
stage_next <= UPDATE_INSTANCE;
|
|
end if;
|
|
else -- (WITH_KEY)
|
|
-- Latch Instance Pointer
|
|
cur_inst_next <= inst_empty_head;
|
|
|
|
-- Provided Instance Handle Invalid
|
|
if (instance_handle /= HANDLE_NIL) then
|
|
-- Invalid Operation
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_BAD_PARAMETER;
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
-- Ignore Unregister Operation on Unknown Instance
|
|
elsif (sample_status_info(SSI_UNREGISTERED_FLAG) = '1') then
|
|
-- Drop Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
-- RESOURCE_LIMITS_QOS (MAX_INSTANCES) (Instance Memory Full)
|
|
elsif (inst_empty_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- No Stale Instances available
|
|
if (stale_inst_cnt = 0) then
|
|
-- Reject Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OUT_OF_RESOURCES;
|
|
stage_next <= IDLE;
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES)
|
|
elsif (empty_sample_list_head = empty_sample_list_tail) then
|
|
-- Synthesis Guard
|
|
if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then
|
|
-- No ACKed Samples exist
|
|
if (global_ack_cnt = 0) then
|
|
-- Reject Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OUT_OF_RESOURCES;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest ACKed Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- Remove Stale and insert new Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
stage_next <= REMOVE_STALE_INSTANCE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else -- HISTORY_QOS = KEEP_LAST_HISTORY_QOS
|
|
-- Accept Change (Remove Oldest (ACKed) Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1' when (global_ack_cnt /= 0) else '0';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- Remove Stale and insert new Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
stage_next <= REMOVE_STALE_INSTANCE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- Accept Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- Remove Stale and insert new Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
stage_next <= REMOVE_STALE_INSTANCE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- RESOURCE_LIMITS_QOS (MAX_SAMPLES)
|
|
if (empty_sample_list_head = empty_sample_list_tail) then
|
|
-- Synthesis Guard
|
|
if (HISTORY_QOS = KEEP_ALL_HISTORY_QOS) then
|
|
-- No ACKed Samples exist
|
|
if (global_ack_cnt = 0) then
|
|
-- Reject Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OUT_OF_RESOURCES;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Accept Change (Remove Oldest ACKed Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- Insert New Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= INSERT_INSTANCE;
|
|
status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0');
|
|
sample_cnt <= to_unsigned(1, WORD_WIDTH);
|
|
ack_cnt <= (others => '0');
|
|
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else -- HISTORY_QOS = KEEP_LAST_HISTORY_QOS
|
|
-- Accept Change (Remove Oldest (ACKed) Sample)
|
|
remove_oldest_sample_next <= '1';
|
|
remove_ack_sample_next <= '1' when (global_ack_cnt /= 0) else '0';
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- Insert New Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= INSERT_INSTANCE;
|
|
status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0');
|
|
sample_cnt <= to_unsigned(1, WORD_WIDTH);
|
|
ack_cnt <= (others => '0');
|
|
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- Accept Change
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
|
|
-- Insert New Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= INSERT_INSTANCE;
|
|
status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0');
|
|
sample_cnt <= to_unsigned(1, WORD_WIDTH);
|
|
ack_cnt <= (others => '0');
|
|
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when UPDATE_INSTANCE =>
|
|
-- Precondition: inst_data set (IMF_STATUS_FLAG, IMF_SAMPLE_CNT_FLAG, IMF_ACK_CNT_FLAG)
|
|
|
|
-- Memory Operation Guard
|
|
if (not WITH_KEY or inst_op_done = '1') then
|
|
assert check_mask(current_imf, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG) severity FAILURE;
|
|
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG;
|
|
status_info_update <= inst_data.status_info;
|
|
status_info_update(ISI_LIVELINESS_FLAG) <= '1';
|
|
if (sample_status_info(SSI_DISPOSED_FLAG) = '0' and sample_status_info(SSI_UNREGISTERED_FLAG) = '0') then
|
|
status_info_update(ISI_DISPOSED_FLAG) <= '0';
|
|
status_info_update(ISI_UNREGISTERED_FLAG) <= '0';
|
|
elsif (sample_status_info(SSI_DISPOSED_FLAG) = '1') then
|
|
status_info_update(ISI_DISPOSED_FLAG) <= '1';
|
|
elsif (sample_status_info(SSI_UNREGISTERED_FLAG) = '1') then
|
|
status_info_update(ISI_UNREGISTERED_FLAG) <= '1';
|
|
end if;
|
|
sample_cnt <= inst_data.sample_cnt + 1;
|
|
|
|
-- Update Stale Instance Count
|
|
-- NOTE: We enter this state only when we have a new sample, so an instance cannot turn stale, but only
|
|
-- become relevant again.
|
|
if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.sample_cnt = inst_data.ack_cnt) then
|
|
stale_inst_cnt_next <= stale_inst_cnt - 1;
|
|
end if;
|
|
else
|
|
if (sample_status_info(SSI_DISPOSED_FLAG) = '0' and sample_status_info(SSI_UNREGISTERED_FLAG) = '0') then
|
|
inst_data_next2.status_info(ISI_DISPOSED_FLAG) <= '0';
|
|
inst_data_next2.status_info(ISI_UNREGISTERED_FLAG) <= '0';
|
|
elsif (sample_status_info(SSI_DISPOSED_FLAG) = '1') then
|
|
inst_data_next2.status_info(ISI_DISPOSED_FLAG) <= '1';
|
|
elsif (sample_status_info(SSI_UNREGISTERED_FLAG) = '1') then
|
|
inst_data_next2.status_info(ISI_UNREGISTERED_FLAG) <= '1';
|
|
end if;
|
|
inst_data_next2.status_info(ISI_LIVELINESS_FLAG) <= '1';
|
|
inst_data_next2.sample_cnt <= inst_data.sample_cnt + 1;
|
|
end if;
|
|
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when FINALIZE_PAYLOAD =>
|
|
-- Precondition: cur_payload set
|
|
|
|
case (cnt) is
|
|
-- GET Next Pointer
|
|
when 0 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET;
|
|
payload_read <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (payload_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Next Pointer
|
|
when 1 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET;
|
|
-- Make current Slot the Tail
|
|
payload_write_data <= 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 <= resize(unsigned(payload_read_data), PAYLOAD_MEMORY_ADDR_WIDTH);
|
|
|
|
stage_next <= FINALIZE_SAMPLE;
|
|
cur_sample_next <= empty_sample_list_head;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when FINALIZE_SAMPLE =>
|
|
-- Precondition: 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 = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
assert (oldest_sample = SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 2; -- Skip Next Step
|
|
else
|
|
cnt_next <= cnt + 3; -- Skip Next 2 Steps
|
|
end if;
|
|
else
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Next Pointer (Previous Sample)
|
|
when 1 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= newest_sample + 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
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 2; --Skip Next Step
|
|
end if;
|
|
end if;
|
|
-- SET Instance Pointer
|
|
when 2 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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;
|
|
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, 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 <= resize(unsigned(sample_read_data), SAMPLE_MEMORY_ADDR_WIDTH);
|
|
|
|
-- Fix List Pointers
|
|
newest_sample_next <= cur_sample;
|
|
if (oldest_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
oldest_sample_next <= cur_sample;
|
|
end if;
|
|
|
|
-- Increment Global Sequence Number
|
|
global_seq_nr_next <= global_seq_nr + 1;
|
|
|
|
-- Increment Global Sample Count
|
|
global_sample_cnt_next <= global_sample_cnt + 1;
|
|
|
|
-- Signal Data Available
|
|
data_available_sig_next <= '1';
|
|
|
|
-- NOTE: This is needed to prevent the new Sample to be 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 (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 /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= FIND_SAMPLE;
|
|
cnt_next <= 0;
|
|
elsif (remove_oldest_sample = '1') then
|
|
assert (oldest_sample /= SAMPLE_MEMORY_MAX_ADDRESS) severity FAILURE;
|
|
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
stage_next <= GET_OLDEST_SAMPLE_INSTANCE;
|
|
cnt_next <= 0;
|
|
else
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_OLDEST_SAMPLE_INSTANCE =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
case (cnt) is
|
|
-- GET Instance Pointer (Oldest Sample)
|
|
when 0 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= oldest_sample + SMF_INSTANCE_ADDR_OFFSET;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Instance Pointer (Oldest Sample)
|
|
when 1 =>
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
sample_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_valid_out = '1') then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
inst_addr_update <= resize(unsigned(sample_read_data), INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
cur_sample_next <= oldest_sample;
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
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; -- Skip Next Step
|
|
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
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 2; -- Skip Next Step
|
|
end if;
|
|
end if;
|
|
-- GET Instance Pointer
|
|
when 2 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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;
|
|
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;
|
|
assert(WITH_KEY) severity FAILURE;
|
|
|
|
cnt_next <= cnt + 2; -- Skip Next Step
|
|
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
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- Continue
|
|
sample_abort_read <= '1';
|
|
cur_sample_next <= next_sample;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
-- READ Instance Pointer
|
|
when 5 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
inst_addr_update <= resize(unsigned(sample_read_data), INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
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;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE_ORPHAN_SAMPLES =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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;
|
|
end if;
|
|
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 = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
empty_sample_list_head_next <= cur_sample;
|
|
empty_sample_list_tail_next <= cur_sample;
|
|
cnt_next <= cnt + 2; --Skip Next Step
|
|
else
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- 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 + 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 <= cur_sample;
|
|
|
|
-- Current Sample is Newest (Occupied List Tail)
|
|
if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
assert (cur_sample = newest_sample) severity FAILURE;
|
|
|
|
-- Fix Newest Pointer
|
|
newest_sample_next <= prev_sample;
|
|
|
|
-- Current Sample is Oldest (List Head)
|
|
if (prev_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
assert (cur_sample = oldest_sample) severity FAILURE;
|
|
assert (newest_sample = oldest_sample) severity FAILURE;
|
|
-- NOTE: Sample Memory Empty (newest_sample also set to MAX_ADDR)
|
|
|
|
-- Fix Oldest Pointer
|
|
oldest_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
|
|
cnt_next <= cnt + 3; -- Skip next 2 steps
|
|
else
|
|
cnt_next <= cnt + 2; -- Skip next step
|
|
end if;
|
|
else
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- 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) report "Previous Sample is MAX_ADDR, but cur_sample /= oldest_sample" severity FAILURE;
|
|
|
|
-- Fix Oldest Pointer
|
|
oldest_sample_next <= next_sample;
|
|
|
|
cnt_next <= cnt + 2; -- Skip next step
|
|
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 <= global_sample_cnt - 1;
|
|
|
|
-- Update Global ACK Count
|
|
-- Sample was ACKed
|
|
if (sample_status_info(SSI_ACK_FLAG) = '1') then
|
|
global_ack_cnt_next <= global_ack_cnt - 1;
|
|
end if;
|
|
|
|
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 = PAYLOAD_MEMORY_MAX_ADDRESS) then
|
|
-- Fix Empty List Head
|
|
empty_payload_list_head_next <= 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 <= cnt - 1;
|
|
end if;
|
|
end if;
|
|
-- SET Next Payload Pointer (Last Payload of Current Sample)
|
|
when 14 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET;
|
|
payload_write_data <= std_logic_vector(resize(empty_payload_list_head,WORD_WIDTH));
|
|
|
|
-- Fix Empty List Head
|
|
empty_payload_list_head_next <= 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 (not WITH_KEY or inst_op_done = '1') then
|
|
assert check_mask(current_imf, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG) severity FAILURE;
|
|
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
inst_op_start <= '1';
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
inst_mem_fields <= IMF_SAMPLE_CNT_FLAG;
|
|
sample_cnt <= inst_data.sample_cnt - 1;
|
|
-- Sample was ACKed
|
|
if (sample_status_info(SSI_ACK_FLAG) = '1') then
|
|
inst_mem_fields <= IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
ack_cnt <= inst_data.ack_cnt - 1;
|
|
else
|
|
-- Update Stale Instance Count
|
|
-- Instance is Unregistered and last NACKed sample is removed
|
|
if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.sample_cnt = 1) then
|
|
stale_inst_cnt_next <= stale_inst_cnt + 1;
|
|
end if;
|
|
end if;
|
|
else
|
|
inst_data_next2.sample_cnt <= inst_data.sample_cnt - 1;
|
|
-- Sample was ACKed
|
|
if (sample_status_info(SSI_ACK_FLAG) = '1') then
|
|
inst_data_next2.ack_cnt <= inst_data.ack_cnt - 1;
|
|
end if;
|
|
end if;
|
|
|
|
if (is_rtps = '1') then
|
|
-- DONE
|
|
done_rtps <= '1';
|
|
ret_rtps <= OK;
|
|
stage_next <= IDLE;
|
|
elsif (is_lifespan_check = '1') then
|
|
-- Reached End of Samples
|
|
if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
cur_sample_next <= next_sample;
|
|
stage_next <= CHECK_LIFESPAN;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
end if;
|
|
when SKIP_AND_RETURN =>
|
|
case (cnt) is
|
|
-- SKIP READ
|
|
when 0 =>
|
|
ready_in_dds <= '1';
|
|
-- Wait until last word from input
|
|
if (last_word_in_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Return Code
|
|
when 1 =>
|
|
done_dds <= '1';
|
|
return_code_dds <= return_code_latch;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when SKIP =>
|
|
ready_in_dds <= '1';
|
|
-- Wait until last word from input
|
|
if (last_word_in_dds = '1') then
|
|
stage_next <= return_stage;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when REMOVE_STALE_INSTANCE =>
|
|
-- Precondition: inst_data set (IMF_STATUS_FLAG, IMF_SAMPLE_CNT_FLAG, IMF_ACK_CNT_FLAG)
|
|
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Wait for Instance Data
|
|
if (inst_op_done = '1') then
|
|
case (cnt) is
|
|
-- Find and Remove First Stale Instance
|
|
when 0 =>
|
|
assert check_mask(current_imf, IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG) severity FAILURE;
|
|
|
|
-- Iterated through all Instances
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- NOTE: We should enter this state only if there is at least one stale Instance to be removed, so we should never enter this branch.
|
|
assert FALSE severity FAILURE;
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Found Stale Instance (Unregistered and all Samples ACKed)
|
|
if (inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.sample_cnt = inst_data.ack_cnt) then
|
|
-- Remove Stale Instance
|
|
inst_op_start <= '1';
|
|
inst_opcode <= REMOVE_INSTANCE;
|
|
-- Update Stale Instance Count
|
|
stale_inst_cnt_next <= stale_inst_cnt - 1;
|
|
|
|
-- Instance has Samples
|
|
if (inst_data.sample_cnt /= 0) then
|
|
-- NOTE: The Stale Instance has Samples that need to be removed, but we cannot do that now,
|
|
-- because that would mess with our current Sample that is currently in "limbo" until
|
|
-- finalized. So we postpone the Sample removal until after the finalization of the
|
|
-- current sample.
|
|
orphan_samples_next <= '1';
|
|
dead_inst_next <= inst_addr_base;
|
|
end if;
|
|
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
-- Continue Search
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_NEXT_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
end if;
|
|
end if;
|
|
-- Insert New Instance
|
|
when 1 =>
|
|
inst_op_start <= '1';
|
|
inst_opcode <= INSERT_INSTANCE;
|
|
ack_cnt <= (others => '0');
|
|
if (register_op = '1') then
|
|
status_info_update <= (others => '0');
|
|
sample_cnt <= (others => '0');
|
|
else
|
|
status_info_update <= (ISI_LIVELINESS_FLAG => '1', others => '0');
|
|
sample_cnt <= to_unsigned(1, WORD_WIDTH);
|
|
end if;
|
|
|
|
-- Latch Instance Pointer
|
|
cur_inst_next <= inst_empty_head;
|
|
|
|
-- Register Operation in progress
|
|
if (register_op = '1') then
|
|
-- DONE
|
|
stage_next <= PUSH_KEY_HASH;
|
|
cnt_next <= 0;
|
|
else
|
|
stage_next <= FINALIZE_PAYLOAD;
|
|
cnt_next <= 0;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
when GET_SEQ_NR =>
|
|
-- Precondition: cur_sample set
|
|
|
|
case (cnt) is
|
|
-- GET Sequence Number 1/2
|
|
when 0 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Sequence Number 2/2
|
|
when 1 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET + 1;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Sequence Number 1/2
|
|
when 2 =>
|
|
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 <= '1';
|
|
ret_rtps <= OK;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when FIND_SEQ_NR =>
|
|
-- NOTE: We are searching in backwards order, since it is more likely that newer Sequence Numbers are polled
|
|
case (cnt) is
|
|
-- GET Previous Sample
|
|
when 0 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Sequence Number 1/2
|
|
when 1 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Sequence Number 2/2
|
|
when 2 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_SEQ_NR_OFFSET + 1;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 2; -- Skip Next Step
|
|
end if;
|
|
end if;
|
|
-- GET Instance Pointer
|
|
when 3 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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;
|
|
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
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 2; -- Skip Next Step
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- READ Instance Pointer
|
|
when 7 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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;
|
|
end if;
|
|
-- Check Result
|
|
when 8 =>
|
|
-- No Sample with Requested Sequence Number found
|
|
if (cur_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
done_rtps <= '1';
|
|
ret_rtps <= INVALID;
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
-- Fetch Instance Data
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_INSTANCE;
|
|
inst_mem_fields <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
inst_addr_update <= cur_inst;
|
|
|
|
stage_next <= return_stage;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
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 <= '1';
|
|
ret_rtps <= OK;
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Status Info
|
|
when 2 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_STATUS_INFO_OFFSET;
|
|
sample_write_data <= sample_status_info;
|
|
sample_write_data(SSI_ACK_FLAG) <= '1' when (is_ack = '1') else '0';
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
global_ack_cnt_next <= (global_ack_cnt + 1) when (is_ack = '1') else (global_ack_cnt - 1);
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- SET Instance Data
|
|
when 3 =>
|
|
if (WITH_KEY) then
|
|
-- Wait for Instance Data
|
|
if (inst_op_done = '1') then
|
|
assert check_mask(current_imf, 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_mem_fields <= IMF_ACK_CNT_FLAG;
|
|
inst_addr_update <= cur_inst;
|
|
ack_cnt <= (inst_data.ack_cnt + 1) when (is_ack = '1') else (inst_data.ack_cnt - 1);
|
|
|
|
-- Update Stale Instance Count
|
|
-- XXX: Possible Worst Case Path (Addition and Comparison in same clock)
|
|
if (is_ack = '1' and inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and (inst_data.ack_cnt+1) = inst_data.sample_cnt) then
|
|
stale_inst_cnt_next <= stale_inst_cnt + 1;
|
|
elsif (is_ack = '0' and inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and inst_data.ack_cnt = inst_data.sample_cnt) then
|
|
stale_inst_cnt_next <= stale_inst_cnt - 1;
|
|
end if;
|
|
|
|
-- DONE
|
|
done_rtps <= '1';
|
|
ret_rtps <= OK;
|
|
stage_next <= IDLE;
|
|
end if;
|
|
else
|
|
inst_data_next2.ack_cnt <= (inst_data.ack_cnt + 1) when (is_ack = '1') else (inst_data.ack_cnt - 1);
|
|
|
|
-- DONE
|
|
done_rtps <= '1';
|
|
ret_rtps <= 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);
|
|
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 2; -- Skip Next Step
|
|
end if;
|
|
end if;
|
|
-- Instance Handle
|
|
when 8 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Wait for Instance Data
|
|
if (inst_op_done = '1') then
|
|
assert check_mask(current_imf, IMF_KEY_HASH_FLAG) severity FAILURE;
|
|
|
|
cc_instance_handle_sig_next <= inst_data.key_hash;
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- Present Sample
|
|
when 9 =>
|
|
done_rtps <= '1';
|
|
ret_rtps <= OK;
|
|
|
|
-- RTPS Requestes Payload
|
|
if (get_data_rtps = '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 Controler 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-1,CDR_LONG_WIDTH));
|
|
end if;
|
|
end if;
|
|
-- GET Payload Offset
|
|
when 2 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PAYLOAD_FRAME_SIZE-1;
|
|
payload_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (payload_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Payload Offset
|
|
when 3 =>
|
|
payload_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (payload_valid_out = '1') then
|
|
long_latch_next <= payload_read_data;
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET PAYLOAD
|
|
when 4 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + cnt2;
|
|
payload_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (payload_ready_in = '1') then
|
|
cnt3_next <= cnt3 + 1;
|
|
tmp_bool := TRUE;
|
|
-- End of Payload Slot
|
|
if (cnt2 = unsigned(long_latch)) then
|
|
-- End of Payload
|
|
if (next_payload = PAYLOAD_MEMORY_MAX_ADDRESS) then
|
|
-- DONE (Wait for Output to finidh reading)
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
-- Next Payload Slot
|
|
cur_payload_next <= next_payload;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
cnt2_next <= cnt2 + 1;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
|
|
-- Data available for Output
|
|
if (cnt3 /= 0) then
|
|
-- Memory Flow Control Guard
|
|
if (payload_valid_out = '1') then
|
|
valid_out_rtps <= '1';
|
|
data_out_rtps <= payload_read_data;
|
|
|
|
-- End of Payload
|
|
if (cnt3 = 1 and cnt = 5) then
|
|
last_word_out_rtps <= '1';
|
|
end if;
|
|
|
|
-- DDS Read
|
|
if (ready_out_rtps = '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 Sample
|
|
when 0 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Lifespan 1/2
|
|
when 1 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- GET Lifespan 2/2
|
|
when 2 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_LIFESPAN_DEADLINE_OFFSET + 1;
|
|
sample_read <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_ready_in = '1') then
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
cnt_next <= cnt + 2; --Skip Next Step
|
|
end if;
|
|
end if;
|
|
-- GET Instance Pointer
|
|
when 3 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
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;
|
|
end if;
|
|
-- READ Next Sample
|
|
when 4 =>
|
|
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 5 =>
|
|
sample_ready_out <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_valid_out = '1') then
|
|
long_latch_next <= sample_read_data;
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- READ Lifespan 2/2
|
|
when 6 =>
|
|
sample_ready_out <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_valid_out = '1') then
|
|
tmp_dw := (0 => unsigned(long_latch), 1 => unsigned(sample_read_data));
|
|
|
|
-- Sample Lifespan Expired
|
|
if (tmp_dw /= TIME_INVALID and time >= tmp_dw) then
|
|
if (WITH_KEY) then
|
|
cnt_next <= cnt + 1;
|
|
else
|
|
-- Remove Sample
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
else
|
|
sample_abort_read <= '1';
|
|
|
|
-- Update Check Time
|
|
if (tmp_dw /= TIME_INVALID and tmp_dw < lifespan_time) then
|
|
lifespan_time_next <= tmp_dw;
|
|
end if;
|
|
|
|
-- Reached End of Samples
|
|
if (next_sample = SAMPLE_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
cur_sample_next <= next_sample;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
-- READ Instance Pointer
|
|
when 7 =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
sample_ready_out <= '1';
|
|
|
|
-- Memory Control Flow Guard
|
|
if (sample_valid_out = '1') then
|
|
-- Fetch Instance Data
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG or IMF_SAMPLE_CNT_FLAG or IMF_ACK_CNT_FLAG;
|
|
inst_addr_update <= resize(unsigned(sample_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
-- Remove Sample
|
|
stage_next <= REMOVE_SAMPLE;
|
|
cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_LIVELINESS_LOST_STATUS =>
|
|
case (cnt) is
|
|
-- Return Code
|
|
when 0 =>
|
|
done_dds <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
cnt_next <= cnt + 1;
|
|
-- Total Count
|
|
when 1 =>
|
|
data_out_dds <= std_logic_vector(liveliness_lost_cnt);
|
|
valid_out_dds <= '1';
|
|
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Total Count Change
|
|
when 2 =>
|
|
data_out_dds <= std_logic_vector(liveliness_lost_cnt_change);
|
|
valid_out_dds <= '1';
|
|
last_word_out_dds <= '1';
|
|
|
|
if (ready_out_dds = '1') then
|
|
-- Reset
|
|
liveliness_lost_cnt_change_next <= (others => '0');
|
|
status_sig_next <= status_sig 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 <= '1';
|
|
return_code_dds <= RETCODE_OK;
|
|
cnt_next <= cnt + 1;
|
|
-- Total Count
|
|
when 1 =>
|
|
data_out_dds <= std_logic_vector(deadline_miss_cnt);
|
|
valid_out_dds <= '1';
|
|
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Total Count Change
|
|
when 2 =>
|
|
data_out_dds <= std_logic_vector(deadline_miss_cnt_change);
|
|
valid_out_dds <= '1';
|
|
|
|
if (ready_out_dds = '1') then
|
|
-- Reset
|
|
deadline_miss_cnt_change_next <= (others => '0');
|
|
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Last Instance Handle 1/4
|
|
when 3 =>
|
|
data_out_dds <= deadline_miss_last_inst(0);
|
|
valid_out_dds <= '1';
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Last Instance Handle 2/4
|
|
when 4 =>
|
|
data_out_dds <= deadline_miss_last_inst(1);
|
|
valid_out_dds <= '1';
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Last Instance Handle 3/4
|
|
when 5 =>
|
|
data_out_dds <= deadline_miss_last_inst(2);
|
|
valid_out_dds <= '1';
|
|
if (ready_out_dds = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Last Instance Handle 4/4
|
|
when 6 =>
|
|
data_out_dds <= deadline_miss_last_inst(3);
|
|
valid_out_dds <= '1';
|
|
last_word_out_dds <= '1';
|
|
if (ready_out_dds = '1') then
|
|
-- Reset
|
|
deadline_miss_last_inst_next <= HANDLE_NIL;
|
|
status_sig_next <= status_sig and (not OFFERED_DEADLINE_MISSED_STATUS);
|
|
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when CHECK_DEADLINE =>
|
|
-- Synthesis Guard
|
|
if (WITH_KEY) then
|
|
-- Memory Operation Guard
|
|
if (inst_op_done = '1') then
|
|
case (cnt) is
|
|
-- Get First Instance
|
|
when 0 =>
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_FIRST_INSTANCE;
|
|
inst_mem_fields <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG;
|
|
cnt_next <= 2;
|
|
-- Get Next Instance
|
|
when 1 =>
|
|
inst_op_start <= '1';
|
|
inst_opcode <= GET_NEXT_INSTANCE;
|
|
inst_mem_fields <= IMF_KEY_HASH_FLAG or IMF_STATUS_FLAG;
|
|
cnt_next <= 2;
|
|
-- Check Instance
|
|
when 2 =>
|
|
assert check_mask(current_imf, IMF_STATUS_FLAG or IMF_KEY_HASH_FLAG) severity FAILURE;
|
|
|
|
-- Reached End of Instances
|
|
if (inst_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
else
|
|
-- Instance received Sample
|
|
if (inst_data.status_info(ISI_LIVELINESS_FLAG) = '1') then
|
|
-- Reset Liveliness Flag
|
|
inst_op_start <= '1';
|
|
inst_opcode <= UPDATE_INSTANCE;
|
|
inst_mem_fields <= IMF_STATUS_FLAG;
|
|
status_info_update <= inst_data.status_info;
|
|
status_info_update(ISI_LIVELINESS_FLAG) <= '0';
|
|
cnt_next <= 1;
|
|
else
|
|
-- Update Requested Deadline Missed Status
|
|
status_sig_next <= status_sig or OFFERED_DEADLINE_MISSED_STATUS;
|
|
deadline_miss_cnt_next <= deadline_miss_cnt + 1;
|
|
deadline_miss_cnt_change_next <= deadline_miss_cnt_change + 1;
|
|
deadline_miss_last_inst_next <= inst_data.key_hash;
|
|
cnt_next <= 1;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
when RESET_SAMPLE_MEMORY =>
|
|
case (cnt) is
|
|
-- Initialize
|
|
when 0 =>
|
|
prev_sample_next <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
cur_sample_next <= (others => '0');
|
|
cnt_next <= cnt + 1;
|
|
-- SET Previous Pointer
|
|
when 1 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_PREV_ADDR_OFFSET;
|
|
sample_write_data <= 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 2 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_NEXT_ADDR_OFFSET;
|
|
if (cur_sample = MAX_SAMPLE_ADDRESS) 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) then
|
|
-- DONE
|
|
stage_next <= RESET_PAYLOAD_MEMORY;
|
|
cnt_next <= 0;
|
|
empty_sample_list_head_next <= FIRST_SAMPLE_ADDRESS;
|
|
empty_sample_list_tail_next <= MAX_SAMPLE_ADDRESS;
|
|
else
|
|
-- Continue
|
|
cur_sample_next <= cur_sample + SAMPLE_FRAME_SIZE;
|
|
prev_sample_next <= cur_sample;
|
|
cnt_next <= 1;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when RESET_PAYLOAD_MEMORY =>
|
|
case (cnt) is
|
|
-- Initialize
|
|
when 0 =>
|
|
cur_payload_next <= (others => '0');
|
|
cnt_next <= cnt + 1;
|
|
-- SET Next Pointer
|
|
when 1 =>
|
|
payload_valid_in <= '1';
|
|
payload_addr <= cur_payload + PMF_NEXT_ADDR_OFFSET;
|
|
if (cur_payload = MAX_PAYLOAD_ADDRESS) then
|
|
payload_write_data <= std_logic_vector(resize(PAYLOAD_MEMORY_MAX_ADDRESS,WORD_WIDTH));
|
|
else
|
|
payload_write_data <= std_logic_vector(resize(cur_payload + PAYLOAD_FRAME_SIZE,WORD_WIDTH));
|
|
end if;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (payload_ready_in = '1') then
|
|
if (cur_payload = MAX_PAYLOAD_ADDRESS) then
|
|
-- DONE
|
|
stage_next <= IDLE;
|
|
empty_payload_list_head_next <= FIRST_PAYLOAD_ADDRESS;
|
|
else
|
|
cur_payload_next <= cur_payload + PAYLOAD_FRAME_SIZE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end process;
|
|
|
|
gen_inst_ctrl_prc : if WITH_KEY generate
|
|
|
|
-- *Instance Memory Process*
|
|
-- STATE DESCRIPTION
|
|
-- IDLE Idle State. Done Signal is pulled high and Memory FSM accepts new memory operations
|
|
-- SEARCH_INSTANCE_HASH See Memory OPCODE Description
|
|
-- SEARCH_INSTANCE_ADDR See Memory OPCODE Description
|
|
-- GET_NEXT_INSTANCE See Memory OPCODE Description
|
|
-- GET_INSTANCE_DATA Latch specified Instance Data for use by main process
|
|
-- INSERT_INSTANCE See Memory OPCODE Description
|
|
-- UPDATE_INSTANCE See Memory OPCODE Description
|
|
-- REMOVE_INSTANCE See Memory OPCODE Description
|
|
-- RESET_MEMORY Reset Endpoint Memory to Empty State
|
|
inst_ctrl_prc : process(all)
|
|
begin
|
|
-- DEFAULT Registered
|
|
inst_stage_next <= inst_stage;
|
|
inst_addr_base_next <= inst_addr_base;
|
|
inst_empty_head_next <= inst_empty_head;
|
|
inst_occupied_head_next <= inst_occupied_head;
|
|
inst_latch_data_next <= inst_latch_data;
|
|
inst_next_addr_base_next <= inst_next_addr_base;
|
|
inst_prev_addr_base_next <= inst_prev_addr_base;
|
|
inst_cnt_next <= inst_cnt;
|
|
inst_data_next <= inst_data;
|
|
inst_long_latch_next <= inst_long_latch;
|
|
current_imf_next <= current_imf;
|
|
-- 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
|
|
-- Latch Signals needed for Mermory Operation (Use _next signals, because some signals are set in same clk)
|
|
inst_latch_data_next <= (
|
|
key_hash => key_hash_next,
|
|
status_info => status_info_update,
|
|
sample_cnt => sample_cnt,
|
|
ack_cnt => ack_cnt,
|
|
field_flags => inst_mem_fields,
|
|
addr => inst_addr_update
|
|
);
|
|
|
|
case(inst_opcode) is
|
|
when SEARCH_INSTANCE_HASH =>
|
|
-- Reset Data
|
|
current_imf_next <= inst_mem_fields;
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
-- No Instances available
|
|
if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_stage_next <= SEARCH_INSTANCE_HASH;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when SEARCH_INSTANCE_ADDR =>
|
|
-- Reset Data
|
|
current_imf_next <= inst_mem_fields;
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
-- No Instances avialable
|
|
if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_stage_next <= SEARCH_INSTANCE_ADDR;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when INSERT_INSTANCE =>
|
|
-- NOTE: Since this process has no way to communicate a failed insert to the main process, it has to be made sure
|
|
-- by the main process that the operation can succeed (Memory is available)
|
|
assert (inst_empty_head /= INSTANCE_MEMORY_MAX_ADDRESS) report "Instance Insertion while memory Full" severity FAILURE;
|
|
|
|
-- Reset Data
|
|
current_imf_next <= (others => '1');
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
inst_addr_base_next <= inst_empty_head;
|
|
inst_stage_next <= INSERT_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
|
|
-- SET Instance Data
|
|
inst_data_next.key_hash <= key_hash_next;
|
|
inst_data_next.status_info <= status_info_update;
|
|
inst_data_next.sample_cnt <= sample_cnt;
|
|
inst_data_next.ack_cnt <= ack_cnt;
|
|
when UPDATE_INSTANCE =>
|
|
current_imf_next <= current_imf or inst_mem_fields;
|
|
inst_stage_next <= UPDATE_INSTANCE;
|
|
|
|
if check_mask(inst_mem_fields,IMF_STATUS_FLAG) then
|
|
inst_cnt_next <= 0;
|
|
elsif check_mask(inst_mem_fields,IMF_SAMPLE_CNT_FLAG) then
|
|
inst_cnt_next <= 1;
|
|
elsif check_mask(inst_mem_fields,IMF_ACK_CNT_FLAG) then
|
|
inst_cnt_next <= 2;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when GET_FIRST_INSTANCE =>
|
|
-- Reset
|
|
current_imf_next <= inst_mem_fields;
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
-- No Instances avialable
|
|
if (inst_occupied_head = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_addr_base_next <= inst_occupied_head;
|
|
inst_stage_next <= GET_NEXT_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when GET_NEXT_INSTANCE =>
|
|
-- Reset
|
|
current_imf_next <= inst_mem_fields;
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
-- No Instances avialable
|
|
if (inst_next_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
else
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_stage_next <= GET_NEXT_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
when REMOVE_INSTANCE =>
|
|
-- Reset
|
|
current_imf_next <= (others => '0');
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
|
|
inst_stage_next <= REMOVE_INSTANCE;
|
|
inst_cnt_next <= 0;
|
|
when GET_INSTANCE =>
|
|
inst_addr_base_next <= inst_addr_update;
|
|
if (inst_addr_base /= inst_addr_update) then
|
|
-- Reset
|
|
current_imf_next <= inst_mem_fields;
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
else
|
|
current_imf_next <= current_imf or inst_mem_fields;
|
|
end if;
|
|
|
|
-- Get Instance Data
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
if check_mask(inst_mem_fields,IMF_KEY_HASH_FLAG) then
|
|
inst_cnt_next <= 0;
|
|
elsif check_mask(inst_mem_fields,IMF_STATUS_FLAG) then
|
|
inst_cnt_next <= 4;
|
|
elsif check_mask(inst_mem_fields,IMF_SAMPLE_CNT_FLAG) then
|
|
inst_cnt_next <= 5;
|
|
elsif check_mask(inst_mem_fields,IMF_ACK_CNT_FLAG) then
|
|
inst_cnt_next <= 6;
|
|
else
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
when SEARCH_INSTANCE_HASH =>
|
|
|
|
case (inst_cnt) is
|
|
-- GET Next Instance
|
|
when 0 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- GET Key Hash 1/4
|
|
when 1 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- GET Key Hash 2/4
|
|
when 2 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 1;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- GET Key Hash 3/4
|
|
when 3 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 2;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- GET Key Hash 4/4
|
|
when 4 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- READ Next Instance
|
|
when 5 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
inst_next_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- READ Key Hash 1/4
|
|
when 6 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(0)) then
|
|
inst_abort_read <= '1';
|
|
-- Reached List Tail, No Match
|
|
if (inst_next_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
else
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- READ Key Hash 2/4
|
|
when 7 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(1)) then
|
|
inst_abort_read <= '1';
|
|
-- Reached List Tail, No Match
|
|
if (inst_next_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
else
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- READ Key Hash 3/4
|
|
when 8 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(2)) then
|
|
inst_abort_read <= '1';
|
|
-- Reached List Tail, No Match
|
|
if (inst_next_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
else
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- READ Key Hash 4/4
|
|
when 9 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
-- No Match
|
|
if (inst_read_data /= inst_latch_data.key_hash(3)) then
|
|
-- Reached List Tail, No Match
|
|
if (inst_next_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= inst_next_addr_base;
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
else
|
|
-- Get Instance Data
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
if check_mask(inst_latch_data.field_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 SEARCH_INSTANCE_ADDR =>
|
|
|
|
case (inst_cnt) is
|
|
-- GET Next Instance
|
|
when 0 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- READ Next Instance
|
|
when 1 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
inst_prev_addr_base_next <= inst_addr_base;
|
|
inst_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
-- Match
|
|
if (resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = inst_latch_data.addr) then
|
|
-- Get Instance Data
|
|
inst_stage_next <= GET_INSTANCE_DATA;
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
if check_mask(inst_latch_data.field_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;
|
|
-- No Match
|
|
else
|
|
-- Reached List Tail, No Match
|
|
if (resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH) = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS; --No match
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
else
|
|
-- Continue Search
|
|
inst_cnt_next <= 0;
|
|
end if;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when GET_NEXT_INSTANCE =>
|
|
case (inst_cnt) is
|
|
-- GET next Instance
|
|
when 0 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- READ Next Instance
|
|
when 1 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
inst_next_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
-- Get Instance Data
|
|
inst_data_next <= ZERO_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;
|
|
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;
|
|
|
|
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;
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
end case;
|
|
when INSERT_INSTANCE =>
|
|
-- Precondition: inst_addr_base set
|
|
|
|
case (inst_cnt) is
|
|
-- GET Next Instance Pointer
|
|
when 0 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Next Instance Pointer
|
|
when 1 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_write_data <= std_logic_vector(resize(inst_occupied_head,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
-- Fix Occupied List Head
|
|
inst_occupied_head_next <= inst_addr_base;
|
|
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- READ Next Instance Pointer
|
|
when 2 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
-- Fix Empty List Head
|
|
inst_empty_head_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Key Hash 1/4
|
|
when 3 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET;
|
|
inst_write_data <= inst_latch_data.key_hash(0);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Key Hash 2/4
|
|
when 4 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 1;
|
|
inst_write_data <= inst_latch_data.key_hash(1);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Key Hash 3/4
|
|
when 5 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 2;
|
|
inst_write_data <= inst_latch_data.key_hash(2);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Key Hash 4/4
|
|
when 6 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_KEY_HASH_OFFSET + 3;
|
|
inst_write_data <= inst_latch_data.key_hash(3);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Status Info
|
|
when 7 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET;
|
|
inst_write_data <= inst_latch_data.status_info;
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Sample Count
|
|
when 8 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_SAMPLE_CNT_OFFSET;
|
|
inst_write_data <= std_logic_vector(inst_latch_data.sample_cnt);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET ACK Count
|
|
when 9 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_ACK_CNT_OFFSET;
|
|
inst_write_data <= std_logic_vector(inst_latch_data.ack_cnt);
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when UPDATE_INSTANCE =>
|
|
case (inst_cnt) is
|
|
-- Status Info
|
|
when 0 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_STATUS_INFO_OFFSET;
|
|
inst_write_data <= inst_latch_data.status_info;
|
|
inst_data_next.status_info <= inst_latch_data.status_info;
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
if check_mask(inst_latch_data.field_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;
|
|
-- 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;
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when REMOVE_INSTANCE =>
|
|
-- Precondition: inst_addr_base set, inst_prev_addr_base set
|
|
|
|
case (inst_cnt) is
|
|
-- GET Next Instance
|
|
when 0 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_read <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- READ Next Instance
|
|
when 1 =>
|
|
inst_ready_out <= '1';
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_valid_out = '1') then
|
|
inst_next_addr_base_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
-- Removed Instance is List Head
|
|
if (inst_prev_addr_base = INSTANCE_MEMORY_MAX_ADDRESS) then
|
|
assert (inst_addr_base = inst_occupied_head) severity FAILURE;
|
|
|
|
-- Fix Occupied Head
|
|
inst_occupied_head_next <= resize(unsigned(inst_read_data),INSTANCE_MEMORY_ADDR_WIDTH);
|
|
|
|
inst_cnt_next <= inst_cnt + 2; -- Skip Next Step
|
|
else
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
end if;
|
|
-- SET Next Pointer (Previous Instance)
|
|
when 2 =>
|
|
-- Point Previous instance to Next Instance (Remove current Instance from inbetween)
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_prev_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_write_data <= std_logic_vector(resize(inst_next_addr_base,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
end if;
|
|
-- SET Next Pointer (Current/Removed Instance)
|
|
when 3 =>
|
|
-- Point Current Instance to Empty List Head (Make Removed Instance Head of the Empty List)
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
inst_write_data <= std_logic_vector(resize(inst_empty_head,WORD_WIDTH));
|
|
|
|
-- Memory Flow Control Guard
|
|
if (inst_ready_in = '1') then
|
|
-- Fix Empty List Head
|
|
inst_empty_head_next <= inst_addr_base;
|
|
|
|
-- Reset
|
|
inst_data_next <= ZERO_INSTANCE_DATA;
|
|
inst_addr_base_next <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when RESET_MEMORY =>
|
|
case (inst_cnt) is
|
|
-- Initialize
|
|
when 0 =>
|
|
inst_addr_base_next <= FIRST_INSTANCE_ADDRESS;
|
|
inst_cnt_next <= inst_cnt + 1;
|
|
-- SET Next Pointer
|
|
when 1 =>
|
|
inst_valid_in <= '1';
|
|
inst_addr <= inst_addr_base + IMF_NEXT_ADDR_OFFSET;
|
|
if (inst_addr_base = MAX_INSTANCE_ADDRESS) then
|
|
inst_write_data <= 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
|
|
if (inst_addr_base = MAX_INSTANCE_ADDRESS) then
|
|
-- DONE
|
|
inst_stage_next <= IDLE;
|
|
inst_empty_head_next <= FIRST_INSTANCE_ADDRESS;
|
|
else
|
|
inst_addr_base_next <= inst_addr_base + INSTANCE_FRAME_SIZE;
|
|
end if;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end process;
|
|
end generate;
|
|
|
|
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 <= HANDLE_NIL;
|
|
key_hash <= HANDLE_NIL;
|
|
deadline_time <= time + DEADLINE_QOS;
|
|
lifespan_time <= TIME_INFINITE;
|
|
source_ts <= TIME_INVALID;
|
|
timeout_time <= TIME_INVALID;
|
|
lease_deadline <= time + LEASE_DURATION;
|
|
cc_source_timestamp_sig <= TIME_INVALID;
|
|
lifespan <= DURATION_INFINITE;
|
|
global_seq_nr <= 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_INST_LATCH_DATA;
|
|
cnt <= 0;
|
|
cnt2 <= 0;
|
|
cnt3 <= 0;
|
|
global_sample_cnt <= 0;
|
|
global_ack_cnt <= 0;
|
|
stale_inst_cnt <= 0;
|
|
inst_cnt <= 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 <= '0';
|
|
is_ack <= '0';
|
|
is_rtps <= '0';
|
|
data_available_sig <= '0';
|
|
orphan_samples <= '0';
|
|
newest_sample <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
oldest_sample <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
empty_payload_list_head <= PAYLOAD_MEMORY_MAX_ADDRESS;
|
|
empty_sample_list_head <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
empty_sample_list_tail <= SAMPLE_MEMORY_MAX_ADDRESS;
|
|
payload_addr_latch_1 <= (others => '0');
|
|
payload_addr_latch_2 <= (others => '0');
|
|
long_latch <= (others => '0');
|
|
sample_addr_latch_1 <= (others => '0');
|
|
sample_addr_latch_2 <= (others => '0');
|
|
sample_addr_latch_3 <= (others => '0');
|
|
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 => '0');
|
|
deadline_miss_cnt_change <= (others => '0');
|
|
liveliness_lost_cnt <= (others => '0');
|
|
liveliness_lost_cnt_change <= (others => '0');
|
|
status_sig <= (others => '0');
|
|
current_imf <= (others => '0');
|
|
inst_addr_base <= (others => '0');
|
|
inst_empty_head <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_occupied_head <= INSTANCE_MEMORY_MAX_ADDRESS;
|
|
inst_long_latch <= (others => '0');
|
|
inst_next_addr_base <= (others => '0');
|
|
inst_prev_addr_base <= (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_time <= deadline_time_next;
|
|
lifespan_time <= lifespan_time_next;
|
|
source_ts <= source_ts_next;
|
|
timeout_time <= timeout_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 when WITH_KEY else inst_data_next2;
|
|
inst_latch_data <= inst_latch_data_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;
|
|
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;
|
|
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;
|
|
current_imf <= current_imf_next when WITH_KEY else (others => '1');
|
|
inst_addr_base <= inst_addr_base_next;
|
|
inst_empty_head <= inst_empty_head_next;
|
|
inst_occupied_head <= inst_occupied_head_next;
|
|
inst_long_latch <= inst_long_latch_next;
|
|
inst_next_addr_base <= inst_next_addr_base_next;
|
|
inst_prev_addr_base <= inst_prev_addr_base_next;
|
|
return_code_latch <= return_code_latch_next;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end architecture; |