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

added ip checksum inserter + added generics to eth_tester for setting

the header length
parent 2a782937
No related branches found
No related tags found
1 merge request!338added ip checksum inserter + added generics to eth_tester for setting
Pipeline #52660 passed
......@@ -62,18 +62,36 @@ package rdma_demo_pkg is
( field_name_pad("dp_sync" ), "RW", 1, field_default(0) ),
( field_name_pad("dp_bsn" ), "RW", 64, field_default(0) )
);
constant c_rdma_demo_dp_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_demo_dp_hdr_field_arr, c_word_w))
constant c_rdma_demo_dp_reg_hdr_dat_addr_span : natural := 2**c_rdma_demo_dp_reg_hdr_dat_addr_w
constant c_rdma_demo_dp_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_demo_dp_hdr_field_arr, c_word_w));
constant c_rdma_demo_dp_reg_hdr_dat_addr_span : natural := 2**c_rdma_demo_dp_reg_hdr_dat_addr_w;
constant c_rdma_demo_dp_app_hdr_len : natural := 12; -- octets
-- RoCEv2 header for RDMA write operation (excluding ETH, IP, UDP)
-- Base Transport Header (BTH) + RDMA Extended Transport Header (RETH) + Immediate Data
constant c_rdma_demo_roce_nof_hdr_fields : natural := 13 + 3 + 1;
constant c_rdma_demo_roce_hdr_field_sel : std_logic_vector(c_rdma_demo_nof_hdr_fields - 1 downto 0) := "1111111111111" & "111" & "1";
constant c_rdma_demo_roce_nof_hdr_fields : natural := 12 + 4 + 13 + 3 + 1;
constant c_rdma_demo_roce_hdr_field_sel : std_logic_vector(c_rdma_demo_roce_nof_hdr_fields - 1 downto 0) := "111011111001" & "0100" & "1111111111111" & "111" & "1";
constant c_rdma_demo_roce_hdr_field_arr : t_common_field_arr(c_rdma_demo_roce_nof_hdr_fields - 1 downto 0) := (
( field_name_pad("ip_version" ), "RW", 4, field_default(4) ),
( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ),
( field_name_pad("ip_services" ), "RW", 8, field_default(0) ),
( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- depends on BG block size, so set by data path
( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ),
( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ),
( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ),
( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ),
( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ),
( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ),
( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ),
( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- c_eth_tester_ip_dst_addr
( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ),
( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- c_eth_tester_udp_dst_port
( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- depends on BG block size, so set by data path
( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ),
constant c_rdma_demo_roce_hdr_field_arr : t_common_field_arr(c_rdma_demo_nof_hdr_fields - 1 downto 0) := (
( field_name_pad("bth_opcode" ), "RW", 8, field_default(0) ),
( field_name_pad("bth_se" ), "RW", 1, field_default(0) ),
( field_name_pad("bth_m" ), "RW", 1, field_default(0) ),
......@@ -87,15 +105,18 @@ package rdma_demo_pkg is
( field_name_pad("bth_ack_req" ), "RW", 1, field_default(0) ),
( field_name_pad("bth_reserved_b" ), "RW", 7, field_default(0) ),
( field_name_pad("bth_psn" ), "RW", 32, field_default(0) ),
( field_name_pad("reth_virtual_address" ), "RW", 64, field_default(0) ),
( field_name_pad("reth_r_key" ), "RW", 32, field_default(0) ),
( field_name_pad("reth_dma_length" ), "RW", 32, field_default(0) ),
( field_name_pad("immediate_data" ), "RW", 32, field_default(0) )
);
constant c_rdma_demo_roce_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_demo_roce_hdr_field_arr, c_word_w))
constant c_rdma_demo_roce_reg_hdr_dat_addr_span : natural := 2**c_rdma_demo_roce_reg_hdr_dat_addr_w
constant c_rdma_demo_roce_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_demo_roce_hdr_field_arr, c_word_w));
constant c_rdma_demo_roce_reg_hdr_dat_addr_span : natural := 2**c_rdma_demo_roce_reg_hdr_dat_addr_w;
constant c_rdma_demo_roce_hdr_len : natural := 32; -- octets
constant c_rdma_demo_roce_icrc_len : natural := 4; -- octets
end rdma_demo_pkg;
......
......@@ -42,7 +42,7 @@ use eth_lib.eth_pkg.all;
use eth_lib.eth_tester_pkg.all;
use work.rdma_demo_pkg.all;
entity rdma_demo_eth_tester_wrapper is
entity rdma_demo_roce_tester_wrapper is
port (
-- Clocks and reset
mm_clk : in std_logic;
......@@ -148,10 +148,10 @@ entity rdma_demo_eth_tester_wrapper is
reg_strobe_total_count_rx_avs_writedata : in std_logic_vector(32 - 1 downto 0)
);
end rdma_demo_eth_tester_wrapper;
end rdma_demo_roce_tester_wrapper;
architecture str of rdma_demo_eth_tester_wrapper is
architecture str of rdma_demo_roce_tester_wrapper is
constant c_nof_byte : natural := c_rdma_demo_nof_octet_output_100gbe;
signal rx_udp_sosi_arr : t_dp_sosi_arr(0 downto 0) := (others => c_dp_sosi_rst);
......@@ -189,10 +189,12 @@ begin
generic map (
g_nof_octet_generate => c_rdma_demo_nof_octet_generate_100gbe,
g_nof_octet_output => c_rdma_demo_nof_octet_output_100gbe,
g_use_network_header => false,
g_use_dp_header => true,
g_use_eth_header => false,
g_use_ip_udp_header => true,
g_use_dp_header => false,
g_hdr_field_arr => c_rdma_demo_dp_hdr_field_arr,
g_hdr_field_sel => c_rdma_demo_dp_hdr_field_sel,
g_hdr_app_len => c_rdma_demo_roce_hdr_len + c_rdma_demo_roce_icrc_len, -- Add icrc length here as this generic is used to calculate the total packet length.
g_remove_crc => false
)
port map (
......
......@@ -26,6 +26,7 @@ library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.common_pkg.all;
use work.common_field_pkg.all;
package common_network_layers_pkg is
......@@ -355,8 +356,36 @@ package common_network_layers_pkg is
constant c_network_udp_header_ones : t_network_udp_header := ("0000000000000001", "0000000000000001",
"0000000000000001", "0000000000000001");
function func_network_ip_header_checksum(field_arr : t_common_field_arr; hdr_fields_slv : std_logic_vector) return std_logic_vector;
end common_network_layers_pkg;
package body common_network_layers_pkg is
function func_network_ip_header_checksum(field_arr : t_common_field_arr; hdr_fields_slv : std_logic_vector) return std_logic_vector is
-- function to calculate the ip header checksum based on a header field array.
constant c_cin_w : natural := 4; -- bit width of carry
constant c_nof_halfword : natural := (c_network_ip_header_len / c_halfword_sz) - 1; -- -1 as we exclude the checksum field itself for calculation.
variable sum : unsigned(c_network_ip_header_checksum_w + c_cin_w - 1 downto 0) := (others => '0');
variable crc : std_logic_vector(c_network_ip_header_checksum_w - 1 downto 0);
variable vec : std_logic_vector(c_halfword_w * c_nof_halfword - 1 downto 0);
begin
-- vec = whole ip header excluding ip_header_checksum.
vec :=
hdr_fields_slv(field_hi(field_arr, "ip_version" ) downto field_lo(field_arr, "ip_protocol" ))
& hdr_fields_slv(field_hi(field_arr, "ip_src_addr" ) downto field_lo(field_arr, "ip_dst_addr" ));
-- sum up vec in halfwords
for i in 0 to c_nof_halfword - 1 loop
sum := sum + unsigned(vec(( i + 1 ) * c_halfword_w - 1 downto i * c_halfword_w));
end loop;
-- checksum = inverted (sum + carry)
crc := not(std_logic_vector(sum(c_halfword_w - 1 downto 0) + sum(sum'high downto c_halfword_w)));
return crc;
end func_network_ip_header_checksum;
end common_network_layers_pkg;
......@@ -7,7 +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_ip_header_checksum.vhd
src/vhdl/eth_hdr_store.vhd
src/vhdl/eth_hdr_status.vhd
src/vhdl/eth_hdr_ctrl.vhd
......@@ -33,6 +33,7 @@ test_bench_files =
src/vhdl/eth_statistics.vhd
tb/vhdl/tb_eth_checksum.vhd
tb/vhdl/tb_eth_crc_ctrl.vhd
tb/vhdl/tb_eth_ip_header_checksum.vhd
tb/vhdl/tb_eth_hdr.vhd
tb/vhdl/tb_eth.vhd
tb/vhdl/tb_eth_tester_pkg.vhd
......@@ -46,6 +47,7 @@ test_bench_files =
tb/vhdl/tb_eth_udp_offload.vhd
tb/vhdl/tb_eth_ihl_to_20.vhd
tb/vhdl/tb_tb_tb_eth_regression.vhd
tb/vhdl/tb_tb_eth_ip_header_checksum.vhd
regression_test_vhdl =
tb/vhdl/tb_eth_checksum.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;
----------------------------------------------------------------------------------
-- Purpose: --
-- Can be used to calculate and insert the checksum for the IP header --
-- in a 10GbE package, if the correct longwords are provided. --
-- Description: --
-- Determine the 16 bit 1-complement checksum according IPv4 to for the valid --
-- words between snk_in.sop and the last ip header field. --
-- After calculation, the checksum is inserted in the outgoing stream --
----------------------------------------------------------------------------------
entity eth_checksum_10g is
port (
rst : in std_logic;
clk : in std_logic;
src_out : out t_dp_sosi;
snk_in : in t_dp_sosi;
src_in : in t_dp_siso;
snk_out : out t_dp_siso
);
end eth_checksum_10g;
architecture rtl of eth_checksum_10g is
constant c_cin_w : natural := 4; -- bit width of carry
constant c_pipeline_delay : natural := 2;
signal sum : unsigned(c_halfword_w + c_cin_w - 1 downto 0) := (others => '0');
signal checksum : std_logic_vector(c_halfword_w - 1 downto 0);
signal cnt_clr, cnt_p_clr : std_logic;
signal cnt_en, cnt_p_en : std_logic;
signal count, count_p : std_logic_vector(31 downto 0);
signal dp_pipeline_src_out : t_dp_sosi;
begin
-------------------------------------------------
-- process to calculate the ip_header_checksum --
-------------------------------------------------
p_calc_chksum : process(clk)
begin
if rst = '1' then
sum <= (others => '0');
elsif rising_edge(clk) then
if cnt_clr = '1' then
sum <= (others => '0');
elsif cnt_en = '1' then
case TO_UINT(count) is
when 0 => -- 0 is the cycle after the sop due to the common_counter latency
sum <= sum + unsigned(snk_in.data(c_halfword_w - 1 downto 0)); -- ip_version, ip_header_length, ip_services
when 1 =>
sum <= sum + unsigned(snk_in.data(c_halfword_w * 4 - 1 downto c_halfword_w * 3)) -- ip_total_length
+ unsigned(snk_in.data(c_halfword_w * 3 - 1 downto c_halfword_w * 2)) -- ip_identification
+ unsigned(snk_in.data(c_halfword_w * 2 - 1 downto c_halfword_w)) -- ip_flags, ip_fragment_offset
+ unsigned(snk_in.data(c_halfword_w - 1 downto 0)); -- ip_time_to_live, ip_protocol
when 2 => -- skip ip_header_checksum
sum <= sum + unsigned(snk_in.data(c_halfword_w * 3 - 1 downto c_halfword_w * 2)) -- ip_src_addr(1/2)
+ unsigned(snk_in.data(c_halfword_w * 2 - 1 downto c_halfword_w)) -- ip_src_addr(2/2)
+ unsigned(snk_in.data(c_halfword_w - 1 downto 0)); -- ip_dst_addr(1/2)
when 3 =>
sum <= sum + unsigned(snk_in.data(c_halfword_w * 4 - 1 downto c_halfword_w * 3)); -- ip_dst_addr(2/2)
when others =>
end case;
end if;
end if;
end process;
---------------------------------------------------
-- process to insert checksum in outgoing stream --
---------------------------------------------------
checksum <= not(std_logic_vector(sum(c_halfword_w - 1 downto 0) + sum(sum'high downto c_halfword_w))); -- checksum = inverted (sum + carry)
p_insert_chksum : process(dp_pipeline_src_out, checksum, count)
begin
src_out <= dp_pipeline_src_out;
if TO_UINT(count_p) = 2 then
src_out.data(c_halfword_w * 4 - 1 downto c_halfword_w * 3) <= checksum;
end if;
end process;
-------------------------------------------------------------------------------------------
-- useing common_counter to keep track of the word alignment during checksum calculation --
-------------------------------------------------------------------------------------------
cnt_en <= snk_in.valid; -- only count when valid
cnt_clr <= snk_in.sop; -- restart counter on sop
u_calc_counter : entity common_lib.common_counter
port map (
rst => rst,
clk => clk,
cnt_clr => cnt_clr,
cnt_en => cnt_en,
count => count
);
-----------------------------------------------------------------------------------------
-- useing common_counter to keep track of the word alignment during checksum insertion --
-----------------------------------------------------------------------------------------
cnt_p_en <= dp_pipeline_src_out.valid; -- only count when valid
cnt_p_clr <= dp_pipeline_src_out.sop; -- restart counter on sop
u_pipe_counter : entity common_lib.common_counter
port map (
rst => rst,
clk => clk,
cnt_clr => cnt_p_clr,
cnt_en => cnt_p_en,
count => count_p
);
--------------------------------------------------------------------------------
-- useing dp_pipeline to make room for the checksum calculation and insertion --
--------------------------------------------------------------------------------
u_dp_pipeline : entity dp_lib.dp_pipeline
generic map (
g_pipeline => c_pipeline_delay
)
port map (
rst => rst,
clk => clk,
-- ST sink
snk_out => snk_out,
snk_in => snk_in,
-- ST source
src_in => src_in,
src_out => dp_pipeline_src_out
);
end rtl;
-- --------------------------------------------------------------------------
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- --------------------------------------------------------------------------
--
-- Author: R. van der Walle
-- Purpose:
-- Can be used to calculate and insert the checksum for the IP header
-- in a network package, if the correct hdr_fields_slv_in is provided.
-- Description:
-- Determine the 16 bit 1-complement checksum according IPv4 to for the
-- hdr_fields_slv_in.
-- After calculation, the checksum is inserted in the outgoing stream at
-- corresponding position based on g_hdr_field_arr and g_data_w.
-- Remarks:
-- The hdr_fields_slv_in should be valid on the snk_in.sop
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_field_pkg.all;
use common_lib.common_network_layers_pkg.all;
use dp_lib.dp_stream_pkg.all;
entity eth_ip_header_checksum is
generic (
g_data_w : natural := 64;
g_hdr_field_arr : t_common_field_arr
);
port (
rst : in std_logic;
clk : in std_logic;
src_out : out t_dp_sosi;
snk_in : in t_dp_sosi;
src_in : in t_dp_siso;
snk_out : out t_dp_siso;
hdr_fields_slv_in : std_logic_vector(1023 downto 0) := (others => '0')
);
end eth_ip_header_checksum;
architecture rtl of eth_ip_header_checksum is
constant c_hdr_len : natural := field_slv_len(g_hdr_field_arr);
constant c_hdr_crc_bit_hi : natural := field_hi(g_hdr_field_arr, "ip_header_checksum");
constant c_hdr_crc_bit_lo : natural := field_lo(g_hdr_field_arr, "ip_header_checksum");
-- calculate which word(s) of the incoming snk_in stream should contain the checksum.
constant c_hdr_crc_word_hi : natural := sel_a_b((c_hdr_crc_bit_hi / g_data_w) > 0, c_hdr_crc_bit_hi / g_data_w,
sel_a_b( c_hdr_crc_bit_hi > (c_hdr_len mod g_data_w), 1, 0)); --special case as the last hdr word can be < g_data_w.
constant c_hdr_crc_word_lo : natural := sel_a_b((c_hdr_crc_bit_lo / g_data_w) > 0, c_hdr_crc_bit_lo / g_data_w,
sel_a_b( c_hdr_crc_bit_lo > (c_hdr_len mod g_data_w), 1, 0)); --special case as the last hdr word can be < g_data_w.
-- calculate in which bit range of the selected word(s) the checksum should go.
constant c_crc_hi_bit_in_word : natural := g_data_w - ((c_hdr_len - c_hdr_crc_bit_hi) mod g_data_w);
constant c_crc_lo_bit_in_word : natural := (g_data_w - ((c_hdr_len - c_hdr_crc_bit_lo) mod g_data_w)) mod g_data_w;
constant c_hdr_nof_words : natural := ceil_div(c_hdr_len, g_data_w);
constant c_crc_word_span : natural := 1 + c_hdr_crc_word_hi - c_hdr_crc_word_lo;
signal checksum : std_logic_vector(c_network_ip_header_checksum_w - 1 downto 0) := (others => '0');
signal count : std_logic_vector(31 downto 0);
signal dp_pipeline_src_out : t_dp_sosi;
signal reg_done : std_logic := '0';
signal nxt_reg_done : std_logic := '0';
begin
-- calculate checksum
checksum <= func_network_ip_header_checksum(g_hdr_field_arr, hdr_fields_slv_in) when rising_edge(clk);
-- register to know when crc has been inserted.
reg_done <= nxt_reg_done when rising_edge(clk);
---------------------------------------------------
-- process to insert checksum in outgoing stream --
---------------------------------------------------
p_insert_crc : process(dp_pipeline_src_out, checksum, count, reg_done)
variable v_count : natural := 0;
variable v_hi : natural := 0;
variable v_lo : natural := 0;
begin
v_count := TO_UINT(count);
src_out <= dp_pipeline_src_out;
nxt_reg_done <= reg_done;
if reg_done = '0' and dp_pipeline_src_out.valid = '1' then
if v_count = c_hdr_crc_word_hi and v_count = c_hdr_crc_word_lo then -- checksum is in 1 word.
src_out.data(c_crc_hi_bit_in_word downto c_crc_lo_bit_in_word) <= checksum;
nxt_reg_done <= '1';
elsif v_count = c_hdr_crc_word_hi then
src_out.data(c_crc_hi_bit_in_word downto 0) <= checksum(c_network_ip_header_checksum_w - 1 downto c_network_ip_header_checksum_w - c_crc_hi_bit_in_word - 1);
elsif v_count = c_hdr_crc_word_lo then
src_out.data(g_data_w - 1 downto c_crc_lo_bit_in_word) <= checksum(g_data_w - c_crc_lo_bit_in_word - 1 downto 0);
nxt_reg_done <= '1';
elsif v_count < c_hdr_crc_word_hi and v_count > c_hdr_crc_word_lo then
v_hi := c_network_ip_header_checksum_w - 1 - c_crc_hi_bit_in_word - 1 - g_data_w * (c_hdr_crc_word_hi - v_count - 1);
v_lo := v_hi + 1 - g_data_w;
src_out.data(g_data_w - 1 downto 0) <= checksum(v_hi downto v_lo);
end if;
end if;
if reg_done = '1' and dp_pipeline_src_out.eop = '1' then
nxt_reg_done <= '0';
end if;
end process;
------------------------------------------------------------------------------------------
-- using common_counter to keep track of the word alignment during checksum calculation --
------------------------------------------------------------------------------------------
u_calc_counter : entity common_lib.common_counter
generic map (
g_init => c_hdr_nof_words - 1,
g_step_size => -1
)
port map (
rst => rst,
clk => clk,
cnt_ld => snk_in.sop,
cnt_en => snk_in.valid,
count => count
);
-------------------------------------------------------------------------------
-- using dp_pipeline to make room for the checksum calculation and insertion --
-------------------------------------------------------------------------------
u_dp_pipeline : entity dp_lib.dp_pipeline
generic map (
g_pipeline => 1 -- fixed to 1 as common_counter has fixed latency of 1 (cannot be higher)
)
port map (
rst => rst,
clk => clk,
-- ST sink
snk_out => snk_out,
snk_in => snk_in,
-- ST source
src_in => src_in,
src_out => dp_pipeline_src_out
);
end rtl;
......@@ -42,10 +42,12 @@ entity eth_tester is
g_bg_sync_timeout : natural := c_eth_tester_sync_timeout;
g_nof_octet_generate : natural := 1;
g_nof_octet_output : natural := 4; -- must be multiple of g_nof_octet_generate.
g_use_network_header : boolean := true;
g_use_eth_header : boolean := true;
g_use_ip_udp_header : boolean := true;
g_use_dp_header : boolean := true;
g_hdr_field_arr : t_common_field_arr := c_eth_tester_hdr_field_arr;
g_hdr_field_sel : std_logic_vector := c_eth_tester_hdr_field_sel;
g_hdr_app_len : natural := c_eth_tester_app_hdr_len;
g_remove_crc : boolean := true -- use TRUE when using sim_tse and tech_tse link interface,
-- use FALSE when streaming link interface
);
......@@ -125,10 +127,12 @@ begin
g_bg_sync_timeout => g_bg_sync_timeout,
g_nof_octet_generate => g_nof_octet_generate,
g_nof_octet_output => g_nof_octet_output,
g_use_network_header => g_use_network_header,
g_use_eth_header => g_use_eth_header,
g_use_ip_udp_header => g_use_ip_udp_header,
g_use_dp_header => g_use_dp_header,
g_hdr_field_arr => g_hdr_field_arr,
g_hdr_field_sel => g_hdr_field_sel
g_hdr_field_sel => g_hdr_field_sel,
g_hdr_app_len => g_hdr_app_len
)
port map (
-- Clocks and reset
......
......@@ -48,11 +48,12 @@ entity eth_tester_tx is
g_bg_sync_timeout : natural := 220 * 10**6; -- 10% margin for nominal 1 s with st_clk at 200MHz
g_nof_octet_generate : natural := 1;
g_nof_octet_output : natural := 4; -- must be multiple of g_nof_octet_generate
g_use_network_header : boolean := true;
g_use_eth_header : boolean := true;
g_use_ip_udp_header : boolean := true;
g_use_dp_header : boolean := true;
g_hdr_field_arr : t_common_field_arr := c_eth_tester_hdr_field_arr;
g_hdr_field_sel : std_logic_vector := c_eth_tester_hdr_field_sel
g_hdr_field_sel : std_logic_vector := c_eth_tester_hdr_field_sel;
g_hdr_app_len : natural := c_eth_tester_app_hdr_len
);
port (
-- Clocks and reset
......@@ -334,12 +335,15 @@ begin
-- until it restarts, so no need to pass bg_block_len on via e.g. the channel
-- field in u_fifo.
bg_block_len <= split_nof_symbols when c_use_split else TO_UINT(bg_ctrl_hold.samples_per_packet(15 downto 0)); -- packet lenghts fit in 16b
app_total_length <= c_eth_tester_app_hdr_len + bg_block_len when rising_edge(st_clk);
app_total_length <= g_hdr_app_len + bg_block_len when rising_edge(st_clk);
udp_total_length <= c_network_udp_header_len + app_total_length when rising_edge(st_clk);
ip_total_length <= c_network_ip_header_len + udp_total_length when rising_edge(st_clk);
gen_network_header : if g_use_network_header generate
gen_eth_header : if g_use_eth_header generate
hdr_fields_slv_in(field_hi(g_hdr_field_arr, "eth_src_mac" ) downto field_lo(g_hdr_field_arr, "eth_src_mac" )) <= eth_src_mac;
end generate;
gen_ip_udp_header : if g_use_ip_udp_header generate
hdr_fields_slv_in(field_hi(g_hdr_field_arr, "ip_total_length" ) downto field_lo(g_hdr_field_arr, "ip_total_length" )) <= TO_UVEC(ip_total_length, 16);
hdr_fields_slv_in(field_hi(g_hdr_field_arr, "ip_src_addr" ) downto field_lo(g_hdr_field_arr, "ip_src_addr" )) <= ip_src_addr;
hdr_fields_slv_in(field_hi(g_hdr_field_arr, "udp_src_port" ) downto field_lo(g_hdr_field_arr, "udp_src_port" )) <= udp_src_port;
......
-- --------------------------------------------------------------------------
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- --------------------------------------------------------------------------
-- Author: R. van der Walle
-- Purpose:
-- . Test bench for eth_ip_header_checksum.
-- Description:
-- u_tx DUT u_rx
-- ___________________ ___________________ ___________________
-- |dp_offload_tx_v3 | |eth_ip_header_ | |dp_offload_rx |
-- stimuli_src -->| |----->|checksum |----->| |--> verify_snk
-- | in out | | in out | | | in out |
-- |___________________| |___________________| | |___________________|
-- |
-- i link_offload_sosi
--
-- The verification of the header - data block boundary is controlled via
-- g_symbol_w:
-- . g_symbol_w = g_data_w : boundary at g_data_w
-- . g_symbol_w < g_data_w : boundary at g_symbol_w, by reducing the number
-- of the header dp_bsn field by 1 symbol. If the c_bsn_w <= 32 then the
-- header MM interface only needs one MM word to read the header, so
-- therefore there are two sizes of c_expected_tx_hdr_word_arr_* and
-- c_expected_rx_hdr_word_arr_*.
--
-- Remarks:
-- . The g_flow_control_verify has to be e_active, otherwise the tb fails,
-- probably due to limitation in dp_offload_rx.vhd.
-- . It appears that the tx_hdr_word read values are the MM write values, so
-- read of value from logic fields (with MM override '0', e.g. dp_bsn,
-- eth_src_mac) is not supported.
-- . testbench is based on tb_offload_tx_v3.
--
-- 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 common_lib.common_lfsr_sequences_pkg.all;
use common_lib.common_mem_pkg.all;
use common_lib.common_field_pkg.all;
use common_lib.common_str_pkg.all;
use common_lib.tb_common_pkg.all;
use common_lib.tb_common_mem_pkg.all;
use dp_lib.dp_stream_pkg.all;
use dp_lib.tb_dp_pkg.all;
entity tb_eth_ip_header_checksum is
generic (
-- general
g_flow_control_stimuli : t_dp_flow_control_enum := e_pulse; -- always e_active, e_random or e_pulse flow control
g_flow_control_verify : t_dp_flow_control_enum := e_active; -- always e_active, e_random or e_pulse flow control
g_print_en : boolean := true;
-- specific
g_data_w : natural := 64;
g_symbol_w : natural := 8;
g_empty : natural := 6; -- number of empty symbols in header when g_symbol_w < g_data_w, must be < c_nof_symbols_per_data
g_pkt_len : natural := 240;
g_pkt_gap : natural := 16
);
end tb_eth_ip_header_checksum;
architecture tb of tb_eth_ip_header_checksum is
constant c_mm_clk_period : time := 1 ns;
constant c_dp_clk_period : time := 5 ns;
-- Simulate header / payload boundary at g_data_w boundary or at g_symbol_w
-- boundary with one empty symbol, by adapting the size of the header dp_bsn
-- field:
-- . If g_symbol_w = g_data_w then boundary is at g_data_w, so empty is 0.
-- . If g_symbol_w < g_data_w then boundary is at last symbol, so empty is 1.
constant c_nof_symbols_per_data : natural := g_data_w / g_symbol_w;
constant c_nof_symbols_per_bsn : natural := c_dp_stream_bsn_w / g_symbol_w; -- = 64 / g_symbol_w
constant c_bsn_w : natural := sel_a_b(c_nof_symbols_per_data = 1,
g_symbol_w * c_nof_symbols_per_bsn,
g_symbol_w * (c_nof_symbols_per_bsn - g_empty));
constant c_use_shortened_header : boolean := c_bsn_w <= c_word_w;
-- dp_stream_stimuli
constant c_stimuli_pulse_active : natural := 3;
constant c_stimuli_pulse_period : natural := 4;
-- dp_stream_verify
constant c_verify_pulse_active : natural := 1;
constant c_verify_pulse_period : natural := 5;
constant c_data_max : unsigned(g_data_w - 1 downto 0) := (others => '1');
constant c_dsp_max : unsigned(g_data_w - 1 downto 0) := (others => '1');
constant c_verify_snk_in_cnt_max : t_dp_sosi_unsigned := TO_DP_SOSI_UNSIGNED('0', '0', '0', '0', c_data_max, c_dsp_max, c_dsp_max, c_unsigned_0, c_unsigned_0, c_unsigned_0, c_unsigned_0);
constant c_verify_snk_in_cnt_gap : t_dp_sosi_unsigned := c_dp_sosi_unsigned_ones; -- default only accept increment +1
constant c_expected_pkt_len : natural := g_pkt_len;
constant c_sync_period : natural := 5;
constant c_sync_offset : natural := 2;
constant c_data_init : natural := 17;
constant c_bsn_init : std_logic_vector(c_dp_stream_bsn_w - 1 downto 0) := TO_DP_BSN(0);
constant c_nof_sync : natural := 3;
constant c_nof_packets : natural := c_sync_period * c_nof_sync;
constant c_hdr_len : natural := ceil_div(448, g_data_w);
constant c_wait_last_evt : natural := 100 + c_nof_packets * c_hdr_len;
-----------------------------------------------------------------------------
-- Tx offload
-----------------------------------------------------------------------------
-- From apertif_udp_offload_pkg.vhd:
constant c_udp_offload_nof_hdr_fields : natural := 3 + 12 + 4 + 3; -- 22, 448b; 7 64b words
constant c_udp_offload_nof_hdr_words_default : natural := 26; -- 23 single word + 3 double word = 26 32b words
constant c_udp_offload_nof_hdr_words_shortened : natural := c_udp_offload_nof_hdr_words_default - 1;
constant c_udp_offload_nof_hdr_words : natural := sel_a_b(c_use_shortened_header, c_udp_offload_nof_hdr_words_shortened, c_udp_offload_nof_hdr_words_default);
-- Notes:
-- . pre-calculated ip_header_checksum is valid only for UNB0, FN0 targeting IP 10.10.10.10
-- . udp_total_length = 176 beamlets * 64b / 8b = 1408B + 14 DP bytes + 8 UDP bytes = 1430B
constant c_udp_offload_hdr_field_arr : t_common_field_arr(c_udp_offload_nof_hdr_fields - 1 downto 0) := ( -- index
( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"001B214368AC") ), -- 21
( field_name_pad("eth_src_mac" ), "RW", 48, field_default(x"0123456789AB") ), -- 20
( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), -- 19
( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), -- 18
( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), -- 17
( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), -- 16
( field_name_pad("ip_total_length" ), "RW", 16, field_default(1450) ), -- 15
( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), -- 14
( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), -- 13
( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), -- 12
( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), -- 11
( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), -- 10
( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), -- 9, will be calculated by DUT
( field_name_pad("ip_src_addr" ), "RW", 32, field_default(x"C0A80009") ), -- 8
( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(x"C0A80001") ), -- 7
( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), -- 6
( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- 5
( field_name_pad("udp_total_length" ), "RW", 16, field_default(1430) ), -- 4
( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), -- 3
( field_name_pad("dp_reserved" ), "RW", 47, field_default(x"010203040506") ), -- 2
( field_name_pad("dp_sync" ), "RW", 1, field_default(0) ), -- 1
( field_name_pad("dp_bsn" ), "RW", c_bsn_w, field_default(0) ) ); -- 0
-- TX: Corresponding storage of c_udp_offload_hdr_field_arr in MM register words
-- . Note: It appears that the tx_hdr_word read values are the MM write values, so read of value from logic fields (with MM override '0', e.g. dp_bsn, eth_src_mac) is not supported.
constant c_expected_tx_hdr_word_arr_default : t_slv_32_arr(0 to c_udp_offload_nof_hdr_words_default - 1) := ( -- word address
X"00000000", -- 0 = dp_bsn[31:0] -- readback is MM value, not the logic value
X"00000000", -- 1 = dp_bsn[c_bsn_w-1:32]
X"00000000", -- 2 = dp_sync
X"03040506", -- 3 = dp_reserved[31:0]
X"00000102", -- 4 = dp_reserved[47:32]
X"00000000", -- 5 = udp_checksum
X"00000596", -- 6 = udp_total_length
X"00000000", -- 7 = udp_dst_port
X"00000000", -- 8 = udp_src_port -- readback is MM value, not the logic value
X"C0A80001", -- 9 = ip_dst_addr
X"C0A80009", -- 10 = ip_src_addr
X"00000000", -- 11 = ip_header_checksum
X"00000011", -- 12 = ip_protocol
X"0000007F", -- 13 = ip_time_to_live
X"00000000", -- 14 = ip_fragment_offset
X"00000002", -- 15 = ip_flags
X"00000000", -- 16 = ip_identification
X"000005AA", -- 17 = ip_total_length
X"00000000", -- 18 = ip_services
X"00000005", -- 19 = ip_header_length
X"00000004", -- 20 = ip_version
X"00000800", -- 21 = eth_type[15:0]
X"456789AB", -- 22 = eth_src_mac[31:0] -- readback is MM value, not the logic value
X"00000123", -- 23 = eth_src_mac[47:32]
X"214368AC", -- 24 = eth_dst_mac[31:0]
X"0000001B"); -- 25 = eth_dst_mac[47:32]
constant c_expected_tx_hdr_word_arr_shortened : t_slv_32_arr(0 to c_udp_offload_nof_hdr_words_shortened - 1) := ( -- word address
X"00000000", -- 0 = dp_bsn[c_bsn_w-1:0] -- readback is MM value, not the logic value
X"00000000", -- 1 = dp_sync
X"03040506", -- 2 = dp_reserved[31:0]
X"00000102", -- 3 = dp_reserved[47:32]
X"00000000", -- 4 = udp_checksum
X"00000596", -- 5 = udp_total_length
X"00000000", -- 6 = udp_dst_port
X"00000000", -- 7 = udp_src_port -- readback is MM value, not the logic value
X"C0A80001", -- 8 = ip_dst_addr
X"C0A80009", -- 9 = ip_src_addr
X"00000000", -- 10 = ip_header_checksum
X"00000011", -- 11 = ip_protocol
X"0000007F", -- 12 = ip_time_to_live
X"00000000", -- 13 = ip_fragment_offset
X"00000002", -- 14 = ip_flags
X"00000000", -- 15 = ip_identification
X"000005AA", -- 16 = ip_total_length
X"00000000", -- 17 = ip_services
X"00000005", -- 18 = ip_header_length
X"00000004", -- 19 = ip_version
X"00000800", -- 20 = eth_type[15:0]
X"456789AB", -- 21 = eth_src_mac[31:0] -- readback is MM value, not the logic value
X"00000123", -- 22 = eth_src_mac[47:32]
X"214368AC", -- 23 = eth_dst_mac[31:0]
X"0000001B"); -- 24 = eth_dst_mac[47:32]
-- RX: Corresponding storage of c_udp_offload_hdr_field_arr in MM register words
constant c_expected_rx_hdr_word_arr_default : t_slv_32_arr(0 to c_udp_offload_nof_hdr_words_default - 1) := ( -- word address
X"00000002", -- 0 = dp_bsn[31:0] -- dynamic value obtained from simulation
X"00000000", -- 1 = dp_bsn[c_bsn_w-1:32]
X"00000001", -- 2 = dp_sync -- dynamic value obtained from simulation
X"03040506", -- 3 = dp_reserved[31:0]
X"00000102", -- 4 = dp_reserved[47:32]
X"00000000", -- 5 = udp_checksum
X"00000596", -- 6 = udp_total_length
X"00000000", -- 7 = udp_dst_port
X"00000000", -- 8 = udp_src_port
X"C0A80001", -- 9 = ip_dst_addr
X"C0A80009", -- 10 = ip_src_addr
X"000074E8", -- 11 = ip_header_checksum
X"00000011", -- 12 = ip_protocol
X"0000007F", -- 13 = ip_time_to_live
X"00000000", -- 14 = ip_fragment_offset
X"00000002", -- 15 = ip_flags
X"00000000", -- 16 = ip_identification
X"000005AA", -- 17 = ip_total_length
X"00000000", -- 18 = ip_services
X"00000005", -- 19 = ip_header_length
X"00000004", -- 20 = ip_version
X"00000800", -- 21 = eth_type[15:0]
X"86080000", -- 22 = eth_src_mac[31:0] -- readback is the logic value x"00228608" & id_backplane = 0 & id_chip = 0 (c_NODE_ID = 0)
X"00000022", -- 23 = eth_src_mac[47:32]
X"214368AC", -- 24 = eth_dst_mac[31:0]
X"0000001B"); -- 25 = eth_dst_mac[47:32]
constant c_expected_rx_hdr_word_arr_shortened : t_slv_32_arr(0 to c_udp_offload_nof_hdr_words_shortened - 1) := ( -- word address
X"00000002", -- 0 = dp_bsn[c_bsn_w-1:0] -- dynamic value obtained from simulation
X"00000001", -- 1 = dp_sync -- dynamic value obtained from simulation
X"03040506", -- 2 = dp_reserved[31:0]
X"00000102", -- 3 = dp_reserved[47:32]
X"00000000", -- 4 = udp_checksum
X"00000596", -- 5 = udp_total_length
X"00000000", -- 6 = udp_dst_port
X"00000000", -- 7 = udp_src_port
X"C0A80001", -- 8 = ip_dst_addr
X"C0A80009", -- 9 = ip_src_addr
X"000074E8", -- 10 = ip_header_checksum
X"00000011", -- 11 = ip_protocol
X"0000007F", -- 12 = ip_time_to_live
X"00000000", -- 13 = ip_fragment_offset
X"00000002", -- 14 = ip_flags
X"00000000", -- 15 = ip_identification
X"000005AA", -- 16 = ip_total_length
X"00000000", -- 17 = ip_services
X"00000005", -- 18 = ip_header_length
X"00000004", -- 19 = ip_version
X"00000800", -- 20 = eth_type[15:0]
X"86080000", -- 21 = eth_src_mac[31:0] -- readback is the logic value x"00228608" & id_backplane = 0 & id_chip = 0 (c_NODE_ID = 0)
X"00000022", -- 22 = eth_src_mac[47:32]
X"214368AC", -- 23 = eth_dst_mac[31:0]
X"0000001B"); -- 24 = eth_dst_mac[47:32]
-- Override ('1') only the Ethernet fields so we can use MM defaults there
constant c_hdr_field_ovr_init : std_logic_vector(c_udp_offload_nof_hdr_fields - 1 downto 0) := "101" & "111111111111" & "1111" & "100";
constant c_NODE_ID : std_logic_vector(7 downto 0) := TO_UVEC(0, 8);
signal id_backplane : std_logic_vector(c_byte_w - 1 downto 0);
signal id_chip : std_logic_vector(c_byte_w - 1 downto 0);
signal dp_fifo_sc_src_in : t_dp_siso := c_dp_siso_rdy;
signal dp_fifo_sc_src_out : t_dp_sosi;
signal dp_offload_tx_snk_in_arr : t_dp_sosi_arr(0 downto 0);
signal dp_offload_tx_snk_out_arr : t_dp_siso_arr(0 downto 0);
signal tx_hdr_fields_in_arr : t_slv_1024_arr(0 downto 0);
signal tx_hdr_fields_out_arr : t_slv_1024_arr(0 downto 0);
signal tx_hdr_word : std_logic_vector(c_word_w - 1 downto 0);
signal rx_hdr_word : std_logic_vector(c_word_w - 1 downto 0);
signal reg_dp_offload_tx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst;
signal reg_dp_offload_tx_hdr_dat_miso : t_mem_miso;
-----------------------------------------------------------------------------
-- Link
-----------------------------------------------------------------------------
signal tx_offload_sosi_arr : t_dp_sosi_arr(0 downto 0);
signal tx_offload_siso_arr : t_dp_siso_arr(0 downto 0);
signal link_offload_sosi_arr : t_dp_sosi_arr(0 downto 0);
signal link_offload_siso_arr : t_dp_siso_arr(0 downto 0);
-----------------------------------------------------------------------------
-- Rx offload
-----------------------------------------------------------------------------
signal dp_offload_rx_src_out_arr : t_dp_sosi_arr(0 downto 0);
signal dp_offload_rx_src_in_arr : t_dp_siso_arr(0 downto 0);
signal rx_hdr_fields_out_arr : t_slv_1024_arr(0 downto 0);
signal rx_hdr_fields_raw_arr : t_slv_1024_arr(0 downto 0);
signal reg_dp_offload_rx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst;
signal reg_dp_offload_rx_hdr_dat_miso : t_mem_miso;
-----------------------------------------------------------------------------
-- Test
-----------------------------------------------------------------------------
signal mm_clk : std_logic := '1';
signal mm_rst : std_logic := '1';
signal dp_clk : std_logic := '1';
signal dp_rst : std_logic := '1';
signal tb_end : std_logic := '0';
signal stimuli_src_in : t_dp_siso := c_dp_siso_rdy;
signal stimuli_src_out : t_dp_sosi;
signal stimuli_src_out_data : std_logic_vector(g_data_w - 1 downto 0);
signal verify_snk_in_enable : t_dp_sosi_sl := c_dp_sosi_sl_rst;
signal last_snk_in : t_dp_sosi;
signal last_snk_in_evt : std_logic;
signal verify_last_snk_in_evt : t_dp_sosi_sl := c_dp_sosi_sl_rst;
signal verify_snk_out : t_dp_siso := c_dp_siso_rdy;
signal verify_snk_in : t_dp_sosi;
signal verify_snk_in_data : std_logic_vector(g_data_w - 1 downto 0);
signal prev_verify_snk_in_data : std_logic_vector(g_data_w - 1 downto 0);
begin
------------------------------------------------------------------------------
-- Clock & reset
------------------------------------------------------------------------------
mm_clk <= (not mm_clk) or tb_end after c_mm_clk_period / 2;
mm_rst <= '1', '0' after c_mm_clk_period * 7;
dp_clk <= (not dp_clk) or tb_end after c_dp_clk_period / 2;
dp_rst <= '1', '0' after c_dp_clk_period * 7;
------------------------------------------------------------------------------
-- DATA GENERATION
------------------------------------------------------------------------------
u_dp_stream_stimuli : entity dp_lib.dp_stream_stimuli
generic map (
g_instance_nr => 0, -- only one stream so choose index 0
-- flow control
g_random_w => 15, -- use different random width for stimuli and for verify to have different random sequences
g_pulse_active => c_stimuli_pulse_active,
g_pulse_period => c_stimuli_pulse_period,
g_flow_control => g_flow_control_stimuli, -- always active, random or pulse flow control
-- initializations
g_sync_period => c_sync_period,
g_sync_offset => c_sync_offset,
g_data_init => c_data_init,
g_bsn_init => c_bsn_init,
-- specific
g_in_dat_w => g_data_w,
g_nof_repeat => c_nof_packets,
g_pkt_len => g_pkt_len,
g_pkt_gap => g_pkt_gap,
g_wait_last_evt => c_wait_last_evt
)
port map (
rst => dp_rst,
clk => dp_clk,
-- Generate stimuli
src_in => stimuli_src_in,
src_out => stimuli_src_out,
-- End of stimuli
last_snk_in => last_snk_in, -- expected verify_snk_in after end of stimuli
last_snk_in_evt => last_snk_in_evt, -- trigger verify to verify the last_snk_in
tb_end => tb_end -- signal end of tb as far as this dp_stream_stimuli is concerned
);
------------------------------------------------------------------------------
-- DATA VERIFICATION
------------------------------------------------------------------------------
-- Select fields that need to be verified
-- . during the test
verify_snk_in_enable.sync <= '1';
verify_snk_in_enable.bsn <= '1';
verify_snk_in_enable.data <= '1';
verify_snk_in_enable.re <= '0';
verify_snk_in_enable.im <= '0';
verify_snk_in_enable.valid <= '1';
verify_snk_in_enable.sop <= '1';
verify_snk_in_enable.eop <= '1';
verify_snk_in_enable.empty <= '0';
verify_snk_in_enable.channel <= '0';
verify_snk_in_enable.err <= '0';
-- . after the test
verify_last_snk_in_evt.sync <= last_snk_in_evt;
verify_last_snk_in_evt.bsn <= last_snk_in_evt; -- thanks to using rx_hdr_fields_raw_arr for bsn field
verify_last_snk_in_evt.data <= last_snk_in_evt;
verify_last_snk_in_evt.re <= '0';
verify_last_snk_in_evt.im <= '0';
verify_last_snk_in_evt.valid <= last_snk_in_evt;
verify_last_snk_in_evt.sop <= last_snk_in_evt;
verify_last_snk_in_evt.eop <= last_snk_in_evt;
verify_last_snk_in_evt.empty <= '0';
verify_last_snk_in_evt.channel <= '0';
verify_last_snk_in_evt.err <= '0';
u_dp_stream_verify : entity dp_lib.dp_stream_verify
generic map (
g_instance_nr => 0, -- only one stream so choose index 0
-- flow control
g_random_w => 14, -- use different random width for stimuli and for verify to have different random sequences
g_pulse_active => c_verify_pulse_active,
g_pulse_period => c_verify_pulse_period,
g_flow_control => g_flow_control_verify, -- always active, random or pulse flow control
-- initializations
g_sync_period => c_sync_period,
g_sync_offset => c_sync_offset,
g_snk_in_cnt_max => c_verify_snk_in_cnt_max,
g_snk_in_cnt_gap => c_verify_snk_in_cnt_gap,
-- specific
g_in_dat_w => g_data_w,
g_pkt_len => c_expected_pkt_len
)
port map (
rst => dp_rst,
clk => dp_clk,
-- Verify data
snk_out => verify_snk_out,
snk_in => verify_snk_in,
-- During stimuli
verify_snk_in_enable => verify_snk_in_enable, -- enable verify to verify that the verify_snk_in fields are incrementing
-- End of stimuli
expected_snk_in => last_snk_in, -- expected verify_snk_in after end of stimuli
verify_expected_snk_in_evt => verify_last_snk_in_evt -- trigger verify to verify the last_snk_in
);
------------------------------------------------------------------------------
-- offload Tx
------------------------------------------------------------------------------
stimuli_src_in <= c_dp_siso_rdy;
-- Use FIFO to handle backpressure just like in a network design.
u_dp_fifo_sc : entity dp_lib.dp_fifo_sc
generic map (
g_data_w => g_data_w,
g_bsn_w => 64,
g_use_sync => true,
g_use_bsn => true,
g_fifo_size => 1024
)
port map (
rst => dp_rst,
clk => dp_clk,
snk_out => OPEN, -- stimuli_src_in
snk_in => stimuli_src_out,
src_in => dp_fifo_sc_src_in,
src_out => dp_fifo_sc_src_out
);
dp_offload_tx_snk_in_arr(0) <= dp_fifo_sc_src_out;
dp_fifo_sc_src_in <= dp_offload_tx_snk_out_arr(0);
-- Extract the chip and backplane numbers from c_NODE_ID
id_backplane <= RESIZE_UVEC(c_NODE_ID(7 downto 3), c_byte_w);
id_chip <= RESIZE_UVEC(c_NODE_ID(2 downto 0), c_byte_w);
-- Wire the hardwired header fields to DP signals and c_NODE_ID
tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "eth_src_mac" ) downto field_lo(c_udp_offload_hdr_field_arr, "eth_src_mac" )) <= x"00228608" & id_backplane & id_chip;
tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "udp_src_port") downto field_lo(c_udp_offload_hdr_field_arr, "udp_src_port" )) <= x"D0" & c_NODE_ID;
tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "udp_dst_port") downto field_lo(c_udp_offload_hdr_field_arr, "udp_dst_port" )) <= x"D0" & c_NODE_ID;
tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "ip_src_addr" ) downto field_lo(c_udp_offload_hdr_field_arr, "ip_src_addr" )) <= x"0A63" & id_backplane & INCR_UVEC(id_chip, 1);
tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_sync" ) downto field_lo(c_udp_offload_hdr_field_arr, "dp_sync" )) <= slv(dp_offload_tx_snk_in_arr(0).sync);
tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_bsn" ) downto field_lo(c_udp_offload_hdr_field_arr, "dp_bsn" )) <= dp_offload_tx_snk_in_arr(0).bsn(c_bsn_w - 1 downto 0);
u_tx : entity dp_lib.dp_offload_tx_v3
generic map (
g_nof_streams => 1,
g_data_w => g_data_w,
g_symbol_w => g_symbol_w,
g_hdr_field_arr => c_udp_offload_hdr_field_arr,
g_hdr_field_sel => c_hdr_field_ovr_init
)
port map (
mm_rst => mm_rst,
mm_clk => mm_clk,
dp_rst => dp_rst,
dp_clk => dp_clk,
reg_hdr_dat_mosi => reg_dp_offload_tx_hdr_dat_mosi,
reg_hdr_dat_miso => reg_dp_offload_tx_hdr_dat_miso,
snk_in_arr => dp_offload_tx_snk_in_arr,
snk_out_arr => dp_offload_tx_snk_out_arr,
src_out_arr => tx_offload_sosi_arr,
src_in_arr => tx_offload_siso_arr,
hdr_fields_in_arr => tx_hdr_fields_in_arr,
hdr_fields_out_arr => tx_hdr_fields_out_arr
);
------------------------------------------------------------------------------
-- DUT: IP header CRC checksum
------------------------------------------------------------------------------
u_dut : entity work.eth_ip_header_checksum
generic map (
g_data_w => g_data_w,
g_hdr_field_arr => c_udp_offload_hdr_field_arr
)
port map (
rst => dp_rst,
clk => dp_clk,
src_out => link_offload_sosi_arr(0),
snk_in => tx_offload_sosi_arr(0),
src_in => link_offload_siso_arr(0),
snk_out => tx_offload_siso_arr(0),
hdr_fields_slv_in => tx_hdr_fields_out_arr(0)
);
p_rd_tx_hdr_words : process
variable v_word : std_logic_vector(c_word_w - 1 downto 0);
begin
proc_common_wait_until_hi_lo(dp_clk, tx_offload_sosi_arr(0).sync);
print_str("", g_print_en);
for I in 0 to c_udp_offload_nof_hdr_words - 1 loop
proc_mem_mm_bus_rd(I, mm_clk, reg_dp_offload_tx_hdr_dat_mosi);
proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
v_word := reg_dp_offload_tx_hdr_dat_miso.rddata(31 downto 0);
-- Log word in transcript window
print_str("tx_hdr_word(" & int_to_str(I) & ") = " & slv_to_hex(v_word), g_print_en);
-- View word in wave window
tx_hdr_word <= v_word;
-- Verify expected word
if c_use_shortened_header then
assert c_expected_tx_hdr_word_arr_shortened(I) = v_word report "Unexpected tx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_tx_hdr_word_arr_shortened(I)) severity ERROR;
else
assert c_expected_tx_hdr_word_arr_default(I) = v_word report "Unexpected tx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_tx_hdr_word_arr_default(I)) severity ERROR;
end if;
end loop;
print_str("", g_print_en);
wait;
end process;
------------------------------------------------------------------------------
-- offload Rx
------------------------------------------------------------------------------
u_rx : entity dp_lib.dp_offload_rx
generic map (
g_nof_streams => 1,
g_data_w => g_data_w,
g_symbol_w => g_symbol_w,
g_hdr_field_arr => c_udp_offload_hdr_field_arr,
g_remove_crc => false,
g_crc_nof_words => 0
)
port map (
mm_rst => mm_rst,
mm_clk => mm_clk,
dp_rst => dp_rst,
dp_clk => dp_clk,
reg_hdr_dat_mosi => reg_dp_offload_rx_hdr_dat_mosi,
reg_hdr_dat_miso => reg_dp_offload_rx_hdr_dat_miso,
snk_in_arr => link_offload_sosi_arr,
snk_out_arr => link_offload_siso_arr,
src_out_arr => dp_offload_rx_src_out_arr,
src_in_arr => dp_offload_rx_src_in_arr,
hdr_fields_out_arr => rx_hdr_fields_out_arr,
hdr_fields_raw_arr => rx_hdr_fields_raw_arr
);
p_restore_sync_bsn : process(dp_offload_rx_src_out_arr, rx_hdr_fields_out_arr)
begin
verify_snk_in <= dp_offload_rx_src_out_arr(0);
verify_snk_in.sync <= sl(rx_hdr_fields_out_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_sync") downto field_lo(c_udp_offload_hdr_field_arr, "dp_sync" )));
verify_snk_in.bsn <= RESIZE_UVEC(rx_hdr_fields_raw_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_bsn" ) downto field_lo(c_udp_offload_hdr_field_arr, "dp_bsn" )), c_dp_stream_bsn_w);
end process;
dp_offload_rx_src_in_arr <= (others => c_dp_siso_rdy);
dp_offload_rx_src_in_arr(0) <= verify_snk_out;
p_rd_rx_hdr_words : process
variable v_word : std_logic_vector(c_word_w - 1 downto 0);
begin
proc_common_wait_until_hi_lo(dp_clk, verify_snk_in.sync);
-- Check first packet after sync with dp_sync = 1
-- wait some latency until header fields of this sync packet are available via MM
proc_common_wait_some_cycles(dp_clk, c_hdr_len + 10);
print_str("", g_print_en);
for I in 0 to c_udp_offload_nof_hdr_words - 1 loop
proc_mem_mm_bus_rd(I, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
v_word := reg_dp_offload_rx_hdr_dat_miso.rddata(31 downto 0);
-- Log word in transcript window
print_str("rx_hdr_word(" & int_to_str(I) & ") : " & slv_to_hex(v_word), g_print_en);
-- View word in wave window
rx_hdr_word <= v_word;
-- Verify expected word
if c_use_shortened_header then
assert v_word = c_expected_rx_hdr_word_arr_shortened(I) report "Unexpected rx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_rx_hdr_word_arr_shortened(I)) severity ERROR;
else
assert v_word = c_expected_rx_hdr_word_arr_default(I) report "Unexpected rx_hdr_word at address " & int_to_str(I) & ", expected " & slv_to_hex(c_expected_rx_hdr_word_arr_default(I)) severity ERROR;
end if;
end loop;
print_str("", g_print_en);
-- Check dp_bsn and dp_sync of second packet after sync with dp_sync = 0
proc_common_wait_until_hi_lo(dp_clk, verify_snk_in.sop);
-- wait some latency until header fields of this sync packet are available via MM
proc_common_wait_some_cycles(dp_clk, c_hdr_len + 5);
-- dp_bsn lo
proc_mem_mm_bus_rd(0, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
v_word := reg_dp_offload_rx_hdr_dat_miso.rddata(31 downto 0);
rx_hdr_word <= v_word; -- View word in wave window
if c_use_shortened_header then
assert v_word = INCR_UVEC(c_expected_rx_hdr_word_arr_shortened(0), 1) report "Unexpected dp_bsn from MM" severity ERROR;
else
assert v_word = INCR_UVEC(c_expected_rx_hdr_word_arr_default(0), 1) report "Unexpected dp_bsn from MM" severity ERROR;
end if;
-- dp_sync
if c_use_shortened_header then
proc_mem_mm_bus_rd(1, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
else
proc_mem_mm_bus_rd(2, mm_clk, reg_dp_offload_rx_hdr_dat_mosi);
end if;
proc_mem_mm_bus_rd_latency(c_mem_reg_rd_latency, mm_clk);
v_word := reg_dp_offload_rx_hdr_dat_miso.rddata(31 downto 0);
rx_hdr_word <= v_word; -- View word in wave window
assert v_word = TO_UVEC(0, 32) report "Unexpected dp_sync from MM" severity ERROR;
wait;
end process;
------------------------------------------------------------------------------
-- Auxiliary
------------------------------------------------------------------------------
-- Map to slv to ease monitoring in wave window
stimuli_src_out_data <= stimuli_src_out.data(g_data_w - 1 downto 0);
verify_snk_in_data <= verify_snk_in.data(g_data_w - 1 downto 0);
end tb;
-- --------------------------------------------------------------------------
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- --------------------------------------------------------------------------
--
-- Author: R. vd Walle
-- Purpose: Regression multi tb for eth_ip_header_checksum
-- Description:
-- Usage:
-- > as 4
-- > run -all
library IEEE, dp_lib;
use IEEE.std_logic_1164.all;
use dp_lib.tb_dp_pkg.all; -- for t_dp_flow_control_enum
entity tb_tb_eth_ip_header_checksum is
end tb_tb_eth_ip_header_checksum;
architecture tb of tb_tb_eth_ip_header_checksum is
signal tb_end : std_logic := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
begin
-- -- general
-- g_flow_control_stimuli : t_dp_flow_control_enum := e_pulse; -- always e_active, e_random or e_pulse flow control
-- g_flow_control_verify : t_dp_flow_control_enum := e_active; -- always e_active, e_random or e_pulse flow control
-- g_print_en : BOOLEAN := TRUE;
-- -- specific
-- g_data_w : NATURAL := 64;
-- g_symbol_w : NATURAL := 16;
-- g_empty : NATURAL := 6; -- number of empty symbols in header when g_symbol_w < g_data_w, must be < c_nof_symbols_per_data
-- g_pkt_len : NATURAL := 240;
-- g_pkt_gap : NATURAL := 16
u_pls_act_data_w_256 : entity work.tb_eth_ip_header_checksum generic map (e_pulse, e_active, false, 256, 64, 0, 240, 16);
u_act_act_data_w_512_no_gap : entity work.tb_eth_ip_header_checksum generic map (e_active, e_active, false, 512, 8, 0, 240, 0);
u_pls_act_data_w_64_no_gap : entity work.tb_eth_ip_header_checksum generic map (e_pulse, e_active, false, 64, 64, 0, 240, 0);
u_rnd_act_data_w_32 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 32, 8, 0, 240, 16);
u_rnd_act_data_w_8 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 8, 8, 0, 240, 16);
--u_act_rnd_data_w : ENTITY work.tb_eth_ip_header_checksum GENERIC MAP (e_active, e_random, FALSE, 64, 64, 0, 240, 16); -- dp_offload_rx requires e_active
u_rnd_act_data_64_symbol_8_empty_1 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 64, 8, 1, 240, 16);
u_rnd_act_data_64_symbol_8_empty_6 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 64, 8, 6, 240, 16);
u_rnd_act_data_64_symbol_16 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 64, 16, 1, 240, 16);
u_rnd_act_data_64_symbol_32 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 64, 32, 1, 240, 16);
u_rnd_act_data_32_symbol_8 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 32, 8, 1, 240, 16);
u_rnd_act_data_32_symbol_16 : entity work.tb_eth_ip_header_checksum generic map (e_random, e_active, false, 32, 16, 1, 240, 16);
end tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment