Skip to content
Snippets Groups Projects
Commit 0074f040 authored by Reinier van der Walle's avatar Reinier van der Walle
Browse files

added first unverified version of eth_checksum_10G

parent 5d046381
No related branches found
No related tags found
No related merge requests found
......@@ -7,6 +7,7 @@ hdl_lib_technology =
synth_files =
src/vhdl/eth_pkg.vhd
src/vhdl/eth_checksum.vhd
src/vhdl/eth_checksum_10G.vhd
src/vhdl/eth_hdr_store.vhd
src/vhdl/eth_hdr_status.vhd
src/vhdl/eth_hdr_ctrl.vhd
......@@ -25,6 +26,7 @@ synth_files =
test_bench_files =
src/vhdl/eth_statistics.vhd
tb/vhdl/tb_eth_checksum.vhd
tb/vhdl/tb_eth_checksum_10G.vhd
tb/vhdl/tb_eth_crc_ctrl.vhd
tb/vhdl/tb_eth_hdr.vhd
tb/vhdl/tb_eth.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 dp_lib.dp_stream_pkg.ALL;
USE work.eth_pkg.ALL;
-- Purpose:
-- Can be used to calculate the checksum for IPv4, ICMP and UDP, provided
-- the correct words are provided between sop and eop.
-- Description:
-- Determine the 16 bit 1-complement checksum according IPv4 to for the valid
-- words between snk_in.sop and snk_in.eop, taking in account snk_in.empty.
-- . For checksum verification the result should be 0 when the words are OK.
-- . For checksum calculation the result should be used at the checksum field
-- in the packet header.
-- Remarks:
-- . At the snk_in.sop the checksum is initialized to 0.
-- . At the snk_in.eop the snk_in.empty LSBytes are padded with 0.
-- . The words do not need to be provided in order, because the checksum is
-- based on addition.
-- . Assume that snk_in.sop and snk_in.eop are only active when snk_in.valid
-- is active.
-- . Assume that between packets so from snk_in.eop to next snk_in.sop the
-- snk_in.valid is inactive and that snk_in.valid is only active for new
-- data.
ENTITY eth_checksum_10G IS
PORT (
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
snk_in : IN t_dp_sosi;
checksum : OUT STD_LOGIC_VECTOR(c_halfword_w-1 DOWNTO 0);
checksum_val : OUT STD_LOGIC
);
END eth_checksum_10G;
ARCHITECTURE rtl OF eth_checksum_10G IS
SIGNAL in_data : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0);
SIGNAL in_valid : STD_LOGIC;
SIGNAL in_sop : STD_LOGIC;
SIGNAL in_eop : STD_LOGIC;
SIGNAL prev_in_valid : STD_LOGIC;
SIGNAL prev_in_eop : STD_LOGIC;
SIGNAL prev_in_eop_dly : STD_LOGIC;
SIGNAL word_sum_cin : UNSIGNED(1 DOWNTO 0); -- carry in
SIGNAL word_sum_dat : UNSIGNED(c_halfword_w-1 DOWNTO 0);
SIGNAL word_sum : UNSIGNED(c_halfword_w+1 DOWNTO 0);
SIGNAL nxt_word_sum : UNSIGNED(c_halfword_w+1 DOWNTO 0);
SIGNAL sum_cin : UNSIGNED(0 DOWNTO 0); -- carry in
SIGNAL sum_dat : UNSIGNED(c_halfword_w-1 DOWNTO 0);
SIGNAL sum : UNSIGNED(c_halfword_w DOWNTO 0);
SIGNAL nxt_sum : UNSIGNED(c_halfword_w DOWNTO 0);
SIGNAL last_dat : UNSIGNED(c_halfword_w-1 DOWNTO 0);
SIGNAL i_checksum : STD_LOGIC_VECTOR(checksum'RANGE);
SIGNAL nxt_checksum : STD_LOGIC_VECTOR(checksum'RANGE);
SIGNAL i_checksum_val : STD_LOGIC;
SIGNAL nxt_checksum_val : STD_LOGIC;
SIGNAL data_p0 : STD_LOGIC_VECTOR(c_halfword_w+1 DOWNTO 0);
SIGNAL data_p1 : STD_LOGIC_VECTOR(c_halfword_w+1 DOWNTO 0);
SIGNAL data_p2 : STD_LOGIC_VECTOR(c_halfword_w+1 DOWNTO 0);
SIGNAL data_p3 : STD_LOGIC_VECTOR(c_halfword_w+1 DOWNTO 0);
BEGIN
data_p0 <= "00" & in_data(c_longword_w -1 DOWNTO c_halfword_w * 3);
data_p1 <= "00" & in_data(c_halfword_w*3 -1 DOWNTO c_halfword_w * 2);
data_p2 <= "00" & in_data(c_halfword_w*2 -1 DOWNTO c_halfword_w );
data_p3 <= "00" & in_data(c_halfword_w -1 DOWNTO 0);
checksum <= i_checksum;
checksum_val <= i_checksum_val;
p_clk : PROCESS(rst, clk)
BEGIN
IF rst='1' THEN
prev_in_valid <= '0';
prev_in_eop <= '0';
prev_in_eop_dly <= '0';
word_sum <= (OTHERS=>'0');
sum <= (OTHERS=>'0');
i_checksum <= (OTHERS=>'0');
i_checksum_val <= '0';
ELSIF rising_edge(clk) THEN
-- input
prev_in_valid <= in_valid;
prev_in_eop <= in_eop;
prev_in_eop_dly <= prev_in_eop;
-- internal
word_sum <= nxt_word_sum;
sum <= nxt_sum;
-- outputs
i_checksum <= nxt_checksum;
i_checksum_val <= nxt_checksum_val;
END IF;
END PROCESS;
-- Combinatorial sink input
p_zero_empty : PROCESS(snk_in, in_eop)
BEGIN
in_data <= snk_in.data(c_longword_w-1 DOWNTO 0);
IF in_eop='1' THEN
CASE TO_INTEGER(UNSIGNED(snk_in.empty(c_eth_empty_w-1 DOWNTO 0))) IS
WHEN 1 => in_data <= snk_in.data(c_longword_w-1 DOWNTO c_byte_w) & c_slv0( c_byte_w-1 DOWNTO 0);
WHEN 2 => in_data <= snk_in.data(c_longword_w-1 DOWNTO 2*c_byte_w) & c_slv0(2*c_byte_w-1 DOWNTO 0);
WHEN 3 => in_data <= snk_in.data(c_longword_w-1 DOWNTO 3*c_byte_w) & c_slv0(3*c_byte_w-1 DOWNTO 0);
WHEN 4 => in_data <= snk_in.data(c_longword_w-1 DOWNTO 4*c_byte_w) & c_slv0(4*c_byte_w-1 DOWNTO 0);
WHEN 5 => in_data <= snk_in.data(c_longword_w-1 DOWNTO 5*c_byte_w) & c_slv0(5*c_byte_w-1 DOWNTO 0);
WHEN 6 => in_data <= snk_in.data(c_longword_w-1 DOWNTO 6*c_byte_w) & c_slv0(6*c_byte_w-1 DOWNTO 0);
WHEN 7 => in_data <= snk_in.data(c_longword_w-1 DOWNTO 7*c_byte_w) & c_slv0(7*c_byte_w-1 DOWNTO 0);
WHEN OTHERS => NULL;
END CASE;
END IF;
END PROCESS;
in_valid <= snk_in.valid;
in_sop <= snk_in.sop;
in_eop <= snk_in.eop;
-- Word sum
word_sum_cin <= (OTHERS => '0') WHEN in_sop='1' ELSE word_sum(c_halfword_w +1 DOWNTO c_halfword_w);
word_sum_dat <= word_sum(c_halfword_w-1 DOWNTO 0);
nxt_word_sum <= UNSIGNED(data_p0) +
UNSIGNED(data_p1) +
UNSIGNED(data_p2) +
UNSIGNED(data_p3) +
word_sum_cin WHEN in_valid='1' ELSE
word_sum;
-- Accumulated sum
sum_cin(0) <= sum(c_halfword_w);
sum_dat <= sum(c_halfword_w-1 DOWNTO 0);
nxt_sum <= (OTHERS=>'0') WHEN in_sop='1' ELSE
('0' & sum_dat) + word_sum_dat + sum_cin WHEN prev_in_valid='1' ELSE
sum;
-- Accumulate the last carry
last_dat <= sum(c_halfword_w-1 DOWNTO 0) + sum_cin;
-- Checksum is 1-complement of the sum
nxt_checksum <= NOT(STD_LOGIC_VECTOR(last_dat)) WHEN prev_in_eop_dly='1' ELSE i_checksum;
nxt_checksum_val <= '1' WHEN prev_in_eop_dly='1' ELSE
'0' WHEN in_sop='1' ELSE i_checksum_val;
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/>.
--
-------------------------------------------------------------------------------
-- Purpose: Testbench for eth_checksum
-- Description:
--
-- Example from Wiki IPv4. Use Hex 45000030442240008006442e8c7c19acae241e2b
-- (20Bytes IP header) the c_exp_checksum then becomes:
--
-- 4500 + 0030 + 4422 + 4000 + 8006 + 0000 + 8c7c + 19ac + ae24 + 1e2b = 2BBCF
-- 2 + BBCF = BBD1 = 1011101111010001, the 1'S of sum = 0100010000101110 = 442E
--
-- Verify that checksum=c_exp_checksum when checksum_val='1'
--
-- Usage:
-- > as 10
-- > run -all
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 work.eth_pkg.ALL;
ENTITY tb_eth_checksum_10G IS
END tb_eth_checksum_10G;
ARCHITECTURE tb OF tb_eth_checksum_10G IS
CONSTANT clk_period : TIME := 10 ns; -- 100 MHz
CONSTANT c_exp_checksum : NATURAL := 16#442E#;
-- Minimum nof clk cycles between eop and sop
CONSTANT c_checksum_latency : NATURAL := 3;
CONSTANT c_wait_eop_sop : NATURAL := 10; -- >= c_checksum_latency-1;
SIGNAL tb_end : STD_LOGIC := '0';
SIGNAL clk : STD_LOGIC := '1';
SIGNAL rst : STD_LOGIC;
SIGNAL src_out : t_dp_sosi;
SIGNAL checksum : STD_LOGIC_VECTOR(c_halfword_w-1 DOWNTO 0);
SIGNAL checksum_val : STD_LOGIC;
BEGIN
clk <= NOT clk OR tb_end AFTER clk_period/2;
rst <= '1', '0' AFTER 3*clk_period;
p_stimuli : PROCESS
BEGIN
src_out.data <= TO_DP_DATA(0);
src_out.valid <= '0';
src_out.sop <= '0';
src_out.eop <= '0';
src_out.empty <= TO_DP_EMPTY(0);
WAIT UNTIL rst='0';
WAIT UNTIL rising_edge(clk);
----------------------------------------------------------------------------
-- First
----------------------------------------------------------------------------
src_out.sop <= '1';
src_out.valid <= '1';
src_out.data <= RESIZE_DP_DATA(X"4500003044224000");
WAIT UNTIL rising_edge(clk);
src_out.sop <= '0';
src_out.data <= RESIZE_DP_DATA(X"800600008c7c19ac");
WAIT UNTIL rising_edge(clk);
src_out.eop <= '1';
src_out.data <= RESIZE_DP_DATA(X"00000000ae241e2b");
WAIT UNTIL rising_edge(clk);
src_out.data <= (OTHERS=>'0');
src_out.valid <= '0';
src_out.eop <= '0';
-- Wait latency
FOR I IN 0 TO c_wait_eop_sop-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Again with valid low for a few cycles
----------------------------------------------------------------------------
src_out.sop <= '1';
src_out.valid <= '1';
src_out.data <= RESIZE_DP_DATA(X"4500003044224000");
WAIT UNTIL rising_edge(clk);
src_out.sop <= '0';
src_out.data <= RESIZE_DP_DATA(X"800600008c7c19ac");
-- pause
src_out.valid <= '0';
FOR I IN 0 TO 1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
src_out.valid <= '1';
WAIT UNTIL rising_edge(clk);
src_out.eop <= '1';
src_out.data <= RESIZE_DP_DATA(X"00000000ae241e2b");
WAIT UNTIL rising_edge(clk);
src_out.data <= (OTHERS=>'0');
src_out.valid <= '0';
src_out.eop <= '0';
-- Wait latency
FOR I IN 0 TO c_wait_eop_sop-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Again with carry in within word_sum
----------------------------------------------------------------------------
src_out.sop <= '1';
src_out.valid <= '1';
src_out.data <= RESIZE_DP_DATA(X"4500003044224000");
-- WAIT UNTIL rising_edge(clk);
-- src_out.data <= RESIZE_DP_DATA(X"80060000");
-- WAIT UNTIL rising_edge(clk);
-- src_out.data <= RESIZE_DP_DATA(X"8c7c19ac");
WAIT UNTIL rising_edge(clk);
src_out.sop <= '0';
src_out.data <= RESIZE_DP_DATA(X"80068c7c000019ac");
-- pause
src_out.valid <= '0';
FOR I IN 0 TO 0 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
src_out.valid <= '1';
WAIT UNTIL rising_edge(clk);
src_out.eop <= '1';
src_out.data <= RESIZE_DP_DATA(X"00000000ae241e2b");
WAIT UNTIL rising_edge(clk);
src_out.data <= (OTHERS=>'0');
src_out.valid <= '0';
src_out.eop <= '0';
-- Wait latency
FOR I IN 0 TO c_wait_eop_sop-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
----------------------------------------------------------------------------
-- Again with empty = 2
----------------------------------------------------------------------------
src_out.empty <= TO_DP_EMPTY(2);
src_out.sop <= '1';
src_out.valid <= '1';
src_out.data <= RESIZE_DP_DATA(X"4500003044224000");
WAIT UNTIL rising_edge(clk);
src_out.sop <= '0';
src_out.data <= RESIZE_DP_DATA(X"80061e2b8c7c19ac"); -- overwrite these "0000" with the last 2, now empty, bytes "1e2b", to keep the seem expected result
WAIT UNTIL rising_edge(clk);
src_out.eop <= '1';
src_out.data <= RESIZE_DP_DATA(X"00000000ae241e2b");
WAIT UNTIL rising_edge(clk);
src_out.data <= (OTHERS=>'0');
src_out.valid <= '0';
src_out.eop <= '0';
-- Wait latency
FOR I IN 0 TO c_wait_eop_sop-1 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
tb_end <= '1';
ASSERT FALSE REPORT "Simulation tb_eth_checksum finished." SEVERITY NOTE;
WAIT;
END PROCESS;
p_verify : PROCESS
BEGIN
WAIT UNTIL rising_edge(clk);
IF checksum_val='1' THEN
ASSERT UNSIGNED(checksum)=c_exp_checksum REPORT "Wrong checksum" SEVERITY ERROR;
END IF;
IF tb_end='1' THEN
ASSERT checksum_val='1' REPORT "Checksum is not valid at tb_end" SEVERITY ERROR;
END IF;
END PROCESS;
u_dut : ENTITY work.eth_checksum_10G
PORT MAP (
rst => rst,
clk => clk,
snk_in => src_out,
checksum => checksum,
checksum_val => checksum_val
);
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment