diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index f64fd1ecaa1314e1de75ace410648826c42109b7..118ac6f5a32916305b826e0ed8a6500509ade1d0 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -203,6 +203,7 @@ test_bench_files = tb/vhdl/tb_dp_mux.vhd tb/vhdl/tb2_dp_mux.vhd tb/vhdl/tb3_dp_mux.vhd + tb/vhdl/tb_dp_concat_field_blk.vhd tb/vhdl/tb_dp_packet.vhd tb/vhdl/tb_dp_packet_merge.vhd tb/vhdl/tb_dp_packetizing.vhd diff --git a/libraries/base/dp/tb/vhdl/tb_dp_concat_field_blk.vhd b/libraries/base/dp/tb/vhdl/tb_dp_concat_field_blk.vhd new file mode 100644 index 0000000000000000000000000000000000000000..ad87a38771c6fcea2ddd8c4d9a751b24e0eb8766 --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_concat_field_blk.vhd @@ -0,0 +1,398 @@ +------------------------------------------------------------------------------- +-- +-- 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_concat_field_blk and dp_offload_rx +-- Description: +-- u_tx u_rx +-- ___________________ ___________________ +-- |dp_concat_field_blk| |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_concat_field_blk IS + GENERIC ( + -- general + g_flow_control_stimuli : t_dp_flow_control_enum := e_active; -- 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 := 13; + g_pkt_len : NATURAL := 100; + g_pkt_gap : NATURAL := 30 + ); +END tb_dp_concat_field_blk; + + +ARCHITECTURE tb OF tb_dp_concat_field_blk 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 := 7; + + -- 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; + + ----------------------------------------------------------------------------- + -- 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_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 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 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 + ) + 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 <= '0'; -- in rx_hdr_fields_out_arr from dp_offload_rx output the bsn is only valid at sop + 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 + ------------------------------------------------------------------------------ + dp_offload_tx_snk_in_arr(0) <= stimuli_src_out; + stimuli_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_concat_field_blk + 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 + ); + + ------------------------------------------------------------------------------ + -- Link + ------------------------------------------------------------------------------ + + p_link_offload : PROCESS(tx_offload_sosi_arr, link_offload_siso_arr) + BEGIN + link_offload_sosi_arr <= tx_offload_sosi_arr; + link_offload_sosi_arr(0).re <= (OTHERS=>'0'); + link_offload_sosi_arr(0).im <= (OTHERS=>'0'); + + tx_offload_siso_arr <= link_offload_siso_arr; + 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 + ); + + 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_out_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;