* Added Documentation

- UDP Protocol
* Added Synthesis Report for IPv4 Parser with different buffer sizes
* Small fixes in IPv4 Handler
* Added addsub Entity
* Added Checksum entity
* Implemented RTPS Parser
	- Compiles in Modelsim
* Backup Version of RTPS Parser to extract and implement UDP Checksuming
* Updated RTPS Package
* Added VHDL comilation test file
This commit is contained in:
Greek 2020-05-24 13:08:03 +02:00
parent 10cda546bf
commit 9ab7d79d87
11 changed files with 2582 additions and 193 deletions

127
Report.txt Normal file
View File

@ -0,0 +1,127 @@
---------------------------------------------------------------------------------
Start RTL Component Statistics (1 Buffer)
---------------------------------------------------------------------------------
Detailed RTL Component Info :
+---Adders :
3 Input 14 Bit Adders := 1
2 Input 14 Bit Adders := 3
2 Input 9 Bit Adders := 1
+---Registers :
400 Bit Registers := 1
88 Bit Registers := 1
32 Bit Registers := 1
14 Bit Registers := 5
9 Bit Registers := 1
4 Bit Registers := 1
1 Bit Registers := 3
+---RAMs :
512K Bit RAMs := 1
+---Muxes :
2 Input 400 Bit Muxes := 2
18 Input 400 Bit Muxes := 1
2 Input 32 Bit Muxes := 10
18 Input 32 Bit Muxes := 2
2 Input 14 Bit Muxes := 1
18 Input 14 Bit Muxes := 4
18 Input 9 Bit Muxes := 1
17 Input 5 Bit Muxes := 1
2 Input 5 Bit Muxes := 10
2 Input 2 Bit Muxes := 2
2 Input 1 Bit Muxes := 7
18 Input 1 Bit Muxes := 16
---------------------------------------------------------------------------------------------------
State | New Encoding | Previous Encoding
---------------------------------------------------------------------------------------------------
ipv4_init | 00000 | 00000
ipv4_header_1 | 00001 | 00001
ipv4_header_2 | 00010 | 00010
ipv4_header_3 | 00011 | 00011
ipv4_header_4 | 00100 | 00100
ipv4_header_5 | 00101 | 00101
skip_header | 00110 | 01111
ipv4_fragment_pre | 00111 | 01000
ipv4_fragment | 01000 | 01001
ipv4_fragment_post | 01001 | 01010
ipv4_buffer_src | 01010 | 01011
ipv4_buffer_dest | 01011 | 01100
ipv4_buffer_length | 01100 | 01101
ipv4_buffer_payload | 01101 | 01110
skip_packet | 01110 | 10000
iSTATE | 01111 | 11111
ipv4_payload_length | 10000 | 00110
ipv4_payload | 10001 | 00111
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------
Start RTL Component Statistics (0 Buffer)
---------------------------------------------------------------------------------
Detailed RTL Component Info :
+---Adders :
2 Input 14 Bit Adders := 3
3 Input 14 Bit Adders := 1
2 Input 9 Bit Adders := 1
+---Registers :
400 Bit Registers := 1
88 Bit Registers := 1
14 Bit Registers := 5
9 Bit Registers := 1
4 Bit Registers := 1
1 Bit Registers := 2
+---Muxes :
2 Input 400 Bit Muxes := 2
2 Input 32 Bit Muxes := 7
12 Input 32 Bit Muxes := 1
2 Input 14 Bit Muxes := 1
11 Input 4 Bit Muxes := 1
2 Input 4 Bit Muxes := 7
2 Input 1 Bit Muxes := 4
12 Input 1 Bit Muxes := 7
---------------------------------------------------------------------------------------------------
State | New Encoding | Previous Encoding
---------------------------------------------------------------------------------------------------
ipv4_init | 0000 | 00000
ipv4_header_1 | 0001 | 00001
ipv4_header_2 | 0010 | 00010
ipv4_header_3 | 0011 | 00011
ipv4_header_4 | 0100 | 00100
ipv4_header_5 | 0101 | 00101
skip_header | 0110 | 01111
ipv4_fragment_pre | 0111 | 01000
ipv4_payload_length | 1000 | 00110
ipv4_payload | 1001 | 00111
skip_packet | 1010 | 10000
iSTATE | 1011 | 11111
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------
Start RTL Component Statistics (No Frag)
---------------------------------------------------------------------------------
Detailed RTL Component Info :
+---Adders :
2 Input 14 Bit Adders := 1
3 Input 14 Bit Adders := 1
+---Registers :
14 Bit Registers := 1
4 Bit Registers := 1
+---Muxes :
2 Input 32 Bit Muxes := 3
11 Input 32 Bit Muxes := 1
10 Input 4 Bit Muxes := 1
2 Input 4 Bit Muxes := 5
2 Input 1 Bit Muxes := 1
11 Input 1 Bit Muxes := 6
---------------------------------------------------------------------------------------------------
State | New Encoding | Previous Encoding
---------------------------------------------------------------------------------------------------
ipv4_init | 0000 | 0000
ipv4_header_1 | 0001 | 0001
ipv4_header_2 | 0010 | 0010
ipv4_header_3 | 0011 | 0011
ipv4_header_4 | 0100 | 0100
ipv4_header_5 | 0101 | 0101
skip_header | 0110 | 1000
ipv4_payload_length | 0111 | 0110
ipv4_payload | 1000 | 0111
skip_packet | 1001 | 1001
iSTATE | 1010 | 1111
---------------------------------------------------------------------------------------------------

BIN
doc/rfc768.pdf (Stored with Git LFS) Normal file

Binary file not shown.

87
src/TODO.txt Normal file
View File

@ -0,0 +1,87 @@
RULES 8.4.2
===========
GENERAL
-------
* All communications must take place using RTPS Messages
* All implementations must implement the RTPS Message Receiver
* The timing characteristics of all implementations must be tunable
* Implementations must implement the Simple Participant and Endpoint Discovery Protocols
WRITER
------
* Writers must not send data out-of-order
* Writers must include in-line QoS values if requested by a Reader
* Writers must send periodic HEARTBEAT Messages (reliable only)
* Writers must eventually respond to a negative acknowledgment (reliable only)
* Sending Heartbeats and Gaps with Writer Group Information (Writer belonging to a Group)
READER
------
A best-effort Reader is completely passive as it only receives data and does not send messages itself.
Therefore, the requirements below only apply to reliable Readers.
* Readers must respond eventually after receiving a HEARTBEAT with final flag not set
* Readers must respond eventually after receiving a HEARTBEAT that indicates a sample is missing
* Once acknowledged, always acknowledged
* Readers can only send an ACKNACK Message in response to a HEARTBEAT Message
RELIABILITY
===========
* Best Effort Writer can only be matched with Best Effort Reader
* Stateless Reader can only be Best Effort (maintains absolutely no state, does not handle duplicate and out-of-order changes)
STATELESS WRITER
================
Note that the processing of this message uses the reply locators in the RTPS Receiver.
This is the only source of information for the StatelessWriter to determine where to send the reply to.
Proper functioning of the protocol requires that the RTPS Reader inserts an InfoReply Submessage ahead of the AckNack such that these fields are properly set.
Writer Liveness Protocol
========================
ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER
ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER
OPTIONAL 8.4.14
===============
Optional features may not be supported by all RTPS implementations.
* LARGE DATA (Fragmented Data)
--------------------------------------------
ENTITYID_UKNOWN also for Built-In?
Ignore Participant/Topic/Publication/Subscription (handle argument of Sampleinfo)
ENDIANNESS
==========
You have to see what datatypes PSM maps to each element.
If the datatype is bigger than a byte, byte swaping has to occur.
The elements of an array are in order (but the elements themselves may need to be swapped if bigger than a Byte)
ENDPOINT FIFO PACKET FORMAT
===========================
0...2...........8...............16..............24..............32
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LENTGH |
+---------------+---------------+---------------+---------------+
| OPCODE | FLAGS | UDP_PORT |
+---------------+---------------+---------------+---------------+
| IPv4_ADDR |
+---------------------------------------------------------------+
| ENTITYID |
+---------------------------------------------------------------+
| |
+ Sequence Number [only for DATA Submessage] +
| |
+---------------------------------------------------------------+
| |
~ PAYLOAD (SUBMESSAGE CONTENT) ~
| |
+---------------------------------------------------------------+
ENDPOINT_ID
===========
MSB...........LSB
READERS...WRITERS

76
src/addsub.vhd Normal file
View File

@ -0,0 +1,76 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Library UNISIM;
use UNISIM.vcomponents.all;
Library UNIMACRO;
use UNIMACRO.vcomponents.all;
-- Add/Sub
-- This entity adds or subtracts inputs 'A' and 'B', depending on 'mode' (1 = add, 0 = sub).
-- If 'cap' is high, on Overfolw/Underflow conditions the result is capped at max/min value.
entity addsub is
generic (
PIPELINE_STAGES : integer := 1;
DATA_WIDTH : integer := 16
);
port (
clk : in std_logic;
reset : in std_logic;
mode : in std_logic;
cap : in std_logic;
A : in std_logic_vector(DATA_WIDTH-1 downto 0);
B : in std_logic_vector(DATA_WIDTH-1 downto 0);
RES : out std_logic_vector(DATA_WIDTH-1 downto 0)
);
end entity;
architecture arch of addsub is
--*****SIGNAl DECLARATION
signal result : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0');
signal carry : std_logic := '0';
begin
ADDSUB_MACRO_inst : ADDSUB_MACRO
generic map (
DEVICE => "7SERIES", -- Target Device: "VIRTEX5", "7SERIES", "SPARTAN6"
LATENCY => PIPELINE_STAGES, -- Desired clock cycle latency, 0-2
WIDTH => DATA_WIDTH -- Input / Output bus width, 1-48
)
port map (
CARRYOUT => open, -- 1-bit carry-out output signal
RESULT => result, -- Add/sub result output, width defined by WIDTH generic
A => A, -- Input A bus, width defined by WIDTH generic
ADD_SUB => mode, -- 1-bit add/sub input, high selects add, low selects subtract
B => B, -- Input B bus, width defined by WIDTH generic
CARRYIN => '0', -- 1-bit carry-in input
CE => '1', -- 1-bit clock enable input
CLK => clk, -- 1-bit clock input
RST => reset -- 1-bit active high synchronous reset
);
clamp : process(all)
begin
--DEFAULT VALUE
RES <= result;
--Overflow/Underflow
if(carry = '1' and cap = '1') then
--ADD
if(mode = '1') then
--CAP AT MAX VALUE
RES <= (others => '1');
--SUB
else
--CAP AT ZERO
RES <= (others => '0');
end if;
end if;
end process;
end architecture;

47
src/checksum.vhd Normal file
View File

@ -0,0 +1,47 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity addsub is
generic (
INPUT_WIDTH : integer := 32;
OUTPUT_WIDTH : integer := 16
);
port (
clk : in std_logic;
reset : in std_logic;
op : in std_logic_vector(1 downto 0);
input : in std_logic_vector(INPUT_WIDTH-1 downto 0);
output : out std_logic_vector(OUTPUT_WIDTH-1 downto 0);
done : out std_logic
);
end entity;
architecture arch of addsub is
--*****COMPONENT DECLARATION*****
entity addsub is
generic (
PIPELINE_STAGES : integer := 1;
DATA_WIDTH : integer := 32
);
port (
clk : in std_logic;
reset : in std_logic;
cin : in std_logic;
A : in std_logic_vector(DATA_WIDTH-1 downto 0);
B : in std_logic_vector(DATA_WIDTH-1 downto 0);
RES : out std_logic_vector(DATA_WIDTH-1 downto 0);
cout : out std_logic
);
end entity;
--*****SIGNAl DECLARATION
signal result : std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0');
signal carry : std_logic := '0';
begin
end architecture;

View File

@ -5,26 +5,76 @@ use ieee.numeric_std.all;
use work.ip_package.all;
use work.math_pkg.all;
entity ipv4_in is
-- IPv4 Handler
-- This entity parses IPv4 packets read from the input FIFO, and extracts the underlying Protocol (Payload)
-- to the respective output FIFO together with the Src and Dest Addresses.
-- The input FIFO has to be a 32-bit wide FWFT (First Word Fall Through) FIFO. The IPv4 packet has to be
-- 32-bit word aligned (padded with zeroes in the end to the closest 32-bit boundary), and the first word
-- before the actual packet has to be the length of the following IPv4 packet (in 32-bit words + padding).
-- This is necessary to recover from spurious packets.
-- ex.
-- 31 0
-- +------------------------------+
-- | LENGTH=4 |
-- +------------------------------+
-- | IPv4 Packet |
-- + +
-- | |
-- + +
-- | |
-- + +--------------+
-- | | PADDING |
-- +---------------+--------------+
-- The output FIFO distribution is controlled by the 'LAYER3_PROTOCOLS' constant in the 'ip_package' package.
-- The array position of the protocol version number is also the id of the output FIFO where this protocol
-- is sent to. First word on the output FIFO is the Source address, second the Destination Address, third
-- the payload length (in 32-bit words + padding), followed by the actual packet.
-- ex.
-- 31 0
-- +------------------------------+
-- | Source Address |
-- +------------------------------+
-- | Destination Address |
-- +------------------------------+
-- | LENGTH=4 |
-- +------------------------------+
-- | UDP Packet |
-- + +
-- | |
-- | +
-- | |
-- + +--------------+
-- | | PADDING |
-- +---------------+--------------+
-- This Entity features 2 architecture implementations.
-- The 'no_frag' implementation does not support fragmentation and just drops fragmented packets. This needs the least amount of resources
-- The 'with_frag' implementation supports fragmentation as stated in RFC 791 (fragments of any size received in any order with auto adjusted
-- timeout according to transmitted TTL). The re-assembly needs considerable more resources for packet buffering and state holding.
-- The generics allow tuning of the supported packet sizes and used resources.
entity ipv4_in_handler is
generic(
CLK_FREQ : integer := 20000000;
MAX_FRAG_SIZE : integer := 1600;
MAX_PARALLEL_FRAG : integer := 1;
DEFAULT_FRAG_TIMEOUT: integer := 5
CLK_FREQ : integer := 20000000; -- Frequency of input clock in Hz
MAX_FRAG_SIZE : integer := 1600; -- Maximum re-assembled IP packet size. If a re-assembled packet exceeds this threshold it is dropped. (Does not limit the size of received non-fragmented packets)
MAX_PARALLEL_FRAG : integer := 1; -- Maximum number of parallel running re-assemble procedures. If a fragment of a new Ip packet is received, while 'MAX_PARALLEL_FRAG' packets are already in the re-assembly procedure, it is dropped.
DEFAULT_FRAG_TIMEOUT: integer := 5 -- Default timeout in seconds until which the re-assembly procedure of an IP packet has to be completed before being dropped to fre up resources.
);
port (
clk : in std_logic;
reset : in std_logic;
empty : in std_logic;
data_in : in std_logic_vector(31 downto 0);
rd : out std_logic;
wr : out std_logic_vector(LAYER3_PROTOCOL_NUM-1 downto 0);
full : in std_logic_vector(LAYER3_PROTOCOL_NUM-1 downto 0);
data_out: out IP_OUTPUT_TYPE
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
full : in std_logic_vector(LAYER3_PROTOCOL_NUM-1 downto 0); -- Output FIFO full flag
wr : out std_logic_vector(LAYER3_PROTOCOL_NUM-1 downto 0); -- Output FIFO write signal
data_out: out IP_OUTPUT_TYPE -- Output FIFO data signal
);
end entity;
architecture arch of ipv4_in is
architecture with_frag of ipv4_in_handler is
--*****COMPONENT DECLARATION*****
-- The RAM is used for reassembly of ip fragments.
@ -60,15 +110,15 @@ architecture arch of ipv4_in is
-- NOTE: The MAX_PARALLEL_FRAG array position is not mapped to a buffer, but is used for comparison purposes
type BUFFER_ID_ARRAY is array (MAX_PARALLEL_FRAG downto 0) of std_logic_vector(87 downto 0);
-- Array of bitmaps used to identify received fragment words.
type BUFFER_BITMAP_ARRAY is array (max(MAX_PARALLEL_FRAG-1,0) downto 0) of std_logic_vector((MAX_FRAG_SIZE/4)-1 downto 0);
type BUFFER_BITMAP_ARRAY is array (MAX_PARALLEL_FRAG-1 downto 0) of std_logic_vector((MAX_FRAG_SIZE/4)-1 downto 0);
-- Array of buffer timers used for timeout checking
type BUFFER_TIMER_ARRAY is array (max(MAX_PARALLEL_FRAG-1,0) downto 0) of unsigned(7 downto 0);
type BUFFER_TIMER_ARRAY is array (MAX_PARALLEL_FRAG-1 downto 0) of unsigned(7 downto 0);
-- Array of address offsets for the RAM. Used as constant
type BUFFER_ADDR_OFFSET_TYPE is array (max(MAX_PARALLEL_FRAG-1,0) downto 0) of unsigned(RAM_ADDR_WIDTH-1 downto 0);
type BUFFER_ADDR_OFFSET_TYPE is array (MAX_PARALLEL_FRAG-1 downto 0) of unsigned(RAM_ADDR_WIDTH-1 downto 0);
-- Array of packet sizes in buffers
type FRAG_SIZE_ARRAY is array (max(MAX_PARALLEL_FRAG-1,0) downto 0) of std_logic_vector(13 downto 0);
type FRAG_SIZE_ARRAY is array (MAX_PARALLEL_FRAG-1 downto 0) of std_logic_vector(13 downto 0);
-- Array of 32-bit buffer word counters. Used for counting new received fragments and determining if the packet is completely re-assebled
type BUFFER_WORD_COUNTER_ARRAY is array (max(MAX_PARALLEL_FRAG-1,0) downto 0) of integer range 0 to (MAX_FRAG_SIZE/4);
type BUFFER_WORD_COUNTER_ARRAY is array (MAX_PARALLEL_FRAG-1 downto 0) of integer range 0 to (MAX_FRAG_SIZE/4);
--*****SIGNAL DECLARATION*****
@ -113,9 +163,9 @@ architecture arch of ipv4_in is
-- Signal used to reset buffer timers
signal reset_buffer_timer : std_logic := '0';
-- ID of buffer timer to be reset
signal reset_buffer_timer_id : integer range 0 to max(MAX_PARALLEL_FRAG-1,0) := 0;
signal reset_buffer_timer_id : integer range 0 to MAX_PARALLEL_FRAG-1 := 0;
-- ID of current buffer
signal cur_buffer_id, cur_buffer_id_next : integer range 0 to max(MAX_PARALLEL_FRAG-1,0) := 0;
signal cur_buffer_id, cur_buffer_id_next : integer range 0 to MAX_PARALLEL_FRAG-1 := 0;
-- Signal used to reset the word counter
signal reset_read_cnt : std_logic;
-- Intermediate output signal
@ -191,37 +241,37 @@ architecture arch of ipv4_in is
begin
-- Generic Assertions
assert (MAX_PARALLEL_FRAG >= 0) report "MAX_PARALLEL_FRAG has to be positive" severity failure;
assert (MAX_PARALLEL_FRAG > 0) report "MAX_PARALLEL_FRAG has to be greater than 0" severity failure;
assert (MAX_FRAG_SIZE mod 4 = 0) report "MAX_FRAG_SIZE has to be multiple of 4" severity failure;
assert (MAX_FRAG_SIZE <= 65516) report "MAX_FRAG_SIZE has to be smaller or equal to 65516" severity error;
assert (DEFAULT_FRAG_TIMEOUT <= 255) report "DEFAULT_FRAG_TIMEOUT has to be smaller or equal to 255" severity error;
-- Generic Dependant Constant
-- Does not change its value after generation
-- TODO: Change to constant with function initialization
const_gen : for i in 0 to buffer_addr_offset'length-1 generate
buffer_addr_offset(i) <= to_unsigned(MAX_FRAG_SIZE*i,buffer_addr_offset(i)'length);
end generate;
--*****COMPONENT INSTANTIATION*****
buffer_gen : if (MAX_PARALLEL_FRAG /= 0) generate
ram_inst : single_port_ram
generic map (
ADDR_WIDTH => RAM_ADDR_WIDTH,
DATA_WIDTH => 32,
MEMORY_SIZE => MAX_PARALLEL_FRAG*MAX_FRAG_SIZE
)
port map (
clk => clk,
addr => std_logic_vector(buffer_addr),
wen => buffer_wen,
ren => buffer_ren,
wr_data => buffer_wr_data,
rd_data => buffer_rd_data
);
end generate;
ram_inst : single_port_ram
generic map (
ADDR_WIDTH => RAM_ADDR_WIDTH,
DATA_WIDTH => 32,
MEMORY_SIZE => MAX_PARALLEL_FRAG*MAX_FRAG_SIZE
)
port map (
clk => clk,
addr => std_logic_vector(buffer_addr),
wen => buffer_wen,
ren => buffer_ren,
wr_data => buffer_wr_data,
rd_data => buffer_rd_data
);
rd <= rd_sig;
-- TODO: Make only wr signal conditional and connect ALL output FIFOs to the Signal
-- This process is responsible for MUXing the correct signal to the correct output FIFO
output_prc : process(all)
begin
@ -294,7 +344,7 @@ begin
-- Reset packet Byte Counter
reset_read_cnt <= '1';
-- Check Buffer timers for timeouts
for i in 0 to max(MAX_PARALLEL_FRAG-1,0) loop
for i in 0 to MAX_PARALLEL_FRAG-1 loop
-- If timeout reached
if(buffer_timer(i) >= max_buffer_timer(i)) then
-- Free Buffer ID
@ -334,22 +384,16 @@ begin
stage_next <= IPv4_HEADER_3;
-- IP Fragmentation
else
-- Fragmentation Reassembly disabled, skip packet
if (MAX_PARALLEL_FRAG = 0) then
stage_next <= SKIP_PACKET;
-- Store Fragment relevant data
else
is_fragment_next <= '1';
frag_offset_next <= unsigned(std_logic_vector'(ip_frag_offset & "0")); --'std_logic_vector needed to avoid "Ambiguous type in infix expression"
-- Temporal storage for comparison
buffer_id_next(MAX_PARALLEL_FRAG)(15 downto 0) <= ip_id;
-- Needed to determine the total size of the reassembled packet
if (ip_MF_flag = '0') then
is_last_fragment_next <= '1';
end if;
-- Continue Parsing
stage_next <= IPv4_HEADER_3;
is_fragment_next <= '1';
frag_offset_next <= unsigned(std_logic_vector'(ip_frag_offset & "0")); --'std_logic_vector needed to avoid "Ambiguous type in infix expression"
-- Temporal storage for comparison
buffer_id_next(MAX_PARALLEL_FRAG)(15 downto 0) <= ip_id;
-- Needed to determine the total size of the reassembled packet
if (ip_MF_flag = '0') then
is_last_fragment_next <= '1';
end if;
-- Continue Parsing
stage_next <= IPv4_HEADER_3;
end if;
end if;
-- Third IPv4 Header word (Fields: TTL, Protocol, Checksum)
@ -642,7 +686,7 @@ begin
buffer_timer(reset_buffer_timer_id) <= (others => '0');
else
-- Increment Timers
for i in 0 to max(MAX_PARALLEL_FRAG-1,0) loop
for i in 0 to MAX_PARALLEL_FRAG-1 loop
-- Timers stay at highest value until reset
if(buffer_timer(i) /= (buffer_timer(i)'reverse_range => '1')) then
buffer_timer(i) <= buffer_timer(i) + 1;
@ -726,4 +770,267 @@ begin
end if;
end process;
end architecture;
architecture no_frag of ipv4_in_handler is
--*****TYPE DECLARATION*****
-- FSM states. Explained delow in detail
type PARSER_STAGE_TYPE is (IPv4_INIT, IPv4_HEADER_1, IPv4_HEADER_2, IPv4_HEADER_3, IPv4_HEADER_4,
IPv4_HEADER_5, IPv4_PAYLOAD_LENGTH, IPv4_PAYLOAD, SKIP_HEADER, SKIP_PACKET);
--*****SIGNAL DECLARATION*****
-- FSM state
signal stage, stage_next : PARSER_STAGE_TYPE := IPv4_INIT;
-- 32-bit aligned total packet length
signal packet_length, packet_length_next : unsigned(13 downto 0) := (others => '0');
-- 32-bit aligned header length
signal header_length, header_length_next : unsigned(3 downto 0) := (others => '0');
-- 32-bit word counter (Counts words read from input fifo)
signal read_cnt : unsigned(13 downto 0) := (others => '0');
-- Intermediate input read signal. (Read from output port not allowed)
signal rd_sig : std_logic := '0';
-- ID of current output fifo (Used to MUX output FIFOs)
signal output_id, output_id_next : integer range 0 to LAYER3_PROTOCOL_NUM-1 := 0;
-- Signal used to reset the word counter
signal reset_read_cnt : std_logic;
-- Intermediate output signal
signal data_out_sig : std_logic_vector(31 downto 0);
-- Intermediate output signal, and its 1 clk cycle delayed variant
signal wr_sig : std_logic;
--*****ALIAS DEFINATION*****
--IPv4 HEADER
alias ip_version : std_logic_vector(3 downto 0) is data_in(31 downto 28);
alias ip_ihl : std_logic_vector(3 downto 0) is data_in(27 downto 24);
alias ip_dscp : std_logic_vector(5 downto 0) is data_in(23 downto 18);
alias ip_ecn : std_logic_vector(1 downto 0) is data_in(17 downto 16);
alias ip_length : std_logic_vector(15 downto 0) is data_in(15 downto 0);
alias ip_id : std_logic_vector(15 downto 0) is data_in(31 downto 16);
alias ip_DF_flag : std_logic is data_in(14);
alias ip_MF_flag : std_logic is data_in(13);
alias ip_frag_offset: std_logic_vector(12 downto 0) is data_in(12 downto 0);
alias ip_ttl : std_logic_vector(7 downto 0) is data_in(31 downto 24);
alias ip_protocol : std_logic_vector(7 downto 0) is data_in(23 downto 16);
alias ip_checksum : std_logic_vector(15 downto 0) is data_in(15 downto 0);
--*****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) + to_unsigned(1, tmp'length));
end if;
return tmp;
end function;
begin
rd <= rd_sig;
-- This process is responsible for MUXing the correct signal to the correct output FIFO
output_prc : process(all)
begin
data_out(output_id) <= data_out_sig;
wr(output_id) <= wr_sig;
end process;
-- Main State Machine
-- STATE DESCRIPSION
-- IPv4_INIT Initial and idle state. Responsible for checking the buffer timers, and reading the packet length from the input FIFO
-- IPv4_HEADER_1 Parsing first word of IPv4 HEADER
-- IPv4_HEADER_2 Parsing second word of IPv4 HEADER
-- IPv4_HEADER_3 Parsing third word of IPv4 HEADER
-- IPv4_HEADER_4 Parsing fourth word of IPv4 HEADER and writing SRC Addr to output FIFO (if not a fragment)
-- IPv4_HEADER_5 Parsing fifth word of IPv4 HEADER and writing DEST Addr to output FIFO (if not a fragment)
-- IPv4_PAYLOAD_LENGTH Writing packet(payload) length to output FIFO
-- IPv4_PAYLOAD Writing of packet(payload) from input FIFO to output FIFO
-- SKIP_HEADER Skip to beginning of Payload in input FIFO
-- SKIP_PACKET Skip to end of packet in input FIFO
parser_prc : process(all)
variable tmp : integer range 0 to max(MAX_PARALLEL_FRAG,LAYER3_PROTOCOL_NUM) := 0;
begin
--DEFAULT Registered
stage_next <= stage;
packet_length_next <= packet_length;
header_length_next <= header_length;
output_id_next <= output_id;
-- DEFAULT Unregistered
rd_sig <= '0';
wr_sig <= '0';
data_out_sig <= (others => '0');
reset_read_cnt <= '0';
case(stage) is
-- Initial/Idle State
when IPv4_INIT =>
-- Reset packet Byte Counter
reset_read_cnt <= '1';
-- Read Packet Length from input
if (empty = '0') then
packet_length_next <= unsigned(data_in(13 downto 0));
rd_sig <= '1';
-- Begin Processing
stage_next <= IPv4_HEADER_1;
end if;
-- First IPv4 Header word (Fields: Version, IHL, DSCP, ECN, Total Length)
when IPv4_HEADER_1 =>
if (empty = '0') then
rd_sig <= '1';
-- Wrong IP Version or Packet Length missmatch, skip packet
if (ip_version /= "0100" or normalize_length(ip_length) /= std_logic_vector(packet_length)) then
stage_next <= SKIP_PACKET;
-- Store data and continue Parsing
else
header_length_next <= unsigned(ip_ihl);
stage_next <= IPv4_HEADER_2;
end if;
end if;
-- Second IPv4 Header word (Fields: Identification, Flags, Fragment Offset)
when IPv4_HEADER_2 =>
if (empty = '0') then
rd_sig <= '1';
-- No fragmentation, continue parsing normaly
if (ip_MF_flag = '0' and ip_frag_offset = (ip_frag_offset'reverse_range => '0')) then
stage_next <= IPv4_HEADER_3;
-- IP Fragmentation
else
-- Fragmentation Reassembly disabled, skip packet
stage_next <= SKIP_PACKET;
end if;
end if;
-- Third IPv4 Header word (Fields: TTL, Protocol, Checksum)
when IPv4_HEADER_3 =>
if (empty = '0') then
rd_sig <= '1';
-- Select Output according to Layer 3 Protocol
tmp := LAYER3_PROTOCOL_NUM;
for i in 0 to LAYER3_PROTOCOL_NUM-1 loop
if(ip_protocol = LAYER3_PROTOCOLS(i)) then
tmp := i;
end if;
end loop;
-- No Protocol match, skip packet
if (tmp = LAYER3_PROTOCOL_NUM) then
stage_next <= SKIP_PACKET;
-- Protocol Match, continue parsing
else
output_id_next <= tmp;
stage_next <= IPv4_HEADER_4;
end if;
end if;
-- Fourth IPv4 Header word (Fields: Src Address)
when IPv4_HEADER_4 =>
if (empty = '0') then
-- Write Src Address to Output FIFO
if (full(output_id) = '0') then
rd_sig <= '1';
wr_sig <= '1';
data_out_sig <= data_in;
-- Continue parsing
stage_next <= IPv4_HEADER_5;
end if;
end if;
-- Fourth IPv4 Header word (Fields: Dest Address)
when IPv4_HEADER_5 =>
if (empty = '0') then
-- Write Dst Address to Output FIFO
if (full(output_id) = '0') then
rd_sig <= '1';
wr_sig <= '1';
data_out_sig <= data_in;
-- Check Header Size
if (read_cnt /= ("0000000000" & header_length)) then
-- If Header has "Options", skip to Payload
stage_next <= SKIP_HEADER;
else
-- Payload Processing
stage_next <= IPv4_PAYLOAD_LENGTH;
end if;
end if;
end if;
-- Push Payload Length
when IPv4_PAYLOAD_LENGTH =>
-- Write Payload Length to Output FIFO
if (full(output_id) = '0') then
wr_sig <= '1';
data_out_sig(13 downto 0) <= std_logic_vector(packet_length - ("0000000000" & header_length));
stage_next <= IPv4_PAYLOAD;
end if;
-- Push Payload
when IPv4_PAYLOAD =>
-- Write to Output FIFO
if (empty = '0' and full(output_id) = '0') then
rd_sig <= '1';
wr_sig <= '1';
data_out_sig <= data_in;
-- End Of Packet
if (read_cnt = packet_length) then
-- Done, process next packet
stage_next <= IPv4_INIT;
end if;
end if;
-- Skip until beginning of payload
when SKIP_HEADER =>
if (empty = '0') then
rd_sig <= '1';
-- End of Header
if(read_cnt = header_length) then
-- Payload Processing
stage_next <= IPv4_PAYLOAD;
end if;
end if;
-- Skip entire packet
when SKIP_PACKET =>
if (empty = '0') then
rd_sig <= '1';
-- End of Packet
if(read_cnt = packet_length) then
-- Continue parsing next packet
stage_next <= IPv4_INIT;
end if;
end if;
when others =>
null;
end case;
end process;
-- Process responsible for counting read words
-- This process uses the actual RAM and 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 + to_unsigned(1, read_cnt'length);
end if;
end if;
end process;
-- State Machine Sync Process (Registers)
sync : process(clk)
begin
if rising_edge(clk) then
if (reset = '1') then
stage <= IPv4_INIT;
packet_length <= (others => '0');
header_length <= (others => '0');
output_id <= 0;
else
stage <= stage_next;
packet_length <= packet_length_next;
header_length <= header_length_next;
output_id <= output_id_next;
end if;
end if;
end process;
end architecture;

1030
src/rtps_handler.vhd Normal file

File diff suppressed because it is too large Load Diff

516
src/rtps_handler.vhd.BAK Normal file
View File

@ -0,0 +1,516 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.math_pkg.all;
entity rtps_handler is
generic(
);
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
);
end entity;
architecture arch of rtps_handler is
--*****COMPOENENT DECLARATION******
entity adder is
generic (
PIPELINE_STAGES : integer := 1;
DATA_WIDTH : integer := 32
);
port (
clk : in std_logic;
reset : in std_logic;
cin : in std_logic;
A : in std_logic_vector(DATA_WIDTH-1 downto 0);
B : in std_logic_vector(DATA_WIDTH-1 downto 0);
RES : out std_logic_vector(DATA_WIDTH-1 downto 0);
cout : out std_logic
);
end entity;
--*****CONSTANT DECLARATION*****
-- Minimum Packet Length to consider valid
-- 2 UDP Header 32-bit Words, 5 RTPS Header 32-bit Words
constant MIN_PACKET_LENGTH : integer := 7;
constant MAX_ENDPOINTS : integer := NUM_READERS+NUM_WRITERS;
--GUIDPREFIX(1 downto 0) <= VENDORID;
--*****TYPE DECLARATION*****
type STAGE_TYPE is (INIT, SRC_ADDR, DEST_ADDR, UDP_HEADER_1, UDP_HEADER_2, RTPS_HEADER_1,
RTPS_HEADER_2, RTPS_HEADER_3, RTPS_HEADER_4, SKIP_PACKET);
--*****SIGNAL DECLARATION*****
-- FSM state
signal stage, stage_next : PARSER_STAGE_TYPE := INIT;
-- 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 aligned total packet length
signal packet_length, packet_length_next : unsigned(13 downto 0) := (others => '0');
signal sub_length, sub_length_next : unsigned(13 downto 0) := (others => '0');
signal align_sig, align_sig_next : std_logic_vector(23 downto 0) := (others => '0');
signal aligned_data_in : std_logic_vector(31 downto 0);
signal align_offset, align_offset_next : std_logic_vector(1 downto 0) := (others => '0');
signal offset_latch, offset_latch_next : std_logic_vector(1 downto 0) := (others => '0');
signal src_addr, src_addr_next : std_logic_vector(31 downto 0) := (others => '0');
signal src_port, src_port_next : std_logic_vector(15 downto 0) := (others => '0');
signal is_multicast, is_multicast_next : std_logic := '0';
signal is_metatraffic, is_metatraffic_next : std_logic := '0';
signal participant_id, participant_id_next : integer range 0 to NUM_DOMAIN-1 := 0;
signal flags, flags_next : std_logic_vector(7 downto 0) := (others => '0');
-- General purpose counter
signal cnt, cnt_next : integer := 0; --TODO: Range
-- Adder Signals
signal add_res, add_a, add_b : std_logic_vector(31 downto 0) := (others => '0');
signal add_cin, add_cout : std_logic := '0';
--*****ALIAS DEFINATION*****
-- UDP HEADER
alias udp_src_port : std_logic_vector(15 downto 0) is data_in(31 downto 16);
alias udp_dest_port : std_logic_vector(15 downto 0) is data_in(15 downto 0);
alias udp_length : std_logic_vector(15 downto 0) is data_in(31 downto 16);
alias udp_checksum : std_logic_vector(15 downto 0) is data_in(15 downto 0);
-- RTPS HEADER
alias rtps_version : std_logic_vector(15 downto 0) is data_in(31 downto 16);
alias rtps_vendorid : std_logic_vector(15 downto 0) is data_in(15 downto 0);
-- RTPS SUBMESSAGE HEADER
alias rtps_sub_id : std_logic_vector(7 downto 0) is aligned_data_in(31 downto 24);
alias rtps_sub_flags : std_logic_vector(7 downto 0) is aligned_data_in(23 downto 16);
alias rtps_sub_length : std_logic_vector(7 downto 0) is aligned_data_in(15 downto 0);
-- ACKNACK
alias rtps_acknack_final : std_logic is rtps_sub_flags(1);
-- MISC
--*****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) + to_unsigned(1, tmp'length));
end if;
return tmp;
end function;
-- Depending on the offset argument "off" returns a 32-bit slice from the 56-bit input signal
-- This is used to extract 32-bit aligned words from the input signal
function align_word ( off : std_logic_vector(1 downto 0),
input : std_logic_vector(56 downto 0)) return std_logic_vector is
variable ret : std_logic_vector(31 downto 0) := (others => '0');
begin
case(off) is
when "00" =>
ret := input(31 downto 0);
when "01" =>
ret := input(39 downto 8);
when "10" =>
ret := input(47 downto 16);
when "11" =>
ret := input(55 downto 24);
end case;
return ret;
end function;
-- Compares argument 'ref' with every elemant of 'ar', and returns the index of the last match.
-- If no match is found, array length is returned.
function match_domain_id ( ref : std_logic_vector(UDP_PORT_WIDTH-1 downto 0),
ar : IPv4_PORT_TYPE) return integer is
variable id : integer := 0;
begin
id := ar'length(1);
for i in 0 to ar'length-1 loop
if(ref = ar(i)) then
id := i;
end if;
end loop;
return id;
end function;
-- Returns the 'data' argument either as is, or with reversed Byte order, depending on the
-- 'endianness' argument.
function endian_swap( endianness : std_logic,
data :std_logic_vector(31 downto 0)) return std_logic_vector is
variable ret : std_logic_vector(31 downto 0);
begin
-- Little Endian
if (endianness = '1') then
-- Reverse byte Order
for i in 0 to 3 loop
ret(i*8+8-1 downto i*8) := data((3-i)*8+8-1 downto (3-i)*8);
end loop;
-- Big Endian
else
ret := data;
end if;
return ret;
end function;
begin
rd <= rd_sig;
align_prc : process(all)
variable input : std_logic_vector(55 downto 0) := (others => '0');
begin
input := align_sig & data_in;
case(align_offset) is
when "00" =>
aligned_data_in <= input(31 downto 0);
when "01" =>
aligned_data_in <= input(39 downto 8);
when "10" =>
aligned_data_in <= input(47 downto 16);
when "11" =>
aligned_data_in <= input(55 downto 24);
end case;
end process;
checksum_adder : adder
generic map (
PIPELINE_STAGES => 1,
DATA_WIDTH => 32
)
port map(
clk => clk,
reset => reset,
cin => add_cin,
A => add_a,
B => add_b,
RES => add_res,
cout => add_cout
);
end entity;
parse_prc: process(all)
variable tmp : integer range 0 to MAX_ENDPOINTS := 0;
begin
--DEFAULT
stage_next <= stage;
reset_read_cnt <= '0';
add_a <= (others => '0');
add_b <= (others => '0');
add_cin <= '0';
cnt_next <= count;
align_offset_next <= align_offset;
align_sig_next <= align_sig;
packet_length_next <= packet_length;
sub_length_next <= sub_length;
offset_latch_next <= offset_latch;
src_addr_next <= src_addr;
is_multicast_next <= is_multicast;
src_port_next <= src_port;
is_metatraffic_next <= is_metatraffic;
participant_id_next <= participant_id;
flags_next <= flags;
case(stage) is
-- Initial/Idle State
-- Src Addr
when SRC_ADDR =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Src Address
src_addr_next <= data_in;
-- Initiate Checksum Calculation
add_a <= data_in;
-- TODO: Reset Flags
is_multicast_next <= '0';
is_metatraffic_next <= '0';
-- Next Stage
stage_next <= DEST_ADDR;
end if;
-- Dest Addr
when DEST_ADDR =>
if (empty = '0') then
rd_sig <= '1';
-- Check Destination Address
if (data_in = IPv4_UNICAST_ADDRESS or data_in = DEFAULT_IPv4_MULTICAST_ADDRESS) then
-- Latch if Addr is Multicast
if (data_in = DEFAULT_IPv4_MULTICAST_ADDRESS) then
is_multicast_next <= '1';
end if;
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
-- Next Stage
stage_next <= UDP_HEADER_1;
-- packet not for us, skip
else
stage_next <= SKIP_PACKET;
end if;
else
-- Hold Checksum Value
add_a <= add_res;
end if;
when LEN =>
-- Reset packet Byte Counter
reset_read_cnt <= '1';
-- Hold Checksum Value
add_a <= add_res;
if (empty = '0') then
rd_sig <= '1';
-- Read Packet Length from input
packet_length_next <= unsigned(data_in(13 downto 0));
-- Check Packet Length
if(to_integer(unsigned(data_in(13 downto 0))) < MIN_PACKET_LENGTH) then
stage_next <= SKIP_PACKET;
else
-- Begin Processing
stage_next <= UDP_HEADER_1;
end if;
end if;
-- First UDP Header word (Fields: Src Port, Dest Port)
when UDP_HEADER_1 =>
if (empty = '0') then
rd_sig <= '1';
-- Latch Src Port
src_port_next <= udp_src_port;
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
-- Default Next Stage
stage_next <= SKIP_PACKET;
-- Check if Dest Port is valid, if not Skip Packet
if (is_multicast = '1') then
-- Check if Metatraffic (via Mutlicast)
tmp := match_domain_id(udp_dest_port, META_IPv4_MULTICAST_PORT);
if (tmp != MAX_ENDPOINTS) then
is_metatraffic_next <= '1';
participant_id_next <= tmp;
stage_next <= UDP_HEADER_2;
-- Check if User Traffic (via Multicast)
else
tmp := match_domain_id(udp_dest_port, USER_IPv4_MULTICAST_PORT);
if (tmp != MAX_ENDPOINTS) then
stage_next <= UDP_HEADER_2;
participant_id_next <= tmp;
end if;
end if;
else
-- Check if Metatraffic (via Unicast)
tmp := match_domain_id(udp_dest_port, META_IPv4_UNICAST_PORT);
if (tmp != MAX_ENDPOINTS) then
is_metatraffic_next <= '1';
participant_id_next <= tmp;
stage_next <= UDP_HEADER_2;
-- Check if User Traffic (via Unicast)
else
tmp := match_domain_id(udp_dest_port, USER_IPv4_UNICAST_PORT);
if (tmp != MAX_ENDPOINTS) then
stage_next <= UDP_HEADER_2;
participant_id_next <= tmp;
end if;
end if;
end if;
else
-- Hold Checksum Value
add_a <= add_res;
end if;
-- Second UDP Header Word (Fields: Length, Checksum)
when UDP_HEADER_2 =>
if (empty = '0') then
rd_sig <= '1';
-- If UPD header length does not match actual packet length, skip packet
if (normalize_length(udp_length) /= std_logic_vector(packet_length)) then
stage_next <= SKIP_PACKET;
else
-- Checksum Calculation
add_a <= (udp_length & x"0000");
add_b <= add_res;
add_cin <= add_cout;
-- Next Stage
stage_next <= RTPS_HEADER_1;
end if;
else
-- Hold Checksum Value
add_a <= add_res;
end if;
-- First RTPS Header word (Fields: Protocolld)
when RTPS_HEADER_1 =>
if (empty = '0') then
rd_sig <= '1';
-- If underlying Protocol is not RTPS, skip packet
if(data_in /= PROTOCOLLD_RTPS) then
stage_next <= SKIP_PACKET;
-- Continue Parsing
else
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
-- Next Stage
stage_next <= RTPS_HEADER_2;
end if;
else
-- Hold Checksum Value
add_a <= add_res;
end if;
-- Second RTPS Header word (Fields: Protocol Version, Vendor ID)
when RTPS_HEADER_2 =>
if (empty = '0') then
rd_sig <= '1';
-- If RTPS Protocol Major Version is not 2, skip packet
if(rtps_version(15 downto 8) /= PROTOCOLVERSION_2_4(15 downto 8)) then
stage_next <= SKIP_PACKET;
-- Continue Parsing
else
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
-- Reset GP Counter
cnt_next <= 1;
-- Next Stage
stage_next <= RTPS_HEADER_3;
end if;
else
-- Hold Checksum Value
add_a <= add_res;
end if;
-- Rest of RTPS Header (Fields: GUID Prefix)
when RTPS_HEADER_3 =>
if (empty = '0') then
rd_sig <= '1';
-- Sender GUID_Prefix
TODO <= data_in;
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
if (cnt = GUIDPREFIX_WIDTH/32) then
-- Next Stage
stage_next <= RTPS_SUB_HEADER;
else
cnt_next <= cnt + 1;
end if;
else
-- Hold Checksum Value
add_a <= add_res;
end if;
-- NOTE: From here on, due to the nature of the RTPS Protocol, 32-bit word alignement
-- is not guaranteed, and has to be handled.
-- RTPS Submessage Header (Fields: Submessage ID, Flags, Submessage Length)
when RTPS_SUB_HEADER =>
if (empty = '0') then
rd_sig <= '1';
case (rtps_sub_id) is
when SID_ACKNACK =>
-- Ignore Submessage if Final Flag not set
if (rtps_acknack_final = '1') then
-- Next Stage
stage_next <= ACKNACK_1;
else
-- Skip Submessage
stage_next <= SKIP_SUB;
end if;
when SID_PAD =>
when SID_HEARTBEAT =>
when SID_GAP =>
when SID_INFO_TS => --state
when SID_INFO_SRC => --state
when SID_INFO_REPLY_IP4 =>
when SID_INFO_DST => --state
when SID_INFO_REPLY => --state
when SID_NACK_FRAG =>
when SID_HEARTBEAT_FRAG =>
when SID_DATA =>
when SID_DATA_FRAG =>
-- Unknown ID, skip submessage
when others =>
stage_next <= SKIP_SUB;
end case;
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
-- Store Submessage Length
-- TODO: The below conditional +1 adder should be solved with a carry-in
sub_length_next <= packet_length + unsigned(normalize_length(rtps_sub_length));
-- Store Byte offset of next Header
offset_latch_next <= unsigned(align_offset) + unsigned(rtps_sub_length(1 downto 0));
-- Next Stage
align_sig_next <= data_in(23 downto 0);
else
-- Hold Checksum Value
add_a <= add_res;
end if;
when ACKNACK_1 =>
if (empty = '0') then
rd_sig <= '1';
--TODO
-- Checksum Calculation
add_a <= data_in;
add_b <= add_res;
add_cin <= add_cout;
-- Next Stage
align_sig_next <= data_in(23 downto 0);
else
-- Hold Checksum Value
add_a <= add_res;
end if;
when SKIP_PACKET =>
if (empty = '0') then
rd_sig <= '1';
-- End of Packet
if (read_cnt = packet_length) then
-- Continue parsing next packet
stage_next <= SRC_ADDR;
end if;
end if;
when SKIP_SUB =>
if (empty = '0') then
rd_sig <= '1';
-- End of Packet (No further Submessages)
if (read_cnt = packet_length) then
-- Continue parsing next packet
stage_next <= SRC_ADDR;
-- End of Submessage
elsif (read_cnt = sub_length) then
-- Begin parsing of next submessage
stage_next <= RTPS_SUB_HEADER;
-- Fix alignement
align_offset <= offset_latch;
end if;
end if;
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' or buffer_ren = '1') then
read_cnt <= read_cnt + to_unsigned(1, read_cnt'length);
end if;
end if;
end process;
end architecture;

View File

@ -3,145 +3,292 @@ use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package rtps_package is
--*****USER CONFIG*****
-- Unicast IPv4 Address used by all RTPS Entities [Default 192.168.0.80]
constant IPv4_UNICAST_ADDRESS : std_logic_vector(31 downto 0) := x"C0A80080";
-- Number of RTPS Writer Endpoints
constant NUM_WRITERS : integer := 0;
-- Number of RTPS Reader Endpoints
constant NUM_READERS : integer := 1;
-- PB Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_PB : integer := 7400;
-- DG Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_DG : integer := 250;
-- PG Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_PG : integer := 2;
-- D0 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D0 : integer := 0;
-- D1 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D1 : integer := 10;
-- D2 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D2 : integer := 1;
-- D3 Value of Default Port Generation (see DDSI-RTPS 2.3 Section 9.6.1)
constant PORT_CONFIG_D3 : integer := 11;
-- Number of Domains
constant NUM_DOMAIN : integer := 1;
-- MAC Address of underlying network stack (Used to generate GUIDs)
constant MAC_ADDRESS : std_logic_vector(47 downto 0) := x"97917E0BA8CF";
-----------------------------------------------------------------------------------------------------
-- *DO NOT MODIFY BEGIN*
type USER_DOMAIN_ID_TYPE is array (NUM_DOMAIN-1 downto 0) of integer;
-- *DO NOT MODIFY END*
-----------------------------------------------------------------------------------------------------
-- Array of Domain IDs
constant USER_DOMAIN_ID : USER_DOMAIN_ID_TYPE := (0 => 1);
-----------------------------------------------------------------------------------------------------
-- *DO NOT MODIFY BEGIN*
type ENDPOINT_DOMAIN_MAP_TYPE is array (NUM_READERS+NUM_WRITERS-1 downto 0) of integer;
type ENDPOINT_WITH_KEY_TYPE is array (NUM_READERS+NUM_WRITERS-1 downto 0) of boolean;
-- *DO NOT MODIFY END*
-----------------------------------------------------------------------------------------------------
--***RTPS ENDPOINTS***
-- Array mapping the RTPS Endpoints to their respective Domain IDs
-- The index of this array denotes the Endpoint, and the element value the index of the Domain in the 'USER_DOMAIN_ID'.
constant ENDPOINT_DOMAIN_MAP: ENDPOINT_DOMAIN_MAP_TYPE := (0 => 0);
-- Array denoting if Endpoints use Keyed Topics
constant ENDPOINT_WITH_KEY : ENDPOINT_WITH_KEY_TYPE := (0 => FALSE);
--*****DDSI-RTPS 2.3*****
-- Default Multicast Ipv4 Address (239.255.0.1)
constant DEFAULT_IPv4_MULTICAST_ADDRESS : std_logic_vector(31 downto 0) := x"EFFF0001";
subtype BYTE is std_logic_vector(7 downto 0);
type GUIDPREFIX_TYPE is array (11 downto 0) of BYTE;
constant GUIDPREFIX_UNKNOWN : GUIDPREFIX_TYPE := (others => (others => '0'));
type ENTITYID_TYPE is array (3 downto 0) of BYTE;
constant ENTITYID_UNKNOWN : ENTITYID_TYPE := (others => (others => '0'));
--alias ENTITYKIND : BYTE is ENTITYID(0);
--alias ENTITYKIND_UPPER : std_logic_vector(1 downto 0) is ENTITYKIND(7 downto 6);
--FOLLOWING MAP TO ENTITYKIND_UPPER
constant USER_DEFINED_ENTITY_KIND : std_logic_vector(1 downto 0) := "00";
constant BUILT_IN_ENTITY_KIND : std_logic_vector(1 downto 0) := "11";
constant VENDOR_SPECIFIC_ENTITY_KIND: std_logic_vector(1 downto 0) := "01";
--alias ENTITYKIND_LOWER : std_logic_vector(1 downto 0) is ENTITYKIND(5 downto 0);
--FOLLOWING MAP TO ENTITYKIND_LOWER
constant WRITER_WITH_KEY : std_logic_vector(5 downto 0) := "000010";
constant WRITER_NO_KEY : std_logic_vector(5 downto 0) := "000011";
constant READER_NO_KEY : std_logic_vector(5 downto 0) := "000100";
constant READER_WITH_KEY : std_logic_vector(5 downto 0) := "000111";
constant WRITER_GROUP : std_logic_vector(5 downto 0) := "001000";
constant READER_GROUP : std_logic_vector(5 downto 0) := "001001";
--
constant ENTITYID_PARTICIPANT : ENTITYID_TYPE := (x"00", x"00", x"01", x"c1");
constant ENTITYID_SEDP_BUILTIN_TOPICS_ANNOUNCER : ENTITYID_TYPE := (x"00", x"00", x"02", x"c2");
constant ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR : ENTITYID_TYPE := (x"00", x"00", x"02", x"c7");
constant ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER : ENTITYID_TYPE := (x"00", x"00", x"03", x"c2");
constant ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR : ENTITYID_TYPE := (x"00", x"00", x"03", x"c7");
constant ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER : ENTITYID_TYPE := (x"00", x"00", x"04", x"c2");
constant ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR : ENTITYID_TYPE := (x"00", x"00", x"04", x"c7");
constant ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER : ENTITYID_TYPE := (x"00", x"01", x"00", x"c2");
constant ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR : ENTITYID_TYPE := (x"00", x"01", x"00", x"c7");
constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: ENTITYID_TYPE := (x"00", x"02", x"00", x"c2");
constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: ENTITYID_TYPE := (x"00", x"02", x"00", x"c7");
type VENDORID_TYPE is array (1 downto 0) of BYTE;
--GUIDPREFIX(1 downto 0) <= VENDORID;
constant VENDORID_UNKNOWN : VENDORID_TYPE := (others => (others => '0'));
type PROTOCOLVERSION_TYPE is array (1 downto 0) of BYTE;
constant PROTOCOLVERSION_2_4 : PROTOCOLVERSION_TYPE := (x"02", x"04");
--General BITMAP SET Constants
constant NUMBITS_WIDTH : integer := 32;
constant BITMAP_WIDTH : integer := 32;
constant SEQUENCENUMBER_WIDTH : integer := 64;
type SEQUENCENUMBERSET_HEADER_TYPE is record {
bitmapBase : std_logic_vector(SEQUENCENUMBER_WIDTH-1 downto 0);
numBits : std_logic_vector(NUMBITS_WIDTH-1 downto 0);
};
subtype FRAGMENTNUMBER_WIDTH : integer := 32;;
type FRAGMENTNUMBERSET_HEADER_TYPE is record{
bitmapBase : std_logic_vector(FRAGMENTNUMBER_WIDTH-1 downto 0);
numBits : std_logic_vector(NUMBITS_WIDTH-1 downto 0);
};
--Fixed Point Q32.32
constant TIMESTAMP_WIDTH : integer := 64;
constant LOCATOR_KIND : integer := 32;
constant LOCATOR_PORT : integer := 32;
constant LOCATOR_ADDR : integer := 128;
type LOCATOR_TYPE is record{
kind : std_logic_vector(LOCATOR_KIND-1 downto 0);
port : std_logic_vector(LOCATOR_PORT-1 downto 0);
addr : std_logic_vector(LOCATOR_ADDR-1 downto 0);
};
constant NUMLOCATOR_WIDTH : integer := 32;
constant LOCATORUDPv4_PORT : integer := 32;
constant LOCATORUDPv4_ADDR : integer := 32;
type LOCATORUDPv4_TYPE is record{
addr : std_logic_vector(LOCATORUDPv4_ADDR-1 downto 0);
port : std_logic_vector(LOCATORUDPv4_PORT-1 downto 0);
};
constant PARAMETERID_WIDTH : integer := 16;
constant PARAMETERLENGTH_WIDTH : integer := 16;
type PARAMETER_HEADER_TYPE is record{
pid : std_logic_vector(PARAMETERID_WIDTH-1 downto 0);
length : std_logic_vector(PARAMETERLENGTH_WIDTH-1 downto 0);
};
constant PID_PAD : std_logic_vector(PARAMETERID_WIDTH-1 downto 0) := (others => '0');
constant PID_SENTINEL : std_logic_vector(PARAMETERID_WIDTH-1 downto 0) := std_logic_vector(unsigned(1,PARAMETERID_WIDTH));
constant COUNT_WIDTH : integer := 32;
--TODO: GroupDigest?
constant PROTOCOLLD_WIDTH : integer := 32;
type RTPS_HEADER_TYPE is record{
protocol : std_logic_vector(PROTOCOLLD_WIDTH-1 downto 0);
version : PROTOCOLVERSION_TYPE;
vendorid : VENDORID_TYPE;
guidprefix : GUIDPREFIX_TYPE;
};
constant PROTOCOLLD_RTPS : std_logic_vector(PROTOCOLLD_WIDTH-1 downto 0) := x"52545053";
constant SUBMESSAGE_ID_WIDTH : integer := 8;
constant SUBMESSAGE_FLAGS_WIDTH : integer := 8;
constant SUBMESSAGE_LENGTH_WIDTH : integer := 16;
type RTPS_SUBMESSAGE_HEADER_TYPE is record{
id : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0);
flags : std_logic_vector(SUBMESSAGE_FLAGS_WIDTH-1 downto 0);
length : std_logic_vector(SUBMESSAGE_LENGTH_WIDTH-1 downto 0);
};
constant SID_PAD : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"01";
constant SID_ACKNACK : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"06";
constant SID_HEARTBEAT : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"07";
constant SID_GAP : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"08";
constant SID_INFO_TS : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"09";
constant SID_INFO_SRC : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0c";
constant SID_INFO_REPLY_IP4 : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0d";
constant SID_INFO_DST : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0e";
constant SID_INFO_REPLY : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0f";
constant SID_NACK_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"12";
constant SID_HEARTBEAT_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"13";
constant SID_DATA : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"15";
constant SID_DATA_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"16";
--TODO: Enum it?
constant ENDIANNESS_FLAG_POS : integer := 0;
--ACKNACK
constant FINAL_FLAG_POS : integer := 1;
--DATA
constant INLINEQOS_FLAG_POS : integer := 1;
constant DATA_FLAG_POS : integer := 2;
constant KEY_FLAG_POS : integer := 3;
constant NONSTANDARDPAYLOAD_FLAG_POS: integer := 4;
constant GUIDPREFIX_WIDTH : integer := 96;
constant PROTOCOLVERSION_WIDTH : integer := 16;
constant VENDORID_WIDTH : integer := 16;
constant SUBMESSAGE_ID_WIDTH : integer := 8;
constant DOMAIN_ID_WIDTH : integer := 32;
constant UDP_PORT_WIDTH : integer := 16;
constant ENTITYID_WIDTH : integer := 32;
constant PROTOCOL_WIDTH : integer := 32;
-- 'RTPS' in Ascii code
constant PROTOCOL_RTPS : std_logic_vector(PROTOCOL_WIDTH-1 downto 0) := x"52545053";
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 VENDORID : std_logic_vector(VENDORID_WIDTH-1 downto 0) := VENDORID_UNKNOWN;
-- Submessage IDs
constant SID_PAD : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"01";
constant SID_ACKNACK : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"06";
constant SID_HEARTBEAT : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"07";
constant SID_GAP : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"08";
constant SID_INFO_TS : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"09";
constant SID_INFO_SRC : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0c";
constant SID_INFO_REPLY_IP4 : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0d";
constant SID_INFO_DST : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0e";
constant SID_INFO_REPLY : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"0f";
constant SID_NACK_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"12";
constant SID_HEARTBEAT_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"13";
constant SID_DATA : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"15";
constant SID_DATA_FRAG : std_logic_vector(SUBMESSAGE_ID_WIDTH-1 downto 0) := x"16";
type DOMAIN_ID_TYPE is array (NUM_DOMAIN-1 downto 0) of std_logic_vector(DOMAIN_ID_WIDTH-1 downto 0);
constant DOMAIN_ID : DOMAIN_ID_TYPE; -- Deferred to Package Body
type DOMAIN_ENDPOINT_MAP_TYPE is array (NUM_DOMAIN-1 downto 0) of std_logic_vector(NUM_READERS+NUM_WRITERS-1 downto 0);
constant DOMAIN_ENDPOINT_MAP : DOMAIN_ENDPOINT_MAP_TYPE; -- Deferred to Package Body
-- Since this implementation runs on the same network stack and the RTPS Endpoints (Readers & Writers)
-- can be differentiated based on their Entity ID, it makes no sense to have multiple IP Addresses
-- (and hence multiple Participants).
-- We generate just single participant for every Domain, and later match the Endpoints to their respective
-- Domain (and thus also to their respective RTPS Participant).
type IPv4_PORT_TYPE is array (NUM_DOMAIN-1 downto 0) of std_logic_vector(UDP_PORT_WIDTH-1 downto 0);
constant META_IPv4_MULTICAST_PORT: IPv4_PORT_TYPE; -- Deferred to Package Body
constant META_IPv4_UNICAST_PORT : IPv4_PORT_TYPE; -- Deferred to Package Body
constant USER_IPv4_MULTICAST_PORT: IPv4_PORT_TYPE; -- Deferred to Package Body
constant USER_IPv4_UNICAST_PORT : IPv4_PORT_TYPE; -- Deferred to Package Body
type GUIDPREFIX_TYPE is array (NUM_DOMAIN-1 downto 0) of std_logic_vector(GUIDPREFIX_WIDTH-1 downto 0);
constant GUIDPREFIX : GUIDPREFIX_TYPE; -- Deferred to Package Body
constant GUIDPREFIX_UNKNOWN : std_logic_vector(GUIDPREFIX_WIDTH-1 downto 0) := (others => '0');
subtype ENTITY_KIND_H is std_logic_vector(1 downto 0);
subtype ENTITY_KIND_L is std_logic_vector(5 downto 0);
--FOLLOWING MAP TO ENTITY_KIND_H
constant USER_DEFINED_ENTITY : ENTITY_KIND_H := "00";
constant BUILT_IN_ENTITY : ENTITY_KIND_H := "11";
constant VENDOR_SPECIFIC_ENTITY : ENTITY_KIND_H := "01";
--FOLLOWING MAP TO ENTITY_KIND_L
constant WRITER_WITH_KEY : ENTITY_KIND_L := "000010";
constant WRITER_NO_KEY : ENTITY_KIND_L := "000011";
constant READER_NO_KEY : ENTITY_KIND_L := "000100";
constant READER_WITH_KEY : ENTITY_KIND_L := "000111";
constant WRITER_GROUP : ENTITY_KIND_L := "001000";
constant READER_GROUP : ENTITY_KIND_L := "001001";
-- DDSI-RTPS 2.3 states that Entity IDs have to be unique within each Participant.
-- For simplicity and ease of mapping we make the Entity IDs unique across all Participant and Domains on this node.
type ENTITYID_TYPE is array (NUM_READERS+NUM_WRITERS-1 downto 0) of std_logic_vector(ENTITYID_WIDTH-1 downto 0);
constant ENTITYID : ENTITYID_TYPE; -- Deferred to Package Body
constant ENTITYID_UNKNOWN : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (others => '0');
constant ENTITYID_PARTICIPANT : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000001c1");
constant ENTITYID_SEDP_BUILTIN_TOPICS_ANNOUNCER : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000002c2");
constant ENTITYID_SEDP_BUILTIN_TOPICS_DETECTOR : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000002c7");
constant ENTITYID_SEDP_BUILTIN_PUBLICATIONS_ANNOUNCER : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000003c2");
constant ENTITYID_SEDP_BUILTIN_PUBLICATIONS_DETECTOR : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000003c7");
constant ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_ANNOUNCER : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000004c2");
constant ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_DETECTOR : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000004c7");
constant ENTITYID_SPDP_BUILTIN_PARTICIPANT_ANNOUNCER : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000100c2");
constant ENTITYID_SPDP_BUILTIN_PARTICIPANT_DETECTOR : std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000100c7");
constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000200c2");
constant ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: std_logic_vector(ENTITYID_WIDTH-1 downto 0) := (x"000200c7");
constant LOCATOR_KIND_WIDTH : integer := 32;
constant LOCATOR_KIND_INVALID : std_logic_vector := std_logic_vector(to_signed(-1,LOCATOR_KIND_WIDTH));
constant LOCATOR_KIND_RESERVERD : std_logic_vector := std_logic_vector(to_signed(0,LOCATOR_KIND_WIDTH));
constant LOCATOR_KIND_UDPv4 : std_logic_vector := std_logic_vector(to_signed(1,LOCATOR_KIND_WIDTH));
constant LOCATOR_KIND_UDPv6 : std_logic_vector := std_logic_vector(to_signed(2,LOCATOR_KIND_WIDTH));
--*****CUSTOM*****
--****************
type USER_ENDPOINT_OUTPUT is array (NUM_READERS+NUM_WRITERS-1 downto 0) of std_logic_vector(31 downto 0);
type BUILTIN_ENDPOINT_TYPE is array (NUM_DOMAIN-1 downto 0) of std_logic_vector(31 downto 0);
end package;
package body rtps_package is
function gen_domain_ids (user_id : USER_DOMAIN_ID_TYPE) return DOMAIN_ID_TYPE is
variable ret : DOMAIN_ID_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to user_id'length-1 loop
-- Check if User provided Domain ID fits
-- NOTE: Cannot assert due to vhdl integer overflow.
--assert (user_id(i) < (2**DOMAIN_ID_WIDTH-1 - PORT_CONFIG_PB) / PORT_CONFIG_DG) report "Domain ID range exceeded" severity failure;
ret(i) := std_logic_vector(to_unsigned(user_id(i), ret(i)'length));
end loop;
return ret;
end function;
constant DOMAIN_ID : DOMAIN_ID_TYPE := gen_domain_ids(USER_DOMAIN_ID);
function gen_domain_endpoint_map (end_id : ENDPOINT_DOMAIN_MAP_TYPE) return DOMAIN_ENDPOINT_MAP_TYPE is
variable ret : DOMAIN_ENDPOINT_MAP_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to NUM_DOMAIN-1 loop
for j in 0 to NUM_READERS+NUM_WRITERS-1 loop
if (i = end_id(j)) then
ret(i)(j) := '1';
end if;
end loop;
end loop;
return ret;
end function;
constant DOMAIN_ENDPOINT_MAP : DOMAIN_ENDPOINT_MAP_TYPE := gen_domain_endpoint_map(ENDPOINT_DOMAIN_MAP);
function gen_meta_multicast_ports (domain_id : DOMAIN_ID_TYPE) return IPv4_PORT_TYPE is
variable ret : IPv4_PORT_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to domain_id'length-1 loop
-- (see DDSI-RTPS 2.3 Section 9.6.1)
-- PB + DG * domain_id + d0
ret(i) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D0 + PORT_CONFIG_DG*to_integer(unsigned(domain_id(i))), ret(i)'length));
end loop;
return ret;
end function;
function gen_meta_unicast_ports (domain_id : DOMAIN_ID_TYPE) return IPv4_PORT_TYPE is
variable ret : IPv4_PORT_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to domain_id'length-1 loop
-- (see DDSI-RTPS 2.3 Section 9.6.1)
-- PB + DG * domainId + d1 + PG * participant_id
-- participant_id=0
ret(i) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D1 + PORT_CONFIG_DG*to_integer(unsigned(domain_id(i))), ret(i)'length));
end loop;
return ret;
end function;
function gen_user_multicast_ports (domain_id : DOMAIN_ID_TYPE) return IPv4_PORT_TYPE is
variable ret : IPv4_PORT_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to domain_id'length-1 loop
-- (see DDSI-RTPS 2.3 Section 9.6.1)
-- PB + DG * domainId + d2
ret(i) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D2 + PORT_CONFIG_DG*to_integer(unsigned(domain_id(i))), ret(i)'length));
end loop;
return ret;
end function;
function gen_user_unicast_ports (domain_id : DOMAIN_ID_TYPE) return IPv4_PORT_TYPE is
variable ret : IPv4_PORT_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to domain_id'length-1 loop
-- (see DDSI-RTPS 2.3 Section 9.6.1)
-- PB + DG * domainId + d3 + PG * participant_id
-- participant_id=0
ret(i) := std_logic_vector(to_unsigned(PORT_CONFIG_PB + PORT_CONFIG_D3 + PORT_CONFIG_DG*to_integer(unsigned(domain_id(i))), ret(i)'length));
end loop;
return ret;
end function;
constant META_IPv4_MULTICAST_PORT: IPv4_PORT_TYPE := gen_meta_multicast_ports(DOMAIN_ID);
constant META_IPv4_UNICAST_PORT : IPv4_PORT_TYPE := gen_meta_unicast_ports(DOMAIN_ID);
constant USER_IPv4_MULTICAST_PORT: IPv4_PORT_TYPE := gen_user_multicast_ports(DOMAIN_ID);
constant USER_IPv4_UNICAST_PORT : IPv4_PORT_TYPE := gen_user_unicast_ports(DOMAIN_ID);
function gen_guid_prefix (domain_id : DOMAIN_ID_TYPE) return GUIDPREFIX_TYPE is
variable ret : GUIDPREFIX_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to ret'length-1 loop
-- First to bytes have to be Vendor ID (see DDSI-RTPS 2.3 Section 9.3.1.5)
ret(i)(ret(i)'length-1 downto ret(i)'length-VENDORID_WIDTH) := VENDORID;
-- Next we insert the MAC address for uniqueness
ret(i)(ret(i)'length-VENDORID_WIDTH-1 downto ret(i)'length-VENDORID_WIDTH-48) := MAC_ADDRESS;
-- Next we insert the Domain ID
-- NOTE: If the widths of signals change in the future, this will overwrite part of the MAC Address.
ret(i)(DOMAIN_ID_WIDTH-1 downto 0) := domain_id(i);
end loop;
return ret;
end function;
constant GUIDPREFIX : GUIDPREFIX_TYPE := gen_guid_prefix(DOMAIN_ID);
function gen_entyid return ENTITYID_TYPE is
variable ret : ENTITYID_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to ret'length-1 loop
-- (see DDSI-RTPS 2.3 Section 9.3.1.2)
-- Entity Kind Mapping
ret(i)(7 downto 6) := USER_DEFINED_ENTITY;
if (i <= NUM_READERS-1) then
if (ENDPOINT_WITH_KEY(i)) then
ret(i)(5 downto 0) := READER_WITH_KEY;
else
ret(i)(5 downto 0) := READER_NO_KEY;
end if;
else
if (ENDPOINT_WITH_KEY(i)) then
ret(i)(5 downto 0) := WRITER_WITH_KEY;
else
ret(i)(5 downto 0) := WRITER_NO_KEY;
end if;
end if;
-- ID Mapping
ret(i)(ENTITYID_WIDTH-1 downto 8) := std_logic_vector(to_unsigned(i,ENTITYID_WIDTH-8));
end loop;
return ret;
end function;
constant ENTITYID : ENTITYID_TYPE := gen_entyid;
end package body;

46
src/test.vhd Normal file
View File

@ -0,0 +1,46 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package rtps_package is
-- Number of Domains
constant NUM_DOMAIN : integer := 1;
-----------------------------------------------------------------------------------------------------
-- *DO NOT MODIFY BEGIN*
type USER_DOMAIN_ID_TYPE is array (NUM_DOMAIN-1 downto 0) of integer;
-- *DO NOT MODIFY END*
-----------------------------------------------------------------------------------------------------
-- Array of Domain IDs
constant USER_DOMAIN_ID : USER_DOMAIN_ID_TYPE := (0 => 1);
constant DOMAIN_ID_WIDTH : integer := 32;
type DOMAIN_ID_TYPE is array (NUM_DOMAIN-1 downto 0) of std_logic_vector(DOMAIN_ID_WIDTH-1 downto 0);
function gen_domain_ids (user_id : USER_DOMAIN_ID_TYPE) return DOMAIN_ID_TYPE;
end package;
package body rtps_package is
function gen_domain_ids (user_id : USER_DOMAIN_ID_TYPE) return DOMAIN_ID_TYPE is
variable ret : DOMAIN_ID_TYPE;
begin
ret := (others => (others => '0'));
for i in 0 to user_id'length-1 loop
-- Check if User provided Domain ID fits
-- NOTE: Cannot assert due to vhdl integer overflow.
--assert (user_id(i) < (2**DOMAIN_ID_WIDTH-1 - PORT_CONFIG_PB) / PORT_CONFIG_DG) report "Domain ID range exceeded" severity failure;
ret(i) := std_logic_vector(to_unsigned(user_id(i), ret(i)'length));
end loop;
return ret;
end function;
constant DOMAIN_ID : DOMAIN_ID_TYPE := gen_domain_ids(USER_DOMAIN_ID);
end package body;

View File

@ -86,7 +86,9 @@
</File>
<Config>
<Option Name="DesignMode" Val="RTL"/>
<Option Name="TopModule" Val="ipv4_in"/>
<Option Name="TopModule" Val="ipv4_in_handler"/>
<Option Name="TopLib" Val="xil_defaultlib"/>
<Option Name="TopArchitecture" Val="with_frag"/>
<Option Name="TopAutoSet" Val="TRUE"/>
</Config>
</FileSet>
@ -106,8 +108,9 @@
<Filter Type="Srcs"/>
<Config>
<Option Name="DesignMode" Val="RTL"/>
<Option Name="TopModule" Val="ipv4_in"/>
<Option Name="TopModule" Val="ipv4_in_handler"/>
<Option Name="TopLib" Val="xil_defaultlib"/>
<Option Name="TopArchitecture" Val="with_frag"/>
<Option Name="TopAutoSet" Val="TRUE"/>
<Option Name="TransportPathDelay" Val="0"/>
<Option Name="TransportIntDelay" Val="0"/>