diff --git a/applications/lofar2/libraries/sdp/hdllib.cfg b/applications/lofar2/libraries/sdp/hdllib.cfg index bc0e30b24863c2e0ddcb8ae42b731be1fde5d120..25f8a6fd36cebf53d125124a3df4b81779deaf8a 100644 --- a/applications/lofar2/libraries/sdp/hdllib.cfg +++ b/applications/lofar2/libraries/sdp/hdllib.cfg @@ -1,22 +1,23 @@ hdl_lib_name = lofar2_sdp hdl_library_clause_name = lofar2_sdp_lib hdl_lib_uses_synth = common dp wpfb rTwoSDF filter si st reorder technology tech_pll mm dp diag aduh tech_jesd204b nw_10GbE eth ring -hdl_lib_uses_sim = -hdl_lib_technology = +hdl_lib_uses_sim = +hdl_lib_technology = -synth_files = - src/vhdl/sdp_pkg.vhd +synth_files = + src/vhdl/sdp_pkg.vhd src/vhdl/sdp_scope.vhd src/vhdl/sdp_subband_weights.vhd src/vhdl/sdp_subband_equalizer.vhd - src/vhdl/sdp_bf_weights.vhd - src/vhdl/sdp_beamformer_local.vhd - src/vhdl/sdp_beamformer_remote.vhd - 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/sdp_crosslets_subband_select.vhd + src/vhdl/sdp_bf_weights.vhd + src/vhdl/sdp_beamformer_local.vhd + src/vhdl/sdp_beamformer_remote.vhd + src/vhdl/sdp_info_reg.vhd + src/vhdl/sdp_info.vhd + src/vhdl/sdp_bdo_destinations_reg.vhd + src/vhdl/sdp_beamformer_output.vhd + src/vhdl/sdp_statistics_offload.vhd + src/vhdl/sdp_crosslets_subband_select.vhd src/vhdl/node_sdp_adc_input_and_timing.vhd src/vhdl/node_sdp_filterbank.vhd src/vhdl/node_sdp_oversampled_filterbank.vhd @@ -29,13 +30,13 @@ test_bench_files = tb/vhdl/tb_sdp_info.vhd tb/vhdl/tb_sdp_statistics_offload.vhd tb/vhdl/tb_tb_sdp_statistics_offload.vhd - tb/vhdl/tb_sdp_crosslets_subband_select.vhd + tb/vhdl/tb_sdp_crosslets_subband_select.vhd -regression_test_vhdl = +regression_test_vhdl = tb/vhdl/tb_sdp_info.vhd - tb/vhdl/tb_sdp_statistics_offload.vhd + tb/vhdl/tb_sdp_statistics_offload.vhd tb/vhdl/tb_tb_sdp_statistics_offload.vhd - tb/vhdl/tb_sdp_crosslets_subband_select.vhd + tb/vhdl/tb_sdp_crosslets_subband_select.vhd [modelsim_project_file] diff --git a/applications/lofar2/libraries/sdp/sdp.peripheral.yaml b/applications/lofar2/libraries/sdp/sdp.peripheral.yaml index 73acf210efb3dbed285dc6417e3f2e7748f82d5e..a01fbaaebaeaf21ac8997e87e675f9576b8dd118 100644 --- a/applications/lofar2/libraries/sdp/sdp.peripheral.yaml +++ b/applications/lofar2/libraries/sdp/sdp.peripheral.yaml @@ -27,7 +27,7 @@ peripherals: - - { field_name: block_period, mm_width: 16, access_mode: RO, address_offset: 0x0 } - - peripheral_name: sdp_crosslets_subband_select # pi_sdp_crosslets_info.py + - peripheral_name: sdp_crosslets_subband_select # pi_sdp_crosslets_info.py peripheral_description: "SDP crosslets info." mm_ports: # MM port for sdp_info.vhd @@ -35,15 +35,15 @@ peripherals: mm_port_type: REG mm_port_span: 16 * MM_BUS_SIZE mm_port_description: | - "The SDP crosslets info contains the step size and 15 offsets, that are used to select a new + "The SDP crosslets info contains the step size and 15 offsets, that are used to select a new crosslet subband for every integration interval" fields: - - { field_name: step, access_mode: RW, address_offset: 0x3C } - - field_name: offset - number_of_fields: 15 + number_of_fields: 15 address_offset: 0x0 - - peripheral_name: sdp_nof_crosslets # pi_sdp_nof_crosslets.py + - peripheral_name: sdp_nof_crosslets # pi_sdp_nof_crosslets.py peripheral_description: "SDP nof crosslets." mm_ports: - mm_port_name: REG_NOF_CROSSLETS @@ -104,7 +104,7 @@ peripherals: - peripheral_name: sdp_bf_weights # pi_sdp_bf_weights.py - peripheral_description: "SDP Beamformer weights (= beamlet weights)." + peripheral_description: "SDP Beamformer (BF) weights (= beamlet weights)." parameters: # Parameters of pi_sdp_bf_weights.py, fixed in sdp_bf_weights.vhd / sdp_pkg.vhd - { name: N_pol_bf, value: 2 } @@ -155,7 +155,7 @@ peripherals: - peripheral_name: sdp_bf_scale # pi_sdp_bf_scale.py - peripheral_description: "SDP BF beamlet data output scaling and requantization." + peripheral_description: "SDP beamlet data output (BDO) scaling and requantization." parameters: # Parameters fixed in node_sdp_beamformer.vhd / mms_dp_scale.vhd / sdp_pkg.vhd - { name: g_gain_w, value: 16 } @@ -190,8 +190,35 @@ peripherals: address_offset: 0x4 + - peripheral_name: sdp_bdo_destinations + peripheral_description: "SDP beamlet data output (BDO) destinations." + parameters: + # Parameters fixed in sdp_beamformer_output.vhd / sdp_pkg.vhd + - { name: N_destinations_max, value: 16 } + - { name: N_reorder_blocks_max, value: 16 } + mm_ports: + # MM port for sdp_beamformer_output.vhd / mm_fields.vhd + - mm_port_name: REG_BDO_DESTINATIONS + mm_port_type: REG + mm_port_span: 16 * MM_BUS_SIZE + mm_port_description: | + "The SDP beamlets in a beamset can be send to 1 or multiple destinations, each identified + by destination MAC addess, IP address and UDP port. + The number of destinations is 1 <= nof_destinations <= N_destinations_max. + The number of blocks per packet is nof_blocks_per_packet <= N_reorder_blocks_max / nof_destinations. + The actual nof_blocks_per_packet and nof_destinations is reported via the corresponding _act fields." + fields: + - - { field_name: eth_destination_mac, number_of_fields: N_destinations_max, mm_width: 32, user_width: 48, radix: uint64, access_mode: RW, address_offset: 0x0 } + - - { field_name: ip_destination_address, number_of_fields: N_destinations_max, mm_width: 32, access_mode: RW, address_offset: 0x80 } + - - { field_name: udp_destination_port, number_of_fields: N_destinations_max, mm_width: 16, access_mode: RW, address_offset: 0xC0 } + - - { field_name: nof_destinations, mm_width: 8, access_mode: RW, address_offset: 0x100 } + - - { field_name: nof_destinations_act, mm_width: 8, access_mode: RW, address_offset: 0x104 } + - - { field_name: nof_blocks_per_packet, mm_width: 8, access_mode: RW, address_offset: 0x108 } + - - { field_name: nof_blocks_per_packet_act, mm_width: 8, access_mode: RW, address_offset: 0x10C } + + - peripheral_name: sdp_beamformer_output_hdr_dat # pi_dp_offload_tx_hdr_dat_lofar2_beamformer_output.py - peripheral_description: "SDP BF beamlet data output header." + peripheral_description: "SDP beamlet data output (BDO) header." mm_ports: # MM port for sdp_beamformer_output.vhd / dp_offload_tx_v3.vhd - mm_port_name: REG_DP_OFFLOAD_TX_HDR_DAT diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e049c553ec1b3b2568c67431e46c2dfe77292694 --- /dev/null +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_bdo_destinations_reg.vhd @@ -0,0 +1,235 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- +-- +-- Author: E. Kooistra +-- Purpose: +-- . SDP beamlet data output (BDO) destinations register +-- Description: +-- _________ +-- |mm_fields| +-- | | +-- reg_copi -->| slv_out|------- _wr ---- +-- reg_cipo <--| | | +-- | | v +-- | slv_in|<--+--- _rd <--+<---- _ro +-- |_________| | +-- -----------------> output value +-- +-- where: +-- . _ro = parsed_nof_destinations, parsed_nof_blocks_per_packet +-- . output value = sdp_bdo_destinations +-- +-- References: +-- 1 https://plm.astron.nl/polarion/#/project/LOFAR2System/wiki/L2%20Interface%20Control%20Documents/SC%20to%20SDP%20ICD +-- 2 https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Multiple+beamlet+output+destinations +-- + +library IEEE, common_lib, mm_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 work.sdp_pkg.all; + +entity sdp_bdo_destinations_reg is + port ( + -- Clocks and reset + mm_rst : in std_logic; + mm_clk : in std_logic; + + dp_clk : in std_logic; + dp_rst : in std_logic; + + reg_copi : in t_mem_copi; + reg_cipo : out t_mem_cipo; + + -- sdp info + sdp_bdo_destinations : out t_sdp_bdo_destinations_info + ); +end sdp_bdo_destinations_reg; + +architecture str of sdp_bdo_destinations_reg is + constant c_field_arr : t_common_field_arr(c_sdp_bdo_destinations_info_nof_hdr_fields - 1 downto 0) := + ( (field_name_pad("nof_blocks_per_packet_act"), "RO", 8, field_default(c_sdp_cep_nof_blocks_per_packet)), + (field_name_pad("nof_blocks_per_packet"), "RW", 8, field_default(c_sdp_cep_nof_blocks_per_packet)), + (field_name_pad("nof_destinations_act"), "RO", 8, field_default(1)), + (field_name_pad("nof_destinations"), "RW", 8, field_default(1)), + + (field_name_pad("udp_destination_port_15"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_14"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_13"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_12"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_11"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_10"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_9"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_8"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_7"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_6"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_5"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_4"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_3"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_2"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_1"), "RW", 16, field_default(0)), + (field_name_pad("udp_destination_port_0"), "RW", 16, field_default(0)), + + (field_name_pad("ip_destination_address_15"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_14"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_13"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_12"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_11"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_10"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_9"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_8"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_7"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_6"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_5"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_4"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_3"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_2"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_1"), "RW", 32, field_default(0)), + (field_name_pad("ip_destination_address_0"), "RW", 32, field_default(0)), + + (field_name_pad("eth_destination_mac_15"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_14"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_13"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_12"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_11"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_10"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_9"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_8"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_7"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_6"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_5"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_4"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_3"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_2"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_1"), "RW", 48, field_default(0)), + (field_name_pad("eth_destination_mac_0"), "RW", 48, field_default(0)) ); + + signal mm_fields_in : std_logic_vector(field_slv_in_len(c_field_arr) - 1 downto 0); + signal mm_fields_out : std_logic_vector(field_slv_out_len(c_field_arr) - 1 downto 0); + + signal sdp_bdo_destinations_rd : t_sdp_bdo_destinations_info; + signal sdp_bdo_destinations_wr : t_sdp_bdo_destinations_info; + + signal parsed_nof_destinations : natural; + signal parsed_nof_blocks_per_packet : natural; +begin + sdp_bdo_destinations <= sdp_bdo_destinations_rd; + + p_sdp_bdo_destinations_rd : process(sdp_bdo_destinations_wr, + parsed_nof_destinations, + parsed_nof_blocks_per_packet) + begin + -- default write assign all fields + sdp_bdo_destinations_rd <= sdp_bdo_destinations_wr; + + -- overrule the read only fields + sdp_bdo_destinations_rd.nof_destinations_act <= parsed_nof_destinations; + sdp_bdo_destinations_rd.nof_blocks_per_packet_act <= parsed_nof_blocks_per_packet; + end process; + + u_mm_fields: entity mm_lib.mm_fields + generic map( + g_use_slv_in_val => false, -- use FALSE to save logic when always slv_in_val='1' + g_field_arr => c_field_arr + ) + port map ( + mm_clk => mm_clk, + mm_rst => mm_rst, + + mm_mosi => reg_copi, + mm_miso => reg_cipo, + + slv_clk => dp_clk, + slv_rst => dp_rst, + + slv_in => mm_fields_in, + slv_in_val => '1', + + slv_out => mm_fields_out + ); + + -- add "RO" fields to mm_fields + mm_fields_in(field_hi(c_field_arr, "nof_destinations_act") downto field_lo(c_field_arr, "nof_destinations_act")) <= to_uvec(sdp_bdo_destinations_rd.nof_destinations_act, 8); + mm_fields_in(field_hi(c_field_arr, "nof_blocks_per_packet_act") downto field_lo(c_field_arr, "nof_blocks_per_packet_act")) <= to_uvec(sdp_bdo_destinations_rd.nof_blocks_per_packet_act, 8); + + -- get "RW" fields from mm_fields + sdp_bdo_destinations_wr.eth_destination_mac_arr(0) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_0") downto field_lo(c_field_arr, "eth_destination_mac_0")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(1) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_1") downto field_lo(c_field_arr, "eth_destination_mac_1")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(2) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_2") downto field_lo(c_field_arr, "eth_destination_mac_2")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(3) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_3") downto field_lo(c_field_arr, "eth_destination_mac_3")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(4) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_4") downto field_lo(c_field_arr, "eth_destination_mac_4")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(5) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_5") downto field_lo(c_field_arr, "eth_destination_mac_5")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(6) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_6") downto field_lo(c_field_arr, "eth_destination_mac_6")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(7) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_7") downto field_lo(c_field_arr, "eth_destination_mac_7")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(8) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_8") downto field_lo(c_field_arr, "eth_destination_mac_8")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(9) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_9") downto field_lo(c_field_arr, "eth_destination_mac_9")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(10) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_10") downto field_lo(c_field_arr, "eth_destination_mac_10")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(11) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_11") downto field_lo(c_field_arr, "eth_destination_mac_11")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(12) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_12") downto field_lo(c_field_arr, "eth_destination_mac_12")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(13) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_13") downto field_lo(c_field_arr, "eth_destination_mac_13")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(14) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_14") downto field_lo(c_field_arr, "eth_destination_mac_14")); + sdp_bdo_destinations_wr.eth_destination_mac_arr(15) <= mm_fields_out(field_hi(c_field_arr, "eth_destination_mac_15") downto field_lo(c_field_arr, "eth_destination_mac_15")); + + sdp_bdo_destinations_wr.ip_destination_address_arr(0) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_0") downto field_lo(c_field_arr, "ip_destination_address_0")); + sdp_bdo_destinations_wr.ip_destination_address_arr(1) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_1") downto field_lo(c_field_arr, "ip_destination_address_1")); + sdp_bdo_destinations_wr.ip_destination_address_arr(2) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_2") downto field_lo(c_field_arr, "ip_destination_address_2")); + sdp_bdo_destinations_wr.ip_destination_address_arr(3) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_3") downto field_lo(c_field_arr, "ip_destination_address_3")); + sdp_bdo_destinations_wr.ip_destination_address_arr(4) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_4") downto field_lo(c_field_arr, "ip_destination_address_4")); + sdp_bdo_destinations_wr.ip_destination_address_arr(5) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_5") downto field_lo(c_field_arr, "ip_destination_address_5")); + sdp_bdo_destinations_wr.ip_destination_address_arr(6) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_6") downto field_lo(c_field_arr, "ip_destination_address_6")); + sdp_bdo_destinations_wr.ip_destination_address_arr(7) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_7") downto field_lo(c_field_arr, "ip_destination_address_7")); + sdp_bdo_destinations_wr.ip_destination_address_arr(8) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_8") downto field_lo(c_field_arr, "ip_destination_address_8")); + sdp_bdo_destinations_wr.ip_destination_address_arr(9) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_9") downto field_lo(c_field_arr, "ip_destination_address_9")); + sdp_bdo_destinations_wr.ip_destination_address_arr(10) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_10") downto field_lo(c_field_arr, "ip_destination_address_10")); + sdp_bdo_destinations_wr.ip_destination_address_arr(11) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_11") downto field_lo(c_field_arr, "ip_destination_address_11")); + sdp_bdo_destinations_wr.ip_destination_address_arr(12) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_12") downto field_lo(c_field_arr, "ip_destination_address_12")); + sdp_bdo_destinations_wr.ip_destination_address_arr(13) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_13") downto field_lo(c_field_arr, "ip_destination_address_13")); + sdp_bdo_destinations_wr.ip_destination_address_arr(14) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_14") downto field_lo(c_field_arr, "ip_destination_address_14")); + sdp_bdo_destinations_wr.ip_destination_address_arr(15) <= mm_fields_out(field_hi(c_field_arr, "ip_destination_address_15") downto field_lo(c_field_arr, "ip_destination_address_15")); + + sdp_bdo_destinations_wr.udp_destination_port_arr(0) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_0") downto field_lo(c_field_arr, "udp_destination_port_0")); + sdp_bdo_destinations_wr.udp_destination_port_arr(1) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_1") downto field_lo(c_field_arr, "udp_destination_port_1")); + sdp_bdo_destinations_wr.udp_destination_port_arr(2) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_2") downto field_lo(c_field_arr, "udp_destination_port_2")); + sdp_bdo_destinations_wr.udp_destination_port_arr(3) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_3") downto field_lo(c_field_arr, "udp_destination_port_3")); + sdp_bdo_destinations_wr.udp_destination_port_arr(4) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_4") downto field_lo(c_field_arr, "udp_destination_port_4")); + sdp_bdo_destinations_wr.udp_destination_port_arr(5) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_5") downto field_lo(c_field_arr, "udp_destination_port_5")); + sdp_bdo_destinations_wr.udp_destination_port_arr(6) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_6") downto field_lo(c_field_arr, "udp_destination_port_6")); + sdp_bdo_destinations_wr.udp_destination_port_arr(7) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_7") downto field_lo(c_field_arr, "udp_destination_port_7")); + sdp_bdo_destinations_wr.udp_destination_port_arr(8) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_8") downto field_lo(c_field_arr, "udp_destination_port_8")); + sdp_bdo_destinations_wr.udp_destination_port_arr(9) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_9") downto field_lo(c_field_arr, "udp_destination_port_9")); + sdp_bdo_destinations_wr.udp_destination_port_arr(10) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_10") downto field_lo(c_field_arr, "udp_destination_port_10")); + sdp_bdo_destinations_wr.udp_destination_port_arr(11) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_11") downto field_lo(c_field_arr, "udp_destination_port_11")); + sdp_bdo_destinations_wr.udp_destination_port_arr(12) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_12") downto field_lo(c_field_arr, "udp_destination_port_12")); + sdp_bdo_destinations_wr.udp_destination_port_arr(13) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_13") downto field_lo(c_field_arr, "udp_destination_port_13")); + sdp_bdo_destinations_wr.udp_destination_port_arr(14) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_14") downto field_lo(c_field_arr, "udp_destination_port_14")); + sdp_bdo_destinations_wr.udp_destination_port_arr(15) <= mm_fields_out(field_hi(c_field_arr, "udp_destination_port_15") downto field_lo(c_field_arr, "udp_destination_port_15")); + + sdp_bdo_destinations_wr.nof_destinations <= to_uint(mm_fields_out(field_hi(c_field_arr, "nof_destinations") downto field_lo(c_field_arr, "nof_destinations"))); + sdp_bdo_destinations_wr.nof_blocks_per_packet <= to_uint(mm_fields_out(field_hi(c_field_arr, "nof_blocks_per_packet") downto field_lo(c_field_arr, "nof_blocks_per_packet"))); + + parsed_nof_destinations <= func_sdp_parse_nof_destinations( + sdp_bdo_destinations_wr.nof_destinations); + + parsed_nof_blocks_per_packet <= func_sdp_parse_nof_blocks_per_packet( + sdp_bdo_destinations_wr.nof_blocks_per_packet, + sdp_bdo_destinations_wr.nof_destinations); +end str; diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd index da3ee350e94f7478d7f0713fcf9e93deeb3252ce..3d44aca5cadcfa188ef7cea9b0c057b489cdb02f 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_pkg.vhd @@ -112,7 +112,9 @@ package sdp_pkg is constant c_sdp_W_local_oscillator : natural := 16; -- = w in s(w, p), s = signed constant c_sdp_W_local_oscillator_fraction : natural := 15; -- = p in s(w, p) constant c_sdp_W_local_oscillator_magnitude : natural := c_sdp_W_local_oscillator - c_sdp_W_local_oscillator_fraction - 1; -- = 0 - constant c_sdp_N_ring_nof_mac10g : natural := 3; -- for sdp_station_xsub_ring design. + constant c_sdp_N_ring_nof_mac10g : natural := 3; -- for sdp_station_xsub_ring design. + constant c_sdp_N_bdo_nof_destinations_max : natural := 16; + constant c_sdp_N_bdo_reorder_nof_blocks_max : natural := 16; -- Derived constants constant c_sdp_FS_adc : natural := 2**(c_sdp_W_adc - 1); -- full scale FS corresponds to amplitude 1.0, will just cause clipping of +FS to +FS-1 @@ -401,7 +403,7 @@ package sdp_pkg is end record; ----------------------------------------------------------------------------- - -- Beamlet output via 10GbE to CEP (= central processor, see ICD STAT-CEP) + -- Beamlet data output (BDO) via 10GbE to CEP (= central processor, see ICD STAT-CEP) ----------------------------------------------------------------------------- constant c_sdp_cep_version_id : natural := 5; constant c_sdp_marker_beamlets : natural := 98; -- = x"62" = 'b' @@ -424,6 +426,43 @@ package sdp_pkg is constant c_sdp_cep_payload_nof_longwords : natural := c_sdp_cep_nof_beamlets_per_packet / c_sdp_nof_beamlets_per_longword; -- = 976 constant c_sdp_cep_packet_nof_longwords : natural := ceil_div(c_sdp_cep_header_len, c_longword_sz) + c_sdp_cep_payload_nof_longwords; -- without tail CRC, the CRC is applied by 10GbE MAC + -- Beamlet data output (BDO) multiple destinations + constant c_sdp_bdo_destinations_info_nof_hdr_fields : natural := c_sdp_N_bdo_nof_destinations_max * 3 + 4; -- = 52 fields + + type t_sdp_bdo_destinations_info is record + eth_destination_mac_arr : t_slv_48_arr(c_sdp_N_bdo_nof_destinations_max - 1 downto 0); + ip_destination_address_arr : t_slv_32_arr(c_sdp_N_bdo_nof_destinations_max - 1 downto 0); + udp_destination_port_arr : t_slv_16_arr(c_sdp_N_bdo_nof_destinations_max - 1 downto 0); + nof_destinations : natural; + nof_destinations_act : natural; + nof_blocks_per_packet : natural; + nof_blocks_per_packet_act : natural; + end record; + + constant t_sdp_bdo_destinations_info_rst : t_sdp_bdo_destinations_info := + ( (others => (others => '0')), + (others => (others => '0')), + (others => (others => '0')), 0, 0, 0, 0 ); + + -- Determine maximum nof_blocks_per_packet as function of nof_destinations: + -- . Use same number of nof_blocks_per_packet for each destination. + -- . In total there are maximum c_sdp_N_bdo_reorder_nof_blocks_max = 16 blocks to + -- distribute over N destinations, so floor(16 / N) per destination yields: + -- N = 1:16 --> 16, 8, 5, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 + -- . With 1 destination c_sdp_cep_nof_blocks_per_packet = 4 can fit in a jumbo frame. + -- . With N destinations N * c_sdp_cep_nof_blocks_per_packet can fit in a jumbo frame, + -- because the number of beamlets per destination reduces by N. + -- N = 1:16 --> 4 * [1, 2, 3, 4, 5 ,6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + -- . Taking smallest yields the actual maximum number of blocks per packet + -- per destination, as function of nof_destinations N: + -- N = 1:16 --> 4, 8, 5, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 + constant c_sdp_nof_blocks_per_packet_max_per_destination_arr : t_natural_arr(1 to c_sdp_N_bdo_nof_destinations_max) := + (4, 8, 5, 4, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1); + + function func_sdp_parse_nof_destinations(nof_destinations : natural) return natural; + function func_sdp_parse_nof_blocks_per_packet(nof_blocks_per_packet, nof_destinations : natural) return natural; + + -- CEP packet header constant c_sdp_cep_nof_hdr_fields : natural := 3 + 12 + 4 + 4 + 9 + 6 + 1; -- = 39 fields -- c_sdp_cep_header_len / c_longword_sz = 74 / 8 = 9.25 64b words = 592b -- hdr_field_sel bit selects where the hdr_field value is set: @@ -689,7 +728,6 @@ package sdp_pkg is function func_sdp_map_crosslets_info(info_slv : std_logic_vector) return t_sdp_crosslets_info; -- map all c_sdp_N_crosslets_max offsets function func_sdp_map_crosslets_info(info_rec : t_sdp_crosslets_info) return std_logic_vector; -- map all c_sdp_N_crosslets_max offsets function func_sdp_step_crosslets_info(info_rec : t_sdp_crosslets_info) return t_sdp_crosslets_info; -- step all c_sdp_N_crosslets_max offsets - end package sdp_pkg; package body sdp_pkg is @@ -1007,4 +1045,27 @@ package body sdp_pkg is return v_info; end func_sdp_step_crosslets_info; + function func_sdp_parse_nof_destinations(nof_destinations : natural) return natural is + begin + if nof_destinations = 0 then + return 1; + elsif nof_destinations > c_sdp_N_bdo_nof_destinations_max then + return c_sdp_N_bdo_nof_destinations_max; + else + return nof_destinations; + end if; + end func_sdp_parse_nof_destinations; + + function func_sdp_parse_nof_blocks_per_packet(nof_blocks_per_packet, nof_destinations : natural) return natural is + constant c_nof_blocks_per_packet_max : natural := c_sdp_nof_blocks_per_packet_max_per_destination_arr(nof_destinations); + begin + if nof_blocks_per_packet = 0 then + return 1; + elsif nof_blocks_per_packet > c_nof_blocks_per_packet_max then + return c_nof_blocks_per_packet_max; + else + return nof_blocks_per_packet; + end if; + end func_sdp_parse_nof_blocks_per_packet; + end sdp_pkg;