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.
3203 lines
178 KiB
VHDL
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;
|