diff --git a/applications/lofar2/libraries/sdp/hdllib.cfg b/applications/lofar2/libraries/sdp/hdllib.cfg index 06720dbf4fed95af61f17c22350b8afce784719d..97a713a2e7a5ee6c639742c4d31f72639ebc19f5 100644 --- a/applications/lofar2/libraries/sdp/hdllib.cfg +++ b/applications/lofar2/libraries/sdp/hdllib.cfg @@ -13,15 +13,18 @@ synth_files = src/vhdl/sdp_info_reg.vhd src/vhdl/sdp_info.vhd src/vhdl/sdp_beamformer_output.vhd + src/vhdl/sdp_statistics_offload.vhd src/vhdl/node_sdp_adc_input_and_timing.vhd src/vhdl/node_sdp_filterbank.vhd src/vhdl/node_sdp_beamformer.vhd test_bench_files = tb/vhdl/tb_sdp_info.vhd + tb/vhdl/tb_sdp_statistics_offload.vhd regression_test_vhdl = tb/vhdl/tb_sdp_info.vhd + tb/vhdl/tb_sdp_statistics_offload.vhd [modelsim_project_file] diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd index 2668b93b27041cb0af04bc4e7c717d0028f6279d..d20dee52d26ca046d6630eb4aa94be1f6278f880 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd @@ -78,10 +78,10 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_W_adc : NATURAL := 14; CONSTANT c_sdp_W_fir_coef : NATURAL := 16; CONSTANT c_sdp_W_subband : NATURAL := 18; - CONSTANT c_sdp_P_pfb : NATURAL := c_sdp_S_pn/c_sdp_Q_fft; + CONSTANT c_sdp_P_pfb : NATURAL := c_sdp_S_pn / c_sdp_Q_fft; CONSTANT c_sdp_S_sub_bf : NATURAL := 488; CONSTANT c_sdp_f_adc_MHz : NATURAL := 200; - CONSTANT c_sdp_T_adc : TIME := (10**6/c_sdp_f_adc_MHz) * 1 ps; + CONSTANT c_sdp_T_adc : TIME := (10**6 / c_sdp_f_adc_MHz) * 1 ps; CONSTANT c_sdp_T_sub : TIME := c_sdp_N_fft * c_sdp_T_adc; CONSTANT c_sdp_W_sub_weight : NATURAL := 16; CONSTANT c_sdp_W_sub_magnitude : NATURAL := 2; @@ -96,6 +96,11 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_W_gn_id : NATURAL := 5; CONSTANT c_sdp_N_pn_lb : NATURAL := 16; + -- + CONSTANT c_sdp_marker_sst : NATURAL := 83; -- = 0x53 = 'S' + CONSTANT c_sdp_marker_bst : NATURAL := 66; -- = 0x42 = 'B' + CONSTANT c_sdp_marker_xst : NATURAL := 88; -- = 0x58 = 'X' + -- AIT constants CONSTANT c_sdp_ait_buf_nof_data_jesd : NATURAL := 1024; -- 1024 14 bit samples fit in one M20k BRAM CONSTANT c_sdp_ait_buf_nof_data_bsn : NATURAL := 1024; -- 1024 14 bit samples fit in one M20k BRAM @@ -199,6 +204,58 @@ PACKAGE sdp_pkg is CONSTANT c_sdp_reg_nw_10GbE_mac_addr_w : NATURAL := 13; CONSTANT c_sdp_reg_nw_10GbE_eth10g_addr_w : NATURAL := 1; + -- statistics offload + CONSTANT c_sdp_stat_nof_hdr_fields : NATURAL := 3+12+4+20+1; -- 592b; 9.25 64b words + CONSTANT c_sdp_stat_hdr_field_sel : STD_LOGIC_VECTOR(c_sdp_stat_nof_hdr_fields-1 DOWNTO 0) := "101"&"111111111001"&"0111"&"01000000000000000000"&"0"; -- 0=data path, 1=MM controlled TODO + + CONSTANT c_sdp_stat_hdr_field_arr : t_common_field_arr(c_sdp_stat_nof_hdr_fields-1 DOWNTO 0) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"00074306C700") ), -- 00074306C700=DOP36-eth0 + ( 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(7868) ), + ( 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(x"C0A80001") ), -- C0A80001=DOP36-eth0 '192.168.0.1' + + ( 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(7848) ), + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + + ( field_name_pad("sdp_marker" ), "RW", 8, field_default(0) ), + ( field_name_pad("sdp_version_id" ), "RW", 8, field_default(5) ), + + ( field_name_pad("sdp_observation_id" ), "RW", 32, field_default(0) ), + ( field_name_pad("sdp_station_id" ), "RW", 16, field_default(0) ), + ( field_name_pad("sdp_source_info_antenna_band_id" ), "RW", 1, field_default(0) ), + ( field_name_pad("sdp_source_info_nyquist_zone_id" ), "RW", 2, field_default(0) ), + ( field_name_pad("sdp_source_info_f_adc" ), "RW", 1, field_default(0) ), + ( field_name_pad("sdp_source_info_fsub_type" ), "RW", 1, field_default(0) ), + ( field_name_pad("sdp_source_info_payload_error" ), "RW", 1, field_default(0) ), + ( field_name_pad("sdp_source_info_beam_repositioning_flag" ), "RW", 1, field_default(0) ), + ( field_name_pad("sdp_source_info_subband_calibrated_flag" ), "RW", 1, field_default(0) ), + ( field_name_pad("sdp_source_info_reserved" ), "RW", 3, field_default(0) ), + ( field_name_pad("sdp_source_info_gn_id" ), "RW", 5, field_default(0) ), + + ( field_name_pad("sdp_reserved" ), "RW", 8, field_default(0) ), + ( field_name_pad("sdp_integration_interval" ), "RW", 24, field_default(0) ), + ( field_name_pad("sdp_data_id" ), "RW", 32, field_default(0) ), + ( field_name_pad("sdp_nof_signal_inputs" ), "RW", 8, field_default(0) ), + ( field_name_pad("sdp_nof_bytes_per_statistics" ), "RW", 8, field_default(8) ), + ( field_name_pad("sdp_nof_statistics_per_packet" ), "RW", 16, field_default(0) ), + ( field_name_pad("sdp_block_period" ), "RW", 16, field_default(0) ), + + ( field_name_pad("dp_bsn" ), "RW", 64, field_default(0) ) + ); END PACKAGE sdp_pkg; PACKAGE BODY sdp_pkg IS diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd new file mode 100644 index 0000000000000000000000000000000000000000..582ed069d69311742e4a36aa452d2eef873a7c33 --- /dev/null +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_statistics_offload.vhd @@ -0,0 +1,299 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- 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: P. Donker + +-- Purpose: +-- . SDP statistics offload +-- Description: +-- https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+filterbank +-- . See figure 4.3 +-- https://plm.astron.nl/polarion/#/project/LOFAR2System/wiki/L2%20Interface%20Control%20Documents/SC%20to%20SDP%20ICD +-- . See 2.9.4 Station Control (L3-SC) - SDP Firmware (L4-SDPFW) +-- +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, mm_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE work.sdp_pkg.ALL; + +ENTITY sdp_statistics_offload IS + GENERIC ( + g_statistics_type : STRING := "SST"; + g_offload_time : NATURAL := 13000; -- from wave window 62855nS / 5nS = 12571 cycles. + g_beamset_id : NATURAL := 0 + ); + PORT ( + -- Clocks and reset + mm_rst : IN STD_LOGIC; -- reset synchronous with mm_clk + mm_clk : IN STD_LOGIC; -- memory-mapped bus clock + + dp_clk : IN STD_LOGIC; + dp_rst : IN STD_LOGIC; + + -- Memory access to statistics values + master_mosi : OUT t_mem_mosi; -- := c_mem_mosi_rst; + master_miso : IN t_mem_miso; + + -- Memory access to read/write settings + reg_enable_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_enable_miso : OUT t_mem_miso; + + reg_hdr_dat_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_hdr_dat_miso : OUT t_mem_miso; + + -- Input timing regarding the integration interval of the statistics + in_sosi : IN t_dp_sosi; + + -- Streaming output of offloaded statistics packets + out_sosi : OUT t_dp_sosi; + out_siso : IN t_dp_siso; + + -- inputs from other blocks + eth_src_mac : IN STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + udp_src_port : IN STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0); + ip_src_addr : IN STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0); + sdp_info : IN t_sdp_info; + + gn_index : IN NATURAL + ); +END sdp_statistics_offload; + + +ARCHITECTURE str OF sdp_statistics_offload IS + + CONSTANT c_step_size : NATURAL := 4; + CONSTANT c_nof_data : NATURAL := 512; + CONSTANT c_block_size : NATURAL := c_nof_data * c_step_size; + + + CONSTANT c_nof_streams : NATURAL := 1; + CONSTANT c_data_size : NATURAL := 2; + CONSTANT c_nof_data_per_step : NATURAL := 2; + CONSTANT c_nof_packets : NATURAL := sel_a_b(g_statistics_type="BST", 1, + sel_a_b(g_statistics_type="XST", c_sdp_S_pn, + c_sdp_S_pn)); -- SST + + CONSTANT c_marker : NATURAL := sel_a_b(g_statistics_type="BST", c_sdp_marker_bst, + sel_a_b(g_statistics_type="XST", c_sdp_marker_xst, + c_sdp_marker_sst)); + + CONSTANT c_nof_signal_inputs : NATURAL := sel_a_b(g_statistics_type="BST", 0, + sel_a_b(g_statistics_type="XST", c_sdp_S_pn, + 1)); -- SST + + CONSTANT c_nof_statistics_per_packet : NATURAL := sel_a_b(g_statistics_type="BST", c_sdp_S_sub_bf, + sel_a_b(g_statistics_type="XST", (c_sdp_S_pn * c_sdp_S_pn * c_nof_complex), + c_sdp_N_sub)); -- SST + + CONSTANT c_beamlet_id : NATURAL := g_beamset_id * c_sdp_S_sub_bf; + + TYPE t_reg IS RECORD + block_count : NATURAL; + start_address : NATURAL; + start_pulse : STD_LOGIC; + dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0); + data_id : STD_LOGIC_VECTOR(31 DOWNTO 0); + nof_cycles_dly : NATURAL; + payload_err : STD_LOGIC; + interval_cnt : NATURAL; + END RECORD; + + CONSTANT c_reg_rst : t_reg := (0, 0, '0', (OTHERS => '0'), (OTHERS => '0'), 0, '0', 0); + + SIGNAL r : t_reg; + SIGNAL d : t_reg; + + SIGNAL trigger : STD_LOGIC := '0'; + SIGNAL mm_done : STD_LOGIC := '0'; + SIGNAL dp_block_from_mm_src_out : t_dp_sosi; + SIGNAL dp_block_from_mm_src_in : t_dp_siso; + + SIGNAL dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0):= (OTHERS => '0'); + SIGNAL integration_interval : NATURAL := 0; + SIGNAL bsn_at_sync : STD_LOGIC_VECTOR(63 DOWNTO 0) := (OTHERS => '0'); + + --SIGNAL sdp_data_id : STD_LOGIC_VECTOR(31 DOWNTO 0); + +BEGIN + + bsn_at_sync <= RESIZE_UVEC(in_sosi.bsn, 64) WHEN rising_edge(dp_clk) AND in_sosi.sync = '1'; + + + ------------------------------------------------------------------------------- + -- Assemble offload header info + ------------------------------------------------------------------------------- + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "eth_src_mac" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "eth_src_mac" )) <= eth_src_mac; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "udp_src_port" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "udp_src_port" )) <= udp_src_port; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "ip_src_addr" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_src_addr" )) <= ip_src_addr; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_marker" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_marker" )) <= TO_UVEC(c_marker, 8); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_observation_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_observation_id" )) <= sdp_info.observation_id; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_station_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_station_id" )) <= sdp_info.station_id; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_antenna_band_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_antenna_band_id" )) <= SLV(sdp_info.antenna_band_index); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_nyquist_zone_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_nyquist_zone_id" )) <= sdp_info.nyquist_zone_index; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_f_adc" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_f_adc" )) <= SLV(sdp_info.f_adc); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_fsub_type" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_fsub_type" )) <= SLV(sdp_info.fsub_type); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_payload_error" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_payload_error" )) <= SLV(r.payload_err); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_beam_repositioning_flag" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_beam_repositioning_flag" )) <= SLV(sdp_info.beam_repositioning_flag); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_subband_calibrated_flag" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_subband_calibrated_flag" )) <= SLV(sdp_info.subband_calibrated_flag); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_reserved" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_reserved" )) <= (OTHERS => '0'); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_gn_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_gn_id" )) <= TO_UVEC(gn_index, 5); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_reserved" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_reserved" )) <= (OTHERS => '0'); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_integration_interval" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_integration_interval" )) <= TO_UVEC(integration_interval, 24); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_data_id" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_data_id" )) <= r.data_id; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_signal_inputs" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_signal_inputs" )) <= TO_UVEC(c_nof_signal_inputs, 8); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_statistics_per_packet" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_statistics_per_packet" )) <= TO_UVEC(c_nof_statistics_per_packet, 16); + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "sdp_block_period" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_block_period" )) <= sdp_info.block_period; + dp_header_info(field_hi(c_sdp_stat_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "dp_bsn" )) <= bsn_at_sync; + + p_reg : PROCESS(dp_rst, dp_clk) + BEGIN + IF dp_rst='1' THEN + r <= c_reg_rst; + ELSIF rising_edge(dp_clk) THEN + r <= d; + END IF; + END PROCESS; + + p_control_packet_offload : PROCESS(r, gn_index, in_sosi, trigger, mm_done, dp_header_info) + BEGIN + d <= r; + d.start_pulse <= '0'; + d.nof_cycles_dly <= gn_index * g_offload_time; + + -- Count number of sop's in a sync interval and get payload errors and keep them till next sync. + IF in_sosi.sync = '1' THEN + integration_interval <= r.interval_cnt; + d.interval_cnt <= 0; + d.payload_err <= '0'; + ELSE + IF in_sosi.eop = '1' THEN + d.payload_err <= r.payload_err OR in_sosi.err(0); + END IF; + + IF in_sosi.sop = '1' THEN + d.interval_cnt <= r.interval_cnt + 1; + END IF; + END IF; + + -- assign sdp_data_id for different statistic types + IF g_statistics_type = "SST" THEN + d.data_id <= x"000000" & TO_UVEC(r.block_count + c_sdp_S_pn * gn_index, 8); + ELSIF g_statistics_type = "BST" THEN + d.data_id <= x"0000" & TO_UVEC(c_beamlet_id, 16); + ELSIF g_statistics_type = "XST" THEN + d.data_id <= x"00" & TO_UVEC(0, 8) & TO_UVEC(0, 8) & TO_UVEC(0, 8); -- TODO: fill in right values for XST. + ELSE + d.data_id <= x"00000000"; + END IF; + + -- Issue start_pulse per packet offload + IF trigger = '1' THEN + -- Use trigger to start first packet + d.start_pulse <= '1'; + d.start_address <= 0; + d.block_count <= 1; + ELSIF mm_done = '1' THEN + -- Use mm_done to start next packets + IF r.block_count < c_nof_packets THEN + IF r.block_count MOD c_nof_data_per_step = 0 THEN + d.start_address <= r.start_address + c_data_size; -- step to next packet within block + ELSE + d.start_address <= r.block_count / c_nof_data_per_step * c_block_size; -- jump to first packet in next block + END IF; + d.start_pulse <= '1'; + d.block_count <= r.block_count + 1; + ELSE + -- Prepare for next trigger interval. + d.start_address <= 0; + d.block_count <= 0; + END IF; + END IF; + + -- Release header info per packet offload + IF trigger = '1' OR mm_done = '1' THEN + d.dp_header_info <= dp_header_info; + END IF; + END PROCESS; + + u_mms_common_variable_delay : ENTITY common_lib.mms_common_variable_delay + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + + -- MM interface + reg_enable_mosi => reg_enable_mosi, + reg_enable_miso => reg_enable_miso, + + delay => r.nof_cycles_dly, + trigger => in_sosi.sync, + trigger_dly => trigger + ); + + u_dp_block_from_mm : ENTITY dp_lib.dp_block_from_mm + GENERIC MAP ( + g_data_size => c_data_size, + g_step_size => c_step_size, + g_nof_data => c_nof_data + ) + PORT MAP( + rst => dp_rst, + clk => dp_clk, + start_pulse => r.start_pulse, + start_address => r.start_address, + mm_done => mm_done, + mm_mosi => master_mosi, + mm_miso => master_miso, + out_sosi => dp_block_from_mm_src_out, + out_siso => dp_block_from_mm_src_in + ); + + u_dp_offload_tx_v3: ENTITY dp_lib.dp_offload_tx_v3 + GENERIC MAP ( + g_nof_streams => c_nof_streams, + g_data_w => c_word_w, + g_symbol_w => c_word_w, + g_hdr_field_arr => c_sdp_stat_hdr_field_arr, + g_hdr_field_sel => c_sdp_stat_hdr_field_sel, + g_pipeline_ready => TRUE + ) + PORT MAP( + mm_rst => mm_rst, + mm_clk => mm_clk, + dp_rst => dp_rst, + dp_clk => dp_clk, + reg_hdr_dat_mosi => reg_hdr_dat_mosi, + reg_hdr_dat_miso => reg_hdr_dat_miso, + snk_in_arr(0) => dp_block_from_mm_src_out, + snk_out_arr(0) => dp_block_from_mm_src_in, + src_out_arr(0) => out_sosi, + src_in_arr(0) => out_siso, + hdr_fields_in_arr(0) => r.dp_header_info + ); +END str; diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd new file mode 100644 index 0000000000000000000000000000000000000000..751119c7d17c5a81dc1d7a0544e5f43001d2cf3c --- /dev/null +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_statistics_offload.vhd @@ -0,0 +1,484 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- 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: P. Donker + +-- Purpose: +-- . test bench for sdp_statistics_offload.vhd +-- Description: +-- +-- https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Subband+filterbank +-- . See figure 4.8 +-- +-- Remark: +-- . +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_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 common_lib.common_field_pkg.ALL; +USE common_lib.common_str_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE work.sdp_pkg.ALL; + + +ENTITY tb_sdp_statistics_offload IS + GENERIC ( + g_statistics_type : STRING := "SST"; + g_nof_signal_inputs_per_pn : NATURAL := 12; + g_offload_time : NATURAL := 500 + ); +END tb_sdp_statistics_offload; + +ARCHITECTURE tb OF tb_sdp_statistics_offload IS + CONSTANT c_dp_clk_period : TIME := 5 ns; -- 200 MHz + CONSTANT c_mm_clk_period : TIME := 20 ns; -- 50 MHz + + CONSTANT c_cross_clock_domain_latency : NATURAL := 20; + + CONSTANT c_eth_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := x"123456789ABC"; + CONSTANT c_ip_src_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := x"0A090807"; + CONSTANT c_udp_src_port : STD_LOGIC_VECTOR(c_network_udp_port_w-1 DOWNTO 0) := x"D001"; + + -- Used mm_adresses on mm bus "enable_mosi/miso". + CONSTANT c_reg_enable_mm_addr_enable : NATURAL := 0; + + -- Used mm_adresses on mm bus "hdr_dat_mosi/miso". + CONSTANT c_hdr_dat_mm_addr_eth_src_mac : NATURAL := 1; + CONSTANT c_hdr_dat_mm_addr_ip_src_addr : NATURAL := 13; + CONSTANT c_hdr_dat_mm_addr_udp_src_port : NATURAL := 15; + + -- Define SST RAM structure. + CONSTANT c_nof_data : NATURAL := 512; + CONSTANT c_data_size : NATURAL := 2; + CONSTANT c_step_size : NATURAL := 4; + + -- Define SST RAM size for g_nof_signal_inputs_per_pn. + CONSTANT c_ram_size : NATURAL := c_nof_data * c_data_size * g_nof_signal_inputs_per_pn; + CONSTANT c_ram_w : NATURAL := ceil_log2(c_ram_size); + --CONSTANT c_ram_buf : t_c_mem := (c_mem_ram_rd_latency, c_ram_w, 32, 2**c_ram_w, 'X'); + CONSTANT c_ram_buf : t_c_mem := (1, c_ram_w, 32, 2**c_ram_w, 'X'); + + -- Define block timing. + CONSTANT c_nof_block_per_sync : NATURAL := 20; -- Sufficient to fit more than g_nof_signal_inputs_per_pn offload packets per sync interval. + CONSTANT c_nof_clk_per_block : NATURAL := c_nof_data * c_data_size; + + -- Based on g_statistics_type: 'S'=0x53="SST", 'B'=0x42="BST", 'X'=0x58="XST". + CONSTANT c_marker : NATURAL := sel_a_b(g_statistics_type="BST", c_sdp_marker_bst, + sel_a_b(g_statistics_type="XST", c_sdp_marker_xst, + c_sdp_marker_sst)); -- SST + + CONSTANT c_nof_signal_inputs : NATURAL := sel_a_b(g_statistics_type="BST", 0, + sel_a_b(g_statistics_type="XST", c_sdp_S_pn, + 1)); -- SST + + CONSTANT c_nof_statistics_per_packet : NATURAL := sel_a_b(g_statistics_type="BST", c_sdp_S_sub_bf, + sel_a_b(g_statistics_type="XST", (c_sdp_S_pn * c_sdp_S_pn * c_nof_complex), + c_sdp_N_sub)); -- SST + + CONSTANT c_nof_valid_per_block : NATURAL := c_nof_data * c_data_size; + CONSTANT c_nof_sync : NATURAL := 5; + CONSTANT c_nof_clk_per_sync : NATURAL := c_nof_block_per_sync * c_nof_clk_per_block; + + SIGNAL tb_end : STD_LOGIC := '0'; + + SIGNAL dp_clk : STD_LOGIC := '1'; -- Digital data path clock = 200 MHz (deser factor 4); + SIGNAL dp_rst : STD_LOGIC; + + SIGNAL mm_clk : STD_LOGIC := '1'; -- MM control clock = 50 MHz + SIGNAL mm_rst : STD_LOGIC; + + SIGNAL master_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL master_miso : t_mem_miso; + + SIGNAL enable_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL enable_miso : t_mem_miso; + + SIGNAL hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL hdr_dat_miso : t_mem_miso; + + SIGNAL offload_rx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL offload_rx_hdr_dat_miso : t_mem_miso; + + SIGNAL in_sosi : t_dp_sosi := c_dp_sosi_rst; + SIGNAL offload_sosi : t_dp_sosi; + SIGNAL offload_siso : t_dp_siso := c_dp_siso_rst; + + SIGNAL test_offload_sosi : t_dp_sosi := c_dp_sosi_rst; + SIGNAL test_offload_siso : t_dp_siso; + + SIGNAL rx_hdr_fields_out : STD_LOGIC_VECTOR(1023 DOWNTO 0); + SIGNAL rx_hdr_fields_raw : STD_LOGIC_VECTOR(1023 DOWNTO 0) := (OTHERS => '0'); + + -- Signals used to change settings of sdp_info. + SIGNAL gn_index : NATURAL := 1; -- select > 0 to see effect of g_offload_time + + SIGNAL sdp_info : t_sdp_info := ( + TO_UVEC(601, 16), -- station_id + '0', -- antenna_band_index + x"00001111", -- observation_id + b"01", -- nyquist_zone_index + '0', -- f_adc + '1', -- fsub_type + '0', -- beam_repositioning_flag + '1', -- subband_calibrated_flag + x"01", -- O_si + x"02", -- N_si + x"04", -- O_rn + x"08", -- N_rn + x"1400", -- block_period = 5120 + x"0000" -- beamlet_scale + ); + + -- Signals used for starting processes. + SIGNAL ram_wr_data : STD_LOGIC_VECTOR(c_ram_buf.dat_w-1 DOWNTO 0); + SIGNAL ram_wr_addr : STD_LOGIC_VECTOR(c_ram_buf.adr_w-1 DOWNTO 0); + SIGNAL ram_wr_en : STD_LOGIC; + SIGNAL init_ram_done : STD_LOGIC := '0'; + + SIGNAL in_sync_hold : STD_LOGIC := '0'; + SIGNAL rx_prev_bsn : NATURAL := 0; + SIGNAL rx_bsn : NATURAL := 0; + SIGNAL rx_block_cnt : NATURAL := 0; + SIGNAL rx_valid_clk_cnt : NATURAL := 0; + +BEGIN + dp_rst <= '1', '0' AFTER c_dp_clk_period*7; + dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2; + + mm_rst <= '1', '0' AFTER c_mm_clk_period*7; + mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; + + -- Fill ram with data, data is same as address number. + p_mm_statistics_ram : PROCESS + BEGIN + ram_wr_en <= '0'; + -- Initialyze + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 10); + + FOR i IN 0 TO c_ram_buf.nof_dat-1 LOOP + ram_wr_addr <= TO_UVEC(i, c_ram_buf.adr_w); + ram_wr_data <= TO_UVEC(i, c_ram_buf.dat_w); + ram_wr_en <= '1'; + proc_common_wait_some_cycles(mm_clk, 1); + END LOOP; + ram_wr_en <= '0'; + + proc_common_wait_until_high(dp_clk, in_sosi.sync); + init_ram_done <= '1'; + WAIT; + END PROCESS; + + p_enable_trigger : PROCESS + BEGIN + proc_common_wait_until_high(mm_clk, init_ram_done); + -- Enable common variabel delay. + proc_mem_mm_bus_wr(c_reg_enable_mm_addr_enable, 1, mm_clk, enable_miso, enable_mosi); + proc_common_wait_some_cycles(mm_clk, c_cross_clock_domain_latency); + WAIT; + END PROCESS; + + -- Module dp_offload_tx_v3.vhd can handle 32 data that is not aligned, dp_offload_rx can not. + -- This is the reason the first 16bit of the header are always zero. + -- This process will start counting with bit16 high, the first bit that wil be received, + -- on each dp_clk the bsn is incremented with 0x10000, if you look at b63..b16 it looks like normal counting. + -- If dp_offload_rx.vhd is fixed this can be set normal again. + p_in_sosi : PROCESS + BEGIN + proc_common_wait_until_low(dp_clk, dp_rst); + proc_common_wait_some_cycles(dp_clk, 12); + in_sosi.bsn <= TO_DP_BSN(16#10000#); + in_sosi.valid <= '1'; + WHILE TRUE LOOP + FOR i IN 0 TO c_nof_block_per_sync-1 LOOP + FOR j IN 0 TO c_nof_clk_per_block-1 LOOP + in_sosi.sync <= '0'; + in_sosi.sop <= '0'; + in_sosi.eop <= '0'; + IF i = 0 AND j = 0 THEN + in_sosi.sync <= '1'; + END IF; + IF j = 0 THEN + in_sosi.sop <= '1'; + in_sosi.bsn <= INCR_UVEC(in_sosi.bsn, 16#10000#); -- = 2**16 = 65536 + END IF; + IF j = c_nof_clk_per_block-1 THEN + in_sosi.eop <= '1'; + END IF; + proc_common_wait_some_cycles(dp_clk, 1); + END LOOP; + END LOOP; + END LOOP; + WAIT; + END PROCESS; + + p_verify_header : PROCESS(test_offload_sosi) + BEGIN + IF test_offload_sosi.eop = '1' THEN + -- bsn is not fully received (bit 0-15 is missing) because 32 bit allignment not working in dp_offload_rx.vhd. + -- Check fixed settings. + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "eth_dst_mac") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "eth_dst_mac")) = x"00074306C700" + REPORT "wrong eth_dst_mac" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "eth_type") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "eth_type")) = x"0800" + REPORT "wrong eth_type" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_version") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_version")) = TO_UVEC(4, 4) + REPORT "wrong ip_version" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_header_length") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_header_length")) = TO_UVEC(5, 4) + REPORT "wrong ip_header_length" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_services") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_services")) = TO_UVEC(0, 8) + REPORT "wrong ip_services" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_total_length") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_total_length")) = TO_UVEC(7868, 16) + REPORT "wrong ip_total_length" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_identification") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_identification")) = TO_UVEC(0, 16) + REPORT "wrong ip_identification" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_flags") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_flags")) = TO_UVEC(2, 3) + REPORT "wrong ip_flags" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_fragment_offset") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_fragment_offset")) = TO_UVEC(0, 13) + REPORT "wrong ip_fragment_offset" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_time_to_live") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_time_to_live")) = TO_UVEC(127, 8) + REPORT "wrong ip_time_to_live" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_protocol") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_protocol")) = TO_UVEC(17, 8) + REPORT "wrong ip_protocol" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_dst_addr") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_dst_addr")) = x"C0A80001" + REPORT "wrong ip_dst_addr" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "udp_dst_port") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "udp_dst_port")) = TO_UVEC(0, 16) + REPORT "wrong udp_dst_port" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "udp_total_length") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "udp_total_length")) = TO_UVEC(7848, 16) + REPORT "wrong udp_total_length" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_version_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_version_id")) = TO_UVEC(5, 8) + REPORT "wrong sdp_version_id" SEVERITY ERROR; + + -- Check settings set by mm interface in this test bench. + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "eth_src_mac") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "eth_src_mac")) = c_eth_src_mac + REPORT "wrong eth_src_mac" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "ip_src_addr") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_src_addr")) = c_ip_src_addr + REPORT "wrong ip_src_addr" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "udp_src_port") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "udp_src_port")) = c_udp_src_port + REPORT "wrong udp_src_port" SEVERITY ERROR; + + -- Check g_statistics_type settings set by sdp_statistics_offload.vhd. + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_marker") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_marker")) = TO_UVEC(c_marker, 8) + REPORT "wrong sdp_marker" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_signal_inputs") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_signal_inputs")) = TO_UVEC(c_nof_signal_inputs, 8) + REPORT "wrong sdp_nof_signal_inputs" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_nof_statistics_per_packet") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_nof_statistics_per_packet")) = TO_UVEC(c_nof_statistics_per_packet, 16) + REPORT "wrong sdp_nof_statistics_per_packet: " SEVERITY ERROR; + + -- Check some values from sdp_source_info. + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_observation_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_observation_id")) = sdp_info.observation_id + REPORT "wrong sdp_observation_id" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_station_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_station_id")) = sdp_info.station_id + REPORT "wrong sdp_station_id" SEVERITY ERROR; + ASSERT SL(rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_antenna_band_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_antenna_band_id"))) = sdp_info.antenna_band_index + REPORT "wrong sdp_source_info_antenna_band_id" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_nyquist_zone_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_nyquist_zone_id")) = sdp_info.nyquist_zone_index + REPORT "wrong sdp_source_info_nyquist_zone_id" SEVERITY ERROR; + ASSERT SL(rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_f_adc") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_f_adc"))) = sdp_info.f_adc + REPORT "wrong sdp_source_info_f_adc" SEVERITY ERROR; + ASSERT SL(rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_fsub_type") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_fsub_type"))) = sdp_info.fsub_type + REPORT "wrong sdp_source_info_fsub_type" SEVERITY ERROR; + ASSERT SL(rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_beam_repositioning_flag") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_beam_repositioning_flag"))) = sdp_info.beam_repositioning_flag + REPORT "wrong sdp_source_info_beam_repositioning_flag" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_source_info_gn_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_source_info_gn_id")) = TO_UVEC(gn_index, 5) + REPORT "wrong sdp_source_info_gn_id" SEVERITY ERROR; + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_block_period") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_block_period")) = sdp_info.block_period + REPORT "wrong sdp_block_period" SEVERITY ERROR; + + -- Check variable header info. + ASSERT rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "sdp_data_id") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "sdp_data_id")) = TO_UVEC(rx_block_cnt + c_sdp_S_pn * gn_index, 32) + REPORT "wrong block count number, received data_id not same as counted blocks" SEVERITY ERROR; + END IF; + END PROCESS; + + -- Count number of blocks in a sync interval. + -- There is no active test_offload_sosi.sync to restart the count. Therefore capture the in_sosi.sync in in_sync_hold, and + -- use in_sync_hold with test_offload_sosi.sop to start counting blocks (packets) from 0, at the start of every sync interval. + p_rx_block_cnt : PROCESS(dp_clk) + BEGIN + IF rising_edge(dp_clk) THEN + IF test_offload_sosi.sop = '1' THEN + IF in_sync_hold = '1' THEN + rx_block_cnt <= 0; + in_sync_hold <= '0'; + ELSE + rx_block_cnt <= rx_block_cnt + 1; + END IF; + END IF; + IF in_sosi.sync = '1' THEN + in_sync_hold <= '1'; + END IF; + END IF; + END PROCESS; + + -- Capture rx_bsn from header. + rx_bsn <= TO_UINT(rx_hdr_fields_raw(field_hi(c_sdp_stat_hdr_field_arr, "dp_bsn") DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "dp_bsn")+16)); + -- Keep rx_bsn from previous header. + rx_prev_bsn <= rx_bsn WHEN rising_edge(dp_clk); + + -- Verify number of blocks between 2 syncs and between 2 changed bsn numbers. + p_verify_nof_blocks : PROCESS(dp_clk) + BEGIN + IF rising_edge(dp_clk) THEN + IF init_ram_done = '1' THEN + + IF in_sosi.sync = '1' AND rx_block_cnt > 0 THEN + ASSERT rx_block_cnt = g_nof_signal_inputs_per_pn - 1 REPORT "wrong number of blocks between 2 sync" SEVERITY ERROR; + END IF; + + -- rx_prev_bsn > 0 is needed for the first time, when there is no previous BSN. + -- rx_bsn > rx_prev_bsn is needed to detect a new rx_bsn. + IF rx_prev_bsn > 0 AND rx_bsn > rx_prev_bsn THEN + ASSERT (rx_bsn - rx_prev_bsn) = c_nof_block_per_sync REPORT "wrong number of blocks between 2 bsn numbers" SEVERITY ERROR; + END IF; + END IF; + test_offload_siso <= c_dp_siso_rdy; + END IF; + END PROCESS; + + p_verify_nof_valid : PROCESS(dp_clk) + BEGIN + IF rising_edge(dp_clk) THEN + IF test_offload_sosi.sop = '1' THEN + rx_valid_clk_cnt <= 1; + ELSIF test_offload_sosi.eop = '1' THEN + ASSERT rx_valid_clk_cnt = c_nof_valid_per_block REPORT "wrong number of clock counts while valid" SEVERITY ERROR; + ELSE + rx_valid_clk_cnt <= rx_valid_clk_cnt + 1; + END IF; + END IF; + END PROCESS; + + p_mm_offload : PROCESS + BEGIN + proc_common_wait_until_low(mm_clk, mm_rst); + proc_common_wait_some_cycles(mm_clk, 10); + -- Write ethernet destinations via reg_hdr_dat_mosi. + proc_mem_mm_bus_wr(c_hdr_dat_mm_addr_udp_src_port, TO_UINT(c_udp_src_port), mm_clk, hdr_dat_miso, hdr_dat_mosi); + proc_common_wait_some_cycles(mm_clk, c_cross_clock_domain_latency); + + proc_mem_mm_bus_wr(c_hdr_dat_mm_addr_ip_src_addr, TO_UINT(c_ip_src_addr), mm_clk, hdr_dat_miso, hdr_dat_mosi); + proc_common_wait_some_cycles(mm_clk, c_cross_clock_domain_latency); + + proc_mem_mm_bus_wr(c_hdr_dat_mm_addr_eth_src_mac, TO_UINT(c_eth_src_mac), mm_clk, hdr_dat_miso, hdr_dat_mosi); + proc_common_wait_some_cycles(mm_clk, c_cross_clock_domain_latency); + WAIT; + END PROCESS; + + p_dp_end : PROCESS + BEGIN + proc_common_wait_until_high(mm_clk, init_ram_done); + proc_common_wait_some_cycles(dp_clk, c_nof_sync * c_nof_clk_per_sync); -- will show some sync periods + tb_end <= '1'; + WAIT; + END PROCESS; + + u_ram: ENTITY common_lib.common_ram_crw_crw + GENERIC MAP ( + g_ram => c_ram_buf + ) + PORT MAP ( + -- MM write port clock domain. + rst_a => mm_rst, + clk_a => mm_clk, + wr_en_a => ram_wr_en, + wr_dat_a => ram_wr_data, + adr_a => ram_wr_addr, + + -- DP read only port clock domain. + rst_b => dp_rst, + clk_b => dp_clk, + adr_b => master_mosi.address(c_ram_buf.adr_w-1 DOWNTO 0), + rd_en_b => master_mosi.rd, + rd_dat_b => master_miso.rddata(c_ram_buf.dat_w-1 DOWNTO 0), + rd_val_b => master_miso.rdval + ); + + u_rx : ENTITY dp_lib.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => c_word_w, + g_hdr_field_arr => c_sdp_stat_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 => offload_rx_hdr_dat_mosi, + reg_hdr_dat_miso => offload_rx_hdr_dat_miso, + + snk_in_arr(0) => offload_sosi, + snk_out_arr(0) => offload_siso, + + src_out_arr(0) => test_offload_sosi, + src_in_arr(0) => test_offload_siso, + + hdr_fields_out_arr(0) => rx_hdr_fields_out, + hdr_fields_raw_arr(0) => rx_hdr_fields_raw + ); + + -- SDP info + u_dut: ENTITY work.sdp_statistics_offload + GENERIC MAP ( + g_statistics_type => "SST", + g_offload_time => g_offload_time, + g_beamset_id => 0 + ) + PORT MAP ( + mm_clk => mm_clk, + mm_rst => mm_rst, + + dp_clk => dp_clk, + dp_rst => dp_rst, + + master_mosi => master_mosi, + master_miso => master_miso, + + reg_enable_mosi => enable_mosi, + reg_enable_miso => enable_miso, + + reg_hdr_dat_mosi => hdr_dat_mosi, + reg_hdr_dat_miso => hdr_dat_miso, + + sdp_info => sdp_info, + gn_index => gn_index, + + in_sosi => in_sosi, + out_sosi => offload_sosi, + out_siso => offload_siso, + + eth_src_mac => c_eth_src_mac, + udp_src_port => c_udp_src_port, + ip_src_addr => c_ip_src_addr + ); + +END tb; \ No newline at end of file diff --git a/libraries/base/common/src/vhdl/common_variable_delay.vhd b/libraries/base/common/src/vhdl/common_variable_delay.vhd index 847bb54e531d2bc300783c1f2431f25fcef1b97f..8d4c8f65e3be65b5320b083d4d8b57a76b60a48f 100644 --- a/libraries/base/common/src/vhdl/common_variable_delay.vhd +++ b/libraries/base/common/src/vhdl/common_variable_delay.vhd @@ -57,7 +57,7 @@ ARCHITECTURE rtl OF common_variable_delay IS BEGIN out_val <= i_out_val; - p_delay: PROCESS(enable, in_val, prev_in_val, delay, delay_cnt) + p_delay: PROCESS(in_val, prev_in_val, delay, delay_cnt) BEGIN nxt_out_val <= '0'; nxt_delay_cnt <= 0; diff --git a/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd b/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd index 553d7370c4038002aed2b45922052cddf6fff0af..d3b8c961bbbb390ae5ec1ec9d44594e8de8c1a97 100644 --- a/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd +++ b/libraries/base/dp/src/vhdl/dp_block_from_mm.vhd @@ -42,7 +42,7 @@ ENTITY dp_block_from_mm IS rst : IN STD_LOGIC; clk : IN STD_LOGIC; start_pulse : IN STD_LOGIC; - start_address : IN NATURAL RANGE 0 TO g_step_size * g_nof_data; + start_address : IN NATURAL; mm_done : OUT STD_LOGIC; mm_mosi : OUT t_mem_mosi; mm_miso : IN t_mem_miso; @@ -72,7 +72,7 @@ ARCHITECTURE rtl OF dp_block_from_mm IS SIGNAL last_mm_address : NATURAL := 0; BEGIN - last_mm_address <= g_step_size * (g_nof_data - 1) + g_data_size + start_address; + last_mm_address <= g_step_size * (g_nof_data - 1) + g_data_size + start_address - 1; mm_address <= start_address + r.word_index + r.step_index; mm_mosi.address <= TO_MEM_ADDRESS(mm_address); @@ -82,7 +82,7 @@ BEGIN out_sosi.sop <= r.sop; -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.sop can be used for output sop out_sosi.eop <= r.eop; -- read latency from mm_mosi.rd to mm_miso.rdval is 1, so r.eop can be used for output eop - mm_done <= d.eop; + mm_done <= r.eop; p_reg : PROCESS(rst, clk) BEGIN diff --git a/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd b/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd index 8313c467f3690c236eba85393fec21351941cb2d..10eba26202abd8eafd39ac04b3387b9c67b77117 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_block_from_mm.vhd @@ -59,10 +59,10 @@ END tb_dp_block_from_mm; ARCHITECTURE tb OF tb_dp_block_from_mm IS CONSTANT c_nof_blocks : NATURAL := g_step_size / g_data_size; - CONSTANT c_ram_data_size : NATURAL := g_nof_data * g_data_size * c_nof_blocks; + CONSTANT c_ram_data_size : NATURAL := g_nof_data * g_data_size * c_nof_blocks + g_data_size; -- Size is g_data_size addresses more than needed, to check for oversized blocks. CONSTANT c_ram_adr_w : NATURAL := ceil_log2(c_ram_data_size); - CONSTANT c_ram : t_c_mem := (1, c_ram_adr_w, c_word_w, 2**c_ram_adr_w, '0'); + CONSTANT c_ram : t_c_mem := (1, c_ram_adr_w, c_word_w, 2**c_ram_adr_w, '0'); SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL clk : STD_LOGIC := '1'; @@ -83,16 +83,22 @@ ARCHITECTURE tb OF tb_dp_block_from_mm IS SIGNAL wr_miso : t_mem_miso; -- needed for init and verify - SIGNAL ram_wr_en : STD_LOGIC := '0'; - SIGNAL ram_wr_adr : STD_LOGIC_VECTOR(c_ram.adr_w-1 DOWNTO 0) := (OTHERS=>'0'); - SIGNAL ram_wr_dat : STD_LOGIC_VECTOR(c_ram.dat_w-1 DOWNTO 0) := (OTHERS=>'0'); - SIGNAL ram_rd_en : STD_LOGIC := '0'; - SIGNAL ram_rd_adr : STD_LOGIC_VECTOR(c_ram.adr_w-1 DOWNTO 0); - SIGNAL ram_rd_dat : STD_LOGIC_VECTOR(c_ram.dat_w-1 DOWNTO 0); - SIGNAL ram_rd_val : STD_LOGIC; - - SIGNAL init_done : STD_LOGIC := '0'; - SIGNAL transfer_done : STD_LOGIC := '0'; + SIGNAL ram_wr_en : STD_LOGIC := '0'; + SIGNAL ram_wr_adr : STD_LOGIC_VECTOR(c_ram.adr_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL ram_wr_dat : STD_LOGIC_VECTOR(c_ram.dat_w-1 DOWNTO 0) := (OTHERS=>'0'); + SIGNAL ram_rd_en : STD_LOGIC := '0'; + SIGNAL ram_rd_adr : STD_LOGIC_VECTOR(c_ram.adr_w-1 DOWNTO 0); + SIGNAL ram_rd_dat : STD_LOGIC_VECTOR(c_ram.dat_w-1 DOWNTO 0); + SIGNAL ram_rd_val : STD_LOGIC; + SIGNAL ram_prev_rd_val : STD_LOGIC; + + SIGNAL rd_nxt_data : NATURAL := 0; + SIGNAL rd_data : NATURAL := 0; + + SIGNAL stop_address : NATURAL := 0; + + SIGNAL init_done : STD_LOGIC := '0'; + SIGNAL transfer_done : STD_LOGIC := '0'; BEGIN @@ -110,7 +116,7 @@ BEGIN ram_wr_en <= '0'; proc_common_wait_until_low(clk, rst); proc_common_wait_some_cycles(clk, 10); - FOR i IN 0 TO c_ram_data_size-1 LOOP + FOR i IN 0 TO c_ram_data_size - 1 LOOP ram_wr_adr <= TO_UVEC(i, c_ram.adr_w); ram_wr_dat <= TO_UVEC(i, c_ram.dat_w); ram_wr_en <= '1'; @@ -128,25 +134,39 @@ BEGIN start_address <= 0; proc_common_wait_until_high(clk, init_done); FOR i IN 0 TO c_nof_blocks-1 LOOP - start_address <= i * g_data_size; + start_address <= i * g_data_size; + start_pulse <= '1'; proc_common_wait_some_cycles(clk, 1); - start_pulse <= '0'; + + stop_address <= start_address + (g_nof_data - 1) * g_step_size + g_data_size - 1; proc_common_wait_until_high(clk, block_done); END LOOP; - proc_common_wait_some_cycles(clk, 1); -- needed for dp_block_to_mm to proccess last word. + proc_common_wait_some_cycles(clk, 1); -- Needed for dp_block_to_mm to proccess last word. transfer_done <= '1'; WAIT; END PROCESS; - p_verify_read : PROCESS + p_verify_transfer : PROCESS + BEGIN + proc_common_wait_until_high(clk, init_done); + WHILE tb_end = '0' LOOP + WAIT UNTIL rising_edge(clk); + IF block_done = '1' THEN + ASSERT stop_address = TO_UINT(wr_mosi.wrdata(c_ram.dat_w-1 DOWNTO 0)) REPORT "wrong data at mm_done signal, must be same as stop_address" SEVERITY ERROR; + END IF; + END LOOP; + WAIT; + END PROCESS; + + p_read_ram : PROCESS BEGIN ram_rd_en <= '0'; ram_rd_adr <= TO_UVEC(0 , c_ram.adr_w); proc_common_wait_until_high(clk, transfer_done); ram_rd_en <= '1'; - FOR i IN 0 TO c_ram_data_size-1 LOOP + FOR i IN 0 TO c_ram_data_size - 1 LOOP ram_rd_adr <= TO_UVEC(i, c_ram.adr_w); proc_common_wait_some_cycles(clk, 1); END LOOP; @@ -157,15 +177,24 @@ BEGIN WAIT; END PROCESS; - p_verify_check: PROCESS - VARIABLE v_cnt: NATURAL := 0; + ram_prev_rd_val <= ram_rd_val WHEN rising_edge(clk); + + p_verify_read_ram_data: PROCESS BEGIN + rd_nxt_data <= 1; proc_common_wait_until_high(clk, transfer_done); WHILE tb_end = '0' LOOP WAIT UNTIL rising_edge(clk); - IF ram_rd_val = '1' THEN - ASSERT v_cnt = TO_UINT(ram_rd_dat) REPORT "RAM values not equal" SEVERITY ERROR; - v_cnt := v_cnt + 1; + rd_data <= TO_UINT(ram_rd_dat); + IF rd_data > 0 THEN + IF ram_rd_val = '1' THEN + ASSERT rd_data = rd_nxt_data REPORT "wrong order of RAM values" SEVERITY ERROR; + ASSERT rd_data <= stop_address REPORT "wrong RAM values, greater then block size" SEVERITY ERROR; + rd_nxt_data <= rd_nxt_data + 1; + END IF; + IF ram_rd_val = '0' AND ram_prev_rd_val = '1' THEN -- If ram_rd_val goes from hi tot lo. + ASSERT rd_data = stop_address REPORT "wrong last RAM values, not same as block size" SEVERITY ERROR; + END IF; END IF; END LOOP; WAIT;