rtps-fpga/src/rtps_builtin_endpoint.vhd

3102 lines
162 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.math_pkg.all;
use work.rtps_package.all;
entity rtps_builtin_endpoint is
port (
clk : in std_logic; -- Input Clock
reset : in std_logic; -- Synchronous Reset
empty : in std_logic; -- Input FIFO empty flag
rd : out std_logic; -- Input FIFO read signal
data_in : in std_logic_vector(31 downto 0); -- Input FIFO data signal
last_word_in : in std_logic;
time : in DOUBLE_WORD_ARRAY;
endpoint_output : out USER_ENDPOINT_OUTPUT;
endpoint_full : in std_logic_vector(0 to MAX_ENDPOINTS-1);
endpoint_wr : out std_logic_vector(0 to MAX_ENDPOINTS-1);
rtps_output : out std_logic_vector(31 downto 0);
rtps_wr : out std_logic;
rtps_full : in std_logic;
last_word_out : out std_logic;
alive : in std_logic_vector(0 to MAX_ENDPOINTS-1);
);
end entity;
architecture arch of rtps_builtin_endpoint is
--*****COMPONENT DECLARATION******
component single_port_ram is
generic (
ADDR_WIDTH : natural := 8;
DATA_WIDTH : natural := 12;
MEMORY_SIZE : natural := DATA_WIDTH*(2**ADDR_WIDTH)
);
port (
clk : in std_logic;
addr : in std_logic_vector(ADDR_WIDTH-1 downto 0);
wen : in std_logic;
ren : in std_logic;
wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0);
rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0)
);
end component;
--*****TYPE DECLARATION*****
-- FSM states. Explained below in detail
type STAGE_TYPE is (TODO);
type MEM_STAGE_TYPE is (TODO);
type MESSAGE_TYPE_TYPE is (PDP, EDP, MESSAGE, NONE);
type MEM_OPCODE_TYPE is (NOP, SEARCH_PARTICIPANT, SEARCH_ENDPOINT);
type PARTICIPANT_DATA_TYPE is record
meta_addr : std_logic_vector(31 downto 0);
def_addr : std_logic_vector(31 downto 0);
meta_port : std_logic_vector(15 downto 0);
def_port : std_logic_vector(15 downto 0);
extra_flags : std_logic_vector(31 downto 0);
lease_duration : DOUBLE_WORD_ARRAY;
lease_deadline : DOUBLE_WORD_ARRAY;
heartbeat_res_time : DOUBLE_WORD_ARRAY;
acknack_res_time : DOUBLE_WORD_ARRAY;
spdp_seq_nr : DOUBLE_WORD_ARRAY;
pub_seq_nr : DOUBLE_WORD_ARRAY;
sub_seq_nr : DOUBLE_WORD_ARRAY;
mes_seq_nr : DOUBLE_WORD_ARRAY;
end record;
--*****CONSTANT DECLARATION*****
constant BUILTIN_BUFFER_SIZE : natural := MAX_REMOTE_PARTICIPANTS*PARTICIPANT_FRAME_SIZE;
constant BUILTIN_BUFFER_ADDR_WIDTH : natural := log2c(BUILTIN_BUFFER_SIZE);
constant PARTICIPANT_DATA_FLAG : natural := 0;
constant LEASE_DEADLINE_FLAG : natural := 1;
constant EXTRA_FLAGS_FLAG : natural := 2;
constant ACKNACK_RES_TIME_FLAG : natural := 3;
constant HEARTBEAT_RES_TIME_FLAG : natural := 4;
constant EDP_SEQ_NR_FLAG : natural := 5;
constant PUB_DATA_FLAG : natural := 31;
constant SUB_DATA_FLAG : natural := 30;
constant MES_DATA_FLAG : natural := 29;
constant PUB_SEQUENCE_NR : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(NUM_WRITERS, 64));
constant SUB_SEQUENCE_NR : DOUBLE_WORD_ARRAY := convert_to_double_word(to_unsigned(NUM_READERS, 64));
constant ZERO_PARTICIPANT_DATA : PARTICIPANT_DATA_TYPE := (
meta_addr => (others => '0'),
def_addr => (others => '0'),
meta_port => (others => '0'),
def_port => (others => '0'),
extra_flags => (others => '0'),
lease_duration => (others => (others => '0')),
lease_deadline => (others => (others => '0')),
heartbeat_res_time => (others => (others => '0')),
acknack_res_time => (others => (others => '0')),
spdp_seq_nr => (others => (others => '0')),
pub_seq_nr => (others => (others => '0')),
sub_seq_nr => (others => (others => '0')),
mes_seq_nr => (others => (others => '0'))
);
--*****SIGNAL DECLARATION*****
-- FSM state
signal stage, stage_next : STAGE_TYPE := SRC_ADDR_HEADER;
signal mem_stage, mem_stage_next : MEM_STAGE_TYPE := TODO;
-- Intermediate input read signal. (Read from output port not allowed)
signal rd_sig : std_logic := '0';
-- Signal used to reset the word counter
signal reset_read_cnt : std_logic;
-- 32-bit Word counter (Counts words read from input fifo)
signal read_cnt : unsigned(13 downto 0) := (others => '0');
-- 32-bit Word aligned total packet length
signal packet_length, packet_length_next : unsigned(13 downto 0) := (others => '0');
signal opcode, opcode_next : std_logic_vector(7 downto 0) := (others => '0');
signal flags, flags_next : std_logic_vector(7 downto 0) := (others => '0');
signal src_port, src_port_next : std_logic_vector(15 downto 0) := (others => '0');
signal src_addr, src_addr_next : std_logic_vector(31 downto 0) := (others => '0');
-- TODO: Initialise metatraffic with default locator, since it may not be in the message (Take src Locator?)
-- TODO: Default locator should always be in the message
signal addr_latch_1, addr_latch_1_next, addr_latch_2, addr_latch_2_next : std_logic_vector(31 downto 0) := (others => '0');
signal port_latch_1, port_latch_1_next, port_latch_2, port_latch_2_next : std_logic_vector(15 downto 0) := (others => '0');
signal src_entityid, src_entityid_next : std_logic_vector(31 downto 0) := (others => '0');
signal dest_entityid, dest_entityid_next : std_logic_vector(31 downto 0) := (others => '0');
signal parameter_end, parameter_end_next : unsigned(13 downto 0) := (others => '0');
signal message_type, message_type_next : MESSAGE_TYPE_TYPE := PDP;
signal data_in_swapped : std_logic_vector(31 downto 0) := (others => '0');
signal string_length, string_length_next : unsigned(31 downto 0) := (others => '0');
--TODO: Always reset before COMPARE_STRING stage
signal compare_length, compare_length_next : unsigned(31 downto 0) := (others => '0');
signal endpoint_mask, endpoint_mask_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0');
signal endpoint_match, endpoint_match_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0');
signal endpoint_unmatch, endpoint_unmatch_next : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0');
signal endpoint_mask_array, endpoint_mask_array_next : ENDPOINT_BITMASK_ARRAY_TYPE := (others => (others => '0'));
signal participant_match, participant_match_next : std_logic := '0';
signal is_subscriber, is_subscriber_next : std_logic := '0';
signal lease_duration, lease_duration_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal deadline, deadline_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal lifespan_duration, lifespan_duration_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal addr_latch_index, addr_latch_index_next : std_logic := '0';
-- General Purpose counter
-- TODO: Constrain range
signal cnt, cnt_next : natural := 0;
signal expects_inline_qos, expects_inline_qos_next : std_logic := '0';
signal guid, guid_next : GUID_ARRAY_TYPE := (others => (others => '0'));
signal start_mem_op, mem_op_busy, mem_op_done : std_logic := '0';
signal mem_opcode : MEM_OPCODE_TYPE := NOP;
signal participant_message_best_effort, participant_message_best_effort_next : std_logic := '0';
signal mem_addr, mem_addr_next, mem_addr_base, mem_addr_base_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0');
signal addr_res, addr_res_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0');
signal last_addr, last_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0');
signal max_participant_addr, max_participant_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0');
signal max_endpoint_addr, max_endpoint_addr_next : unsigned(BUILTIN_BUFFER_ADDR_WIDTH-1 downto 0) := (others => '0');
signal mem_read_data, mem_write_data : std_logic_vector(31 downto 0) := (others => '0');
signal mem_rd, mem_wr, mem_busy, mem_done : std_logic := '0';
-- TODO: Re-check range
signal mem_cnt, mem_cnt_next : natural range 0 to 3 := 0;
-- NOTE: Participant Index limited to 32 bits
signal participant_index, participant_index_next : std_logic_vector(31 downto 0) := (others => '0');
signal seq_nr, seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal mem_seq_nr, mem_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal next_seq_nr, next_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal first_seq_nr, first_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal last_seq_nr, last_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal is_orphan_search, is_orphan_search_next : std_logic := '0';
signal orphan_entityid, orphan_entityid_next : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (others => '0');
signal output_sig : std_logic_vector(31 downto 0) := (others => '0');
signal mem_def_addr, mem_def_addr_next : std_logic_vector(31 downto 0) := (others => '0');
signal mem_def_port, mem_def_port_next : std_logic_vector(15 downto 0) := (others => '0');
signal mem_xflags, mem_xflags_next : std_logic_vector(15 downto 0) := (others => '0');
signal reset_max_pointer, reset_max_pointer_next : std_logic := '0';
signal stale_check, stale_check_next : std_logic := '0';
signal mem_guidprefix, mem_guidprefix_next : GUIDPREFIX_ARRAY_TYPE : (others => (others => '0'));
signal last_word_in_latch, last_word_in_latch_next : std_logic := '0';
signal update_participant_flags, update_participant_flags_next : std_logic_vector(5 downto 0) := (others => '0');
signal mem_participant_data, mem_participant_data_next : PARTICIPANT_DATA_TYPE := ZERO_PARTICIPANT_DATA;
signal is_heartbeat_res, is_heartbeat_res_next : std_logic := '0';
signal seq_prc_done, seq_prc_done_next : std_logic := '0';
signal count, count_next : unsigned(31 downto 0) := (others => '0');
signal endpoint_alive : std_logic := '0';
signal reset_endpoint_alive : std_logic := '0';
-- TODO: Make sure sequences are initialized to 1
signal auto_live_seq_nr, auto_live_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal man_live_seq_nr, man_live_seq_nr_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal live_gap_start, live_gap_start_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal live_gap_end, live_gap_end_next : DOUBLE_WORD_ARRAY := (others => (others => '0'));
signal extra_flags, extra_flags_next : std_logic_vector(31 downto 0) := (others => '0');
--*****ALIAS DEFINATION*****
alias header_opcode : std_logic_vector(7 downto 0) is data_in(31 downto 24);
alias header_flags : std_logic_vector(7 downto 0) is data_in(23 downto 16);
alias header_udp_port : std_logic_vector(15 downto 0) is data_in(15 downto 0);
alias parameter_id : std_logic_vector(15 downto 0) is data_in(31 downto 16);
alias parameter_length : std_logic_vector(15 downto 0) is data_in(15 downto 0);
alias representation_id : std_logic_vector(15 downto 0) is data_in(31 downto 16);
alias representation_options : std_logic_vector(15 downto 0) is data_in(15 downto 0);
-- RTPS SUBMESSAGE FLAGS
alias endian_flag : std_logic is flags(0);
alias endian_flag_next : std_logic is flags_next(0);
alias qos_flag : std_logic is flags(1);
alias qos_flag_next : std_logic is flags_next(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 payload_flag : std_logic is header_flags(4);
alias must_undersand : std_logic is parameter_id(14);
--*****FUNCTION DECLARATION*****
-- Truncates the lower 2 bits of the input, and if they are not equal zero, adds one to the result.
-- This is used to round the byte length to 32-bit word length.
function normalize_length (len : std_logic_vector(15 downto 0)) return std_logic_vector is
variable tmp : std_logic_vector(13 downto 0) := (others => '0');
begin
tmp := len(15 downto 2);
if(len(1 downto 0) /= "00") then
tmp := std_logic_vector(unsigned(tmp) + 1);
end if;
return tmp;
end function;
function convert_to_bitmask_array (bitmask : std_logic_vector) return ENDPOINT_BITMASK_ARRAY is
variable ret : ENDPOINT_BITMASK_ARRAY := (others => (others => '0'));
begin
ret := (others => (others => '0'));
for i in 0 to ENDPOINT_BITMASK_ARRAY'length-1 loop
if (i = ENDPOINT_BITMASK_ARRAY'length-1) then
ret(i) := bitmask(i*32 to i*32+31);
else
ret(i)(0 to (bitmask'length mod 32)-1) := bitmask(i*32 to i*32+(bitmask'length mod 32)-1);
end if;
end loop;
return ret;
end function;
function convert_from_bitmask_array (bitmask : ENDPOINT_BITMASK_ARRAY, len : natural) return std_logic_vector is
variable ret : std_logic_vector(0 to len-1) := (others => '0');
begin
ret := (others => '0');
for i in 0 to ENDPOINT_BITMASK_ARRAY'length-1 loop
if (i = ENDPOINT_BITMASK_ARRAY'length-1) then
ret(i*32 to i*32+31) := bitmask(i);
else
ret(i*32 to i*32+(len mod 32)-1) := bitmask(i)(0 to (len mod 32)-1);
end if;
end loop;
return ret;
end function;
begin
--*****COMPONENT INSTANTIATION*****
ram_inst : single_port_ram is
generic map (
ADDR_WIDTH => BUILTIN_BUFFER_ADDR_WIDTH,
DATA_WIDTH => 32,
MEMORY_SIZE => BUILTIN_BUFFER_SIZE
)
port map (
clk => clk,
addr => mem_addr,
wen => mem_wr,
ren => mem_rd,
wr_data => mem_write_data,
rd_data => mem_read_data
);
rd <= rd_sig;
endian_swap_prc: process(all)
begin
data_in_swapped <= data_in;
if (endian_flag = '1') then
for i in 0 to 3 loop
data_in_swapped(i*8+8-1 downto i*8) <= data((3-i)*8+8-1 downto (3-i)*8);
end loop;
end if;
end process;
endpoint_alive_prc: process(all)
begin
if (rising_edge(clk)) then
-- Reset Endpoint Alive Signal
if (reset = '1' or reset_endpoint_alive = '1') then
endpoint_alive <= '0';
-- Set Endpoint Alive Signal, if at least one endpoint asserts liveliness
-- XXX: VHDL-2008 unary logic operator
elsif (or alive = '1') then
endpoint_alive <= '1';
end if;
end if;
end process;
seq_nr_prc: process(all)
begin
-- DEFAULT
seq_prc_done_next <= seq_prc_done;
mem_seq_nr_next <= mem_seq_nr;
next_seq_nr_next <= next_seq_nr;
if (mem_op_done = '1') then
seq_prc_done_next <= '1';
case (message_type) is
when PDP =>
mem_seq_nr_next <= mem_participant_data.spdp_seq_nr;
next_seq_nr_next <= mem_participant_data.spdp_seq_nr + 1;
when EDP =>
if (is_subscriber = '1') then
mem_seq_nr_next <= mem_participant_data.sub_seq_nr;
next_seq_nr_next <= mem_participant_data.sub_seq_nr + 1;
else
mem_seq_nr_next <= mem_participant_data.pub_seq_nr;
next_seq_nr_next <= mem_participant_data.pub_seq_nr + 1;
end if;
when MESSAGE =>
mem_seq_nr_next <= mem_participant_data.mes_seq_nr;
next_seq_nr_next <= mem_participant_data.mes_seq_nr + 1;
when others =>
null;
end case;
else
seq_prc_done_next <= '0';
mem_seq_nr_next <= (others => '0');
next_seq_nr_next <= (others => '0');
end if;
end process;
-- This process connects the Intermediate Output Signals to the actual output FIFOs
output_prc : process(all)
begin
-- Data Signal
for i in 0 to NUM_DOMAIN-1 loop
endpoint_output(i) <= output_sig;
end loop;
--Write Enable Signal
endpoint_wr <= (others => '0');
case (stage) is
when INFORM_ENDPOINTS_MATCH =>
if (wr_sig = '1') then
endpoint_wr <= endpoint_match;
end if;
when INFORM_ENDPOINTS_UNMATCH =>
if (wr_sig = '1') then
endpoint_wr <= endpoint_unmatch;
end if;
when others =>
null;
end case;
end process;
parse_prc: process(all)
variable tmp_endpoint_mask : std_logic_vector(0 to MAX_ENDPOINTS-1) := (others => '0');
begin
--DEFAULT
stage_next <= stage;
packet_length_next <= packet_length;
rd_sig <= '0';
reset_read_cnt <= '0';
opcode_next <= opcode;
flags_next <= flags;
src_port_next <= src_port;
src_addr_next <= src_addr;
src_entityid_next <= src_entityid;
dest_entityid_next <= dest_entityid;
parameter_end_next <= parameter_end;
message_type_next <= message_type;
string_length_next <= string_length;
endpoint_mask_next <= endpoint_mask;
endpoint_match_next <= endpoint_match;
endpoint_unmatch_next <= endpoint_unmatch;
participant_match_next <= participant_match_next;
is_subscriber_next <= is_subscriber;
lease_duration_next <= lease_duration;
lifespan_duration_next <= lifespan_duration;
addr_latch_1_next <= addr_latch_1;
addr_latch_2_next <= addr_latch_2;
port_latch_1_next <= port_latch_1;
port_latch_2_next <= port_latch_2;
addr_latch_index_next <= addr_latch_index;
cnt_next <= cnt;
expects_inline_qos_next <= expects_inline_qos;
mem_opcode <= NOP;
start_mem_op <= '0';
is_orphan_search_next <= is_orphan_search;
extra_flags_next <= extra_flags;
output_sig <= (others => '0');
wr_sig <= '0';
stale_check_next <= stale_check;
first_seq_nr_next <= first_seq_nr;
last_seq_nr_next <= last_seq_nr;
update_participant_flags_next <= update_participant_flags;
deadline_next <= deadline;
last_word_out <= '0';
reset_endpoint_alive <= '0';
auto_live_seq_nr_next <= auto_live_seq_nr;
man_live_seq_nr_next <= man_live_seq_nr;
live_gap_start_next <= live_gap_start;
live_gap_end_next <= live_gap_end;
-- Last Word Latch Setter
if (last_word_in = '1') then
last_word_in_latch_next <= '1';
-- TODO: Also set in AUTO_PURGE to exit from SKIP_PACKET stage
else
last_word_in_latch_next <= last_word_in_latch;
end if;
-- TODO: Reset Latches
case(stage) is
-- Initial/Idle State
when IDLE =>
-- No Packets to process
if (empty = '1') then
mem_opcode <= FIND_STALE_PARTICIPANT;
start_mem_op <= '1';
stale_check_next <= '1';
stage_next <= STALE_CHECK;
elsif (stale_check = '0') then
mem_opcode <= FIND_STALE_PARTICIPANT;
start_mem_op <= '1';
stale_check_next <= '1';
stage_next <= STALE_CHECK;
else
-- Process Packet
stale_check_next <= '0';
stage_next <= PACKET_HEADER;
end if;
when PACKET_HEADER =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Opcode
opcode_next <= header_opcode;
-- Latch Flags
flags_next <= header_flags;
-- Latch Source UDP Port
src_port_next <= header_udp_port;
-- Next Stage
stage_next <= PACKET_SRC_ADDR;
-- SANITY CHECK
-- Skip Packet if non-standard Payload
if(header_opcode = SID_DATA and payload_flag = '1') then
stage_next <= SKIP_PACKET;
end if;
end if;
when PACKET_SRC_ADDR =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Source IP Address
src_addr_next <= data_in;
-- Next Stage
stage_next <= PACKET_SRC_ENTITYID;
end if;
when PACKET_SRC_ENTITYID =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Source Entity ID
src_entityid_next <= data_in;
-- Reset Counter
cnt_next <= 1;
-- Next Stage
stage_next <= PACKET_SRC_GUIDPREFIX;
end if;
when PACKET_SRC_GUIDPREFIX =>
if (empty = '0' and mem_op_done = '1') then
rd_sig <= '1';
-- Latch Src GUIDPrefix
case (cnt) is
when 1 =>
guid_next(0) <= data_in;
when 2 =>
guid_next(1) <= data_in;
when 3 =>
guid_next(2) <= data_in;
guid_next(3) <= (others => '0');
-- Start Participant Search
mem_opcode <= SEARCH_PARTICIPANT;
start_mem_op <= '1';
-- Next Stage
stage_next <= PACKET_DEST_ENTITYID;
when others =>
null;
end case;
end if;
when PACKET_DEST_ENTITYID =>
if (empty = '0') then
rd_sig <= '1';
-- DEFAULT STAGE
stage_next <= SKIP_PACKET;
-- *Check Dest Entity ID*
case (data_in) is
when ENTITYID_UNKNOWN =>
-- Wildcard Destination
-- Content has to be determined through src
stage_next <= CHECK_SRC_ENTITYID;
when ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR =>
-- Only DATA relevant
if (opcode = SID_DATA) then
-- Packet Contains Participant Data
message_type_next <= PDP;
stage_next <= LATCH_SEQ_NR;
-- Initialise counter
cnt_next <= 1;
-- Reset Participant Match
participant_match_next <= '1';
end if;
when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER =>
-- SANITY CHECK: Ignore if no Writers
-- Only ACKNACKs are relevant
if (NUM_WRITERS /= 0 and opcode = SID_ACKNACK) then
message_type_next <= EDP;
stage_next <= PROCESS_ACKNACK; --ACKNACK Processing
-- Initialise Counter
cnt_next <= 1;
end if;
when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR =>
-- SANITY CHECK: Ignore if no Readers
if (NUM_READERS /= 0) then
-- Only HEARTBEATs and DATA are relevant (GAPs irrelevant, since depth is 1)
case (opcode) is
when SID_HEARTBEAT =>
message_type_next <= EDP;
stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing
-- Initialise counter
cnt_next <= 1;
when SID_DATA =>
message_type_next <= EDP;
stage_next <= LATCH_SEQ_NR; -- DATA Processing
-- Initialise counter
cnt_next <= 1;
-- QoS is publisher-offered
is_subscriber_next <= '0';
-- Reset Endpoint Mask (ALL READERS)
endpoint_mask_next <= (others => '0');
endpoint_mask_next(MAX_ENDPOINTS-1 downto MAX_ENDPOINTS-NUM_READERS) <= (others => '1');
end case;
end if;
when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER =>
-- SANITY CHECK: Ignore if no Readers
-- Only ACKNACKs are relevant
if (NUM_READERS /= 0 and opcode = SID_ACKNACK) then
message_type_next <= EDP;
stage_next <= PROCESS_ACKNACK; --ACKNACK Processing
-- Initialise counter
cnt_next <= 1;
end if;
when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR =>
-- SANITY CHECK: Ignore if no Writers
if (NUM_WRITERS /= 0) then
-- Only HEARTBEATs and DATA are relevant (GAPs irrelevant, since depth is 1)
case (opcode) is
when SID_HEARTBEAT =>
message_type_next <= EDP;
stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing
-- Initialise counter
cnt_next <= 1;
when SID_DATA =>
message_type_next <= EDP;
stage_next <= LATCH_SEQ_NR; -- DATA Processing
-- Initialise counter
cnt_next <= 1;
-- QoS is subscriber-requested
is_subscriber_next <= '1';
-- Reset Endpoint Mask (ALL WRITERS)
endpoint_mask_next <= (others => '0');
endpoint_mask_next(NUM_WRITERS-1 downto 0) <= (others => '1');
end case;
end if;
when ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER =>
-- Only ACKNACKs are relevant
if (opcode = SID_ACKNACK) then
message_type_next <= MESSAGE;
stage_next <= PROCESS_ACKNACK; --ACKNACK Processing
-- Initialise counter
cnt_next <= 1;
end if;
when ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER =>
-- Only HEARTBEATs and DATA are relevant (GAPs irrelevant, since depth is 1)
case (opcode) is
when SID_HEARTBEAT =>
message_type_next <= MESSAGE;
stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing
-- Initialise counter
cnt_next <= 1;
when SID_DATA =>
message_type_next <= MESSAGE;
stage_next <= LATCH_SEQ_NR; -- DATA Processing
-- Initialise counter
cnt_next <= 1;
end case;
when others =>
null;
end case;
end if;
when CHECK_SRC_ENTITYID =>
-- DEFAULT STAGE
stage_next <= SKIP_PACKET;
-- *Check Dest Entity ID*
case (src_entityid) is
when ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER =>
-- Only DATA relevant
if (opcode = SID_DATA) then
-- Packet Contains Participant Data
message_type_next <= PDP;
stage_next <= LATCH_SEQ_NR;
-- Initialise counter
cnt_next <= 1;
-- Reset Participant Match
participant_match_next <= '1';
end if;
when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR =>
-- SANITY CHECK: Ignore if no Writers
-- Only ACKNACKs are relevant
if (NUM_WRITERS /= 0 and opcode = SID_ACKNACK) then
message_type_next <= EDP;
stage_next <= PROCESS_ACKNACK; --ACKNACK Processing
-- Initialise counter
cnt_next <= 1;
end if;
when ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER =>
-- SANITY CHECK: Ignore if no Readers
if (NUM_READERS /= 0) then
-- Only HEARTBEATs and DATA are relevant (GAPs irrelevant, since depth is 1)
case (opcode) is
when SID_HEARTBEAT =>
message_type_next <= EDP;
stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing
-- Initialise counter
cnt_next <= 1;
when SID_DATA =>
message_type_next <= EDP;
stage_next <= LATCH_SEQ_NR; -- DATA Processing
-- Initialise counter
cnt_next <= 1;
-- QoS is publisher-offered
is_subscriber_next <= '0';
-- Reset Endpoint Mask (ALL READERS)
endpoint_mask_next <= (others => '0');
endpoint_mask_next(MAX_ENDPOINTS-1 downto MAX_ENDPOINTS-NUM_READERS) <= (others => '1');
end case;
end if;
when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR =>
-- SANITY CHECK: Ignore if no Readers
-- Only ACKNACKs are relevant
if (NUM_READERS /= 0 and opcode = SID_ACKNACK) then
message_type_next <= EDP;
stage_next <= PROCESS_ACKNACK; --ACKNACK Processing
-- Initialise counter
cnt_next <= 1;
end if;
when ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER =>
-- SANITY CHECK: Ignore if no Writers
if (NUM_WRITERS /= 0) then
-- Only HEARTBEATs and DATA are relevant (GAPs irrelevant, since depth is 1)
case (opcode) is
when SID_HEARTBEAT =>
message_type_next <= EDP;
stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing
-- Initialise counter
cnt_next <= 1;
when SID_DATA =>
message_type_next <= EDP;
stage_next <= LATCH_SEQ_NR; -- DATA Processing
-- Initialise counter
cnt_next <= 1;
-- QoS is subscriber-requested
is_subscriber_next <= '1';
-- Reset Endpoint Mask (ALL WRITERS)
endpoint_mask_next <= (others => '0');
endpoint_mask_next(NUM_WRITERS-1 downto 0) <= (others => '1');
end case;
end if;
when ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER =>
-- Only ACKNACKs are relevant
if (opcode = SID_ACKNACK) then
message_type_next <= MESSAGE;
stage_next <= PROCESS_ACKNACK; --ACKNACK Processing
-- Initialise counter
cnt_next <= 1;
end if;
when ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER =>
-- Only HEARTBEATs and DATA are relevant (GAPs irrelevant, since depth is 1)
case (opcode) is
when SID_HEARTBEAT =>
message_type_next <= MESSAGE;
stage_next <= PROCESS_HEARTBEAT; -- HEARTBEAT Processing
-- Initialise counter
cnt_next <= 1;
when SID_DATA =>
message_type_next <= MESSAGE;
stage_next <= LATCH_SEQ_NR; -- DATA Processing
-- Initialise counter
cnt_next <= 1;
end case;
when others =>
null;
end case;
when LATCH_SEQ_NR =>
if (empty = '0') then
rd_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
-- Latch Sequence Number
case (cnt) is
when 1 =>
seq_nr_next(0) <= unsigned(data_in);
when 2 =>
seq_nr_next(1) <= unsigned(data_in);
stage_next <= PROCESS_DATA;
when others =>
null;
end case;
end if;
when PROCESS_DATA =>
-- Data Message contains inline QoS
if (qos_flag = '1') then
stage_next <= PROCESS_PL;
-- Data Message contains Payload
elsif (data_flag = '1') then
-- Process Payload Header
if (empty = '0') then
rd_sig <= '1';
-- DEFAULT Stage Next
stage_next <= SKIP_PACKET;
-- Process Payload Header
case(representation_id) is
when PL_CDR_BE =>
endian_flag_next <= '0';
stage_next <= PROCESS_PL;
when PL_CDR_LE =>
endian_flag_next <= '1';
stage_next <= PROCESS_PL;
when CDR_BE =>
if (message_type = MESSAGE) then
endian_flag_next <= '0';
stage_next <= PROCESS_MESSAGE;
end if;
when CDR_LE =>
if (message_type = MESSAGE) then
endian_flag_next <= '1';
stage_next <= PROCESS_MESSAGE;
end if;
when others =>
null;
end case;
end if;
end if;
when PROCESS_PL =>
if (empty = '0') then
rd_sig <= '1';
-- Reset Word Counter
reset_read_cnt <= '1';
-- Latch Parameter End
parameter_end_next <= unsigned(normalize_length(endian_swap(endian_flag,parameter_length)));
-- DEFAULT
stage_next <= SKIP_PARAMETER;
-- TODO: Use inline QoS?
-- TODO: DDS-XTYPES: When reading data, implementations of this specification shall be robust to any setting of the FLAG_MUST_UNDERSTAND bit and accept the parameter nevertheless.
case (parameter_id) is
when PID_TOPIC_NAME =>
-- Topic Name only relevant for EDP
if(qos_flag = '0' and message_type = EDP) then
stage_next <= LATCH_STRING_LENGTH;
end if;
when PID_TYPE_NAME =>
-- Type Name only relevant for EDP
if(qos_flag = '0' and message_type = EDP) then
stage_next <= LATCH_STRING_LENGTH;
end if;
when PID_USER_DATA =>
-- Ignore
null;
when PID_GROUP_DATA =>
-- Ignore
null;
when PID_TOPIC_DATA =>
-- Ignore
null;
when PID_DURABILITY =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_DURABILITY;
end if;
when PID_DURABILITY_SERVICE =>
-- Ignore
when PID_DEADLINE =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_DEADLINE_1;
end if;
when PID_LATENCY_BUDGET =>
-- Ignore
when PID_LIVELINESS =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_LIVELINESS;
end if;
when PID_RELIABILITY =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_RELIABILITY;
end if;
when PID_LIFESPAN =>
if(qos_flag = '0' and message_type = EDP) then
-- TODO: Do not latch lifespan. Request it via inline QoS
stage_next <= LATCH_LIFESPAN_1;
end if;
when PID_DESTINATION_ORDER =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_DESTINATION_ORDER;
end if;
when PID_HISTORY =>
-- Ignore
when PID_RESOURCE_LIMITS =>
-- Ignore
when PID_OWNERSHIP =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_OWNERSHIP;
end if;
when PID_OWNERSHIP_STRENGTH =>
-- Ignore
when PID_PRESENTATION =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_PRESENTATION;
end if;
when PID_PARTITION =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= RXO_PARTITION;
end if;
when PID_TIME_BASED_FILTER =>
-- Ignore
when PID_TRANSPORT_PRIORITY =>
-- Ignore
when PID_DOMAIN_ID =>
if(qos_flag = '0' and message_type = PDP) then
stage_next <= MATCH_DOMAIN_ID;
end if;
when PID_DOMAIN_TAG =>
if(qos_flag = '0' and message_type = PDP) then
stage_next <= LATCH_STRING_LENGTH;
end if;
when PID_PROTOCOL_VERSION =>
if(qos_flag = '0' and message_type = PDP) then
stage_next <= MATCH_PROTOCOL_VERSION;
end if;
when PID_VENDORID =>
-- Ignore
when PID_UNICAST_LOCATOR =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= LATCH_LOCATOR;
addr_latch_index_next <= '0';
-- Initialise counter
cnt_next <= 1;
end if;
when PID_MULTICAST_LOCATOR =>
if(qos_flag = '0' and message_type = EDP) then
stage_next <= LATCH_LOCATOR;
addr_latch_index_next <= '0';
-- Initialise counter
cnt_next <= 1;
end if;
when PID_DEFAULT_UNICAST_LOCATOR =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_LOCATOR;
addr_latch_index_next <= '0';
-- Initialise counter
cnt_next <= 1;
end if;
when PID_DEFAULT_MULTICAST_LOCATOR =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_LOCATOR;
addr_latch_index_next <= '0';
-- Initialise counter
cnt_next <= 1;
end if;
when PID_METATRAFFIC_UNICAST_LOCATOR =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_LOCATOR;
addr_latch_index_next <= '1';
-- Initialise counter
cnt_next <= 1;
end if;
when PID_METATRAFFIC_MULTICAST_LOCATOR =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_LOCATOR;
addr_latch_index_next <= '1';
-- Initialise counter
cnt_next <= 1;
end if;
when PID_EXPECTS_INLINE_QOS =>
stage_next <= LATCH_EXPECTS_INLINE_QOS;
when PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT =>
-- Ignore
when PID_PARTICIPANT_LEASE_DURATION =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_LEASE_DURATION_1;
end if;
when PID_CONTENT_FILTER_PROPERTY =>
-- Ignore
when PID_PARTICIPANT_GUID =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_GUID;
-- Initialise counter
cnt_next <= 1;
end if;
when PID_GROUP_GUID =>
-- Ignore
when PID_BUILTIN_ENDPOINT_SET =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= CHECK_REMOTE_BUILTIN_ENDPOINTS;
end if;
when PID_BUILTIN_ENDPOINT_QOS =>
if(qos_flag = '0' and message_type = DPD) then
stage_next <= LATCH_BUILTIN_ENDPOINT_QOS;
end if;
when PID_PROPERTY_LIST =>
-- Ignore
when PID_TYPE_MAX_SIZE_SERIALIZED =>
-- Ignore
when PID_ENTITY_NAME =>
-- Ignore
when PID_ENDPOINT_GUID =>
if(qos_flag = '0' and message_type = EPD) then
stage_next <= LATCH_GUID;
-- Initialise counter
cnt_next <= 1;
end if;
when PID_CONTENT_FILTER_INFO =>
-- Ignore
when PID_COHERENT_SET =>
-- Ignore
when PID_DIRECTED_WRITE =>
-- Ignore
when PID_ORIGINAL_WRITER_INFO =>
-- Ignore
when PID_GROUP_COHERENT_SET =>
-- Ignore
when PID_GROUP_SEQ_NUM =>
-- Ignore
when PID_WRITER_GROUP_INFO =>
-- Ignore
when PID_SECURE_WRITER_GROUP_INFO =>
-- Ignore
when PID_KEY_HASH =>
-- Ignore
when PID_STATUS_INFO =>
-- Ignore
when PID_EXTENDED =>
-- TODO
when PID_PAD =>
-- Ignore
when PID_IGNORE =>
-- Ignore
when PID_SENTINEL =>
-- If Processing in-line QoS until now
if(qos_flag = '1') then
qos_flag_next <= '0';
stage_next <= PROCESS_DATA;
else
stage_next <= PARTICIPANT_MATCH_STAGE;
end if;
when PID_LIST_END =>
-- TODO
when others =>
-- If MUST_UNDERSTAND Flag is set, we have incompatible communication. Drop Packet
if (must_undersand = '1') then
stage_next <= SKIP_PACKET;
-- Else skip Uknown Parameter
else
stage_next <= SKIP_PARAMETER;
end if;
end case;
end if;
when LATCH_STRING_LENGTH =>
if (empty = '0') then
rd_sig <= '1';
string_length_next <= unsigned(data_in_swapped);
stage_next <= COMPARE_STRING;
compare_length_next <= (others => '0');
end if;
when COMPARE_STRING =>
-- TODO: FIX (Type Name not handled)
if (empty = '0') then
rd_sig <= '1';
-- Increment compare position counter
compare_length_next <= compare_length + 32;
-- Compare Strings
if (message_type = EDP) then
for i in 0 to ENDPOINT_TOPIC'length-1 loop
if (data_in /= ENDPOINT_TOPIC(i)(to_integer(compare_length) to to_integer(compare_length)+7)) then
endpoint_mask_next(i) <= '0';
end if;
end loop;
elsif (message_type = DPD) then
if (data_in /= DOMAIN_TAG(to_integer(compare_length) to to_integer(compare_length)+7)) then
participant_match_next <= '0';
end if;
end if;
-- End of String (Exit Condition)
-- NOTE: This assumes that the Parameter is padded with zeroes
-- TODO: XTypes 7.4.1.1 requires padding bytes for "PLAIN_CDR" to be zero, but does not specify the value for "PL_CDR"
if (compare_length >= string_length) then
stage_next <= SKIP_PARAMETER;
end if;
end if;
when RXO_DURABILITY =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped > ENDPOINT_DURABILITY(i)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped < ENDPOINT_DURABILITY(i)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_DEADLINE_1 =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped < ENDPOINT_DEADLINE(i)(1)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped > ENDPOINT_DEADLINE(i)(1)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= RXO_DEADLINE_2;
end if;
when RXO_DEADLINE_2 =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped < ENDPOINT_DEADLINE(i)(0)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped > ENDPOINT_DEADLINE(i)(0)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_LIVELINESS =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped > ENDPOINT_LIVELINESS(i)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped < ENDPOINT_LIVELINESS(i)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= RXO_LEASE_DURATION;
cnt_next <= 0;
end if;
when RXO_LEASE_DURATION =>
-- TODO: Convert to two stages to avoid counter complexity?
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped > ENDPOINT_LEASE_DURATION(i)(cnt)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped < ENDPOINT_LIVELINESS(i)(cnt)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
--Increment Counter
cnt_next <= cnt + 1;
-- Exit Condition
if (cnt = 1) then
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
end if;
when LATCH_LEASE_DURATION_1 =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Lease Duration
lease_duration_next(0) <= data_in_swapped;
-- Next Stage
stage_next <= LATCH_LEASE_DURATION_2;
end if;
when LATCH_LEASE_DURATION_2 =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Lease Duration
lease_duration_next(1) <= data_in_swapped;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_RELIABILITY =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped > ENDPOINT_RELIABILITY(i)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped < ENDPOINT_RELIABILITY(i)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
-- NOTE: The max_blocking_time value is ignored
stage_next <= SKIP_PARAMETER;
end if;
when LATCH_LIFESPAN_1 =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Lease Duration
lifespan_duration_next(1) <= data_in_swapped;
-- Next Stage
stage_next <= LATCH_LIFESPAN_2;
end if;
when LATCH_LIFESPAN_2 =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Lease Duration
lifespan_duration_next(0) <= data_in_swapped;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_DESTINATION_ORDER =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped > ENDPOINT_DESTINATION_ORDER(i)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped < ENDPOINT_DESTINATION_ORDER(i)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_OWNERSHIP =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
if (data_in_swapped /= (data_in_swapped'reverse_range => '0')) then
endpoint_mask_next <= (others => '0');
end if;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_PRESENTATION_1 =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in_swapped > ENDPOINT_PRESENTATION(i)) then
endpoint_mask_next(i) <= '0';
end if;
-- data-in is Publisher-Offered
else
if (data_in_swapped < ENDPOINT_PRESENTATION(i)) then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= RXO_PRESENTATION_2;
end if;
when RXO_PRESENTATION_2 =>
if (empty = '0') then
rd_sig <= '1';
-- Check QoS Compatibility
for i in 0 to ENDPOINT_TOPIC'length-1 loop
-- data-in is Subscriber-Requested
if (is_subscriber = '1') then
if (data_in(23) = '1' and ENDPOINT_COHERENT_ACCESS(i) = '0') then
endpoint_mask_next(i) <= '0';
end if;
if (data_in(15) = '1' and ENDPOINT_ORDERED_ACCESS(i) = '0') then
endpoint_mask_next(i) <= '0';
end if;
end if;
end loop;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when RXO_PARTITION =>
if (empty = '0') then
rd_sig <= '1';
--TODO: Implement full partition Name support?
-- NOTE: Endpoints are only matched against the default empty partition.
-- Check QoS Compatibility
if (data_in_swapped /= (data_in_swapped'reverse_range => '0')) then
endpoint_mask_next <= (others => '0');
end if;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when MATCH_DOMAIN_ID =>
if (empty = '0') then
rd_sig <= '1';
-- DEAFULT Stage
stage_next <= SKIP_PARAMETER;
-- MATCH DOMAIN ID
if (data_in_swapped /= DOMAIN_ID) then
-- No Match
participant_match_next <= '0';
end if;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when MATCH_PROTOCOL_VERSION =>
if (empty = '0') then
rd_sig <= '1';
-- DEAFULT Stage
stage_next <= SKIP_PARAMETER;
-- If RTPS Protocol Major Version is not 2, skip packet
if(data_in(31 downto 24) /= PROTOCOLVERSION_2_4(15 downto 8)) then
-- No Match
participant_match_next <= '0';
end if;
-- Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when LATCH_LOCATOR =>
if (empty = '0') then
rd_sig <= '1';
-- Increment Counter (Default)
cnt_next <= cnt + 1;
-- Locator Kind
if (cnt = 1) then
-- Check if UDPv4 Locator
if (data_in_swapped /= LOCATOR_KIND_UDPv4) then
stage_next <= SKIP_PARAMETER;
end if;
-- Locator Port
elsif (cnt = 2) then
-- Latch Source Port
if (addr_latch_index = '0') then
port_latch_1 <= data_in_swapped(port_latch_1'length-1 downto 0);
else
port_latch_2 <= data_in_swapped(port_latch_2'length-1 downto 0);
end if;
-- Locator Addr (IPv4)
elsif (cnt = 6) then
-- Latch Src Addr
if (addr_latch_index = '0') then
addr_latch_1 <= data_in_swapped;
else
addr_latch_2 <= data_in_swapped;
end if;
-- Exit Stage
stage_next <= SKIP_PARAMETER;
end if;
end if;
when LATCH_EXPECTS_INLINE_QOS =>
if (empty = '0') then
rd_sig <= '1';
-- Latch 'expectsInlineQoS'
expects_inline_qos_next <= data_in(24);
stage_next <= SKIP_PARAMETER;
end if;
when LATCH_GUID =>
if (empty = '0') then
rd_sig <= '1';
-- Increment Counter (Default)
cnt_next <= cnt + 1;
-- Check if GUID Prefix valid (Should be the same as the GUID Prefix of the Packet)
-- and update the Entity ID
case (cnt) is
when 1 =>
if (data_in /= guid(0)) then
stage_next <= SKIP_PACKET;
end if;
when 2 =>
if (data_in /= guid(1)) then
stage_next <= SKIP_PACKET;
end if;
when 3 =>
if (data_in /= guid(2)) then
stage_next <= SKIP_PACKET;
end if;
when 4 =>
-- NOTE: Even though the mem_ctrl_prc is currently using the guid signal, it only uses the first
-- 3 bytes (GUIDPrefix) for the SEARCH_PARTICIPANT
guid_next(3) <= data_in;
stage_next <= SKIP_PARAMETER;
end case;
end if;
when CHECK_REMOTE_BUILTIN_ENDPOINTS =>
if (empty = '0') then
rd_sig <= '1';
-- Next Stage
stage_next <= SKIP_PARAMETER;
-- SANITY CHECK (Builtin Participant and Participant Message Endpoints have to be always available)
if ( data_in_swapped(DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER) = '0' or
data_in_swapped(DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR) = '0' or
data_in_swapped(BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER) = '0' or
data_in_swapped(BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER) = '0') then
-- No Match
participant_match_next <= '0';
end if;
-- Check for necessary Builtin Endpoints for Readers
if (NUM_READERS > 0) then
if ( data_in_swapped(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_ANNOUNCER) = '0' or
data_in_swapped(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_DETECTOR) = '0') then
-- No Match
participant_match_next <= '0';
end if;
end if;
-- Check for necessary Builtin Endpoints for Writers
if (NUM_WRITERS > 0) then
if ( data_in_swapped(DISC_BUILTIN_ENDPOINT_SUBSCRIPTIONS_ANNOUNCER) = '0' or
data_in_swapped(DISC_BUILTIN_ENDPOINT_PUBLICATIONS_DETECTOR) = '0') then
-- No Match
participant_match_next <= '0';
end if;
end if;
end if;
when LATCH_BUILTIN_ENDPOINT_QOS =>
if (empty = '0') then
rd_sig <= '1';
-- Latch QoS
extra_flags_next <= data_in_swapped;
-- DEFAULT Next Stage
stage_next <= SKIP_PARAMETER;
end if;
when PARTICIPANT_MATCH_STAGE_1 =>
-- Wait for Participant Search and Sequence Number Process
if (mem_op_done = '1' and seq_prc_done = '1') then
-- No Match in Buffer
if (addr_res = BUILTIN_BUFFER_SIZE) then
-- Participant Match
if (message_type = PDP and participant_match = '1') then
-- Add participant in buffer
deadline_next <= time + lease_duration;
mem_opcode <= INSERT_PARTICIPANT;
start_mem_op <= '1';
-- DONE
stage_next <= SKIP_PACKET;
else
-- Ignore all other messages, since there is no corresponding participant in the buffer.
stage_next <= SKIP_PACKET;
end if;
-- Match in Buffer, Next Sequence Number
-- NOTE: We only process the Sequences in order. This may lead to more traffic being exchanged
-- (since all Data messages with a higher sequence number than the next expected will be ignored),
-- but keeps the logic simple.
elsif (next_seq_nr = seq_nr)
-- Participant
if (message_type = PDP) then
-- Participant Unmatch
if (participant_match = '0') then
-- Remove participant from buffer
mem_opcode <= REMOVE_PARTICIPANT;
start_mem_op <= '1';
-- Find and delete all orphaned endpoints in Buffer
stage_next <= FIND_ORPHAN_ENDPOINT;
else
-- Update Participant Data
mem_opcode <= UPDATE_PARTICIPANT;
-- Update Lease
deadline_next <= time + lease_duration;
update_participant_flags_next <= (PARTICIPANT_DATA_FLAG => '1', LEASE_DEADLINE_FLAG => '1', EXTRA_FLAGS_FLAG => '1', others => '0');
start_mem_op <= '1';
-- DONE
stage_next <= SKIP_PACKET;
end if;
-- Endpoint
elsif (message_type = EDP) then
-- TODO: Should we renew the Participant Lease on Endpoint Activity? - No, it is clearly stated that a participant anouncement has to be received during the lease duration
-- Store new Sequence Number
mem_opcode <= UPDATE_PARTICIPANT;
update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0');
start_mem_op <= '1';
stage_next <= INITIATE_ENDPOINT_SEARCH;
else
-- Ignore
stage_next <= SKIP_PACKET;
end if;
-- Old Sequence Number
else
-- If Participant Anouncement, renew lease deadline
if (message_type = PDP) then
-- Update Lease
mem_opcode <= UPDATE_PARTICIPANT;
deadline_next <= time + lease_duration;
update_participant_flags_next <= (LEASE_DEADLINE_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
-- Done
stage_next <= SKIP_PACKET;
end if;
end if;
-- Help stage, because we need to do two consecutive memory operations
when INITIATE_ENDPOINT_SEARCH =>
if (mem_op_done = '1') then
-- Search Endpoint in Buffer
mem_opcode <= SEARCH_ENDPOINT;
start_mem_op <= '1';
-- DONE
stage_next <= ENDPOINT_MATCH_STAGE;
end if;
when ENDPOINT_MATCH_STAGE =>
-- Wait for Endpoint Search
if (mem_op_done = '1') then
-- No Match in Buffer (New remote Endpoint)
if (addr_res = BUILTIN_BUFFER_SIZE) then
-- At least one local endpoint match
if (endpoint_mask /= (endpoint_mask'range => '0')) then
-- Add endpoint in buffer
mem_opcode <= INSERT_ENDPOINT;
start_mem_op <= '1';
-- Mark UNMATCHES
endpoint_match_next <= endpoint_mask;
endpoint_unmatch_next <= (others => '0');
-- Propagate Match Changes to local Endpoints
stage_next <= INFORM_ENDPOINTS_MATCH;
cnt_next <= 1;
end if;
-- Match in buffer (Existing Endpoint)
else
-- At least one local endpoint match
if (endpoint_mask /= (endpoint_mask'range => '0')) then
tmp_endpoint_mask := convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS);
-- Mark Endpoint match changes
tmp_endpoint_mask := tmp_endpoint_mask xor endpoint_mask;
-- Mark UNMATCHES
endpoint_unmatch_next <= tmp_endpoint_mask xor endpoint_mask;
-- Mark NEW MATCHES
endpoint_match_next <= tmp_endpoint_mask and endpoint_mask;
-- Update endpoint in buffer
mem_opcode <= UPDATE_ENDPOINT;
start_mem_op <= '1';
-- Propagate Match Changes to local Endpoints
stage_next <= INFORM_ENDPOINTS_MATCH;
cnt_next <= 1;
else
-- Remove endpoint from buffer
mem_opcode <= REMOVE_ENDPOINT;
start_mem_op <= '1';
-- Mark UNMATCHES
endpoint_match_next <= (others => '0');
endpoint_unmatch_next <= convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS);
-- Propagate Match Changes to local Endpoints
stage_next <= INFORM_ENDPOINTS_UNMATCH;
cnt_next <= 1;
end if;
end if;
end if;
when FIND_ORPHAN_ENDPOINT =>
if (mem_op_done = '1') then
is_orphan_search_next <= '1';
mem_opcode <= SEARCH_ENDPOINT;
start_mem_op <= '1';
stage_next <= PURGE_ORPHAN_ENDPOINT;
end if;
when PURGE_ORPHAN_ENDPOINT =>
if (mem_op_done = '1') then
-- Orphan Match
if (addr_res /= BUILTIN_BUFFER_SIZE) then
-- Remove orphaned endpoint from buffer
mem_opcode <= REMOVE_ENDPOINT;
start_mem_op <= '1';
-- Mark UNMATCHES
endpoint_match_next <= (others => '0');
endpoint_unmatch_next <= convert_from_bitmask_array(endpoint_mask_array, MAX_ENDPOINTS);
-- Propagate Match Changes to local Endpoints
stage_next <= INFORM_ENDPOINTS_UNMATCH;
cnt_next <= 1;
-- Buffer has no more orphans
else
-- DONE
stage_next <= SKIP_PACKET;
end if;
end if;
when INFORM_ENDPOINTS_MATCH =>
if ((endpoint_match and endpoint_full) = (endpoint_full'range => '0')) then
-- Increment Counter
cnt_next <= cnt + 1;
-- Enable Write
wr_sig <= '1';
case (cnt) is
when 1 =>
output_sig <= OPCODE_MATCH;
when 2 =>
output_sig <= guid(0);
when 3 =>
output_sig <= guid(1);
when 4 =>
output_sig <= guid(2);
when 5 =>
output_sig <= guid(3);
when 6 =>
-- Use Address set by PID
if (addr_latch_1 /= (addr_latch_1'reverse_range => '0')) then
output_sig <= addr_latch_1;
-- Else use the Default Address from Participant
else
output_sig <= mem_def_addr;
end if;
when 7 =>
-- Use Port set by PID
if (port_latch_1 /= (port_latch_1'reverse_range => '0')) then
output_sig <= port_latch_1 & mem_xflags;
-- Else use the Default Port from Participant
else
output_sig <= mem_def_port & mem_xflags;
end if;
-- If there are endpoints to unmatch, inform them
if (endpoint_unmatch /= (endpoint_unmatch'range => '0')) then
stage_next <= INFORM_ENDPOINTS_UNMATCH;
else
-- DONE
stage_next <= SKIP_PACKET;
end if;
end case;
end if;
when INFORM_ENDPOINTS_UNMATCH =>
if ((endpoint_unmatch and endpoint_full) = (endpoint_full'range => '0')) then
-- Increment Counter
cnt_next <= cnt + 1;
-- Enable Write
wr_sig <= '1';
case (cnt) is
when 1 =>
output_sig <= OPCODE_UNMATCH;
when 2 =>
output_sig <= guid(0);
when 3 =>
output_sig <= guid(1);
when 4 =>
output_sig <= guid(2);
when 5 =>
output_sig <= guid(3);
-- If we are in the middle of an orphan purge process, return to the search stage
if (is_orphan_search = '1') then
stage_next <= FIND_ORPHAN_ENDPOINT;
else
-- DONE
stage_next <= SKIP_PACKET;
end if;
end case;
end if;
when STALE_CHECK =>
-- Wait for memory OP
if (mem_op_done = '1') then
-- Found Stale Entry
if (addr_res /= BUILTIN_BUFFER_SIZE) then
-- Participant Lease Expired
-- NOTE: The mem_participant_data is zero initialized on lease expiration, so we check the default address for zero
-- (since the default address should always be set)
if (mem_participant_data.def_addr /= (mem_participant_data.def_addr'reverse_range => '0')) then
-- Remove Participant
mem_opcode <= REMOVE_PARTICIPANT;
start_mem_op <= '1';
stage_next <= AUTO_PURGE;
-- Participant Response Time Reached
else
-- Heartbeat Response
if (is_heartbeat_res = '1') then
-- If Suppression Delay passed, zero the time
if(mem_participant_data.heartbeat_res_time(0) = '1') then
mem_opcode <= UPDATE_PARTICIPANT;
-- Zero Heartbeat Response Time
deadline_next <= (others => '0');
update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0');
start_mem_op <= '1';
-- DONE
stage_next <= IDLE;
-- If Response Delay Passed
else
-- Set Heartbeat Suppression Time
mem_opcode <= UPDATE_PARTICIPANT;
if (TODO /= 0) then
-- Set Heartbeat Suppression Time
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '1';
else
-- Zero Heartbeat Response Time
deadline_next <= (others => '0');
end if;
update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG_FLAG => '1', others => '0');
start_mem_op <= '1';
-- Send Acknack
stage_next <= SEND_ACKNACK;
cnt_next <= 1;
end if;
-- Acknack Response Time
else
-- If Suppression Delay passed, zero the time
if(mem_participant_data.acknack_res_time(0) = '1') then
mem_opcode <= UPDATE_PARTICIPANT;
-- Zero Acknack Response Time
deadline_next <= (others => '0');
update_participant_flags_next <= (ACKNACK_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
-- DONE
stage_next <= IDLE;
-- If Response Delay Passed
else
mem_opcode <= UPDATE_PARTICIPANT;
if (TODO /= 0) then
-- Set Acknack Suppression Time
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '1';
else
-- Zero Acknack Response Time
deadline_next <= (others => '0');
end if;
-- Zero Data Response Flags
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(PUB_DATA_FLAG) <= '0';
extra_flags_next(SUB_DATA_FLAG) <= '0';
extra_flags_next(MES_DATA_FLAG) <= '0';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
-- Send Requested Data
stage_next <= SEND_PUB_DATA;
cnt_next <= 0;
end if;
end if;
end if;
else
-- No Stale Entry Found, DONE
stage_next <= IDLE;
end if;
end if;
when AUTO_PURGE =>
if (mem_op_done = '1') then
-- Help Stage needed to latch the GUID Prefix of the removed staled participant (Needed for the orphan search)
guid_next(0) <= mem_guidprefix(0);
guid_next(1) <= mem_guidprefix(1);
guid_next(2) <= mem_guidprefix(2);
stage_next <= FIND_ORPHAN_ENDPOINT;
end if;
when PROCESS_HEARTBEAT =>
if (empty = '0') then
rd_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
-- Latch Sequence Number
case (cnt) is
when 1 =>
first_seq_nr_next(0) <= data_in;
when 2 =>
first_seq_nr_next(1) <= data_in;
when 3 =>
last_seq_nr_next(0) <= data_in;
when 4 =>
last_seq_nr_next(1) <= data_in;
stage_next <= PROCESS_HEARTBEAT_SEQUENCE_NUMBERS;
end case;
end if;
when PROCESS_HEARTBEAT_SEQUENCE_NUMBERS =>
-- Wait for Sequence Number to be fetched from buffer
if (mem_done = '1' and seq_prc_done = '1') then
-- No scheduled Heartbeat Response
if (mem_participant_data.heartbeat_res_time /= (mem_participant_data.heartbeat_res_time'reverse_range => '0')) then
-- If current sequence number obsolete (removed from source history cache),
-- reset sequence number to expect the first available and request it
if (first_seq_nr > next_seq_nr) then
-- Store expected sequence number -1, since we process only stored sequence number +1
seq_nr_next <= first_seq_nr - 1;
mem_opcode <= UPDATE_PARTICIPANT;
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '0';
update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', HEARTBEAT_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
-- If new sequence number is available or Writer expects ACKNACK, send it
elsif (last_seq_nr > mem_seq_nr or final_flag = '0') then
mem_opcode <= UPDATE_PARTICIPANT;
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '0';
update_participant_flags_next <= (HEARTBEAT_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
-- Currently in Heartbeat Response Delay
elsif (mem_participant_data.heartbeat_res_time(0) = '0') then
-- If current sequence number obsolete (removed from source history cache),
-- reset sequence number to expect the first available and request it
if (first_seq_nr > next_seq_nr) then
-- Store expected sequence number -1, since we process only stored sequence number +1
seq_nr_next <= first_seq_nr - 1;
mem_opcode <= UPDATE_PARTICIPANT;
update_participant_flags_next <= (EDP_SEQ_NR_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
end if;
-- Done
stage_next <= SKIP_PACKET;
end if;
when SEND_ACKNACK =>
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
case (cnt) is
-- OUTPUT HEADER
-- Src IPv4 Address
when 1 =>
output_sig <= DEFAULT_IPv4_MULTICAST_ADDRESS;
-- Dest IPv4 Address
when 2 =>
output_sig <= mem_participant_data.meta_addr;
-- Src and Dest UDPv4 Ports
when 3 =>
output_sig <= META_IPv4_UNICAST_PORT & mem_participant_data.meta_port;
-- RTPS MESSAGE HEADER
when 4 =>
output_sig <= PROTOCOL_RTPS;
when 5 =>
output_sig <= PROTOCOLVERSION_2_4 & VENDORID;
when 6 =>
output_sig <= GUIDPREFIX(0);
when 7 =>
output_sig <= GUIDPREFIX(1);
when 8 =>
output_sig <= GUIDPREFIX(2);
-- ACKNACK RTPS SUBMESSAGE (Publication)
-- RTPS Submessage Header
when 9 =>
output_sig <= SID_ACKNACK & "00000010" & std_logic_vector(to_unsigned(24, 16));
-- Reader Entity ID
when 10 =>
output_sig <= ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR;
-- Writer Entity ID
when 11 =>
output_sig <= ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER;
-- Sequence Number Set (Bitmap Base 1/2)
when 12 =>
output_sig <= mem_participant_data.pub_seq_nr(0);
-- Sequence Number Set (Bitmap Base 2/2)
when 13 =>
output_sig <= mem_participant_data.pub_seq_nr(1);
-- Sequence Number Set (NumBits)
when 14 =>
output_sig <= (others => '0');
-- Count
when 15 =>
output_sig <= count;
-- ACKNACK RTPS SUBMESSAGE (Subscription)
-- RTPS Submessage Header
when 16 =>
output_sig <= SID_ACKNACK & "00000010" & std_logic_vector(to_unsigned(24, 16));
-- Reader Entity ID
when 17 =>
output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR;
-- Writer Entity ID
when 18 =>
output_sig <= ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER;
-- Sequence Number Set (Bitmap Base 1/2)
when 19 =>
output_sig <= mem_participant_data.sub_seq_nr(0);
-- Sequence Number Set (Bitmap Base 2/2)
when 20 =>
output_sig <= mem_participant_data.sub_seq_nr(1);
-- Sequence Number Set (NumBits)
when 21 =>
output_sig <= (others => '0');
-- Count
when 22 =>
output_sig <= count;
-- ACKNACK RTPS SUBMESSAGE (Message)
-- RTPS Submessage Header
when 23 =>
output_sig <= SID_ACKNACK & "00000010" & std_logic_vector(to_unsigned(24, 16));
-- Reader Entity ID
when 24 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER;
-- Writer Entity ID
when 25 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER;
-- Sequence Number Set (Bitmap Base 1/2)
when 26 =>
output_sig <= mem_participant_data.mes_seq_nr(0);
-- Sequence Number Set (Bitmap Base 2/2)
when 27 =>
output_sig <= mem_participant_data.mes_seq_nr(1);
-- Sequence Number Set (NumBits)
when 28 =>
output_sig <= (others => '0');
-- Count
when 29 =>
output_sig <= count;
-- Signal Last Word
last_word_out <= '1';
-- DONE
stage_next <= IDLE;
end case;
end if;
when PROCESS_ACKNACK =>
if (empty = '0') then
rd_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
-- Latch Sequence Number
-- NOTE: Because we always sent the entire history cache, we only need to look at the SequenceNumberSetBase to determine if we need to sent data or not
case (cnt) is
when 1 =>
first_seq_nr_next(0) <= data_in;
when 2 =>
first_seq_nr_next(1) <= data_in;
stage_next <= PROCESS_ACKNACK_SEQUENCE_NUMBERS
end case;
end if;
when PROCESS_ACKNACK_SEQUENCE_NUMBERS =>
-- Wait for Memory Operation to finish
if (mem_done = '1') then
-- No scheduled Acknack Response
if (mem_participant_data.acknack_res_time /= (mem_participant_data.acknack_res_time'reverse_range => '0')) then
case (message_type) is
when EDP =>
-- Subscriber Acknack
if (is_subscriber = '1') then
-- If reader has not acked all Publisher history cache, mark for send
if (first_seq_nr <= PUB_SEQUENCE_NR) then
mem_opcode <= UPDATE_PARTICIPANT;
-- Set Acknack Response Time
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '0';
-- Set Publisher Data as Acknack Response
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(PUB_DATA_FLAG) <= '1';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
-- Publisher Acknack
else
-- If reader has not acked all Subscriber history cache, mark for send
if (first_seq_nr <= SUB_SEQUENCE_NR) then
mem_opcode <= UPDATE_PARTICIPANT;
-- Set Acknack Response Time
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '0';
-- Set Subscriber Data as Acknack Response
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(SUB_DATA_FLAG) <= '1';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
end if;
-- Message Acknack
when MESSAGE =>
-- NOTE: "auto_live_seq_nr" always has the higher sequence number by design, so we just need to
-- check against that
-- If reader has not acked all Message history cache, mark for send
if (first_seq_nr <= auto_live_seq_nr) then
mem_opcode <= UPDATE_PARTICIPANT;
-- Set Acknack Response Time
deadline_next <= time + TODO;
-- NOTE: Last Bit denotes if this is Response or Suppression Delay
deadline_next(0) <= '0';
-- Set Message Data as Acknack Response
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(MES_DATA_FLAG) <= '1';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', ACKNACK_RES_TIME_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
end case;
-- Currently in Acknack Response Delay
elsif (mem_participant_data.acknack_res_time(0) = '0') then
case (message_type) is
when EDP =>
-- Subscriber Acknack
if (is_subscriber = '1') then
-- Publisher Data not scheduled for response
if (mem_participant_data.extra_flags(PUB_DATA_FLAG)) then
-- If reader has not acked all Publisher history cache, mark for send
if (first_seq_nr <= PUB_SEQUENCE_NR) then
mem_opcode <= UPDATE_PARTICIPANT;
-- Set Publisher Data as Acknack Response
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(PUB_DATA_FLAG) <= '1';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
end if;
-- Publisher Acknack
else
-- Subscriber Data not scheduled for response
if (mem_participant_data.extra_flags(SUB_DATA_FLAG)) then
-- If reader has not acked all Subscriber history cache, mark for send
if (first_seq_nr <= SUB_SEQUENCE_NR) then
mem_opcode <= UPDATE_PARTICIPANT;
-- Set Subscriber Data as Acknack Response
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(SUB_DATA_FLAG) <= '1';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
end if;
-- Message Acknack
when MESSAGE =>
-- Message Data not scheduled for response
if (mem_participant_data.extra_flags(MES_DATA_FLAG)) then
-- NOTE: "auto_live_seq_nr" always has the higher sequence number by design, so we just need to
-- check against that
-- If reader has not acked all Message history cache, mark for send
if (first_seq_nr <= auto_live_seq_nr) then
mem_opcode <= UPDATE_PARTICIPANT;
-- Set Message Data as Acknack Response
extra_flags_next <= mem_participant_data.extra_flags;
extra_flags_next(MES_DATA_FLAG) <= '1';
update_participant_flags_next <= (EXTRA_FLAGS_FLAG => '1', others => '0');
start_mem_op <= '1';
end if;
end if;
end case;
end if;
-- Done
stage_next <= SKIP_PACKET;
end if;
when SEND_PUB_DATA =>
-- If Publisher Data not scheduled for response or no Writers available, skip
if (mem_participant_data.extra_flags(PUB_DATA_FLAG) = '0' or NUM_WRITERS = 0) then
stage_next <= SEND_SUB_DATA;
end if;
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
-- Send Data
output_sig <= WRITER_ENDPOINT_DATA.data(cnt);
-- Exit Condition
if (cnt = (WRITER_ENDPOINT_DATA.length-1)) then
last_word_out <= '1';
cnt_next <= 0;
stage_next <= SEND_SUB_DATA;
end if;
end if;
when SEND_SUB_DATA =>
-- If Subscriber Data not scheduled for response or no Readers available, skip
if (mem_participant_data.extra_flags(PUB_DATA_FLAG) = '0' or NUM_READERS = 0) then
stage_next <= SEND_MES_DATA;
end if;
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
-- Send Data
output_sig <= READER_ENDPOINT_DATA.data(cnt);
-- Exit Condition
if (cnt = (READER_ENDPOINT_DATA.length-1)) then
last_word_out <= '1';
cnt_next <= 1;
stage_next <= SEND_MES_DATA;
end if;
end if;
when SEND_MES_DATA =>
-- If Message Data not scheduled for response, skip
if (mem_participant_data.extra_flags(MES_DATA_FLAG) = '0') then
stage_next <= IDLE;
end if;
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
case (cnt) is
-- OUTPUT HEADER
-- Src IPv4 Address
when 1 =>
output_sig <= DEFAULT_IPv4_MULTICAST_ADDRESS;
-- Dest IPv4 Address
when 2 =>
output_sig <= mem_participant_data.meta_addr;
-- Src and Dest UDPv4 Ports
when 3 =>
output_sig <= META_IPv4_UNICAST_PORT & mem_participant_data.meta_port;
-- RTPS MESSAGE HEADER
when 4 =>
output_sig <= PROTOCOL_RTPS;
when 5 =>
output_sig <= PROTOCOLVERSION_2_4 & VENDORID;
when 6 =>
output_sig <= GUIDPREFIX(0);
when 7 =>
output_sig <= GUIDPREFIX(1);
when 8 =>
output_sig <= GUIDPREFIX(2);
cnt_next <= 1;
stage_next <= SEND_MAN_LIVE;
end case;
end if;
when SEND_MES_MAN_LIVE =>
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
case (cnt) is
-- DATA RTPS SUBMESSAGE (Participant Message)
-- RTPS Submessage Header
when 1 =>
output_sig <= SID_DATA & "00000100" & std_logic_vector(to_unsigned(44, 16));
-- ExtraFlags, octetsToInlineQoS
when 2 =>
output_sig <= x"0000" & std_logic_vector(to_unsigned(16, 16));
-- Reader Entity ID
when 3 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER;
-- Writer Entity ID
when 4 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER;
-- Sequence Number 1/2
when 5 =>
output_sig <= man_live_seq_nr(0);
-- Sequence Number 2/2
when 6 =>
output_sig <= man_live_seq_nr(1);
-- Serialized Payload Header
when 7 =>
output_sig <= CDR_BE & x"0000";
-- Serialized Payload BEGIN
-- GUID Prefix 1/3
when 8 =>
output_sig <= GUIDPREFIX(0);
-- GUID Prefix 2/3
when 9 =>
output_sig <= GUIDPREFIX(1);
-- GUID Prefix 3/3
when 10 =>
output_sig <= GUIDPREFIX(3);
-- Participant Message Kind
when 11 =>
output_sig <= PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE;
-- Data Length
when 12 =>
output_sig <= (others => '0');
-- If manual and automatic sequence numbers are not consecutive, we need to send a GAP Message
if (live_gap_start /= auto_live_seq_nr) then
stage_next <= SEND_MES_GAP;
cnt_next <= 1;
-- Else Continue with Automatic Liveliness
else
stage_next <= SEND_MES_AUTO_LIVE;
cnt_next <= 1;
end if;
end case;
end if;
when SEND_MES_GAP =>
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
case (cnt) is
-- DATA RTPS SUBMESSAGE (Participant Message)
-- RTPS Submessage Header
when 1 =>
output_sig <= SID_GAP & "00000000" & std_logic_vector(to_unsigned(28, 16));
-- Reader Entity ID
when 2 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER;
-- Writer Entity ID
when 3 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER;
-- GAP Start Sequence Number 1/2
when 4 =>
output_sig <= live_gap_start(0);
-- GAP Start Sequence Number 2/2
when 5 =>
output_sig <= live_gap_start(1);
-- GAP End Sequence Number Set (Bitmap Base 1/2)
when 6 =>
output_sig <= live_gap_end(0);
-- GAP End Sequence Number Set (Bitmap Base 2/2)
when 7 =>
output_sig <= live_gap_end(1);
-- GAP End Sequence Number Set (NumBits)
when 8 =>
output_sig <= (others => '0');
stage_next <= SEND_MES_AUTO_LIVE;
cnt_next <= 1;
end case;
end if;
when SEND_MES_AUTO_LIVE =>
if (rtps_full = '0') then
wr_sig <= '1';
--Increment Counter
cnt_next <= cnt + 1;
case (cnt) is
-- DATA RTPS SUBMESSAGE (Participant Message)
-- RTPS Submessage Header
when 1 =>
output_sig <= SID_DATA & "00000100" & std_logic_vector(to_unsigned(44, 16));
-- ExtraFlags, octetsToInlineQoS
when 2 =>
output_sig <= x"0000" & std_logic_vector(to_unsigned(16, 16));
-- Reader Entity ID
when 3 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER;
-- Writer Entity ID
when 4 =>
output_sig <= ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER;
-- Sequence Number 1/2
when 5 =>
output_sig <= auto_live_seq_nr(0);
-- Sequence Number 2/2
when 6 =>
output_sig <= auto_live_seq_nr(1);
-- Serialized Payload Header
when 7 =>
output_sig <= CDR_BE & x"0000";
-- Serialized Payload BEGIN
-- GUID Prefix 1/3
when 8 =>
output_sig <= GUIDPREFIX(0);
-- GUID Prefix 2/3
when 9 =>
output_sig <= GUIDPREFIX(1);
-- GUID Prefix 3/3
when 10 =>
output_sig <= GUIDPREFIX(3);
-- Participant Message Kind
when 11 =>
output_sig <= PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE;
-- Data Length
when 12 =>
output_sig <= (others => '0');
last_word_out <= '1';
stage_next <= IDLE;
end case;
end if;
--#############################
when SKIP_PARAMETER =>
-- End of Parameter
if (read_cnt > parameter_end) then
-- Begin parsing of next parameter
stage_next <= PROCESS_PL;
elsif (empty = '0') then
rd_sig <= '1';
if (read_cnt = parameter_end) then
-- Begin parsing of next parameter
stage_next <= PROCESS_PL;
end if;
end if;
when SKIP_PACKET =>
if (last_word_in_latch = '1') then
-- Begin parsing of next parameter
stage_next <= IDLE;
elsif (empty = '0') then
rd_sig <= '1';
-- End of Packet
if (last_word_in = '1') then
-- Continue parsing next packet
stage_next <= IDLE;
end if;
end if;
when others =>
null;
end case;
end process;
mem_op_busy <= not mem_op_done;
mem_ctrl_prc : process(all)
variable tmp : unsigned(mem_addr_base'range) := (others => '0');
variable tmp2 : unsigned(mem_addr_base'range) := (others => '0');
variable tmp3 : unsigned(mem_addr_base'range) := (others => '0');
begin
-- DEFAULT
mem_op_done <= '0';
mem_stage_next <= mem_stage;
mem_addr_base_next <= mem_addr_base;
mem_addr_next <= mem_addr;
mem_rd <= '0';
mem_wr <= '0';
addr_res_next <= addr_res;
mem_cnt_next <= mem_cnt;
mem_seq_nr_next <= mem_seq_nr;
orphan_entityid_next <= orphan_entityid;
mem_def_addr_next <= mem_def_addr;
mem_def_port_next <= mem_def_port;
mem_xflags_next <= mem_xflags;
last_addr_next <= last_addr;
mem_participant_data_next <= mem_participant_data;
is_heartbeat_res_next <= is_heartbeat_res;
case (mem_stage) is
when IDLE =>
mem_op_done <= '1';
reset_max_pointer_next <= '0';
if (start_mem_op = '1') then
case(mem_opcode) is
when SEARCH_PARTICIPANT =>
mem_stage_next <= SEARCH_PARTICIPANT;
tmp := (others => '0');
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
when SEARCH_ENDPOINT =>
mem_stage_next <= SEARCH_ENDPOINT;
tmp := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, mem_addr_base'length);
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
when REMOVE_PARTICIPANT =>
mem_stage_next <= REMOVE_PARTICIPANT;
mem_addr_next <= addr_res;
mem_cnt_next <= 1;
when REMOVE_ENDPOINT =>
mem_stage_next <= REMOVE_ENDPOINT;
mem_addr_next <= addr_res;
mem_cnt_next <= 1;
when UPDATE_ENDPOINT =>
mem_stage_next <= UPDATE_ENDPOINT;
mem_addr_next <= addr_res + 4;
mem_cnt_next <= 0;
endpoint_mask_array_next <= convert_to_bitmask_array(endpoint_mask);
when INSERT_PARTICIPANT =>
mem_stage_next <= FIND_PARTICIPANT_SLOT;
tmp := (others => '0');
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
mem_cnt_next <= 0;
when INSERT_ENDPOINT =>
mem_stage_next <= FIND_ENDPOINT_SLOT;
tmp := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, mem_addr_base'length);
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
mem_cnt_next <= 0;
when RESET_MAX_PARTICIPANT_POINTER =>
mem_stage_next <= FIND_PARTICIPANT_SLOT;
tmp := (others => '0');
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
mem_cnt_next <= 0;
reset_max_pointer_next <= '1';
last_addr_next <= (others => '0');
when RESET_MAX_ENDPOINT_POINTER =>
mem_stage_next <= FIND_ENDPOINT_SLOT;
tmp := to_unsigned(BUILTIN_BUFFER_SIZE - ENDPOINT_FRAME_SIZE, mem_addr_base'length);
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
mem_cnt_next <= 0;
reset_max_pointer_next <= '1';
last_addr_next <= to_unsigned(BUILTIN_BUFFER_SIZE, mem_addr_base'length);
when FIND_STALE_PARTICIPANT =>
mem_stage_next <= FIND_STALE_PARTICIPANT;
tmp := (others => '0');
mem_addr_base_next <= tmp;
mem_addr_next <= tmp;
mem_cnt_next <= 0;
when UPDATE_PARTICIPANT =>
mem_stage_next <= UPDATE_PARTICIPANT;
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_addr_next <= addr_res + 3;
mem_cnt_next <= 1;
elsif (update_participant_flags(LEASE_DEADLINE_FLAG) = '1') then
mem_addr_next <= addr_res + 10;
mem_cnt_next <= 8;
elsif (update_participant_flags(EXTRA_FLAGS_FLAG) = '1') then
mem_addr_next <= addr_res + 12;
mem_cnt_next <= 10;
elsif (update_participant_flags(ACKNACK_RES_TIME_FLAG) = '1') then
mem_addr_next <= addr_res + 13;
mem_cnt_next <= 11;
elsif (update_participant_flags(HEARTBEAT_RES_TIME_FLAG) = '1') then
mem_addr_next <= addr_res + 15;
mem_cnt_next <= 13;
elsif (update_participant_flags(EDP_SEQ_NR_FLAG) = '1') then
mem_addr_next <= addr_res + 17;
mem_cnt_next <= 15;
end if;
when others =>
null;
end case;
end if;
when SEARCH_PARTICIPANT =>
mem_rd <= '1';
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Next Participant Frame Address
tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE;
case (mem_cnt) is
when 0 =>
-- Preload
-- Reached MAX Addr, No Match Found
if (mem_addr_base = max_participant_addr) then
addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length); --No match
mem_stage_next <= IDLE;
end if;
when 1 =>
-- No Match
if (mem_read_data /= guid(0)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
end if;
when 2 =>
-- No Match
if (mem_read_data /= guid(1)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
end if;
when 3 =>
-- No Match
if (mem_read_data /= guid(2)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
-- Match
else
-- Fetch Participant Data
mem_stage_next <= GET_PARTICIPANT_DATA;
-- No preload needed
mem_cnt_next <= 1;
end if;
end case;
when GET_PARTICIPANT_DATA =>
mem_rd <= '1';
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
case (mem_cnt) is
when 0 =>
-- Memory Preload
null;
when 1 =>
-- Metatraffic IPv4 Address
mem_participant_data_next.meta_addr <= mem_read_data;
when 2 =>
-- Default Endpoint IPv4 Address
mem_participant_data_next.def_addr <= mem_read_data;
when 3 =>
-- UDPv4 Ports
mem_participant_data_next.meta_port <= mem_read_data(31 downto 16);
mem_participant_data_next.def_port <= mem_read_data(15 downto 0);
when 4 =>
-- SPDP Sequence Number 1/2
mem_participant_data_next.spdp_seq_nr(0) <= unsigned(mem_read_data);
when 5 =>
-- SPDP Sequence Number 2/2
mem_participant_data_next.spdp_seq_nr(1) <= unsigned(mem_read_data);
when 6 =>
-- Lease Duration 1/2
mem_participant_data_next.lease_duration(0) <= unsigned(mem_read_data);
when 7 =>
-- Lease Duration 2/2
mem_participant_data_next.lease_duration(1) <= unsigned(mem_read_data);
when 8 =>
-- Lease Deadline 1/2
mem_participant_data_next.lease_deadline(0) <= unsigned(mem_read_data);
when 9 =>
-- Lease Deadline 2/2
mem_participant_data_next.lease_deadline(1) <= unsigned(mem_read_data);
when 10 =>
-- Extra Flags
mem_participant_data_next.extra_flags <= mem_read_data;
when 11 =>
-- ACKNACK DEADLINE 1/2
mem_participant_data_next.acknack_res_time(0) <= unsigned(mem_read_data);
when 12 =>
-- ACKNACK DEADLINE 2/2
mem_participant_data_next.acknack_res_time(1) <= unsigned(mem_read_data);
when 13 =>
-- HEARTBEAT DEADLINE 1/2
mem_participant_data_next.heartbeat_res_time(0) <= unsigned(mem_read_data);
when 14 =>
-- HEARTBEAT DEADLINE 2/2
mem_participant_data_next.heartbeat_res_time(1) <= unsigned(mem_read_data);
when 15 =>
-- Publication Sequence Number 1/2
mem_participant_data_next.pub_seq_nr(0) <= unsigned(mem_read_data);
when 16 =>
-- Publication Sequence Number 2/2
mem_participant_data_next.pub_seq_nr(1) <= unsigned(mem_read_data);
when 17 =>
-- Subscription Sequence Number 1/2
mem_participant_data_next.sub_seq_nr(0) <= unsigned(mem_read_data);
when 18 =>
-- Subscription Sequence Number 2/2
mem_participant_data_next.sub_seq_nr(1) <= unsigned(mem_read_data);
when 19 =>
-- Participant Message Sequence Number 1/2
mem_participant_data_next.mes_seq_nr(0) <= unsigned(mem_read_data);
when 20 =>
-- Participant Message Sequence Number 2/2
mem_participant_data_next.mes_seq_nr(1) <= unsigned(mem_read_data);
-- DONE
mem_stage_next <= IDLE;
end case;
when SEARCH_ENDPOINT =>
mem_rd <= '1';
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Next Endpoint Frame Address
tmp := mem_addr_base - ENDPOINT_FRAME_SIZE;
case (mem_cnt) is
when 0 =>
-- Reached MAX Addr, No Match Found
if (mem_addr_base = max_endpoint_addr) then
addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length);; -- No match
mem_stage_next <= IDLE;
end if;
when 1 =>
-- If we search for orphan endpoint, ignore Entity id match and latch it for later use
if (is_orphan_search = '1') then
orphan_entityid_next <= mem_read_data;
else
-- No Match
-- NOTE: Endpoint GUID is stored with Entity ID first, and then the GUID Prefix
if (mem_read_data /= guid(3)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
end if;
end if;
when 2 =>
-- No Match
if (mem_read_data /= guid(0)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
end if;
when 3 =>
-- No Match
if (mem_read_data /= guid(1)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
end if;
when 4 =>
-- No Match
if (mem_read_data /= guid(2)) then
-- Continue Search
mem_addr_next <= tmp;
mem_addr_base <= tmp;
mem_cnt_next <= 0;
-- Match Found
else
mem_stage_next <= GET_ENDPOINT_MASK;
mem_cnt_next <= 0;
end if;
end case;
when GET_ENDPOINT_MASK =>
mem_rd <= '1';
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Latch Endpoint Bitmask
-- TODO: Use a different integer ranged in the smalled possible range?
endpoint_mask_array_next(mem_cnt) <= mem_read_data;
-- Exit Condition
if (mem_cnt = ENDPOINT_BITMASK_SIZE-1) then
-- DONE
mem_stage_next <= IDLE;
end if;
when REMOVE_PARTICIPANT =>
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Latch Participant GUID Prefix, and then overwrite with GUIDPREFIX_UNKNOWN to mark as empty
case (mem_cnt) is
when 0 =>
-- Preload
mem_rd <= '1';
when 1 =>
mem_rd <= '1';
mem_guidprefix_next(0) <= mem_read_data;
when 2 =>
mem_rd <= '1';
mem_guidprefix_next(1) <= mem_read_data;
when 3 =>
mem_rd <= '1';
mem_guidprefix_next(2) <= mem_read_data;
mem_addr_next <= addr_res;
when 4 =>
mem_wr <= '1';
mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(0);
when 5 =>
mem_wr <= '1';
mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(1);
when 6 =>
mem_wr <= '1';
mem_write_data <= GUIDPREFIX_UNKNOWN_ARRAY(2);
-- DONE
mem_stage_next <= RESET_MAX_PARTICIPANT_POINTER;
when others =>
null;
end case;
when REMOVE_ENDPOINT =>
mem_wr <= '1';
mem_write_data <= ENTITYID_UNKNOWN;
-- DONE
mem_stage_next <= RESET_MAX_ENDPOINT_POINTER;
when UPDATE_ENDPOINT =>
mem_wr <= '1';
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
mem_write_data <= endpoint_mask_array(mem_cnt);
-- Exit Condition
if (mem_cnt = ENDPOINT_BITMASK_SIZE-1) then
-- DONE
mem_stage_next <= IDLE;
end if;
when FIND_PARTICIPANT_SLOT =>
mem_rd <= '1';
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Next Participant Frame Address
tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE;
case (mem_cnt) is
when 0 =>
-- Preload
-- Reached MAX Addr
if (mem_addr_base = max_participant_addr) then
if (reset_max_pointer = '1') then
-- Reset "max_participant_addr" to first free slot after last occupied slot
if (last_addr /= (last_addr'reverse_range => '0')) then
max_participant_addr_next <= last_addr;
end if;
-- DONE (reset pointer)
mem_stage_next <= IDLE;
-- MEMORY COLLISION
-- XXX: Posible worst case path (addition and comparison same clock)
elsif (tmp > max_endpoint_addr) then
-- Ignore Insertion
mem_stage_next <= IDLE;
else
-- Extend Participant Memory Area
-- NOTE: "max_participant_addr" points to the first address after the last participant frame
max_participant_addr_next <= tmp;
-- DONE
mem_stage_next <= INSERT_PARTICIPANT;
mem_cnt_next <= 1;
end if;
end if;
when 1 =>
if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(0)) then
mem_addr_next <= tmp;
mem_addr_base_next <= tmp;
mem_cnt_next <= 0;
last_addr_next <= (others => '0');
end if;
when 2 =>
if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(1)) then
mem_addr_next <= tmp;
mem_addr_base_next <= tmp;
mem_cnt_next <= 0;
last_addr_next <= (others => '0');
end if;
when 3 =>
if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(2)) then
mem_addr_next <= tmp;
mem_addr_base_next <= tmp;
mem_cnt_next <= 0;
last_addr_next <= (others => '0');
else
-- If "reset_max_pointer" is set, go through all the participant memory area to reset the pointer
if (reset_max_pointer = '1') then
-- Max pointer reset logic
-- Store first free slot address after occupied slot
if (last_addr /= (last_addr'reverse_range => '0')) then
last_addr_next <= mem_addr_base;
end if;
else
-- Found Empty Slot, DONE
mem_stage_next <= INSERT_PARTICIPANT;
mem_cnt_next <= 1;
end if;
end if;
end case;
when INSERT_PARTICIPANT =>
mem_wr <= '1';
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
case (mem_cnt) is
when 1 =>
-- GUIDPrefix 1/3
mem_write_data <= guid(0);
when 2 =>
-- GUIDPrefix 2/3
mem_write_data <= guid(1);
when 3 =>
-- GUIDPrefix 3/3
mem_write_data <= guid(2);
when 4 =>
-- Metatraffic IPv4 Address
mem_write_data <= addr_latch_2;
when 5 =>
-- Default Endpoint IPv4 Address
mem_write_data <= addr_latch_1;
when 6 =>
-- UDPv4 Ports
mem_write_data <= port_latch_2 & port_latch_1;
when 7 =>
-- SPDP Sequence Number 1/2
mem_write_data <= std_logic_vector(seq_nr(0));
when 8 =>
-- SPDP Sequence Number 2/2
mem_write_data <= std_logic_vector(seq_nr(1));
when 9 =>
-- Lease Duration 1/2
mem_write_data <= std_logic_vector(lease_duration(0));
when 10 =>
-- Lease Duration 2/2
mem_write_data <= std_logic_vector(lease_duration(1));
when 11 =>
-- Lease Deadline 1/2
mem_write_data <= std_logic_vector(lease_deadline(0));
when 12 =>
-- Lease Deadline 2/2
mem_write_data <= std_logic_vector(lease_deadline(1));
when 13 =>
-- Extra Flags
mem_write_data <= extra_flags;
when 14 =>
-- ACKNACK DEADLINE 1/2
mem_write_data <= (others => '0');
when 15 =>
-- ACKNACK DEADLINE 2/2
mem_write_data <= (others => '0');
when 16 =>
-- HEARTBEAT DEADLINE 1/2
mem_write_data <= (others => '0');
when 17 =>
-- HEARTBEAT DEADLINE 2/2
mem_write_data <= (others => '0');
when 18 =>
-- Publication Sequence Number 1/2
mem_write_data <= (others => '0');
when 19 =>
-- Publication Sequence Number 2/2
mem_write_data <= (others => '0');
when 20 =>
-- Subscription Sequence Number 1/2
mem_write_data <= (others => '0');
when 21 =>
-- Subscription Sequence Number 2/2
mem_write_data <= (others => '0');
when 22 =>
-- Participant Message Sequence Number 1/2
mem_write_data <= (others => '0');
when 23 =>
-- Participant Message Sequence Number 2/2
mem_write_data <= (others => '0');
end case;
when FIND_ENDPOINT_SLOT =>
mem_rd <= '1';
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Next Endpoint Frame Address
tmp := mem_addr_base - ENDPOINT_FRAME_SIZE;
case (mem_cnt) is
when 0 =>
-- Preload
-- Exceeded MAX Addr
if (mem_addr_base > max_endpoint_addr) then
if (reset_max_pointer = '1') then
-- Reset "max_endpoint_addr" to last occupied slot
if (last_addr /= BUILTIN_BUFFER_SIZE) then
max_endpoint_addr_next <= last_addr;
end if;
-- DONE (reset pointer)
mem_stage_next <= IDLE;
-- MEMORY COLLISION
elsif (mem_addr_base < max_participant_addr) then
-- Ignore Insertion
mem_stage_next <= IDLE;
else
-- Extend Participant Memory Area
-- NOTE: "max_endpoint_addr" points to the beginning of the last endpoint frame
max_endpoint_addr <= mem_addr_base;
-- DONE
mem_stage_next <= INSERT_PARTICIPANT;
mem_cnt_next <= 1;
end if;
end if;
when 1 =>
if (mem_read_data /= ENTITYID_UNKNOWN) then
mem_addr_next <= tmp;
mem_addr_base_next <= tmp;
mem_cnt_next <= 0;
-- Store last occupied endpoint slot
last_addr_next <= mem_addr_base;
else
-- If "reset_max_pointer" is set, go through all the endpoint memory area to reset the pointer
if (reset_max_pointer = '0') then
-- Found Empty Slot, DONE
mem_stage_next <= INSERT_ENDPOINT;
mem_cnt_next <= 1;
end if;
end if;
end case;
when INSERT_ENDPOINT =>
mem_wr <= '1';
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
case (mem_cnt) is
when 1 =>
-- Entity ID
mem_write_data <= guid(3);
when 2 =>
-- GUIDPrefix 1/3
mem_write_data <= guid(0);
when 3 =>
-- GUIDPrefix 2/3
mem_write_data <= guid(1);
when 4 =>
-- GUIDPrefix 3/3
mem_write_data <= guid(2);
-- Write endpoint bitmask via update method
mem_stage_next <= UPDATE_ENDPOINT;
mem_cnt_next <= 0;
endpoint_mask_array_next <= convert_to_bitmask_array(endpoint_mask);
end case;
when FIND_STALE_PARTICIPANT =>
mem_rd <= '1';
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
-- Next Participant Frame Address
tmp := mem_addr_base + PARTICIPANT_FRAME_SIZE;
tmp2 := mem_addr_base + 11;
tmp3 := mem_addr_base + 3;
case (mem_cnt) is
when 0 =>
-- Preload
-- Reached MAX Addr, No Match Found
if (mem_addr_base = max_participant_addr) then
addr_res_next <= to_unsigned(BUILTIN_BUFFER_SIZE, addr_res'length); --No match
mem_stage_next <= IDLE;
end if;
when 1 =>
-- If slot occupied, jump to stale check
if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(0)) then
mem_addr_next <= tmp2;
mem_cnt_next <= 4;
end if;
when 2 =>
-- If slot occupied, jump to stale check
if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(1)) then
mem_addr_next <= tmp2;
mem_cnt_next <= 4;
end if;
when 3 =>
-- If slot occupied, jump to stale check
if (mem_read_data /= GUIDPREFIX_UNKNOWN_ARRAY(2)) then
mem_addr_next <= tmp2;
mem_cnt_next <= 4;
-- Slot empty, check next slot
else
mem_addr_next <= tmp;
mem_addr_base_next <= tmp;
mem_cnt_next <= 0;
end if;
when 4 =>
-- Preload
null;
when 5 =>
-- Lease Deadline passed, mark participant
if (unsigned(mem_read_data) < time(0)) then
addr_res_next <= mem_addr_base;
-- Mark that this is a stale participant
mem_participant_data_next <= ZERO_PARTICIPANT_DATA;
-- DONE
mem_stage_next <= IDLE;
end if;
when 6 =>
-- Lease Deadline passed, mark participant
if (unsigned(mem_read_data) < time(1)) then
addr_res_next <= mem_addr_base;
-- Mark that this is a stale participant
mem_participant_data_next <= ZERO_PARTICIPANT_DATA;
-- DONE
mem_stage_next <= IDLE;
end if;
when 7 =>
-- Heartbeat Deadline passed, mark participant
if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(0)) then
addr_res_next <= mem_addr_base;
-- Fetch Participant Data
mem_addr_next <= tmp3;
mem_cnt_next <= 0;
mem_stage_next <= GET_PARTICIPANT_DATA;
-- Mark as Heartbeat deadline miss
is_heartbeat_res_next <= '1';
end if;
when 8 =>
-- Heartbeat Deadline passed, mark participant
if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(1)) then
addr_res_next <= mem_addr_base;
-- Fetch Participant Data
mem_addr_next <= tmp3;
mem_cnt_next <= 0;
mem_stage_next <= GET_PARTICIPANT_DATA;
-- Mark as Heartbeat deadline miss
is_heartbeat_res_next <= '1';
end if;
when 9 =>
-- Acknack Deadline passed, mark participant
if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(0)) then
addr_res_next <= mem_addr_base;
-- Fetch Participant Data
mem_addr_next <= tmp3;
mem_cnt_next <= 0;
mem_stage_next <= GET_PARTICIPANT_DATA;
-- Mark as Acknack deadline miss
is_heartbeat_res_next <= '0';
end if;
when 10 =>
-- Acknack Deadline passed, mark participant
if (mem_read_data /= (mem_read_data'reverse_range => '0') and unsigned(mem_read_data) < time(1)) then
addr_res_next <= mem_addr_base;
-- Fetch Participant Data
mem_addr_next <= tmp3;
mem_cnt_next <= 0;
mem_stage_next <= GET_PARTICIPANT_DATA;
-- Mark as Acknack deadline miss
is_heartbeat_res_next <= '0';
-- No deadline expired, check next slot
else
mem_addr_next <= tmp;
mem_addr_base_next <= tmp;
mem_cnt_next <= 0;
end if;
end case;
when UPDATE_PARTICIPANT =>
-- Increment counter
mem_cnt_next <= mem_cnt + 1;
-- Default Address Increment
mem_addr_next <= mem_addr + 1;
case (mem_cnt) is
when 1 =>
-- Metatraffic IPv4 Address
mem_write_data <= addr_latch_2;
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
when 2 =>
-- Default Endpoint IPv4 Address
mem_write_data <= addr_latch_1;
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
when 3 =>
-- UDPv4 Ports
mem_write_data <= port_latch_2 & port_latch_1;
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
when 4 =>
-- SPDP Sequence Number 1/2
mem_write_data <= std_logic_vector(seq_nr(0));
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
when 5 =>
-- SPDP Sequence Number 2/2
mem_write_data <= std_logic_vector(seq_nr(1));
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
when 6 =>
-- Lease Duration 1/2
mem_write_data <= std_logic_vector(lease_duration(0));
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
when 7 =>
-- Lease Duration 2/2
mem_write_data <= std_logic_vector(lease_duration(1));
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
-- If nothing else to update, skip
if (update_participant_flags(5 downto 1) = (5 downto 1 => '0')) then
mem_stage_next <= IDLE;
end if;
when 8 =>
-- Lease Deadline 1/2
mem_write_data <= std_logic_vector(lease_deadline(0));
if (update_participant_flags(LEASE_DEADLINE_FLAG) = '1') then
mem_wr <= '1';
end if;
when 9 =>
-- Lease Deadline 2/2
mem_write_data <= std_logic_vector(lease_deadline(1));
if (update_participant_flags(LEASE_DEADLINE_FLAG) = '1') then
mem_wr <= '1';
end if;
-- If nothing else to update, skip
if (update_participant_flags(5 downto 2) = (5 downto 2 => '0')) then
mem_stage_next <= IDLE;
end if;
when 10 =>
-- Extra Flags
mem_write_data <= extra_flags;
if (update_participant_flags(PARTICIPANT_DATA_FLAG) = '1') then
mem_wr <= '1';
end if;
-- If nothing else to update, skip
if (update_participant_flags(5 downto 3) = (5 downto 3 => '0')) then
mem_stage_next <= IDLE;
end if;
when 11 =>
-- ACKNACK DEADLINE 1/2
mem_write_data <= std_logic_vector(acknack_res_time(0));
if (update_participant_flags(ACKNACK_RES_TIME_FLAG) = '1') then
mem_wr <= '1';
end if;
when 12 =>
-- ACKNACK DEADLINE 2/2
mem_write_data <= std_logic_vector(acknack_res_time(1));
if (update_participant_flags(ACKNACK_RES_TIME_FLAG) = '1') then
mem_wr <= '1';
end if;
-- If nothing else to update, skip
if (update_participant_flags(5 downto 4) = (5 downto 4 => '0')) then
mem_stage_next <= IDLE;
end if;
when 13 =>
-- HEARTBEAT DEADLINE 1/2
mem_write_data <= std_logic_vector(heartbeat_res_time(0));
if (update_participant_flags(HEARTBEAT_RES_TIME_FLAG) = '1') then
mem_wr <= '1';
end if;
when 14 =>
-- HEARTBEAT DEADLINE 2/2
mem_write_data <= std_logic_vector(heartbeat_res_time(1));
if (update_participant_flags(HEARTBEAT_RES_TIME_FLAG) = '1') then
mem_wr <= '1';
end if;
-- If nothing else to update, skip
if (update_participant_flags(5 downto 5) = (5 downto 5 => '0')) then
mem_stage_next <= IDLE;
end if;
when 15 =>
-- Publication Sequence Number 1/2
mem_write_data <= std_logic_vector(seq_nr(0));
if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '0') then
mem_wr <= '1';
end if;
when 16 =>
-- Publication Sequence Number 2/2
mem_write_data <= std_logic_vector(seq_nr(1));
if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '0') then
mem_wr <= '1';
end if;
when 17 =>
-- Subscription Sequence Number 1/2
mem_write_data <= std_logic_vector(seq_nr(0));
if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '1') then
mem_wr <= '1';
end if;
when 18 =>
-- Subscription Sequence Number 2/2
mem_write_data <= std_logic_vector(seq_nr(1));
if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = EDP and is_subscriber = '1') then
mem_wr <= '1';
end if;
when 19 =>
-- Participant Message Sequence Number 1/2
mem_write_data <= std_logic_vector(seq_nr(0));
if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = MESSAGE) then
mem_wr <= '1';
end if;
when 20 =>
-- Participant Message Sequence Number 2/2
mem_write_data <= std_logic_vector(seq_nr(1));
if (update_participant_flags(EDP_SEQ_NR_FLAG) = '1' and message_type = MESSAGE) then
mem_wr <= '1';
end if;
mem_stage_next <= IDLE;
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 <= to_unsigned(1, read_cnt'length);
-- Increment read counter each time rd is high
elsif (rd_sig = '1') then
read_cnt <= read_cnt + 1;
end if;
end if;
end process;
end architecture;