rtps-fpga/syn/loopback.vhd
John Daktylidis 4c51a3944a Add UDP loopback in De10-Nano GHRD Project and generate output files
The UDP loopback just reads from the input FIFO, reverses src and destination
addresses, and writes back to the output FIFO.
This can be used to measure the throughput of the HPS-FPGA communication
2023-07-29 12:23:06 +02:00

173 lines
6.6 KiB
VHDL

-- altera vhdl_input_version vhdl_2008
-- XXX: QSYS Fix (https://www.intel.com/content/www/us/en/support/programmable/articles/000079458.html)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.rtps_package.all;
-- LOOPBACK
-- This entity reads packets form the input FIFO, flips the src/dest address and ports, and writes the packet back to
-- the output FIFO.
-- This loopback entity can be used to measure maximum throughput through the FIFO interfaces.
-- Packets have following structure:
-- 31............24..............16..............8...............0
-- | | | | |
-- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-- +---------------------------------------------------------------+
-- 01| SRC_IPv4_ADDR |
-- +---------------------------------------------------------------+
-- 02| DEST_IPv4_ADDR |
-- +-------------------------------+-------------------------------+
-- 03| SRC_UDP_PORT | DEST_UDP_PORT |
-- +-------------------------------+-------------------------------+
-- 04| PACKET_LENGTH |
-- +---------------------------------------------------------------+
-- 05| |
-- ~ PACKET ~
-- **| |
-- +---------------------------------------------------------------+
entity loopback is
port (
-- SYSTEM
clk : in std_logic;
reset : in std_logic;
-- INPUT
empty : in std_logic;
rd : out std_logic;
data_in : in std_logic_vector(WORD_WIDTH-1 downto 0);
-- OUTPUT
full : in std_logic;
wr : out std_logic;
data_out : out std_logic_vector(WORD_WIDTH-1 downto 0)
);
end entity;
architecture arch of loopback is
-- *TYPE DECLARATION*
type STAGE_TYPE is (READ_SRC_ADDR, READ_DEST_ADDR, READ_PORTS, READ_LENGTH, WRITE_SRC_ADDR, WRITE_DEST_ADDR, WRITE_PORTS, WRITE_LENGTH, PASSTHROUGH);
-- *SIGNAL DECLARATION*
signal stage, stage_next : STAGE_TYPE;
signal src_addr, src_addr_next : std_logic_vector(WORD_WIDTH-1 downto 0);
signal dest_addr, dest_addr_next : std_logic_vector(WORD_WIDTH-1 downto 0);
signal ports, ports_next : std_logic_vector(WORD_WIDTH-1 downto 0);
signal length, length_next : unsigned(WORD_WIDTH-1 downto 0);
signal cnt, cnt_next : unsigned(WORD_WIDTH-1 downto 0);
begin
main_prc : process (all)
begin
-- DEFAULT
stage_next <= stage;
src_addr_next <= src_addr;
dest_addr_next <= dest_addr;
ports_next <= ports;
length_next <= length;
cnt_next <= cnt;
-- DEFAULT Unregistered
rd <= '0';
wr <= '0';
data_out <= (others => '0');
case (stage) is
when READ_SRC_ADDR =>
-- Input FIFO Guard
if (empty = '0') then
src_addr_next <= data_in;
rd <= '1';
stage_next <= READ_DEST_ADDR;
end if;
when READ_DEST_ADDR =>
-- Input FIFO Guard
if (empty = '0') then
dest_addr_next <= data_in;
rd <= '1';
stage_next <= READ_PORTS;
end if;
when READ_PORTS =>
-- Input FIFO Guard
if (empty = '0') then
ports_next <= data_in;
rd <= '1';
stage_next <= READ_LENGTH;
end if;
when READ_LENGTH =>
-- Input FIFO Guard
if (empty = '0') then
length_next <= unsigned(data_in);
rd <= '1';
stage_next <= WRITE_SRC_ADDR;
end if;
when WRITE_SRC_ADDR =>
-- Output FIFO Guard
if (full = '0') then
data_out <= dest_addr;
wr <= '1';
stage_next <= WRITE_DEST_ADDR;
end if;
when WRITE_DEST_ADDR =>
-- Output FIFO Guard
if (full = '0') then
data_out <= src_addr;
wr <= '1';
stage_next <= WRITE_PORTS;
end if;
when WRITE_PORTS =>
-- Output FIFO Guard
if (full = '0') then
data_out <= ports(UDP_PORT_WIDTH-1 downto 0) & ports(WORD_WIDTH-1 downto UDP_PORT_WIDTH);
wr <= '1';
stage_next <= WRITE_LENGTH;
end if;
when WRITE_LENGTH =>
-- Output FIFO Guard
if (full = '0') then
data_out <= std_logic_vector(length);
wr <= '1';
stage_next <= PASSTHROUGH;
cnt_next <= to_unsigned(1,WORD_WIDTH);
end if;
when PASSTHROUGH =>
-- Input & Output FIFO Guard
if (empty = '0' and full = '0') then
data_out <= data_in;
rd <= '1';
wr <= '1';
cnt_next <= cnt + 1;
-- Reached End of Packet
if (cnt = length) then
stage_next <= READ_SRC_ADDR;
end if;
end if;
end case;
end process;
sync_prc : process(all)
begin
if rising_edge(clk) then
if (reset = '1') then
stage <= READ_SRC_ADDR;
src_addr <= (others => '0');
dest_addr <= (others => '0');
ports <= (others => '0');
length <= (others => '0');
cnt <= (others => '0');
else
stage <= stage_next;
src_addr <= src_addr_next;
dest_addr <= dest_addr_next;
ports <= ports_next;
length <= length_next;
cnt <= cnt_next;
end if;
end if;
end process;
end architecture;