* Add documentation
- IPv4 RFC - FPGA Network Stack Master Thesis * Updated .gitignore * Added Single Port RAM - Xillinx Specific * Added IPv4 Parser - Dynamic Re-assembly Buffer selection - Main entity documentation missing - Synthesized, but not tested or simulated * Added Vivado (Zedboard) project for synthesis testing
This commit is contained in:
parent
b118482e63
commit
10cda546bf
14
.gitignore
vendored
14
.gitignore
vendored
@ -0,0 +1,14 @@
|
|||||||
|
#Ignore List
|
||||||
|
/syn/**
|
||||||
|
/modelsim/**
|
||||||
|
/download/**
|
||||||
|
|
||||||
|
|
||||||
|
#Unignore Directories (Needed to unignore files in Subdirectories)
|
||||||
|
!*/
|
||||||
|
|
||||||
|
#WHITELIST
|
||||||
|
#Vivado Project File
|
||||||
|
!*.xpr
|
||||||
|
#Modelsim Do files
|
||||||
|
!*.do
|
||||||
BIN
doc/TFM - MEMORY .pdf
(Stored with Git LFS)
Normal file
BIN
doc/TFM - MEMORY .pdf
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
doc/rfc791.pdf
(Stored with Git LFS)
Normal file
BIN
doc/rfc791.pdf
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
doc/rfc815.pdf
(Stored with Git LFS)
Normal file
BIN
doc/rfc815.pdf
(Stored with Git LFS)
Normal file
Binary file not shown.
18
src/ip_package.vhd
Normal file
18
src/ip_package.vhd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
package ip_package is
|
||||||
|
|
||||||
|
-- TODO : Fix assignemnt of 1 wide array
|
||||||
|
constant LAYER3_PROTOCOL_NUM : integer := 1;
|
||||||
|
type LAYER3_PROTOCOL_TYPE is array (LAYER3_PROTOCOL_NUM-1 downto 0) of std_logic_vector(7 downto 0);
|
||||||
|
constant LAYER3_PROTOCOLS : LAYER3_PROTOCOL_TYPE := (0 => x"11");
|
||||||
|
|
||||||
|
--OUTPUT TYPES
|
||||||
|
type IP_OUTPUT_TYPE is array (LAYER3_PROTOCOL_NUM-1 downto 0) of std_logic_vector(31 downto 0);
|
||||||
|
|
||||||
|
end package;
|
||||||
|
|
||||||
|
package body ip_package is
|
||||||
|
end package body;
|
||||||
729
src/ipv4_in.vhd
Normal file
729
src/ipv4_in.vhd
Normal file
@ -0,0 +1,729 @@
|
|||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use work.ip_package.all;
|
||||||
|
use work.math_pkg.all;
|
||||||
|
|
||||||
|
entity ipv4_in is
|
||||||
|
generic(
|
||||||
|
CLK_FREQ : integer := 20000000;
|
||||||
|
MAX_FRAG_SIZE : integer := 1600;
|
||||||
|
MAX_PARALLEL_FRAG : integer := 1;
|
||||||
|
DEFAULT_FRAG_TIMEOUT: integer := 5
|
||||||
|
);
|
||||||
|
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
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of ipv4_in is
|
||||||
|
|
||||||
|
--*****COMPONENT DECLARATION*****
|
||||||
|
-- The RAM is used for reassembly of ip fragments.
|
||||||
|
-- The RAM should have a READ latency of 1 clock cycle,
|
||||||
|
-- and a WRITE latency smaller than 5 clock cycles
|
||||||
|
component single_port_ram is
|
||||||
|
generic (
|
||||||
|
ADDR_WIDTH : integer := 8;
|
||||||
|
DATA_WIDTH : integer := 12;
|
||||||
|
MEMORY_SIZE : integer := DATA_WIDTH*(2**ADDR_WIDTH)
|
||||||
|
);
|
||||||
|
port (
|
||||||
|
clk : in std_logic;
|
||||||
|
addr : in std_logic_vector(ADDR_WIDTH-1 downto 0);
|
||||||
|
wen : in std_logic;
|
||||||
|
ren : in std_logic;
|
||||||
|
wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0);
|
||||||
|
rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0)
|
||||||
|
);
|
||||||
|
end component;
|
||||||
|
|
||||||
|
--*****CONSTANT DECLARATION*****
|
||||||
|
-- The width of the RAM address has a lower bound equal to the fragment offset field
|
||||||
|
constant RAM_ADDR_WIDTH : integer := max(log2c(MAX_PARALLEL_FRAG*MAX_FRAG_SIZE), 14);
|
||||||
|
|
||||||
|
--*****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, IPv4_FRAGMENT_PRE, IPv4_FRAGMENT,
|
||||||
|
IPv4_FRAGMENT_POST, IPv4_BUFFER_SRC, IPv4_BUFFER_DEST, IPv4_BUFFER_LENGTH, IPv4_BUFFER_PAYLOAD,
|
||||||
|
SKIP_HEADER, SKIP_PACKET);
|
||||||
|
-- Array of buffer identifiers. A buffer identifier is the concatenation of source, destination, protocol, and identification fields
|
||||||
|
-- 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);
|
||||||
|
-- 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);
|
||||||
|
-- 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);
|
||||||
|
-- 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);
|
||||||
|
-- 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);
|
||||||
|
|
||||||
|
|
||||||
|
--*****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';
|
||||||
|
-- States if the current processed packet is a fragment
|
||||||
|
signal is_fragment, is_fragment_next : std_logic := '0';
|
||||||
|
-- States if the current processed packet is the last fragment (Needed to determine total payload size)
|
||||||
|
signal is_last_fragment, is_last_fragment_next : std_logic := '0';
|
||||||
|
-- Clock with 1 Hz Frequency
|
||||||
|
signal sec_clk : std_logic := '0';
|
||||||
|
-- Counter used to generate 'sec_clk'
|
||||||
|
signal sec_cnt : integer range 0 to (CLK_FREQ/2)-1 := 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;
|
||||||
|
-- Buffer Identifiers for each buffer. See 'BUFFER_ID_ARRAY'
|
||||||
|
signal buffer_id, buffer_id_next : BUFFER_ID_ARRAY := (others => (others => '0'));
|
||||||
|
-- Used as Constant. See 'BUFFER_ADDR_OFFSET_TYPE'
|
||||||
|
signal buffer_addr_offset : BUFFER_ADDR_OFFSET_TYPE := (others => (others => '0'));
|
||||||
|
-- Bitmap array. See 'BUFFER_BITMAP_ARRAY'
|
||||||
|
signal buffer_bitmap, buffer_bitmap_next : BUFFER_BITMAP_ARRAY := (others => (others => '0'));
|
||||||
|
-- 32-bit word aligned fragment offset
|
||||||
|
signal frag_offset, frag_offset_next : unsigned(13 downto 0) := (others => '0');
|
||||||
|
-- Packet size array. See 'FRAG_SIZE_ARRAY'
|
||||||
|
signal frag_size, frag_size_next : FRAG_SIZE_ARRAY := (others => (others => '0'));
|
||||||
|
-- TimeToLive temporary storage
|
||||||
|
signal ttl, ttl_next : std_logic_vector(7 downto 0);
|
||||||
|
-- Buffer Timers. See 'BUFFER_TIMER_ARRAY'
|
||||||
|
signal buffer_timer : BUFFER_TIMER_ARRAY := (others => (others => '0'));
|
||||||
|
-- Received fragment word counters. See BUFFER_WORD_COUNTER_ARRAY
|
||||||
|
signal buffer_word_cnt, buffer_word_cnt_next : BUFFER_WORD_COUNTER_ARRAY := (others => 0);
|
||||||
|
-- Timeout values of buffer timers
|
||||||
|
signal max_buffer_timer, max_buffer_timer_next : BUFFER_TIMER_ARRAY := (others => (others => '0'));
|
||||||
|
-- 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;
|
||||||
|
-- ID of current buffer
|
||||||
|
signal cur_buffer_id, cur_buffer_id_next : integer range 0 to max(MAX_PARALLEL_FRAG-1,0) := 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, wr_sig_del : std_logic;
|
||||||
|
-- RAM Signals
|
||||||
|
signal buffer_addr, buffer_addr_next : unsigned(RAM_ADDR_WIDTH-1 downto 0) := (others => '0');
|
||||||
|
signal buffer_wen, buffer_ren : std_logic := '0';
|
||||||
|
signal buffer_wr_data, buffer_rd_data : std_logic_vector(31 downto 0) := (others => '0');
|
||||||
|
-- Old RAM Address (Used to reset address on read error)
|
||||||
|
signal buffer_addr_old, buffer_addr_old_next : unsigned(RAM_ADDR_WIDTH-1 downto 0) := (others => '0');
|
||||||
|
|
||||||
|
|
||||||
|
--*****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*****
|
||||||
|
|
||||||
|
-- Compares all buffer identifiers with the last identifier. If there is a match, it returns the
|
||||||
|
-- array index of the buffer identifier that matches, else it returns the highest index (which is the
|
||||||
|
-- base of the comparisons)
|
||||||
|
function match_buffer_id (ids : BUFFER_ID_ARRAY) return integer is
|
||||||
|
variable id, max_id : integer := 0;
|
||||||
|
begin
|
||||||
|
max_id := ids'length - 1;
|
||||||
|
id := max_id;
|
||||||
|
for i in 0 to ids'length - 2 loop
|
||||||
|
if(ids(i) = ids(max_id)) then
|
||||||
|
id := i;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
return id;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
-- Returns the last zero buffer id index
|
||||||
|
function empty_buffer_id (ids : BUFFER_ID_ARRAY) return integer is
|
||||||
|
variable id : integer := 0;
|
||||||
|
begin
|
||||||
|
id := ids'length - 1;
|
||||||
|
for i in 0 to ids'length - 2 loop
|
||||||
|
if(ids(i) = (ids(i)'reverse_range => '0')) then
|
||||||
|
id := i;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
return id;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
-- Generic Assertions
|
||||||
|
assert (MAX_PARALLEL_FRAG >= 0) report "MAX_PARALLEL_FRAG has to be positive" 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
|
||||||
|
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;
|
||||||
|
|
||||||
|
rd <= rd_sig;
|
||||||
|
|
||||||
|
-- This process is responsible for MUXing the correct signal to the correct output FIFO
|
||||||
|
output_prc : process(all)
|
||||||
|
begin
|
||||||
|
-- Reading from input FIFO
|
||||||
|
if(stage /= IPv4_BUFFER_PAYLOAD) then
|
||||||
|
data_out(output_id) <= data_out_sig;
|
||||||
|
wr(output_id) <= wr_sig;
|
||||||
|
-- Reading from RAM Buffer
|
||||||
|
else
|
||||||
|
data_out(output_id) <= buffer_rd_data;
|
||||||
|
-- The state machine toggles the 'wr_sig_del' on the first cycle when full is high
|
||||||
|
-- The and gate here prevents this from propagating to the actual fifo.
|
||||||
|
wr(output_id) <= wr_sig_del and (not full(output_id));
|
||||||
|
end if;
|
||||||
|
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
|
||||||
|
-- IPv4_FRAGMENT_PRE Fragment pre-processing. Checking if fragment is part of already initiated packet re-assembly, initiating new packetre-assembly, or dropping packet if no resources available
|
||||||
|
-- IPv4_FRAGMENT Writing fragment from input FIFO to RAM buffer
|
||||||
|
-- IPv4_FRAGMENT_POST Fragment post-processing. Checking if received fragment completes the re-assembled packet.
|
||||||
|
-- IPv4_BUFFER_SRC Writing re-assembled packet(payload) SRC Address to output FIFO
|
||||||
|
-- IPv4_BUFFER_DEST Writing re-assembled packet(payload) DEST Address to output FIFO
|
||||||
|
-- IPv4_BUFFER_LENGTH Writing re-assembled packet(payload) length to output FIFO
|
||||||
|
-- IPv4_BUFFER_PAYLOAD Writing re-assembled packet(payload) from RAM 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;
|
||||||
|
variable tmp_frag_offset : unsigned(buffer_addr'length-1 downto 0) := (others => '0');
|
||||||
|
begin
|
||||||
|
--DEFAULT Registered
|
||||||
|
stage_next <= stage;
|
||||||
|
packet_length_next <= packet_length;
|
||||||
|
header_length_next <= header_length;
|
||||||
|
is_fragment_next <= is_fragment;
|
||||||
|
is_last_fragment_next <= is_last_fragment;
|
||||||
|
frag_offset_next <= frag_offset;
|
||||||
|
buffer_id_next <= buffer_id;
|
||||||
|
ttl_next <= ttl;
|
||||||
|
output_id_next <= output_id;
|
||||||
|
frag_size_next <= frag_size;
|
||||||
|
cur_buffer_id_next <= cur_buffer_id;
|
||||||
|
buffer_bitmap_next <= buffer_bitmap;
|
||||||
|
buffer_addr_next <= buffer_addr;
|
||||||
|
buffer_addr_old_next <= buffer_addr_old;
|
||||||
|
buffer_word_cnt_next <= buffer_word_cnt;
|
||||||
|
-- DEFAULT Unregistered
|
||||||
|
rd_sig <= '0';
|
||||||
|
wr_sig <= '0';
|
||||||
|
data_out_sig <= (others => '0');
|
||||||
|
reset_buffer_timer <= '0';
|
||||||
|
reset_buffer_timer_id <= 0;
|
||||||
|
buffer_wen <= '0';
|
||||||
|
buffer_ren <= '0';
|
||||||
|
buffer_wr_data <= (others => '0');
|
||||||
|
reset_read_cnt <= '0';
|
||||||
|
|
||||||
|
case(stage) is
|
||||||
|
-- Initial/Idle State
|
||||||
|
when IPv4_INIT =>
|
||||||
|
-- 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
|
||||||
|
-- If timeout reached
|
||||||
|
if(buffer_timer(i) >= max_buffer_timer(i)) then
|
||||||
|
-- Free Buffer ID
|
||||||
|
buffer_id_next(i) <= (others => '0');
|
||||||
|
-- The rest of the Buffer related values are reset upon buffer selection
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
-- Read Packet Length from input
|
||||||
|
if (empty = '0') then
|
||||||
|
packet_length_next <= unsigned(data_in(13 downto 0));
|
||||||
|
rd_sig <= '1';
|
||||||
|
-- Reset Parsing Flags
|
||||||
|
is_fragment_next <= '0';
|
||||||
|
is_last_fragment_next <= '0';
|
||||||
|
-- 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
|
||||||
|
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;
|
||||||
|
end if;
|
||||||
|
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;
|
||||||
|
-- Store Fragment relevant data
|
||||||
|
if (is_fragment = '1') then
|
||||||
|
ttl_next <= ip_ttl;
|
||||||
|
-- Temporal storage for comparison
|
||||||
|
buffer_id_next(MAX_PARALLEL_FRAG)(23 downto 16) <= ip_protocol;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
-- Fourth IPv4 Header word (Fields: Src Address)
|
||||||
|
when IPv4_HEADER_4 =>
|
||||||
|
if (empty = '0') then
|
||||||
|
-- Store relevant fragment data
|
||||||
|
if (is_fragment = '1') then
|
||||||
|
rd_sig <= '1';
|
||||||
|
-- Temporal storage for comparison
|
||||||
|
buffer_id_next(MAX_PARALLEL_FRAG)(87 downto 56) <= data_in;
|
||||||
|
-- Write Src Address to Output FIFO
|
||||||
|
elsif (full(output_id) = '0') then
|
||||||
|
rd_sig <= '1';
|
||||||
|
wr_sig <= '1';
|
||||||
|
data_out_sig <= data_in;
|
||||||
|
end if;
|
||||||
|
-- In both cases, Continue Parsing
|
||||||
|
if (is_fragment = '1' or full(output_id) = '0') then
|
||||||
|
stage_next <= IPv4_HEADER_5;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
-- Fourth IPv4 Header word (Fields: Dest Address)
|
||||||
|
when IPv4_HEADER_5 =>
|
||||||
|
if (empty = '0') then
|
||||||
|
-- Store relevant fragment data
|
||||||
|
if (is_fragment = '1') then
|
||||||
|
rd_sig <= '1';
|
||||||
|
-- Temporal storage for comparison
|
||||||
|
buffer_id_next(MAX_PARALLEL_FRAG)(55 downto 24) <= data_in;
|
||||||
|
-- Write Dst Address to Output FIFO
|
||||||
|
elsif (full(output_id) = '0') then
|
||||||
|
rd_sig <= '1';
|
||||||
|
wr_sig <= '1';
|
||||||
|
data_out_sig <= data_in;
|
||||||
|
end if;
|
||||||
|
-- In both cases
|
||||||
|
if (is_fragment = '1' or full(output_id) = '0') then
|
||||||
|
-- Check Header Size
|
||||||
|
if (read_cnt /= ("0000000000" & header_length)) then
|
||||||
|
-- If Header has "Options", skip to Payload
|
||||||
|
stage_next <= SKIP_HEADER;
|
||||||
|
else
|
||||||
|
if (is_fragment = '1') then
|
||||||
|
-- Fragment Processing
|
||||||
|
stage_next <= IPv4_FRAGMENT_PRE;
|
||||||
|
else
|
||||||
|
-- Payload Processing
|
||||||
|
stage_next <= IPv4_PAYLOAD_LENGTH;
|
||||||
|
end if;
|
||||||
|
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;
|
||||||
|
-- Fragment Pre-Processing
|
||||||
|
when IPv4_FRAGMENT_PRE =>
|
||||||
|
tmp := match_buffer_id(buffer_id);
|
||||||
|
-- Existing Buffer ID Match (Fragment is part of packet in a buffer)
|
||||||
|
if(tmp /= MAX_PARALLEL_FRAG) then
|
||||||
|
-- Calculate buffer address
|
||||||
|
tmp_frag_offset := (others => '0');
|
||||||
|
tmp_frag_offset(13 downto 0) := frag_offset;
|
||||||
|
buffer_addr_next <= buffer_addr_offset(tmp) + tmp_frag_offset;
|
||||||
|
-- Reset timeout if needed
|
||||||
|
if (max_buffer_timer(tmp) < unsigned(ttl)) then
|
||||||
|
max_buffer_timer_next(tmp) <= unsigned(ttl);
|
||||||
|
end if;
|
||||||
|
-- Save Buffer ID
|
||||||
|
cur_buffer_id_next <= tmp;
|
||||||
|
-- Store Fragment
|
||||||
|
stage_next <= IPv4_FRAGMENT;
|
||||||
|
-- Fragment is not part of a packet in a buffer
|
||||||
|
else
|
||||||
|
-- Search for free buffer
|
||||||
|
tmp := empty_buffer_id(buffer_id);
|
||||||
|
-- Buffer Found
|
||||||
|
if (tmp /= MAX_PARALLEL_FRAG) then
|
||||||
|
-- Store Buffer ID
|
||||||
|
buffer_id_next(tmp) <= buffer_id(MAX_PARALLEL_FRAG);
|
||||||
|
-- Reset Bitmap
|
||||||
|
buffer_bitmap_next(tmp) <= (others => '0');
|
||||||
|
-- Reset Buffer Timer
|
||||||
|
reset_buffer_timer <= '1';
|
||||||
|
reset_buffer_timer_id <= tmp;
|
||||||
|
-- Reset Maximum Fragment Size
|
||||||
|
frag_size_next(tmp) <= (others => '0');
|
||||||
|
-- Reset fragment word cntouer
|
||||||
|
buffer_word_cnt_next(tmp) <= 0;
|
||||||
|
-- Calculate buffer address
|
||||||
|
tmp_frag_offset := (others => '0');
|
||||||
|
tmp_frag_offset(13 downto 0) := frag_offset;
|
||||||
|
buffer_addr_next <= buffer_addr_offset(tmp) + tmp_frag_offset;
|
||||||
|
-- Reset timeout if needed
|
||||||
|
if (max_buffer_timer(tmp) < unsigned(ttl)) then
|
||||||
|
max_buffer_timer_next(tmp) <= unsigned(ttl);
|
||||||
|
end if;
|
||||||
|
-- Save Buffer ID
|
||||||
|
cur_buffer_id_next <= tmp;
|
||||||
|
stage_next <= IPv4_FRAGMENT;
|
||||||
|
-- No buffer available, skip packet.
|
||||||
|
else
|
||||||
|
stage_next <= SKIP_PACKET;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
-- Store Fragment
|
||||||
|
when IPv4_FRAGMENT =>
|
||||||
|
if (empty = '0') then
|
||||||
|
-- Re-assembled packet exceeds buffer resources or fragments included in packet already received
|
||||||
|
if (to_integer(frag_offset) > MAX_FRAG_SIZE or buffer_bitmap(cur_buffer_id)(to_integer(frag_offset)) = '0') then
|
||||||
|
-- Free Buffer ID
|
||||||
|
buffer_id_next(cur_buffer_id) <= (others => '0');
|
||||||
|
-- The rest of the Buffer related values are reset upon buffer selection
|
||||||
|
-- Skip Rest of Packet
|
||||||
|
stage_next <= SKIP_PACKET;
|
||||||
|
else
|
||||||
|
rd_sig <= '1';
|
||||||
|
-- Write Data to Buffer
|
||||||
|
buffer_wen <= '1';
|
||||||
|
buffer_wr_data <= data_in;
|
||||||
|
-- Mark BITMAP
|
||||||
|
buffer_bitmap_next(cur_buffer_id)(to_integer(frag_offset)) <= '1';
|
||||||
|
-- Increment Word Counter
|
||||||
|
buffer_word_cnt_next(cur_buffer_id) <= buffer_word_cnt(cur_buffer_id) + 1;
|
||||||
|
-- End of Packet
|
||||||
|
if (read_cnt = packet_length) then
|
||||||
|
-- If this is the last fragment, save total length
|
||||||
|
if (is_last_fragment = '1') then
|
||||||
|
frag_size_next(cur_buffer_id) <= std_logic_vector(frag_offset);
|
||||||
|
end if;
|
||||||
|
-- Continue with Post-Processing
|
||||||
|
stage_next <= IPv4_FRAGMENT_POST;
|
||||||
|
else
|
||||||
|
-- Increment Pointers
|
||||||
|
buffer_addr_next <= buffer_addr + 1;
|
||||||
|
frag_offset_next <= frag_offset + 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
-- Fragment Postprocessing
|
||||||
|
when IPv4_FRAGMENT_POST =>
|
||||||
|
-- Check if BITMAP complete (All fragments of packet received)
|
||||||
|
-- Done by comparing the number of received fragment words to the expected size
|
||||||
|
-- 'frag_size' is either zero or the expected value, and 'buffer_word_cnt' is at least 1 when this state is entered
|
||||||
|
if (to_integer(unsigned(frag_size(cur_buffer_id))) = buffer_word_cnt(cur_buffer_id)) then
|
||||||
|
-- Reset Buffer Address
|
||||||
|
buffer_addr_next <= buffer_addr_offset(cur_buffer_id);
|
||||||
|
buffer_addr_old_next<= buffer_addr_offset(cur_buffer_id);
|
||||||
|
-- Reset read count
|
||||||
|
reset_read_cnt <= '1';
|
||||||
|
-- Write buffer packet to Output FIFO
|
||||||
|
stage_next <= IPv4_BUFFER_SRC;
|
||||||
|
else
|
||||||
|
-- Done, process next packet
|
||||||
|
stage_next <= IPv4_INIT;
|
||||||
|
end if;
|
||||||
|
-- Push Src Address
|
||||||
|
when IPv4_BUFFER_SRC =>
|
||||||
|
if (full(output_id) = '0') then
|
||||||
|
-- Write Packet Length
|
||||||
|
wr_sig <= '1';
|
||||||
|
data_out_sig <= buffer_id(MAX_PARALLEL_FRAG)(87 downto 56);
|
||||||
|
-- Next State
|
||||||
|
stage_next <= IPv4_BUFFER_DEST;
|
||||||
|
end if;
|
||||||
|
-- Push Dest Address
|
||||||
|
when IPv4_BUFFER_DEST =>
|
||||||
|
if (full(output_id) = '0') then
|
||||||
|
-- Write Packet Length
|
||||||
|
wr_sig <= '1';
|
||||||
|
data_out_sig <= buffer_id(MAX_PARALLEL_FRAG)(55 downto 24);
|
||||||
|
-- Next State
|
||||||
|
stage_next <= IPv4_BUFFER_LENGTH;
|
||||||
|
end if;
|
||||||
|
-- Push Payload Length
|
||||||
|
when IPv4_BUFFER_LENGTH =>
|
||||||
|
if (full(output_id) = '0') then
|
||||||
|
-- Write Packet Length
|
||||||
|
wr_sig <= '1';
|
||||||
|
data_out_sig(13 downto 0) <= frag_size(cur_buffer_id);
|
||||||
|
-- Next State
|
||||||
|
stage_next <= IPv4_BUFFER_PAYLOAD;
|
||||||
|
end if;
|
||||||
|
-- Push Payload from Buffer
|
||||||
|
when IPv4_BUFFER_PAYLOAD =>
|
||||||
|
-- Buffer read complete (End Of Packet)
|
||||||
|
if (buffer_addr_old = packet_length) then
|
||||||
|
-- Free Buffer ID
|
||||||
|
buffer_id_next(cur_buffer_id) <= (others => '0');
|
||||||
|
-- The rest of the Buffer related values are reset upon buffer selection
|
||||||
|
-- Done, process next packet
|
||||||
|
stage_next <= IPv4_INIT;
|
||||||
|
-- Buffer Read in progress
|
||||||
|
else
|
||||||
|
-- Write from Buffer to Output FIFO
|
||||||
|
if (full(output_id) = '0') then
|
||||||
|
-- Read, and write output next cycle
|
||||||
|
-- Note that 'wr_sig_del' is actually connected to the output fifo
|
||||||
|
wr_sig <= '1';
|
||||||
|
buffer_ren <= '1';
|
||||||
|
buffer_addr_next <= buffer_addr + 1;
|
||||||
|
buffer_addr_old_next<= buffer_addr;
|
||||||
|
-- Output Fifo Full, reset read position
|
||||||
|
else
|
||||||
|
-- Reset buffer address
|
||||||
|
buffer_addr_next <= buffer_addr_old;
|
||||||
|
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
|
||||||
|
if (is_fragment = '1') then
|
||||||
|
-- Fragment Processing
|
||||||
|
stage_next <= IPv4_FRAGMENT_PRE;
|
||||||
|
else
|
||||||
|
-- Payload Processing
|
||||||
|
stage_next <= IPv4_PAYLOAD;
|
||||||
|
end if;
|
||||||
|
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 the buffer timers
|
||||||
|
-- The timers increment each second until they reach the maximum value, and stay there until a reset
|
||||||
|
buffer_timer_prc : process(sec_clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(sec_clk) then
|
||||||
|
-- Reset timer specified by id
|
||||||
|
if(reset_buffer_timer = '0') then
|
||||||
|
buffer_timer(reset_buffer_timer_id) <= (others => '0');
|
||||||
|
else
|
||||||
|
-- Increment Timers
|
||||||
|
for i in 0 to max(MAX_PARALLEL_FRAG-1,0) 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;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
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' or buffer_ren = '1') then
|
||||||
|
read_cnt <= read_cnt + to_unsigned(1, read_cnt'length);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
-- 1 Hz Clock Generator
|
||||||
|
sec_clk_prc : process(clk, reset)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
if (reset = '1') then
|
||||||
|
sec_cnt <= 0;
|
||||||
|
sec_clk <= '0';
|
||||||
|
else
|
||||||
|
sec_cnt <= sec_cnt + 1;
|
||||||
|
-- Toggle sec_clk every second
|
||||||
|
if (sec_cnt = (CLK_FREQ/2)-1) then
|
||||||
|
sec_clk <= not sec_clk;
|
||||||
|
end if;
|
||||||
|
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');
|
||||||
|
is_fragment <= '0';
|
||||||
|
is_last_fragment <= '0';
|
||||||
|
frag_offset <= (others => '0');
|
||||||
|
buffer_id <= (others => (others => '0'));
|
||||||
|
ttl <= (others => '0');
|
||||||
|
output_id <= 0;
|
||||||
|
frag_size <= (others => (others => '0'));
|
||||||
|
cur_buffer_id <= 0;
|
||||||
|
buffer_bitmap <= (others => (others => '0'));
|
||||||
|
buffer_addr <= (others => '0');
|
||||||
|
buffer_addr_old <= (others => '0');
|
||||||
|
wr_sig_del <= '0';
|
||||||
|
buffer_word_cnt <= (others => 0);
|
||||||
|
else
|
||||||
|
stage <= stage_next;
|
||||||
|
packet_length <= packet_length_next;
|
||||||
|
header_length <= header_length_next;
|
||||||
|
is_fragment <= is_fragment_next;
|
||||||
|
is_last_fragment <= is_last_fragment_next;
|
||||||
|
frag_offset <= frag_offset_next;
|
||||||
|
buffer_id <= buffer_id;
|
||||||
|
ttl <= ttl_next;
|
||||||
|
output_id <= output_id_next;
|
||||||
|
frag_size <= frag_size_next;
|
||||||
|
cur_buffer_id <= cur_buffer_id_next;
|
||||||
|
buffer_bitmap <= buffer_bitmap_next;
|
||||||
|
buffer_addr <= buffer_addr_next;
|
||||||
|
buffer_addr_old <= buffer_addr_old_next;
|
||||||
|
wr_sig_del <= wr_sig;
|
||||||
|
buffer_word_cnt <= buffer_word_cnt_next;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture;
|
||||||
58
src/math_pkg.vhd
Normal file
58
src/math_pkg.vhd
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package math_pkg is
|
||||||
|
-- calculates the logarithm dualis of the operand and rounds up
|
||||||
|
-- the result to the next integer value.
|
||||||
|
function log2c(constant value : in integer) return integer;
|
||||||
|
-- returns the maximum of the two operands
|
||||||
|
function max(constant value1, value2 : in integer) return integer;
|
||||||
|
-- returns the maximum of the three operands
|
||||||
|
function max(constant value1, value2, value3 : in integer) return integer;
|
||||||
|
-- returns the minimum of the two operands
|
||||||
|
function min(constant value1, value2 : in integer) return integer;
|
||||||
|
end package;
|
||||||
|
|
||||||
|
|
||||||
|
package body math_pkg is
|
||||||
|
|
||||||
|
--*****FUNCTION DEFINITION*****
|
||||||
|
|
||||||
|
function log2c(constant value : in integer) return integer is
|
||||||
|
variable ret_value : integer;
|
||||||
|
variable cur_value : integer;
|
||||||
|
begin
|
||||||
|
ret_value := 0;
|
||||||
|
cur_value := 1;
|
||||||
|
|
||||||
|
while cur_value < value loop
|
||||||
|
ret_value := ret_value + 1;
|
||||||
|
cur_value := cur_value * 2;
|
||||||
|
end loop;
|
||||||
|
return ret_value;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
function max(constant value1, value2 : in integer) return integer is
|
||||||
|
variable ret_value : integer;
|
||||||
|
begin
|
||||||
|
if value1 > value2 then
|
||||||
|
ret_value := value1;
|
||||||
|
else
|
||||||
|
ret_value := value2;
|
||||||
|
end if;
|
||||||
|
return ret_value;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
function max(constant value1, value2, value3 : in integer) return integer is
|
||||||
|
begin
|
||||||
|
return max(max(value1, value2), value3);
|
||||||
|
end function;
|
||||||
|
|
||||||
|
function min(constant value1, value2 : in integer) return integer is
|
||||||
|
variable ret_value : integer;
|
||||||
|
begin
|
||||||
|
if value1 < value2 then
|
||||||
|
ret_value := value1;
|
||||||
|
else
|
||||||
|
ret_value := value2;
|
||||||
|
end if;
|
||||||
|
return ret_value;
|
||||||
|
end function;
|
||||||
|
end package body;
|
||||||
66
src/single_port_ram.vhd
Normal file
66
src/single_port_ram.vhd
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
Library xpm;
|
||||||
|
use xpm.vcomponents.all;
|
||||||
|
|
||||||
|
entity single_port_ram is
|
||||||
|
generic (
|
||||||
|
ADDR_WIDTH : integer := 8;
|
||||||
|
DATA_WIDTH : integer := 12;
|
||||||
|
MEMORY_SIZE : integer := DATA_WIDTH*(2**ADDR_WIDTH)
|
||||||
|
|
||||||
|
);
|
||||||
|
port (
|
||||||
|
clk : in std_logic;
|
||||||
|
addr : in std_logic_vector(ADDR_WIDTH-1 downto 0);
|
||||||
|
wen : in std_logic;
|
||||||
|
ren : in std_logic;
|
||||||
|
wr_data : in std_logic_vector(DATA_WIDTH-1 downto 0);
|
||||||
|
rd_data : out std_logic_vector(DATA_WIDTH-1 downto 0)
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture arch of single_port_ram is
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
xpm_memory_spram_inst : xpm_memory_spram
|
||||||
|
generic map (
|
||||||
|
ADDR_WIDTH_A => ADDR_WIDTH,
|
||||||
|
AUTO_SLEEP_TIME => 0,
|
||||||
|
BYTE_WRITE_WIDTH_A => DATA_WIDTH,
|
||||||
|
ECC_MODE => "no_ecc",
|
||||||
|
MEMORY_INIT_FILE => "none",
|
||||||
|
MEMORY_INIT_PARAM => "0",
|
||||||
|
MEMORY_OPTIMIZATION => "true",
|
||||||
|
MEMORY_PRIMITIVE => "auto",
|
||||||
|
MEMORY_SIZE => DATA_WIDTH*(2**ADDR_WIDTH),
|
||||||
|
MESSAGE_CONTROL => 0,
|
||||||
|
READ_DATA_WIDTH_A => DATA_WIDTH,
|
||||||
|
READ_LATENCY_A => 1,
|
||||||
|
READ_RESET_VALUE_A => "0",
|
||||||
|
RST_MODE_A => "SYNC",
|
||||||
|
USE_MEM_INIT => 1,
|
||||||
|
WAKEUP_TIME => "disable_sleep",
|
||||||
|
WRITE_DATA_WIDTH_A => DATA_WIDTH,
|
||||||
|
WRITE_MODE_A => "read_first"
|
||||||
|
)
|
||||||
|
port map (
|
||||||
|
dbiterra => open,
|
||||||
|
douta => rd_data,
|
||||||
|
sbiterra => open,
|
||||||
|
addra => addr,
|
||||||
|
clka => clk,
|
||||||
|
dina => wr_data,
|
||||||
|
ena => (ren or wen),
|
||||||
|
injectdbiterra => '0',
|
||||||
|
injectsbiterra => '0',
|
||||||
|
regcea => '1',
|
||||||
|
rsta => '0',
|
||||||
|
sleep => '0',
|
||||||
|
wea => (others => wen) --1-bit Vector
|
||||||
|
);
|
||||||
|
|
||||||
|
end architecture;
|
||||||
6
src/top.xdc
Normal file
6
src/top.xdc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#100 Mhz
|
||||||
|
create_clock -period 10.000 -name sys_clk -waveform {0.000 5.000} [get_ports clk]
|
||||||
|
# 166 Mhz
|
||||||
|
#create_clock -period 6.000 -name sys_clk -waveform {0.000 3.000} [get_ports clk]
|
||||||
|
# 200 Mhz
|
||||||
|
#create_clock -period 5.000 -name sys_clk -waveform {0.000 2.500} [get_ports clk]
|
||||||
208
syn/project_1.xpr
Normal file
208
syn/project_1.xpr
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Product Version: Vivado v2018.3.1 (64-bit) -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- Copyright 1986-2019 Xilinx, Inc. All Rights Reserved. -->
|
||||||
|
|
||||||
|
<Project Version="7" Minor="39" Path="C:/Users/JohnD/Desktop/rtps-fpga/syn/project_1.xpr">
|
||||||
|
<DefaultLaunch Dir="$PRUNDIR"/>
|
||||||
|
<Configuration>
|
||||||
|
<Option Name="Id" Val="3bd9305e3cf440fd9fb9a10df1d7144f"/>
|
||||||
|
<Option Name="Part" Val="xc7z020clg484-1"/>
|
||||||
|
<Option Name="CompiledLibDir" Val="$PCACHEDIR/compile_simlib"/>
|
||||||
|
<Option Name="CompiledLibDirXSim" Val=""/>
|
||||||
|
<Option Name="CompiledLibDirModelSim" Val="$PCACHEDIR/compile_simlib/modelsim"/>
|
||||||
|
<Option Name="CompiledLibDirQuesta" Val="$PCACHEDIR/compile_simlib/questa"/>
|
||||||
|
<Option Name="CompiledLibDirIES" Val="$PCACHEDIR/compile_simlib/ies"/>
|
||||||
|
<Option Name="CompiledLibDirXcelium" Val="$PCACHEDIR/compile_simlib/xcelium"/>
|
||||||
|
<Option Name="CompiledLibDirVCS" Val="$PCACHEDIR/compile_simlib/vcs"/>
|
||||||
|
<Option Name="CompiledLibDirRiviera" Val="$PCACHEDIR/compile_simlib/riviera"/>
|
||||||
|
<Option Name="CompiledLibDirActivehdl" Val="$PCACHEDIR/compile_simlib/activehdl"/>
|
||||||
|
<Option Name="BoardPart" Val="em.avnet.com:zed:part0:1.4"/>
|
||||||
|
<Option Name="ActiveSimSet" Val="sim_1"/>
|
||||||
|
<Option Name="DefaultLib" Val="xil_defaultlib"/>
|
||||||
|
<Option Name="ProjectType" Val="Default"/>
|
||||||
|
<Option Name="IPOutputRepo" Val="$PCACHEDIR/ip"/>
|
||||||
|
<Option Name="IPCachePermission" Val="read"/>
|
||||||
|
<Option Name="IPCachePermission" Val="write"/>
|
||||||
|
<Option Name="EnableCoreContainer" Val="FALSE"/>
|
||||||
|
<Option Name="CreateRefXciForCoreContainers" Val="FALSE"/>
|
||||||
|
<Option Name="IPUserFilesDir" Val="$PIPUSERFILESDIR"/>
|
||||||
|
<Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/>
|
||||||
|
<Option Name="EnableBDX" Val="FALSE"/>
|
||||||
|
<Option Name="DSAVendor" Val="xilinx"/>
|
||||||
|
<Option Name="DSABoardId" Val="zed"/>
|
||||||
|
<Option Name="DSANumComputeUnits" Val="60"/>
|
||||||
|
<Option Name="WTXSimLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTModelSimLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTQuestaLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTIesLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTVcsLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTRivieraLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTActivehdlLaunchSim" Val="0"/>
|
||||||
|
<Option Name="WTXSimExportSim" Val="0"/>
|
||||||
|
<Option Name="WTModelSimExportSim" Val="0"/>
|
||||||
|
<Option Name="WTQuestaExportSim" Val="0"/>
|
||||||
|
<Option Name="WTIesExportSim" Val="0"/>
|
||||||
|
<Option Name="WTVcsExportSim" Val="0"/>
|
||||||
|
<Option Name="WTRivieraExportSim" Val="0"/>
|
||||||
|
<Option Name="WTActivehdlExportSim" Val="0"/>
|
||||||
|
<Option Name="GenerateIPUpgradeLog" Val="TRUE"/>
|
||||||
|
<Option Name="XSimRadix" Val="hex"/>
|
||||||
|
<Option Name="XSimTimeUnit" Val="ns"/>
|
||||||
|
<Option Name="XSimArrayDisplayLimit" Val="1024"/>
|
||||||
|
<Option Name="XSimTraceLimit" Val="65536"/>
|
||||||
|
<Option Name="SimTypes" Val="rtl"/>
|
||||||
|
<Option Name="SimTypes" Val="bfm"/>
|
||||||
|
<Option Name="SimTypes" Val="tlm"/>
|
||||||
|
<Option Name="SimTypes" Val="tlm_dpi"/>
|
||||||
|
<Option Name="MEMEnableMemoryMapGeneration" Val="TRUE"/>
|
||||||
|
</Configuration>
|
||||||
|
<FileSets Version="1" Minor="31">
|
||||||
|
<FileSet Name="sources_1" Type="DesignSrcs" RelSrcDir="$PSRCDIR/sources_1">
|
||||||
|
<Filter Type="Srcs"/>
|
||||||
|
<File Path="$PPRDIR/../src/ip_package.vhd">
|
||||||
|
<FileInfo SFType="VHDL2008">
|
||||||
|
<Attr Name="UsedIn" Val="synthesis"/>
|
||||||
|
<Attr Name="UsedIn" Val="simulation"/>
|
||||||
|
</FileInfo>
|
||||||
|
</File>
|
||||||
|
<File Path="$PPRDIR/../src/math_pkg.vhd">
|
||||||
|
<FileInfo SFType="VHDL2008">
|
||||||
|
<Attr Name="UsedIn" Val="synthesis"/>
|
||||||
|
<Attr Name="UsedIn" Val="simulation"/>
|
||||||
|
</FileInfo>
|
||||||
|
</File>
|
||||||
|
<File Path="$PPRDIR/../src/single_port_ram.vhd">
|
||||||
|
<FileInfo SFType="VHDL2008">
|
||||||
|
<Attr Name="UsedIn" Val="synthesis"/>
|
||||||
|
<Attr Name="UsedIn" Val="simulation"/>
|
||||||
|
</FileInfo>
|
||||||
|
</File>
|
||||||
|
<File Path="$PPRDIR/../src/ipv4_in.vhd">
|
||||||
|
<FileInfo SFType="VHDL2008">
|
||||||
|
<Attr Name="UsedIn" Val="synthesis"/>
|
||||||
|
<Attr Name="UsedIn" Val="simulation"/>
|
||||||
|
</FileInfo>
|
||||||
|
</File>
|
||||||
|
<Config>
|
||||||
|
<Option Name="DesignMode" Val="RTL"/>
|
||||||
|
<Option Name="TopModule" Val="ipv4_in"/>
|
||||||
|
<Option Name="TopAutoSet" Val="TRUE"/>
|
||||||
|
</Config>
|
||||||
|
</FileSet>
|
||||||
|
<FileSet Name="constrs_1" Type="Constrs" RelSrcDir="$PSRCDIR/constrs_1">
|
||||||
|
<Filter Type="Constrs"/>
|
||||||
|
<File Path="$PPRDIR/../src/top.xdc">
|
||||||
|
<FileInfo>
|
||||||
|
<Attr Name="UsedIn" Val="synthesis"/>
|
||||||
|
<Attr Name="UsedIn" Val="implementation"/>
|
||||||
|
</FileInfo>
|
||||||
|
</File>
|
||||||
|
<Config>
|
||||||
|
<Option Name="ConstrsType" Val="XDC"/>
|
||||||
|
</Config>
|
||||||
|
</FileSet>
|
||||||
|
<FileSet Name="sim_1" Type="SimulationSrcs" RelSrcDir="$PSRCDIR/sim_1">
|
||||||
|
<Filter Type="Srcs"/>
|
||||||
|
<Config>
|
||||||
|
<Option Name="DesignMode" Val="RTL"/>
|
||||||
|
<Option Name="TopModule" Val="ipv4_in"/>
|
||||||
|
<Option Name="TopLib" Val="xil_defaultlib"/>
|
||||||
|
<Option Name="TopAutoSet" Val="TRUE"/>
|
||||||
|
<Option Name="TransportPathDelay" Val="0"/>
|
||||||
|
<Option Name="TransportIntDelay" Val="0"/>
|
||||||
|
<Option Name="SrcSet" Val="sources_1"/>
|
||||||
|
</Config>
|
||||||
|
</FileSet>
|
||||||
|
<FileSet Name="utils_1" Type="Utils" RelSrcDir="$PSRCDIR/utils_1">
|
||||||
|
<Filter Type="Utils"/>
|
||||||
|
<Config>
|
||||||
|
<Option Name="TopAutoSet" Val="TRUE"/>
|
||||||
|
</Config>
|
||||||
|
</FileSet>
|
||||||
|
</FileSets>
|
||||||
|
<Simulators>
|
||||||
|
<Simulator Name="XSim">
|
||||||
|
<Option Name="Description" Val="Vivado Simulator"/>
|
||||||
|
<Option Name="CompiledLib" Val="0"/>
|
||||||
|
</Simulator>
|
||||||
|
<Simulator Name="ModelSim">
|
||||||
|
<Option Name="Description" Val="ModelSim Simulator"/>
|
||||||
|
</Simulator>
|
||||||
|
<Simulator Name="Questa">
|
||||||
|
<Option Name="Description" Val="Questa Advanced Simulator"/>
|
||||||
|
</Simulator>
|
||||||
|
<Simulator Name="Riviera">
|
||||||
|
<Option Name="Description" Val="Riviera-PRO Simulator"/>
|
||||||
|
</Simulator>
|
||||||
|
<Simulator Name="ActiveHDL">
|
||||||
|
<Option Name="Description" Val="Active-HDL Simulator"/>
|
||||||
|
</Simulator>
|
||||||
|
</Simulators>
|
||||||
|
<Runs Version="1" Minor="10">
|
||||||
|
<Run Id="synth_1" Type="Ft3:Synth" SrcSet="sources_1" Part="xc7z020clg484-1" ConstrsSet="constrs_1" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" Dir="$PRUNDIR/synth_1" IncludeInArchive="true">
|
||||||
|
<Strategy Version="1" Minor="2">
|
||||||
|
<StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2018">
|
||||||
|
<Desc>Vivado Synthesis Defaults</Desc>
|
||||||
|
</StratHandle>
|
||||||
|
<Step Id="synth_design"/>
|
||||||
|
</Strategy>
|
||||||
|
<GeneratedRun Dir="$PRUNDIR" File="gen_run.xml"/>
|
||||||
|
<ReportStrategy Name="Vivado Synthesis Default Reports" Flow="Vivado Synthesis 2018"/>
|
||||||
|
<Report Name="ROUTE_DESIGN.REPORT_METHODOLOGY" Enabled="1"/>
|
||||||
|
</Run>
|
||||||
|
<Run Id="impl_1" Type="Ft2:EntireDesign" Part="xc7z020clg484-1" ConstrsSet="constrs_1" Description="Default settings for Implementation." AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" SynthRun="synth_1" IncludeInArchive="true" GenFullBitstream="true">
|
||||||
|
<Strategy Version="1" Minor="2">
|
||||||
|
<StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2018">
|
||||||
|
<Desc>Default settings for Implementation.</Desc>
|
||||||
|
</StratHandle>
|
||||||
|
<Step Id="init_design"/>
|
||||||
|
<Step Id="opt_design"/>
|
||||||
|
<Step Id="power_opt_design"/>
|
||||||
|
<Step Id="place_design"/>
|
||||||
|
<Step Id="post_place_power_opt_design"/>
|
||||||
|
<Step Id="phys_opt_design"/>
|
||||||
|
<Step Id="route_design"/>
|
||||||
|
<Step Id="post_route_phys_opt_design"/>
|
||||||
|
<Step Id="write_bitstream"/>
|
||||||
|
</Strategy>
|
||||||
|
<ReportStrategy Name="Vivado Implementation Default Reports" Flow="Vivado Implementation 2018"/>
|
||||||
|
<Report Name="ROUTE_DESIGN.REPORT_METHODOLOGY" Enabled="1"/>
|
||||||
|
</Run>
|
||||||
|
</Runs>
|
||||||
|
<Board>
|
||||||
|
<Jumpers/>
|
||||||
|
</Board>
|
||||||
|
<DashboardSummary Version="1" Minor="0">
|
||||||
|
<Dashboards>
|
||||||
|
<Dashboard Name="default_dashboard">
|
||||||
|
<Gadgets>
|
||||||
|
<Gadget Name="drc_1" Type="drc" Version="1" Row="2" Column="0">
|
||||||
|
<GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_drc_0 "/>
|
||||||
|
</Gadget>
|
||||||
|
<Gadget Name="methodology_1" Type="methodology" Version="1" Row="2" Column="1">
|
||||||
|
<GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_methodology_0 "/>
|
||||||
|
</Gadget>
|
||||||
|
<Gadget Name="power_1" Type="power" Version="1" Row="1" Column="0">
|
||||||
|
<GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_power_0 "/>
|
||||||
|
</Gadget>
|
||||||
|
<Gadget Name="timing_1" Type="timing" Version="1" Row="0" Column="1">
|
||||||
|
<GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_route_report_timing_summary_0 "/>
|
||||||
|
</Gadget>
|
||||||
|
<Gadget Name="utilization_1" Type="utilization" Version="1" Row="0" Column="0">
|
||||||
|
<GadgetParam Name="REPORTS" Type="string_list" Value="synth_1#synth_1_synth_report_utilization_0 "/>
|
||||||
|
<GadgetParam Name="RUN.STEP" Type="string" Value="synth_design"/>
|
||||||
|
<GadgetParam Name="RUN.TYPE" Type="string" Value="synthesis"/>
|
||||||
|
</Gadget>
|
||||||
|
<Gadget Name="utilization_2" Type="utilization" Version="1" Row="1" Column="1">
|
||||||
|
<GadgetParam Name="REPORTS" Type="string_list" Value="impl_1#impl_1_place_report_utilization_0 "/>
|
||||||
|
</Gadget>
|
||||||
|
</Gadgets>
|
||||||
|
</Dashboard>
|
||||||
|
<CurrentDashboard>default_dashboard</CurrentDashboard>
|
||||||
|
</Dashboards>
|
||||||
|
</DashboardSummary>
|
||||||
|
<BootPmcSettings Version="1" Minor="0">
|
||||||
|
<Parameters/>
|
||||||
|
</BootPmcSettings>
|
||||||
|
</Project>
|
||||||
Loading…
Reference in New Issue
Block a user