Remove non-Quartus-supported VHDL 2008 features. Remove inferred Latches. Add test Entities to see resulting hw synthesis of various code segments.
4688 lines
255 KiB
VHDL
4688 lines
255 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 (
|
|
-- XXX: Quartus Limitation [VHDL error at <location>: generic "<name>" cannot be used in its own interface list (ID: 10556)]
|
|
--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 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
|
|
|
|
--*****COMPONENT DECLARATION*****
|
|
component key_holder is
|
|
port (
|
|
-- SYSTEM
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
-- CONTROL
|
|
start : in std_logic;
|
|
opcode : in KEY_HOLDER_OPCODE_TYPE;
|
|
ack : out std_logic;
|
|
decode_error : out std_logic;
|
|
abort : in std_logic;
|
|
-- INPUT
|
|
ready_in : out std_logic;
|
|
valid_in : in std_logic;
|
|
data_in : in std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
last_word_in : in std_logic;
|
|
-- OUTPUT
|
|
ready_out : in std_logic;
|
|
valid_out : out std_logic;
|
|
data_out : out std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
last_word_out : out std_logic
|
|
);
|
|
end component;
|
|
|
|
--*****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
|
|
if (lifespan /= DURATION_INFINITE) then
|
|
ret := SMF_LIFESPAN_DEADLINE_OFFSET + 2;
|
|
else
|
|
ret := SMF_LIFESPAN_DEADLINE_OFFSET;
|
|
end if;
|
|
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
|
|
if (WITH_KEY) then
|
|
ret := SMF_INSTANCE_ADDR_OFFSET + 1;
|
|
else
|
|
ret := SMF_INSTANCE_ADDR_OFFSET;
|
|
end if;
|
|
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 => KEY_HASH_NIL,
|
|
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 => KEY_HASH_NIL,
|
|
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);
|
|
signal sample_read : std_logic;
|
|
signal sample_read_data, sample_write_data : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
signal sample_ready_in, sample_valid_in : std_logic;
|
|
signal sample_ready_out, sample_valid_out : std_logic;
|
|
signal sample_abort_read : std_logic;
|
|
|
|
-- *PAYLOAD MEMORY CONNECTION SIGNALS*
|
|
signal payload_addr : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
signal payload_read : std_logic;
|
|
signal payload_read_data, payload_write_data : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
signal payload_ready_in, payload_valid_in : std_logic;
|
|
signal payload_ready_out, payload_valid_out : std_logic;
|
|
signal payload_abort_read : std_logic;
|
|
|
|
-- *INSTANCE MEMORY CONNECTION SIGNALS*
|
|
signal inst_addr : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
signal inst_read : std_logic;
|
|
signal inst_read_data, inst_write_data : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
signal inst_ready_in, inst_valid_in : std_logic;
|
|
signal inst_ready_out, inst_valid_out : std_logic;
|
|
signal inst_abort_read : std_logic;
|
|
|
|
-- *KEY HOLDER CONNECTION SIGNALS*
|
|
signal start_kh, ack_kh, valid_in_kh, ready_in_kh, last_word_in_kh, valid_out_kh, ready_out_kh, last_word_out_kh, abort_kh : std_logic;
|
|
signal opcode_kh : KEY_HOLDER_OPCODE_TYPE;
|
|
signal data_in_kh, data_out_kh : std_logic_vector(WORD_WIDTH-1 downto 0);
|
|
|
|
-- *MAIN PROCESS*
|
|
-- FSM state
|
|
signal stage, stage_next : STAGE_TYPE;
|
|
-- FSM state latch. Used to transition dynamically to different states from the same state.
|
|
signal return_stage, return_stage_next : STAGE_TYPE;
|
|
-- General Purpose Counter
|
|
signal cnt, cnt_next : natural range 0 to 14;
|
|
-- Counter used to read/write Payload Fames
|
|
signal cnt2, cnt2_next : natural range 0 to max(PAYLOAD_FRAME_SIZE, INSTANCE_HANDLE_TYPE'length-1);
|
|
-- Counter used to read/write Payload Fames
|
|
signal cnt3, cnt3_next : natural range 0 to PAYLOAD_FRAME_SIZE;
|
|
-- Head of Empty Sample List
|
|
signal empty_sample_list_head, empty_sample_list_head_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Tail of Empty Sample List
|
|
signal empty_sample_list_tail, empty_sample_list_tail_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Head of Empty Payload List
|
|
signal empty_payload_list_head, empty_payload_list_head_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Oldest Sample (Head of Occupied Sample List)
|
|
signal oldest_sample, oldest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Newest Sample (Tail of Occupied Sample List)
|
|
signal newest_sample, newest_sample_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Denotes if the oldest Sample should be removed
|
|
signal remove_oldest_sample, remove_oldest_sample_next : std_logic;
|
|
-- Denotes if the oldest sample of the Instance with 'key_hash' should be removed
|
|
signal remove_oldest_inst_sample, remove_oldest_inst_sample_next : std_logic;
|
|
-- Denotes if the Sample tobe removed should be ACKed
|
|
signal remove_ack_sample, remove_ack_sample_next : std_logic;
|
|
-- Lifespan Latch
|
|
signal lifespan, lifespan_next : TIME_TYPE;
|
|
-- Key hash Latch
|
|
signal key_hash, key_hash_next : KEY_HASH_TYPE;
|
|
-- Return Code Latch
|
|
signal return_code_latch, return_code_latch_next : std_logic_vector(RETURN_CODE_WIDTH-1 downto 0);
|
|
-- Instance Handle Latch
|
|
signal instance_handle, instance_handle_next : INSTANCE_HANDLE_TYPE;
|
|
-- Source Timestamp Latch
|
|
signal source_ts, source_ts_next : TIME_TYPE;
|
|
-- Sequence Number Latch
|
|
signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE;
|
|
-- Sample Status Info Latch
|
|
signal sample_status_info, sample_status_info_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
|
|
-- General Purpose Payload Pointer
|
|
signal payload_addr_latch_1, payload_addr_latch_1_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Payload Pointer
|
|
signal payload_addr_latch_2, payload_addr_latch_2_next : unsigned(PAYLOAD_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_1, sample_addr_latch_1_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_2, sample_addr_latch_2_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_3, sample_addr_latch_3_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Sample Pointer
|
|
signal sample_addr_latch_4, sample_addr_latch_4_next : unsigned(SAMPLE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Instance Pointer
|
|
signal inst_addr_latch_1, inst_addr_latch_1_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Instance Pointer
|
|
signal inst_addr_latch_2, inst_addr_latch_2_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- General Purpose Long Latch
|
|
signal long_latch, long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
|
|
-- Signal used to pass Sample Status Infos to Instance Memory Process
|
|
signal status_info_update : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
|
|
-- 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);
|
|
-- Signal used to pass Instance Pointers to the Instance Memory Process
|
|
signal inst_addr_update : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Signal used to pass Sample Counts to the Instance Memory Process
|
|
signal sample_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0);
|
|
-- Signal used to pass ACK Counts to the Instance Memory Process
|
|
signal ack_cnt : unsigned(CDR_LONG_WIDTH-1 downto 0);
|
|
-- Signals start of Instance Memory Operation
|
|
signal inst_op_start : std_logic;
|
|
-- Opcode of Instance Memory Operation (Valid only when inst_op_start is high)
|
|
signal inst_opcode : INSTANCE_OPCODE_TYPE;
|
|
-- Signals the end of an Instance Memory Operation
|
|
signal inst_op_done : std_logic;
|
|
-- Time of next Sample Lifespan Check
|
|
signal lifespan_time, lifespan_time_next : TIME_TYPE;
|
|
-- Signifies if a Lifespan Check is in progress
|
|
signal is_lifespan_check, is_lifespan_check_next : std_logic;
|
|
-- Signal used to generate the monotonically rising Sequence Numbers
|
|
-- It contains the next applicable Sequence Number
|
|
signal global_seq_nr, global_seq_nr_next : SEQUENCENUMBER_TYPE;
|
|
-- 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);
|
|
-- 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);
|
|
-- 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));
|
|
-- Signifies if a Instance Register Operation is in progress
|
|
signal register_op, register_op_next : std_logic;
|
|
-- Signifies if a Instance Lookup Operation is in progress
|
|
signal lookup_op, lookup_op_next : std_logic;
|
|
-- Signifies if a WAIT_FOR_ACKNOWLEDGEMENT Operation is in progress
|
|
signal ack_wait, ack_wait_next : std_logic;
|
|
-- Timout time for DDS Operation
|
|
signal timeout_time, timeout_time_next : TIME_TYPE;
|
|
-- Signal used to differentiate between ACK and NACK Operations
|
|
signal is_ack, is_ack_next : std_logic;
|
|
-- Signal used to differentiate between RTPS and DDS Operations
|
|
signal is_rtps, is_rtps_next : std_logic;
|
|
-- Signifies if new Samples are available for RTPS Writer
|
|
signal data_available_sig, data_available_sig_next : std_logic;
|
|
-- Denotes if Orphan Samples (of an removed stale instance) need to be removed
|
|
signal orphan_samples, orphan_samples_next : std_logic;
|
|
-- Test signal used for testbench synchronisation
|
|
signal idle_sig : std_logic;
|
|
|
|
|
|
-- *COMMUNICATION STATUS*
|
|
signal status_sig, status_sig_next : std_logic_vector(STATUS_KIND_WIDTH-1 downto 0);
|
|
-- LIVELINESS LOST STATUS
|
|
-- Time of next Liveliness Deadline
|
|
signal lease_deadline, lease_deadline_next : TIME_TYPE;
|
|
signal liveliness_lost_cnt, liveliness_lost_cnt_next : unsigned(LIVELINESS_LOST_STATUS_COUNT_WIDTH-1 downto 0);
|
|
signal liveliness_lost_cnt_change, liveliness_lost_cnt_change_next : unsigned(LIVELINESS_LOST_STATUS_COUNT_WIDTH-1 downto 0);
|
|
-- SAMPLE REJECT STATUS
|
|
signal sample_rej_cnt, sample_rej_cnt_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0);
|
|
signal sample_rej_cnt_change, sample_rej_cnt_change_next : unsigned(SAMPLE_REJECTED_STATUS_COUNT_WIDTH-1 downto 0);
|
|
signal sample_rej_last_reason, sample_rej_last_reason_next : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);
|
|
signal sample_rej_last_inst, sample_rej_last_inst_next : INSTANCE_HANDLE_TYPE;
|
|
-- OFFERED DEADLINE MISSED STATUS
|
|
-- Time of next Deadline Miss Check
|
|
signal deadline_time, deadline_time_next : TIME_TYPE;
|
|
signal deadline_miss_cnt, deadline_miss_cnt_next : unsigned(REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH-1 downto 0);
|
|
signal deadline_miss_cnt_change, deadline_miss_cnt_change_next : unsigned(REQUESTED_DEADLINE_MISSED_STATUS_COUNT_WIDTH-1 downto 0);
|
|
signal deadline_miss_last_inst, deadline_miss_last_inst_next : INSTANCE_HANDLE_TYPE;
|
|
|
|
-- *CACHE CHANGE*
|
|
signal cc_instance_handle_sig, cc_instance_handle_sig_next : INSTANCE_HANDLE_TYPE;
|
|
signal cc_kind_sig, cc_kind_sig_next : CACHE_CHANGE_KIND_TYPE;
|
|
signal cc_source_timestamp_sig, cc_source_timestamp_sig_next : TIME_TYPE;
|
|
signal cc_seq_nr_sig, cc_seq_nr_sig_next : SEQUENCENUMBER_TYPE;
|
|
|
|
-- *INSTANCE MEMORY PROCESS*
|
|
-- Instance Memory FSM state
|
|
signal inst_stage, inst_stage_next : INST_STAGE_TYPE;
|
|
-- Pointer to current relevant Instance Memory Frame Address
|
|
signal inst_addr_base, inst_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- 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);
|
|
-- Pointer to previous Instacne Memory Address
|
|
signal inst_prev_addr_base, inst_prev_addr_base_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Head of Empty Instance List
|
|
signal inst_empty_head, inst_empty_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Head of Occupied Instance List
|
|
signal inst_occupied_head, inst_occupied_head_next : unsigned(INSTANCE_MEMORY_ADDR_WIDTH-1 downto 0);
|
|
-- Latch for Instance Data from main process
|
|
signal inst_latch_data, inst_latch_data_next : INST_LATCH_DATA_TYPE;
|
|
-- 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;
|
|
-- General Purpose Counter
|
|
signal inst_cnt, inst_cnt_next : natural range 0 to 13;
|
|
-- General Purpose Long Latch
|
|
signal inst_long_latch, inst_long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0);
|
|
-- 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);
|
|
|
|
--*****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*****
|
|
|
|
key_holder_inst : key_holder
|
|
port map (
|
|
-- SYSTEM
|
|
clk => clk,
|
|
reset => reset,
|
|
-- CONTROL
|
|
start => start_kh,
|
|
opcode => opcode_kh,
|
|
ack => ack_kh,
|
|
decode_error => open,
|
|
abort => abort_kh,
|
|
-- INPUT
|
|
ready_in => ready_out_kh,
|
|
valid_in => valid_out_kh,
|
|
data_in => data_out_kh,
|
|
last_word_in => last_word_out_kh,
|
|
-- OUTPUT
|
|
ready_out => ready_in_kh,
|
|
valid_out => valid_in_kh,
|
|
data_out => data_in_kh,
|
|
last_word_out => last_word_in_kh
|
|
);
|
|
|
|
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;
|
|
variable tmp_bool : boolean;
|
|
begin
|
|
-- DEFAULT Registered
|
|
stage_next <= stage;
|
|
oldest_sample_next <= oldest_sample;
|
|
newest_sample_next <= newest_sample;
|
|
empty_payload_list_head_next <= empty_payload_list_head;
|
|
empty_sample_list_head_next <= empty_sample_list_head;
|
|
empty_sample_list_tail_next <= empty_sample_list_tail;
|
|
payload_addr_latch_1_next <= payload_addr_latch_1;
|
|
payload_addr_latch_2_next <= payload_addr_latch_2;
|
|
long_latch_next <= long_latch;
|
|
sample_addr_latch_1_next <= sample_addr_latch_1;
|
|
sample_addr_latch_2_next <= sample_addr_latch_2;
|
|
sample_addr_latch_3_next <= sample_addr_latch_3;
|
|
sample_addr_latch_4_next <= sample_addr_latch_4;
|
|
inst_addr_latch_1_next <= inst_addr_latch_1;
|
|
inst_addr_latch_2_next <= inst_addr_latch_2;
|
|
sample_status_info_next <= sample_status_info;
|
|
remove_oldest_sample_next <= remove_oldest_sample;
|
|
remove_oldest_inst_sample_next <= remove_oldest_inst_sample;
|
|
remove_ack_sample_next <= remove_ack_sample;
|
|
instance_handle_next <= instance_handle;
|
|
sample_rej_cnt_next <= sample_rej_cnt;
|
|
sample_rej_cnt_change_next <= sample_rej_cnt_change;
|
|
sample_rej_last_reason_next <= sample_rej_last_reason;
|
|
sample_rej_last_inst_next <= sample_rej_last_inst;
|
|
deadline_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');
|
|
status_info_update <= (others => '0');
|
|
inst_mem_fields <= (others => '0');
|
|
sample_cnt <= (others => '0');
|
|
ack_cnt <= (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 <= KEY_HASH_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 <= KEY_HASH_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 <= KEY_HASH_NIL;
|
|
stage_next <= SKIP;
|
|
return_stage_next <= PUSH_KEY_HASH;
|
|
end if;
|
|
when WAIT_FOR_ACKNOWLEDGEMENTS =>
|
|
-- NOTE: In case of BEST_EFFORT the RTPS Writer still manually ACKs the Samples, so we do not handle this case differently here.
|
|
ack_dds <= '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;
|
|
if (source_ts /= TIME_INVALID) then
|
|
sample_write_data <= std_logic_vector(source_ts(0));
|
|
else
|
|
sample_write_data <= std_logic_vector(time(0));
|
|
end if;
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
cnt_next <= cnt + 1;
|
|
end if;
|
|
-- Timestamp 2/2
|
|
when 4 =>
|
|
sample_valid_in <= '1';
|
|
sample_addr <= cur_sample + SMF_TIMESTAMP_OFFSET + 1;
|
|
if (source_ts /= TIME_INVALID) then
|
|
sample_write_data <= std_logic_vector(source_ts(1));
|
|
else
|
|
sample_write_data <= std_logic_vector(time(1));
|
|
end if;
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
-- 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 <= KEY_HASH_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 <= KEY_HASH_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 (not WITH_KEY or 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';
|
|
if (inst_data.ack_cnt /= 0) then
|
|
remove_ack_sample_next <= '1';
|
|
else
|
|
remove_ack_sample_next <= '0';
|
|
end if;
|
|
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';
|
|
if (global_ack_cnt /= 0) then
|
|
remove_ack_sample_next <= '1';
|
|
else
|
|
remove_ack_sample_next <= '0';
|
|
end if;
|
|
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';
|
|
if (global_ack_cnt /= 0) then
|
|
remove_ack_sample_next <= '1';
|
|
else
|
|
remove_ack_sample_next <= '0';
|
|
end if;
|
|
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';
|
|
if (global_ack_cnt /= 0) then
|
|
remove_ack_sample_next <= '1';
|
|
else
|
|
remove_ack_sample_next <= '0';
|
|
end if;
|
|
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 (not WITH_KEY or 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 (not WITH_KEY or 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;
|
|
if (is_ack = '1') then
|
|
sample_write_data(SSI_ACK_FLAG) <= '1';
|
|
else
|
|
sample_write_data(SSI_ACK_FLAG) <= '0';
|
|
end if;
|
|
-- Memory Flow Control Guard
|
|
if (sample_ready_in = '1') then
|
|
if (is_ack = '1') then
|
|
global_ack_cnt_next <= global_ack_cnt + 1;
|
|
else
|
|
global_ack_cnt_next <= global_ack_cnt - 1;
|
|
end if;
|
|
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;
|
|
if (is_ack = '1') then
|
|
ack_cnt <= inst_data.ack_cnt + 1;
|
|
else
|
|
ack_cnt <= inst_data.ack_cnt - 1;
|
|
end if;
|
|
|
|
-- Update Stale Instance Count
|
|
-- XXX: Possible Worst Case Path (Addition and Comparison in same clock)
|
|
if (is_ack = '1' and inst_data.status_info(ISI_UNREGISTERED_FLAG) = '1' and (inst_data.ack_cnt+1) = inst_data.sample_cnt) then
|
|
stale_inst_cnt_next <= 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
|
|
if (is_ack = '1') then
|
|
inst_data_next2.ack_cnt <= inst_data.ack_cnt + 1;
|
|
else
|
|
inst_data_next2.ack_cnt <= inst_data.ack_cnt - 1;
|
|
end if;
|
|
|
|
-- 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 <= KEY_HASH_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;
|
|
if (WITH_KEY) then
|
|
inst_data <= inst_data_next;
|
|
else
|
|
inst_data <= inst_data_next2;
|
|
end if;
|
|
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;
|
|
if (WITH_KEY) then
|
|
current_imf <= current_imf_next;
|
|
else
|
|
current_imf <= (others => '1');
|
|
end if;
|
|
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; |