Skip to content
Snippets Groups Projects
Commit d9915ff3 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Port the files that use eth_layers_pkg that now for $RADIOHDL is in common_lib.

parent da5812ab
No related branches found
No related tags found
No related merge requests found
......@@ -8,18 +8,18 @@ build_synth_dir =
synth_files =
src/vhdl/eth_pkg.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_checksum.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_hdr_store.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_hdr_status.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_hdr_ctrl.vhd
eth_hdr_store.vhd
eth_hdr_status.vhd
eth_hdr_ctrl.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_hdr.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_crc_ctrl.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_crc_word.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_mm_registers.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_mm_reg_frame.vhd
eth_mm_reg_frame.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_udp_channel.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_buffer.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_control.vhd
$UNB/Firmware/modules/tse/src/vhdl/eth_ihl_to_20.vhd
eth_control.vhd
eth_ihl_to_20.vhd
src/vhdl/eth.vhd
src/vhdl/avs_eth.vhd
......@@ -32,4 +32,4 @@ test_bench_files =
tb/vhdl/tb_eth.vhd
tb/vhdl/tb_tb_eth.vhd
tb/vhdl/tb_eth_udp_offload.vhd
$UNB/Firmware/modules/tse/tb/vhdl/tb_eth_ihl_to_20.vhd
tb/vhdl/tb_eth_ihl_to_20.vhd
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
ENTITY eth_control IS
PORT (
-- Clocks and reset
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Control registers
reg_config : IN t_eth_mm_reg_config;
reg_control : IN t_eth_mm_reg_control;
reg_continue_wr : IN STD_LOGIC; -- used to know that control reg has been written and ETH module can continue from TX_PENDING state
reg_status : OUT t_eth_mm_reg_status;
reg_status_wr : IN STD_LOGIC; -- used to know that status reg has been read and can be cleared to remove the sla_interrupt
-- Streaming sink Rx frame
-- . The rcv_rd, rcv_ack and rcv_done act instead of rcv_out.ready to have rcv_out ready per frame instead of per data word
rcv_rd : OUT STD_LOGIC;
rcv_ack : IN STD_LOGIC;
rcv_done : IN STD_LOGIC;
rcv_in : IN t_dp_sosi; -- packet memory is always ready for packet data
rcv_hdr_words : IN t_eth_total_header_arr;
rcv_hdr_status : IN t_eth_hdr_status;
-- Streaming source Tx frame
xmt_in : IN t_dp_siso;
xmt_out : OUT t_dp_sosi;
-- MM frame memory
mem_in : OUT t_mem_mosi;
mem_out : IN t_mem_miso
);
END eth_control;
ARCHITECTURE rtl OF eth_control IS
-- Internal source ready latency of this component
CONSTANT c_this_src_latency : NATURAL := 1; -- xmt_in, xmt_out
TYPE t_state_enum IS (
s_idle,
s_rx_request,
s_rx_frame,
s_hdr_response,
s_tx_pending,
s_tx_frame,
s_tx_done
);
SIGNAL nxt_rcv_rd : STD_LOGIC;
SIGNAL rcv_in_eop_dly : STD_LOGIC;
SIGNAL hdr_response : t_eth_total_header_arr;
SIGNAL nxt_hdr_response : t_eth_total_header_arr;
SIGNAL hdr_word_cnt : NATURAL RANGE 0 TO c_eth_total_header_nof_words := c_eth_total_header_nof_words;
SIGNAL nxt_hdr_word_cnt : NATURAL;
SIGNAL hdr_en : STD_LOGIC;
SIGNAL nxt_hdr_en : STD_LOGIC;
SIGNAL hdr_done : STD_LOGIC;
SIGNAL nxt_hdr_done : STD_LOGIC;
SIGNAL tx_insert : STD_LOGIC;
SIGNAL nxt_tx_insert : STD_LOGIC;
SIGNAL i_reg_status : t_eth_mm_reg_status;
SIGNAL nxt_reg_status : t_eth_mm_reg_status;
SIGNAL xmt_start : STD_LOGIC;
SIGNAL nxt_xmt_start : STD_LOGIC;
SIGNAL xmt_en : STD_LOGIC;
SIGNAL nxt_xmt_en : STD_LOGIC;
SIGNAL xmt_done : STD_LOGIC;
SIGNAL nxt_xmt_done : STD_LOGIC;
SIGNAL xmt_word_cnt : NATURAL RANGE 0 TO c_eth_frame_nof_words;
SIGNAL nxt_xmt_word_cnt : NATURAL;
SIGNAL tx_nof_words : STD_LOGIC_VECTOR(c_eth_frame_nof_words_w-1 DOWNTO 0);
SIGNAL nxt_tx_nof_words : STD_LOGIC_VECTOR(c_eth_frame_nof_words_w-1 DOWNTO 0);
SIGNAL tx_empty : STD_LOGIC_VECTOR(c_eth_empty_w-1 DOWNTO 0);
SIGNAL nxt_tx_empty : STD_LOGIC_VECTOR(c_eth_empty_w-1 DOWNTO 0);
SIGNAL i_mem_in : t_mem_mosi;
SIGNAL nxt_mem_in : t_mem_mosi;
SIGNAL rd_val : STD_LOGIC_VECTOR(0 TO c_mem_ram_rd_latency); -- use [0] to combinatorially store rd (= rd_en)
SIGNAL nxt_rd_val : STD_LOGIC_VECTOR(1 TO c_mem_ram_rd_latency);
SIGNAL rd_sop : STD_LOGIC_VECTOR( rd_val'RANGE);
SIGNAL nxt_rd_sop : STD_LOGIC_VECTOR(nxt_rd_val'RANGE);
SIGNAL rd_eop : STD_LOGIC_VECTOR( rd_val'RANGE);
SIGNAL nxt_rd_eop : STD_LOGIC_VECTOR(nxt_rd_val'RANGE);
SIGNAL xmt_siso : t_dp_siso;
SIGNAL xmt_sosi : t_dp_sosi;
SIGNAL i_xmt_out : t_dp_sosi;
-- ST->MM state machine
SIGNAL state : t_state_enum;
SIGNAL nxt_state : t_state_enum;
BEGIN
reg_status <= i_reg_status;
mem_in <= i_mem_in;
xmt_out <= i_xmt_out;
p_clk : PROCESS(rst, clk)
BEGIN
IF rst='1' THEN
rcv_rd <= '0';
rcv_in_eop_dly <= '0';
hdr_word_cnt <= c_eth_total_header_nof_words;
hdr_en <= '0';
hdr_done <= '0';
tx_insert <= '0';
xmt_start <= '0';
i_reg_status <= c_eth_mm_reg_status_rst;
tx_nof_words <= (OTHERS=>'0');
tx_empty <= (OTHERS=>'0');
xmt_word_cnt <= 0;
xmt_en <= '0';
xmt_done <= '0';
i_mem_in <= c_mem_mosi_rst;
rd_val(nxt_rd_val'RANGE) <= (OTHERS=>'0');
rd_sop(nxt_rd_val'RANGE) <= (OTHERS=>'0');
rd_eop(nxt_rd_val'RANGE) <= (OTHERS=>'0');
state <= s_idle;
ELSIF rising_edge(clk) THEN
rcv_rd <= nxt_rcv_rd;
rcv_in_eop_dly <= rcv_in.eop;
hdr_response <= nxt_hdr_response;
hdr_word_cnt <= nxt_hdr_word_cnt;
hdr_en <= nxt_hdr_en;
hdr_done <= nxt_hdr_done;
tx_insert <= nxt_tx_insert;
xmt_start <= nxt_xmt_start;
i_reg_status <= nxt_reg_status;
tx_nof_words <= nxt_tx_nof_words;
tx_empty <= nxt_tx_empty;
xmt_word_cnt <= nxt_xmt_word_cnt;
xmt_en <= nxt_xmt_en;
xmt_done <= nxt_xmt_done;
i_mem_in <= nxt_mem_in;
rd_val(nxt_rd_val'RANGE) <= nxt_rd_val;
rd_sop(nxt_rd_val'RANGE) <= nxt_rd_sop;
rd_eop(nxt_rd_val'RANGE) <= nxt_rd_eop;
state <= nxt_state;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Response header
------------------------------------------------------------------------------
p_hdr_response : PROCESS(rcv_hdr_words, rcv_hdr_status, reg_config)
BEGIN
nxt_hdr_response <= func_eth_response_header( rcv_hdr_words, reg_config.mac_address);
IF rcv_hdr_status.is_arp='1' THEN
nxt_hdr_response <= func_eth_arp_response_header( rcv_hdr_words, reg_config.mac_address, reg_config.ip_address);
ELSIF rcv_hdr_status.is_icmp='1' THEN
nxt_hdr_response <= func_eth_icmp_response_header(rcv_hdr_words, reg_config.mac_address);
ELSIF rcv_hdr_status.is_udp='1' THEN
nxt_hdr_response <= func_eth_udp_response_header( rcv_hdr_words, reg_config.mac_address);
ELSIF rcv_hdr_status.is_ip='1' THEN
-- If it is another protocol over IP than ICMP or UDP, then prepare only IP response
nxt_hdr_response <= func_eth_ip_response_header( rcv_hdr_words, reg_config.mac_address);
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Frame memory access
------------------------------------------------------------------------------
p_mem_access : PROCESS(i_mem_in, rcv_in, hdr_en, hdr_word_cnt, hdr_response, xmt_en, xmt_siso, xmt_word_cnt)
BEGIN
nxt_mem_in.address <= i_mem_in.address;
nxt_mem_in.wrdata <= i_mem_in.wrdata;
nxt_mem_in.wr <= '0';
nxt_mem_in.rd <= '0';
nxt_hdr_word_cnt <= 0;
nxt_xmt_word_cnt <= 0;
-- Rx frame
IF rcv_in.valid='1' THEN
nxt_mem_in.address <= INCR_UVEC(i_mem_in.address, 1);
nxt_mem_in.wrdata <= RESIZE_MEM_DATA(rcv_in.data);
nxt_mem_in.wr <= '1';
END IF;
IF rcv_in.sop='1' THEN
nxt_mem_in.address <= TO_MEM_ADDRESS(c_eth_ram_rx_offset); -- rx buffer starts at address 0
END IF;
-- Prepare the Tx header
IF hdr_en='1' THEN -- tx buffer starts at address 380
nxt_mem_in.address <= TO_MEM_ADDRESS(c_eth_ram_tx_offset + hdr_word_cnt);
nxt_mem_in.wrdata <= RESIZE_MEM_DATA(hdr_response(hdr_word_cnt));
nxt_mem_in.wr <= '1';
nxt_hdr_word_cnt <= hdr_word_cnt+1;
END IF;
-- Tx frame
IF xmt_en='1' THEN
nxt_mem_in.address <= TO_MEM_ADDRESS(c_eth_ram_tx_offset + xmt_word_cnt);
nxt_xmt_word_cnt <= xmt_word_cnt;
IF xmt_siso.ready='1' THEN
nxt_mem_in.rd <= '1';
nxt_xmt_word_cnt <= xmt_word_cnt+1; -- rd_en side counter
END IF;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Tx frame output control
------------------------------------------------------------------------------
rd_val(0) <= i_mem_in.rd;
rd_sop(0) <= i_mem_in.rd WHEN xmt_word_cnt=1 ELSE '0';
rd_eop(0) <= i_mem_in.rd WHEN xmt_word_cnt=UNSIGNED(tx_nof_words) ELSE '0';
-- rd_val side after read latency
nxt_rd_val <= rd_val(0 TO rd_val'HIGH-1);
nxt_rd_sop <= rd_sop(0 TO rd_val'HIGH-1);
nxt_rd_eop <= rd_eop(0 TO rd_val'HIGH-1);
xmt_sosi.data <= RESIZE_DP_DATA(mem_out.rddata);
xmt_sosi.valid <= rd_val(rd_val'HIGH);
xmt_sosi.sop <= rd_sop(rd_val'HIGH);
xmt_sosi.eop <= rd_eop(rd_val'HIGH);
xmt_sosi.empty <= RESIZE_DP_EMPTY(tx_empty);
-- adapt mem read latency to xmt ready latency
u_xmt_out_adapter : ENTITY dp_lib.dp_latency_adapter
GENERIC MAP (
g_in_latency => c_mem_ram_rd_latency+1, -- = 2 + 1 latency for xmt_siso.ready -> nxt_mem_in.rd
g_out_latency => c_this_src_latency -- = 1
)
PORT MAP (
rst => rst,
clk => clk,
-- ST sink
snk_out => xmt_siso,
snk_in => xmt_sosi,
-- ST source
src_in => xmt_in,
src_out => i_xmt_out
);
nxt_xmt_done <= i_xmt_out.eop;
------------------------------------------------------------------------------
-- Master-slave handshake control via status register
------------------------------------------------------------------------------
-- Gather Rx and Tx status into the status register
p_reg_status : PROCESS(i_reg_status, reg_status_wr, rcv_in, rcv_in_eop_dly, i_mem_in, tx_insert, hdr_done, xmt_done)
BEGIN
nxt_reg_status <= i_reg_status;
-- MM write access to the status address clears the status register, which removes the interrupt
-- using write instead of read access to remove the interrupt allows for polling reg_status
IF reg_status_wr='1' THEN nxt_reg_status <= c_eth_mm_reg_status_rst; END IF;
-- Events that set the status register
IF rcv_in.eop='1' THEN nxt_reg_status.rx_empty <= rcv_in.empty(c_eth_empty_w-1 DOWNTO 0); END IF;
IF rcv_in_eop_dly='1' THEN
nxt_reg_status.rx_nof_words <= (OTHERS=>'0');
nxt_reg_status.rx_nof_words(c_eth_frame_nof_words_w-1 DOWNTO 0) <= INCR_UVEC(i_mem_in.address(c_eth_frame_nof_words_w-1 DOWNTO 0), 1);
END IF;
IF tx_insert='1' THEN nxt_reg_status.tx_avail <= '1'; END IF;
IF hdr_done='1' THEN nxt_reg_status.rx_avail <= '1'; END IF;
IF xmt_done='1' THEN nxt_reg_status.tx_done <= '1'; END IF;
END PROCESS;
-- Capture the control register tx fields for a new transmit
nxt_tx_nof_words <= reg_control.tx_nof_words(c_eth_frame_nof_words_w-1 DOWNTO 0) WHEN xmt_start='1' ELSE tx_nof_words;
nxt_tx_empty <= reg_control.tx_empty WHEN xmt_start='1' ELSE tx_empty;
------------------------------------------------------------------------------
-- State machine
------------------------------------------------------------------------------
p_state : PROCESS(state, reg_control, reg_continue_wr, rcv_in, rcv_ack, rcv_done, hdr_word_cnt, xmt_siso, xmt_word_cnt, tx_nof_words, xmt_done)
BEGIN
nxt_rcv_rd <= '0'; -- read frame start pulse
nxt_hdr_en <= '0'; -- prepare response header enable
nxt_hdr_done <= '0'; -- prepare response header done
nxt_tx_insert <= '0'; -- accept tx insert request
nxt_xmt_start <= '0'; -- write frame start pulse
nxt_xmt_en <= '0'; -- write frame enable
nxt_state <= state;
CASE state IS
WHEN s_idle =>
IF reg_control.tx_request='1' THEN -- MM master requests to insert an extra tx frame
nxt_tx_insert <= '1';
nxt_state <= s_tx_pending;
END IF;
IF reg_control.rx_en='1' THEN -- MM master enables default Rx-Tx operation so request a new rx frame
nxt_rcv_rd <= '1';
nxt_state <= s_rx_request;
END IF;
WHEN s_rx_request =>
IF rcv_in.sop='1' THEN -- busy receiving a new frame (best check for sop, so no need to check rcv_busy, rcv_err in eth_rx_frame)
nxt_state <= s_rx_frame;
ELSIF rcv_ack='1' THEN -- rcv ack with no rcv sop, so there was no rx frame pending, try request again
nxt_state <= s_idle;
END IF;
WHEN s_rx_frame =>
IF rcv_done='1' THEN -- frame received
nxt_state <= s_hdr_response;
END IF;
WHEN s_hdr_response => -- prepare tx header for rx response
IF hdr_word_cnt < c_eth_total_header_nof_words-1 THEN
nxt_hdr_en <= '1';
ELSE
nxt_hdr_done <= '1'; -- new frame received and response prepared
nxt_state <= s_tx_pending;
END IF;
WHEN s_tx_pending => -- wait for MM master
IF reg_continue_wr='1' THEN -- MM master done
IF reg_control.tx_en='1' THEN -- continue with response tx frame
nxt_xmt_start <= '1';
nxt_state <= s_tx_frame;
ELSE -- do not response tx frame
nxt_state <= s_idle;
END IF;
END IF;
WHEN s_tx_frame =>
IF xmt_siso.ready='0' OR xmt_word_cnt < UNSIGNED(tx_nof_words)-1 THEN
nxt_xmt_en <= '1';
ELSE
nxt_state <= s_tx_done; -- frame transmitted
END IF;
WHEN OTHERS => -- s_tx_done
IF xmt_done='1' THEN
nxt_state <= s_idle; -- frame transmitted, to be safe wait for xmt_done
END IF;
END CASE;
END PROCESS;
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_lib.common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
-- Description:
-- . for IP frames replace IP header checksum with the calculated value
-- . discard frames shorter than 11 words
-- . frame discard input to optionally discard a frame based on some header criteria
ENTITY eth_hdr_ctrl IS
PORT (
-- Clocks and reset
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Stored header
hdr_words : IN t_eth_total_header_arr;
hdr_status : IN t_eth_hdr_status;
frm_discard : IN STD_LOGIC := '0';
-- ST interface
snk_in_word_cnt : IN NATURAL RANGE 0 TO c_eth_total_header_nof_words; -- snk_in hdr word count
snk_in : IN t_dp_sosi;
snk_out : OUT t_dp_siso;
src_in : IN t_dp_siso;
src_out : OUT t_dp_sosi
);
END eth_hdr_ctrl;
ARCHITECTURE rtl OF eth_hdr_ctrl IS
-- Internal sink ready latency and source ready latency of this component
CONSTANT c_this_snk_latency : NATURAL := 1;
CONSTANT c_this_src_latency : NATURAL := 1;
TYPE t_state_enum IS (
s_idle,
s_store_header,
s_src_header_sop,
s_src_header,
s_src_data
);
SIGNAL state : t_state_enum;
SIGNAL nxt_state : t_state_enum;
-- Sink
SIGNAL snk_in_eop_hold : STD_LOGIC;
SIGNAL nxt_snk_in_eop_hold : STD_LOGIC;
-- Source
SIGNAL next_src_out : t_dp_sosi;
SIGNAL i_src_out : t_dp_sosi;
SIGNAL nxt_src_out : t_dp_sosi;
SIGNAL src_word_cnt : NATURAL RANGE 0 TO c_eth_total_header_nof_words;
SIGNAL nxt_src_word_cnt : NATURAL;
BEGIN
src_out <= i_src_out;
p_reg : PROCESS(rst, clk)
BEGIN
IF rst='1' THEN
state <= s_idle;
snk_in_eop_hold <= '0';
src_word_cnt <= 0;
i_src_out <= c_dp_sosi_rst;
ELSIF rising_edge(clk) THEN
state <= nxt_state;
snk_in_eop_hold <= nxt_snk_in_eop_hold;
src_word_cnt <= nxt_src_word_cnt;
i_src_out <= nxt_src_out;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Hold the sink input for source output
------------------------------------------------------------------------------
u_snk_in : ENTITY dp_lib.dp_hold_input
PORT MAP (
rst => rst,
clk => clk,
-- ST sink
snk_out => OPEN,
snk_in => snk_in,
-- ST source
src_in => src_in, -- must not use snk_out.ready here to avoid wrong first payload data
next_src_out => next_src_out,
pend_src_out => OPEN,
src_out_reg => i_src_out
);
------------------------------------------------------------------------------
-- Control state machine for the source output
------------------------------------------------------------------------------
-- Hold snk_in.eop, because snk_in packet can only have a header of exactly 11 words (e.g. ARP).
-- Discard snk_in packets that are shorter than 11 words (e.g. ???), for both Rx and Tx shorter frames are not useful.
nxt_snk_in_eop_hold <= '0' WHEN snk_in.sop='1' ELSE
'1' WHEN snk_in.eop='1' ELSE snk_in_eop_hold;
p_state : PROCESS(state, src_word_cnt, i_src_out, snk_in, snk_in_word_cnt, frm_discard, src_in, hdr_words, hdr_status, snk_in_eop_hold, next_src_out)
BEGIN
snk_out.ready <= '1'; -- default accept sink input
nxt_state <= state;
nxt_src_word_cnt <= src_word_cnt;
nxt_src_out <= i_src_out;
nxt_src_out.valid <= '0';
nxt_src_out.sop <= '0';
nxt_src_out.eop <= '0';
CASE state IS
WHEN s_idle =>
-- wait for new frame, then store the frame header and no output yet
IF snk_in.sop='1' THEN
nxt_src_word_cnt <= 0;
nxt_state <= s_store_header;
END IF;
WHEN s_store_header =>
-- stop the sink when the whole header has arrived or when a eop has arrived
IF snk_in.valid='1' AND snk_in_word_cnt=c_eth_total_header_nof_words-1 THEN
snk_out.ready <= '0';
nxt_state <= s_src_header_sop;
ELSIF snk_in.eop='1' THEN
-- discard not supported packets shorter than 11 words
snk_out.ready <= '0';
nxt_state <= s_idle;
END IF;
WHEN s_src_header_sop =>
-- stop the input and output the (modified) header, first the sop
snk_out.ready <= '0';
IF frm_discard='1' THEN
-- discard this frame because of optional external reasons
nxt_state <= s_idle;
ELSIF src_in.ready='1' THEN
nxt_src_out.data <= RESIZE_DP_DATA(hdr_words(src_word_cnt));
nxt_src_out.valid <= '1';
nxt_src_out.sop <= '1';
nxt_src_out.eop <= '0';
nxt_src_word_cnt <= src_word_cnt+1;
nxt_state <= s_src_header;
END IF;
WHEN s_src_header =>
-- stop the input and output the rest of the (modified) header
snk_out.ready <= '0';
IF src_in.ready='1' THEN
nxt_src_out.data <= RESIZE_DP_DATA(hdr_words(src_word_cnt));
nxt_src_out.valid <= '1';
nxt_src_out.sop <= '0';
nxt_src_out.eop <= '0';
nxt_src_word_cnt <= src_word_cnt+1;
-- Replace IP header checksum with the calculated checksum from hdr_status.ip_checksum:
-- . for Rx: the verified checksum, so will be 0 when OK or != when the received frame has an IP header error.
-- . for Tx: the calculated checksum for the Tx IP header.
IF hdr_status.is_ip='1' AND src_word_cnt=c_ip_header_checksum_wi THEN
nxt_src_out.data(c_ip_header_checksum_w-1 DOWNTO 0) <= hdr_status.ip_checksum;
END IF;
IF src_word_cnt=c_eth_total_header_nof_words-1 THEN
IF snk_in_eop_hold='1' THEN
-- header only packet
nxt_src_out.eop <= '1';
nxt_state <= s_idle;
ELSE
-- packet with payload
nxt_state <= s_src_data;
END IF;
END IF;
END IF;
WHEN OTHERS => -- s_src_data
-- continue the input payload and output it
snk_out.ready <= src_in.ready;
nxt_src_out <= next_src_out;
IF next_src_out.eop='1' THEN
nxt_state <= s_idle;
END IF;
END CASE;
-- Pass on frame level flow control
snk_out.xon <= src_in.xon;
END PROCESS;
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_lib.common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
-- Purpose:
-- Determine the Ethernet header status.
-- Description:
-- Determines all relevant information from the Ethernet header after every
-- asserted sop.
-- Remark:
-- . g_ip_header_checksum_calculate:
-- = TRUE, then the IP header checksum is calculated for hdr_status
-- = FALSE, then the IP header checksum is read for hdr_status
ENTITY eth_hdr_status IS
GENERIC (
g_ip_header_checksum_calculate : BOOLEAN := TRUE
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Total header
hdr_words : IN t_eth_total_header_arr;
hdr_words_val : IN STD_LOGIC_VECTOR(0 TO c_eth_total_header_nof_words-1);
hdr_fields : IN t_eth_total_header;
hdr_fields_val : IN STD_LOGIC_VECTOR(0 TO c_eth_total_header_nof_words-1);
hdr_data : IN STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
hdr_data_val : IN STD_LOGIC;
-- Header status
hdr_status : OUT t_eth_hdr_status
);
END eth_hdr_status;
ARCHITECTURE rtl OF eth_hdr_status IS
SIGNAL i_hdr_status : t_eth_hdr_status;
SIGNAL nxt_hdr_status : t_eth_hdr_status;
SIGNAL ip_header : t_dp_sosi;
SIGNAL calc_checksum : STD_LOGIC_VECTOR(c_halfword_w-1 DOWNTO 0);
SIGNAL calc_checksum_val : STD_LOGIC;
SIGNAL ip_checksum : STD_LOGIC_VECTOR(c_halfword_w-1 DOWNTO 0);
SIGNAL ip_checksum_val : STD_LOGIC;
BEGIN
hdr_status <= i_hdr_status;
p_clk : PROCESS(rst, clk)
BEGIN
IF rst='1' THEN
i_hdr_status <= c_eth_hdr_status_rst;
ELSIF rising_edge(clk) THEN
i_hdr_status <= nxt_hdr_status;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Packet type
nxt_hdr_status.is_arp <= '1' WHEN UNSIGNED(hdr_fields.eth.eth_type)=c_eth_type_arp AND hdr_fields_val(c_eth_type_wi)='1' ELSE '0';
nxt_hdr_status.is_ip <= '1' WHEN UNSIGNED(hdr_fields.eth.eth_type)=c_eth_type_ip AND hdr_fields_val(c_eth_type_wi)='1' ELSE '0';
nxt_hdr_status.is_icmp <= '1' WHEN UNSIGNED(hdr_fields.ip.protocol)=c_ip_protocol_icmp AND hdr_fields_val(c_ip_protocol_wi)='1' AND i_hdr_status.is_ip='1' ELSE '0';
nxt_hdr_status.is_udp <= '1' WHEN UNSIGNED(hdr_fields.ip.protocol)=c_ip_protocol_udp AND hdr_fields_val(c_ip_protocol_wi)='1' AND i_hdr_status.is_ip='1' ELSE '0';
nxt_hdr_status.is_dhcp <= '1' WHEN UNSIGNED(hdr_fields.udp.dst_port)=c_udp_port_dhcp_in AND hdr_fields_val(c_udp_dst_port_wi)='1' AND i_hdr_status.is_udp='1' ELSE '0';
------------------------------------------------------------------------------
-- IP Header checksum
ip_header.data <= RESIZE_dp_data(hdr_data);
ip_header.valid <= '1' WHEN UNSIGNED(hdr_words_val(c_ip_lo_wi TO c_ip_hi_wi))/=0 ELSE '0';
ip_header.sop <= hdr_words_val(c_ip_lo_wi);
ip_header.eop <= hdr_words_val(c_ip_hi_wi);
ip_header.empty <= (OTHERS=>'0');
-- Calculate the IP header checksum for the packet header
u_calc_checksum : ENTITY work.eth_checksum
PORT MAP (
rst => rst,
clk => clk,
snk_in => ip_header,
checksum => calc_checksum,
checksum_val => calc_checksum_val
);
-- Use calculated IP header checksum
gen_calc : IF g_ip_header_checksum_calculate=TRUE GENERATE
ip_checksum <= calc_checksum;
ip_checksum_val <= calc_checksum_val;
END GENERATE;
-- Use IP header checksum field read from the frame header
gen_read : IF g_ip_header_checksum_calculate=FALSE GENERATE
ip_checksum <= hdr_fields.ip.header_checksum;
ip_checksum_val <= calc_checksum_val; -- use u_calc_checksum only for valid control
END GENERATE;
-- If it is an IP packet then update the hdr_status IP checksum fields, else leave them 0
p_hdr_status_ip_checksum : PROCESS(i_hdr_status, ip_checksum, ip_checksum_val)
BEGIN
nxt_hdr_status.ip_checksum_val <= '0';
nxt_hdr_status.ip_checksum <= (OTHERS=>'0');
nxt_hdr_status.ip_checksum_is_ok <= '0';
IF i_hdr_status.is_ip='1' AND ip_checksum_val='1' THEN
nxt_hdr_status.ip_checksum_val <= '1';
nxt_hdr_status.ip_checksum <= ip_checksum;
IF UNSIGNED(ip_checksum)=0 THEN
nxt_hdr_status.ip_checksum_is_ok <= '1';
END IF;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- UDP port number
nxt_hdr_status.udp_port <= hdr_fields.udp.dst_port;
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
-- Purpose:
-- Provide the total Ethernet header information for the user to decide upon.
-- Description:
-- Extract the first c_eth_total_header_nof_words = 11 words from an Ethernet
-- packet and make them available via as a word array and as records fields.
-- The component has three output formats:
-- 1) hdr_words, the 11 word header store
-- 2) hdr_data, the currently active header word
-- 3) hdr_fields, combinatorial mapping of the 11 word header store to
-- various Ethernet packet header fields.
-- Which format to use depends on the application. The logic for words or
-- header fields that are not used, will get optimized away during synthesis.
-- The snk_in word count is also output for the header words. The first valid
-- word marked by the snk_in.sop has count 0, the last header word has count
-- 10 and the payload words have count 11.
-- Remarks:
-- . This component acts as a stream monitor, therefore it does not output a
-- snk_out.ready.
-- . The word indices from eth_pkg together with hdr_words_val[] can be used
-- to determine which word of the Ethernet header words is valid.
-- . The word indices from eth_pkg together with hdr_fields_val[] can be used
-- to determine which fields of the Ethernet header records are valid. The
-- difference with hdr_words_val is that hdr_words_val is a single cycle
-- pulse, whereas hdr_fields_val keeps its state until the next sop.
--
ENTITY eth_hdr_store IS
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Streaming Sink
snk_in : IN t_dp_sosi;
snk_in_word_cnt : OUT NATURAL RANGE 0 TO c_eth_total_header_nof_words;
-- Total header
hdr_words : OUT t_eth_total_header_arr;
hdr_words_val : OUT STD_LOGIC_VECTOR(0 TO c_eth_total_header_nof_words-1);
-- Combinatorial map of the 11 header words on to the Ethernet header records
hdr_fields : OUT t_eth_total_header;
hdr_fields_val : OUT STD_LOGIC_VECTOR(0 TO c_eth_total_header_nof_words-1);
-- Support also outputting only the currently valid header data
hdr_data : OUT STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
hdr_data_val : OUT STD_LOGIC
);
END eth_hdr_store;
ARCHITECTURE rtl OF eth_hdr_store IS
SIGNAL word_cnt : NATURAL RANGE 0 TO c_eth_total_header_nof_words;
SIGNAL nxt_word_cnt : NATURAL;
SIGNAL i_hdr_words : t_eth_total_header_arr := (OTHERS=>(OTHERS=>'0')); -- init to avoid numeric_std warning, no need to rst
SIGNAL nxt_hdr_words : t_eth_total_header_arr;
SIGNAL nxt_hdr_words_val : STD_LOGIC_VECTOR(hdr_fields_val'RANGE);
SIGNAL i_hdr_fields_val : STD_LOGIC_VECTOR(hdr_fields_val'RANGE);
SIGNAL nxt_hdr_fields_val : STD_LOGIC_VECTOR(hdr_fields_val'RANGE);
SIGNAL i_hdr_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := (OTHERS=>'0'); -- init to avoid numeric_std warning, no need to rst
SIGNAL nxt_hdr_data : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0);
SIGNAL nxt_hdr_data_val : STD_LOGIC;
BEGIN
snk_in_word_cnt <= word_cnt;
hdr_words <= i_hdr_words;
hdr_fields_val <= i_hdr_fields_val;
hdr_data <= i_hdr_data;
p_clk : PROCESS(rst, clk)
BEGIN
IF rst='1' THEN
-- input
-- internal
word_cnt <= 0;
-- output
hdr_words_val <= (OTHERS=>'0');
i_hdr_fields_val <= (OTHERS=>'0');
hdr_data_val <= '0';
ELSIF rising_edge(clk) THEN
-- input
-- internal
word_cnt <= nxt_word_cnt;
-- output
i_hdr_words <= nxt_hdr_words; -- stored array of 11 words
hdr_words_val <= nxt_hdr_words_val;
i_hdr_fields_val <= nxt_hdr_fields_val;
i_hdr_data <= nxt_hdr_data; -- current word
hdr_data_val <= nxt_hdr_data_val;
END IF;
END PROCESS;
-- Extract the 11 words from the Ethernet header
p_words : PROCESS(word_cnt, i_hdr_words, i_hdr_fields_val, i_hdr_data, snk_in)
BEGIN
nxt_word_cnt <= word_cnt;
nxt_hdr_words <= i_hdr_words;
nxt_hdr_words_val <= (OTHERS=>'0');
nxt_hdr_fields_val <= i_hdr_fields_val;
nxt_hdr_data <= i_hdr_data;
nxt_hdr_data_val <= '0';
IF snk_in.sop='1' THEN
nxt_hdr_fields_val <= (OTHERS=>'0');
END IF;
IF snk_in.valid='1' AND word_cnt < c_eth_total_header_nof_words THEN
-- new Ethernet header is arriving
nxt_word_cnt <= word_cnt + 1;
nxt_hdr_words( word_cnt) <= snk_in.data(c_eth_data_w-1 DOWNTO 0);
nxt_hdr_words_val( word_cnt) <= '1';
nxt_hdr_fields_val(word_cnt) <= '1';
nxt_hdr_data <= snk_in.data(c_eth_data_w-1 DOWNTO 0);
nxt_hdr_data_val <= '1';
END IF;
IF snk_in.eop='1' THEN
nxt_word_cnt <= 0;
END IF;
END PROCESS;
-- Combinatorial map of the total header on to the Ethernet header records
hdr_fields.eth <= func_eth_map_eth_header( i_hdr_words);
hdr_fields.arp <= func_eth_map_arp_packet( i_hdr_words);
hdr_fields.ip <= func_eth_map_ip_header( i_hdr_words);
hdr_fields.icmp <= func_eth_map_icmp_header(i_hdr_words);
hdr_fields.udp <= func_eth_map_udp_header( i_hdr_words);
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program IS free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program IS distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_lib.common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
-- Purpose:
-- Description:
-- Strip IPv4 headers to 20 bytes
-- Set ihl to 5 (5 * 4 = 20 bytes)
-- Ajust IPv4 Packet Total Length field
-- IP Header Checksum is set to 0x0000 and should be ignored
-- The checksum could be updated using https://tools.ietf.org/html/rfc1624
-- Remarks:
-- . c_this_snk_latency = 1
-- . c_this_src_latency = 1
------------------------------------------------------------------------------
-- IPv4 Packet
--
-- 0 3 4 7 8 15 16 18 19 31 wi
-- |----------------------------------------------------------------------|
-- | Version | ihl | Services | IPv4 Packet Total Length | 4
-- |----------------------------------------------------------------------|
-- | Identification | Flags | Fragment Offset | 5
-- |----------------------------------------------------------------------|
-- | TTL | Protocol | Header Checksum | 6
-- |----------------------------------------------------------------------|
-- | Source IP Address | 7
-- |----------------------------------------------------------------------|
-- | Destination IP Address | 8
-- |----------------------------------------------------------------------|
-- | Options ... |
-- |----------------------------------------------------------------------|
ENTITY eth_ihl_to_20 IS
GENERIC (
incoming_ihl : NATURAL := 20
);
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
-- Streaming Sink
snk_in : IN t_dp_sosi;
snk_out : OUT t_dp_siso;
-- Streaming Source
src_in : IN t_dp_siso;
src_out : OUT t_dp_sosi
);
END eth_ihl_to_20;
ARCHITECTURE rtl OF eth_ihl_to_20 IS
SIGNAL i_src_out : t_dp_sosi;
TYPE state_type IS (Idle, Eth_DestMAC0, Eth_DestMAC1, Eth_SrcMAC0, Eth_SrcMAC1, IPv4_lengths, IPv4_ID, IPv4_TTL, IPv4_SrcIP, IPv4_DestIP, IPv4_Options, IPv4_Payload);
SIGNAL state : state_type;
SIGNAL ihl : unsigned(c_ip_header_length_w-1 downto 0);
BEGIN
src_out <= i_src_out;
--i_src_out <= snk_in;
-- Pass on frame level flow control
snk_out.xon <= src_in.xon;
-- No change in ready latency, c_this_snk_latency = c_this_src_latency
snk_out.ready <= src_in.ready;
PROCESS(clk, rst)
BEGIN
IF rst = '1' THEN
state <= Idle;
ihl <= TO_UNSIGNED(0,ihl'LENGTH);
ELSIF (rising_edge(clk)) THEN
i_src_out <= snk_in;
CASE state IS
WHEN Idle=>
IF snk_in.sop = '1' and snk_in.valid = '1' THEN
state <= Eth_DestMAC0;
END IF;
WHEN Eth_DestMAC0=>
IF snk_in.valid = '1' THEN
state <= Eth_DestMAC1;
END IF;
WHEN Eth_DestMAC1 =>
IF snk_in.valid = '1' THEN
state <= Eth_SrcMAC0;
END IF;
WHEN Eth_SrcMAC0 =>
IF snk_in.valid = '1' THEN
IF snk_in.data(c_eth_type_slv'RANGE) = TO_UVEC(c_eth_type_ip,c_eth_type_w) THEN -- if IPv4 frame
state <= Eth_SrcMAC1;
ELSE
state <= Idle;
END IF;
END IF;
WHEN Eth_SrcMAC1 =>
IF snk_in.valid = '1' THEN
IF snk_in.data(27 downto 24) = TO_UVEC(c_ip_header_length,c_ip_header_length_w) THEN -- if ihl = 20, nothing to do
state <= Idle;
ELSE
state <= IPv4_lengths;
i_src_out.data(27 downto 24) <= TO_UVEC(c_ip_header_length ,c_ip_header_length_w); -- make IHL = 20
i_src_out.data(c_ip_total_length_w-1 downto 0) <= std_logic_vector(unsigned(snk_in.data(c_ip_total_length_w-1 downto 0))
- ((unsigned(snk_in.data(27 downto 24))
- to_unsigned(c_ip_header_length ,c_ip_header_length_w)
) & "00"
)
); -- correct Total Length
ihl <= unsigned(snk_in.data(27 downto 24)); -- save IHL
END IF;
END IF;
WHEN IPv4_lengths =>
IF snk_in.valid = '1' THEN
state <= IPv4_ID;
ihl <= ihl - 1;
END IF;
WHEN IPv4_ID =>
IF snk_in.valid = '1' THEN
state <= IPv4_TTL;
i_src_out.data(c_ip_header_checksum_w-1 downto 0) <= TO_UVEC(0,c_ip_header_checksum_w);
ihl <= ihl - 1;
END IF;
WHEN IPv4_TTL =>
IF snk_in.valid = '1' THEN
state <= IPv4_SrcIP;
ihl <= ihl - 1;
END IF;
WHEN IPv4_SrcIP =>
IF snk_in.valid = '1' THEN
state <= IPv4_DestIP;
ihl <= ihl - 1;
END IF;
WHEN IPv4_DestIP =>
IF snk_in.valid = '1' THEN
i_src_out.valid <= '0'; -- do not allow option words to get through this module
state <= IPv4_Options;
ihl <= ihl - 1;
IF ihl = 2 THEN
state <= IPv4_Payload;
END IF;
END IF;
WHEN IPv4_Options =>
IF snk_in.valid = '1' THEN
i_src_out.valid <= '0'; -- do not allow option words to get through this module
ihl <= ihl - 1;
IF ihl = 2 THEN
state <= IPv4_Payload;
END IF;
END IF;
WHEN IPv4_Payload =>
IF snk_in.eop = '1' and snk_in.valid = '1' THEN
state <= Idle;
END IF;
WHEN others =>
state <= Idle;
END CASE;
END IF;
end PROCESS ;
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
ENTITY eth_mm_reg_frame IS
PORT (
-- Clocks and reset
rst : IN STD_LOGIC; -- reset synchronous with clk
clk : IN STD_LOGIC; -- packet stream clock
-- Inputs need for the frame register
hdr_fields : IN t_eth_total_header; -- Header info
hdr_status : IN t_eth_hdr_status; -- Header info
erc_word : IN STD_LOGIC_VECTOR(c_eth_data_w-1 DOWNTO 0); -- Extracted CRC word (enumerate: 0=OK, >0 AND odd = Error)
reg_config : IN t_eth_mm_reg_config; -- Config setting
-- Frame register
reg_frame : OUT t_eth_mm_reg_frame
);
END eth_mm_reg_frame;
ARCHITECTURE str OF eth_mm_reg_frame IS
SIGNAL nxt_reg_frame : t_eth_mm_reg_frame;
BEGIN
p_reg : PROCESS(rst, clk)
BEGIN
IF rst='1' THEN
reg_frame <= c_eth_mm_reg_frame_rst;
ELSIF rising_edge(clk) THEN
reg_frame <= nxt_reg_frame;
END IF;
END PROCESS;
nxt_reg_frame.is_dhcp <= hdr_status.is_dhcp;
nxt_reg_frame.is_udp_ctrl_port <= '1' WHEN hdr_status.is_udp='1' AND UNSIGNED(hdr_status.udp_port)=UNSIGNED(reg_config.udp_port) ELSE '0';
nxt_reg_frame.is_udp <= hdr_status.is_udp;
nxt_reg_frame.is_icmp <= hdr_status.is_icmp;
nxt_reg_frame.ip_address_match <= '1' WHEN UNSIGNED(hdr_fields.ip.dst_ip_addr)=UNSIGNED(reg_config.ip_address) ELSE '0';
nxt_reg_frame.ip_checksum_is_ok <= hdr_status.ip_checksum_is_ok;
nxt_reg_frame.is_ip <= hdr_status.is_ip;
nxt_reg_frame.is_arp <= hdr_status.is_arp;
nxt_reg_frame.mac_address_match <= '1' WHEN UNSIGNED(hdr_fields.eth.dst_mac)=UNSIGNED(reg_config.mac_address) ELSE '0';
nxt_reg_frame.eth_mac_error <= erc_word(c_eth_error_w-1 DOWNTO 0);
END str;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2010
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE common_lib.common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE common_lib.eth_layers_pkg.ALL;
USE work.eth_pkg.ALL;
ENTITY tb_eth_IHL_to_20 IS
END tb_eth_IHL_to_20;
ARCHITECTURE tb OF tb_eth_IHL_to_20 IS
CONSTANT clk_period : TIME := 5 ns; -- 100 MHz
SIGNAL clk : STD_LOGIC := '0';
SIGNAL rst : STD_LOGIC;
SIGNAL snk_in : t_dp_sosi := c_dp_sosi_rst;
SIGNAL snk_out : t_dp_siso;
SIGNAL src_in : t_dp_siso := c_dp_siso_rdy;
SIGNAL src_out : t_dp_sosi;
TYPE int_arr is array (natural range <>) of integer;
CONSTANT c_IHL_to_test : int_arr(1 to 11) := (5,6,7,8,9,10,11,12,13,14,15);
CONSTANT c_len_to_test : int_arr(1 to 5) := (0,1,16,20,3000);
PROCEDURE gen_eth_frame (constant IHL : natural;
constant UDP_payload_len : natural;
signal clk : in std_logic;
signal snk_in : inout t_dp_sosi) is
BEGIN
snk_in.sop <= '1';
snk_in.valid <= '1';
snk_in.data <= RESIZE_DP_DATA(X"0000FFFF"); -- Eth header
WAIT UNTIL rising_edge(clk);
snk_in.sop <= '0';
snk_in.data <= RESIZE_DP_DATA(X"FFFFFFFF");
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"10FA0004");
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"00000800");
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"4" & -- IPv4 header
TO_UVEC(IHL,c_ip_header_length_w) &
X"00" &
TO_UVEC((IHL+UDP_payload_len+2)*4,c_ip_total_length_w));
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"00004000");
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"80110000");
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"0A0B0001");
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(X"0A0B00FF");
WAIT UNTIL rising_edge(clk);
FOR I IN 6 TO IHL LOOP
snk_in.data <= RESIZE_DP_DATA(X"BAD000" & TO_UVEC(I,c_ip_header_length_w)); -- optionnal option word
WAIT UNTIL rising_edge(clk);
END LOOP;
snk_in.data <= RESIZE_DP_DATA(X"10FA10FA"); -- UDP header
WAIT UNTIL rising_edge(clk);
snk_in.data <= RESIZE_DP_DATA(TO_UVEC((UDP_payload_len+2)*4,c_udp_total_length_w) & X"0000");
WAIT UNTIL rising_edge(clk);
FOR I IN 0 TO UDP_payload_len-1 LOOP -- UDP payload
snk_in.data <= RESIZE_DP_DATA(X"BEEF" & TO_UVEC(I,16));
WAIT UNTIL rising_edge(clk);
END LOOP;
snk_in.data <= RESIZE_DP_DATA(X"CCCCCCCC"); -- Eth CRC
snk_in.eop <= '1';
WAIT UNTIL rising_edge(clk);
snk_in.data <= (OTHERS=>'0');
snk_in.valid <= '0';
snk_in.eop <= '0';
WAIT UNTIL rising_edge(clk);
END PROCEDURE gen_eth_frame;
PROCEDURE check_eth_frame ( constant UDP_payload_len : natural;
signal clk : in std_logic;
signal src_out : in t_dp_sosi) is
CONSTANT c_IHL : natural := 5;
BEGIN
-- Eth header
WAIT UNTIL falling_edge(clk) and src_out.valid = '1' and src_out.sop = '1';
ASSERT src_out.data(31 downto 0) = X"0000FFFF" REPORT "Wrong word align and Destination MAC" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"FFFFFFFF" REPORT "Wrong Destination MAC" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"10FA0004" REPORT "Wrong Source MAC" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"00000800" REPORT "Wrong Source MAC and EtherType" SEVERITY FAILURE;
-- IPv4 header
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"4" &
TO_UVEC(c_IHL,c_ip_header_length_w) &
X"00" &
TO_UVEC((c_IHL+UDP_payload_len+2)*4,c_ip_total_length_w)
REPORT "Wrong Version / IHL / Total Length" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"00004000" REPORT "Wrong identification / Flags / Frag Offset" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"80110000" REPORT "Wrong TTL / Protocol / Checksum" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"0A0B0001" REPORT "Wrong Source IP" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"0A0B00FF" REPORT "Wrong Dest IP" SEVERITY FAILURE;
-- No options Here
-- UDP header
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"10FA10FA" REPORT "Wrong UDP ports" SEVERITY FAILURE;
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = TO_UVEC((UDP_payload_len+2)*4,c_udp_total_length_w) &
X"0000"
REPORT "Wrong UDP length / CRC" SEVERITY FAILURE;
-- UDP payload
FOR I IN 0 TO UDP_payload_len-1 LOOP
WAIT UNTIL falling_edge(clk) and src_out.valid = '1';
ASSERT src_out.data(31 downto 0) = X"BEEF" & TO_UVEC(I,16) REPORT "Wrong UDP Payload" SEVERITY FAILURE;
-- ASSERT src_out.data(31 downto 0) = X"BEEF" & TO_UVEC(I,16) REPORT "Wrong UDP Payload: 0xBEEF" & TO_UVEC(I,16)'IMAGE SEVERITY FAILURE;
END LOOP;
-- Eth CRC
WAIT UNTIL falling_edge(clk) and src_out.valid = '1' and src_out.eop <= '1';
ASSERT src_out.data(31 downto 0) = X"CCCCCCCC" REPORT "Wrong Eth CRC" SEVERITY FAILURE;
END PROCEDURE check_eth_frame;
BEGIN
clk <= NOT clk AFTER clk_period/2;
rst <= '1', '0' AFTER clk_period*7;
gen_frame: PROCESS
BEGIN
WAIT UNTIL rst='0';
FOR len_n in c_len_to_test'RANGE LOOP
FOR IHL_n in c_IHL_to_test'RANGE LOOP
WAIT FOR 50 ns; WAIT UNTIL rising_edge(clk);
gen_eth_frame (c_IHL_to_test(IHL_n),
c_len_to_test(len_n),
clk,snk_in);
END LOOP;
END LOOP;
wait for 1 ms;
ASSERT FALSE REPORT "ERROR: Processing was too long. DUT is stuck" SEVERITY FAILURE;
WAIT;
END PROCESS;
dut : ENTITY work.eth_IHL_to_20
GENERIC MAP (
incoming_IHL => 24
)
PORT MAP (
rst => rst,
clk => clk,
-- Streaming Sink
snk_in => snk_in,
snk_out => snk_out,
-- Streaming Source
src_in => src_in,
src_out => src_out
);
check_frame: PROCESS
BEGIN
FOR len_n in c_len_to_test'RANGE LOOP
FOR IHL_n in c_IHL_to_test'RANGE LOOP
check_eth_frame (
c_len_to_test(len_n),
clk,src_out);
END LOOP;
END LOOP;
WAIT for 1 us;
ASSERT FALSE REPORT "Simulation finished: NO ERRORS" SEVERITY FAILURE;
WAIT;
END PROCESS;
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment