From 57cb9ba908bcd5351d2f739d40e8b5061627e1ae Mon Sep 17 00:00:00 2001 From: Eric Kooistra <kooistra@astron.nl> Date: Mon, 21 Nov 2022 15:50:06 +0100 Subject: [PATCH] Add eth_stream.vhd with test benches. --- libraries/io/eth/hdllib.cfg | 4 + libraries/io/eth/src/vhdl/eth_stream.vhd | 185 ++++++++ libraries/io/eth/tb/vhdl/tb_eth_stream.vhd | 436 ++++++++++++++++++ libraries/io/eth/tb/vhdl/tb_tb_eth_stream.vhd | 80 ++++ 4 files changed, 705 insertions(+) create mode 100644 libraries/io/eth/src/vhdl/eth_stream.vhd create mode 100644 libraries/io/eth/tb/vhdl/tb_eth_stream.vhd create mode 100644 libraries/io/eth/tb/vhdl/tb_tb_eth_stream.vhd diff --git a/libraries/io/eth/hdllib.cfg b/libraries/io/eth/hdllib.cfg index 11d97855c2..9a89f41a6d 100644 --- a/libraries/io/eth/hdllib.cfg +++ b/libraries/io/eth/hdllib.cfg @@ -22,6 +22,7 @@ synth_files = src/vhdl/eth_control.vhd src/vhdl/eth_ihl_to_20.vhd src/vhdl/eth.vhd + src/vhdl/eth_stream.vhd src/vhdl/eth_tester_pkg.vhd src/vhdl/eth_tester_tx.vhd src/vhdl/eth_tester_rx.vhd @@ -35,8 +36,10 @@ test_bench_files = tb/vhdl/tb_eth.vhd tb/vhdl/tb_eth_tester_pkg.vhd tb/vhdl/tb_eth_tester.vhd + tb/vhdl/tb_eth_stream.vhd tb/vhdl/tb_tb_eth.vhd tb/vhdl/tb_tb_eth_tester.vhd + tb/vhdl/tb_tb_eth_stream.vhd tb/vhdl/tb_eth_udp_offload.vhd tb/vhdl/tb_eth_ihl_to_20.vhd tb/vhdl/tb_tb_tb_eth_regression.vhd @@ -49,6 +52,7 @@ regression_test_vhdl = tb/vhdl/tb_eth_ihl_to_20.vhd tb/vhdl/tb_tb_eth.vhd tb/vhdl/tb_tb_eth_tester.vhd + tb/vhdl/tb_tb_eth_stream.vhd [modelsim_project_file] diff --git a/libraries/io/eth/src/vhdl/eth_stream.vhd b/libraries/io/eth/src/vhdl/eth_stream.vhd new file mode 100644 index 0000000000..8f3921ac2e --- /dev/null +++ b/libraries/io/eth/src/vhdl/eth_stream.vhd @@ -0,0 +1,185 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2022 +-- 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/>. +-- +------------------------------------------------------------------------------- + +-- Author: Eric Kooistra +-- Purpose: +-- Provide Ethernet access to a node for one UDP stream. +-- Description: +-- * This eth_stream.vhd is a stripped down version of eth.vhd. +-- * This eth_stream only contains the components that are needed to send or +-- receive an UDP stream via 1GbE. +-- The IP checksum is filled in for Tx and checked or Rx. +-- The Tx only contains UDP stream data, so no need for a dp_mux. +-- The Rx may contain other packet types, because the 1GbE connects to a +-- network. All Rx packets that are not UDP for g_rx_udp_port are discarded. +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + +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 work.eth_pkg.ALL; + +ENTITY eth_stream IS + GENERIC ( + g_rx_udp_port : NATURAL + ); + PORT ( + -- Clocks and reset + st_rst : IN STD_LOGIC; + st_clk : IN STD_LOGIC; + + -- User UDP interface + -- . Tx + udp_tx_sosi : IN t_dp_sosi; + udp_tx_siso : OUT t_dp_siso; + -- . Rx + udp_rx_sosi : OUT t_dp_sosi; + udp_rx_siso : IN t_dp_siso := c_dp_siso_rdy; + + -- PHY interface + -- . Tx + tse_tx_sosi : OUT t_dp_sosi; + tse_tx_siso : IN t_dp_siso; + -- . Rx + tse_rx_sosi : IN t_dp_sosi; + tse_rx_siso : OUT t_dp_siso + ); +END eth_stream; + + +ARCHITECTURE str OF eth_stream IS + + -- ETH Tx + SIGNAL eth_tx_siso : t_dp_siso; + SIGNAL eth_tx_sosi : t_dp_sosi; + + -- ETH Rx + SIGNAL rx_adapt_siso : t_dp_siso; + SIGNAL rx_adapt_sosi : t_dp_sosi; + + SIGNAL rx_hdr_status : t_eth_hdr_status; + SIGNAL rx_hdr_status_complete : STD_LOGIC; + + SIGNAL rx_eth_discard : STD_LOGIC; + SIGNAL rx_eth_discard_val : STD_LOGIC; + +BEGIN + + ------------------------------------------------------------------------------ + -- TX + ------------------------------------------------------------------------------ + + -- Insert IP header checksum + u_tx_ip : ENTITY work.eth_hdr + GENERIC MAP ( + g_header_store_and_forward => TRUE, + g_ip_header_checksum_calculate => TRUE + ) + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => udp_tx_sosi, + snk_out => udp_tx_siso, + + -- Streaming Source + src_in => tse_tx_siso, + src_out => tse_tx_sosi -- with err field value 0 for OK + ); + + ------------------------------------------------------------------------------ + -- RX + ------------------------------------------------------------------------------ + + -- Adapt the TSE RX source ready latency from 2 to 1 + u_adapt : ENTITY dp_lib.dp_latency_adapter + GENERIC MAP ( + g_in_latency => c_eth_rx_ready_latency, -- = 2 + g_out_latency => c_eth_ready_latency -- = 1 + ) + PORT MAP ( + rst => st_rst, + clk => st_clk, + -- ST sink + snk_out => tse_rx_siso, + snk_in => tse_rx_sosi, + -- ST source + src_in => rx_adapt_siso, + src_out => rx_adapt_sosi + ); + + -- Pass on UDP stream for g_rx_udp_port + -- . Verify IP header checksum for IP + u_rx_udp : ENTITY work.eth_hdr + GENERIC MAP ( + g_header_store_and_forward => TRUE, + g_ip_header_checksum_calculate => TRUE + ) + PORT MAP ( + -- Clocks and reset + rst => st_rst, + clk => st_clk, + + -- Streaming Sink + snk_in => rx_adapt_sosi, + snk_out => rx_adapt_siso, + + -- Streaming Source + src_in => udp_rx_siso, + src_out => udp_rx_sosi, + + -- Frame control + frm_discard => rx_eth_discard, + frm_discard_val => rx_eth_discard_val, + + -- Header info + hdr_status => rx_hdr_status, + hdr_status_complete => rx_hdr_status_complete + ); + + -- Discard all Rx data that is not UDP for g_rx_udp_port + p_rx_discard : PROCESS(st_rst, st_clk) + BEGIN + IF st_rst = '1' THEN + rx_eth_discard <= '1'; -- default discard + rx_eth_discard_val <= '0'; + ELSIF rising_edge(st_clk) THEN + -- Default keep rx_eth_discard status (instead of '1'), to more clearly + -- see when a change occurs + IF rx_hdr_status_complete = '1' THEN + rx_eth_discard <= '1'; -- default discard + IF rx_hdr_status.is_ip = '1' AND + rx_hdr_status.is_udp = '1' AND + TO_UINT(rx_hdr_status.udp_port) = g_rx_udp_port THEN + rx_eth_discard <= '0'; -- pass on IP/UDP stream for g_rx_udp_port + END IF; + END IF; + + rx_eth_discard_val <= rx_hdr_status_complete; + END IF; + END PROCESS; + +END str; diff --git a/libraries/io/eth/tb/vhdl/tb_eth_stream.vhd b/libraries/io/eth/tb/vhdl/tb_eth_stream.vhd new file mode 100644 index 0000000000..0907bc0757 --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_eth_stream.vhd @@ -0,0 +1,436 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Test bench for eth_stream using eth_tester +-- Description: +-- Similar as tb_eth_tester.vhd, but for only one stream and using streaming +-- interface loop back. +-- +-- Usage: +-- > as 8 +-- > run -a +-- +-- References: +-- [1] https://support.astron.nl/confluence/display/L2M/L6+FWLIB+Design+Document%3A+ETH+tester+unit+for+1GbE + +LIBRARY IEEE, common_lib, dp_lib, diag_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 common_lib.common_str_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE diag_lib.diag_pkg.ALL; +USE work.eth_pkg.ALL; +USE work.eth_tester_pkg.ALL; +USE work.tb_eth_tester_pkg.ALL; + +ENTITY tb_eth_stream IS + GENERIC ( + g_tb_index : NATURAL := 0; -- use to incremental delay logging from tb instances in tb_tb + g_nof_sync : NATURAL := 2; -- number of BG sync intervals to set c_run_time + g_udp_port_match : BOOLEAN := TRUE; + + -- t_diag_block_gen_integer = + -- sl: enable + -- sl: enable_sync + -- nat: samples_per_packet + -- nat: blocks_per_sync + -- nat: gapsize + -- nat: mem_low_adrs + -- nat: mem_high_adrs + -- nat: bsn_init + g_bg_ctrl : t_diag_block_gen_integer := ('1', '1', 50, 3, 200, 0, c_diag_bg_mem_max_adr, 0) -- for first stream + ); +END tb_eth_stream; + + +ARCHITECTURE tb OF tb_eth_stream IS + + CONSTANT c_tb_str : STRING := "tb-" & NATURAL'IMAGE(g_tb_index) & " : "; -- use to distinguish logging from tb instances in tb_tb + CONSTANT mm_clk_period : TIME := 10 ns; -- 100 MHz + CONSTANT c_nof_st_clk_per_s : NATURAL := 200 * 10**6; + CONSTANT st_clk_period : TIME := (10**9 / c_nof_st_clk_per_s) * 1 ns; -- 5 ns, 200 MHz + + CONSTANT c_bg_block_len : NATURAL := g_bg_ctrl.samples_per_packet; + CONSTANT c_bg_slot_len : NATURAL := c_bg_block_len + g_bg_ctrl.gapsize; + CONSTANT c_eth_packet_len : NATURAL := func_eth_tester_eth_packet_length(c_bg_block_len); + + -- Use REAL to avoid NATURAL overflow in bps calculation + CONSTANT c_bg_nof_bps : REAL := REAL(c_bg_block_len * c_octet_w) * REAL(c_nof_st_clk_per_s) / REAL(c_bg_slot_len); + CONSTANT c_bg_sync_period : NATURAL := c_bg_slot_len * g_bg_ctrl.blocks_per_sync; + + CONSTANT c_run_time : NATURAL := g_nof_sync * c_bg_sync_period; + CONSTANT c_nof_sync : NATURAL := c_run_time / c_bg_sync_period; + + -- Destination UDP port + CONSTANT c_rx_udp_port : NATURAL := TO_UINT(c_eth_tester_udp_dst_port); + CONSTANT c_dst_udp_port : NATURAL := sel_a_b(g_udp_port_match, c_rx_udp_port, 17); + + -- Expected Tx --> Rx latency values obtained from a tb run + CONSTANT c_tx_exp_latency : NATURAL := 0; + CONSTANT c_rx_exp_latency_en : BOOLEAN := c_bg_block_len >= 50; + CONSTANT c_rx_exp_latency_st : NATURAL := sel_a_b(g_udp_port_match, 58, 0); + + CONSTANT c_nof_valid_per_packet : NATURAL := c_bg_block_len; + + CONSTANT c_total_count_nof_valid_per_sync : NATURAL := g_bg_ctrl.blocks_per_sync * c_nof_valid_per_packet; + + CONSTANT c_mon_nof_sop_tx : NATURAL := g_bg_ctrl.blocks_per_sync; + CONSTANT c_mon_nof_sop_rx : NATURAL := sel_a_b(g_udp_port_match, c_mon_nof_sop_tx, 0); + CONSTANT c_mon_nof_valid_tx : NATURAL := c_mon_nof_sop_tx * ceil_div(c_bg_block_len * c_octet_w, c_word_w); + CONSTANT c_mon_nof_valid_rx : NATURAL := c_mon_nof_sop_rx * c_nof_valid_per_packet; + + -- Use sim default src MAC, IP, UDP port from eth_tester_pkg.vhd and based on c_gn_index + CONSTANT c_gn_index : NATURAL := 17; -- global node index + CONSTANT c_gn_eth_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := c_eth_tester_eth_src_mac_47_16 & func_eth_tester_gn_index_to_mac_15_0(c_gn_index); + CONSTANT c_gn_ip_src_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := c_eth_tester_ip_src_addr_31_16 & func_eth_tester_gn_index_to_ip_15_0(c_gn_index); + CONSTANT c_gn_udp_src_port : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := c_eth_tester_udp_src_port_15_8 & TO_UVEC(c_gn_index, 8); + + -- Clocks and reset + SIGNAL mm_rst : STD_LOGIC := '1'; + SIGNAL mm_clk : STD_LOGIC := '1'; + SIGNAL st_rst : STD_LOGIC := '1'; + SIGNAL st_clk : STD_LOGIC := '1'; + SIGNAL st_pps : STD_LOGIC := '0'; + SIGNAL stimuli_end : STD_LOGIC := '0'; + SIGNAL tb_end : STD_LOGIC := '0'; + + SIGNAL tx_fifo_rd_emp : STD_LOGIC; + + -- ETH UDP data path interface + SIGNAL tx_udp_sosi : t_dp_sosi; + SIGNAL tx_udp_siso : t_dp_siso := c_dp_siso_rdy; + SIGNAL rx_udp_sosi : t_dp_sosi; + + -- MM interface + -- . Tx + SIGNAL reg_bg_ctrl_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_bg_ctrl_cipo : t_mem_cipo; + SIGNAL reg_hdr_dat_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_hdr_dat_cipo : t_mem_cipo; + SIGNAL reg_bsn_monitor_v2_tx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_bsn_monitor_v2_tx_cipo : t_mem_cipo; + SIGNAL reg_strobe_total_count_tx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_strobe_total_count_tx_cipo : t_mem_cipo; + -- . Rx + SIGNAL reg_bsn_monitor_v2_rx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_bsn_monitor_v2_rx_cipo : t_mem_cipo; + SIGNAL reg_strobe_total_count_rx_copi : t_mem_copi := c_mem_copi_rst; + SIGNAL reg_strobe_total_count_rx_cipo : t_mem_cipo; + + -- . reg_strobe_total_count + SIGNAL tx_total_count_nof_packet : NATURAL; + SIGNAL rx_total_count_nof_packet : NATURAL; + SIGNAL tx_exp_total_count_nof_packet : NATURAL; + SIGNAL rx_exp_total_count_nof_packet : NATURAL; + + SIGNAL rx_total_count_nof_valid : NATURAL; + SIGNAL rx_exp_total_count_nof_valid : NATURAL; + + -- . reg_bsn_monitor_v2 + SIGNAL tx_mon_nof_sop : NATURAL; + SIGNAL tx_mon_nof_valid : NATURAL; + SIGNAL tx_mon_latency : NATURAL; + SIGNAL rx_mon_nof_sop : NATURAL; + SIGNAL rx_mon_nof_valid : NATURAL; + SIGNAL rx_mon_latency : NATURAL; + + -- ETH stream + SIGNAL tse_tx_sosi : t_dp_sosi; + SIGNAL tse_tx_siso : t_dp_siso; + SIGNAL tse_rx_sosi : t_dp_sosi; + SIGNAL tse_rx_siso : t_dp_siso; + + -- View in Wave window + SIGNAL dbg_g_bg_ctrl : t_diag_block_gen_integer := g_bg_ctrl; + SIGNAL dbg_c_run_time : NATURAL := c_run_time; + SIGNAL dbg_c_mon_nof_sop_tx : NATURAL := c_mon_nof_sop_tx; + SIGNAL dbg_c_mon_nof_sop_rx : NATURAL := c_mon_nof_sop_rx; + SIGNAL dbg_c_mon_nof_valid_tx : NATURAL := c_mon_nof_valid_tx; + SIGNAL dbg_c_mon_nof_valid_rx : NATURAL := c_mon_nof_valid_rx; + +BEGIN + + mm_clk <= (NOT mm_clk) OR tb_end AFTER mm_clk_period/2; + st_clk <= (NOT st_clk) OR tb_end AFTER st_clk_period/2; + mm_rst <= '1', '0' AFTER mm_clk_period*5; + st_rst <= '1', '0' AFTER st_clk_period*5; + + tx_exp_total_count_nof_packet <= c_nof_sync * g_bg_ctrl.blocks_per_sync; + rx_exp_total_count_nof_packet <= sel_a_b(g_udp_port_match, tx_exp_total_count_nof_packet, 0); + + rx_exp_total_count_nof_valid <= sel_a_b(g_udp_port_match, c_nof_sync * c_total_count_nof_valid_per_sync, 0); + + ----------------------------------------------------------------------------- + -- MM control and monitoring + ----------------------------------------------------------------------------- + p_mm : PROCESS + BEGIN + tb_end <= '0'; + + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 10); + + --------------------------------------------------------------------------- + -- Rx UDP offload port + --------------------------------------------------------------------------- + -- Set destination MAC/IP/UDP port in tx header + -- The MM addresses follow from byte address_offset // 4 in eth.peripheral.yaml + proc_mem_mm_bus_wr(16#7#, c_dst_udp_port, mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + proc_mem_mm_bus_wr(16#10#, TO_SINT(c_eth_tester_ip_dst_addr), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); -- use signed to fit 32 b in INTEGER + proc_mem_mm_bus_wr(16#18#, TO_SINT(c_eth_tester_eth_dst_mac(31 DOWNTO 0)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); -- use signed to fit 32 b in INTEGER + proc_mem_mm_bus_wr(16#19#, TO_UINT(c_eth_tester_eth_dst_mac(47 DOWNTO 32)), mm_clk, reg_hdr_dat_cipo, reg_hdr_dat_copi); + + --------------------------------------------------------------------------- + -- Stimuli + --------------------------------------------------------------------------- + -- Prepare the BG + proc_mem_mm_bus_wr(1, g_bg_ctrl.samples_per_packet, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(2, g_bg_ctrl.blocks_per_sync, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(3, g_bg_ctrl.gapsize, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(4, g_bg_ctrl.mem_low_adrs, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(5, g_bg_ctrl.mem_high_adrs, mm_clk, reg_bg_ctrl_copi); + proc_mem_mm_bus_wr(6, g_bg_ctrl.bsn_init, mm_clk, reg_bg_ctrl_copi); -- low part + proc_mem_mm_bus_wr(7, 0, mm_clk, reg_bg_ctrl_copi); -- high part + -- Enable the BG at st_pps pulse. + proc_mem_mm_bus_wr(0, 3, mm_clk, reg_bg_ctrl_copi); + proc_common_wait_some_cycles(mm_clk, 10); + -- Issue an st_pps pulse to start the enabled BG + proc_common_gen_pulse(st_clk, st_pps); + + -- Run test + proc_common_wait_some_cycles(st_clk, c_run_time); + + -- Disable the BG + proc_mem_mm_bus_wr(0, 0, mm_clk, reg_bg_ctrl_copi); + + -- Wait until Tx FIFO has emptied for the stream + WHILE tx_fifo_rd_emp /= '1' LOOP + proc_common_wait_some_cycles(st_clk, 1); + END LOOP; + proc_common_wait_some_cycles(st_clk, c_bg_sync_period); + stimuli_end <= '1'; + + -- Delay logging between different tb instances + proc_common_wait_some_cycles(st_clk, g_tb_index * 100); + + -- Print logging + print_str(""); -- log empty line between tb results + print_str(c_tb_str & + "ETH bit rate :" & + " c_bg_nof_bps = " & REAL'IMAGE(c_bg_nof_bps) & " bps"); + ASSERT c_bg_nof_bps < 10.0**9 REPORT "Tx flow control will keep ETH bitrate < 1Gbps." SEVERITY NOTE; + + ------------------------------------------------------------------------- + -- Verification: Total counts + ------------------------------------------------------------------------- + -- . read low part, ignore high part (= 0) of two word total counts + -- Tx total nof packets + proc_mem_mm_bus_rd(0, mm_clk, reg_strobe_total_count_tx_cipo, reg_strobe_total_count_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_total_count_nof_packet <= TO_UINT(reg_strobe_total_count_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- Rx total nof packets + proc_mem_mm_bus_rd(0, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_packet <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- Rx total nof valids + proc_mem_mm_bus_rd(2, mm_clk, reg_strobe_total_count_rx_cipo, reg_strobe_total_count_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_total_count_nof_valid <= TO_UINT(reg_strobe_total_count_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(mm_clk, 1); + + -- Print logging + print_str(c_tb_str & + "Tx total counts monitor :" & + " nof_packet = " & NATURAL'IMAGE(tx_total_count_nof_packet)); + + print_str(c_tb_str & + "Rx total counts monitor :" & + " nof_packet = " & NATURAL'IMAGE(rx_total_count_nof_packet) & + ", nof_valid = " & NATURAL'IMAGE(rx_total_count_nof_valid)); + + -- Verify, only log when wrong + IF c_bg_nof_bps < 10.0**9 THEN + ASSERT tx_total_count_nof_packet = tx_exp_total_count_nof_packet REPORT c_tb_str & + "Wrong Tx total nof packets count, Tx count = " & NATURAL'IMAGE(tx_total_count_nof_packet) & + " /= " & NATURAL'IMAGE(tx_exp_total_count_nof_packet) & + " = Expected count" SEVERITY ERROR; + + ASSERT rx_total_count_nof_packet = rx_exp_total_count_nof_packet REPORT c_tb_str & + "Wrong Rx total nof packets count, Rx count = " & NATURAL'IMAGE(rx_total_count_nof_packet) & + " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_packet) & + " = Expected count" SEVERITY ERROR; + + ASSERT rx_total_count_nof_valid = rx_exp_total_count_nof_valid REPORT c_tb_str & + "Wrong Rx total nof valids count, Rx count = " & NATURAL'IMAGE(rx_total_count_nof_valid) & + " /= " & NATURAL'IMAGE(rx_exp_total_count_nof_valid) & + " = Expected count" SEVERITY ERROR; + END IF; + + ------------------------------------------------------------------------- + -- Verification: BSN monitors (yield same values in every sync interval) + ------------------------------------------------------------------------- + -- 3 = nof_sop + -- 4 = nof_valid + -- 6 = latency + -- . Tx + proc_mem_mm_bus_rd(3, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_nof_sop <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(4, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_nof_valid <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(6, mm_clk, reg_bsn_monitor_v2_tx_cipo, reg_bsn_monitor_v2_tx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + tx_mon_latency <= TO_UINT(reg_bsn_monitor_v2_tx_cipo.rddata(c_word_w-1 DOWNTO 0)); + -- . Rx + proc_mem_mm_bus_rd(3, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_mon_nof_sop <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(4, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_mon_nof_valid <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_mem_mm_bus_rd(6, mm_clk, reg_bsn_monitor_v2_rx_cipo, reg_bsn_monitor_v2_rx_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + rx_mon_latency <= TO_UINT(reg_bsn_monitor_v2_rx_cipo.rddata(c_word_w-1 DOWNTO 0)); + proc_common_wait_some_cycles(mm_clk, 1); + + -- Print logging + print_str(c_tb_str & + "Tx BSN monitor :" & + " nof_sop = " & NATURAL'IMAGE(tx_mon_nof_sop) & + ", nof_valid = " & NATURAL'IMAGE(tx_mon_nof_valid) & + ", latency = " & NATURAL'IMAGE(tx_mon_latency)); + + print_str(c_tb_str & + "Rx BSN monitor :" & + " nof_sop = " & NATURAL'IMAGE(rx_mon_nof_sop) & + ", nof_valid = " & NATURAL'IMAGE(rx_mon_nof_valid) & + ", latency = " & NATURAL'IMAGE(rx_mon_latency)); + + IF c_bg_nof_bps < 10.0**9 THEN + -- Verify BSN monitors only when the BG sync interval is stable, so + -- the ETH data rate < 1 Gbps and no BG block flow control. + -- Verify, only log when wrong + ASSERT tx_mon_nof_sop = c_mon_nof_sop_tx REPORT c_tb_str & "Wrong tx nof_sop" SEVERITY ERROR; + ASSERT rx_mon_nof_sop = c_mon_nof_sop_rx REPORT c_tb_str & "Wrong rx nof_sop" SEVERITY ERROR; + ASSERT tx_mon_nof_valid = c_mon_nof_valid_tx REPORT c_tb_str & "Wrong tx nof_valid" SEVERITY ERROR; + ASSERT rx_mon_nof_valid = c_mon_nof_valid_rx REPORT c_tb_str & "Wrong rx nof_valid" SEVERITY ERROR; + ASSERT tx_mon_latency = c_tx_exp_latency REPORT c_tb_str & "Wrong tx latency" SEVERITY ERROR; + + -- For short block lengths the Rx latency appears to become less, the + -- exact Rx latency is therefore hard to predetermine. The actual + -- latency is not critical, therefore it is sufficient to only very + -- the latency when it is more or less fixed. + IF c_rx_exp_latency_en THEN + ASSERT almost_equal(rx_mon_latency, c_rx_exp_latency_st, 0) REPORT + c_tb_str & "Wrong rx latency using st interface" SEVERITY ERROR; + END IF; + END IF; + + ------------------------------------------------------------------------- + -- End of test + ------------------------------------------------------------------------- + proc_common_wait_some_cycles(mm_clk, 100); + tb_end <= '1'; + WAIT; + END PROCESS; + + u_eth_tester : ENTITY work.eth_tester + GENERIC MAP ( + g_nof_streams => 1, + g_bg_sync_timeout => c_eth_tester_sync_timeout, + g_remove_crc => FALSE -- no CRC with streaming loopback + ) + PORT MAP ( + -- Clocks and reset + mm_rst => mm_rst, + mm_clk => mm_clk, + st_rst => st_rst, + st_clk => st_clk, + st_pps => st_pps, + + -- UDP transmit interface + eth_src_mac => c_gn_eth_src_mac, + ip_src_addr => c_gn_ip_src_addr, + udp_src_port => c_gn_udp_src_port, + + sl(tx_fifo_rd_emp_arr) => tx_fifo_rd_emp, + + TO_DP_ONE(tx_udp_sosi_arr) => tx_udp_sosi, + tx_udp_siso_arr => TO_DP_ARR(tx_udp_siso), + + -- UDP receive interface + rx_udp_sosi_arr => TO_DP_ARR(rx_udp_sosi), + + -- Memory Mapped Slaves (one per stream) + -- . Tx + reg_bg_ctrl_copi => reg_bg_ctrl_copi, + reg_bg_ctrl_cipo => reg_bg_ctrl_cipo, + reg_hdr_dat_copi => reg_hdr_dat_copi, + reg_hdr_dat_cipo => reg_hdr_dat_cipo, + reg_bsn_monitor_v2_tx_copi => reg_bsn_monitor_v2_tx_copi, + reg_bsn_monitor_v2_tx_cipo => reg_bsn_monitor_v2_tx_cipo, + reg_strobe_total_count_tx_copi => reg_strobe_total_count_tx_copi, + reg_strobe_total_count_tx_cipo => reg_strobe_total_count_tx_cipo, + -- . Rx + reg_bsn_monitor_v2_rx_copi => reg_bsn_monitor_v2_rx_copi, + reg_bsn_monitor_v2_rx_cipo => reg_bsn_monitor_v2_rx_cipo, + reg_strobe_total_count_rx_copi => reg_strobe_total_count_rx_copi, + reg_strobe_total_count_rx_cipo => reg_strobe_total_count_rx_cipo + ); + + + -- ETH stream + u_dut : ENTITY work.eth_stream + GENERIC MAP ( + g_rx_udp_port => c_rx_udp_port + ) + PORT MAP ( + -- Clocks and reset + st_rst => st_rst, + st_clk => st_clk, + + -- User UDP interface + -- . Tx + udp_tx_sosi => tx_udp_sosi, + udp_tx_siso => tx_udp_siso, + -- . Rx + udp_rx_sosi => rx_udp_sosi, + udp_rx_siso => c_dp_siso_rdy, + + -- PHY interface + -- . Tx + tse_tx_sosi => tse_tx_sosi, + tse_tx_siso => tse_tx_siso, + -- . Rx + tse_rx_sosi => tse_rx_sosi, + tse_rx_siso => tse_rx_siso + ); + + -- Loopback wire Tx to Rx, register to increasy ready latency from 1 to 2 + tse_rx_sosi <= tse_tx_sosi WHEN rising_edge(st_clk); + tse_tx_siso <= tse_rx_siso; + +END tb; diff --git a/libraries/io/eth/tb/vhdl/tb_tb_eth_stream.vhd b/libraries/io/eth/tb/vhdl/tb_tb_eth_stream.vhd new file mode 100644 index 0000000000..f501837459 --- /dev/null +++ b/libraries/io/eth/tb/vhdl/tb_tb_eth_stream.vhd @@ -0,0 +1,80 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: E. Kooistra +-- Purpose: Multi test bench for eth_stream +-- Description: +-- +-- Usage: +-- > as 8 +-- > run -all + +LIBRARY IEEE, diag_lib; +USE IEEE.std_logic_1164.ALL; +USE diag_lib.diag_pkg.ALL; +USE work.tb_eth_tester_pkg.ALL; + +ENTITY tb_tb_eth_stream IS +END tb_tb_eth_stream; + +ARCHITECTURE tb OF tb_tb_eth_stream IS + + -- Tb + CONSTANT c_eth_clk_MHz : NATURAL := 125; + CONSTANT c_st_clk_MHz : NATURAL := 200; + CONSTANT c_nof_sync : NATURAL := 2; + CONSTANT c_nof_blk : NATURAL := 3; -- nof_blk per sync + + -- Tx packet size and gap size in octets + CONSTANT c_block_len : NATURAL := 50; + CONSTANT c_link_len : NATURAL := func_eth_tester_eth_packet_on_link_length(c_block_len); + + -- For near maximum 1Gbps link rate the c_block_len + c_gap_len_min time + -- in the st_clk domain equals c_link_len time in eth_clk domain. + CONSTANT c_gap_len_min : NATURAL := c_link_len * c_st_clk_MHz / c_eth_clk_MHz - c_block_len; + + -- Choose c_gap_len somewhat larger to have packet link rate < 1 Gbps + CONSTANT c_gap_len : NATURAL := c_gap_len_min * 2; -- for g_nof_streams = 1 + + -- BG ctrl + CONSTANT c_high : NATURAL := c_diag_bg_mem_max_adr; -- = 2**24 + + CONSTANT c_bg_ctrl : t_diag_block_gen_integer := ('1', '1', c_block_len, c_nof_blk, c_gap_len, 0, c_high, 0); -- for first stream + +BEGIN + +-- g_tb_index : NATURAL := 0; -- use to incremental delay logging from tb instances in tb_tb +-- g_nof_sync : NATURAL := 2; -- number of BG sync intervals to set c_run_time +-- g_udp_port_match : BOOLEAN := TRUE; +-- +-- -- t_diag_block_gen_integer = +-- -- sl: enable +-- -- sl: enable_sync +-- -- nat: samples_per_packet +-- -- nat: blocks_per_sync +-- -- nat: gapsize +-- -- nat: mem_low_adrs +-- -- nat: mem_high_adrs +-- -- nat: bsn_init +-- g_bg_ctrl : t_diag_block_gen_integer := ('1', '1', 50, 3, 200, 0, c_diag_bg_mem_max_adr, 0) -- for first stream + + u_udp : ENTITY work.tb_eth_stream GENERIC MAP (0, c_nof_sync, TRUE, c_bg_ctrl); + u_udp_mismatch : ENTITY work.tb_eth_stream GENERIC MAP (1, c_nof_sync, FALSE, c_bg_ctrl); + +END tb; -- GitLab