From 190dcc546deeae971f565c02adcf3744117ef904 Mon Sep 17 00:00:00 2001 From: Reinier van der Walle <walle@astron.nl> Date: Fri, 28 Feb 2020 10:50:08 +0100 Subject: [PATCH] Added dp_offload_tx_v3 --- libraries/base/dp/hdllib.cfg | 2 + .../base/dp/src/vhdl/dp_offload_tx_v3.vhd | 232 ++++++++++ .../base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd | 436 ++++++++++++++++++ 3 files changed, 670 insertions(+) create mode 100644 libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd create mode 100644 libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 864bb29d1a..4981181020 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -128,6 +128,7 @@ synth_files = src/vhdl/dp_field_blk.vhd src/vhdl/dp_concat_field_blk.vhd src/vhdl/dp_offload_tx.vhd + src/vhdl/dp_offload_tx_v3.vhd src/vhdl/dp_offload_rx_filter.vhd src/vhdl/dp_offload_rx_filter_mm.vhd src/vhdl/dp_offload_rx.vhd @@ -289,6 +290,7 @@ test_bench_files = tb/vhdl/tb_tb_dp_xonoff.vhd tb/vhdl/tb_tb_tb_dp_backpressure.vhd + tb/vhdl/tb_dp_offload_tx_v3.vhd tb/vhdl/tb_dp_offload_rx_filter.vhd regression_test_vhdl = diff --git a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd new file mode 100644 index 0000000000..e841015d54 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd @@ -0,0 +1,232 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2017 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.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: +-- . Concatenate a user-defined header to a DP frame e.g. to create an Ethernet frame +-- Description: +-- . The header contents can be controlled dynamically by data path or MM control (selected by g_hdr_field_sel) +-- . The header and data can be concatened at symbol level. The g_symbol_w defines the +-- resolution of the empty field. The g_data_w must be an integer multiple of the +-- g_symbol_w. If the empty field is not used or if the empty field is always 0 then +-- set g_symbol_w = g_data_w. +-- . For example to concat header and data for an Ethernet frame use: +-- - g_data_w = 32 (1GbE) or 64 (10GbE) +-- - g_symbol_w = c_byte_w = 8 if either the header or the data can have an +-- non-zero empty field, so when they are not a multiple of 4 bytes +-- (= 32b) or 8 bytes (= 64b). +-- g_symbol_w = g_data_w if the empty field is always 0, so the number of bits in +-- the header and data are an integer number of g_data_w. + + +LIBRARY IEEE, common_lib, technology_lib, mm_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 work.dp_stream_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; + +ENTITY dp_offload_tx_v3 IS + GENERIC ( + g_nof_streams : NATURAL; + g_data_w : NATURAL; + g_symbol_w : NATURAL; + g_hdr_field_arr : t_common_field_arr; -- User defined header fields + g_hdr_field_sel : STD_LOGIC_VECTOR; -- For each header field, select the source: 0=data path, 1=MM controlled + g_pipeline_ready : BOOLEAN := FALSE + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + + reg_hdr_dat_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_hdr_dat_miso : OUT t_mem_miso; + + snk_in_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + snk_out_arr : OUT t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + + src_out_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + src_in_arr : IN t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + + hdr_fields_in_arr : IN t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); -- hdr_fields_in_arr(i) is considered valid @ snk_in_arr(i).sop + hdr_fields_out_arr : OUT t_slv_1024_arr(g_nof_streams-1 DOWNTO 0) + ); +END dp_offload_tx_v3; + + +ARCHITECTURE str OF dp_offload_tx_v3 IS + + CONSTANT c_dp_field_blk_snk_data_w : NATURAL := field_slv_out_len(field_arr_set_mode(g_hdr_field_arr , "RW")); + CONSTANT c_dp_field_blk_src_data_w : NATURAL := g_data_w; + + SIGNAL dbg_c_dp_field_blk_snk_data_w : NATURAL := c_dp_field_blk_snk_data_w; + SIGNAL dbg_c_dp_field_blk_src_data_w : NATURAL := c_dp_field_blk_src_data_w; + + SIGNAL dp_field_blk_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_field_blk_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL dp_field_blk_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_field_blk_src_in_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL dp_concat_snk_in_2arr : t_dp_sosi_2arr_2(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_concat_snk_out_2arr : t_dp_siso_2arr_2(g_nof_streams-1 DOWNTO 0); + + SIGNAL reg_hdr_dat_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL reg_hdr_dat_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL mm_fields_slv_out_arr : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL field_override_arr : STD_LOGIC_VECTOR(g_hdr_field_arr'RANGE) := g_hdr_field_sel; --1 override bit per field + + +BEGIN + + ASSERT c_dp_field_blk_snk_data_w <= c_dp_stream_data_w REPORT "Number of header bits must fit in t_dp_sosi data field." SEVERITY FAILURE; + --------------------------------------------------------------------------------------- + -- Create header block & concatenate header to offload stream. + --------------------------------------------------------------------------------------- + p_wire_valid : PROCESS(snk_in_arr, hdr_fields_in_arr) + BEGIN + FOR i IN 0 TO g_nof_streams-1 LOOP + -- default pass on the other snk_in_arr fields as well, especially the sync, bsn and channel can + -- be useful to preserve for the packetized output, even though only the sosi.data of the + -- packetized output will get transmitted. + dp_field_blk_snk_in_arr(i) <= snk_in_arr(i); + -- Prepare packet header as a data block with only one data word, so valid = sop = eop. If + -- c_dp_field_blk_snk_data_w > c_dp_field_blk_src_data_w then dp_repack_data in dp_field_blk will + -- repack this data word into a multi word header block, else dp_field_blk will pass on the + -- dp_field_blk_snk_in_arr as a single word header block. + dp_field_blk_snk_in_arr(i).data <= RESIZE_DP_DATA(hdr_fields_in_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0)); + dp_field_blk_snk_in_arr(i).valid <= snk_in_arr(i).sop; + dp_field_blk_snk_in_arr(i).sop <= snk_in_arr(i).sop; -- necessary for single word header block + dp_field_blk_snk_in_arr(i).eop <= snk_in_arr(i).sop; -- necessary for single word header block + END LOOP; + END PROCESS; + + gen_dp_field_blk : FOR i IN 0 TO g_nof_streams-1 GENERATE + + -- Both dp_concat inputs must be ready. One of the inputs toggles ready via dp_field_blk. + snk_out_arr(i).ready <= dp_field_blk_snk_out_arr(i).ready AND dp_concat_snk_out_2arr(i)(0).ready; + snk_out_arr(i).xon <= src_in_arr(i).xon; + + -- Wire hdr_fields_out_arr + -- MM override bits determine source for each field + gen_field_wires: FOR j IN g_hdr_field_arr'RANGE GENERATE + hdr_fields_out_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)) <= mm_fields_slv_out_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)) + WHEN field_override_arr(j) = '1' ELSE + hdr_fields_in_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)); + END GENERATE; + + --------------------------------------------------------------------------------------- + -- mm_fields for MM access to each field + --------------------------------------------------------------------------------------- + u_mm_fields_slv: ENTITY mm_lib.mm_fields + GENERIC MAP( + g_field_arr => field_arr_set_mode(g_hdr_field_arr , "RW") + ) + PORT MAP ( + mm_clk => mm_clk, + mm_rst => mm_rst, + + mm_mosi => reg_hdr_dat_mosi_arr(i), + mm_miso => OPEN, -- Not used + + slv_clk => dp_clk, + slv_rst => dp_rst, + + slv_out => mm_fields_slv_out_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0) + ); + + + -- Create multi-cycle header block from single-cycle wide header SLV + u_dp_field_blk : ENTITY work.dp_field_blk + GENERIC MAP ( + g_field_arr => field_arr_set_mode(g_hdr_field_arr , "RW"), + g_field_sel => g_hdr_field_sel, + g_snk_data_w => c_dp_field_blk_snk_data_w, + g_src_data_w => c_dp_field_blk_src_data_w, + g_in_symbol_w => g_symbol_w, + g_out_symbol_w => g_symbol_w, + g_pipeline_ready => g_pipeline_ready + ) + PORT MAP ( + dp_clk => dp_clk, + dp_rst => dp_rst, + + mm_clk => mm_clk, + mm_rst => mm_rst, + + snk_in => dp_field_blk_snk_in_arr(i), + snk_out => dp_field_blk_snk_out_arr(i), + + src_out => dp_field_blk_src_out_arr(i), + src_in => dp_field_blk_src_in_arr(i), + + reg_slv_mosi => reg_hdr_dat_mosi_arr(i), + reg_slv_miso => reg_hdr_dat_miso_arr(i) + ); + + dp_field_blk_src_in_arr(i) <= dp_concat_snk_out_2arr(i)(1); + + END GENERATE; + + -- Prepend the header block to the input block + gen_dp_concat : FOR i IN 0 TO g_nof_streams-1 GENERATE + + dp_concat_snk_in_2arr(i)(0) <= snk_in_arr(i); + dp_concat_snk_in_2arr(i)(1) <= dp_field_blk_src_out_arr(i); + + u_dp_concat : ENTITY work.dp_concat + GENERIC MAP ( + g_data_w => g_data_w, + g_symbol_w => g_symbol_w + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + snk_out_arr => dp_concat_snk_out_2arr(i), + snk_in_arr => dp_concat_snk_in_2arr(i), + + src_in => src_in_arr(i), + src_out => src_out_arr(i) + ); + END GENERATE; + + --------------------------------------------------------------------------------------- + -- MM control & monitoring + --------------------------------------------------------------------------------------- + u_common_mem_mux_hdr_dat : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => ceil_log2(field_nof_words(g_hdr_field_arr, c_word_w)) + ) + PORT MAP ( + mosi => reg_hdr_dat_mosi, + miso => reg_hdr_dat_miso, + mosi_arr => reg_hdr_dat_mosi_arr, + miso_arr => reg_hdr_dat_miso_arr + ); + +END str; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd b/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd new file mode 100644 index 0000000000..0856662122 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd @@ -0,0 +1,436 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2015 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.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: +-- . Test bench for dp_offload_tx_v3 and dp_offload_rx +-- Description: +-- u_tx u_rx +-- ___________________ ___________________ +-- |dp_offload_tx_v3| |dp_offload_rx | +-- stimuli_src -->| |--->| |--> verify_snk +-- | in out | | | in out | +-- |___________________| | |___________________| +-- | +-- link_offload_sosi +-- Usage: +-- > as 10 +-- > run -all +-- + +LIBRARY IEEE, common_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.tb_common_pkg.ALL; +USE work.dp_stream_pkg.ALL; +USE work.tb_dp_pkg.ALL; + + +ENTITY tb_dp_offload_tx_v3 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 + -- specific + g_data_w : NATURAL := 64; + g_nof_repeat : NATURAL := 100; + g_pkt_len : NATURAL := 240; + g_pkt_gap : NATURAL := 16 + ); +END tb_dp_offload_tx_v3; + + +ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS + + CONSTANT c_mm_clk_period : TIME := 1 ns; + CONSTANT c_dp_clk_period : TIME := 5 ns; + + -- 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 := c_dp_sosi_unsigned_rst; -- default 0 is no wrap + 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_hdr_len : NATURAL := 7; + CONSTANT c_wait_last_evt : NATURAL := 100 + g_nof_repeat * c_hdr_len; + + ----------------------------------------------------------------------------- + -- Tx offload + ----------------------------------------------------------------------------- + -- From apertif_udp_offload_pkg.vhd: + CONSTANT c_udp_offload_nof_hdr_fields : NATURAL := 3+12+4+3; -- 448b; 7 64b words + -- 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) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"001B214368AC") ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + ( 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(1450) ), + ( 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(29928) ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(x"C0A80009") ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(x"C0A80001") ), + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(1430) ), + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + ( field_name_pad("dp_reserved" ), "RW", 47, field_default(0) ), + ( field_name_pad("dp_sync" ), "RW", 1, field_default(0) ), + ( field_name_pad("dp_bsn" ), "RW", 64, field_default(0) ) ); + + -- From apertif_unb1_fn_beamformer_udp_offload.vhd: + -- 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 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); + +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 work.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, + -- specific + g_in_dat_w => g_data_w, + g_nof_repeat => g_nof_repeat, + 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 work.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 + ); + + ------------------------------------------------------------------------------ + -- DUT offload Tx + ------------------------------------------------------------------------------ + stimuli_src_in <= c_dp_siso_rdy; + + -- Use FIFO to mimic apertif_unb1_fn_beamformer_udp_offload.vhd, without FIFO dp_stream_stimuli + -- would handle the back pressure + u_dp_fifo_sc : ENTITY work.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(63 DOWNTO 0); + + u_tx : ENTITY work.dp_offload_tx_v3 + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => g_data_w, + g_symbol_w => g_data_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 + ); + + ------------------------------------------------------------------------------ + -- Link + ------------------------------------------------------------------------------ + + p_link_offload : PROCESS(tx_offload_sosi_arr, link_offload_siso_arr) + BEGIN + -- Model active packet fields of tr_10GbE Rx sosi output interface + link_offload_sosi_arr(0) <= c_dp_sosi_rst; + link_offload_sosi_arr(0).data <= tx_offload_sosi_arr(0).data; + link_offload_sosi_arr(0).empty <= tx_offload_sosi_arr(0).empty; + link_offload_sosi_arr(0).valid <= tx_offload_sosi_arr(0).valid; + link_offload_sosi_arr(0).sop <= tx_offload_sosi_arr(0).sop; + link_offload_sosi_arr(0).eop <= tx_offload_sosi_arr(0).eop; + + tx_offload_siso_arr <= (OTHERS=>c_dp_siso_rdy); + END PROCESS; + + ------------------------------------------------------------------------------ + -- DUT offload Rx + ------------------------------------------------------------------------------ + + u_rx : ENTITY work.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => g_data_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; + + ------------------------------------------------------------------------------ + -- 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; -- GitLab