From d54bf55b46bec4948fbe5ab7ae3bfb940616a898 Mon Sep 17 00:00:00 2001 From: Greek Date: Fri, 29 Jan 2021 11:50:22 +0100 Subject: [PATCH] Redo Memory Interface of RTPS Endpoint The Memory Control Process is made more generic (with less specialised code), to allow the main process more control. I.e. all Memory Frame Fields are individually addressable (during GET and UPDATE). The RAM instance is hidden behind a Memory Controller with Flow Control Signals, allowing easy future integration to different Memory Interfaces (e.g. AXI Lite). --- src/REF.txt | 49 +- src/mem_ctrl.vhd | 98 ++ src/rtps_config_package.vhd | 12 + src/rtps_endpoint.vhd | 1944 ++++++++++++++++++++++------------- src/rtps_package.vhd | 1 + 5 files changed, 1406 insertions(+), 698 deletions(-) create mode 100644 src/mem_ctrl.vhd diff --git a/src/REF.txt b/src/REF.txt index 3407e34..4ad2f1d 100644 --- a/src/REF.txt +++ b/src/REF.txt @@ -303,6 +303,9 @@ ENDPOINT LIVELINESS UPDATE LOCAL ENDPOINT BUFFER ===================== + +READER +------ 31............24..............16..............8...............0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-------------------------------------------------------------+ @@ -315,21 +318,55 @@ LOCAL ENDPOINT BUFFER 03| | +-------------------------------------------------------------+ 04| IPv4_ADDRESS | [Reliable Only] - +-----------------------------+-----------------------------+-+ -05| UDP_PORT | UNUSED |Q| [Reliable Only] - +-----------------------------+-----------------------------+-+ + +-----------------------------+-------------------------------+ +05| UDP_PORT | UNUSED | [Reliable Only] + +-----------------------------+-------------------------------+ +06| | + + NEXT_SEQ_NR + +07| | + +-------------------------------------------------------------+ +08| | + + LEASE_DEADLINE + +09| | + +-------------------------------------------------------------+ +10| | + + RES_TIME + [Reliable Only] +11| | + +-------------------------------------------------------------+ + +WRITER +------ + 31............24..............16..............8...............0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-------------------------------------------------------------+ +00| ENTITYID | + +-------------------------------------------------------------+ +01| | + + + +02| GUIDPREFIX | + + + +03| | + +-------------------------------------------------------------+ +04| IPv4_ADDRESS | [Reliable Only] + +-----------------------------+---------------------------+-+-+ +05| UDP_PORT | UNUSED |P|Q| [Reliable Only] + +-----------------------------+---------------------------+-+-+ 06| | + LEASE_DEADLINE + 07| | +-------------------------------------------------------------+ -08| | - + RES_TIME + [Reliable Only] +08| | + + GAP_LOW_SEQ_NR + [Reliable Only] 09| | +-------------------------------------------------------------+ 10| | - + NEXT_SEQ_NR + + + GAP_HIGH_SEQ_NR + [Reliable Only] 11| | +-------------------------------------------------------------+ +12| | + + RES_TIME + [Reliable Only] +13| | + +-------------------------------------------------------------+ HISTORY CACHE diff --git a/src/mem_ctrl.vhd b/src/mem_ctrl.vhd new file mode 100644 index 0000000..190ceba --- /dev/null +++ b/src/mem_ctrl.vhd @@ -0,0 +1,98 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity mem_ctrl is + generic ( + ADDR_WIDTH : natural; + DATA_WIDTH : natural; + MEMORY_DEPTH : natural; + MAX_BURST_LENGTH : natural + ); + port ( + clk : in std_logic; + reset : in std_logic; + addr : in std_logic_vector(ADDR_WIDTH-1 downto 0); + read : in std_logic; + ready_in : out std_logic; + valid_in : in std_logic; + data_in : in std_logic_vector(DATA_WIDTH-1 downto 0); + ready_out : in std_logic; + valid_out : out std_logic; + data_out : out std_logic_vector(DATA_WIDTH-1 downto 0) + ); +end entity; + +architecture arch of mem_ctrl is + + -- *CONSTANT DECLARATION* + constant READ_LATENCY : natural := 1; + + -- *TYPE DECLARATION* + + -- *SIGNAL DECLARATION* + signal mem_read_data : std_logic_vector(DATA_WIDTH-1 downto 0); + signal delay_line : std_logic_vector(READ_LATENCY downto 0) := (others => '0'); + signal fifo_empty : std_logic := '0'; + signal fifo_cnt : natural 0 to MAX_BURST_LENGTH := 0; + signal delay_cnt : natural 0 to READ_LATENCY := 0; + +begin + + --*****COMPONENT INSTANTIATION***** + ram_inst : entity work.single_port_ram(arch) + generic map ( + ADDR_WIDTH => ADDR_WIDTH, + DATA_WIDTH => DATA_WIDTH, + MEMORY_DEPTH => MEMORY_DEPTH + ) + port map ( + clk => clk, + addr => addr, + wen => not read, + ren => read, + wr_data => data_in, + rd_data => mem_read_data + ); + + delay_line_prc : process(clk) + begin + if rising_edge(clk) then + if (reset = '1') then + delay_line <= (others => '0'); + delay_cnt <= 0; + else + -- Shift Right + delay_line(READ_LATENCY-1 downto 0) <= delay_line(READ_LATENCY downto 1); + delay_line(READ_LATENCY) <= read; + + if (read = '1' and delay_line(1) = '0') then + delay_cnt <= delay_cnt + 1; + elsif (read = '0' and delay_line(1) = '1') then + delay_cnt <= delay_cnt - 1; + end if; + end if; + end if; + end process; + + burst_fifo_inst : entity work.FWFT_FIFO(arch) + generic map ( + FIFO_DEPTH => MAX_BURST_LENGTH, + DATA_WIDTH => DATA_WIDTH + ) + port map ( + clk => clk, + reset => reset, + data_in => mem_read_data, + write => delay_line(0), + read => ready_out, + data_out => data_out, + empty => fifo_empty, + full => open, + free => fifo_cnt, + ); + + ready_in <= '0' when (fifo_cnt + delay_cnt = MAX_BURST_LENGTH) else '1'; + valid_out <= not fifo_empty; + +end architecture; \ No newline at end of file diff --git a/src/rtps_config_package.vhd b/src/rtps_config_package.vhd index 81c8c35..de2de23 100644 --- a/src/rtps_config_package.vhd +++ b/src/rtps_config_package.vhd @@ -136,6 +136,8 @@ package rtps_config_package is function check_qos_compatibility(src_is_reader : std_logic; direction : std_logic; remote : unsigned(WORD_WIDTH-1 downto 0); local : unsigned(WORD_WIDTH-1 downto 0)) return boolean; function check_qos_compatibility(src_is_reader : std_logic; direction : std_logic; remote : DOUBLE_WORD_ARRAY; local : DOUBLE_WORD_ARRAY) return boolean; + function check_mask(flags : std_logic_vector, mask : std_logic_vector) return boolean; + end package; package body rtps_config_package is @@ -1087,4 +1089,14 @@ package body rtps_config_package is return ret; end function; + function check_mask(flags : std_logic_vector, mask : std_logic_vector) return boolean is + begin + assert (flags'length = mask'length) report "Flag and mask Signal have unequal length" severity FAILURE; + if ((flags and mask) = mask) then + return TRUE; + else + return FALSE; + end if; + end function; + end package body; diff --git a/src/rtps_endpoint.vhd b/src/rtps_endpoint.vhd index 9853268..440fc68 100644 --- a/src/rtps_endpoint.vhd +++ b/src/rtps_endpoint.vhd @@ -16,68 +16,77 @@ use work.rtps_config_package.all; entity rtps_endpoint is generic ( - ID : natural; + HEARTBEAT_RESPONSE_DELAY : DURATION_TYPE := TODO; + HEARTBEAT_SUPPRESSION_DELAY : DURATION_TYPE := TODO; + LEASE_DURATION : DURATION_TYPE := DEFAULT_LEASE_DURATION; + ENTITYID : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := ENTITYID_UNKNOWN; ); port ( + -- SYSTEM clk : in std_logic; reset : in std_logic; time : in TIME_TYPE; - alive : out std_logic; - + -- FROM RTPS_HANDLER empty : in std_logic; rd : out std_logic; last_word_in : in std_logic; data_in : in std_logic_vector(WORD_WIDTH-1 downto 0); - + -- FROM RTPS_BUILTIN_ENDPOINT meta_empty : in std_logic; meta_data_in : in std_logic_vector(WORD_WIDTH-1 downto 0); meta_rd : out std_logic; - + -- RTPS OUTPUT rtps_wr : out std_logic; rtps_full : in std_logic; last_word_out : out std_logic; data_out : out std_logic_vector(WORD_WIDTH-1 downto 0); - - hc_start : out std_logic; - hc_opcode : out HISTORY_CACHE_OPCODE_TYPE; - hc_res : in HISTORY_CACHE_RESPOSNE_TYPE; - - hc_data_out : in std_logic_vector(WORD_WIDTH-1 downto 0); - hc_valid_out : in std_logic; - hc_ready_out : out std_logic; - hc_last_word_out: in std_logic; - - hc_data_in : out std_logic_vector(WORD_WIDTH-1 downto 0); - hc_valid_in : out std_logic; - hc_ready_in : in std_logic; - hc_last_word_in : out std_logic + -- TO DDS READER + dds_start : out std_logic; + dds_opcode : out HISTORY_CACHE_OPCODE_TYPE; + dds_res : in HISTORY_CACHE_RESPOSNE_TYPE; + dds_data_out : in std_logic_vector(WORD_WIDTH-1 downto 0); + dds_valid_out : in std_logic; + dds_ready_out : out std_logic; + dds_last_word_out: in std_logic ); end entity; architecture arch of rtps_endpoint is --*****CONSTANT DECLARATION***** + -- *ENDPOINT MEMORY* -- Endpoint Memory Size in 4-Byte Words - constant ENDPOINT_MEMORY_SIZE : natural := TODO; + constant ENDPOINT_MEMORY_SIZE : natural := TODO; -- Endpoint Memory Address Width - constant ENDPOINT_MEMORY_ADDR_WIDTH : natural := log2c(ENDPOINT_MEMORY_SIZE); - -- Highest Memory Address - constant MAX_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(ENDPOINT_MEMORY_SIZE-1, ENDPOINT_MEMORY_ADDR_WIDTH); + constant ENDPOINT_MEMORY_ADDR_WIDTH : natural := log2c(ENDPOINT_MEMORY_SIZE); + -- Highest Endpoint Memory Address + constant ENDPOINT_MEMORY_MAX_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := to_unsigned(ENDPOINT_MEMORY_SIZE-1, ENDPOINT_MEMORY_ADDR_WIDTH); -- Highest Endpoint Frame Address - constant MAX_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := MAX_ADDRESS - ENDPOINT_FRAME_SIZE + 1; + constant MAX_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := ENDPOINT_MEMORY_MAX_ADDRESS - ENDPOINT_FRAME_SIZE + 1; -- Address pointing to the beginning of the first Endpoint Data Frame - constant FIRST_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + constant FIRST_ENDPOINT_ADDRESS : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + + -- *ENDPOINT MEMORY FORMAT FIELD FLAGS* + -- Flags mapping to the respective Endpoint Memory Frame Fields + constant EMF_FLAG_WIDTH : natural := 7; + constant EMF_ENTITYID_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (0 => 1, others => '0'); + constant EMF_GUIDPREFIX_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (1 => 1, others => '0'); + constant EMF_IPV4_ADDR_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (2 => 1, others => '0'); + constant EMF_UDP_PORT_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (3 => 1, others => '0'); + constant EMF_NEXT_SEQ_NR_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (4 => 1, others => '0'); + constant EMF_LEASE_DEADLINE_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (5 => 1, others => '0'); + constant EMF_RES_TIME_FLAG : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (6 => 1, others => '0'); + + -- *ENDPOINT MEMORY FRAME FORMAT* + -- 4-Byte Word Offsets to Beginning of Respective Fields in the Endpoint Memory Frame + constant EMF_ENTITYID_OFFSET : natural := 0; + constant EMF_GUIDPREFIX_OFFSET : natural := 1; + constant EMF_IPV4_ADDR_OFFSET : natural := 4; + constant EMF_UDP_PORT_OFFSET : natural := 5; + constant EMF_NEXT_SEQ_NR_OFFSET : natural := 6; + constant EMF_LEASE_DEADLINE_OFFSET : natural := 8; + constant EMF_RES_TIME_OFFSET : natural := 10; - -- *UPDATE PARTICIPANT FLAG POSITIONS* - constant UPDATE_ENDPOINT_FLAG_WIDTH : natural := 4; - -- Signifies that the main Endpoint Data are updated - constant ENDPOINT_DATA_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (0 => 1, others => '0'); - -- Signifies that the Lease Deadline of the Endpoint Data is updated - constant LEASE_DEADLINE_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (1 => 1, others => '0'); - -- Signifies that the last Sequence Number of the Endpoint Data is updated - constant NEXT_SEQ_NR_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (2 => 1, others => '0'); - -- Signifies that the HEARTBEAT/ACKNACK Timeout Time of the Endpoint Data is updated - constant RES_TIME_FLAG : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (3 => 1, others => '0'); --*****TYPE DECLARATION***** -- FSM states. Explained below in detail @@ -87,38 +96,36 @@ architecture arch of rtps_endpoint is type MEM_STAGE_TYPE is (IDLE, TODO); -- Record of all Participant Data stored in memory type ENDPOINT_DATA_TYPE is record - addr : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0); - portn : std_logic_vector(UDP_PORT_WIDTH-1 downto 0); - expects_inline_qos : std_logic; - lease_deadline : TIME_TYPE; - res_time : TIME_TYPE; - next_seq_nr : SEQUENCENUMBER_TYPE; - end record; - constant ZERO_ENDPOINT_DATA : ENDPOINT_DATA_TYPE := ( - addr => IPv4_ADDRESS_INVALID, - portn => UDP_PORT_INVALID, - expects_inline_qos => '0', - lease_deadline => TIME_INVALID, - res_time => TIME_INVALID, - next_seq_nr => SEQUENCENUMBER_UNKNOWN - ); - type MEM_CTRL_DATA_TYPE is record guid : GUID_TYPE; addr : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0); portn : std_logic_vector(UDP_PORT_WIDTH-1 downto 0); - expects_inline_qos : std_logic; + next_seq_nr : SEQUENCENUMBER_TYPE; + lease_deadline : TIME_TYPE; + res_time : TIME_TYPE; + end record; + constant ZERO_ENDPOINT_DATA : ENDPOINT_DATA_TYPE := ( + guid => GUID_UNKNOWN, + addr => IPv4_ADDRESS_INVALID, + portn => UDP_PORT_INVALID, + next_seq_nr => SEQUENCENUMBER_UNKNOWN, + lease_deadline => TIME_INVALID, + res_time => TIME_INVALID + ); + type ENDPOINT_LATCH_DATA_TYPE is record + guid : GUID_TYPE; + addr : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0); + portn : std_logic_vector(UDP_PORT_WIDTH-1 downto 0); deadline : TIME_TYPE; next_seq_nr : SEQUENCENUMBER_TYPE; - update_flags : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1); + field_flag : std_logic_vector(0 to EMF_FLAG_WIDTH-1); end record; - constant ZERO_MEM_CTRL_DATA : MEM_CTRL_DATA_TYPE := ( - guid => (others => (others => '0')), - addr => (others => '0'), - portn => (others => '0'), - expects_inline_qos => '0', + constant ZERO_ENDPOINT_LATCH_DATA : ENDPOINT_LATCH_DATA_TYPE := ( + guid => GUID_UNKNOWN, + addr => IPv4_ADDRESS_INVALID, + portn => UDP_PORT_INVALID, deadline => TIME_INVALID, next_seq_nr => SEQUENCENUMBER_UNKNOWN, - update_flags => (others => '0'), + field_flag => (others => '0') ); @@ -135,13 +142,13 @@ architecture arch of rtps_endpoint is signal portn, portn_next : std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := (others => '0'); signal expects_inline_qos, expects_inline_qos_next : std_logic := '0'; signal is_meta, is_meta_next : std_logic := '0'; - signal update_endpoint_flags : std_logic_vector(0 to UPDATE_ENDPOINT_FLAG_WIDTH-1) := (others => '0'); + signal mem_field_flags : std_logic_vector(0 to EMF_FLAG_WIDTH-1) := (others => '0'); signal opcode, opcode_next : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := (others => '0'); signal flags, flags_next : std_logic_vector(SUBMESSAGE_FLAGS_WIDTH-1 downto 0) := (others => '0'); signal seq_nr, seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; signal next_seq_nr, next_seq_nr_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; signal ts, ts_next : TIME_TYPE := TIME_INVALID; - signal deadline, deadline_next : DURATION_TYPE := DURATION_ZERO; + signal deadline : TIME_TYPE := TIME_INVALID; signal sn_latch_1, sn_latch_1_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; signal sn_latch_2, sn_latch_2_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; signal sn_latch_3, sn_latch_3_next : SEQUENCENUMBER_TYPE := SEQUENCENUMBER_UNKNOWN; @@ -164,25 +171,29 @@ architecture arch of rtps_endpoint is signal data_in_swapped : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); signal mem_stage, mem_stage_next : MEM_STAGE_TYPE := IDLE; - signal mem_wr, mem_rd : std_logic := '0'; - signal mem_wr_data, mem_rd_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); - signal mem_addr, mem_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); - signal mem_addr_base, mem_addr_base_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); signal mem_addr_base, mem_addr_base_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); signal last_addr, last_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal mem_addr_latch, mem_addr_latch_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); signal max_endpoint_addr, max_endpoint_addr_next : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); signal mem_cnt, mem_cnt_next : natural range TODO := 0; signal mem_endpoint_data, mem_endpoint_data_next : ENDPOINT_DATA_TYPE := ZERO_ENDPOINT_DATA; - signal reset_max_pointer, reset_max_pointer_next : std_logic := '0'; - signal mem_long_latch, mem_long_latch_next : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := (others => '0'); - signal mem_ctrl_data, mem_ctrl_data_next : MEM_CTRL_DATA_TYPE := ZERO_MEM_CTRL_DATA; + signal mem_endpoint_latch_data, mem_endpoint_latch_data_next : ENDPOINT_LATCH_DATA_TYPE := ZERO_ENDPOINT_LATCH_DATA; signal mem_pos, mem_pos_next : natural range TODO := 0; - signal is_psearch, is_psearch_next : std_logic := '0'; + signal abort_read : std_logic := '0'; + + signal mem_addr : unsigned(ENDPOINT_MEMORY_ADDR_WIDTH-1 downto 0) := (others => '0'); + signal mem_read_data, mem_write_data : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal mem_ready_in, mem_valid_in : std_logic := '0'; + signal mem_ready_out, mem_valid_out : std_logic := '0'; + signal mem_read : std_logic := '0'; signal stale_check, stale_check_next : std_logic := '0'; signal count, count_next : unsigned(COUNT_WIDTH-1 downto 0) := (others => '0'); signal return_stage, return_stage_next : STAGE_TYPE := IDLE; + signal check_time, check_time_next : TIME_TYPE := TIME_INVALID; + signal lifespan, lifespan_next : TIME_TYPE := TIME_INVALID; + --*****ALIAS DECLARATION***** -- ENDPOINT FRAME HEADER alias header_opcode : std_logic_vector(7 downto 0) is data_in(31 downto 24); @@ -228,19 +239,24 @@ architecture arch of rtps_endpoint is begin --*****COMPONENT INSTANTIATION***** - ram_inst : single_port_ram + mem_ctrl_inst : entity work.mem_ctrl(arch) generic map ( - ADDR_WIDTH => ENDPOINT_MEMORY_ADDR_WIDTH, - DATA_WIDTH => WORD_WIDTH, - MEMORY_DEPTH => ENDPOINT_MEMORY_SIZE + ADDR_WIDTH => ENDPOINT_MEMORY_ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => ENDPOINT_MEMORY_SIZE, + MAX_BURST_LENGTH => ENDPOINT_FRAME_SIZE ) port map ( clk => clk, - addr => std_logic_vector(end_mem_addr), - wen => mem_wr, - ren => mem_rd, - wr_data => mem_wr_data, - rd_data => mem_rd_data + reset => reset or abort_read, + addr => std_logic_vector(mem_addr), + read => mem_read, + ready_in => mem_ready_in, + valid_in => mem_valid_in, + data_in => mem_write_data, + ready_out => mem_ready_out, + valid_out => mem_valid_out, + data_out => mem_read_data ); -- Big Endian Representation @@ -265,7 +281,6 @@ begin flags_next <= flags; seq_nr_next <= seq_nr; ts_next <= ts; - deadline_next <= deadline; sn_latch_1_next <= sn_latch_1; sn_latch_2_next <= sn_latch_2; sn_latch_3_next <= sn_latch_3; @@ -277,18 +292,21 @@ begin stale_check_next <= stale_check; count_next <= count; return_stage_next <= return_stage; + check_time_next <= check_time; + lifespan_next <= lifespan; meta_rd <= '0'; rd <= '0'; mem_opcode <= NOP; mem_op_start <= '0'; rd_guard := '0'; - update_endpoint_flags <= (others => '0'); - hc_start <= '0'; - hc_opcode <= ADD_CACHE_CHANGE; - hc_data_in <= (others => '0'); - hc_ready_out <= '0'; - hc_valid_in <= '0'; - hc_last_word_in <= '0'; + mem_field_flags <= (others => '0'); + dds_start <= '0'; + dds_opcode <= ADD_CACHE_CHANGE; + dds_data_in <= (others => '0'); + dds_ready_out <= '0'; + dds_valid_in <= '0'; + dds_last_word_in <= '0'; + deadline <= TIME_INVALID; -- Last Word Latch Setter @@ -300,31 +318,28 @@ begin -- OPCODE when IDLE => -- RESET - deadline_next <= TIME_INVALID; + lifespan_next <= TIME_INVALID; addr_next <= (others => '0'); portn_next <= (others => '0'); status_info_next <= (others => '0'); key_hash_rcvd_next <= '0'; - expects_inline_qos_next <= '0'; is_meta_next <= '0'; - -- Stale Entry search is initiated between every packet processing and when there is no packet to process - if (stale_check = '0' or (empty = '1' and meta_empty = '1')) then + if (time >= check_time) then + -- Memory Operation Guard if (mem_op_done = '1') then - mem_opcode <= FIND_STALE_ENDPOINT; - mem_op_start <= '1'; - - -- Stale Check Toggle (Setter) stale_check_next <= '1'; - stage_next <= ENDPOINT_STALE_CHECK; + cnt_next <= 1; + mem_op_start <= '1'; + mem_opcode <= GET_FIRST_ENDPOINT; + mem_field_flags <= EMF_LEASE_DEADLINE_FLAG or EMF_RES_TIME_FLAG; + -- Reset Timeout + check_time_next <= TIME_INFINITE; end if; -- Input FIFO Guard elsif (meta_empty = '0') then - meta_rd <= '1'; - - -- Stale Check Toggle (Resetter) - stale_check_next <= '0'; + meta_rd <= '1'; -- Mark as METATRAFFIC is_meta_next <= '1'; @@ -338,9 +353,6 @@ begin elsif (empty = '0') then rd_guard := '1'; - -- Stale Check Toggle (Resetter) - stale_check_next <= '0'; - -- Latch Opcode opcode_next <= header_opcode; -- Latch Flags @@ -418,19 +430,25 @@ begin when OPCODE_ENDPOINT_MATCH => mem_op_start <= '1'; mem_opcode <= SEARCH_ENDPOINT; + mem_field_flags <= (others => '0'); stage_next <= LATCH_ENDPOINT_DATA; when OPCODE_ENDPOINT_UNMATCH => mem_op_start <= '1'; mem_opcode <= SEARCH_ENDPOINT; + mem_field_flags <= (others => '0'); stage_next <= METATRAFFIC_OPERATION; when OPCODE_PARTICIPANT_UNMATCH => mem_op_start <= '1'; - mem_opcode <= FIND_FIRST_PARTICIPANT_ENDPOINT; + mem_opcode <= GET_FIRST_ENDPOINT; + mem_field_flags <= EMF_GUIDPREFIX_FLAG; stage_next <= METATRAFFIC_OPERATION; + cnt_next <= 0; when OPCODE_LIVELINESS_UPDATE => mem_op_start <= '1'; - mem_opcode <= FIND_FIRST_PARTICIPANT_ENDPOINT; + mem_opcode <= GET_FIRST_ENDPOINT; + mem_field_flags <= (others => '0'); stage_next <= METATRAFFIC_OPERATION; + cnt_next <= 0; when others => assert FALSE report "Uknown metatraffic endpoint frame opcode." severity FAILURE; null; @@ -441,14 +459,17 @@ begin case (opcode) is when SID_DATA => - stage_next <= LATCH_EXTRA_DATA; - cnt_next <= 0; + stage_next <= LATCH_EXTRA_DATA; + mem_field_flags <= (others => '0'); + cnt_next <= 0; when SID_HEARTBEAT => - stage_next <= LATCH_HEARTBEAT; - cnt_next <= 0; + stage_next <= LATCH_HEARTBEAT; + mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG; + cnt_next <= 0; when SID_GAP => - stage_next <= LATCH_GAP; - cnt_next <= 0; + stage_next <= LATCH_GAP; + mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG; + cnt_next <= 0; when others => stage_next <= SKIP_PACKET; end case; @@ -464,14 +485,11 @@ begin -- IPv4 Address when 0 => addr_next <= meta_data_in; - -- UDP Port & EXTRA Flags (Expects InLine QoS) + -- UDP Port when 1 => - portn_next <= meta_data_in(WORD_WIDTH-1 downto WORD_WIDTH-UDP_PORT_WIDTH-1); - expects_inline_qos_next <= meta_data_in(0); - -- Calculate Lease Deadline - deadline_next <= time + ENDPOINT_LEASE_DURATION(ID); + portn_next <= meta_data_in(WORD_WIDTH-1 downto WORD_WIDTH-UDP_PORT_WIDTH-1); - stage_next <= METATRAFFIC_OPERATION; + stage_next <= METATRAFFIC_OPERATION; when others => null; end case; @@ -479,92 +497,113 @@ begin when METATRAFFIC_OPERATION => -- Memory Operation Guard if (mem_op_done = '1') then - case (meta_opcode) is when OPCODE_ENDPOINT_MATCH => -- Endpoint already in Memory - if (mem_addr_base /= MAX_ADDRESS) then + if (mem_addr_base /= ENDPOINT_MEMORY_MAX_ADDRESS) then -- Update the Endpoint Data -- NOTE: The Lease Duration is NOT updated in case of an update. That is the responsibility of the Liveliness Update - update_endpoint_flags <= ENDPOINT_DATA_FLAG; - mem_opcode <= UDPATE_ENDPOINT; mem_op_start <= '1'; + mem_opcode <= UDPATE_ENDPOINT; + mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG; + -- DONE stage_next <= IDLE; else -- Insert Matched Remote Endpoint - mem_opcode <= INSERT_ENDPOINT; mem_op_start <= '1'; + mem_opcode <= INSERT_ENDPOINT; + deadline <= (time + LEASE_DURATION) when (LEASE_DURATION /= DURATION_INFINITE) else TIME_INVALID; + -- DONE stage_next <= IDLE; end if; when OPCODE_ENDPOINT_UNMATCH => -- Endpoint not in Memory - if (mem_addr_base = MAX_ADDRESS) then + if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then -- Ignore stage_next <= IDLE; else -- Output Guard - if (hc_ready_in = '1') then + if (dds_ready_in = '1') then -- Propagate Removal - hc_start <= '1'; - hc_opcode <= REMOVE_WRITER; - hc_valid_in <= '1'; - hc_data_in <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); - -- Wait until HC Acknowledgement - if (hc_res = ACK) then + dds_start <= '1'; + dds_opcode <= REMOVE_WRITER; + dds_valid_in <= '1'; + dds_data_in <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); + -- Wait for Operation Acknowledgement + if (dds_res = ACK) then -- Remove Unmatched Remote Endpoint - mem_opcode <= REMOVE_ENDPOINT; mem_op_start <= '1'; + mem_opcode <= REMOVE_ENDPOINT; + -- DONE stage_next <= IDLE; end if; end if; end if; when OPCODE_PARTICIPANT_UNMATCH => - -- No matches in memory - if (mem_addr_base = MAX_ADDRESS) then - -- DONE - stage_next <= IDLE; - else - -- Output Guard - if (hc_ready_in = '1') then - -- Propagate Removal - hc_start <= '1'; - hc_opcode <= REMOVE_WRITER; - hc_valid_in <= '1'; - hc_data_in <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); - -- Wait until HC Acknowledgement - if (hc_res = ACK) then - -- Remove Unmatched Remote Endpoint - mem_opcode <= REMOVE_ENDPOINT; - mem_op_start <= '1'; - stage_next <= INITIATE_NEXT_ENDPOINT_SEARCH; + case (cnt) is + when 0 => + -- Reached End of Endpoints + if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Participant Match + if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then + -- Output Guard + if (dds_ready_in = '1') then + -- Propagate Removal + dds_start <= '1'; + dds_opcode <= REMOVE_WRITER; + dds_valid_in <= '1'; + dds_data_in <= std_logic_vector(to_unsigned(mem_pos, WORD_WIDTH)); + -- Wait for Operation Acknowledgement + if (dds_res = ACK) then + -- Remove Unmatched Remote Endpoint + mem_op_start <= '1'; + mem_opcode <= REMOVE_ENDPOINT; + end if; + end if; + end if; + cnt_next <= 1; end if; - end if; - end if; + when 1 => + -- Continue Search + mem_op_start <= '1'; + mem_opcode <= GET_NEXT_ENDPOINT; + cnt_next <= 0; + when others => + null; + end case; when OPCODE_LIVELINESS_UPDATE => - -- No matches in memory - if (mem_addr_base = MAX_ADDRESS) then - -- DONE - stage_next <= IDLE; - else - -- Renew Lease of Remote Endpoint - update_endpoint_flags <= LEASE_DEADLINE_FLAG; - mem_opcode <= UDPATE_ENDPOINT; - mem_op_start <= '1'; - stage_next <= INITIATE_NEXT_ENDPOINT_SEARCH; - end if; + case (cnt) is + when 0 => + -- No matches in memory + if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then + -- DONE + stage_next <= IDLE; + else + -- Participant Match + if (guid(0) = mem_endpoint_data.guid(0) and guid(1) = mem_endpoint_data.guid(1) and guid(2) = mem_endpoint_data.guid(2)) then + -- Renew Lease of Remote Endpoint + mem_op_start <= '1'; + mem_opcode <= UDPATE_ENDPOINT; + mem_field_flags <= EMF_LEASE_DEADLINE_FLAG; + deadline <= (time + LEASE_DURATION) when (LEASE_DURATION /= DURATION_INFINITE) else TIME_INVALID; + end if; + cnt_next <= 1; + end if; + when 1 => + -- Continue Search + mem_op_start <= '1'; + mem_opcode <= GET_NEXT_ENDPOINT; + cnt_next <= 0; + when others => + null; + end case; when others => assert FALSE report "Uknown metatraffic endpoint frame opcode." severity FAILURE; null; end case; - -- DONE - stage_next <= SKIP_PACKET; - end if; - when INITIATE_NEXT_ENDPOINT_SEARCH => - -- Memory Operation Guard - if (mem_op_done = '1') then - mem_opcode <= FIND_NEXT_PARTICIPANT_ENDPOINT; - mem_op_start <= '1'; - stage_next <= METATRAFFIC_OPERATION; end if; when LATCH_SRC_ADDR => -- Input FIFO Guard @@ -603,7 +642,7 @@ begin if (qos_flag = '1') then stage_next <= PROCESS_INLINE_QOS; else - stage_next <= INITIATE_HISTORY_CACHE_REQUEST; + stage_next <= INITIATE_ADD_CACHE_CHANGE_REQUEST; end if; when others => null; @@ -641,39 +680,46 @@ begin stage_next <= SKIP_PACKET; -- Endpoint in Buffer - if (mem_addr_base /= MAX_ADDRESS) then + if (mem_addr_base /= ENDPOINT_MEMORY_MAX_ADDRESS) then -- No scheduled Heartbeat Response if (mem_endpoint_data.res_time = 0) then -- If current Sequence Number obsolete (removed from source history cache) if (first_seq_nr > mem_endpoint_data.next_seq_nr and first_seq_nr <= last_seq_nr) then -- Store new expected Sequence Number and set Response Dealy - next_seq_nr_next <= first_seq_nr; - mem_op_start <= '1'; - mem_opcode <= UPDATE_ENDPOINT; - -- XXX: Assumes lease deadline will not be updated concurrently (Since they use the same latch) - deadline_next <= time + ENDPOINT_HEARTBEAT_RESPONSE_DELAY(ID); - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(1)(0) <= '0'; - update_endpoint_flags <= NEXT_SEQ_NR_FLAG or RES_TIME_FLAG; + next_seq_nr_next <= first_seq_nr; + mem_op_start <= '1'; + mem_opcode <= UPDATE_ENDPOINT; + mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG or EMF_RES_TIME_FLAG; + if (HEARTBEAT_RESPONSE_DELAY /= DURATION_INFINITE) then + deadline <= time + HEARTBEAT_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline(1)(0) <= '0'; + else + deadline <= TIME_INVALID; + end if; -- If new Sequence Number is available or Writer expects ACKNACK elsif (last_seq_nr >= mem_endpoint_data.next_seq_nr or final_flag = '0') then -- Set Response Delay - mem_opcode <= UPDATE_ENDPOINT; - mem_op_start <= '1'; - deadline_next <= time + ENDPOINT_HEARTBEAT_RESPONSE_DELAY(ID); - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(1)(0) <= '0'; - update_endpoint_flags <= RES_TIME_FLAG; + mem_op_start <= '1'; + mem_opcode <= UPDATE_ENDPOINT; + mem_field_flags <= EMF_RES_TIME_FLAG; + if (HEARTBEAT_RESPONSE_DELAY /= DURATION_INFINITE) then + deadline <= time + HEARTBEAT_RESPONSE_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline(1)(0) <= '0'; + else + deadline <= TIME_INVALID; + end if; end if; -- Currently in Heartbeat Response Delay - elsif (mem_participant_data.res_time(1)(0) = '0') then + elsif (mem_endpoint_data.res_time(1)(0) = '0') then -- If current Sequence Number obsolete (removed from source history cache) if (first_seq_nr > mem_endpoint_data.next_seq_nr and first_seq_nr <= last_seq_nr) then -- Store new expected Sequence Number next_seq_nr_next <= first_seq_nr; mem_op_start <= '1'; mem_opcode <= UPDATE_ENDPOINT; - update_endpoint_flags <= NEXT_SEQ_NR_FLAG; + mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG; end if; end if; end if; @@ -727,7 +773,7 @@ begin stage_next <= SKIP_PACKET; -- Known Remote Endpoint - if (mem_addr_base /= MAX_ADDRESS) then + if (mem_addr_base /= ENDPOINT_MEMORY_MAX_ADDRESS) then -- GAP is relevant if (gap_start <= mem_endpoint_data.next_seq_nr and mem_endpoint_data.next_seq_nr <= gap_list_end) then -- Next Expected is in GAP List @@ -753,11 +799,11 @@ begin -- First valid sequence number found if (tmp_bitmap(bitmap_pos) = '0') then -- Update next sequence number - mem_op_start <= '1'; - mem_opcode <= UPDATE_ENDPOINT; - update_endpoint_flags <= NEXT_SEQ_NR_FLAG; + mem_op_start <= '1'; + mem_opcode <= UPDATE_ENDPOINT; + mem_field_flags <= EMF_NEXT_SEQ_NR_FLAG; -- DONE - stage_next <= SKIP_PACKET; + stage_next <= SKIP_PACKET; else -- Continue search bitmap_pos_next <= bitmap_pos + 1; @@ -850,7 +896,7 @@ begin null; when PID_SENTINEL => -- QOS DONE - stage_next <= INITIATE_HISTORY_CACHE_REQUEST; + stage_next <= INITIATE_ADD_CACHE_CHANGE_REQUEST; when others => -- If MUST_UNDERSTAND Flag is set, we have incompatible communication. Drop Packet if (must_understand = '1') then @@ -878,7 +924,7 @@ begin -- TODO: Use source timestamp if clocks with remote synchronized -- Calculate Sample Lifespan Deadline - deadline_next <= time + tmp_dw; + deadline <= (time + tmp_dw) when (tmp_dw /= DURATION_INFINITE) else TIME_INVALID; -- DONE stage_next <= SKIP_PARAMETER; @@ -922,72 +968,72 @@ begin -- DONE stage_next <= SKIP_PARAMETER; end if; - when INITIATE_HISTORY_CACHE_REQUEST => - hc_start <= '1'; - hc_opcode <= ADD_CACHE_CHANGE; + when INITIATE_ADD_CACHE_CHANGE_REQUEST => + dds_start <= '1'; + dds_opcode <= ADD_CACHE_CHANGE; -- Wait until History Cache acknowledges request - if (hc_res = ACK) then + if (dds_res = ACK) then stage_next <= ADD_CACHE_CHANGE; cnt_next <= 0; end if; when ADD_CACHE_CHANGE => - if (hc_ready_in = '1') then - hc_valid_in <= '1'; + if (dds_ready_in = '1') then + dds_valid_in <= '1'; cnt_next <= cnt + 1; case (cnt) is -- Status Info when 0 => - hc_data_in <= status_info; - hc_data_in(KEY_HASH_FLAG) <= key_hash_rcvd; - hc_data_in(PAYLOAD_FLAG) <= data_flag; + dds_data_in <= status_info; + dds_data_in(KEY_HASH_FLAG) <= key_hash_rcvd; + dds_data_in(PAYLOAD_FLAG) <= data_flag; -- Timestamp 1/2 when 1 => - hc_data_in <= ts(0); + dds_data_in <= ts(0); -- Timestamp 2/2 when 2 => - hc_data_in <= ts(1); + dds_data_in <= ts(1); -- Lifespan Deadline 1/2 when 3 => - hc_data_in <= deadline(0); + dds_data_in <= lifespan(0); -- Lifespan Deadline 2/2 when 4 => - hc_data_in <= deadline(1); + dds_data_in <= lifespan(1); -- Skip Key Hash, if not received if (key_hash_rcvd = '0') then cnt_next <= 9; end if; -- Key hash 1/4 when 5 => - hc_data_in <= key_hash(0); + dds_data_in <= key_hash(0); -- Key Hash 2/4 when 6 => - hc_data_in <= key_hash(1); + dds_data_in <= key_hash(1); -- Key Hash 3/4 when 7 => - hc_data_in <= key_hash(2); + dds_data_in <= key_hash(2); -- Key hash 4/4 when 8 => - hc_data_in <= key_hash(3); + dds_data_in <= key_hash(3); -- Endpoint Memory Position when 9 => -- Wait for Endpoint Search if (mem_op_done = '1') then -- TODO: Assert mem_pos range fits in CDR_LONG - hc_data_in <= std_logic_vector(to_unsigned(mem_pos, CDR_LONG_WIDTH)); + dds_data_in <= std_logic_vector(to_unsigned(mem_pos, CDR_LONG_WIDTH)); -- Payload exists if (data_flag = '1' or key_flag = '1') then stage_next <= PUSH_PAYLOAD; else -- DONE - hc_last_word_in <= '1'; + dds_last_word_in <= '1'; stage_next <= FINALIZE_HISTORY_CACHE_REQUEST; end if; else -- Keep State - hc_valid_in <= '0'; + dds_valid_in <= '0'; cnt_next <= cnt; end if; when others => @@ -996,16 +1042,16 @@ begin end if; when PUSH_PAYLOAD => -- Input/Output Guard - if (empty = '0' and hc_ready_in = '1') then + if (empty = '0' and dds_ready_in = '1') then rd_guard := '1'; - hc_valid_in <= '1'; + dds_valid_in <= '1'; -- Push Payload to History Cache - hc_data_in <= data_in; + dds_data_in <= data_in; -- Exit Condition if (last_word_in = '1') then - hc_last_word_in <= '1'; + dds_last_word_in <= '1'; stage_next <= FINALIZE_HISTORY_CACHE_REQUEST; end if; end if; @@ -1013,14 +1059,14 @@ begin -- NOTE: Memory is already in done state from previous state (ADD_CACHE_CHANGE) assert (mem_op_done = '1') report "FINALIZE_HISTORY_CACHE_REQUEST precondition not met. mem_op_done /= '1'" severity FAILURE; -- Wai for History Cache Response - if (hc_res /= UNDEFINED) then + if (dds_res /= UNDEFINED) then -- Operation was Accepted - if (hc_res = ACCEPTED) then + if (dds_res = ACCEPTED) then -- Update next sequence number and renew Lease - mem_op_start <= '1'; - mem_opcode <= UPDATE_ENDPOINT; - deadline_next <= time + ENDPOINT_LEASE_DURATION(ID); - update_endpoint_flags <= NEXT_SEQ_NR_FLAG or LEASE_DEADLINE_FLAG; + mem_op_start <= '1'; + mem_opcode <= UPDATE_ENDPOINT; + deadline <= (time + LEASE_DURATION) when (LEASE_DURATION /= DURATION_INFINITE) else TIME_INVALID; + mem_field_flags <= NEXT_SEQ_NR_FLAG or LEASE_DEADLINE_FLAG; end if; -- NOTE: In case the operation was unsucessfull (e.g. reached Resource Limits), the endpoint is not updated and the -- Sequence Number is thus not "acknowledged". @@ -1028,56 +1074,85 @@ begin stage_next <= SKIP_PACKET; end if; when ENDPOINT_STALE_CHECK => - -- Wait for Stale Search to finish + -- Memory Operation Guard if (mem_op_done = '1') then - -- Found Stale Entry - if (mem_addr_base /= MAX_ADDRESS) then - -- Endpoint Lease Expired - -- NOTE: The mem_endpoint_data is zero initialized on lease expiration, so we check if the address is set - if (mem_endpoint_data.addr = IPv4_ADDRESS_INVALID) then - -- Remove Participant - mem_opcode <= REMOVE_ENDPOINT; + case (cnt) is + -- Get Next Endpoint + when 0 => mem_op_start <= '1'; - stage_next <= IDLE; - -- Response Time Reached - else - -- If Suppression Delay passed, zero the time - if(mem_endpoint_data.res_time(1)(0) = '1') then - -- Zero Response Time - mem_opcode <= UPDATE_ENDPOINT; - deadline_next <= TIME_ZERO; - update_participant_flags <= RES_TIME_FLAG; - mem_op_start <= '1'; + mem_opcode <= GET_NEXT_ENDPOINT; + cnt_next <= 1; + -- Check Endpoint + when 1 => + -- End of Endpoints + if (mem_addr_base = ENDPOINT_MEMORY_MAX_ADDRESS) then + -- Reset + stale_check_next <= '0'; -- DONE - stage_next <= IDLE; - -- If Response Delay Passed + stage_next <= IDLE; else - -- Set Heartbeat Suppression Time - if (ENDPOINT_HEARTBEAT_SUPPRESSION_DELAY(ID) /= 0) then - -- Set Heartbeat Suppression Time - deadline_next <= time + ENDPOINT_HEARTBEAT_SUPPRESSION_DELAY(ID); - -- NOTE: Last Bit denotes if this is Response or Suppression Delay - deadline_next(1)(0) <= '1'; - else - -- Zero Heartbeat Response Time - deadline_next <= TIME_ZERO; + -- Endpoint Lease Expired + if (mem_endpoint_data.lease_deadline /= TIME_INVALID and mem_endpoint_data.lease_deadline <= time) then + -- Remove Participant + mem_op_start <= '1'; + mem_opcode <= REMOVE_ENDPOINT; + -- Continue Search + cnt_next <= 0; + -- Response Time Reached + elsif (mem_endpoint_data.res_time /= TIME_INVALID and mem_endpoint_data.res_time <= time) then + -- If Suppression Delay passed, zero the time + if(mem_endpoint_data.res_time(1)(0) = '1') then + -- Disable Suppression + mem_op_start <= '1'; + mem_opcode <= UPDATE_ENDPOINT; + deadline <= TIME_INVALID; + mem_field_flags <= RES_TIME_FLAG; + -- Continue Search + cnt_next <= 0; + -- If Response Delay Passed + else + -- Get Additional Data + mem_op_start <= '1'; + mem_opcode <= GET_ENDPOINT; + mem_field_flags <= EMF_IPV4_ADDR_FLAG or EMF_UDP_PORT_FLAG or EMF_NEXT_SEQ_NR_FLAG; + cnt_next <= 2; + end if; + end if; + -- Set New Timeout (Select the closest next timeout) + if (mem_endpoint_data.res_time /= TIME_INVALID and mem_endpoint_data.lease_deadline /= TIME_INVALID and mem_endpoint_data.res_time < mem_endpoint_data.lease_deadline) then + if (mem_endpoint_data.res_time < check_time) then + check_time_next <= mem_endpoint_data.res_time; + end if; + else + if (mem_endpoint_data.lease_deadline /= TIME_INVALID and mem_endpoint_data.lease_deadline < check_time) then + check_time_next <= mem_endpoint_data.lease_deadline; + end if; end if; - mem_opcode <= UPDATE_PARTICIPANT; - update_participant_flags_next <= RES_TIME_FLAG; - mem_op_start <= '1'; - -- Send ACKNACK - -- Increment Heartbeat/Acknack Counter - count_next <= count + 1; - stage_next <= SEND_HEADER; - return_stage_next <= SEND_ACKNACK; - cnt_next <= 0; end if; - end if; - -- No Stale Entry Found - else - -- DONE - stage_next <= IDLE; - end if; + when 2 => + -- Set Heartbeat Suppression Time + if (HEARTBEAT_SUPPRESSION_DELAY /= DURATION_INFINITE and HEARTBEAT_SUPPRESSION_DELAY /= DURATION_ZERO) then + -- Set Heartbeat Suppression Time + deadline <= time + HEARTBEAT_SUPPRESSION_DELAY; + -- NOTE: Last Bit denotes if this is Response or Suppression Delay + deadline(1)(0) <= '1'; + else + -- Disable Suppression + deadline <= TIME_INVALID; + end if; + mem_op_start <= '1'; + mem_opcode <= UPDATE_PARTICIPANT; + mem_field_flags <= RES_TIME_FLAG; + + -- Send ACKNACK + -- Increment Heartbeat/Acknack Counter + count_next <= count + 1; + stage_next <= SEND_HEADER; + return_stage_next <= SEND_ACKNACK; + cnt_next <= 0; + when others => + null; + end case; end if; when SEND_HEADER => if (rtps_full = '0') then @@ -1094,7 +1169,7 @@ begin data_out <= mem_endpoint_data.addr; -- Src and Dest UDPv4 Ports when 2 => - data_out <= USER_IPv4_UNICAST_PORT & mem_participant_data.meta_port; + data_out <= USER_IPv4_UNICAST_PORT & mem_endpoint_data.portn; -- RTPS MESSAGE HEADER when 3 => data_out <= PROTOCOL_RTPS; @@ -1125,7 +1200,7 @@ begin data_out <= SID_ACKNACK & "00000010" & std_logic_vector(to_unsigned(28, SUBMESSAGE_LENGTH_WIDTH)); -- Reader Entity ID when 1 => - data_out <= ENTITYID(ID); + data_out <= ENTITYID; -- Writer Entity ID when 2 => data_out <= ENTITYID_UNKNOWN; @@ -1145,11 +1220,18 @@ begin data_out <= (others => '1'); -- Count when 7 => - data_out <= std_logic_vector(count); + data_out <= std_logic_vector(count); last_word_out <= '1'; - -- DONE - stage_next <= IDLE; + -- Stale Check in Progress + if (stale_check = '1') then + -- Continue Search + stage_next <= ENDPOINT_STALE_CHECK; + cnt_next <= 0; + else + -- DONE + stage_next <= IDLE; + end if; when others => null; end case; @@ -1231,93 +1313,75 @@ begin end process; 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'); - variable tmp_dw : DOUBLE_WORD_ARRAY := (others => (others => '0')); begin -- DEFAULT Registered mem_stage_next <= mem_stage; mem_addr_base_next <= mem_addr_base; - mem_addr_next <= mem_addr; mem_cnt_next <= mem_cnt; last_addr_next <= last_addr; + mem_addr_latch_next <= mem_addr_latch; mem_endpoint_data_next <= mem_endpoint_data; mem_guidprefix_next <= mem_guidprefix; max_endpoint_addr_next <= max_endpoint_addr; - reset_max_pointer_next <= reset_max_pointer; - mem_long_latch_next <= mem_long_latch; - mem_ctrl_data_next <= mem_ctrl_data; + mem_endpoint_latch_data_next <= mem_endpoint_latch_data; mem_pos_next <= mem_pos; -- DEFAULT Unregistered + mem_addr <= (others => '0'); mem_write_data <= (others => '0'); + mem_read <= '0'; + mem_valid_in <= '0'; + mem_ready_out <= '0'; mem_op_done <= '0'; - mem_rd <= '0'; - mem_wr <= '0'; + abort_read <= '0'; case (mem_stage) is when IDLE => mem_op_done <= '1'; - reset_max_pointer_next <= '0'; - is_psearch_next <= '0'; if (mem_op_start = '1') then -- Latch Signals needed for Mermory Operation (Use _next signals, because some signals are set in same clk) - mem_ctrl_data_next <= ( + mem_endpoint_latch_data_next <= ( guid => guid_next, addr => addr_next, portn => portn_next, - expects_inline_qos => expects_inline_qos_next, - deadline => deadline_next, + deadline => deadline, next_seq_nr => next_seq_nr_next, - update_flags => update_endpoint_flags_next + field_flag => mem_field_flags ); case(mem_opcode) is when SEARCH_ENDPOINT => mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_pos_next <= 0; mem_stage_next <= SEARCH_ENDPOINT; mem_cnt_next <= 0; when INSERT_ENDPOINT => mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_pos_next <= 0; - mem_stage_next <= FIND_ENDPOINT_SLOT; + mem_stage_next <= FIND_EMPTY_SLOT; mem_cnt_next <= 0; when UPDATE_ENDPOINT => - if ((update_endpoint_flags and ENDPOINT_DATA_FLAG) = ENDPOINT_DATA_FLAG) then - mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= mem_addr_base + 4; + mem_stage_next <= UPDATE_ENDPOINT; + if check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then mem_cnt_next <= 0; - elsif ((update_endpoint_flags and LEASE_DEADLINE_FLAG) = LEASE_DEADLINE_FLAG) then - mem_stage_next <= UPDATE_ENDPPOINT; - mem_addr_next <= mem_addr_base + 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 1; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then mem_cnt_next <= 2; - elsif ((update_endpoint_flags and RES_TIME_FLAG) = RES_TIME_FLAG) then - mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= mem_addr_base + 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then mem_cnt_next <= 4; - elsif ((update_endpoint_flags and NEXT_SEQ_NR_FLAG) = NEXT_SEQ_NR_FLAG) then - mem_stage_next <= UPDATE_ENDPOINT; - mem_addr_next <= mem_addr_base + 10; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then mem_cnt_next <= 6; + else + -- DONE + mem_stage_next <= IDLE; end if; when REMOVE_ENDPOINT => - mem_addr_next <= mem_addr_base; mem_stage_next <= REMOVE_ENDPOINT; mem_cnt_next <= 0; - when FIND_STALE_ENDPOINT => - mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_pos_next <= 0; - mem_stage_next <= FIND_STALE_ENDPOINT; - mem_cnt_next <= 0; when GET_FIRST_ENDPOINT => mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; mem_pos_next <= 0; mem_stage_next <= GET_NEXT_ENDPOINT; mem_cnt_next <= 0; @@ -1325,496 +1389,992 @@ begin -- Memory Bound Guard if (mem_addr_base /= max_endpoint_addr) then -- Reached End of Memory, No match - tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; mem_pos_next <= mem_pos + 1; mem_stage_next <= GET_NEXT_ENDPOINT; mem_cnt_next <= 0; else - mem_addr_base_next <= MAX_ADDRESS; + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; end if; - when FIND_FIRST_PARTICIPANT_ENDPOINT => - mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_pos_next <= 0; - mem_stage_next <= SEARCH_ENDPOINT; - mem_cnt_next <= 0; - is_psearch_next <= '1'; - when FIND_NEXT_PARTICIPANT_ENDPOINT => - -- Memory Bound Guard - if (mem_addr_base /= max_endpoint_addr) then - -- Reached End of Memory, No match - tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_stage_next <= SEARCH_ENDPOINT; - mem_cnt_next <= 0; - is_psearch_next <= '1'; + when GET_ENDPOINT => + -- Fetch Endpoint Data + mem_stage_next <= GET_ENDPOINT_DATA; + mem_endpoint_data_next <= ZERO_ENDPOINT_DATA; + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 0; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 1; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 5; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; else - mem_addr_base_next <= MAX_ADDRESS; + -- DONE + mem_stage_next <= IDLE; end if; when others => null; end case; end if; when SEARCH_ENDPOINT => - mem_rd <= '1'; - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; - - -- Next Endpoint Frame Address - tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; - case (mem_cnt) is - -- Preload - when 0 => - null; + -- *READ ADDRESS* -- Entity ID + when 0 => + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; + mem_read <= '1'; + mem_valid_in <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 1/3 when 1 => - -- No Match (Ignore Entity ID match on Participant Endpoint Search, but skip empty Slot) - if ((mem_read_data /= mem_ctrl_data.guid(3) and is_psearch = '0') or (mem_read_data = ENTITYID_UNKNOWN)) then - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET; + mem_read <= '1'; + mem_valid_in <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 2/3 + when 2 => + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 1; + mem_read <= '1'; + mem_valid_in <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 3/3 + when 3 => + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 2; + mem_read <= '1'; + mem_valid_in <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- *READ DATA* + -- Entity ID + when 4 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + -- No Match + if (mem_read_data /= mem_endpoint_latch_data.guid(3)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + abort_read <= '1'; + end if; else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; + mem_cnt_next <= mem_cnt + 1; end if; end if; -- GUID Prefix 1/3 - when 2 => - -- No Match - if (mem_read_data /= mem_ctrl_data.guid(0)) then - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; + when 5 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + -- No Match + if (mem_read_data /= mem_endpoint_latch_data.guid(0)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + abort_read <= '1'; + end if; else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; + mem_cnt_next <= mem_cnt + 1; end if; end if; -- GUID Prefix 2/3 - when 3 => - -- No Match - if (mem_read_data /= mem_ctrl_data.guid(1)) then - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; + when 6 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + -- No Match + if (mem_read_data /= mem_endpoint_latch_data.guid(1)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + abort_read <= '1'; + end if; else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; + mem_cnt_next <= mem_cnt + 1; end if; end if; -- GUID Prefix 3/3 - when 4 => - -- No Match - if (mem_read_data /= mem_ctrl_data.guid(2)) then - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; + when 7 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + -- No Match + if (mem_read_data /= mem_endpoint_latch_data.guid(2)) then + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + abort_read <= '1'; + end if; + -- Match else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; + mem_addr_base_next <= mem_addr_base; + -- Fetch Endpoint Data + mem_stage_next <= GET_ENDPOINT_DATA; + mem_endpoint_data_next <= ZERO_ENDPOINT_DATA; + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 0; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 1; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 5; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + -- DONE + mem_stage_next <= IDLE; + end if; end if; - -- Match - else - mem_addr_base_next <= mem_addr_base; - -- Fetch Endpoint Data - mem_stage_next <= GET_ENDPOINT_DATA; - mem_cnt_next <= 1; -- No preload needed end if; when others => null; end case; when GET_ENDPOINT_DATA => - mem_rd <= '1'; - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; case (mem_cnt) is - -- Memory Preload + -- *READ ADDR* + -- Entity ID when 0 => - null; - -- IPv4 Address + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 1; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 5; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + mem_cnt_next <= 12; + end if; + end if; + -- GUID Prefix 1/3 when 1 => - mem_endpoint_data_next.addr <= mem_read_data; - -- UDPv4 Ports + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 2/3 when 2 => - mem_endpoint_data_next.portn <= mem_read_data(31 downto 16); - mem_endpoint_data_next.expects_inline_qos <= mem_read_data(0); - -- Lease Deadline 1/2 + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 1; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 3/3 when 3 => - mem_endpoint_data_next.lease_deadline(0) <= unsigned(mem_read_data); - -- Lease Deadline 2/2 + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 2; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 5; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 12; + else + mem_cnt_next <= 13; + end if; + end if; + end if; + -- IPv4 Address when 4 => - mem_endpoint_data_next.lease_deadline(1) <= unsigned(mem_read_data); - -- Response/Suppression Time 1/2 + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_IPV4_ADDR_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 5; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 12; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 13; + else + mem_cnt_next <= 16; + end if; + end if; + end if; + -- UDP Port/ Flags when 5 => - mem_endpoint_data_next.res_time(0) <= unsigned(mem_read_data); - -- Response/Suppression Time 2/2 - when 6 => - mem_endpoint_data_next.res_time(1) <= unsigned(mem_read_data); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_UDP_PORT_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 12; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 13; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 16; + else + mem_cnt_next <= 17; + end if; + end if; + end if; -- Next Sequence Number 1/2 - when 7 => - mem_endpoint_data_next.next_seq_nr(0) <= unsigned(mem_read_data); + when 6 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- Next Sequence Number 2/2 + when 7 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET + 1; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 12; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 13; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 16; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 17; + else + mem_cnt_next <= 18; + end if; + end if; + end if; + -- Lease Deadline 1/2 when 8 => - mem_endpoint_data_next.next_seq_nr(1) <= unsigned(mem_read_data); - -- DONE - mem_stage_next <= IDLE; + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Lease Deadline 2/2 + when 9 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET + 1; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 12; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 13; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 16; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 17; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 18; + else + mem_cnt_next <= 20; + end if; + end if; + end if; + -- Response Time 1/2 + when 10 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Response Time 2/2 + when 11 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET + 1; + mem_read <= '1'; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 12; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 13; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 16; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 17; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 18; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 20; + else + mem_cnt_next <= 22; + end if; + end if; + -- *READ DATA* + -- Entity ID + when 12 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.guid(3) <= mem_read_data; + + if check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 13; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 16; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 17; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 18; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 20; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 22; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- GUID Prefix 1/3 + when 13 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.guid(0) <= mem_read_data; + + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 2/3 + when 14 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.guid(1) <= mem_read_data; + + mem_cnt_next <= mem_cnt + 1; + end if; + -- GUID Prefix 3/3 + when 15 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.guid(2) <= mem_read_data; + + if check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 16; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 17; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 18; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 20; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 22; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- IPv4 Address + when 16 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.addr <= mem_read_data; + + if check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 17; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 18; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 20; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 22; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- UDP Port + when 17 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.portn <= mem_read_data; + + if check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 18; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 20; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 22; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- Next Sequence Number 1/2 + when 18 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.next_seq_nr(0) <= mem_read_data; + + mem_cnt_next <= mem_cnt + 1; + end if; + -- Next Sequence Number 2/2 + when 19 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.next_seq_nr(1) <= mem_read_data; + + if check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 20; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 22; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- Lease Deadline 1/2 + when 20 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.lease_deadline(0) <= mem_read_data; + + mem_cnt_next <= mem_cnt + 1; + end if; + -- Lease Deadline 2/2 + when 21 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.addr <= mem_read_data; + + if check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 22; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- Response Time 1/2 + when 22 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.res_time(0) <= mem_read_data; + + mem_cnt_next <= mem_cnt + 1; + end if; + -- Response Time 2/2 + when 23 => + mem_ready_out <= '1'; + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + mem_endpoint_data_next.res_time(1) <= mem_read_data; + + -- DONE + mem_stage_next <= IDLE; + end if; when others => null; end case; when INSERT_ENDPOINT => - mem_wr <= '1'; - mem_addr_next <= mem_addr + 1; - mem_cnt_next <= mem_cnt + 1; - case (mem_cnt) is -- Entity ID when 0 => - mem_write_data <= mem_ctrl_data.guid(3); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; + mem_write_data <= mem_endpoint_latch_data.guid(3); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- GUID Prefix 1/3 when 1 => - mem_write_data <= mem_ctrl_data.guid(0); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET; + mem_write_data <= mem_endpoint_latch_data.guid(0); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- GUID Prefix 2/3 when 2 => - mem_write_data <= mem_ctrl_data.guid(1); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 1; + mem_write_data <= mem_endpoint_latch_data.guid(1); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- GUID Prefix 3/3 when 3 => - mem_write_data <= mem_ctrl_data.guid(2); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_GUIDPREFIX_OFFSET + 2; + mem_write_data <= mem_endpoint_latch_data.guid(2); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- IPv4 Address when 4 => - mem_write_data <= mem_ctrl_data.addr; + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_IPV4_ADDR_OFFSET; + mem_write_data <= mem_endpoint_latch_data.addr; + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- UDPv4 Ports when 5 => - mem_write_data <= mem_ctrl_data.portn & (0 => mem_ctrl_data.expects_inline_qos, 16 downto 1 => '0'); - -- Lease Deadline 1/2 - when 6 => - mem_write_data <= std_logic_vector(mem_ctrl_data.deadline(0)); - -- Lease Deadline 2/2 - when 7 => - mem_write_data <= std_logic_vector(mem_ctrl_data.deadline(1)); - -- Response/Suppression Time 1/2 - when 8 => - mem_write_data <= (others => '0'); - -- Response/Suppression Time 2/2 - when 9 => - mem_write_data <= (others => '0'); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_UDP_PORT_OFFSET; + mem_write_data <= mem_endpoint_latch_data.portn & ((mem_write_data'length-mem_endpoint_latch_data.portn'length-1) downto 0 => '0'); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- Next Sequence Number 1/2 - when 10 => + when 6 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET; mem_write_data <= (others => '0'); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; -- Next Sequence Number 2/2 - when 11 => + when 7 => + mem_write_data <= (others => '0'); + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET + 1; mem_write_data <= to_unsigned(1,CDR_LONG_WIDTH); - -- DONE - mem_stage_next <= IDLE; + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Lease Deadline 1/2 + when 8 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.deadline(0)); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Lease Deadline 2/2 + when 9 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET + 1; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.deadline(1)); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Response/Suppression Time 1/2 + when 10 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET; + mem_write_data <= (others => '0'); + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Response/Suppression Time 2/2 + when 11 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET + 1; + mem_write_data <= (others => '0'); + if (mem_ready_in = '1') then + -- DONE + mem_stage_next <= IDLE; + end if; when others => null; end case; when UPDATE_ENDPOINT => - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; - case (mem_cnt) is -- IPv4 Address when 0 => - mem_write_data <= mem_ctrl_data.addr; - if ((mem_ctrl_data.update_flags and ENDPOINT_DATA_FLAG) = ENDPOINT_DATA_FLAG) then - mem_wr <= '1'; + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_IPV4_ADDR_OFFSET; + mem_write_data <= mem_endpoint_latch_data.addr; + mem_endpoint_data.addr <= mem_endpoint_latch_data.addr; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 1; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 2; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 6; + else + -- DONE + mem_stage_next <= IDLE; + end if; end if; -- UDPv4 Ports when 1 => - mem_write_data <= mem_ctrl_data.portn & (0 => mem_ctrl_data.expects_inline_qos, 16 downto 1 => '0'); - if ((mem_ctrl_data.update_flags and ENDPOINT_DATA_FLAG) = ENDPOINT_DATA_FLAG) then - mem_wr <= '1'; - end if; - -- If nothing else to update - if ((mem_ctrl_data.update_flags and (LEASE_DEADLINE_FLAG or NEXT_SEQ_NR_FLAG or RES_TIME_FLAG)) = (mem_ctrl_data.update_flags'range => '0')) then - -- DONE - mem_stage_next <= IDLE; - end if; - -- Lease Deadline 1/2 - when 2 => - mem_write_data <= std_logic_vector(mem_ctrl_data.deadline(0)); - if ((mem_ctrl_data.update_flags and LEASE_DEADLINE_FLAG) = LEASE_DEADLINE_FLAG) then - mem_wr <= '1'; - end if; - -- Lease Deadline 2/2 - when 3 => - mem_write_data <= std_logic_vector(mem_ctrl_data.deadline(1)); - if ((mem_ctrl_data.update_flags and LEASE_DEADLINE_FLAG) = LEASE_DEADLINE_FLAG) then - mem_wr <= '1'; - end if; - -- If nothing else to update - if ((mem_ctrl_data.update_flags and (NEXT_SEQ_NR_FLAG or RES_TIME_FLAG)) = (mem_ctrl_data.update_flags'range => '0')) then - -- DONE - mem_stage_next <= IDLE; - end if; - -- Response/Suppression Time 1/2 - when 4 => - mem_write_data <= std_logic_vector(mem_ctrl_data.deadline(0)); - if ((mem_ctrl_data.update_flags and RES_TIME_FLAG) = RES_TIME_FLAG) then - mem_wr <= '1'; - end if; - -- Response/Suppression Time 2/2 - when 5 => - mem_write_data <= std_logic_vector(mem_ctrl_data.deadline(1)); - if ((mem_ctrl_data.update_flags and RES_TIME_FLAG) = RES_TIME_FLAG) then - mem_wr <= '1'; - end if; - -- If nothing else to update - if ((mem_ctrl_data.update_flags and (NEXT_SEQ_NR_FLAG)) = (mem_ctrl_data.update_flags'range => '0')) then - -- DONE - mem_stage_next <= IDLE; + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_UDP_PORT_OFFSET; + mem_write_data <= mem_endpoint_latch_data.portn & ((mem_write_data'length-mem_endpoint_latch_data.portn'length-1) downto 0 => '0'); + mem_endpoint_data.portn <= mem_endpoint_latch_data.portn; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 2; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 6; + else + -- DONE + mem_stage_next <= IDLE; + end if; end if; -- Next Sequence Number 1/2 - when 6 => - mem_write_data <= std_logic_vector(mem_ctrl_data.next_seq_nr(0)); - if ((mem_ctrl_data.update_flags and NEXT_SEQ_NR_FLAG) = NEXT_SEQ_NR_FLAG) then - mem_wr <= '1'; - end if; + when 2 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.next_seq_nr(0)); + -- Memory Flow Control Guard + if (mem_ready_in = '1') + mem_cnt_next <= mem_cnt + 1; -- Next Sequence Number 2/2 - when 7 => - mem_write_data <= std_logic_vector(mem_ctrl_data.next_seq_nr(1)); - if ((mem_ctrl_data.update_flags and NEXT_SEQ_NR_FLAG) = NEXT_SEQ_NR_FLAG) then - mem_wr <= '1'; + when 3 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_NEXT_SEQ_NR_OFFSET + 1; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.next_seq_nr(1)); + mem_endpoint_data.next_seq_nr <= mem_endpoint_latch_data.next_seq_nr; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 6; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- Lease Deadline 1/2 + when 4 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.deadline(0)); + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Lease Deadline 2/2 + when 5 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_LEASE_DEADLINE_OFFSET + 1; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.deadline(1)); + mem_endpoint_data.lease_deadline <= mem_endpoint_latch_data.deadline; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + if check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 6; + else + -- DONE + mem_stage_next <= IDLE; + end if; + end if; + -- Response/Suppression Time 1/2 + when 6 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.deadline(0)); + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= mem_cnt + 1; + end if; + -- Response/Suppression Time 2/2 + when 7 => + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_RES_TIME_OFFSET + 1; + mem_write_data <= std_logic_vector(mem_endpoint_latch_data.deadline(1)); + mem_endpoint_data.res_time <= mem_endpoint_latch_data.deadline; + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + -- DONE + mem_stage_next <= IDLE; end if; - -- DONE - mem_stage_next <= IDLE; when others => null; end case; when REMOVE_ENDPOINT => -- Mark with ENTITYID_UNKNOWN to mark slot empty - mem_wr <= '1'; + mem_valid_in <= '1'; + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; mem_write_data <= ENTITYID_UNKNOWN; - -- Reset MAX Endpoint Pointer - mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; - mem_addr_next <= FIRST_ENDPOINT_ADDRESS; - mem_pos_next <= 0; - reset_max_pointer_next <= '1'; - last_addr_next <= (others => '0'); - mem_stage_next <= FIND_ENDPOINT_SLOT; - mem_cnt_next <= 0; - when FIND_ENDPOINT_SLOT => - mem_rd <= '1'; - mem_addr_next <= mem_addr + 1; - mem_cnt_next <= mem_cnt + 1; - - -- Next Endpoint Frame Address - tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; - + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + -- Reset MAX Endpoint Pointer + mem_addr_base_next <= FIRST_ENDPOINT_ADDRESS; + mem_pos_next <= 0; + last_addr_next <= (others => '0'); + mem_stage_next <= RESET_MAX_POINTER; + mem_cnt_next <= 0; + -- Save Current Memory Position + mem_addr_latch_next <= mem_addr_base; + end if; + when FIND_EMPTY_SLOT => case (mem_cnt) is - -- Preload + -- *READ ADDRESS* + -- Entity ID when 0 => - null; + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; + mem_read <= '1'; + mem_valid_in <= '1'; + + -- Memory Control Flow Guard + if (mem_ready_in = '1') then + mem_cnt_next <= 1; + end if; + -- *READ DATA* -- Entity ID when 1 => - -- Slot Occupied - if (mem_read_data /= ENTITYID_UNKNOWN) then - -- Reached end of Endpoint Memory Area - if (mem_addr_base = max_endpoint_addr) then - -- We are in the middle of resetting the MAX Endpoint Pointer - if (reset_max_pointer = '1') then - -- No Change - mem_stage_next <= IDLE; - -- MEMORY FULL - elsif (max_endpoint_addr = MAX_ENDPOINT_ADDRESS) then - report "Memory Full, Ignoring Endpoint Data" severity NOTE; - -- Ignore Insertion - mem_stage_next <= IDLE; - mem_addr_base_next <= MAX_ADDRESS; - else - -- Extend Endpoint Memory Area - -- NOTE: "max_endpoint_addr" points to the first address of last Endpoint Frame - max_endpoint_addr_next <= tmp; - -- Populate Endpoint Slot - mem_stage_next <= INSERT_ENDPOINT; - mem_addr_base_next <= tmp; - mem_addr_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_addr_base_next <= tmp; - mem_cnt_next <= 0; - end if; - else - -- Latch last occupied Endpoint Slot - last_addr_next <= mem_addr_base; - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; - end if; - -- Slot Empty - else - -- We are in the middle of resetting the MAX Endpoint Pointer - if (reset_max_pointer = '1') then - -- Make sure to iterate through complete Endpoint Area + mem_ready_out <= '1'; + + -- Memory Control Flow Guard + if (mem_valid_out = '1') then + -- Slot Occupied + if (mem_read_data /= ENTITYID_UNKNOWN) then + -- Reached end of Endpoint Memory Area if (mem_addr_base = max_endpoint_addr) then - -- Reset Pointer to last occupied Endpoint Slot - max_endpoint_addr_next <= last_addr; - -- DONE - mem_stage_next <= IDLE; + -- MEMORY FULL + if (max_endpoint_addr = MAX_ENDPOINT_ADDRESS) then + report "Memory Full, Ignoring Endpoint Data" severity NOTE; + -- Ignore Insertion + mem_stage_next <= IDLE; + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; + else + -- Extend Endpoint Memory Area + -- NOTE: "max_endpoint_addr" points to the first address of last Endpoint Frame + max_endpoint_addr_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + -- Populate Endpoint Slot + mem_stage_next <= INSERT_ENDPOINT; + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; else -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; mem_pos_next <= mem_pos + 1; mem_cnt_next <= 0; - end if; + end if; + -- Slot Empty else -- Populate Endpoint Slot mem_stage_next <= INSERT_ENDPOINT; - mem_addr_next <= mem_addr_base; mem_cnt_next <= 0; end if; end if; when others => null; end case; + when RESET_MAX_POINTER => + case (mem_cnt) is + -- *READ ADDRESS* + -- Entity ID + when 0 => + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; + mem_read <= '1'; + mem_valid_in <= '1'; + + -- Memory Control Flow Guard + if (mem_ready_in = '1') then + mem_cnt_next <= 1; + end if; + -- *READ DATA* + -- Entity ID + when 1 => + mem_ready_out <= '1'; + + -- Memory Control Flow Guard + if (mem_valid_out = '1') then + -- Slot Occupied + if (mem_read_data /= ENTITYID_UNKNOWN) then + -- Reached end of Endpoint Memory Area + if (mem_addr_base = max_endpoint_addr) then + -- No Change + mem_stage_next <= IDLE; + -- Restore Memory Position + mem_addr_base_next <= mem_addr_latch; + else + -- Latch last occupied Endpoint Slot + last_addr_next <= mem_addr_base; + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; + -- Slot Empty + else + -- Make sure to iterate through complete Endpoint Area + if (mem_addr_base = max_endpoint_addr) then + -- Reset Pointer to last occupied Endpoint Slot + max_endpoint_addr_next <= last_addr; + -- DONE + mem_stage_next <= IDLE; + -- Restore Memory Position + mem_addr_base_next <= mem_addr_latch; + else + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; + end if; + end if; + when others => + null; + end case; when GET_NEXT_ENDPOINT => - mem_rd <= '1'; - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; - - -- Next Endpoint Frame Address - tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; - -- Beginning of Endpoint Data - tmp2 := mem_addr_base + 4; - case (mem_cnt) is - -- Preload + -- *READ ADDRESS* + -- Entity ID when 0 => - null; + mem_valid_in <= '1'; + mem_read <= '1'; + mem_addr <= mem_addr_base + EMF_ENTITYID_OFFSET; + + -- Memory Flow Control Guard + if (mem_ready_in = '1') then + mem_cnt_next <= 1; + end if; + -- *READ DATA* -- Entity ID when 1 => - -- Slot Occupied - if (mem_read_data /= ENTITYID_UNKNOWN) then - -- Get Endpoint Data - mem_addr_next <= tmp2; - mem_stage_next <= GET_ENDPOINT_DATA; - mem_cnt_next <= 0; - -- Slot Empty - else - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; + mem_ready_out <= '1'; + + -- Memory Flow Control Guard + if (mem_valid_out = '1') then + -- Slot Occupied + if (mem_read_data /= ENTITYID_UNKNOWN) then + -- Fetch Endpoint Data + mem_stage_next <= GET_ENDPOINT_DATA; + mem_endpoint_data_next <= ZERO_ENDPOINT_DATA; + if check_mask(mem_endpoint_latch_data.field_flag,EMF_ENTITYID_FLAG) then + mem_cnt_next <= 0; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_GUIDPREFIX_FLAG) then + mem_cnt_next <= 1; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_IPV4_ADDR_FLAG) then + mem_cnt_next <= 4; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_UDP_PORT_FLAG) then + mem_cnt_next <= 5; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_NEXT_SEQ_NR_FLAG) then + mem_cnt_next <= 6; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_LEASE_DEADLINE_FLAG) then + mem_cnt_next <= 8; + elsif check_mask(mem_endpoint_latch_data.field_flag,EMF_RES_TIME_FLAG) then + mem_cnt_next <= 10; + else + -- DONE + mem_stage_next <= IDLE; + end if; + -- Slot Empty else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; - end if; - end if; - when others => - null; - end case; - when FIND_STALE_ENDPOINT => - mem_rd <= '1'; - mem_cnt_next <= mem_cnt + 1; - mem_addr_next <= mem_addr + 1; - - -- Next Endpoint Frame Address - tmp := mem_addr_base + ENDPOINT_FRAME_SIZE; - -- Beginning of Endpoint Data - tmp2 := mem_addr_base + 4; - -- Beginning of Lease Deadline - tmp3 := mem_addr_base + 6; - - case (mem_cnt) is - -- Preload - when 0 => - null; - -- Entity ID - when 1 => - -- Slot Occupied - if (mem_read_data /= ENTITYID_UNKNOWN) then - -- Jump to Stale Check - mem_addr_next <= tmp3; - mem_cnt_next <= 2; - -- Slot Empty - else - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; - else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; - end if; - end if; - -- Preload - when 2 => - null; - -- Lease Deadline 1/2 - when 3 => - mem_long_latch_next <= mem_read_data; - -- Lease Deadline 2/2 - when 4 => - tmp_dw := (0 => unsigned(mem_long_latch), 1 => unsigned(mem_read_data)); - -- Lease Deadline passed - if (tmp_dw < time) then - -- Mark Endpoint as stale - mem_endpoint_data_next <= ZERO_ENDPOINT_DATA; - -- DONE - mem_stage_next <= IDLE; - end if; - -- Response/Suppression Time 1/2 - when 5 => - mem_long_latch_next <= mem_read_data; - -- Response/Suppression Time 2/2 - when 6 => - tmp_dw := (0 => unsigned(mem_long_latch), 1 => unsigned(mem_read_data)); - -- Response/Suppression Time passed - if (tmp_dw /= 0 and tmp_dw < time) then - -- Mark Endpoint and get Endpoint Data - mem_addr_next <= tmp2; - mem_stage_next <= GET_ENDPOINT_DATA; - mem_cnt_next <= 0; - -- Endpoint not Stale - else - -- Reached End of Memory, No Match - if (mem_addr_base = max_endpoint_addr) then - mem_addr_base_next <= MAX_ADDRESS; --No match - -- DONE - mem_stage_next <= IDLE; - else - -- Continue Search - mem_addr_next <= tmp; - mem_addr_base_next <= tmp; - mem_pos_next <= mem_pos + 1; - mem_cnt_next <= 0; + -- Reached End of Memory, No Match + if (mem_addr_base = max_endpoint_addr) then + mem_addr_base_next <= ENDPOINT_MEMORY_MAX_ADDRESS; --No match + -- DONE + mem_stage_next <= IDLE; + else + -- Continue Search + mem_addr_base_next <= mem_addr_base + ENDPOINT_FRAME_SIZE; + mem_pos_next <= mem_pos + 1; + mem_cnt_next <= 0; + end if; end if; end if; when others => diff --git a/src/rtps_package.vhd b/src/rtps_package.vhd index 35a3043..d9b5da5 100644 --- a/src/rtps_package.vhd +++ b/src/rtps_package.vhd @@ -115,6 +115,7 @@ package rtps_package is constant PROTOCOLVERSION_2_4 : std_logic_vector(PROTOCOLVERSION_WIDTH-1 downto 0) := x"0204"; constant VENDORID_UNKNOWN : std_logic_vector(VENDORID_WIDTH-1 downto 0) := (others => '0'); constant GUIDPREFIX_UNKNOWN : GUIDPREFIX_TYPE := (others => (others => '0')); + constant GUID_UNKNOWN : GUID_TYPE := (others => (others => '0')); constant UDP_PORT_INVALID : std_logic_vector(UDP_PORT_WIDTH-1 downto 0) := (others => '0'); constant IPv4_ADDRESS_INVALID : std_logic_vector(IPv4_ADDRESS_WIDTH-1 downto 0) := (others => '0'); constant LENGTH_UNLIMITED : std_logic_vector(CDR_LONG_WIDTH-1 downto 0) := std_logic_vector(to_signed(-1,CDR_LONG_WIDTH));