-
Eric Kooistra authoredEric Kooistra authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
sdp_statistics_offload.vhd 17.25 KiB
-------------------------------------------------------------------------------
--
-- 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, R van der Walle
-- 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 := c_sdp_offload_time;
g_beamset_id : NATURAL := 0;
g_P_sq : NATURAL := c_sdp_P_sq -- use generic to support P_sq = 1 for one node and P_sq = c_sdp_P_sq for multiple nodes (with ring)
);
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;
subband_calibrated_flag : IN STD_LOGIC := '0';
crosslets_info : IN STD_LOGIC_VECTOR(c_sdp_crosslets_info_reg_w-1 DOWNTO 0) := (OTHERS => '0');
gn_index : IN NATURAL
);
END sdp_statistics_offload;
ARCHITECTURE str OF sdp_statistics_offload IS
CONSTANT c_nof_streams : NATURAL := 1;
CONSTANT c_data_size : NATURAL := 2;
CONSTANT c_nof_data_per_step : NATURAL := 2;
CONSTANT c_step_size : NATURAL := sel_a_b(g_statistics_type="BST", c_data_size,
sel_a_b(g_statistics_type="XST", c_data_size,
c_data_size * c_nof_data_per_step)); -- SST
CONSTANT c_nof_data : NATURAL := sel_a_b(g_statistics_type="BST", c_sdp_N_pol_bf * 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_block_size : NATURAL := c_nof_data * c_step_size;
CONSTANT c_nof_packets : NATURAL := sel_a_b(g_statistics_type="BST", 1,
sel_a_b(g_statistics_type="XST", g_P_sq,
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_N_pol_bf * 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;
CONSTANT c_app_total_length : NATURAL := c_sdp_stat_app_header_len + c_nof_data * c_longword_sz;
CONSTANT c_udp_total_length : NATURAL := c_app_total_length + c_network_udp_header_len;
CONSTANT c_ip_total_length : NATURAL := c_app_total_length + c_network_udp_header_len + c_network_ip_header_len;
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;
integration_interval : NATURAL;
END RECORD;
CONSTANT c_reg_rst : t_reg := (0, 0, '0', (OTHERS => '0'), (OTHERS => '0'), 0, '0', 0, 0);
SIGNAL r : t_reg;
SIGNAL nxt_r : t_reg;
SIGNAL trigger : STD_LOGIC := '0';
SIGNAL 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_offload_snk_in : t_dp_sosi;
SIGNAL dp_offload_snk_out : t_dp_siso;
SIGNAL dp_header_info : STD_LOGIC_VECTOR(1023 DOWNTO 0):= (OTHERS => '0');
SIGNAL bsn_at_sync : STD_LOGIC_VECTOR(63 DOWNTO 0) := (OTHERS => '0');
SIGNAL selected_crosslet : STD_LOGIC_VECTOR(c_sdp_crosslets_index_w-1 DOWNTO 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';
selected_crosslet <= crosslets_info(c_sdp_crosslets_index_w-1 DOWNTO 0);
-------------------------------------------------------------------------------
-- 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, "ip_total_length" ) DOWNTO field_lo(c_sdp_stat_hdr_field_arr, "ip_total_length" )) <= TO_UVEC(c_ip_total_length, 16);
dp_header_info(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(c_udp_total_length, 16);
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(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(r.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 <= nxt_r;
END IF;
END PROCESS;
p_control_packet_offload : PROCESS(r, gn_index, in_sosi, trigger, done, dp_header_info, selected_crosslet)
VARIABLE v: t_reg;
BEGIN
v := r;
v.start_pulse := '0';
v.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
v.integration_interval := r.interval_cnt + 1; -- count = index + 1
v.interval_cnt := 0;
v.payload_err := '0';
ELSE
IF in_sosi.eop = '1' THEN
v.payload_err := r.payload_err OR in_sosi.err(0);
END IF;
IF in_sosi.sop = '1' THEN
v.interval_cnt := r.interval_cnt + 1;
END IF;
END IF;
-- assign sdp_data_id for different statistic types
IF g_statistics_type = "SST" THEN
v.data_id := x"000000" & TO_UVEC(r.block_count + c_sdp_S_pn * gn_index, 8);
ELSIF g_statistics_type = "BST" THEN
v.data_id := x"0000" & TO_UVEC(c_beamlet_id, 16);
ELSIF g_statistics_type = "XST" THEN
v.data_id := x"0" & "000" & RESIZE_UVEC(selected_crosslet, 9) & TO_UVEC(r.block_count * c_sdp_S_pn, 8) & TO_UVEC(r.block_count * c_sdp_S_pn, 8); -- RW TODO: define for P_sq > 1
ELSE
v.data_id := x"00000000";
END IF;
-- Issue start_pulse per packet offload
IF trigger = '1' THEN
-- Use trigger to start first packet
v.start_pulse := '1';
v.start_address := 0;
v.block_count := 0;
ELSIF done = '1' THEN
-- Use done to start next packets
IF r.block_count < c_nof_packets-1 THEN
IF r.block_count MOD c_nof_data_per_step = 0 THEN
v.start_address := r.block_count / c_nof_data_per_step * c_block_size; -- jump to first packet in next block
ELSE
v.start_address := r.start_address + c_data_size; -- step to next packet within block
END IF;
v.start_pulse := '1';
v.block_count := r.block_count + 1;
ELSE
-- Prepare for next trigger interval.
v.start_address := 0;
v.block_count := 0;
END IF;
END IF;
-- Release header info per packet offload
IF trigger = '1' OR done = '1' THEN
v.dp_header_info := dp_header_info;
END IF;
nxt_r <= v;
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_dc
GENERIC MAP (
g_data_size => c_data_size,
g_step_size => c_step_size,
g_nof_data => c_nof_data,
g_reverse_word_order => TRUE -- default word order is MSB after LSB, we need to stream LSB after MSB.
)
PORT MAP(
dp_rst => dp_rst,
dp_clk => dp_clk,
mm_rst => mm_rst,
mm_clk => mm_clk,
start_pulse => r.start_pulse,
start_address => r.start_address,
done => 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_pipeline_ready : ENTITY dp_lib.dp_pipeline_ready
PORT MAP(
rst => dp_rst,
clk => dp_clk,
-- ST sink
snk_out => dp_block_from_mm_src_in,
snk_in => dp_block_from_mm_src_out,
-- ST source
src_in => dp_offload_snk_out,
src_out => dp_offload_snk_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_offload_snk_in,
snk_out_arr(0) => dp_offload_snk_out,
src_out_arr(0) => out_sosi,
src_in_arr(0) => out_siso,
hdr_fields_in_arr(0) => r.dp_header_info
);
END str;