rtps-fpga/src/rtps_reader.vhd
Greek 4b81cf9484 Propagate LIFESPAN through ENDPOINT_MATCH_FRAME instead of inline QoS
Since we disabled the 'expectsInlineQoS' Flag due to Cyclone DDS
compatibility, we no longer have access to the lifespan of the remote
writers.
The Endpoint Match Format was changed to also send the Lifespan Duration
from the rtps_builtin_endpoint.
2021-12-23 16:20:18 +01:00

3203 lines
178 KiB
VHDL

-- altera vhdl_input_version vhdl_2008
-- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.math_pkg.all;
use work.rtps_package.all;
use work.user_config.all;
use work.rtps_config_package.all;
-- TODO: Adding LIFESPAN Duration in the stored Endpoint Metatraffic Data would allow us to not expect in-line QoS (Which could be a significant overhead)
entity rtps_reader is
generic (
-- XXX: Quartus Limitation [VHDL error at <location>: generic "<name>" cannot be used in its own interface list (ID: 10556)]
--ID : ID_TYPE := 0;
ENTITYID : std_logic_vector(ENTITYID_WIDTH-1 downto 0);-- := ENTITYID(ID);
RELIABILITY_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);-- := ENDPOINT_RELIABILITY_QOS(ID);
LIVELINESS_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);-- := ENDPOINT_LIVELINESS_QOS(ID);
DURABILITY_QOS : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0);-- := ENDPOINT_DURABILITY_QOS(ID);
HEARTBEAT_RESPONSE_DELAY : DURATION_TYPE;-- := ENDPOINT_HEARTBEAT_RESPONSE_DELAY(ID);
HEARTBEAT_SUPPRESSION_DELAY : DURATION_TYPE;-- := ENDPOINT_HEARTBEAT_SUPPRESSION_DELAY(ID);
LEASE_DURATION : DURATION_TYPE;-- := ENDPOINT_LEASE_DURATION(ID);
WITH_KEY : boolean;-- := ENDPOINT_WITH_KEY(ID);
MAX_REMOTE_ENDPOINTS : natural := 50
);
port (
-- SYSTEM
clk : in std_logic;
reset : in std_logic;
time : in TIME_TYPE;
-- FROM RTPS HANDLER (USER TRAFFIC)
empty_user : in std_logic;
rd_user : out std_logic;
data_in_user : in std_logic_vector(WORD_WIDTH-1 downto 0);
last_word_in_user : in std_logic;
-- FROM RTPS BUILTIN ENDPOINT (META TRAFFIC)
empty_meta : in std_logic;
rd_meta : out std_logic;
data_in_meta : in std_logic_vector(WORD_WIDTH-1 downto 0);
last_word_in_meta : in std_logic;
-- RTPS OUTPUT
full_ro : in std_logic;
wr_ro : out std_logic;
data_out_ro : out std_logic_vector(WORD_WIDTH-1 downto 0);
last_word_out_ro : out std_logic;
-- TO HISTORY CACHE
start_hc : out std_logic;
opcode_hc : out HISTORY_CACHE_OPCODE_TYPE;
ack_hc : in std_logic;
done_hc : in std_logic;
ret_hc : in HISTORY_CACHE_RESPONSE_TYPE;
valid_out_hc : out std_logic;
ready_out_hc : in std_logic;
data_out_hc : out std_logic_vector(WORD_WIDTH-1 downto 0);
last_word_out_hc : out std_logic
);
end entity;
architecture arch of rtps_reader is
--*****CONSTANT DECLARATION*****
-- *ENDPOINT MEMORY*
-- 4-Byte Word Size of a Remote Endpoint Entry in Memory
function gen_frame_size(qos : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0)) return natural is
variable ret : natural := 0;
begin
if (qos = RELIABLE_RELIABILITY_QOS) then
ret := 14;
else
ret := 10;
end if;
return ret;
end function;
constant ENDPOINT_FRAME_SIZE : natural := gen_frame_size(RELIABILITY_QOS);
-- Endpoint Memory Size in 4-Byte Words
constant ENDPOINT_MEMORY_SIZE : natural := MAX_REMOTE_ENDPOINTS * ENDPOINT_FRAME_SIZE;
-- Endpoint Memory Address Width
constant ENDPOINT_MEMORY_ADDR_WIDTH : natural := log2c(ENDPOINT_MEMORY_SIZE);
-- Highest Endpoint Memory Address
constant ENDPOINT_MEMORY_MAX_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(ENDPOINT_MEMORY_SIZE-1, ENDPOINT_MEMORY_ADDR_WIDTH);
-- Highest Endpoint Frame Address
constant MAX_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := ENDPOINT_MEMORY_MAX_ADDRESS - ENDPOINT_FRAME_SIZE + 1;
-- Address pointing to the beginning of the first Endpoint Data Frame
constant FIRST_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0');
-- *ENDPOINT MEMORY FRAME FIELD FLAGS*
-- Flags mapping to the respective Endpoint Memory Frame Fields
constant EMF_FLAG_WIDTH : natural := 8;
constant EMF_ENTITYID_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (0 => '1', others => '0');
constant EMF_GUIDPREFIX_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (1 => '1', others => '0');
constant EMF_IPV4_ADDR_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (2 => '1', others => '0');
constant EMF_UDP_PORT_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (3 => '1', others => '0');
constant EMF_NEXT_SEQ_NR_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (4 => '1', others => '0');
constant EMF_LEASE_DEADLINE_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (5 => '1', others => '0');
constant EMF_LIFESPAN_DURATION_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (6 => '1', others => '0');
constant EMF_RES_TIME_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (7 => '1', others => '0');
-- *ENDPOINT MEMORY FRAME FIELD OFFSETS*
-- 4-Byte Word Offsets to Beginning of Respective Fields in the Endpoint Memory Frame
constant EMF_ENTITYID_OFFSET : natural := 0;
constant EMF_GUIDPREFIX_OFFSET : natural := 1;
constant EMF_IPV4_ADDR_OFFSET : natural := 4;
constant EMF_UDP_PORT_OFFSET : natural := 5;
function gen_emf_next_seq_nr_offset(qos : std_logic_vector(CDR_ENUMERATION_WIDTH-1 downto 0)) return natural is
variable ret : natural := 0;
begin
if (qos = RELIABLE_RELIABILITY_QOS) then
ret := EMF_UDP_PORT_OFFSET + 1;
else
ret := EMF_GUIDPREFIX_OFFSET + 3;
end if;
return ret;
end function;
constant EMF_NEXT_SEQ_NR_OFFSET : natural := gen_emf_next_seq_nr_offset(RELIABILITY_QOS);
constant EMF_LEASE_DEADLINE_OFFSET : natural := EMF_NEXT_SEQ_NR_OFFSET + 2;
constant EMF_LIFESPAN_DURATION_OFFSET : natural := EMF_LEASE_DEADLINE_OFFSET + 2;
constant EMF_RES_TIME_OFFSET : natural := EMF_LIFESPAN_DURATION_OFFSET + 2;
--*****TYPE DECLARATION*****
-- FSM states. Explained below in detail
type STAGE_TYPE is (IDLE, LATCH_GUIDPREFIX, LATCH_ENTITYID, INITIATE_ENDPOINT_SEARCH, LATCH_ENDPOINT_DATA, METATRAFFIC_OPERATION, LATCH_SRC_ADDR,
LATCH_EXTRA_DATA, LATCH_HEARTBEAT, PROCESS_HEARTBEAT, LATCH_GAP, PROCESS_GAP, FIND_NEXT_VALID_IN_BITMAP, PROCESS_INLINE_QOS,
LATCH_KEY_HASH, LATCH_STATUS_INFO, INITIATE_ADD_CACHE_CHANGE_REQUEST, ADD_CACHE_CHANGE, PUSH_PAYLOAD, FINALIZE_ADD_CACHE_CHANGE_REQUEST,
ENDPOINT_STALE_CHECK, SEND_HEADER, SEND_ACKNACK, SKIP_PARAMETER, SKIP_PACKET, SKIP_META_OPERATION);
-- Memory FSM states. Explained below in detail
type MEM_STAGE_TYPE is (IDLE, SEARCH_ENDPOINT, GET_ENDPOINT_DATA, INSERT_ENDPOINT, UPDATE_ENDPOINT, REMOVE_ENDPOINT, FIND_EMPTY_SLOT,
RESET_MAX_POINTER, GET_NEXT_ENDPOINT, RESET_MEMORY);
-- *Memory FSM Opcodes*
-- OPCODE DESCRIPTION
-- SEARCH_ENDPOINT Search memory for Endpoint with GUID equal to "guid" signal.
-- Set "mem_addr_base" to base Address of found Endpoint, or ENDPOINT_MEMORY_MAX_ADDRESS if nothing found.
-- "mem_endpoint_data" contains Endpoint Data according to "mem_field_flags".
-- INSERT_ENDPOINT Insert Endpoint to first available empty slot in memory
-- UPDATE_ENDPOINT Update Endpoint pointed by "mem_addr_base" according to "mem_field_flags".
-- REMOVE_ENDPOINT Remove Endpoint pointed by "mem_addr_base"
-- GET_FIRST_ENDPOINT Get Endpoint Data of first Endpoint stored in Memory according to "mem_field_flags".
-- Set "mem_addr_base" to Address of Endpoint, or ENDPOINT_MEMORY_MAX_ADDRESS if no Endpoint in Memory.
-- GET_NEXT_ENDPOINT Get Endpoint Data of next Endpoint (from the Endpoint pointed by "mem_addr_base") according to "mem_field_flags".
-- Set "mem_addr_base" to Address of Endpoint, or ENDPOINT_MEMORY_MAX_ADDRESS if no other Endpoint in Memory.
-- GET_ENDPOINT Get Endpoint Data from Endpoint pointed by "mem_addr_update" according to "mem_field_flags".
-- Already fetched data of the same Endpoint is not modified.
type MEM_OPCODE_TYPE is (NOP, SEARCH_ENDPOINT, INSERT_ENDPOINT, UPDATE_ENDPOINT, REMOVE_ENDPOINT, GET_FIRST_ENDPOINT, GET_NEXT_ENDPOINT,
GET_ENDPOINT);
-- Record of Endpoint Data
type ENDPOINT_DATA_TYPE is record
guid : GUID_TYPE;
addr : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0);
portn : std_logic_vector(UDP_PORT_WIDTH-1 downto 0);
next_seq_nr : SEQUENCENUMBER_TYPE;
lease_deadline : TIME_TYPE;
lifespan : DURATION_TYPE;
res_time : TIME_TYPE;
end record;
-- Zero initialized Endpoint Data
constant ZERO_ENDPOINT_DATA : ENDPOINT_DATA_TYPE := (
guid => GUID_UNKNOWN,
addr => IPv4_ADDRESS_INVALID,
portn => UDP_PORT_INVALID,
next_seq_nr => SEQUENCENUMBER_UNKNOWN,
lease_deadline => TIME_INVALID,
lifespan => DURATION_INFINITE,
res_time => TIME_INVALID
);
-- Endpoint Data Latch used as temporal cache by Memory Process
type ENDPOINT_LATCH_DATA_TYPE is record
guid : GUID_TYPE;
addr : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0);
portn : std_logic_vector(UDP_PORT_WIDTH-1 downto 0);
lease_deadline : TIME_TYPE;
lifespan : DURATION_TYPE;
res_time : TIME_TYPE;
next_seq_nr : SEQUENCENUMBER_TYPE;
field_flag : std_logic_vector(0 to EMF_FLAG_WIDTH-1);
end record;
-- Zero initialized Endpoint Data Latch
constant ZERO_ENDPOINT_LATCH_DATA : ENDPOINT_LATCH_DATA_TYPE := (
guid => GUID_UNKNOWN,
addr => IPv4_ADDRESS_INVALID,
portn => UDP_PORT_INVALID,
lease_deadline => TIME_INVALID,
lifespan => DURATION_INFINITE,
res_time => TIME_INVALID,
next_seq_nr => SEQUENCENUMBER_UNKNOWN,
field_flag => (others => '0')
);
--*****SIGNAL DECLARATION*****
-- *MAIN PROCESS*
-- FSM state
signal stage, stage_next : STAGE_TYPE;
-- FSM state latch. Used to transition dynamically to different states from the same state.
signal return_stage, return_stage_next : STAGE_TYPE;
-- Intermediate input read signal. (Read from output port not allowed)
signal rd_sig : std_logic;
-- Signal used to reset the word counter
signal reset_read_cnt : std_logic;
-- Word (4-Byte) counter (Counts words read from input fifo)
signal read_cnt : unsigned(SUBMESSAGE_LENGTH_WIDTH-3 downto 0);
-- Word aligned End of Parameter
signal parameter_end, parameter_end_next : unsigned(PARAMETER_LENGTH_WIDTH-1 downto 0);
-- General Purpose Counter
signal cnt, cnt_next : natural range 0 to 9;
-- Packet Opcode Latch (RTPS Message ID)
signal opcode, opcode_next : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0);
-- Metatraffic Opcode Latch
signal meta_opcode, meta_opcode_next : std_logic_vector(EMO_WIDTH-1 downto 0);
-- Signifies if the received packet is a metatraffic operation
signal is_meta, is_meta_next : std_logic;
-- Source GUID Latch
signal guid, guid_next : GUID_TYPE;
-- Source IPv4 Address Latch
signal addr, addr_next : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0);
-- UDP Port Latch
signal portn, portn_next : std_logic_vector(UDP_PORT_WIDTH-1 downto 0);
-- RTPS Header Flags Latch
signal flags, flags_next : std_logic_vector(SUBMESSAGE_FLAGS_WIDTH-1 downto 0);
-- Source Timestamp Latch
signal ts, ts_next : TIME_TYPE;
-- Key Hash Latch
signal key_hash, key_hash_next : KEY_HASH_TYPE;
-- Signifies if a Key Hash was received
signal key_hash_rcvd, key_hash_rcvd_next : std_logic;
-- Status Info Latch
signal status_info, status_info_next : std_logic_vector(STATUS_INFO_WIDTH-1 downto 0);
-- Lifespan Latch (Contains Lifespan Duration during meta parsing, and Lifespan Deadline during user parsing)
signal lifespan, lifespan_next : TIME_TYPE;
-- RTPS Sequence Number Latch
signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE;
-- Signifies the next expected Sequence Number
signal next_seq_nr, next_seq_nr_next : SEQUENCENUMBER_TYPE;
-- Generic Sequence Number Latch
signal sn_latch_1, sn_latch_1_next : SEQUENCENUMBER_TYPE;
-- Generic Sequence Number Latch
signal sn_latch_2, sn_latch_2_next : SEQUENCENUMBER_TYPE;
-- Generic Sequence Number Latch
signal sn_latch_3, sn_latch_3_next : SEQUENCENUMBER_TYPE;
-- Toggle latching the "last_word_in_user" signal until reset
signal last_word_in_latch, last_word_in_latch_next : std_logic;
-- Time of next Stale Endpoint Check
signal check_time, check_time_next : TIME_TYPE;
-- Signifies if a Stale Endpoint Check is in progress
signal stale_check, stale_check_next : std_logic;
-- Signal containing the RTPS ACKNACK Count Field
signal count, count_next : unsigned(COUNT_WIDTH-1 downto 0);
-- Data in represented in Big Endian
signal data_in_swapped : std_logic_vector(WORD_WIDTH-1 downto 0);
-- Denotes the number of valid Bitmap longs (4-Byte words)
signal bitmap_cnt, bitmap_cnt_next : unsigned(log2c(MAX_BITMAP_WIDTH/CDR_LONG_WIDTH)-1 downto 0);
-- NumberSet Bitmap Latch
signal bitmap_latch, bitmap_latch_next : BITMAP_TYPE;
-- Counter used to read out Bitmaps
signal cnt2, cnt2_next : natural range 0 to BITMAP_TYPE'length;
-- Signal used to iterate through Bitmaps
signal bitmap_pos, bitmap_pos_next : natural range 0 to MAX_BITMAP_WIDTH-1;
-- Signals the start of a Memory Operation
signal mem_op_start : std_logic;
-- Opcode of the Memory Operation (Valid only when mem_op_start is high)
signal mem_opcode : MEM_OPCODE_TYPE;
-- Signals the end of a Memory Operation
signal mem_op_done : std_logic;
-- Signal containing the relevant Endpoint Memory Format Fields of the Memory Operation
signal mem_field_flags : std_logic_vector(0 to EMF_FLAG_WIDTH-1);
-- Signal used to pass Lease Deadlines from main to memory process
signal lease_deadline : TIME_TYPE;
-- Signal used to pass Response Deadlines from main to memory process
signal res_time : TIME_TYPE;
-- Test signal used for testbench synchronisation
signal idle_sig : std_logic;
-- Signal used to pass Endpoint Pointers to the Endpoint Memory Process
signal mem_addr_update : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0);
-- *MEMORY PROCESS*
-- Memory FSM state
signal mem_stage, mem_stage_next : MEM_STAGE_TYPE;
-- Pointer to current relevant Endpoint Address
signal mem_addr_base, mem_addr_base_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0);
-- Help signal used to reset the MAX Endpoint Memory Pointer
signal last_addr, last_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0);
-- General Memory Address Latch
signal mem_addr_latch, mem_addr_latch_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0);
-- Highest Endpoint Memory Address (Points to first Address of last occupied Endpoint Frame)
signal max_endpoint_addr, max_endpoint_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0);
-- General Purpose Couter
signal mem_cnt, mem_cnt_next : natural range 0 to 27;
-- Latch for Endpoint Data from Memory
signal mem_endpoint_data, mem_endpoint_data_next : ENDPOINT_DATA_TYPE;
-- Latch for Endpoint Data from main process
signal mem_endpoint_latch_data, mem_endpoint_latch_data_next : ENDPOINT_LATCH_DATA_TYPE;
-- Position (In Endpoint Memory Frame Granularity) of current relevant Endpoint
signal mem_pos, mem_pos_next : natural range 0 to MAX_REMOTE_ENDPOINTS-1;
-- Endpoint Memory Flag Array denoting which mem_endpoint_data Fields are up-to-date with the respective fields of the Endpoint (Pointed by mem_addr_base)
signal current_emf, current_emf_next : std_logic_vector(0 to EMF_FLAG_WIDTH-1);
-- *MEMORY CONTROL CONNECTION SIGNALS*
signal mem_addr : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0);
signal mem_read_data, mem_write_data : std_logic_vector(WORD_WIDTH-1 downto 0);
signal mem_ready_in, mem_valid_in : std_logic;
signal mem_ready_out, mem_valid_out : std_logic;
signal mem_read : std_logic;
signal abort_read : std_logic;
--*****ALIAS DECLARATION*****
-- ENDPOINT FRAME HEADER
alias header_opcode : std_logic_vector(7 downto 0) is data_in_user(31 downto 24);
alias header_flags : std_logic_vector(7 downto 0) is data_in_user(23 downto 16);
alias header_udp_port : std_logic_vector(15 downto 0) is data_in_user(15 downto 0);
-- RTPS PARAMETER LIST HEADER
alias parameter_id : std_logic_vector(15 downto 0) is data_in_user(31 downto 16);
alias parameter_length : std_logic_vector(15 downto 0) is data_in_user(15 downto 0);
-- RTPS DATA PAYLOAD HEADER
alias representation_id : std_logic_vector(15 downto 0) is data_in_user(31 downto 16);
alias representation_options : std_logic_vector(15 downto 0) is data_in_user(15 downto 0);
-- RTPS SUBMESSAGE FLAGS
alias endian_flag : std_logic is flags(0);
alias qos_flag : std_logic is flags(1);
alias data_flag : std_logic is flags(2);
alias key_flag : std_logic is flags(3);
alias final_flag : std_logic is flags(1);
alias non_std_flag : std_logic is flags(4);
alias liveliness_flag : std_logic is flags(2);
-- HEARTBEAT
alias first_seq_nr : SEQUENCENUMBER_TYPE is sn_latch_1;
alias first_seq_nr_next : SEQUENCENUMBER_TYPE is sn_latch_1_next;
alias last_seq_nr : SEQUENCENUMBER_TYPE is sn_latch_2;
alias last_seq_nr_next : SEQUENCENUMBER_TYPE is sn_latch_2_next;
-- GAP
alias gap_start : SEQUENCENUMBER_TYPE is sn_latch_1;
alias gap_start_next : SEQUENCENUMBER_TYPE is sn_latch_1_next;
alias gap_list_base : SEQUENCENUMBER_TYPE is sn_latch_2;
alias gap_list_base_next : SEQUENCENUMBER_TYPE is sn_latch_2_next;
alias gap_list_end : SEQUENCENUMBER_TYPE is sn_latch_3;
alias gap_list_end_next : SEQUENCENUMBER_TYPE is sn_latch_3_next;
--*****FUNCTION DECLARATION*****
-- Helper function to convert BITMAP_TYPE to std_logic_vector
function to_slv_bitmap (input : BITMAP_TYPE) return std_logic_vector is
variable ret : std_logic_vector(0 to MAX_BITMAP_WIDTH-1) := (others => '0');
begin
for i in 0 to BITMAP_TYPE'length-1 loop
ret(i*WORD_WIDTH to ((i+1)*WORD_WIDTH)-1) := input(i);
end loop;
return ret;
end function;
begin
--*****COMPONENT INSTANTIATION*****
mem_ctrl_inst : entity work.mem_ctrl(arch)
generic map (
ADDR_WIDTH => ENDPOINT_MEMORY_ADDR_WIDTH,
DATA_WIDTH => WORD_WIDTH,
MEMORY_DEPTH => ENDPOINT_MEMORY_SIZE,
MAX_BURST_LENGTH => ENDPOINT_FRAME_SIZE
)
port map (
clk => clk,
reset => reset or abort_read,
addr => std_logic_vector(mem_addr),
read => mem_read,
ready_in => mem_ready_in,
valid_in => mem_valid_in,
data_in => mem_write_data,
ready_out => mem_ready_out,
valid_out => mem_valid_out,
data_out => mem_read_data
);
-- Big Endian Representation
data_in_swapped <= endian_swap(endian_flag, data_in_user);
rd_user <= rd_sig;
-- *Main State Machine*
-- STATE DESCRIPTION
-- IDLE Idle State. Initiates Stale Endpoint Checks, Metatraffic Packet Processing, and User Packet Processing, in that priority order.
-- LATCH_GUIDPREFIX Store source GUID Prefix
-- LATCH_ENTITYID Store source Entity ID
-- INITIATE_ENDPOINT_SEARCH Initiate Endpoint Search Memory Operation. This state is used to start the Search operation as soon as the required data is available
-- LATCH_ENDPOINT_DATA Store Remote Endpoint Data
-- METATRAFFIC_OPERATION State handling the Metatraffic Operations
-- LATCH_SRC_ADDR Store source IPv4 Address
-- LATCH_EXTRA_DATA Store source Timestamp, and source Sequence Number
-- LATCH_HEARTBEAT Store RTPS HEARTBEAT Sequence Numbers
-- PROCESS_HEARTBEAT Parse RTPS HEARTBEAT Message. Update stored Sequence Number if necessary. Set HEARTBEAT response time accordingly.
-- LATCH_GAP Store RTPS GAP Sequence Numbers
-- PROCESS_GAP Parse RTPS GAP Submsessage. Initiates search for next valid Sequence Number if currently expected Sequence Number is in GAP
-- FIND_NEXT_VALID_IN_BITMAP Iterate through Bitmap and find the next valid Sequence Number.
-- PROCESS_INLINE_QOS Parse in-line Parameter List QoS
-- LATCH_KEY_HASH Store KEY_HASH
-- LATCH_STATUS_INFO Store STATUS_INFO
-- INITIATE_ADD_CACHE_CHANGE_REQUEST Initiate an ADD_CACHE_CHANGE Operation
-- ADD_CACHE_CHANGE Send CACHE_CHANGE Data
-- PUSH_PAYLOAD Send CACHE_CHANGE Data (Direct Input Passthrough)
-- FINALIZE_ADD_CACHE_CHANGE_REQUEST Wait for ADD_CACHE_CHANGE Operation Results. Update Endpoint Data if successfull.
-- ENDPOINT_STALE_CHECK Check remote Endpoint Entries for Liveliness Lease Expiration, and Response Timeouts.
-- SEND_HEADER Send Output Data Header and RTPS Message Header
-- SEND_ACKNACK Send ACKNACK Submessage
-- SKIP_PARAMETER Skip rest of Parameter
-- SKIP_PACKET Skip rest of Packet
-- SKIP_META_OPERATION Skip Metatraffic Operation
parse_prc : process(all)
variable tmp_dw : DOUBLE_WORD_ARRAY;
-- NOTE: We convert the bitamp to a slv to make operations easier (The tool should handle both cases equally)
variable tmp_bitmap : std_logic_vector(0 to MAX_BITMAP_WIDTH-1);
variable rd_guard : std_logic;
variable tmp_flags : std_logic_vector(0 to EMF_FLAG_WIDTH-1);
begin
-- DEFAULT Registered
stage_next <= stage;
meta_opcode_next <= meta_opcode;
cnt_next <= cnt;
cnt2_next <= cnt2;
guid_next <= guid;
addr_next <= addr;
portn_next <= portn;
is_meta_next <= is_meta;
opcode_next <= opcode;
flags_next <= flags;
seq_nr_next <= seq_nr;
ts_next <= ts;
sn_latch_1_next <= sn_latch_1;
sn_latch_2_next <= sn_latch_2;
sn_latch_3_next <= sn_latch_3;
bitmap_latch_next <= bitmap_latch;
bitmap_cnt_next <= bitmap_cnt;
bitmap_pos_next <= bitmap_pos;
key_hash_rcvd_next <= key_hash_rcvd;
key_hash_next <= key_hash;
status_info_next <= status_info;
last_word_in_latch_next <= last_word_in_latch;
stale_check_next <= stale_check;
count_next <= count;
return_stage_next <= return_stage;
check_time_next <= check_time;
lifespan_next <= lifespan;
parameter_end_next <= parameter_end;
next_seq_nr_next <= next_seq_nr;
-- DEFAULT Unregistered
mem_opcode <= NOP;
opcode_hc <= NOP;
lease_deadline <= TIME_INVALID;
res_time <= TIME_INVALID;
reset_read_cnt <= '0';
rd_meta <= '0';
mem_op_start <= '0';
start_hc <= '0';
valid_out_hc <= '0';
last_word_out_hc <= '0';
wr_ro <= '0';
last_word_out_ro <= '0';
idle_sig <= '0';
rd_guard := '0';
mem_field_flags <= (others => '0');
data_out_hc <= (others => '0');
data_out_ro <= (others => '0');
mem_addr_update <= (others => '0');
-- Last Word Latch Setter
if (last_word_in_user = '1') then
last_word_in_latch_next <= '1';
end if;
case (stage) is
when IDLE =>
idle_sig <= '1';
-- RESET
lifespan_next <= TIME_INVALID;
addr_next <= (others => '0');
portn_next <= (others => '0');
status_info_next <= (others => '0');
key_hash_rcvd_next <= '0';
is_meta_next <= '0';
-- Stale Check Timeout
if (time >= check_time) then
-- Memory Operation Guard
if (mem_op_done = '1') then
stale_check_next <= '1';
stage_next <= ENDPOINT_STALE_CHECK;
cnt_next <= 1;
mem_op_start <= '1';
mem_opcode <= GET_FIRST_ENDPOINT;
mem_field_flags <= EMF_LEASE_DEADLINE_FLAG or EMF_RES_TIME_FLAG;
-- Reset Timeout
check_time_next <= TIME_INFINITE;
end if;
-- Input FIFO Guard
elsif (empty_meta = '0') then
rd_meta <= '1';
-- Mark as METATRAFFIC
is_meta_next <= '1';
-- Latch Endpoint Metatraffic Opcode
meta_opcode_next <= data_in_meta;
case (data_in_meta) is
when EMO_ENDPOINT_MATCH =>
stage_next <= LATCH_GUIDPREFIX;
cnt_next <= 0;
when EMO_ENDPOINT_UNMATCH =>
stage_next <= LATCH_GUIDPREFIX;
cnt_next <= 0;
when EMO_PARTICIPANT_UNMATCH =>
stage_next <= LATCH_GUIDPREFIX;
cnt_next <= 0;
when EMO_LIVELINESS_UPDATE =>
-- Synthesis Guard
if (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then
stage_next <= LATCH_GUIDPREFIX;
cnt_next <= 0;
else
stage_next <= SKIP_META_OPERATION;
end if;
when others =>
stage_next <= SKIP_META_OPERATION;
end case;
-- Input FIFO Guard
elsif (empty_user = '0') then
rd_guard := '1';
-- Latch Opcode
opcode_next <= header_opcode;
-- Latch Flags
flags_next <= header_flags;
-- Latch Source UDP Port
portn_next <= header_udp_port;
stage_next <= LATCH_SRC_ADDR;
-- SANITY CHECK: Skip Packet if non-standard Payload
if(header_opcode = SID_DATA and header_flags(SUBMESSAGE_NON_STANDARD_PAYLOAD_FLAG_POS) = '1') then
stage_next <= SKIP_PACKET;
end if;
end if;
when LATCH_GUIDPREFIX =>
-- Input FIFO Guard
if ((is_meta = '1' and empty_meta = '0') or (is_meta = '0' and empty_user = '0')) then
if (is_meta = '1') then
rd_meta <= '1';
else
rd_guard := '1';
end if;
case (cnt) is
-- GUID Prefix 1/3
when 0 =>
if (is_meta = '1') then
guid_next(0) <= data_in_meta;
else
guid_next(0) <= data_in_user;
end if;
cnt_next <= cnt + 1;
-- GUID Prefix 2/3
when 1 =>
if (is_meta = '1') then
guid_next(1) <= data_in_meta;
else
guid_next(1) <= data_in_user;
end if;
cnt_next <= cnt + 1;
-- GUID Prefix 3/3
when 2 =>
if (is_meta = '1') then
guid_next(2) <= data_in_meta;
else
guid_next(2) <= data_in_user;
end if;
if (is_meta = '1' and (meta_opcode = EMO_PARTICIPANT_UNMATCH or (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS and meta_opcode = EMO_LIVELINESS_UPDATE))) then
--assert (last_word_in_meta = '1') report "last_word_in_meta not set" severity FAILURE;
-- DONE Parsing
stage_next <= INITIATE_ENDPOINT_SEARCH;
else
stage_next <= LATCH_ENTITYID;
end if;
when others =>
null;
end case;
end if;
when LATCH_ENTITYID =>
-- Input FIFO Guard
if ((is_meta = '1' and empty_meta = '0') or (is_meta = '0' and empty_user = '0')) then
if (is_meta = '1') then
--assert (meta_opcode /= EMO_ENDPOINT_UNMATCH or (meta_opcode = EMO_ENDPOINT_UNMATCH and last_word_in_meta = '1')) report "last_word_in_meta not set" severity FAILURE;
rd_meta <= '1';
guid_next(3) <= data_in_meta;
-- Memory Operation Guard
else
rd_guard := '1';
guid_next(3) <= data_in_user;
end if;
stage_next <= INITIATE_ENDPOINT_SEARCH;
end if;
when INITIATE_ENDPOINT_SEARCH =>
-- Memory Operation Guard
if (mem_op_done = '1') then
if (is_meta = '1') then
case (meta_opcode) is
when EMO_ENDPOINT_MATCH =>
mem_op_start <= '1';
mem_opcode <= SEARCH_ENDPOINT;
mem_field_flags <= (others => '0');
stage_next <= LATCH_ENDPOINT_DATA;
cnt_next <= 0;
when EMO_ENDPOINT_UNMATCH =>
mem_op_start <= '1';
mem_opcode <= SEARCH_ENDPOINT;
mem_field_flags <= (others => '0');
stage_next <= METATRAFFIC_OPERATION;
when EMO_PARTICIPANT_UNMATCH =>
mem_op_start <= '1';
mem_opcode <= GET_FIRST_ENDPOINT;
mem_field_flags <= EMF_GUIDPREFIX_FLAG;
stage_next <= METATRAFFIC_OPERATION;
cnt_next <= 0;
when EMO_LIVELINESS_UPDATE =>
-- Synthesis Guard
if (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then
mem_op_start <= '1';
mem_opcode <= GET_FIRST_ENDPOINT;
mem_field_flags <= EMF_GUIDPREFIX_FLAG;
stage_next <= METATRAFFIC_OPERATION;
cnt_next <= 0;
end if;
when others =>
null;
end case;
else
mem_op_start <= '1';
mem_opcode <= SEARCH_ENDPOINT;
case (opcode) is
when SID_DATA =>
stage_next <= LATCH_EXTRA_DATA;
mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG or EMF_LIFESPAN_DURATION_FLAG;
cnt_next <= 0;
when SID_HEARTBEAT =>
stage_next <= LATCH_HEARTBEAT;
mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG or EMF_RES_TIME_FLAG;
cnt_next <= 0;
when SID_GAP =>
stage_next <= LATCH_GAP;
mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG;
cnt_next <= 0;
when others =>
stage_next <= SKIP_PACKET;
end case;
end if;
end if;
when LATCH_ENDPOINT_DATA =>
-- Input FIFO Guard
if (empty_meta = '0') then
rd_meta <= '1';
case (cnt) is
-- IPv4 Address
when 0 =>
addr_next <= data_in_meta;
cnt_next <= cnt + 1;
-- UDP Port
when 1 =>
--assert (last_word_in_meta = '1') report "last_word_in_meta not set" severity FAILURE;
-- NOTE: Reader Flags are ignored, since they are only relevant for Writer Endpoints
portn_next <= data_in_meta(WORD_WIDTH-1 downto WORD_WIDTH-UDP_PORT_WIDTH);
cnt_next <= cnt + 1;
-- Lifespan Duration 1/2
when 2 =>
lifespan_next(0) <= unsigned(data_in_meta);
cnt_next <= cnt + 1;
-- Lifespan Duration 2/2
when 3 =>
lifespan_next(1) <= unsigned(data_in_meta);
stage_next <= METATRAFFIC_OPERATION;
when others =>
null;
end case;
end if;
when METATRAFFIC_OPERATION =>
-- Memory Operation Guard
if (mem_op_done = '1') then
case (meta_opcode) is
when EMO_ENDPOINT_MATCH =>
-- Endpoint already in Memory
if (mem_addr_base /= ENDPOINT_MEMORY_MAX_ADDRESS) then
-- Update the Endpoint Data
-- NOTE: The Lease Duration is NOT updated in case of an update. That is the responsibility of the Liveliness Update
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG or EMF_LIFESPAN_DURATION_FLAG;
else
mem_field_flags <= EMF_LIFESPAN_DURATION_FLAG;
end if;
-- DONE
stage_next <= IDLE;
else
-- Insert Matched Remote Endpoint
mem_op_start <= '1';
mem_opcode <= INSERT_ENDPOINT;
if (LEASE_DURATION /= DURATION_INFINITE) then
lease_deadline <= time + LEASE_DURATION;
-- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock)
-- Update Check Time
if ((time + LEASE_DURATION) < check_time) then
check_time_next <= time + LEASE_DURATION;
end if;
else
lease_deadline <= TIME_INVALID;
end if;
-- DONE
stage_next <= IDLE;
end if;
when EMO_ENDPOINT_UNMATCH =>
-- Endpoint not in Memory
if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then
-- Ignore
stage_next <= IDLE;
else
-- Propagate Removal (Sent Memory Position as ID)
start_hc <= '1';
opcode_hc <= REMOVE_WRITER;
data_out_hc <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH));
-- Wait for Operation Acknowledgement
if (ack_hc = '1') then
-- Remove Unmatched Remote Endpoint
mem_op_start <= '1';
mem_opcode <= REMOVE_ENDPOINT;
-- DONE
stage_next <= IDLE;
end if;
end if;
when EMO_PARTICIPANT_UNMATCH =>
-- Precondition: mem_endpoint_data set (EMF_GUIDPREFIX_FLAG)
case (cnt) is
when 0 =>
assert check_mask(current_emf, EMF_GUIDPREFIX_FLAG) severity FAILURE;
-- Reached End of Endpoints
if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then
-- DONE
stage_next <= IDLE;
else
-- Participant Match
if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then
-- Propagate Removal (Sent Memory Position as ID)
start_hc <= '1';
opcode_hc <= REMOVE_WRITER;
data_out_hc <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH));
-- Wait for Operation Acknowledgement
if (ack_hc = '1') then
-- Remove Unmatched Remote Endpoint
mem_op_start <= '1';
mem_opcode <= REMOVE_ENDPOINT;
cnt_next <= cnt + 1;
end if;
else
cnt_next <= cnt + 1;
end if;
end if;
when 1 =>
-- Continue Search
mem_op_start <= '1';
mem_opcode <= GET_NEXT_ENDPOINT;
mem_field_flags <= EMF_GUIDPREFIX_FLAG;
cnt_next <= 0;
when others =>
null;
end case;
when EMO_LIVELINESS_UPDATE =>
-- Precondition: mem_endpoint_data set (EMF_GUIDPREFIX_FLAG)
-- Synthesis Guard
if (LIVELINESS_QOS /= MANUAL_BY_TOPIC_LIVELINESS_QOS) then
case (cnt) is
when 0 =>
assert check_mask(current_emf, EMF_GUIDPREFIX_FLAG) severity FAILURE;
-- No matches in memory
if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then
-- DONE
stage_next <= IDLE;
else
-- Participant Match
if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then
-- Renew Lease of Remote Endpoint
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
mem_field_flags <= EMF_LEASE_DEADLINE_FLAG;
if (LEASE_DURATION /= DURATION_INFINITE) then
lease_deadline <= time + LEASE_DURATION;
-- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock)
-- Update Check Time
if ((time + LEASE_DURATION) < check_time) then
check_time_next <= time + LEASE_DURATION;
end if;
else
lease_deadline <= TIME_INVALID;
end if;
end if;
cnt_next <= 1;
end if;
when 1 =>
-- Continue Search
mem_op_start <= '1';
mem_opcode <= GET_NEXT_ENDPOINT;
mem_field_flags <= EMF_GUIDPREFIX_FLAG;
cnt_next <= 0;
when others =>
null;
end case;
end if;
when others =>
null;
end case;
end if;
when LATCH_SRC_ADDR =>
-- Input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
-- Latch Source IP Address
addr_next <= data_in_user;
stage_next <= LATCH_GUIDPREFIX;
cnt_next <= 0;
end if;
when LATCH_EXTRA_DATA =>
-- Input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
case (cnt) is
-- Sequence Number 1/2
when 0 =>
seq_nr_next(0) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- Sequence Number 2/2
when 1 =>
seq_nr_next(1) <= unsigned(data_in_user);
-- Store Next Sequence Number
tmp_dw := (0 => seq_nr(0), 1 => unsigned(data_in_user));
next_seq_nr_next <= tmp_dw + 1;
cnt_next <= cnt + 1;
-- Timestamp 1/2
when 2 =>
ts_next(0) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- Timestamp 2/2
when 3 =>
ts_next(1) <= unsigned(data_in_user);
if (qos_flag = '1') then
stage_next <= PROCESS_INLINE_QOS;
else
stage_next <= INITIATE_ADD_CACHE_CHANGE_REQUEST;
end if;
when others =>
null;
end case;
end if;
when LATCH_HEARTBEAT =>
-- Input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
case (cnt) is
-- First Sequence Number 1/2
when 0 =>
first_seq_nr_next(0) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- First Sequence Number 2/2
when 1 =>
first_seq_nr_next(1) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- Last Sequence Number 1/2
when 2 =>
last_seq_nr_next(0) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- Last Sequence Number 2/2
when 3 =>
last_seq_nr_next(1) <= unsigned(data_in_user);
stage_next <= PROCESS_HEARTBEAT;
when others =>
null;
end case;
end if;
when PROCESS_HEARTBEAT =>
-- Precondition: mem_endpoint_data set (EMF_RES_TIME_FLAG, EMF_NEXT_SEQ_NR_FLAG)
-- Wait for Endpoint Search to finish
if (mem_op_done = '1') then
assert check_mask(current_emf, EMF_RES_TIME_FLAG or EMF_NEXT_SEQ_NR_FLAG) severity FAILURE;
-- DEFAULT
stage_next <= SKIP_PACKET;
-- Endpoint in Buffer
if (mem_addr_base /= ENDPOINT_MEMORY_MAX_ADDRESS) then
-- Default
tmp_flags := (others => '0');
tmp_dw := TIME_INFINITE;
-- Liveliness Assertion
if (liveliness_flag = '1') then
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
tmp_flags := tmp_flags or EMF_LEASE_DEADLINE_FLAG;
if (LEASE_DURATION /= DURATION_INFINITE) then
lease_deadline <= time + LEASE_DURATION;
tmp_dw := time + LEASE_DURATION;
else
lease_deadline <= TIME_INVALID;
end if;
end if;
-- No scheduled Heartbeat Response
if (mem_endpoint_data.res_time = TIME_INVALID) then
-- If Reader is Volatile and we have not received anything from the writer yet
if (DURABILITY_QOS = VOLATILE_DURABILITY_QOS and mem_endpoint_data.next_seq_nr = SEQUENCENUMBER_UNKNOWN) then
-- Mark last available SN as next expected (Ignore historical data)
if (first_seq_nr <= last_seq_nr) then
next_seq_nr_next <= last_seq_nr;
else
next_seq_nr_next <= first_seq_nr;
end if;
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
tmp_flags := tmp_flags or EMF_NEXT_SEQ_NR_FLAG or EMF_RES_TIME_FLAG;
-- NOTE: Only response with ACKNACK if SN is available (Or no Final Flag)
if (HEARTBEAT_RESPONSE_DELAY /= DURATION_INFINITE and (first_seq_nr <= last_seq_nr or final_flag = '0')) then
res_time <= time + HEARTBEAT_RESPONSE_DELAY;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
res_time(1)(0) <= '0';
if ((time + HEARTBEAT_RESPONSE_DELAY) < tmp_dw) then
tmp_dw := time + HEARTBEAT_RESPONSE_DELAY;
end if;
else
res_time <= TIME_INVALID;
end if;
-- If current Sequence Number obsolete (removed from source history cache)
elsif (first_seq_nr > mem_endpoint_data.next_seq_nr) then
-- Store new expected Sequence Number and set Response Delay
next_seq_nr_next <= first_seq_nr;
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
tmp_flags := tmp_flags or EMF_NEXT_SEQ_NR_FLAG or EMF_RES_TIME_FLAG;
-- NOTE: Only response with ACKNACK if SN is available (Or no Final Flag)
if (HEARTBEAT_RESPONSE_DELAY /= DURATION_INFINITE and (first_seq_nr <= last_seq_nr or final_flag = '0')) then
res_time <= time + HEARTBEAT_RESPONSE_DELAY;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
res_time(1)(0) <= '0';
if ((time + HEARTBEAT_RESPONSE_DELAY) < tmp_dw) then
tmp_dw := time + HEARTBEAT_RESPONSE_DELAY;
end if;
else
res_time <= TIME_INVALID;
end if;
-- If new Sequence Number is available or Writer expects ACKNACK
elsif (last_seq_nr >= mem_endpoint_data.next_seq_nr or final_flag = '0') then
-- Set Response Delay
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
tmp_flags := tmp_flags or EMF_RES_TIME_FLAG;
if (HEARTBEAT_RESPONSE_DELAY /= DURATION_INFINITE) then
res_time <= time + HEARTBEAT_RESPONSE_DELAY;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
res_time(1)(0) <= '0';
if ((time + HEARTBEAT_RESPONSE_DELAY) < tmp_dw) then
tmp_dw := time + HEARTBEAT_RESPONSE_DELAY;
end if;
else
res_time <= TIME_INVALID;
end if;
end if;
-- Currently in Heartbeat Response Delay
elsif (mem_endpoint_data.res_time(1)(0) = '0') then
-- If current Sequence Number obsolete (removed from source history cache)
if (first_seq_nr > mem_endpoint_data.next_seq_nr) then
-- NOTE: Even if first_seq_nr > last_seq_nr, meaning that the writer does not have any stored SNs
-- we don't cancel the response, because it may have been initiated by the Final Flag.
-- Store new expected Sequence Number
next_seq_nr_next <= first_seq_nr;
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
tmp_flags := tmp_flags or EMF_NEXT_SEQ_NR_FLAG;
end if;
end if;
mem_field_flags <= tmp_flags;
-- XXX: Possible Worst Case Path (MULTIPLE 64-bit addition and comparison in same clock)
-- Update Check Time
if (tmp_dw < check_time) then
check_time_next <= tmp_dw;
end if;
end if;
end if;
when LATCH_GAP =>
-- Input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
case (cnt) is
-- GapStart Sequence Number 1/2
when 0 =>
gap_start_next(0) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- GapStart Sequence Number 2/2
when 1 =>
gap_start_next(1) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- GapList.Base 1/2
when 2 =>
gap_list_base_next(0) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- GapList.Base 2/2
when 3 =>
gap_list_base_next(1) <= unsigned(data_in_user);
cnt_next <= cnt + 1;
-- GapList.NumBits
when 4 =>
gap_list_end_next <= gap_list_base + to_integer(unsigned(data_in_user));
bitmap_cnt_next <= unsigned(round_slv(data_in_user(log2c(MAX_BITMAP_WIDTH)-1 downto 0),bitmap_cnt'length));
cnt2_next <= 0;
cnt_next <= cnt + 1;
-- GapList.Bitmap
when 5 =>
-- Read Bitmap
if (cnt2 < bitmap_cnt) then
cnt2_next <= cnt2 + 1;
bitmap_latch_next(cnt2) <= data_in_user;
else
stage_next <= PROCESS_GAP;
end if;
when others =>
null;
end case;
end if;
when PROCESS_GAP =>
-- Precondition: mem_endpoint_data set (EMF_NEXT_SEQ_NR_FLAG)
-- Wait for Endpoint Search
if (mem_op_done = '1') then
assert check_mask(current_emf, EMF_NEXT_SEQ_NR_FLAG) severity FAILURE;
-- DEFAULT
stage_next <= SKIP_PACKET;
-- Known Remote Endpoint
if (mem_addr_base /= ENDPOINT_MEMORY_MAX_ADDRESS) then
-- GAP is relevant
if (gap_start <= mem_endpoint_data.next_seq_nr and mem_endpoint_data.next_seq_nr <= gap_list_end) then
-- Next Expected is in GAP List
if (gap_list_base <= mem_endpoint_data.next_seq_nr) then
-- Begin searching next valid SN from the current expected in the bitmap list
bitmap_pos_next <= to_integer(next_seq_nr - gap_list_base);
else
-- Begin searching next valid SN from the beginning of the bitmap list
next_seq_nr_next <= gap_list_base;
bitmap_pos_next <= 0;
end if;
stage_next <= FIND_NEXT_VALID_IN_BITMAP;
end if;
end if;
end if;
when FIND_NEXT_VALID_IN_BITMAP =>
-- Memory Operation Guard
if (mem_op_done = '1') then
tmp_bitmap := to_slv_bitmap(bitmap_latch);
-- First valid sequence number found
if (tmp_bitmap(bitmap_pos) = '0') then
-- Update next sequence number
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG;
-- DONE
stage_next <= SKIP_PACKET;
else
-- Continue search
bitmap_pos_next <= bitmap_pos + 1;
next_seq_nr_next <= next_seq_nr + 1;
end if;
end if;
when PROCESS_INLINE_QOS =>
-- input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
-- Reset Word Counter
reset_read_cnt <= '1';
-- Latch Parameter End (In order to skip parameters)
parameter_end_next <= unsigned(endian_swap(endian_flag,parameter_length));
-- DEFAULT STAGE
stage_next <= SKIP_PARAMETER;
case (endian_swap(endian_flag,parameter_id)) is
when PID_TOPIC_NAME =>
-- Ignore
null;
when PID_DURABILITY =>
-- Ignore
null;
when PID_PRESENTATION =>
-- Ignore
null;
when PID_DEADLINE =>
-- Ignore
null;
when PID_LATENCY_BUDGET =>
-- Ignore
null;
when PID_OWNERSHIP =>
-- Ignore
null;
when PID_OWNERSHIP_STRENGTH =>
-- Ignore
null;
when PID_LIVELINESS =>
-- Ignore
null;
when PID_PARTITION =>
-- Ignore
null;
when PID_RELIABILITY =>
-- Ignore
null;
when PID_DESTINATION_ORDER =>
-- Ignore
null;
when PID_TRANSPORT_PRIORITY =>
-- Ignore
null;
when PID_LIFESPAN =>
-- Ignore
null;
when PID_CONTENT_FILTER_INFO =>
-- Ignore
null;
when PID_COHERENT_SET =>
-- Ignore
null;
when PID_DIRECTED_WRITE =>
-- Ignore
null;
when PID_ORIGINAL_WRITER_INFO =>
-- Ignore
null;
when PID_GROUP_COHERENT_SET =>
-- Ignore
null;
when PID_GROUP_SEQ_NUM =>
-- Ignore
null;
when PID_WRITER_GROUP_INFO =>
-- Ignore
null;
when PID_SECURE_WRITER_GROUP_INFO =>
-- Ignore
null;
when PID_KEY_HASH =>
key_hash_rcvd_next <= '1';
stage_next <= LATCH_KEY_HASH;
cnt_next <= 0;
when PID_STATUS_INFO =>
stage_next <= LATCH_STATUS_INFO;
when PID_PAD =>
-- Ignore
null;
when PID_SENTINEL =>
-- Reset
parameter_end_next <= (others => '1');
-- QOS DONE
stage_next <= INITIATE_ADD_CACHE_CHANGE_REQUEST;
when others =>
-- If MUST_UNDERSTAND Flag is set, we have incompatible communication. Drop Packet
if (endian_swap(endian_flag,parameter_id)(PID_MUST_UNDERSTAND_FLAG_POS) = '1') then
stage_next <= SKIP_PACKET;
-- Else skip Unknown Parameter
else
stage_next <= SKIP_PARAMETER;
end if;
end case;
end if;
when LATCH_KEY_HASH =>
-- Input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
case (cnt) is
-- Key Hash 1/4
when 0 =>
key_hash_next(0) <= data_in_user;
cnt_next <= cnt + 1;
-- Key Hash 2/4
when 1 =>
key_hash_next(1) <= data_in_user;
cnt_next <= cnt + 1;
-- Key Hash 3/4
when 2 =>
key_hash_next(2) <= data_in_user;
cnt_next <= cnt + 1;
-- Key Hash 4/4
when 3 =>
key_hash_next(3) <= data_in_user;
-- DONE
stage_next <= SKIP_PARAMETER;
when others =>
null;
end case;
end if;
when LATCH_STATUS_INFO =>
-- Input FIFO Guard
if (empty_user = '0') then
rd_guard := '1';
status_info_next <= data_in_user;
-- DONE
stage_next <= SKIP_PARAMETER;
end if;
when INITIATE_ADD_CACHE_CHANGE_REQUEST =>
-- Precondition: mem_endpoint_data set (EMF_NEXT_SEQ_NR_FLAG, EMF_LIFESPAN_DURATION_FLAG)
-- Wait for Endpoint Data
if (mem_op_done = '1') then
assert check_mask(current_emf, EMF_NEXT_SEQ_NR_FLAG or EMF_LIFESPAN_DURATION_FLAG) severity FAILURE;
-- Unknown Endpoint
if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then
-- Ignore
stage_next <= SKIP_PACKET;
else
-- Data is Next expected Sequence Number
if ((RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and seq_nr = mem_endpoint_data.next_seq_nr) or (RELIABILITY_QOS = BEST_EFFORT_RELIABILITY_QOS and seq_nr >= mem_endpoint_data.next_seq_nr) or (DURABILITY_QOS = VOLATILE_DURABILITY_QOS and mem_endpoint_data.next_seq_nr = SEQUENCENUMBER_UNKNOWN)) then
-- SANITY CHECK: Skip if no Hash Key and no Payload
if (WITH_KEY and key_hash_rcvd = '0' and data_flag = '0' and key_flag = '0') then
-- Ignore
stage_next <= SKIP_PACKET;
else
start_hc <= '1';
opcode_hc <= ADD_CACHE_CHANGE;
-- Wait until History Cache acknowledges request
if (ack_hc = '1') then
-- TODO: Use source timestamp if clocks with remote synchronized
-- Calculate Sample Lifespan Deadline
if (mem_endpoint_data.lifespan /= DURATION_INFINITE) then
lifespan_next <= time + mem_endpoint_data.lifespan;
end if;
stage_next <= ADD_CACHE_CHANGE;
cnt_next <= 0;
end if;
end if;
else
-- Ignore
stage_next <= SKIP_PACKET;
end if;
end if;
end if;
when ADD_CACHE_CHANGE =>
case (cnt) is
-- Status Info
when 0 =>
valid_out_hc <= '1';
data_out_hc <= status_info;
if (WITH_KEY) then
data_out_hc(SSI_KEY_HASH_FLAG) <= key_hash_rcvd;
end if;
-- NOTE: The SSI_DATA_FLAG states if the Payload contains normal Data for the Sample or the Serialized Key for the Key Hash calculation
data_out_hc(SSI_DATA_FLAG) <= data_flag;
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Timestamp 1/2
when 1 =>
valid_out_hc <= '1';
data_out_hc <= std_logic_vector(ts(0));
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Timestamp 2/2
when 2 =>
valid_out_hc <= '1';
data_out_hc <= std_logic_vector(ts(1));
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Lifespan Deadline 1/2
when 3 =>
valid_out_hc <= '1';
data_out_hc <= std_logic_vector(lifespan(0));
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Lifespan Deadline 2/2
when 4 =>
valid_out_hc <= '1';
data_out_hc <= std_logic_vector(lifespan(1));
-- Output Guard
if (ready_out_hc = '1') then
-- Skip Key Hash, if not received
if (not WITH_KEY or key_hash_rcvd = '0') then
cnt_next <= cnt + 5;
else
cnt_next <= cnt + 1;
end if;
end if;
-- Key hash 1/4
when 5 =>
valid_out_hc <= '1';
data_out_hc <= key_hash(0);
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Key Hash 2/4
when 6 =>
valid_out_hc <= '1';
data_out_hc <= key_hash(1);
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Key Hash 3/4
when 7 =>
valid_out_hc <= '1';
data_out_hc <= key_hash(2);
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Key hash 4/4
when 8 =>
valid_out_hc <= '1';
data_out_hc <= key_hash(3);
-- Output Guard
if (ready_out_hc = '1') then
cnt_next <= cnt + 1;
end if;
-- Endpoint Memory Position
when 9 =>
-- Wait for Endpoint Search
if (mem_op_done = '1') then
valid_out_hc <= '1';
-- TODO: Assert mem_pos range fits in CDR_LONG
data_out_hc <= std_logic_vector(to_unsigned(mem_pos, CDR_LONG_WIDTH));
-- Output Guard
if (ready_out_hc = '1') then
-- NOTE: We only push the Payload if there is Data, or if the Key Hash was not received and we need to push
-- the serialized Key.
-- Payload exists
if (data_flag = '1' or (WITH_KEY and key_hash_rcvd = '0')) then
stage_next <= PUSH_PAYLOAD;
else
-- DONE
last_word_out_hc <= '1';
stage_next <= FINALIZE_ADD_CACHE_CHANGE_REQUEST;
end if;
end if;
end if;
when others =>
null;
end case;
when PUSH_PAYLOAD =>
-- Input Guard
if (empty_user = '0') then
valid_out_hc <= '1';
-- Push Payload to History Cache
data_out_hc <= data_in_user;
last_word_out_hc <= last_word_in_user;
-- Output Guard
if (ready_out_hc = '1') then
rd_guard := '1';
-- Exit Condition
if (last_word_in_user = '1') then
stage_next <= FINALIZE_ADD_CACHE_CHANGE_REQUEST;
end if;
end if;
end if;
when FINALIZE_ADD_CACHE_CHANGE_REQUEST =>
-- NOTE: Memory is already in done state from previous state (ADD_CACHE_CHANGE)
assert (mem_op_done = '1') report "FINALIZE_ADD_CACHE_CHANGE_REQUEST precondition not met. mem_op_done /= '1'" severity FAILURE;
-- Wait for History Cache Response
if (done_hc = '1') then
-- NOTE: The Lease Duration is also updated if the Cache Change is not accepted. This in effect "skews" the
-- "correctness" of the Writer Liveliness Protocol until the reader has no pending request from the Writer.
-- Update Endpoint
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
mem_field_flags <= EMF_LEASE_DEADLINE_FLAG;
if (LEASE_DURATION /= DURATION_INFINITE) then
lease_deadline <= time + LEASE_DURATION;
-- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock)
-- Update Check Time
if ((time + LEASE_DURATION) < check_time) then
check_time_next <= time + LEASE_DURATION;
end if;
else
lease_deadline <= TIME_INVALID;
end if;
-- NOTE: In case the operation was unsucessfull (e.g. reached Resource Limits), the Sequence Number is not updated
-- and thus not "acknowledged".
-- Operation was Accepted
if (ret_hc = OK) then
-- Update also next sequence number
mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG or EMF_LEASE_DEADLINE_FLAG;
end if;
-- DONE
stage_next <= SKIP_PACKET;
end if;
when ENDPOINT_STALE_CHECK =>
-- Precondition: mem_endpoint_data set (EMF_LEASE_DEADLINE_FLAG, EMF_RES_TIME_FLAG)
-- Memory Operation Guard
if (mem_op_done = '1') then
case (cnt) is
-- Get Next Endpoint
when 0 =>
mem_op_start <= '1';
mem_opcode <= GET_NEXT_ENDPOINT;
mem_field_flags <= EMF_LEASE_DEADLINE_FLAG or EMF_RES_TIME_FLAG;
cnt_next <= cnt + 1;
-- Check Endpoint
when 1 =>
assert check_mask(current_emf, EMF_LEASE_DEADLINE_FLAG or EMF_RES_TIME_FLAG) severity FAILURE;
-- End of Endpoints
if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then
-- Reset
stale_check_next <= '0';
-- DONE
stage_next <= IDLE;
else
-- Endpoint Lease Expired
if (mem_endpoint_data.lease_deadline /= TIME_INVALID and mem_endpoint_data.lease_deadline <= time) then
-- Propagate Removal (Sent Memory Position as ID)
start_hc <= '1';
opcode_hc <= REMOVE_WRITER;
data_out_hc <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH));
-- Wait for Operation Acknowledgement
if (ack_hc = '1') then
-- Remove Endpoint
mem_op_start <= '1';
mem_opcode <= REMOVE_ENDPOINT;
-- Continue Search
cnt_next <= 0;
end if;
-- Synthesis Guard/Response Time Reached
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and mem_endpoint_data.res_time /= TIME_INVALID and mem_endpoint_data.res_time <= time) then
-- If Suppression Delay passed, zero the time
if(mem_endpoint_data.res_time(1)(0) = '1') then
-- Disable Suppression
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
res_time <= TIME_INVALID;
mem_field_flags <= EMF_RES_TIME_FLAG;
-- Continue Search
cnt_next <= 0;
-- If Response Delay Passed
else
-- Get Additional Data
mem_op_start <= '1';
mem_opcode <= GET_ENDPOINT;
mem_field_flags <= EMF_ENTITYID_FLAG or EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG or EMF_NEXT_SEQ_NR_FLAG;
mem_addr_update <= mem_addr_base;
cnt_next <= 2;
end if;
-- Update Check Time
if (mem_endpoint_data.lease_deadline /= TIME_INVALID and mem_endpoint_data.lease_deadline < check_time) then
check_time_next <= mem_endpoint_data.lease_deadline;
end if;
else
-- Update Check Time
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and mem_endpoint_data.res_time /= TIME_INVALID and mem_endpoint_data.lease_deadline /= TIME_INVALID and mem_endpoint_data.res_time < mem_endpoint_data.lease_deadline) then
if (mem_endpoint_data.res_time < check_time) then
check_time_next <= mem_endpoint_data.res_time;
end if;
elsif (mem_endpoint_data.lease_deadline /= TIME_INVALID) then
if (mem_endpoint_data.lease_deadline < check_time) then
check_time_next <= mem_endpoint_data.lease_deadline;
end if;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and mem_endpoint_data.res_time /= TIME_INVALID) then
if (mem_endpoint_data.res_time < check_time) then
check_time_next <= mem_endpoint_data.res_time;
end if;
end if;
-- Continue Search
cnt_next <= 0;
end if;
end if;
when 2 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
-- Set Heartbeat Suppression Time
if (HEARTBEAT_SUPPRESSION_DELAY /= DURATION_INFINITE and HEARTBEAT_SUPPRESSION_DELAY /= DURATION_ZERO) then
-- Set Heartbeat Suppression Time
res_time <= time + HEARTBEAT_SUPPRESSION_DELAY;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
res_time(1)(0) <= '1';
-- XXX: Possible Worst Case Path (64-bit addition and comparison in same clock)
-- Update Check Time
if ((time + HEARTBEAT_SUPPRESSION_DELAY) < check_time) then
-- NOTE: Strictly speaking the check time may not EXACTLY represent the res_time (Since the last bit is ovverriden for a different functionality)
-- Since the difference is at most 1/10^(-32) seconds, this will never practically impose any problem (since the time will most certainly have
-- progressed beyond that difference from the check_time trigger to the actual res_time check).
-- Nevertheless this has to be taken into account in testbenches that use "static" time.
check_time_next <= time + HEARTBEAT_SUPPRESSION_DELAY;
end if;
else
-- Disable Suppression
res_time <= TIME_INVALID;
end if;
mem_op_start <= '1';
mem_opcode <= UPDATE_ENDPOINT;
mem_field_flags <= EMF_RES_TIME_FLAG;
-- Send ACKNACK
-- Increment Acknack Counter
count_next <= count + 1;
stage_next <= SEND_HEADER;
return_stage_next <= SEND_ACKNACK;
cnt_next <= 0;
end if;
when others =>
null;
end case;
end if;
when SEND_HEADER =>
-- Precondition: mem_endpoint_data set (EMF_IPV4_ADDR_FLAG, EMF_UDP_PORT_FLAG)
-- Synthesis Guard / Wait for Endpoint Data
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and mem_op_done = '1') then
assert check_mask(current_emf, EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG) severity FAILURE;
-- Output FIFO Guard
if (full_ro = '0') then
wr_ro <= '1';
case (cnt) is
-- OUTPUT HEADER
-- Src IPv4 Address
when 0 =>
data_out_ro <= DEFAULT_IPv4_ADDRESS;
cnt_next <= cnt + 1;
-- Dest IPv4 Address
when 1 =>
data_out_ro <= mem_endpoint_data.addr;
cnt_next <= cnt + 1;
-- Src and Dest UDPv4 Ports
when 2 =>
data_out_ro <= USER_IPv4_UNICAST_PORT & mem_endpoint_data.portn;
cnt_next <= cnt + 1;
-- RTPS MESSAGE HEADER
when 3 =>
data_out_ro <= PROTOCOL_RTPS;
cnt_next <= cnt + 1;
when 4 =>
data_out_ro <= PROTOCOLVERSION_2_4 & VENDORID;
cnt_next <= cnt + 1;
when 5 =>
data_out_ro <= GUIDPREFIX(0);
cnt_next <= cnt + 1;
when 6 =>
data_out_ro <= GUIDPREFIX(1);
cnt_next <= cnt + 1;
when 7 =>
data_out_ro <= GUIDPREFIX(2);
-- Continue with respective RTPS Submessage
stage_next <= return_stage;
cnt_next <= 0;
when others =>
null;
end case;
end if;
end if;
when SEND_ACKNACK =>
-- Precondition: mem_endpoint_data set (EMF_ENTITYID_FLAG, EMF_NEXT_SEQ_NR_FLAG)
-- Synthesis Guard / Wait for Endpoint Data
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and mem_op_done = '1') then
assert check_mask(current_emf, EMF_ENTITYID_FLAG or EMF_NEXT_SEQ_NR_FLAG) severity FAILURE;
-- Output FIFO Guard
if (full_ro = '0') then
wr_ro <= '1';
case (cnt) is
-- ACKNACK RTPS SUBMESSAGE
-- RTPS Submessage Header
when 0 =>
data_out_ro <= SID_ACKNACK & "00000010" & std_logic_vector(to_unsigned(28, SUBMESSAGE_LENGTH_WIDTH));
cnt_next <= cnt + 1;
-- Reader Entity ID
when 1 =>
data_out_ro <= ENTITYID;
cnt_next <= cnt + 1;
-- Writer Entity ID
when 2 =>
data_out_ro <= mem_endpoint_data.guid(3);
cnt_next <= cnt + 1;
-- Sequence Number Set (Bitmap Base 1/2)
when 3 =>
data_out_ro <= std_logic_vector(mem_endpoint_data.next_seq_nr(0));
cnt_next <= cnt + 1;
-- Sequence Number Set (Bitmap Base 2/2)
when 4 =>
data_out_ro <= std_logic_vector(mem_endpoint_data.next_seq_nr(1));
cnt_next <= cnt + 1;
-- Sequence Number Set (NumBits)
when 5 =>
data_out_ro <= std_logic_vector(to_unsigned(CDR_LONG_WIDTH, CDR_LONG_WIDTH));
cnt_next <= cnt + 1;
-- Sequence Number Set (Bitmap)
when 6 =>
-- NOTE: In order to avoid having to generate a variable sized bitmap, we always request the next 32 sequence numbers, even if they do not exist (yet)
-- XXX: Assumes correct implementation of the RTPS Protocol (i.e. Writer ignores requested SNs that do not exist)
data_out_ro <= (others => '1');
cnt_next <= cnt + 1;
-- Count
when 7 =>
data_out_ro <= std_logic_vector(count);
last_word_out_ro <= '1';
-- Stale Check in Progress
if (stale_check = '1') then
-- Continue Search
stage_next <= ENDPOINT_STALE_CHECK;
cnt_next <= 0;
else
-- DONE
stage_next <= IDLE;
end if;
when others =>
null;
end case;
end if;
end if;
when SKIP_PARAMETER =>
-- Consumed last word of Packet
if (last_word_in_latch = '1' and last_word_in_user = '0') then
-- Reset Last Word In Latch
last_word_in_latch_next <= '0';
-- Continue parsing next Packet
stage_next <= IDLE;
-- Reset Parameter End
parameter_end_next <= (others => '1');
-- End of Parameter
elsif ((read_cnt & "00" ) >= parameter_end) then
-- Parse Next Parameter
-- NOTE: data_in_user is already showing the next parameter
stage_next <= PROCESS_INLINE_QOS;
-- Reset Parameter End
parameter_end_next <= (others => '1');
-- Input FIFO Guard
elsif (empty_user = '0') then
-- Skip-Read
rd_guard := '1';
end if;
when SKIP_PACKET =>
-- NOTE: At the end of a Stale Entry Removal this stage is entered, without having started reading a Packet from input.
-- Reset Parameter End
parameter_end_next <= (others => '1');
-- Consumed last word of Packet
if (last_word_in_latch = '1' and last_word_in_user = '0') then
-- Reset Last Word In Latch
last_word_in_latch_next <= '0';
-- DONE
stage_next <= IDLE;
-- Input FIFO Guard
elsif (empty_user = '0') then
-- Skip-Read
rd_guard := '1';
end if;
when SKIP_META_OPERATION =>
-- Input Guard
if (empty_meta = '0') then
-- Skip-Read
rd_meta <= '1';
-- Exit Condition
if (last_word_in_meta = '1') then
stage_next <= IDLE;
end if;
end if;
when others =>
null;
end case;
-- OVERREAD GUARD
-- Read outside of packet Length
-- NOTE: If the Packet Length is smaller than expected there will be a read from input FIFO while
-- the Packet Length has been reached and will be caught by this clause.
-- The SKIP_PACKET clause prevents a read signal from occuring in this situation, and thus prevents from entering this state.
if ((last_word_in_latch = '1' and last_word_in_user = '0') and rd_guard = '1') then
-- Force rd_sig low
rd_sig <= '0';
-- Continue parsing next Packet
stage_next <= IDLE;
-- Reset Last Word In Latch
last_word_in_latch_next <= '0';
-- Reset Parameter End
parameter_end_next <= (others => '1');
-- Read outside of Parameter Length
-- NOTE: If the Parameter Length is smaller than expected for a particular parameter, there will be a read from input FIFO while
-- the Parameter Length has been reached and will be caught by this clause.
-- The SKIP_PARAMETER clause prevents a read signal from occuring in this situation, and thus prevents from entering this state.
elsif ((read_cnt & "00") >= parameter_end and rd_guard = '1') then
-- Force rd_sig low
rd_sig <= '0';
-- Invalid Parameter Length, Skip Packet
stage_next <= SKIP_PACKET;
-- Reset Parameter End
parameter_end_next <= (others => '1');
-- DEFAULT
else
rd_sig <= rd_guard;
end if;
end process;
-- *Memory State Machine*
-- STATE DESCRIPTION
-- IDLE Idle State. Done Signal is pulled high and Memory FSM accepts new memory operations
-- SEARCH_ENDPOINT See Memory OPCODE Description
-- GET_ENDPOINT_DATA Latch specified Endpoint Data for use by main FSM
-- INSERT_ENDPOINT See Memory OPCODE Description
-- UPDATE_ENDPOINT See Memory OPCODE Description
-- REMOVE_ENDPOINT See Memory OPCODE Description
-- FIND_EMPTY_SLOT Find first empty_user slot in memory.
-- RESET_MAX_POINTER Reset the max_endpoint_addr pointer to last occupied slot in memory.
-- GET_NEXT_ENDPOINT See Memory OPCODE Description
-- RESET_MEMORY Reset Endpoint Memory to Empty State
mem_ctrl_prc : process(all)
begin
-- DEFAULT Registered
mem_stage_next <= mem_stage;
mem_addr_base_next <= mem_addr_base;
mem_cnt_next <= mem_cnt;
last_addr_next <= last_addr;
mem_addr_latch_next <= mem_addr_latch;
mem_endpoint_data_next <= mem_endpoint_data;
max_endpoint_addr_next <= max_endpoint_addr;
mem_endpoint_latch_data_next <= mem_endpoint_latch_data;
mem_pos_next <= mem_pos;
current_emf_next <= current_emf;
-- DEFAULT Unregistered
mem_addr <= (others => '0');
mem_write_data <= (others => '0');
mem_read <= '0';
mem_valid_in <= '0';
mem_ready_out <= '0';
mem_op_done <= '0';
abort_read <= '0';
case (mem_stage) is
when IDLE =>
mem_op_done <= '1';
if (mem_op_start = '1') then
-- Latch Signals needed for Mermory Operation (Use _next signals, because some signals are set in same clk)
mem_endpoint_latch_data_next <= (
guid => guid_next,
addr => addr_next,
portn => portn_next,
lease_deadline => lease_deadline,
lifespan => lifespan_next,
res_time => res_time,
next_seq_nr => next_seq_nr_next,
field_flag => mem_field_flags
);
case(mem_opcode) is
when SEARCH_ENDPOINT =>
current_emf_next <= mem_field_flags;
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS;
mem_pos_next <= 0;
mem_stage_next <= SEARCH_ENDPOINT;
mem_cnt_next <= 0;
when INSERT_ENDPOINT =>
current_emf_next <= (others => '1');
-- Set Endpoint Data
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
mem_endpoint_data_next.guid <= guid_next;
mem_endpoint_data_next.addr <= addr_next;
mem_endpoint_data_next.portn <= portn_next;
if (DURABILITY_QOS = VOLATILE_DURABILITY_QOS) then
mem_endpoint_data_next.next_seq_nr <= SEQUENCENUMBER_UNKNOWN;
else
mem_endpoint_data_next.next_seq_nr <= FIRST_SEQUENCENUMBER;
end if;
mem_endpoint_data_next.lease_deadline <= lease_deadline;
mem_endpoint_data_next.lifespan <= lifespan_next;
mem_endpoint_data_next.res_time <= TIME_INVALID;
mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS;
mem_pos_next <= 0;
mem_stage_next <= FIND_EMPTY_SLOT;
mem_cnt_next <= 0;
when UPDATE_ENDPOINT =>
current_emf_next <= current_emf or mem_field_flags;
mem_stage_next <= UPDATE_ENDPOINT;
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_field_flags,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 0;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_field_flags,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 1;
elsif check_mask(mem_field_flags,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 2;
elsif check_mask(mem_field_flags,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 4;
elsif check_mask(mem_field_flags,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 6;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_field_flags,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 8;
else
-- DONE
mem_stage_next <= IDLE;
end if;
when REMOVE_ENDPOINT =>
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
current_emf_next <= (others => '0');
mem_stage_next <= REMOVE_ENDPOINT;
mem_cnt_next <= 0;
when GET_FIRST_ENDPOINT =>
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
current_emf_next <= mem_field_flags;
mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS;
mem_pos_next <= 0;
mem_stage_next <= GET_NEXT_ENDPOINT;
mem_cnt_next <= 0;
when GET_NEXT_ENDPOINT =>
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
current_emf_next <= mem_field_flags;
-- Memory Bound Guard
if (mem_addr_base >= max_endpoint_addr) then
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS;
else
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_stage_next <= GET_NEXT_ENDPOINT;
mem_cnt_next <= 0;
end if;
when GET_ENDPOINT =>
if (mem_addr_base /= mem_addr_update) then
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
current_emf_next <= mem_field_flags;
else
current_emf_next <= current_emf or mem_field_flags;
end if;
-- Fetch Endpoint Data
mem_stage_next <= GET_ENDPOINT_DATA;
if check_mask(mem_field_flags,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 0;
elsif check_mask(mem_field_flags,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 1;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_field_flags,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 4;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_field_flags,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 5;
elsif check_mask(mem_field_flags,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_field_flags,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_field_flags,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_field_flags,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
-- DONE
mem_stage_next <= IDLE;
end if;
when others =>
null;
end case;
end if;
when SEARCH_ENDPOINT =>
case (mem_cnt) is
-- GET Entity ID
when 0 =>
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_read <= '1';
mem_valid_in <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET GUID Prefix 1/3
when 1 =>
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET;
mem_read <= '1';
mem_valid_in <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET GUID Prefix 2/3
when 2 =>
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 1;
mem_read <= '1';
mem_valid_in <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET GUID Prefix 3/3
when 3 =>
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 2;
mem_read <= '1';
mem_valid_in <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- READ Entity ID
when 4 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
-- No Match
if (mem_read_data /= mem_endpoint_latch_data.guid(3)) then
abort_read <= '1';
-- Reached End of Memory, No Match
if (mem_addr_base = max_endpoint_addr) then
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match
-- DONE
mem_stage_next <= IDLE;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
else
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- READ GUID Prefix 1/3
when 5 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
-- No Match
if (mem_read_data /= mem_endpoint_latch_data.guid(0)) then
abort_read <= '1';
-- Reached End of Memory, No Match
if (mem_addr_base = max_endpoint_addr) then
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match
-- DONE
mem_stage_next <= IDLE;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
else
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- READ GUID Prefix 2/3
when 6 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
-- No Match
if (mem_read_data /= mem_endpoint_latch_data.guid(1)) then
abort_read <= '1';
-- Reached End of Memory, No Match
if (mem_addr_base = max_endpoint_addr) then
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match
-- DONE
mem_stage_next <= IDLE;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
else
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- READ GUID Prefix 3/3
when 7 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
-- No Match
if (mem_read_data /= mem_endpoint_latch_data.guid(2)) then
abort_read <= '1';
-- Reached End of Memory, No Match
if (mem_addr_base = max_endpoint_addr) then
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match
-- DONE
mem_stage_next <= IDLE;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
-- Match
else
-- Fetch Endpoint Data
mem_stage_next <= GET_ENDPOINT_DATA;
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 0;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 1;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 4;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 5;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
end if;
when others =>
null;
end case;
when GET_ENDPOINT_DATA =>
case (mem_cnt) is
-- GET Entity ID
when 0 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 1;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 4;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 5;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
mem_cnt_next <= 14;
end if;
end if;
-- GET GUID Prefix 1/3
when 1 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET GUID Prefix 2/3
when 2 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 1;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET GUID Prefix 3/3
when 3 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 2;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 4;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 5;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
else
mem_cnt_next <= 15;
end if;
end if;
end if;
-- GET IPv4 Address
when 4 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_IPV4_ADDR_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 5;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif ((RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
else
mem_cnt_next <= 18;
end if;
end if;
end if;
end if;
-- GET UDP Port/ Flags
when 5 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_UDP_PORT_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
else
mem_cnt_next <= 19;
end if;
end if;
end if;
end if;
-- GET Next Sequence Number 1/2
when 6 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET Next Sequence Number 2/2
when 7 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET + 1;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
else
mem_cnt_next <= 20;
end if;
end if;
end if;
-- GET Lease Deadline 1/2
when 8 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET Lease Deadline 2/2
when 9 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET + 1;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
else
mem_cnt_next <= 22;
end if;
end if;
end if;
-- GET Lifespan Duration 1/2
when 10 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LIFESPAN_DURATION_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GET Lifespan Duration 2/2
when 11 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LIFESPAN_DURATION_OFFSET + 1;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
else
mem_cnt_next <= 24;
end if;
end if;
end if;
-- GET Response Time 1/2
when 12 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- GET Response Time 2/2
when 13 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET + 1;
mem_read <= '1';
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 14;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
else
mem_cnt_next <= 26;
end if;
end if;
end if;
-- READ Entity ID
when 14 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.guid(3) <= mem_read_data;
if check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 15;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- READ GUID Prefix 1/3
when 15 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.guid(0) <= mem_read_data;
mem_cnt_next <= mem_cnt + 1;
end if;
-- READ GUID Prefix 2/3
when 16 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.guid(1) <= mem_read_data;
mem_cnt_next <= mem_cnt + 1;
end if;
-- READ GUID Prefix 3/3
when 17 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.guid(2) <= mem_read_data;
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 18;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- READ IPv4 Address
when 18 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.addr <= mem_read_data;
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 19;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
end if;
-- READ UDP Port
when 19 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.portn <= mem_read_data(WORD_WIDTH-1 downto WORD_WIDTH-UDP_PORT_WIDTH);
if check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 20;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
end if;
-- READ Next Sequence Number 1/2
when 20 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.next_seq_nr(0) <= unsigned(mem_read_data);
mem_cnt_next <= mem_cnt + 1;
end if;
-- READ Next Sequence Number 2/2
when 21 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.next_seq_nr(1) <= unsigned(mem_read_data);
if check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 22;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- READ Lease Deadline 1/2
when 22 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.lease_deadline(0) <= unsigned(mem_read_data);
mem_cnt_next <= mem_cnt + 1;
end if;
-- READ Lease Deadline 2/2
when 23 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.lease_deadline(1) <= unsigned(mem_read_data);
if check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 24;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- READ Lifespan Duration 1/2
when 24 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.lifespan(0) <= unsigned(mem_read_data);
mem_cnt_next <= mem_cnt + 1;
end if;
-- READ Lifespan Duration 2/2
when 25 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.lifespan(1) <= unsigned(mem_read_data);
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 26;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- READ Response Time 1/2
when 26 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.res_time(0) <= unsigned(mem_read_data);
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- READ Response Time 2/2
when 27 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
mem_endpoint_data_next.res_time(1) <= unsigned(mem_read_data);
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
when others =>
null;
end case;
when INSERT_ENDPOINT =>
case (mem_cnt) is
-- Entity ID
when 0 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_write_data <= mem_endpoint_latch_data.guid(3);
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GUID Prefix 1/3
when 1 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET;
mem_write_data <= mem_endpoint_latch_data.guid(0);
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GUID Prefix 2/3
when 2 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 1;
mem_write_data <= mem_endpoint_latch_data.guid(1);
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- GUID Prefix 3/3
when 3 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 2;
mem_write_data <= mem_endpoint_latch_data.guid(2);
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_cnt_next <= mem_cnt + 1;
else
mem_cnt_next <= 6;
end if;
end if;
-- IPv4 Address
when 4 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_IPV4_ADDR_OFFSET;
mem_write_data <= mem_endpoint_latch_data.addr;
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- UDPv4 Ports
when 5 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_UDP_PORT_OFFSET;
mem_write_data <= mem_endpoint_latch_data.portn & (0 to (mem_write_data'length-mem_endpoint_latch_data.portn'length-1) => '0');
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- Next Sequence Number 1/2
when 6 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET;
if (DURABILITY_QOS = VOLATILE_DURABILITY_QOS) then
mem_write_data <= std_logic_vector(SEQUENCENUMBER_UNKNOWN(0));
else
mem_write_data <= std_logic_vector(FIRST_SEQUENCENUMBER(0));
end if;
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Next Sequence Number 2/2
when 7 =>
mem_write_data <= (others => '0');
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET + 1;
if (DURABILITY_QOS = VOLATILE_DURABILITY_QOS) then
mem_write_data <= std_logic_vector(SEQUENCENUMBER_UNKNOWN(1));
else
mem_write_data <= std_logic_vector(FIRST_SEQUENCENUMBER(1));
end if;
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Lease Deadline 1/2
when 8 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lease_deadline(0));
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Lease Deadline 2/2
when 9 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET + 1;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lease_deadline(1));
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Lifespan Duration 1/2
when 10 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LIFESPAN_DURATION_OFFSET;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lifespan(0));
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Lifespan Duration 2/2
when 11 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LIFESPAN_DURATION_OFFSET + 1;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lifespan(1));
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_cnt_next <= mem_cnt + 1;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- Response Time 1/2
when 12 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET;
mem_write_data <= std_logic_vector(TIME_INVALID(0));
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- Response Time 2/2
when 13 =>
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET + 1;
mem_write_data <= std_logic_vector(TIME_INVALID(1));
if (mem_ready_in = '1') then
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
when others =>
null;
end case;
when UPDATE_ENDPOINT =>
case (mem_cnt) is
-- IPv4 Address
when 0 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_IPV4_ADDR_OFFSET;
mem_write_data <= mem_endpoint_latch_data.addr;
mem_endpoint_data_next.addr <= mem_endpoint_latch_data.addr;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 1;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 2;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 4;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 6;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 8;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
end if;
-- UDPv4 Ports
when 1 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_UDP_PORT_OFFSET;
mem_write_data <= mem_endpoint_latch_data.portn & (0 to (mem_write_data'length-mem_endpoint_latch_data.portn'length-1) => '0');
mem_endpoint_data_next.portn <= mem_endpoint_latch_data.portn;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 2;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 4;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 6;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 8;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
end if;
-- Next Sequence Number 1/2
when 2 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.next_seq_nr(0));
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Next Sequence Number 2/2
when 3 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET + 1;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.next_seq_nr(1));
mem_endpoint_data_next.next_seq_nr <= mem_endpoint_latch_data.next_seq_nr;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 4;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 6;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 8;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- Lease Deadline 1/2
when 4 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lease_deadline(0));
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Lease Deadline 2/2
when 5 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET + 1;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lease_deadline(1));
mem_endpoint_data_next.lease_deadline <= mem_endpoint_latch_data.lease_deadline;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 6;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 8;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- Lifespan Duration 1/2
when 6 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LIFESPAN_DURATION_OFFSET;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lifespan(0));
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
-- Lifespan Duration 2/2
when 7 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_LIFESPAN_DURATION_OFFSET + 1;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.lifespan(1));
mem_endpoint_data_next.lifespan <= mem_endpoint_latch_data.lifespan;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 8;
else
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
-- Response Time 1/2
when 8 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.res_time(0));
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= mem_cnt + 1;
end if;
end if;
-- Response Time 2/2
when 9 =>
-- Synthesis Guard
if (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS) then
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET + 1;
mem_write_data <= std_logic_vector(mem_endpoint_latch_data.res_time(1));
mem_endpoint_data_next.res_time <= mem_endpoint_latch_data.res_time;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
-- DONE
mem_stage_next <= IDLE;
end if;
end if;
when others =>
null;
end case;
when REMOVE_ENDPOINT =>
-- Mark with ENTITYID_UNKNOWN to mark slot empty_user
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_write_data <= ENTITYID_UNKNOWN;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
-- Reset MAX Endpoint Pointer
mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS;
mem_pos_next <= 0;
last_addr_next <= (others => '0');
mem_stage_next <= RESET_MAX_POINTER;
mem_cnt_next <= 0;
-- Save Current Memory Position
mem_addr_latch_next <= mem_addr_base;
end if;
when FIND_EMPTY_SLOT =>
case (mem_cnt) is
-- *READ ADDRESS*
-- Entity ID
when 0 =>
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_read <= '1';
mem_valid_in <= '1';
-- Memory Control Flow Guard
if (mem_ready_in = '1') then
mem_cnt_next <= 1;
end if;
-- *READ DATA*
-- Entity ID
when 1 =>
mem_ready_out <= '1';
-- Memory Control Flow Guard
if (mem_valid_out = '1') then
-- Slot Occupied
if (mem_read_data /= ENTITYID_UNKNOWN) then
-- Reached end of Endpoint Memory Area
if (mem_addr_base = max_endpoint_addr) then
-- MEMORY FULL
if (max_endpoint_addr = MAX_ENDPOINT_ADDRESS) then
report "Memory Full, Ignoring Endpoint Data" severity NOTE;
-- Ignore Insertion
mem_stage_next <= IDLE;
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS;
else
-- Extend Endpoint Memory Area
-- NOTE: "max_endpoint_addr" points to the first address of last Endpoint Frame
max_endpoint_addr_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
-- Populate Endpoint Slot
mem_stage_next <= INSERT_ENDPOINT;
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
-- Slot Empty
else
-- Populate Endpoint Slot
mem_stage_next <= INSERT_ENDPOINT;
mem_cnt_next <= 0;
end if;
end if;
when others =>
null;
end case;
when RESET_MAX_POINTER =>
case (mem_cnt) is
-- GET Entity ID
when 0 =>
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_read <= '1';
mem_valid_in <= '1';
-- Memory Control Flow Guard
if (mem_ready_in = '1') then
mem_cnt_next <= 1;
end if;
-- READ Entity ID
when 1 =>
mem_ready_out <= '1';
-- Memory Control Flow Guard
if (mem_valid_out = '1') then
-- Slot Occupied
if (mem_read_data /= ENTITYID_UNKNOWN) then
-- Reached end of Endpoint Memory Area
if (mem_addr_base = max_endpoint_addr) then
-- No Change
mem_stage_next <= IDLE;
-- Restore Memory Position
mem_addr_base_next <= mem_addr_latch;
else
-- Latch last occupied Endpoint Slot
last_addr_next <= mem_addr_base;
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_cnt_next <= 0;
end if;
-- Slot Empty
else
-- Make sure to iterate through complete Endpoint Area
if (mem_addr_base = max_endpoint_addr) then
-- Reset Pointer to last occupied Endpoint Slot
max_endpoint_addr_next <= last_addr;
-- DONE
mem_stage_next <= IDLE;
-- Restore Memory Position
mem_addr_base_next <= mem_addr_latch;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_cnt_next <= 0;
end if;
end if;
end if;
when others =>
null;
end case;
when GET_NEXT_ENDPOINT =>
case (mem_cnt) is
-- GET Entity ID
when 0 =>
mem_valid_in <= '1';
mem_read <= '1';
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
mem_cnt_next <= 1;
end if;
-- READ Entity ID
when 1 =>
mem_ready_out <= '1';
-- Memory Flow Control Guard
if (mem_valid_out = '1') then
-- Slot Occupied
if (mem_read_data /= ENTITYID_UNKNOWN) then
-- Fetch Endpoint Data
mem_stage_next <= GET_ENDPOINT_DATA;
mem_endpoint_data_next <= ZERO_ENDPOINT_DATA;
if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then
mem_cnt_next <= 0;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then
mem_cnt_next <= 1;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG)) then
mem_cnt_next <= 4;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG)) then
mem_cnt_next <= 5;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then
mem_cnt_next <= 6;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then
mem_cnt_next <= 8;
elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LIFESPAN_DURATION_FLAG) then
mem_cnt_next <= 10;
elsif (RELIABILITY_QOS = RELIABLE_RELIABILITY_QOS and check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG)) then
mem_cnt_next <= 12;
else
-- DONE
mem_stage_next <= IDLE;
end if;
-- Slot Empty
else
-- Reached End of Memory, No Match
if (mem_addr_base = max_endpoint_addr) then
mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match
-- DONE
mem_stage_next <= IDLE;
else
-- Continue Search
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
mem_pos_next <= mem_pos + 1;
mem_cnt_next <= 0;
end if;
end if;
end if;
when others =>
null;
end case;
when RESET_MEMORY =>
case (mem_cnt) is
-- Initiate Reset
when 0 =>
mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS;
mem_cnt_next <= mem_cnt + 1;
-- Reset Memory
when 1 =>
mem_valid_in <= '1';
mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET;
mem_write_data <= ENTITYID_UNKNOWN;
-- Memory Flow Control Guard
if (mem_ready_in = '1') then
-- End of Memory
if (mem_addr_base = MAX_ENDPOINT_ADDRESS) then
-- DONE
mem_stage_next <= IDLE;
else
-- Next Endpoint Frame
mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE;
end if;
end if;
when others =>
null;
end case;
when others =>
null;
end case;
end process;
-- Process responsible for counting read words
-- This process uses the actual FIFO read signals to determine reads
word_counter_prc : process(clk, reset)
begin
if rising_edge(clk) then
-- Reset Read counter
if (reset = '1' or reset_read_cnt = '1') then
read_cnt <= (others => '0');
-- Increment read counter each time rd_sig is high
elsif (rd_sig = '1') then
read_cnt <= read_cnt + 1;
end if;
end if;
end process;
sync_prc : process(clk)
begin
if rising_edge(clk) then
if (reset = '1') then
stage <= IDLE;
return_stage <= IDLE;
mem_stage <= RESET_MEMORY;
seq_nr <= SEQUENCENUMBER_UNKNOWN;
next_seq_nr <= SEQUENCENUMBER_UNKNOWN;
sn_latch_1 <= SEQUENCENUMBER_UNKNOWN;
sn_latch_2 <= SEQUENCENUMBER_UNKNOWN;
sn_latch_3 <= SEQUENCENUMBER_UNKNOWN;
ts <= TIME_INVALID;
check_time <= TIME_INVALID;
lifespan <= TIME_INVALID;
guid <= GUID_UNKNOWN;
addr <= IPv4_ADDRESS_INVALID;
portn <= UDP_PORT_INVALID;
mem_endpoint_data <= ZERO_ENDPOINT_DATA;
mem_endpoint_latch_data <= ZERO_ENDPOINT_LATCH_DATA;
cnt <= 0;
cnt2 <= 0;
bitmap_pos <= 0;
mem_cnt <= 0;
mem_pos <= 0;
is_meta <= '0';
key_hash_rcvd <= '0';
last_word_in_latch <= '0';
stale_check <= '0';
parameter_end <= (others => '1');
bitmap_cnt <= (others => '0');
meta_opcode <= EMO_NOP;
status_info <= (others => '0');
mem_addr_base <= (others => '0');
last_addr <= (others => '0');
mem_addr_latch <= (others => '0');
max_endpoint_addr <= (others => '0');
flags <= (others => '0');
opcode <= SID_PAD;
count <= (others => '0');
current_emf <= (others => '0');
key_hash <= KEY_HASH_NIL;
bitmap_latch <= (others => (others => '0'));
else
stage <= stage_next;
return_stage <= return_stage_next;
mem_stage <= mem_stage_next;
seq_nr <= seq_nr_next;
next_seq_nr <= next_seq_nr_next;
sn_latch_1 <= sn_latch_1_next;
sn_latch_2 <= sn_latch_2_next;
sn_latch_3 <= sn_latch_3_next;
ts <= ts_next;
check_time <= check_time_next;
lifespan <= lifespan_next;
guid <= guid_next;
addr <= addr_next;
portn <= portn_next;
mem_endpoint_data <= mem_endpoint_data_next;
mem_endpoint_latch_data <= mem_endpoint_latch_data_next;
cnt <= cnt_next;
cnt2 <= cnt2_next;
bitmap_pos <= bitmap_pos_next;
mem_cnt <= mem_cnt_next;
mem_pos <= mem_pos_next;
is_meta <= is_meta_next;
key_hash_rcvd <= key_hash_rcvd_next;
last_word_in_latch <= last_word_in_latch_next;
parameter_end <= parameter_end_next;
bitmap_cnt <= bitmap_cnt_next;
stale_check <= stale_check_next;
meta_opcode <= meta_opcode_next;
status_info <= status_info_next;
mem_addr_base <= mem_addr_base_next;
last_addr <= last_addr_next;
mem_addr_latch <= mem_addr_latch_next;
max_endpoint_addr <= max_endpoint_addr_next;
flags <= flags_next;
opcode <= opcode_next;
count <= count_next;
current_emf <= current_emf_next;
key_hash <= key_hash_next;
bitmap_latch <= bitmap_latch_next;
end if;
end if;
end process;
end architecture;