3102 lines
162 KiB
VHDL
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;
|