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