diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/disturb2_unb2b_sdp_station_full_wg/tb_disturb2_unb2b_sdp_station_full_wg.vhd b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/disturb2_unb2b_sdp_station_full_wg/tb_disturb2_unb2b_sdp_station_full_wg.vhd index 75b4e33e6fbdbfa2086688217e442a54f89d438a..e87e209540427f98bad1b4cb0a240f4b46909bef 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/disturb2_unb2b_sdp_station_full_wg/tb_disturb2_unb2b_sdp_station_full_wg.vhd +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/disturb2_unb2b_sdp_station_full_wg/tb_disturb2_unb2b_sdp_station_full_wg.vhd @@ -27,25 +27,40 @@ -- MM control actions: -- -- 1) Enable calc mode for WG via reg_diag_wg with: --- 1. --- freq = 19.921875MHz (subband 102) --- ampl = 0.5 * 2**13 --- 2. --- freg = 19.43359375 MHz (subband 99.5) --- ampl = 0.5 * 2**13 +-- 1. freq = 19.921875MHz (subband 102, at mid of normal beamlet) +-- 2. freg = 19.43359375 MHz (subband 99.5, at mid of shifted beamlet) +-- Use same ampl for both WG. Use c_beamlet_scale such that beamlet output +-- will fit in W_beamlet = 8 bits. -- -- 2) Read current BSN from reg_bsn_scheduler_wg and write reg_bsn_scheduler_wg -- to trigger start of WG at BSN. -- --- 3) Verify 10GbE output. --- +-- 3) Verify beamlet data in 10GbE output for beamset 0 (with the normal +-- beamlets) and beamset 1 (with the frequency shifted beamlets). +-- . verify subband 102 in beamset 0 +-- . verify subband 99.5 in beamset 1 +-- . These subbands also appear at about half power in the other beamset +-- but these values are not verified, because they are at the edge of +-- the subband and will in practise not be used. Therefore choose WG +-- c_wg_ampl_sp_2 = c_wg_ampl_sp_0 / 3 to distinghuis them. +-- The purpose of the 2x oversampled filterbank is to only use the +-- beamlet frequencies that are around the center of the subband, so +-- the half of the subbands from beamset 0 and half of the subbands +-- from beamset 1. -- -- Usage: -- > as 7 # default -- > as 12 # for detailed debugging -- > run -a --- Remark: TB based on tb_lofar2_unb2b_beamformer.vhd +-- . manually add missing beamlet_arr2_im/re to wave window, and manually +-- copy beamlet_arr2_im[195:215] and [1170:1190] and the rx_beamlet_* +-- index signals to have a more compact view of the relevant indices. +-- . If c_subband_phase = 0.0 then beamlet_arr2_re entries are 0. +-- . manually add top level generics/constants to wave window. +-- +-- Remark: TB is based on tb_lofar2_unb2c_sdp_station_bf. ------------------------------------------------------------------------------- + LIBRARY IEEE, common_lib, unb2b_board_lib, i2c_lib, mm_lib, dp_lib, diag_lib, lofar2_sdp_lib, wpfb_lib, tech_pll_lib, tr_10GbE_lib; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; @@ -89,25 +104,65 @@ ARCHITECTURE tb OF tb_disturb2_unb2b_sdp_station_full_wg IS CONSTANT c_wpfb_complex_sim : t_wpfb := func_wpfb_map_real_input_wpfb_parameters_to_complex_input(c_wpfb_sim); -- WG - CONSTANT c_full_scale_ampl : REAL := REAL(2**(c_sdp_W_adc-1)-1); -- = full scale of WG CONSTANT c_bsn_start_wg : NATURAL := 2; -- start WG at this BSN to instead of some BSN, to avoid mismatches in exact expected data values - CONSTANT c_ampl_sp : NATURAL := 2**(c_sdp_W_adc-1) / 2; -- in number of lsb - CONSTANT c_wg_subband_freq_unit : REAL := c_diag_wg_freq_unit/REAL(c_sdp_N_fft); -- subband freq = Fs/1024 = 200 MSps/1024 = 195312.5 Hz sinus - CONSTANT c_wg_freq_offset : REAL := 0.0/11.0; -- in freq_unit - CONSTANT c_subband_sp_0 : REAL := 102.0; -- Select subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz - CONSTANT c_subband_sp_1 : REAL := 99.5; -- Select subband at index 99.5 = 99.5/1024 * 200MHz = 19.43359375 MHz - CONSTANT c_wg_ampl_lsb : REAL := c_diag_wg_ampl_unit / c_full_scale_ampl; -- amplitude in number of LSbit resolution steps - CONSTANT c_exp_wg_power_sp : REAL := REAL(c_ampl_sp**2)/2.0 * REAL(c_sdp_N_fft*c_nof_block_per_sync); + -- . ampl + CONSTANT c_beamlet_scale : REAL := 1.0 / 2.0**9; + CONSTANT c_wg_ampl_sp_0 : NATURAL := NATURAL(7.0 / c_beamlet_scale); -- choose < 8.0 to have no beamlet output overflow with unit weights and unit beamlet scale + CONSTANT c_wg_ampl_sp_2 : NATURAL := c_wg_ampl_sp_0 / 3; -- use different ampl for sp_0 and sp_2 to distinghuis them + -- . phase + CONSTANT c_subband_phase : REAL := 0.0; -- wanted subband phase in degrees = WG phase at sop + CONSTANT c_wg_latency : INTEGER := c_diag_wg_latency - 0; -- -0 to account for BSN scheduler start trigger latency + CONSTANT c_subband_sp_0 : REAL := 102.0; -- use WG at sp-0 for subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz + CONSTANT c_subband_sp_2 : REAL := 99.5; -- use WG at sp-2 for subband at index 99.5 = 99.5/1024 * 200MHz = 19.43359375 MHz + CONSTANT c_subband_freq_sp_0 : REAL := REAL(c_subband_sp_0) / REAL(c_sdp_N_fft); -- normalized by fs = f_adc = 200 MHz = dp_clk rate + CONSTANT c_subband_freq_sp_2 : REAL := REAL(c_subband_sp_2) / REAL(c_sdp_N_fft); -- normalized by fs = f_adc = 200 MHz = dp_clk rate + CONSTANT c_wg_phase_offset_sp_0 : REAL := 360.0 * REAL(c_wg_latency) * c_subband_freq_sp_0; -- c_diag_wg_latency is in dp_clk cycles + CONSTANT c_wg_phase_offset_sp_2 : REAL := 360.0 * REAL(c_wg_latency) * c_subband_freq_sp_2; -- c_diag_wg_latency is in dp_clk cycles + CONSTANT c_wg_phase_sp_0 : REAL := c_subband_phase + c_wg_phase_offset_sp_0; -- WG phase in degrees + CONSTANT c_wg_phase_sp_2 : REAL := c_subband_phase + c_wg_phase_offset_sp_2; -- WG phase in degrees + + -- WPFB, use default unit subband weights (= 1.0 + 0j) + CONSTANT c_exp_subband_ampl_sp_0 : REAL := REAL(c_wg_ampl_sp_0) * c_sdp_wpfb_subband_sp_ampl_ratio; + CONSTANT c_exp_subband_ampl_sp_2 : REAL := REAL(c_wg_ampl_sp_2) * c_sdp_wpfb_subband_sp_ampl_ratio; + + CONSTANT c_subband_phase_offset : REAL := -90.0; -- WG with zero phase sinus yields subband with -90 degrees phase (negative Im, zero Re) + CONSTANT c_exp_subband_phase : REAL := c_subband_phase + c_subband_phase_offset; + + -- BF + -- . use one active WG per subband, so beamlet_sum of one subband + -- . use default unit BF weights (= 1.0 + 0j), so beamlet_sum = subband + -- . use beamlet output = beamlet_sum * c_beamlet_scale + CONSTANT c_exp_beamlet_scale : NATURAL := NATURAL(c_beamlet_scale * REAL(c_sdp_unit_beamlet_scale)); -- c_sdp_unit_beamlet_scale = 2**15; + CONSTANT c_exp_beamlet_ampl_sp_0 : REAL := c_exp_subband_ampl_sp_0 * c_beamlet_scale; + CONSTANT c_exp_beamlet_ampl_sp_2 : REAL := c_exp_subband_ampl_sp_2 * c_beamlet_scale; + CONSTANT c_exp_beamlet_phase : REAL := c_exp_subband_phase; + CONSTANT c_exp_beamlet_re_sp_0 : INTEGER := INTEGER(COMPLEX_RE(c_exp_beamlet_ampl_sp_0, c_exp_beamlet_phase)); + CONSTANT c_exp_beamlet_re_sp_2 : INTEGER := INTEGER(COMPLEX_RE(c_exp_beamlet_ampl_sp_2, c_exp_beamlet_phase)); + CONSTANT c_exp_beamlet_im_sp_0 : INTEGER := INTEGER(COMPLEX_IM(c_exp_beamlet_ampl_sp_0, c_exp_beamlet_phase)); + CONSTANT c_exp_beamlet_im_sp_2 : INTEGER := INTEGER(COMPLEX_IM(c_exp_beamlet_ampl_sp_2, c_exp_beamlet_phase)); + + CONSTANT c_exp_beamlet_index : NATURAL := NATURAL(c_subband_sp_0) * c_sdp_N_pol; + CONSTANT c_exp_beamlet_index_os : NATURAL := c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block + NATURAL(ROUND(c_subband_sp_2)) * c_sdp_N_pol; TYPE t_real_arr IS ARRAY (INTEGER RANGE <>) OF REAL; TyPE t_slv_64_subbands_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_S_sub_bf); - -- MM + -- MM + -- . Address widths of a single MM instance + CONSTANT c_addr_w_reg_diag_wg : NATURAL := 2; + CONSTANT c_addr_w_reg_dp_xonoff : NATURAL := 1; + CONSTANT c_addr_w_reg_bf_scale : NATURAL := 1; + -- . Address spans of a single MM instance + CONSTANT c_mm_span_reg_diag_wg : NATURAL := 2**c_addr_w_reg_diag_wg; + CONSTANT c_mm_span_reg_dp_xonoff : NATURAL := 2**c_addr_w_reg_dp_xonoff; + CONSTANT c_mm_span_reg_bf_scale : NATURAL := 2**c_addr_w_reg_bf_scale; + CONSTANT c_mm_file_reg_ppsh : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "PIO_PPS"; CONSTANT c_mm_file_reg_bsn_source_v2 : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2"; CONSTANT c_mm_file_reg_bsn_scheduler_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SCHEDULER"; CONSTANT c_mm_file_reg_diag_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_WG"; CONSTANT c_mm_file_reg_dp_xonoff : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_DP_XONOFF"; + CONSTANT c_mm_file_reg_bf_scale : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BF_SCALE"; -- Tb SIGNAL tb_end : STD_LOGIC := '0'; @@ -116,16 +171,25 @@ ARCHITECTURE tb OF tb_disturb2_unb2b_sdp_station_full_wg IS SIGNAL rd_data : STD_LOGIC_VECTOR(c_32-1 DOWNTO 0); -- WG - SIGNAL dbg_c_exp_wg_power_sp : REAL := c_exp_wg_power_sp; - SIGNAL current_bsn_wg : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); + SIGNAL current_bsn_wg : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); + + -- BF + SIGNAL rd_beamlet_scale : STD_LOGIC_VECTOR(15 DOWNTO 0); -- 10GbE - CONSTANT c_exp_beamlet_index : NATURAL := NATURAL(c_subband_sp_0) * c_sdp_N_pol; - CONSTANT c_exp_beamlet_index_os : NATURAL := c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block + NATURAL(ROUND(c_subband_sp_1)) * c_sdp_N_pol; - CONSTANT c_exp_beamlet_re : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"7F"; --Derived from simulation - CONSTANT c_exp_beamlet_im : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"81"; --Derived from simulation - - SIGNAL dbg_beamlet_index_offset : NATURAL := 0; + -- . header fields + SIGNAL rx_beamlet_scale : STD_LOGIC_VECTOR(15 DOWNTO 0); + SIGNAL rx_beamlet_index_offset : NATURAL := 0; + SIGNAL rx_blocks_per_packet : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL rx_beamlets_per_block : STD_LOGIC_VECTOR(15 DOWNTO 0); + SIGNAL rx_block_period : STD_LOGIC_VECTOR(15 DOWNTO 0); + SIGNAL rx_bsn : STD_LOGIC_VECTOR(63 DOWNTO 0); + + -- . payload indices and data arrays + SIGNAL rx_beamlet_blk : NATURAL := 0; + SIGNAL rx_beamlet_cnt : NATURAL := 0; + SIGNAL rx_beamlet_valid : STD_LOGIC := '0'; + SIGNAL rx_beamlet_sop : STD_LOGIC := '0'; SIGNAL beamlet_arr2_re : t_slv_8_arr(c_sdp_R_os * c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block-1 DOWNTO 0); SIGNAL beamlet_arr2_im : t_slv_8_arr(c_sdp_R_os * c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block-1 DOWNTO 0); @@ -274,7 +338,8 @@ BEGIN p_mm_stimuli : PROCESS VARIABLE v_bsn : NATURAL; - VARIABLE v_beamlet_index_offset : NATURAL; + VARIABLE v_offset : NATURAL; + VARIABLE v_beamlet_index_offset : NATURAL; BEGIN -- Wait for DUT power up after reset WAIT FOR 1 us; @@ -282,10 +347,25 @@ BEGIN proc_common_wait_until_hi_lo(ext_clk, ext_pps); ---------------------------------------------------------------------------- - -- Enable UDP offload (dp_xonoff) of beamset 0 + -- Use both beamsets, 0 for BF with normal subbands, 1 for BF with shifted subbands ---------------------------------------------------------------------------- - mmf_mm_bus_wr(c_mm_file_reg_dp_xonoff,0 , 1, tb_clk); - mmf_mm_bus_wr(c_mm_file_reg_dp_xonoff,2 , 1, tb_clk); + FOR bset IN 0 TO c_sdp_N_beamsets-1 LOOP + -- Enable beamlet output + v_offset := bset * c_mm_span_reg_dp_xonoff; + mmf_mm_bus_wr(c_mm_file_reg_dp_xonoff, v_offset + 0, 1, tb_clk); + + -- MM beamlet_scale + -- . write + v_offset := bset * c_mm_span_reg_bf_scale; + mmf_mm_bus_wr(c_mm_file_reg_bf_scale, v_offset + 0, c_exp_beamlet_scale, tb_clk); + proc_common_wait_cross_clock_domain_latency(c_tb_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency*2); + + -- . readback + mmf_mm_bus_rd(c_mm_file_reg_bf_scale, v_offset + 0, rd_data, tb_clk); + rd_beamlet_scale <= rd_data(15 DOWNTO 0); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT TO_UINT(rd_beamlet_scale) = c_exp_beamlet_scale REPORT "Wrong MM read beamlet_scale for beamset " & NATURAL'IMAGE(bset) SEVERITY ERROR; + END LOOP; ---------------------------------------------------------------------------- -- Enable BS @@ -303,14 +383,18 @@ BEGIN -- 1 : phase[15:0] -- 2 : freq[30:0] -- 3 : ampl[16:0] - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 1, INTEGER( 0.0 * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 2, INTEGER((c_subband_sp_0+c_wg_freq_offset) * c_wg_subband_freq_unit), tb_clk); -- freq - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 3, INTEGER(REAL(c_ampl_sp) * c_wg_ampl_lsb), tb_clk); -- ampl - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 8, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 9, INTEGER( 0.0 * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 10, INTEGER((c_subband_sp_1+c_wg_freq_offset) * c_wg_subband_freq_unit), tb_clk); -- freq - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, 11, INTEGER(REAL(c_ampl_sp) * c_wg_ampl_lsb), tb_clk); -- ampl + -- WG at signal input 0 + v_offset := 0 * c_mm_span_reg_diag_wg; + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_wg_phase_sp_0 * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, INTEGER(c_subband_sp_0 * c_sdp_wg_subband_freq_unit), tb_clk); -- freq + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_wg_ampl_sp_0) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl + -- WG at signal input 2 + v_offset := 2 * c_mm_span_reg_diag_wg; + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_wg_phase_sp_2 * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, INTEGER(c_subband_sp_2 * c_sdp_wg_subband_freq_unit), tb_clk); -- freq + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_wg_ampl_sp_2) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl -- Read current BSN mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 0, current_bsn_wg(31 DOWNTO 0), tb_clk); @@ -332,50 +416,114 @@ BEGIN --------------------------------------------------------------------------- -- Read 10GbE Stream --------------------------------------------------------------------------- - FOR BS IN 0 TO 2 LOOP -- Read 3 blocks to make sure we get 1 from each beamset. It can happen that two blocks (but not three) from the same beamset are received back to back. - proc_common_wait_until_high(ext_clk, tr_10GbE_src_out.sop); + + -- Read 3 packets to make sure we get 1 from each beamset. It can happen that two packets + -- (but not three) from the same beamset are received back to back. + FOR packet IN 0 TO 2 LOOP + -- Get beamlet_index from packet header + proc_common_wait_until_clk_and_high(ext_clk, tr_10GbE_src_out.sop); FOR I IN 0 TO 8 LOOP -- Packet header is 9.25 words wide, which can be discarded IF I = 7 THEN - v_beamlet_index_offset := c_sdp_N_pol_bf * TO_UINT(tr_10GbE_src_out.data(39 DOWNTO 24)); -- Read beamlet index - dbg_beamlet_index_offset <= v_beamlet_index_offset; + rx_beamlet_scale <= tr_10GbE_src_out.data(55 DOWNTO 40); + v_beamlet_index_offset := c_sdp_N_pol_bf * TO_UINT(tr_10GbE_src_out.data(39 DOWNTO 24)); -- Read beamlet index + rx_beamlet_index_offset <= v_beamlet_index_offset; + rx_blocks_per_packet <= tr_10GbE_src_out.data(23 DOWNTO 16); + rx_beamlets_per_block <=tr_10GbE_src_out.data(15 DOWNTO 0); + END IF; + IF I = 8 THEN + rx_block_period <= tr_10GbE_src_out.data(63 DOWNTO 48); + rx_bsn(63 DOWNTO 16) <= tr_10GbE_src_out.data(47 DOWNTO 0); END IF; - proc_common_wait_until_high(ext_clk, tr_10GbE_src_out.valid); - proc_common_wait_some_cycles(ext_clk, 1); + proc_common_wait_until_clk_and_high(ext_clk, tr_10GbE_src_out.valid); END LOOP; - - -- First word contains 3 beamlets + 1 header part - beamlet_arr2_re(v_beamlet_index_offset + 0) <= tr_10GbE_src_out.data(7 DOWNTO 0); - beamlet_arr2_im(v_beamlet_index_offset + 0) <= tr_10GbE_src_out.data(15 DOWNTO 8); - beamlet_arr2_re(v_beamlet_index_offset + 1) <= tr_10GbE_src_out.data(23 DOWNTO 16); - beamlet_arr2_im(v_beamlet_index_offset + 1) <= tr_10GbE_src_out.data(31 DOWNTO 24); - beamlet_arr2_re(v_beamlet_index_offset + 2) <= tr_10GbE_src_out.data(39 DOWNTO 32); - beamlet_arr2_im(v_beamlet_index_offset + 2) <= tr_10GbE_src_out.data(47 DOWNTO 40); - proc_common_wait_until_high(ext_clk, tr_10GbE_src_out.valid); - proc_common_wait_some_cycles(ext_clk, 1); - FOR I IN 1 TO (c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block/4)-1 LOOP - beamlet_arr2_re(v_beamlet_index_offset + I*4 -1) <= tr_10GbE_src_out.data(7 DOWNTO 0); - beamlet_arr2_im(v_beamlet_index_offset + I*4 -1) <= tr_10GbE_src_out.data(15 DOWNTO 8); - beamlet_arr2_re(v_beamlet_index_offset + I*4 +0) <= tr_10GbE_src_out.data(23 DOWNTO 16); - beamlet_arr2_im(v_beamlet_index_offset + I*4 +0) <= tr_10GbE_src_out.data(31 DOWNTO 24); - beamlet_arr2_re(v_beamlet_index_offset + I*4 +1) <= tr_10GbE_src_out.data(39 DOWNTO 32); - beamlet_arr2_im(v_beamlet_index_offset + I*4 +1) <= tr_10GbE_src_out.data(47 DOWNTO 40); - beamlet_arr2_re(v_beamlet_index_offset + I*4 +2) <= tr_10GbE_src_out.data(55 DOWNTO 48); - beamlet_arr2_im(v_beamlet_index_offset + I*4 +2) <= tr_10GbE_src_out.data(63 DOWNTO 56); - proc_common_wait_until_high(ext_clk, tr_10GbE_src_out.valid); - proc_common_wait_some_cycles(ext_clk, 1); + rx_bsn(15 DOWNTO 0) <= tr_10GbE_src_out.data(63 DOWNTO 48); + + -- Get all c_sdp_cep_nof_blocks_per_packet = 4 blocks from the packet + FOR blk IN 0 TO c_sdp_cep_nof_blocks_per_packet-1 LOOP + -- . First word contains 1 header part of two bytes and 3 beamlets [0:2]. + -- . expect c_sdp_cep_nof_beamlets_per_block = c_sdp_S_sub_bf = 488 dual pol + -- and complex beamlets per packet, so 2 dual pol beamlets/64b data word. + -- . Beamlets array is stored big endian in the data, so X index 0 first in + -- MSByte of tr_10GbE_src_out.data. + rx_beamlet_blk <= blk; + rx_beamlet_cnt <= 0; + rx_beamlet_valid <= '1'; + rx_beamlet_sop <= '1'; + beamlet_arr2_im(v_beamlet_index_offset + 0) <= tr_10GbE_src_out.data(47 DOWNTO 40); + beamlet_arr2_re(v_beamlet_index_offset + 0) <= tr_10GbE_src_out.data(39 DOWNTO 32); + beamlet_arr2_im(v_beamlet_index_offset + 1) <= tr_10GbE_src_out.data(31 DOWNTO 24); + beamlet_arr2_re(v_beamlet_index_offset + 1) <= tr_10GbE_src_out.data(23 DOWNTO 16); + beamlet_arr2_im(v_beamlet_index_offset + 2) <= tr_10GbE_src_out.data(15 DOWNTO 8); + beamlet_arr2_re(v_beamlet_index_offset + 2) <= tr_10GbE_src_out.data(7 DOWNTO 0); + proc_common_wait_until_clk_and_high(ext_clk, tr_10GbE_src_out.valid); + rx_beamlet_cnt <= rx_beamlet_cnt + 1; + rx_beamlet_sop <= '0'; + -- . get beamlets during block, there are 4 complex beamlets per 64b word + FOR I IN 1 TO (c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block/4)-1 LOOP + beamlet_arr2_im(v_beamlet_index_offset + I*4 -1) <= tr_10GbE_src_out.data(63 DOWNTO 56); + beamlet_arr2_re(v_beamlet_index_offset + I*4 -1) <= tr_10GbE_src_out.data(55 DOWNTO 48); + beamlet_arr2_im(v_beamlet_index_offset + I*4 +0) <= tr_10GbE_src_out.data(47 DOWNTO 40); + beamlet_arr2_re(v_beamlet_index_offset + I*4 +0) <= tr_10GbE_src_out.data(39 DOWNTO 32); + beamlet_arr2_im(v_beamlet_index_offset + I*4 +1) <= tr_10GbE_src_out.data(31 DOWNTO 24); + beamlet_arr2_re(v_beamlet_index_offset + I*4 +1) <= tr_10GbE_src_out.data(23 DOWNTO 16); + beamlet_arr2_im(v_beamlet_index_offset + I*4 +2) <= tr_10GbE_src_out.data(15 DOWNTO 8); + beamlet_arr2_re(v_beamlet_index_offset + I*4 +2) <= tr_10GbE_src_out.data(7 DOWNTO 0); + proc_common_wait_until_clk_and_high(ext_clk, tr_10GbE_src_out.valid); + rx_beamlet_cnt <= rx_beamlet_cnt + 1; + END LOOP; + -- . get last beamlet of block + beamlet_arr2_im(v_beamlet_index_offset + c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block-1) <= tr_10GbE_src_out.data(63 DOWNTO 56); + beamlet_arr2_re(v_beamlet_index_offset + c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block-1) <= tr_10GbE_src_out.data(55 DOWNTO 48); + -- Loop for next block in packet END LOOP; + -- Make rx_beamlet_valid low for next header or after loop during verify. + -- Cannot wait one ext_clk cycle here to include last beamlet of block, + -- because next packet sop may follow immediately after this packet eop. + rx_beamlet_valid <= '0'; - beamlet_arr2_re(v_beamlet_index_offset + c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block-1) <= tr_10GbE_src_out.data(55 DOWNTO 48); - beamlet_arr2_im(v_beamlet_index_offset + c_sdp_N_pol_bf * c_sdp_cep_nof_beamlets_per_block-1) <= tr_10GbE_src_out.data(63 DOWNTO 56); + -- Loop and wait for next packet. END LOOP; --------------------------------------------------------------------------- -- Verify 10GbE UDP offload --------------------------------------------------------------------------- - ASSERT beamlet_arr2_re(c_exp_beamlet_index) = c_exp_beamlet_re REPORT "Wrong 10GbE output (re) on beamset 0" SEVERITY ERROR; - ASSERT beamlet_arr2_im(c_exp_beamlet_index) = c_exp_beamlet_im REPORT "Wrong 10GbE output (im) on beamset 0" SEVERITY ERROR; - ASSERT beamlet_arr2_re(c_exp_beamlet_index_os) = c_exp_beamlet_re REPORT "Wrong 10GbE output (re) on beamset 1 (shifted subbands)" SEVERITY ERROR; - ASSERT beamlet_arr2_im(c_exp_beamlet_index_os) = c_exp_beamlet_im REPORT "Wrong 10GbE output (im) on beamset 1 (shifted subbands)" SEVERITY ERROR; + print_str(""); + print_str("WG:"); + print_str(". sp_0 at mid subband,"); + print_str(". sp_2 at subband edge, so at mid of os subband."); + print_str(". c_wg_ampl_sp_0 = " & int_to_str(c_wg_ampl_sp_0)); + print_str(". c_wg_ampl_sp_2 = " & int_to_str(c_wg_ampl_sp_2)); + print_str(". c_subband_sp_0 = " & real_to_str(c_subband_sp_0, 20, 6)); + print_str(". c_subband_sp_2 = " & real_to_str(c_subband_sp_2, 20, 6)); + print_str("WPFB:"); + print_str(". c_exp_subband_ampl_sp_0 = " & real_to_str(c_exp_subband_ampl_sp_0, 20, 6)); + print_str(". c_exp_subband_ampl_sp_2 = " & real_to_str(c_exp_subband_ampl_sp_2, 20, 6)); + print_str(""); + print_str("Beamlet output: (sp_0 at mid subband, sp_2 at subband edge, so at mid of os subband):"); + print_str(". c_exp_beamlet_index = " & int_to_str(c_exp_beamlet_index)); + print_str(". c_exp_beamlet_index_os = " & int_to_str(c_exp_beamlet_index_os)); + print_str(". c_exp_beamlet_ampl_sp_0 = " & real_to_str(c_exp_beamlet_ampl_sp_0, 20, 6)); + print_str(". c_exp_beamlet_ampl_sp_2 = " & real_to_str(c_exp_beamlet_ampl_sp_2, 20, 6)); + print_str(". c_exp_beamlet_phase = " & real_to_str(c_exp_beamlet_phase, 20, 6)); + print_str(""); + print_str(". c_beamlet_re at index = " & int_to_str(TO_SINT(beamlet_arr2_re(c_exp_beamlet_index)))); + print_str(". c_beamlet_re at index_os = " & int_to_str(TO_SINT(beamlet_arr2_re(c_exp_beamlet_index_os)))); + print_str(". c_exp_beamlet_re_sp_0 = " & int_to_str(INTEGER(c_exp_beamlet_re_sp_0))); + print_str(". c_exp_beamlet_re_sp_2 = " & int_to_str(INTEGER(c_exp_beamlet_re_sp_2))); + print_str(""); + print_str(". c_beamlet_im at index = " & int_to_str(TO_SINT(beamlet_arr2_im(c_exp_beamlet_index)))); + print_str(". c_beamlet_im at index_os = " & int_to_str(TO_SINT(beamlet_arr2_im(c_exp_beamlet_index_os)))); + print_str(". c_exp_beamlet_im_sp_0 = " & int_to_str(INTEGER(c_exp_beamlet_im_sp_0))); + print_str(". c_exp_beamlet_im_sp_2 = " & int_to_str(INTEGER(c_exp_beamlet_im_sp_2))); + + -- WG at subband center will yield same subband value in every subband period + ASSERT SIGNED(beamlet_arr2_re(c_exp_beamlet_index)) = c_exp_beamlet_re_sp_0 REPORT "Wrong 10GbE beamlet output /= c_exp_beamlet_re_sp_0 in beamset 0" SEVERITY ERROR; + ASSERT SIGNED(beamlet_arr2_im(c_exp_beamlet_index)) = c_exp_beamlet_im_sp_0 REPORT "Wrong 10GbE beamlet output /= c_exp_beamlet_im_sp_0 in beamset 0" SEVERITY ERROR; + -- WG at subband edge will change phase 180 degrees in every subband period, so expect factor +-1 + ASSERT SIGNED(beamlet_arr2_re(c_exp_beamlet_index_os)) = c_exp_beamlet_re_sp_2 OR + SIGNED(beamlet_arr2_re(c_exp_beamlet_index_os)) = -c_exp_beamlet_re_sp_2 REPORT "Wrong 10GbE beamlet output /= c_exp_beamlet_re_sp_2 in beamset 1 (shifted subbands)" SEVERITY ERROR; + ASSERT SIGNED(beamlet_arr2_im(c_exp_beamlet_index_os)) = c_exp_beamlet_im_sp_2 OR + SIGNED(beamlet_arr2_im(c_exp_beamlet_index_os)) = -c_exp_beamlet_im_sp_2 REPORT "Wrong 10GbE beamlet output /= c_exp_beamlet_im_sp_2 in beamset 1 (shifted subbands)" SEVERITY ERROR; --------------------------------------------------------------------------- -- End Simulation diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd index a3cd031036e188413dfa5fa7bef82621b956b959..821bd58d57e44525fdbadb34bd2306ddbfa88ee7 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf/tb_lofar2_unb2c_sdp_station_bf.vhd @@ -191,7 +191,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS CONSTANT c_tb_clk_period : TIME := 100 ps; -- use fast tb_clk to speed up M&C CONSTANT c_nof_block_per_sync : NATURAL := 16; - CONSTANT c_nof_clk_per_sync : NATURAL := c_nof_block_per_sync*c_sdp_N_fft; + CONSTANT c_nof_clk_per_sync : NATURAL := c_nof_block_per_sync*c_sdp_N_fft; CONSTANT c_pps_period : NATURAL := c_nof_clk_per_sync; CONSTANT c_wpfb_sim : t_wpfb := func_wpfb_set_nof_block_per_sync(c_sdp_wpfb_subbands, c_nof_block_per_sync); CONSTANT c_stat_data_sz : NATURAL := c_wpfb_sim.stat_data_sz; -- = 2 @@ -253,7 +253,6 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS CONSTANT c_exp_remnant_subband_phase : REAL := g_sp_remnant_phase + c_subband_phase_offset + c_subband_weight_phase; CONSTANT c_exp_remnant_subband_ampl : REAL := REAL(c_wg_remnant_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio * c_subband_weight_gain; - TYPE t_real_arr IS ARRAY (INTEGER RANGE <>) OF REAL; TYPE t_slv_64_subbands_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_sub-1); -- 512 TYPE t_slv_64_beamlets_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_beamlets_sdp-1); -- 2*488 = 976 @@ -271,43 +270,22 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS CONSTANT c_bf_remnant_y_weight_re : INTEGER := INTEGER(COMPLEX_RE(g_bf_remnant_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_y_phase)); CONSTANT c_bf_remnant_y_weight_im : INTEGER := INTEGER(COMPLEX_IM(g_bf_remnant_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_y_phase)); - -- Model the SDP beamformer for one g_sp and S_pn-1 = 11 remnant signal inputs - FUNCTION bf_calculate_expected_beamlet(sp_subband_ampl, sp_subband_phase, sp_bf_gain, sp_bf_phase, - rem_subband_ampl, rem_subband_phase, rem_bf_gain, rem_bf_phase : REAL) RETURN t_real_arr IS -- 0:3 = ampl, phase, re, im - CONSTANT c_nof_rem : REAL := REAL(c_sdp_S_pn - 1); -- BF for one g_sp and 11 remnant signal inputs - VARIABLE v_sp_ampl, v_sp_phase, v_sp_re, v_sp_im : REAL; - VARIABLE v_rem_ampl, v_rem_phase, v_rem_re, v_rem_im : REAL; - VARIABLE v_sum_ampl, v_sum_phase, v_sum_re, v_sum_im : REAL; - VARIABLE v_tuple : t_real_arr(0 TO 3); - BEGIN - v_sp_ampl := sp_subband_ampl * sp_bf_gain; - v_sp_phase := sp_subband_phase + sp_bf_phase; - v_sp_re := COMPLEX_RE(v_sp_ampl, v_sp_phase); - v_sp_im := COMPLEX_IM(v_sp_ampl, v_sp_phase); - v_rem_ampl := rem_subband_ampl * rem_bf_gain; - v_rem_phase := rem_subband_phase + rem_bf_phase; - v_rem_re := COMPLEX_RE(v_rem_ampl, v_rem_phase); - v_rem_im := COMPLEX_IM(v_rem_ampl, v_rem_phase); - v_sum_re := v_sp_re + c_nof_rem * v_rem_re; -- BF sum re - v_sum_im := v_sp_im + c_nof_rem * v_rem_im; -- BF sum im - v_sum_ampl := COMPLEX_RADIUS(v_sum_re, v_sum_im); - v_sum_phase := COMPLEX_PHASE(v_sum_re, v_sum_im); - v_tuple := (0 => v_sum_ampl, 1 => v_sum_phase, 2 => v_sum_re, 3 => v_sum_im); - RETURN v_tuple; - END; - + -- Model the SDP local beamformer for one g_sp and S_pn - 1 remnant signal inputs -- . Beamlet internal - CONSTANT c_exp_beamlet_x_tuple : t_real_arr(0 TO 3) := bf_calculate_expected_beamlet( + CONSTANT c_nof_remnant : NATURAL := c_sdp_S_pn - 1; + CONSTANT c_exp_beamlet_x_tuple : t_real_arr(0 TO 3) := func_sdp_beamformer( c_exp_subband_ampl, c_exp_subband_phase, g_bf_x_gain, g_bf_x_phase, - c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_x_gain, g_bf_remnant_x_phase); + c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_x_gain, g_bf_remnant_x_phase, + c_nof_remnant); CONSTANT c_exp_beamlet_x_ampl : REAL := c_exp_beamlet_x_tuple(0); CONSTANT c_exp_beamlet_x_phase : REAL := c_exp_beamlet_x_tuple(1); CONSTANT c_exp_beamlet_x_re : REAL := c_exp_beamlet_x_tuple(2); CONSTANT c_exp_beamlet_x_im : REAL := c_exp_beamlet_x_tuple(3); - CONSTANT c_exp_beamlet_y_tuple : t_real_arr(0 TO 3) := bf_calculate_expected_beamlet( + CONSTANT c_exp_beamlet_y_tuple : t_real_arr(0 TO 3) := func_sdp_beamformer( c_exp_subband_ampl, c_exp_subband_phase, g_bf_y_gain, g_bf_y_phase, - c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_y_gain, g_bf_remnant_y_phase); + c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_y_gain, g_bf_remnant_y_phase, + c_nof_remnant); CONSTANT c_exp_beamlet_y_ampl : REAL := c_exp_beamlet_y_tuple(0); CONSTANT c_exp_beamlet_y_phase : REAL := c_exp_beamlet_y_tuple(1); CONSTANT c_exp_beamlet_y_re : REAL := c_exp_beamlet_y_tuple(2); @@ -467,7 +445,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS -- DUT SIGNAL ext_clk : STD_LOGIC := '0'; - SIGNAL ext_pps : STD_LOGIC := '0'; + SIGNAL ext_pps : STD_LOGIC := '0'; SIGNAL WDI : STD_LOGIC; SIGNAL INTA : STD_LOGIC; @@ -479,7 +457,7 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf IS SIGNAL SA_CLK : STD_LOGIC := '1'; SIGNAL si_lpbk_0 : STD_LOGIC_VECTOR(c_unb2c_board_tr_qsfp.bus_w-1 DOWNTO 0); - + -- back transceivers SIGNAL JESD204B_SERIAL_DATA : STD_LOGIC_VECTOR(c_sdp_S_pn-1 downto 0); SIGNAL JESD204B_REFCLK : STD_LOGIC := '1'; @@ -495,7 +473,7 @@ BEGIN ---------------------------------------------------------------------------- ext_clk <= NOT ext_clk AFTER c_ext_clk_period/2; -- External clock (200 MHz) eth_clk(0) <= NOT eth_clk(0) AFTER c_eth_clk_period/2; -- Ethernet ref clock (125 MHz) - JESD204B_REFCLK <= NOT JESD204B_REFCLK AFTER c_bck_ref_clk_period/2; -- JESD sample clock (200MHz) + JESD204B_REFCLK <= NOT JESD204B_REFCLK AFTER c_bck_ref_clk_period/2; -- JESD sample clock (200MHz) SA_CLK <= NOT SA_CLK AFTER c_sa_clk_period/2; -- Serial Gigabit IO sa clock (644 MHz) dest_rst <= '0' AFTER c_ext_clk_period * 10; @@ -504,7 +482,7 @@ BEGIN ------------------------------------------------------------------------------ -- External PPS - ------------------------------------------------------------------------------ + ------------------------------------------------------------------------------ proc_common_gen_pulse(5, c_pps_period, '1', pps_rst, ext_clk, gen_pps); jesd204b_sysref <= gen_pps; ext_pps <= gen_pps; @@ -544,8 +522,8 @@ BEGIN -- Transceiver clocks SA_CLK => SA_CLK, -- front transceivers - QSFP_1_RX => si_lpbk_0, - QSFP_1_TX => si_lpbk_0, + QSFP_1_RX => si_lpbk_0, + QSFP_1_TX => si_lpbk_0, -- LEDs QSFP_LED => open, @@ -553,7 +531,7 @@ BEGIN -- back transceivers JESD204B_SERIAL_DATA => JESD204B_SERIAL_DATA, JESD204B_REFCLK => JESD204B_REFCLK, - + -- jesd204b syncronization signals JESD204B_SYSREF => jesd204b_sysref, JESD204B_SYNC_N => jesd204b_sync_n @@ -633,7 +611,7 @@ BEGIN -- MM slave accesses via file IO ------------------------------------------------------------------------------ tb_clk <= NOT tb_clk AFTER c_tb_clk_period/2; -- Testbench MM clock - + p_mm_stimuli : PROCESS VARIABLE v_bsn : NATURAL; VARIABLE v_data_lo, v_data_hi : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); @@ -845,7 +823,7 @@ BEGIN mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 3, 0, tb_clk); -- Write high part activates the init BSN mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 1, c_nof_clk_per_sync, tb_clk); -- nof_block_per_sync mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 0, 16#00000003#, tb_clk); -- Enable BS at PPS - + -- Release PPS pulser, to get first PPS now and to start BSN source WAIT FOR 1 us; pps_rst <= '0'; @@ -880,14 +858,14 @@ BEGIN mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 0, current_bsn_wg(31 DOWNTO 0), tb_clk); mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 1, current_bsn_wg(63 DOWNTO 32), tb_clk); proc_common_wait_some_cycles(tb_clk, 1); - + -- Write scheduler BSN to trigger start of WG at next block v_bsn := TO_UINT(current_bsn_wg) + 2; ASSERT v_bsn <= c_bsn_start_wg REPORT "Too late to start WG: " & int_to_str(v_bsn) & " > " & int_to_str(c_bsn_start_wg) SEVERITY ERROR; v_bsn := c_bsn_start_wg; mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 0, v_bsn, tb_clk); -- first write low then high part mmf_mm_bus_wr(c_mm_file_reg_bsn_scheduler_wg, 1, 0, tb_clk); -- assume v_bsn < 2**31-1 - + ---------------------------------------------------------------------------- -- Read weighted subband selector ---------------------------------------------------------------------------- @@ -1041,7 +1019,7 @@ BEGIN --------------------------------------------------------------------------- -- Read subband statistics - --------------------------------------------------------------------------- + --------------------------------------------------------------------------- -- . the subband statistics are c_stat_data_sz = 2 word power values. -- . there are c_sdp_S_pn = 12 signal inputs A, B, C, D, E, F, G, H, I, J, K, L -- . there are c_sdp_N_sub = 512 subbands per signal input (SI, = signal path, SP) @@ -1065,7 +1043,7 @@ BEGIN -- low part mmf_mm_bus_rd(c_mm_file_ram_st_sst, v_addr, rd_data, tb_clk); v_data_lo := rd_data; - ELSE + ELSE -- high part mmf_mm_bus_rd(c_mm_file_ram_st_sst, v_addr, rd_data, tb_clk); v_data_hi := rd_data; @@ -1082,7 +1060,7 @@ BEGIN sp_sst <= TO_UREAL(sp_ssts_arr2(c_pol_index)(g_subband)); proc_common_wait_some_cycles(tb_clk, 1); proc_common_wait_some_cycles(ext_clk, 100); -- delay for ease of view in Wave window - + --------------------------------------------------------------------------- -- Read beamlet statistics --------------------------------------------------------------------------- @@ -1128,17 +1106,17 @@ BEGIN END LOOP; proc_common_wait_some_cycles(tb_clk, 1); proc_common_wait_some_cycles(ext_clk, 100); -- delay for ease of view in Wave window - + --------------------------------------------------------------------------- -- Log WG, subband and beamlet statistics - --------------------------------------------------------------------------- - + --------------------------------------------------------------------------- + print_str(""); print_str("WG:"); print_str(". c_wg_ampl = " & int_to_str(c_wg_ampl)); print_str(". c_exp_sp_power = " & real_to_str(c_exp_sp_power, 20, 1)); print_str(". c_exp_sp_ast = " & real_to_str(c_exp_sp_ast, 20, 1)); - + print_str(""); print_str("Subband weight:"); print_str(". sp_subband_weight_gain = " & real_to_str(sp_subband_weight_gain, 20, 6)); @@ -1230,8 +1208,8 @@ BEGIN ASSERT v_im < INTEGER(v_im_exp) + c_beamlet_output_delta REPORT "Wrong beamlet Y output (im) " & INTEGER'IMAGE(v_im) & " != " & REAL'IMAGE(v_im_exp) SEVERITY ERROR; --------------------------------------------------------------------------- - -- End Simulation - --------------------------------------------------------------------------- + -- End Simulation + --------------------------------------------------------------------------- tb_almost_end <= '1'; proc_common_wait_some_cycles(ext_clk, 100); -- delay for ease of view in Wave window proc_common_stop_simulation(TRUE, ext_clk, tb_almost_end, tb_end); @@ -1318,24 +1296,24 @@ BEGIN proc_common_wait_until_high(ext_clk, rx_beamlet_sosi.valid); rx_beamlet_valid <= '1'; -- Capture rx beamlets per longword in rx_beamlet_arr, for time series view in Wave window - rx_beamlet_arr_re(0) <= rx_beamlet_sosi.data(55 DOWNTO 48); -- X - rx_beamlet_arr_im(0) <= rx_beamlet_sosi.data(63 DOWNTO 56); - rx_beamlet_arr_re(1) <= rx_beamlet_sosi.data(39 DOWNTO 32); -- Y - rx_beamlet_arr_im(1) <= rx_beamlet_sosi.data(47 DOWNTO 40); - rx_beamlet_arr_re(2) <= rx_beamlet_sosi.data(23 DOWNTO 16); -- X - rx_beamlet_arr_im(2) <= rx_beamlet_sosi.data(31 DOWNTO 24); - rx_beamlet_arr_re(3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); -- Y - rx_beamlet_arr_im(3) <= rx_beamlet_sosi.data(15 DOWNTO 8); + rx_beamlet_arr_im(0) <= rx_beamlet_sosi.data(63 DOWNTO 56); -- X + rx_beamlet_arr_re(0) <= rx_beamlet_sosi.data(55 DOWNTO 48); + rx_beamlet_arr_im(1) <= rx_beamlet_sosi.data(47 DOWNTO 40); -- Y + rx_beamlet_arr_re(1) <= rx_beamlet_sosi.data(39 DOWNTO 32); + rx_beamlet_arr_im(2) <= rx_beamlet_sosi.data(31 DOWNTO 24); -- X + rx_beamlet_arr_re(2) <= rx_beamlet_sosi.data(23 DOWNTO 16); + rx_beamlet_arr_im(3) <= rx_beamlet_sosi.data(15 DOWNTO 8); -- Y + rx_beamlet_arr_re(3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); IF I < c_sdp_cep_nof_beamlets_per_block / c_nof_beamlets_per_data THEN -- Only capture the first beamlets block of each packet in rx_beamlet_list - rx_beamlet_list_re(I*4 + 0) <= rx_beamlet_sosi.data(55 DOWNTO 48); -- X - rx_beamlet_list_im(I*4 + 0) <= rx_beamlet_sosi.data(63 DOWNTO 56); - rx_beamlet_list_re(I*4 + 1) <= rx_beamlet_sosi.data(39 DOWNTO 32); -- Y - rx_beamlet_list_im(I*4 + 1) <= rx_beamlet_sosi.data(47 DOWNTO 40); - rx_beamlet_list_re(I*4 + 2) <= rx_beamlet_sosi.data(23 DOWNTO 16); -- X - rx_beamlet_list_im(I*4 + 2) <= rx_beamlet_sosi.data(31 DOWNTO 24); - rx_beamlet_list_re(I*4 + 3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); -- Y - rx_beamlet_list_im(I*4 + 3) <= rx_beamlet_sosi.data(15 DOWNTO 8); + rx_beamlet_list_im(I*4 + 0) <= rx_beamlet_sosi.data(63 DOWNTO 56); -- X + rx_beamlet_list_re(I*4 + 0) <= rx_beamlet_sosi.data(55 DOWNTO 48); + rx_beamlet_list_im(I*4 + 1) <= rx_beamlet_sosi.data(47 DOWNTO 40); -- Y + rx_beamlet_list_re(I*4 + 1) <= rx_beamlet_sosi.data(39 DOWNTO 32); + rx_beamlet_list_im(I*4 + 2) <= rx_beamlet_sosi.data(31 DOWNTO 24); -- X + rx_beamlet_list_re(I*4 + 2) <= rx_beamlet_sosi.data(23 DOWNTO 16); + rx_beamlet_list_im(I*4 + 3) <= rx_beamlet_sosi.data(15 DOWNTO 8); -- Y + rx_beamlet_list_re(I*4 + 3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); END IF; proc_common_wait_until_high(ext_clk, rx_beamlet_sosi.valid); -- Use at least one WAIT instead of proc_common_wait_some_cycles() to diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd index 0d6c1fd69a6e2b9fb53dc52eb7b877469314c054..a54b08c9df66879f11ab20630509a0d7882b724c 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_bf_ring/tb_lofar2_unb2c_sdp_station_bf_ring.vhd @@ -265,7 +265,6 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf_ring IS CONSTANT c_exp_remnant_subband_phase : REAL := g_sp_remnant_phase + c_subband_phase_offset + c_subband_weight_phase; CONSTANT c_exp_remnant_subband_ampl : REAL := REAL(c_wg_remnant_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio * c_subband_weight_gain; - TYPE t_real_arr IS ARRAY (INTEGER RANGE <>) OF REAL; TYPE t_slv_64_subbands_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_sub-1); -- 512 TYPE t_slv_64_beamlets_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_beamlets_sdp-1); -- 2*488 = 976 @@ -283,43 +282,22 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_bf_ring IS CONSTANT c_bf_remnant_y_weight_re : INTEGER := INTEGER(COMPLEX_RE(g_bf_remnant_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_y_phase)); CONSTANT c_bf_remnant_y_weight_im : INTEGER := INTEGER(COMPLEX_IM(g_bf_remnant_y_gain * REAL(c_sdp_unit_bf_weight), g_bf_remnant_y_phase)); - -- Model the SDP beamformer for one g_global_sp and g_nof_rn * S_pn - 1 remnant signal inputs - FUNCTION bf_calculate_expected_beamlet(sp_subband_ampl, sp_subband_phase, sp_bf_gain, sp_bf_phase, - rem_subband_ampl, rem_subband_phase, rem_bf_gain, rem_bf_phase : REAL) RETURN t_real_arr IS -- 0:3 = ampl, phase, re, im - CONSTANT c_nof_rem : REAL := REAL(g_nof_rn * c_sdp_S_pn - 1); -- BF for one g_global_sp and N_rn * S_PN - 1 remnant signal inputs - VARIABLE v_sp_ampl, v_sp_phase, v_sp_re, v_sp_im : REAL; - VARIABLE v_rem_ampl, v_rem_phase, v_rem_re, v_rem_im : REAL; - VARIABLE v_sum_ampl, v_sum_phase, v_sum_re, v_sum_im : REAL; - VARIABLE v_tuple : t_real_arr(0 TO 3); - BEGIN - v_sp_ampl := sp_subband_ampl * sp_bf_gain; - v_sp_phase := sp_subband_phase + sp_bf_phase; - v_sp_re := COMPLEX_RE(v_sp_ampl, v_sp_phase); - v_sp_im := COMPLEX_IM(v_sp_ampl, v_sp_phase); - v_rem_ampl := rem_subband_ampl * rem_bf_gain; - v_rem_phase := rem_subband_phase + rem_bf_phase; - v_rem_re := COMPLEX_RE(v_rem_ampl, v_rem_phase); - v_rem_im := COMPLEX_IM(v_rem_ampl, v_rem_phase); - v_sum_re := v_sp_re + c_nof_rem * v_rem_re; -- BF sum re - v_sum_im := v_sp_im + c_nof_rem * v_rem_im; -- BF sum im - v_sum_ampl := COMPLEX_RADIUS(v_sum_re, v_sum_im); - v_sum_phase := COMPLEX_PHASE(v_sum_re, v_sum_im); - v_tuple := (0 => v_sum_ampl, 1 => v_sum_phase, 2 => v_sum_re, 3 => v_sum_im); - RETURN v_tuple; - END; - + -- Model the SDP (remote) beamformer for one g_global_sp and g_nof_rn * S_pn - 1 remnant signal inputs -- . Beamlet internal - CONSTANT c_exp_beamlet_x_tuple : t_real_arr(0 TO 3) := bf_calculate_expected_beamlet( + CONSTANT c_nof_remnant : NATURAL := g_nof_rn * c_sdp_S_pn - 1; + CONSTANT c_exp_beamlet_x_tuple : t_real_arr(0 TO 3) := func_sdp_beamformer( c_exp_subband_ampl, c_exp_subband_phase, g_bf_x_gain, g_bf_x_phase, - c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_x_gain, g_bf_remnant_x_phase); + c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_x_gain, g_bf_remnant_x_phase, + c_nof_remnant); CONSTANT c_exp_beamlet_x_ampl : REAL := c_exp_beamlet_x_tuple(0); CONSTANT c_exp_beamlet_x_phase : REAL := c_exp_beamlet_x_tuple(1); CONSTANT c_exp_beamlet_x_re : REAL := c_exp_beamlet_x_tuple(2); CONSTANT c_exp_beamlet_x_im : REAL := c_exp_beamlet_x_tuple(3); - CONSTANT c_exp_beamlet_y_tuple : t_real_arr(0 TO 3) := bf_calculate_expected_beamlet( + CONSTANT c_exp_beamlet_y_tuple : t_real_arr(0 TO 3) := func_sdp_beamformer( c_exp_subband_ampl, c_exp_subband_phase, g_bf_y_gain, g_bf_y_phase, - c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_y_gain, g_bf_remnant_y_phase); + c_exp_remnant_subband_ampl, c_exp_remnant_subband_phase, g_bf_remnant_y_gain, g_bf_remnant_y_phase, + c_nof_remnant); CONSTANT c_exp_beamlet_y_ampl : REAL := c_exp_beamlet_y_tuple(0); CONSTANT c_exp_beamlet_y_phase : REAL := c_exp_beamlet_y_tuple(1); CONSTANT c_exp_beamlet_y_re : REAL := c_exp_beamlet_y_tuple(2); @@ -1436,24 +1414,24 @@ BEGIN proc_common_wait_until_high(ext_clk, rx_beamlet_sosi.valid); rx_beamlet_valid <= '1'; -- Capture rx beamlets per longword in rx_beamlet_arr, for time series view in Wave window - rx_beamlet_arr_re(0) <= rx_beamlet_sosi.data(55 DOWNTO 48); -- X - rx_beamlet_arr_im(0) <= rx_beamlet_sosi.data(63 DOWNTO 56); - rx_beamlet_arr_re(1) <= rx_beamlet_sosi.data(39 DOWNTO 32); -- Y - rx_beamlet_arr_im(1) <= rx_beamlet_sosi.data(47 DOWNTO 40); - rx_beamlet_arr_re(2) <= rx_beamlet_sosi.data(23 DOWNTO 16); -- X - rx_beamlet_arr_im(2) <= rx_beamlet_sosi.data(31 DOWNTO 24); - rx_beamlet_arr_re(3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); -- Y - rx_beamlet_arr_im(3) <= rx_beamlet_sosi.data(15 DOWNTO 8); + rx_beamlet_arr_im(0) <= rx_beamlet_sosi.data(63 DOWNTO 56); -- X + rx_beamlet_arr_re(0) <= rx_beamlet_sosi.data(55 DOWNTO 48); + rx_beamlet_arr_im(1) <= rx_beamlet_sosi.data(47 DOWNTO 40); -- Y + rx_beamlet_arr_re(1) <= rx_beamlet_sosi.data(39 DOWNTO 32); + rx_beamlet_arr_im(2) <= rx_beamlet_sosi.data(31 DOWNTO 24); -- X + rx_beamlet_arr_re(2) <= rx_beamlet_sosi.data(23 DOWNTO 16); + rx_beamlet_arr_im(3) <= rx_beamlet_sosi.data(15 DOWNTO 8); -- Y + rx_beamlet_arr_re(3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); IF I < c_sdp_cep_nof_beamlets_per_block / c_nof_beamlets_per_data THEN -- Only capture the first beamlets block of each packet in rx_beamlet_list - rx_beamlet_list_re(I*4 + 0) <= rx_beamlet_sosi.data(55 DOWNTO 48); -- X - rx_beamlet_list_im(I*4 + 0) <= rx_beamlet_sosi.data(63 DOWNTO 56); - rx_beamlet_list_re(I*4 + 1) <= rx_beamlet_sosi.data(39 DOWNTO 32); -- Y - rx_beamlet_list_im(I*4 + 1) <= rx_beamlet_sosi.data(47 DOWNTO 40); - rx_beamlet_list_re(I*4 + 2) <= rx_beamlet_sosi.data(23 DOWNTO 16); -- X - rx_beamlet_list_im(I*4 + 2) <= rx_beamlet_sosi.data(31 DOWNTO 24); - rx_beamlet_list_re(I*4 + 3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); -- Y - rx_beamlet_list_im(I*4 + 3) <= rx_beamlet_sosi.data(15 DOWNTO 8); + rx_beamlet_list_im(I*4 + 0) <= rx_beamlet_sosi.data(63 DOWNTO 56); -- X + rx_beamlet_list_re(I*4 + 0) <= rx_beamlet_sosi.data(55 DOWNTO 48); + rx_beamlet_list_im(I*4 + 1) <= rx_beamlet_sosi.data(47 DOWNTO 40); -- Y + rx_beamlet_list_re(I*4 + 1) <= rx_beamlet_sosi.data(39 DOWNTO 32); + rx_beamlet_list_im(I*4 + 2) <= rx_beamlet_sosi.data(31 DOWNTO 24); -- X + rx_beamlet_list_re(I*4 + 2) <= rx_beamlet_sosi.data(23 DOWNTO 16); + rx_beamlet_list_im(I*4 + 3) <= rx_beamlet_sosi.data(15 DOWNTO 8); -- Y + rx_beamlet_list_re(I*4 + 3) <= rx_beamlet_sosi.data( 7 DOWNTO 0); END IF; proc_common_wait_until_high(ext_clk, rx_beamlet_sosi.valid); -- Use at least one WAIT instead of proc_common_wait_some_cycles() to diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd index a22fd834f9ef73e68976c18c5bc16c31cb4f0cef..72d65882396fecb24585fe49f4cff215d85f03e2 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd @@ -33,8 +33,11 @@ -- 2) Read current BSN from reg_bsn_scheduler_wg and write reg_bsn_scheduler_wg -- to trigger start of WG at BSN. -- --- 3) Read subband statistics (SST) via MM and verify with exp_subband_sst at g_subband. +-- 3) Read subband statistics (SST) via MM and verify with exp_sp_subband_sst at g_subband. -- . use weighted subbands (default selected by MM) +-- . g_use_cross_weight = TRUE, then use g_sp_cross_subband_weight_gain/phase and c_cross_sp +-- . g_use_cross_weight = FALSE, then do not use c_cross_sp, so only use g_sp and +-- g_co_subband_weight_gain/phase -- -- 4) View in wave window -- . in_sosi.sop and in_data in u_si_arr(g_sp) to check that: @@ -42,10 +45,10 @@ -- - WG amplitude = 8191 (is full scale - 1) when wg_ampl = 1.0 -- . pfb_sosi_arr(c_pfb_index).im/re and fsub_sosi_arr(c_pfb_index).im/re -- in u_fsub in decimal radix and analog format to check that subband --- phase is g_subband_weight_phase phase as set by the subband weight. +-- phase is g_co_subband_weight_phase phase as set by the subband weight. -- - Raw: pfb_sosi_arr = atan2(-65195 / 0) = -90 degrees -- - Weighted: fsub_sosi_arr = atan2(-56457 / 32598) = -60 degrees --- --> rotated expected g_subband_weight_phase = -60 - -90 = +30 degrees. +-- --> rotated expected g_co_subband_weight_phase = -60 - -90 = +30 degrees. -- -- Usage: -- > as 7 # default @@ -71,16 +74,22 @@ USE dp_lib.dp_stream_pkg.ALL; USE diag_lib.diag_pkg.ALL; USE wpfb_lib.wpfb_pkg.ALL; USE lofar2_sdp_lib.sdp_pkg.ALL; +USE lofar2_sdp_lib.tb_sdp_pkg.ALL; USE unb2c_board_lib.unb2c_board_pkg.ALL; ENTITY tb_lofar2_unb2c_sdp_station_fsub IS GENERIC ( - g_sp : NATURAL := 3; -- signal path index in range(S_pn = 12) - g_wg_ampl : REAL := 1.0; -- WG normalized amplitude - g_subband : NATURAL := 102; -- select subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz - g_subband_weight_gain : REAL := 1.0; -- subband weight normalized gain - g_subband_weight_phase : REAL := 30.0; -- subband weight phase rotation in degrees - g_read_all_SST : BOOLEAN := TRUE -- when FALSE only read SST for g_subband, to save sim time + g_sp : NATURAL := 3; -- signal path index in range(S_pn = 12) of co-polarization + g_co_wg_ampl : REAL := 0.5; -- WG normalized amplitude, use same WG settings for both polarizations (g_sp and c_cross_sp) + g_cross_wg_ampl : REAL := 0.4; -- WG normalized amplitude, use same WG settings for both polarizations (g_sp and c_cross_sp) + g_cross_wg_phase : REAL := 90.0; -- WG phase in degrees for cross-sp, relative to co-sp + g_subband : NATURAL := 102; -- select subband at index 102 = 102/1024 * 200MHz = 19.921875 MHz + g_co_subband_weight_gain : REAL := 1.0; -- subband weight normalized gain, for co-polarization in g_sp + g_co_subband_weight_phase : REAL := 30.0; -- subband weight phase rotation in degrees, for co-polarization in g_sp + g_use_cross_weight : BOOLEAN := TRUE; + g_sp_cross_subband_weight_gain : REAL := 0.5; -- subband weight normalized gain, for cross polarization of g_sp + g_sp_cross_subband_weight_phase : REAL := -10.0; -- subband weight phase rotation in degrees, for cross polarization of g_sp + g_read_all_SST : BOOLEAN := TRUE -- when FALSE only read SST for g_subband, to save sim time ); END tb_lofar2_unb2c_sdp_station_fsub; @@ -91,6 +100,9 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS CONSTANT c_node_nr : NATURAL := 0; CONSTANT c_init_bsn : NATURAL := 17; -- some recognizable value >= 0 + -- signal path index of cross-polarization + CONSTANT c_cross_sp : NATURAL := sel_a_b(g_sp MOD c_sdp_N_pol = 0, g_sp + 1, g_sp - 1); + CONSTANT c_id : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; CONSTANT c_version : STD_LOGIC_VECTOR(1 DOWNTO 0) := "00"; CONSTANT c_fw_version : t_unb2c_board_fw_version := (1, 0); @@ -114,38 +126,62 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS -- WG CONSTANT c_bsn_start_wg : NATURAL := c_init_bsn + 2; -- start WG at this BSN to instead of some BSN, to avoid mismatches in exact expected data values -- .ampl - CONSTANT c_wg_ampl : NATURAL := NATURAL(g_wg_ampl * REAL(c_sdp_FS_adc)); -- in number of lsb - CONSTANT c_exp_sp_power : REAL := REAL(c_wg_ampl**2) / 2.0; - CONSTANT c_exp_sp_ast : REAL := c_exp_sp_power * REAL(c_nof_clk_per_sync); + CONSTANT c_co_wg_ampl : NATURAL := NATURAL(g_co_wg_ampl * REAL(c_sdp_FS_adc)); -- in number of lsb + CONSTANT c_cross_wg_ampl : NATURAL := NATURAL(g_cross_wg_ampl * REAL(c_sdp_FS_adc)); -- in number of lsb + CONSTANT c_exp_co_sp_power : REAL := REAL(c_co_wg_ampl**2) / 2.0; + CONSTANT c_exp_cross_sp_power : REAL := REAL(c_cross_wg_ampl**2) / 2.0; + CONSTANT c_exp_co_sp_ast : REAL := c_exp_co_sp_power * REAL(c_nof_clk_per_sync); + CONSTANT c_exp_cross_sp_ast : REAL := c_exp_cross_sp_power * REAL(c_nof_clk_per_sync); + -- . freq + CONSTANT c_subband_freq : REAL := REAL(g_subband) / REAL(c_sdp_N_fft); -- normalized by fs = f_adc = 200 MHz is dp_clk -- . phase CONSTANT c_subband_phase : REAL := 0.0; -- wanted subband phase in degrees = WG phase at sop - CONSTANT c_subband_freq : REAL := REAL(g_subband) / REAL(c_sdp_N_fft); -- normalized by fs = f_adc = 200 MHz is dp_clk CONSTANT c_wg_latency : INTEGER := c_diag_wg_latency - 0; -- -0 to account for BSN scheduler start trigger latency CONSTANT c_wg_phase_offset : REAL := 360.0 * REAL(c_wg_latency) * c_subband_freq; -- c_diag_wg_latency is in dp_clk cycles CONSTANT c_wg_phase : REAL := c_subband_phase + c_wg_phase_offset; -- WG phase in degrees + CONSTANT c_co_wg_phase : REAL := c_wg_phase; + CONSTANT c_cross_wg_phase : REAL := c_wg_phase + g_cross_wg_phase; + CONSTANT c_subband_phase_offset : REAL := -90.0; -- WG with zero phase sinus yields subband with -90 degrees phase (negative Im, zero Re) + CONSTANT c_co_subband_phase : REAL := c_subband_phase_offset + c_co_wg_phase; + CONSTANT c_cross_subband_phase : REAL := c_subband_phase_offset + c_cross_wg_phase; -- FSUB - -- . WPFB - CONSTANT c_pol_index : NATURAL := g_sp MOD c_sdp_Q_fft; - CONSTANT c_pfb_index : NATURAL := g_sp / c_sdp_Q_fft; -- only read used WPFB unit out of range(c_sdp_P_pfb = 6) - CONSTANT c_exp_subband_ampl_raw : REAL := REAL(c_wg_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio; - CONSTANT c_exp_subband_ampl_weighted : REAL := c_exp_subband_ampl_raw * g_subband_weight_gain; - CONSTANT c_exp_subband_power_raw : REAL := c_exp_subband_ampl_raw**2.0; -- complex signal ampl, so power is A**2 (not A**2 / 2 as for real) - CONSTANT c_exp_subband_power_weighted : REAL := c_exp_subband_ampl_weighted**2.0; -- complex signal ampl, so power is A**2 (not A**2 / 2 as for real) - CONSTANT c_exp_subband_sst_raw : REAL := c_exp_subband_power_raw * REAL(c_nof_block_per_sync); - CONSTANT c_exp_subband_sst_weighted : REAL := c_exp_subband_power_weighted * REAL(c_nof_block_per_sync); + CONSTANT c_pol_index : NATURAL := g_sp MOD c_sdp_Q_fft; + CONSTANT c_pfb_index : NATURAL := g_sp / c_sdp_Q_fft; -- only read used WPFB unit out of range(c_sdp_P_pfb = 6) + + CONSTANT c_exp_co_subband_ampl_raw : REAL := REAL(c_co_wg_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio; + CONSTANT c_exp_cross_subband_ampl_raw : REAL := REAL(c_cross_wg_ampl) * c_sdp_wpfb_subband_sp_ampl_ratio; + CONSTANT c_exp_co_subband_ampl_weighted : REAL := c_exp_co_subband_ampl_raw * g_co_subband_weight_gain; + CONSTANT c_exp_cross_subband_ampl_weighted : REAL := c_exp_cross_subband_ampl_raw * 1.0; -- unit gain, this is co gain for cross sp + CONSTANT c_exp_jones_subband_tuple : t_real_arr(0 TO 3) := func_sdp_subband_equalizer( + c_exp_co_subband_ampl_raw, c_co_subband_phase, g_co_subband_weight_gain, g_co_subband_weight_phase, + c_exp_cross_subband_ampl_raw, c_cross_subband_phase, g_sp_cross_subband_weight_gain, g_sp_cross_subband_weight_phase); + CONSTANT c_exp_sp_subband_ampl_weighted : REAL := sel_a_b(g_use_cross_weight, c_exp_jones_subband_tuple(0), c_exp_co_subband_ampl_weighted); + + CONSTANT c_exp_co_subband_power_raw : REAL := c_exp_co_subband_ampl_raw**2.0; -- complex signal ampl, so power is A**2 (not A**2 / 2 as for real) + CONSTANT c_exp_cross_subband_power_raw : REAL := c_exp_cross_subband_ampl_raw**2.0; + CONSTANT c_exp_sp_subband_power_weighted : REAL := c_exp_sp_subband_ampl_weighted**2.0; + CONSTANT c_exp_cross_subband_power_weighted : REAL := c_exp_cross_subband_ampl_weighted**2.0; + CONSTANT c_exp_co_subband_sst_raw : REAL := c_exp_co_subband_power_raw * REAL(c_nof_block_per_sync); + CONSTANT c_exp_cross_subband_sst_raw : REAL := c_exp_cross_subband_power_raw * REAL(c_nof_block_per_sync); + CONSTANT c_exp_sp_subband_sst_weighted : REAL := c_exp_sp_subband_power_weighted * REAL(c_nof_block_per_sync); + CONSTANT c_exp_cross_subband_sst_weighted : REAL := c_exp_cross_subband_power_weighted * REAL(c_nof_block_per_sync); -- . expected limit values, obtained with print_str() for g_subband = 102, - -- g_wg_ampl = 1.0, g_subband_weight_gain = 1.0, g_subband_weight_phase = 30.0 - CONSTANT c_exp_subband_sst_leakage_snr_dB : REAL := 70.0; -- < 74.913 - CONSTANT c_exp_subband_sst_crosstalk_snr_dB : REAL := 90.0; -- < 96.284 + -- g_co_wg_ampl = 1.0, g_co_subband_weight_gain = 1.0, g_co_subband_weight_phase = 30.0 + CONSTANT c_exp_sp_subband_sst_leakage_snr_dB : REAL := 70.0; -- < 74.913 + CONSTANT c_exp_sp_subband_sst_crosstalk_snr_dB : REAL := 90.0; -- < 96.284 TYPE t_real_arr IS ARRAY (INTEGER RANGE <>) OF REAL; TyPE t_slv_64_subbands_arr IS ARRAY (INTEGER RANGE <>) OF t_slv_64_arr(0 TO c_sdp_N_sub-1); -- . Subband weights for selected g_sp - CONSTANT c_subband_weight_re : INTEGER := INTEGER(g_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * COS(g_subband_weight_phase * MATH_2_PI / 360.0)); - CONSTANT c_subband_weight_im : INTEGER := INTEGER(g_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * SIN(g_subband_weight_phase * MATH_2_PI / 360.0)); + CONSTANT c_co_subband_weight_re : INTEGER := INTEGER(g_co_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * COS(g_co_subband_weight_phase * MATH_2_PI / 360.0)); + CONSTANT c_co_subband_weight_im : INTEGER := INTEGER(g_co_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * SIN(g_co_subband_weight_phase * MATH_2_PI / 360.0)); + + -- . Subband weights cross for selected g_sp + CONSTANT c_sp_cross_subband_weight_re : INTEGER := INTEGER(g_sp_cross_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * COS(g_sp_cross_subband_weight_phase * MATH_2_PI / 360.0)); + CONSTANT c_sp_cross_subband_weight_im : INTEGER := INTEGER(g_sp_cross_subband_weight_gain * REAL(c_sdp_unit_sub_weight) * SIN(g_sp_cross_subband_weight_phase * MATH_2_PI / 360.0)); -- MM -- . Address widths of a single MM instance @@ -153,12 +189,13 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS -- . Address spans of a single MM instance CONSTANT c_mm_span_reg_diag_wg : NATURAL := 2**c_addr_w_reg_diag_wg; - CONSTANT c_mm_file_reg_bsn_source_v2 : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2"; - CONSTANT c_mm_file_reg_bsn_scheduler_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SCHEDULER"; - CONSTANT c_mm_file_reg_diag_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_WG"; - CONSTANT c_mm_file_ram_equalizer_gains : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_EQUALIZER_GAINS"; - CONSTANT c_mm_file_reg_dp_selector : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_DP_SELECTOR"; - CONSTANT c_mm_file_ram_st_sst : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_ST_SST"; + CONSTANT c_mm_file_reg_bsn_source_v2 : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SOURCE_V2"; + CONSTANT c_mm_file_reg_bsn_scheduler_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_BSN_SCHEDULER"; + CONSTANT c_mm_file_reg_diag_wg : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_WG"; + CONSTANT c_mm_file_ram_equalizer_gains : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_EQUALIZER_GAINS"; + CONSTANT c_mm_file_ram_equalizer_gains_cross : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_EQUALIZER_GAINS_CROSS"; + CONSTANT c_mm_file_reg_dp_selector : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "REG_DP_SELECTOR"; + CONSTANT c_mm_file_ram_st_sst : STRING := mmf_unb_file_prefix(c_unb_nr, c_node_nr) & "RAM_ST_SST"; -- Tb SIGNAL tb_end : STD_LOGIC := '0'; @@ -177,24 +214,33 @@ ARCHITECTURE tb OF tb_lofar2_unb2c_sdp_station_fsub IS SIGNAL sp_subband_ssts_arr2 : t_slv_64_subbands_arr(c_sdp_N_pol-1 DOWNTO 0); -- [pol][sub] SIGNAL sp_subband_sst_sum_arr : t_real_arr(c_sdp_N_pol-1 DOWNTO 0) := (OTHERS => 0.0); SIGNAL sp_subband_sst : REAL := 0.0; + SIGNAL sp_cross_subband_sst : REAL := 0.0; SIGNAL sp_subband_sst_leakage : REAL := 0.0; SIGNAL sp_subband_sst_leakage_snr_dB : REAL := 0.0; -- signal to noise (leakage) ratio SIGNAL sp_subband_sst_crosstalk : REAL := 0.0; SIGNAL sp_subband_sst_crosstalk_snr_dB : REAL := 0.0; -- signal to noise (crosstalk) ration - SIGNAL exp_subband_ampl : REAL := 0.0; - SIGNAL exp_subband_power : REAL := 0.0; - SIGNAL exp_subband_sst : REAL := 0.0; - SIGNAL stat_data : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0); + SIGNAL exp_sp_subband_ampl : REAL := 0.0; + SIGNAL exp_sp_subband_power : REAL := 0.0; + SIGNAL exp_sp_subband_sst : REAL := 0.0; + SIGNAL exp_cross_subband_sst : REAL := 0.0; + SIGNAL stat_data : STD_LOGIC_VECTOR(c_longword_w-1 DOWNTO 0); -- . Selector SIGNAL sst_offload_weighted_subbands : STD_LOGIC; -- . Subband equalizer - SIGNAL sp_subband_weight_re : INTEGER := 0; - SIGNAL sp_subband_weight_im : INTEGER := 0; - SIGNAL sp_subband_weight_gain : REAL := 0.0; - SIGNAL sp_subband_weight_phase : REAL := 0.0; + SIGNAL sp_co_subband_weight_re : INTEGER := 0; + SIGNAL sp_co_subband_weight_im : INTEGER := 0; + SIGNAL sp_co_subband_weight_gain : REAL := 0.0; + SIGNAL sp_co_subband_weight_phase : REAL := 0.0; + SIGNAL sp_co_subband_weight_val : STD_LOGIC := '0'; + + SIGNAL sp_cross_subband_weight_re : INTEGER := 0; + SIGNAL sp_cross_subband_weight_im : INTEGER := 0; + SIGNAL sp_cross_subband_weight_gain : REAL := 0.0; + SIGNAL sp_cross_subband_weight_phase : REAL := 0.0; + SIGNAL sp_cross_subband_weight_val : STD_LOGIC := '0'; -- DUT SIGNAL ext_clk : STD_LOGIC := '0'; @@ -279,9 +325,10 @@ BEGIN ); -- Raw or weighted subbands - exp_subband_ampl <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_subband_ampl_raw, c_exp_subband_ampl_weighted); - exp_subband_power <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_subband_power_raw, c_exp_subband_power_weighted); - exp_subband_sst <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_subband_sst_raw, c_exp_subband_sst_weighted); + exp_sp_subband_ampl <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_co_subband_ampl_raw, c_exp_sp_subband_ampl_weighted); + exp_sp_subband_power <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_co_subband_power_raw, c_exp_sp_subband_power_weighted); + exp_sp_subband_sst <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_co_subband_sst_raw, c_exp_sp_subband_sst_weighted); + exp_cross_subband_sst <= sel_a_b(sst_offload_weighted_subbands = '0', c_exp_cross_subband_sst_raw, c_exp_cross_subband_sst_weighted); ------------------------------------------------------------------------------ -- MM slave accesses via file IO @@ -327,11 +374,21 @@ BEGIN -- 1 : phase[15:0] -- 2 : freq[30:0] -- 3 : ampl[16:0] + -- g_sp is co-polarization v_offset := g_sp * c_mm_span_reg_diag_wg; mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_wg_phase * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_co_wg_phase * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, INTEGER(REAL(g_subband) * c_sdp_wg_subband_freq_unit), tb_clk); -- freq - mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_wg_ampl) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_co_wg_ampl) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl + + IF g_use_cross_weight THEN + -- c_cross_sp is cross-polarization for g_sp, use same WG settings for c_cross_sp as for g_sp + v_offset := c_cross_sp * c_mm_span_reg_diag_wg; + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 0, 1024*2**16 + 1, tb_clk); -- nof_samples, mode calc + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 1, INTEGER(c_cross_wg_phase * c_diag_wg_phase_unit), tb_clk); -- phase offset in degrees + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, INTEGER(REAL(g_subband) * c_sdp_wg_subband_freq_unit), tb_clk); -- freq + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, INTEGER(REAL(c_cross_wg_ampl) * c_sdp_wg_ampl_lsb), tb_clk); -- ampl + END IF; -- Read current BSN mmf_mm_bus_rd(c_mm_file_reg_bsn_scheduler_wg, 0, current_bsn_wg(31 DOWNTO 0), tb_clk); @@ -347,27 +404,70 @@ BEGIN ---------------------------------------------------------------------------- -- Write subband weight for selected g_sp and g_subband ---------------------------------------------------------------------------- + + -- Co-polarization subband weight for g_sp -- . MM format: (cint16)RAM_EQUALIZER_GAINS[S_pn/Q_fft]_[Q_fft][N_sub] = [S_pn][N_sub] v_addr := g_sp * c_sdp_N_sub + g_subband; -- . read mmf_mm_bus_rd(c_mm_file_ram_equalizer_gains, v_addr, rd_data, tb_clk); v_re := unpack_complex_re(rd_data, c_sdp_W_sub_weight); v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight); - sp_subband_weight_re <= v_re; - sp_subband_weight_im <= v_im; - sp_subband_weight_gain <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_sub_weight); - sp_subband_weight_phase <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI; + sp_co_subband_weight_re <= v_re; + sp_co_subband_weight_im <= v_im; + sp_co_subband_weight_gain <= COMPLEX_RADIUS(REAL(v_re), REAL(v_im)) / REAL(c_sdp_unit_sub_weight); + sp_co_subband_weight_phase <= COMPLEX_PHASE(REAL(v_re), REAL(v_im)); + sp_co_subband_weight_val <= '1'; + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT sp_co_subband_weight_re = c_sdp_unit_sub_weight REPORT "Default sp_co_subband_weight_re /= c_sdp_unit_sub_weight" SEVERITY ERROR; + ASSERT sp_co_subband_weight_im = 0 REPORT "Default sp_co_subband_weight_im /= 0" SEVERITY ERROR; -- . write - v_weight := pack_complex(re => c_subband_weight_re, im => c_subband_weight_im, w => c_sdp_W_sub_weight); -- c_sdp_W_sub_weight = 16 bit + v_weight := pack_complex(re => c_co_subband_weight_re, im => c_co_subband_weight_im, w => c_sdp_W_sub_weight); -- c_sdp_W_sub_weight = 16 bit mmf_mm_bus_wr(c_mm_file_ram_equalizer_gains, v_addr, v_weight, tb_clk); + proc_common_wait_cross_clock_domain_latency(c_tb_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency*2); -- . read back mmf_mm_bus_rd(c_mm_file_ram_equalizer_gains, v_addr, rd_data, tb_clk); v_re := unpack_complex_re(rd_data, c_sdp_W_sub_weight); v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight); - sp_subband_weight_re <= v_re; - sp_subband_weight_im <= v_im; - sp_subband_weight_gain <= SQRT(REAL(v_re)**2.0 + REAL(v_im)**2.0) / REAL(c_sdp_unit_sub_weight); - sp_subband_weight_phase <= atan2(Y => REAL(v_im), X => REAL(v_re)) * 360.0 / MATH_2_PI; + sp_co_subband_weight_re <= v_re; + sp_co_subband_weight_im <= v_im; + sp_co_subband_weight_gain <= COMPLEX_RADIUS(REAL(v_re), REAL(v_im)) / REAL(c_sdp_unit_sub_weight); + sp_co_subband_weight_phase <= COMPLEX_PHASE(REAL(v_re), REAL(v_im)); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT sp_co_subband_weight_re = c_co_subband_weight_re REPORT "Readback sp_co_subband_weight_re /= c_co_subband_weight_re" SEVERITY ERROR; + ASSERT sp_co_subband_weight_im = c_co_subband_weight_im REPORT "Readback sp_co_subband_weight_im /= c_co_subband_weight_im" SEVERITY ERROR; + + IF g_use_cross_weight THEN + -- Cross-polarization subband weight for g_sp + -- . MM format: (cint16)RAM_EQUALIZER_GAINS_CROSS[S_pn/Q_fft]_[Q_fft][N_sub] = [S_pn][N_sub] + v_addr := g_sp * c_sdp_N_sub + g_subband; + -- . read + mmf_mm_bus_rd(c_mm_file_ram_equalizer_gains_cross, v_addr, rd_data, tb_clk); + v_re := unpack_complex_re(rd_data, c_sdp_W_sub_weight); + v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight); + sp_cross_subband_weight_re <= v_re; + sp_cross_subband_weight_im <= v_im; + sp_cross_subband_weight_gain <= COMPLEX_RADIUS(REAL(v_re), REAL(v_im)) / REAL(c_sdp_unit_sub_weight); + sp_cross_subband_weight_phase <= COMPLEX_PHASE(REAL(v_re), REAL(v_im)); + sp_cross_subband_weight_val <= '1'; + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT sp_cross_subband_weight_re = 0 REPORT "Default sp_cross_subband_weight_re /= 0" SEVERITY ERROR; + ASSERT sp_cross_subband_weight_im = 0 REPORT "Default sp_cross_subband_weight_im /= 0" SEVERITY ERROR; + -- . write + v_weight := pack_complex(re => c_sp_cross_subband_weight_re, im => c_sp_cross_subband_weight_im, w => c_sdp_W_sub_weight); -- c_sdp_W_sub_weight = 16 bit + mmf_mm_bus_wr(c_mm_file_ram_equalizer_gains_cross, v_addr, v_weight, tb_clk); + proc_common_wait_cross_clock_domain_latency(c_tb_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency*2); + -- . read back + mmf_mm_bus_rd(c_mm_file_ram_equalizer_gains_cross, v_addr, rd_data, tb_clk); + v_re := unpack_complex_re(rd_data, c_sdp_W_sub_weight); + v_im := unpack_complex_im(rd_data, c_sdp_W_sub_weight); + sp_cross_subband_weight_re <= v_re; + sp_cross_subband_weight_im <= v_im; + sp_cross_subband_weight_gain <= COMPLEX_RADIUS(REAL(v_re), REAL(v_im)) / REAL(c_sdp_unit_sub_weight); + sp_cross_subband_weight_phase <= COMPLEX_PHASE(REAL(v_re), REAL(v_im)); + proc_common_wait_some_cycles(tb_clk, 1); + ASSERT sp_cross_subband_weight_re = c_sp_cross_subband_weight_re REPORT "Readback sp_cross_subband_weight_re /= c_sp_cross_subband_weight_re" SEVERITY ERROR; + ASSERT sp_cross_subband_weight_im = c_sp_cross_subband_weight_im REPORT "Readback sp_cross_subband_weight_im /= c_sp_cross_subband_weight_im" SEVERITY ERROR; + END IF; ---------------------------------------------------------------------------- -- Wait for enough WG data and start of sync interval @@ -423,6 +523,8 @@ BEGIN -- to sp_subband_sst_sum_arr(c_pol_index), because the input is a -- sinus, so most power will be in 1 subband. sp_subband_sst <= TO_UREAL(sp_subband_ssts_arr2(c_pol_index)(g_subband)); + -- Subband power of g_subband in c_cross_sp + sp_cross_subband_sst <= TO_UREAL(sp_subband_ssts_arr2(not_int(c_pol_index))(g_subband)); proc_common_wait_some_cycles(tb_clk, 1); -- The sp_subband_sst_leakage shows how much power from the input sinus at a specific @@ -436,15 +538,18 @@ BEGIN REPORT "Wrong, zero leakage is unexpected for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR; END IF; - -- The sp_subband_sst_crosstalk shows how much power from one WPFB input cross talks - -- into the other output, due to quantization cross talk in the complex FFT. The power - -- ration indicates the suppression, provided that the other input was zero. - v_power := sp_subband_sst_sum_arr(not_int(c_pol_index)); - sp_subband_sst_crosstalk <= v_power; - IF sp_subband_sst > c_eps AND v_power > c_eps THEN - sp_subband_sst_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_sst / v_power); - ELSIF g_read_all_SST THEN - REPORT "Zero crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY NOTE; + IF NOT g_use_cross_weight THEN + -- The other WPFB input WG at c_cross_sp is not used, so it should have ~ zero power. + -- The sp_subband_sst_crosstalk shows how much power from one WPFB input cross talks + -- into the other output, due to quantization cross talk in the complex FFT. The power + -- ration indicates the suppression, provided that the other input was zero. + v_power := sp_subband_sst_sum_arr(not_int(c_pol_index)); -- not_int(0) = 1, not_int(/= 0) = 0 + sp_subband_sst_crosstalk <= v_power; + IF sp_subband_sst > c_eps AND v_power > c_eps THEN + sp_subband_sst_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_sst / v_power); + ELSIF g_read_all_SST THEN + REPORT "Zero crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY NOTE; + END IF; END IF; proc_common_wait_some_cycles(tb_clk, 10); @@ -454,50 +559,67 @@ BEGIN --------------------------------------------------------------------------- print_str(""); print_str("WG:"); - print_str(". c_wg_ampl = " & int_to_str(c_wg_ampl)); - print_str(". c_exp_sp_power = " & real_to_str(c_exp_sp_power, 20, 1)); - print_str(". c_exp_sp_ast = " & real_to_str(c_exp_sp_ast, 20, 1)); + print_str(". c_co_wg_ampl for g_sp = " & int_to_str(c_co_wg_ampl)); + print_str(". c_cross_wg_ampl for c_cross_sp = " & int_to_str(c_cross_wg_ampl)); print_str(""); print_str("Subband selector:"); - print_str(". sst_offload_weighted_subbands = " & sl_to_str(sst_offload_weighted_subbands)); + print_str(". sst_offload_weighted_subbands = " & sl_to_str(sst_offload_weighted_subbands)); print_str(""); - print_str("Subband weight:"); - print_str(". sp_subband_weight_gain = " & real_to_str(sp_subband_weight_gain, 20, 6)); - print_str(". sp_subband_weight_phase = " & real_to_str(sp_subband_weight_phase, 20, 6)); + print_str("Subband weights for g_sp:"); + print_str(". sp_co_subband_weight_gain = " & real_to_str(sp_co_subband_weight_gain, 20, 6)); + print_str(". sp_co_subband_weight_phase = " & real_to_str(sp_co_subband_weight_phase, 20, 6)); + IF g_use_cross_weight THEN + print_str(". sp_cross_subband_weight_gain = " & real_to_str(sp_cross_subband_weight_gain, 20, 6)); + print_str(". sp_cross_subband_weight_phase = " & real_to_str(sp_cross_subband_weight_phase, 20, 6)); + END IF; print_str(""); print_str("SST results:"); - print_str(". exp_subband_ampl = " & int_to_str(NATURAL(exp_subband_ampl))); - print_str(". exp_subband_power = " & real_to_str(exp_subband_power, 20, 1)); - print_str(". exp_subband_sst = " & real_to_str(exp_subband_sst, 20, 1)); + print_str(". exp_sp_subband_ampl = " & int_to_str(NATURAL(exp_sp_subband_ampl))); + print_str(". exp_sp_subband_power = " & real_to_str(exp_sp_subband_power, 20, 1)); + print_str(". exp_sp_subband_sst = " & real_to_str(exp_sp_subband_sst, 20, 1)); + print_str(". exp_cross_subband_sst = " & real_to_str(exp_cross_subband_sst, 20, 1)); print_str(""); - print_str(". sp_subband_sst = " & real_to_str(sp_subband_sst, 20, 1)); - print_str(". sp_subband_sst / exp_subband_sst = " & real_to_str(sp_subband_sst / exp_subband_sst, 20, 6)); + print_str(". sp_subband_sst = " & real_to_str(sp_subband_sst, 20, 1)); + print_str(". sp_subband_sst / exp_sp_subband_sst = " & real_to_str(sp_subband_sst / exp_sp_subband_sst, 20, 6)); + print_str(". sp_cross_subband_sst = " & real_to_str(sp_cross_subband_sst, 20, 1)); + print_str(". sp_cross_subband_sst / exp_cross_subband_sst = " & real_to_str(sp_cross_subband_sst / exp_cross_subband_sst, 20, 6)); IF g_read_all_SST THEN -- Log WPFB details, these are allready verified in tb of wpfb_unit_dev.vhd, so here -- quality indicators like leakage and crosstalk are also reported out of interest. print_str(""); print_str("SST quality indicators"); - print_str(". sp_subband_sst_leakage = " & real_to_str(sp_subband_sst_leakage, 20, 0)); - print_str(". sp_subband_sst_leakage_snr_dB = " & real_to_str(sp_subband_sst_leakage_snr_dB, 20, 3)); - print_str(". sp_subband_sst_crosstalk = " & real_to_str(sp_subband_sst_crosstalk, 20, 0)); - print_str(". sp_subband_sst_crosstalk_snr_db = " & real_to_str(sp_subband_sst_crosstalk_snr_db, 20, 3)); + print_str(". sp_subband_sst_leakage = " & real_to_str(sp_subband_sst_leakage, 20, 0)); + print_str(". sp_subband_sst_leakage_snr_dB = " & real_to_str(sp_subband_sst_leakage_snr_dB, 20, 3)); + IF NOT g_use_cross_weight THEN + print_str(". sp_subband_sst_crosstalk = " & real_to_str(sp_subband_sst_crosstalk, 20, 0)); + print_str(". sp_subband_sst_crosstalk_snr_db = " & real_to_str(sp_subband_sst_crosstalk_snr_db, 20, 3)); + END IF; END IF; --------------------------------------------------------------------------- -- Verify SST --------------------------------------------------------------------------- - -- verify expected subband power based on WG power - ASSERT sp_subband_sst > c_lo_factor * exp_subband_sst REPORT "Wrong subband power for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; - ASSERT sp_subband_sst < c_hi_factor * exp_subband_sst REPORT "Wrong subband power for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + -- Verify expected subband power based on WG power for g_sp + ASSERT sp_subband_sst > c_lo_factor * exp_sp_subband_sst REPORT "Wrong subband power for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + ASSERT sp_subband_sst < c_hi_factor * exp_sp_subband_sst REPORT "Wrong subband power for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + IF g_use_cross_weight THEN + -- Verify expected subband power based on WG power for c_cross_sp + -- The other WPFB input WG at c_cross_sp is used as cross polarization input, with default + -- unit co-polarization subband weight and zero cross-polarization subband weight. + ASSERT sp_cross_subband_sst > c_lo_factor * exp_cross_subband_sst REPORT "Wrong subband power for cross SP " & NATURAL'IMAGE(c_cross_sp) SEVERITY ERROR; + ASSERT sp_cross_subband_sst < c_hi_factor * exp_cross_subband_sst REPORT "Wrong subband power for cross SP " & NATURAL'IMAGE(c_cross_sp) SEVERITY ERROR; + END IF; IF g_read_all_SST THEN -- Verify expected SNR quality measures - ASSERT sp_subband_sst_leakage = 0.0 OR sp_subband_sst_leakage_snr_dB > c_exp_subband_sst_leakage_snr_dB REPORT "Wrong too much leakage for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; - ASSERT sp_subband_sst_crosstalk = 0.0 OR sp_subband_sst_crosstalk_snr_dB > c_exp_subband_sst_crosstalk_snr_dB REPORT "Wrong too much crosstalk for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + ASSERT sp_subband_sst_leakage = 0.0 OR sp_subband_sst_leakage_snr_dB > c_exp_sp_subband_sst_leakage_snr_dB REPORT "Wrong too much leakage for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + IF NOT g_use_cross_weight THEN + ASSERT sp_subband_sst_crosstalk = 0.0 OR sp_subband_sst_crosstalk_snr_dB > c_exp_sp_subband_sst_crosstalk_snr_dB REPORT "Wrong too much crosstalk for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + END IF; END IF; --------------------------------------------------------------------------- diff --git a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_oversampled_filterbank.vhd b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_oversampled_filterbank.vhd index c5e3babf49bcb77568dc796923ab222233061423..bec60072a6ac16140d3fcd74bb33d0a8cdfc6a99 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_oversampled_filterbank.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/node_sdp_oversampled_filterbank.vhd @@ -107,7 +107,10 @@ ARCHITECTURE str OF node_sdp_oversampled_filterbank IS NATURAL'IMAGE(c_sdp_W_sub_weight) & "b" & NATURAL'IMAGE(c_sdp_W_sub_weight_fraction) & "f_unit"; - -- Use quantized subbands + -- Use quantized subbands, so c_subband_raw_dat_w = 18b. + -- . Maybe later use raw subbands like in node_sdp_filterbank, but for now + -- appling subband weights and bf weights at c_sdp_W_subband = 18b subbands + -- is acceptable. CONSTANT c_subband_raw_dat_w : NATURAL := c_sdp_W_subband; CONSTANT c_subband_raw_fraction_w : NATURAL := 0; @@ -118,11 +121,11 @@ ARCHITECTURE str OF node_sdp_oversampled_filterbank IS CONSTANT c_complex_pfb_pipeline : NATURAL := 2; -- Use WG as local oscillator, buf contains 16b sin and 16b cos - -- . c_sdp_W_local_oscillator = c_halfword_w = 16b + -- . c_sdp_W_local_oscillator = 16b -- . c_sdp_W_local_oscillator_fraction = 16b - 1 sign bit = 15b CONSTANT c_buf : t_c_mem := (latency => 1, adr_w => ceil_log2(2 * c_sdp_N_fft), - dat_w => c_nof_complex * c_halfword_w, + dat_w => c_nof_complex * c_sdp_W_local_oscillator, nof_dat => c_sdp_R_os * c_sdp_N_fft, init_sl => '0'); @@ -171,18 +174,22 @@ ARCHITECTURE str OF node_sdp_oversampled_filterbank IS SIGNAL wpfb_unit_out_sosi_arr_piped : t_dp_sosi_arr(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); -- Mixer to shift f_sub/2 - SIGNAL complex_mult_src_out_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); - SIGNAL requantize_src_out_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL mixer_complex_mult_src_out_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL mixer_complex_requantize_src_out_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + -- Complex input FFT (from LO mixer) SIGNAL wpfb_unit_complex_in_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); SIGNAL wpfb_unit_complex_fil_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); SIGNAL wpfb_unit_complex_out_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); - SIGNAL wpfb_unit_out_resized_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); - SIGNAL wpfb_fifo_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); - SIGNAL wpfb_fifo_siso_arr : t_dp_siso_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_siso_rst); - SIGNAL wpfb_resized_sosi_2arr : t_dp_sosi_2arr_2(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => (OTHERS => c_dp_sosi_rst)); - SIGNAL wpfb_resized_siso_2arr : t_dp_siso_2arr_2(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => (OTHERS => c_dp_siso_rst)); + -- Remove negative frequencies + SIGNAL wpfb_complex_out_resized_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + + -- Interleave positive frequencies per factor Q_fft = 2, like with output of real input FFT + SIGNAL wpfb_complex_out_fifo_sosi_arr : t_dp_sosi_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL wpfb_complex_out_fifo_siso_arr : t_dp_siso_arr(c_sdp_S_pn-1 DOWNTO 0) := (OTHERS => c_dp_siso_rst); + SIGNAL wpfb_complex_out_resized_sosi_2arr : t_dp_sosi_2arr_2(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => (OTHERS => c_dp_sosi_rst)); + SIGNAL wpfb_complex_out_resized_siso_2arr : t_dp_siso_2arr_2(c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => (OTHERS => c_dp_siso_rst)); SIGNAL subband_equalizer_in_sosi_arr : t_dp_sosi_arr(c_sdp_R_os * c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); SIGNAL subband_equalizer_out_sosi_arr : t_dp_sosi_arr(c_sdp_R_os * c_sdp_P_pfb-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); @@ -342,23 +349,23 @@ BEGIN gen_complex_mult: FOR I IN 0 TO c_sdp_S_pn-1 GENERATE u_common_complex_mult : ENTITY common_mult_lib.common_complex_mult GENERIC MAP ( - g_in_a_w => c_halfword_w, -- = c_sdp_W_local_oscillator = 16 - g_in_b_w => c_sdp_W_adc, - g_out_p_w => c_halfword_w + c_sdp_W_adc, + g_in_a_w => c_sdp_W_local_oscillator, -- = 16 + g_in_b_w => c_sdp_W_adc, -- = 14 + g_out_p_w => c_sdp_W_local_oscillator + c_sdp_W_adc, -- = 16 + 14 = 30 g_conjugate_b => FALSE ) PORT MAP ( clk => dp_clk, clken => '1', rst => dp_rst, - in_ar => wg_out_dat(c_halfword_w-1 DOWNTO 0), - in_ai => wg_out_dat(2 * c_halfword_w-1 DOWNTO c_halfword_w), + in_ar => wg_out_dat(c_sdp_W_local_oscillator-1 DOWNTO 0), + in_ai => wg_out_dat(2 * c_sdp_W_local_oscillator-1 DOWNTO c_sdp_W_local_oscillator), in_br => si_sosi_arr(I).data(c_sdp_W_adc-1 DOWNTO 0), in_bi => (OTHERS => '0'), in_val => si_sosi_arr(I).valid, - out_pr => complex_mult_src_out_arr(I).re(c_halfword_w + c_sdp_W_adc-1 DOWNTO 0), - out_pi => complex_mult_src_out_arr(I).im(c_halfword_w + c_sdp_W_adc-1 DOWNTO 0), - out_val => complex_mult_src_out_arr(I).valid + out_pr => mixer_complex_mult_src_out_arr(I).re(c_sdp_W_local_oscillator + c_sdp_W_adc-1 DOWNTO 0), + out_pi => mixer_complex_mult_src_out_arr(I).im(c_sdp_W_local_oscillator + c_sdp_W_adc-1 DOWNTO 0), + out_val => mixer_complex_mult_src_out_arr(I).valid ); --requantize @@ -373,16 +380,16 @@ BEGIN g_msb_clip_symmetric => FALSE, g_pipeline_remove_lsb => 0, g_pipeline_remove_msb => 0, - g_in_dat_w => c_halfword_w + c_sdp_W_adc, + g_in_dat_w => c_sdp_W_local_oscillator + c_sdp_W_adc, g_out_dat_w => c_sdp_W_adc ) PORT MAP ( rst => dp_rst, clk => dp_clk, -- ST sink - snk_in => complex_mult_src_out_arr(I), + snk_in => mixer_complex_mult_src_out_arr(I), -- ST source - src_out => requantize_src_out_arr(I) + src_out => mixer_complex_requantize_src_out_arr(I) ); END GENERATE; @@ -411,12 +418,12 @@ BEGIN in_dat => dp_bsn_source_restart_pipe, out_dat => dp_bsn_source_restart_pipe_complex ); - PROCESS(requantize_src_out_arr, si_sosi_0_piped) + PROCESS(mixer_complex_requantize_src_out_arr, si_sosi_0_piped) BEGIN FOR I IN 0 TO c_sdp_S_pn-1 LOOP wpfb_unit_complex_in_sosi_arr(I) <= si_sosi_0_piped; - wpfb_unit_complex_in_sosi_arr(I).re <= requantize_src_out_arr(I).re; - wpfb_unit_complex_in_sosi_arr(I).im <= requantize_src_out_arr(I).im; + wpfb_unit_complex_in_sosi_arr(I).re <= mixer_complex_requantize_src_out_arr(I).re; + wpfb_unit_complex_in_sosi_arr(I).im <= mixer_complex_requantize_src_out_arr(I).im; END LOOP; END PROCESS; @@ -461,7 +468,7 @@ BEGIN rst => dp_rst, clk => dp_clk, snk_in => wpfb_unit_complex_out_sosi_arr(I), - src_out => wpfb_unit_out_resized_sosi_arr(I) + src_out => wpfb_complex_out_resized_sosi_arr(I) ); END GENERATE; @@ -479,18 +486,18 @@ BEGIN PORT MAP ( rst => dp_rst, clk => dp_clk, - snk_in => wpfb_unit_out_resized_sosi_arr(I), - src_out => wpfb_fifo_sosi_arr(I), - src_in => wpfb_fifo_siso_arr(I) + snk_in => wpfb_complex_out_resized_sosi_arr(I), + src_out => wpfb_complex_out_fifo_sosi_arr(I), + src_in => wpfb_complex_out_fifo_siso_arr(I) ); END GENERATE; -- rewire 1d array of 1 X S_pn to 2d array of 2 X P_pfb gen_rewire: FOR I IN 0 TO c_sdp_P_pfb-1 GENERATE - wpfb_resized_sosi_2arr(I)(0) <= wpfb_fifo_sosi_arr(2*I); - wpfb_resized_sosi_2arr(I)(1) <= wpfb_fifo_sosi_arr(2*I + 1); - wpfb_fifo_siso_arr(2*I) <= wpfb_resized_siso_2arr(I)(0); - wpfb_fifo_siso_arr(2*I + 1) <= wpfb_resized_siso_2arr(I)(1); + wpfb_complex_out_resized_sosi_2arr(I)(0) <= wpfb_complex_out_fifo_sosi_arr(2*I); + wpfb_complex_out_resized_sosi_2arr(I)(1) <= wpfb_complex_out_fifo_sosi_arr(2*I + 1); + wpfb_complex_out_fifo_siso_arr(2*I) <= wpfb_complex_out_resized_siso_2arr(I)(0); + wpfb_complex_out_fifo_siso_arr(2*I + 1) <= wpfb_complex_out_resized_siso_2arr(I)(1); END GENERATE; -- Interleave 2 to 1 for all S_pn signals. @@ -502,8 +509,8 @@ BEGIN PORT MAP ( rst => dp_rst, clk => dp_clk, - snk_in_arr => wpfb_resized_sosi_2arr(I), - snk_out_arr => wpfb_resized_siso_2arr(I), + snk_in_arr => wpfb_complex_out_resized_sosi_2arr(I), + snk_out_arr => wpfb_complex_out_resized_siso_2arr(I), src_out => subband_equalizer_in_sosi_arr(c_sdp_P_pfb + I) ); END GENERATE; diff --git a/applications/lofar2/libraries/sdp/src/vhdl/sdp_subband_equalizer.vhd b/applications/lofar2/libraries/sdp/src/vhdl/sdp_subband_equalizer.vhd index c2d73ece5a14d2129c3dc68483eabee5d979d3ca..80f954b2be49c1090be1d61b742033664b1726ed 100644 --- a/applications/lofar2/libraries/sdp/src/vhdl/sdp_subband_equalizer.vhd +++ b/applications/lofar2/libraries/sdp/src/vhdl/sdp_subband_equalizer.vhd @@ -141,7 +141,8 @@ BEGIN g_pipeline_mux_in => 0, -- parallel to serial section g_pipeline_mux_out => 1, g_reverse_len => c_sdp_N_pol, -- = 2 - g_data_w => 16, + g_data_w => g_raw_dat_w * c_nof_complex, + g_use_complex => TRUE, g_signed => TRUE ) PORT MAP ( diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd index 762d2e704f509e7df83aa29ce4d8c0a85382368e..c3f0bc73f755b154ea2f7b8e2f2ae37128371df8 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_pkg.vhd @@ -77,6 +77,31 @@ PACKAGE tb_sdp_pkg is FUNCTION func_sdp_verify_cep_header(in_hdr, exp_hdr : t_sdp_cep_header) RETURN BOOLEAN; + ----------------------------------------------------------------------------- + -- Subband equalizer (ESub) + ----------------------------------------------------------------------------- + -- - ESub is like a two input beamformer + -- - Esub function calculates the expected subband level for signal input sp: + -- sp phasor * sp_weight + cross_phasor * cross weigth, where + -- . sp phasor = (sp_subband_ampl, sp_subband_phase) + -- . sp_weight = (sp_esub_gain, sp_esub_phase) + -- . cross_phasor = (cross_subband_ampl, cross_subband_phase) + -- . cross_weight = (cross_esub_gain, cross_esub_phase) + FUNCTION func_sdp_subband_equalizer(sp_subband_ampl, sp_subband_phase, sp_esub_gain, sp_esub_phase, + cross_subband_ampl, cross_subband_phase, cross_esub_gain, cross_esub_phase : REAL) + RETURN t_real_arr; -- 0:3 = ampl, phase, re, im + + + ----------------------------------------------------------------------------- + -- Beamformer (BF) + ----------------------------------------------------------------------------- + -- Model the SDP beamformer for one signal input (sp) and nof_rem remnant signal inputs (rem) + -- . for local beamformer on one node use nof_rem = S_pn - 1 + -- . for remote beamformer with nof_rn ring nodes use nof_rem = nof_rn * S_pn - 1 + FUNCTION func_sdp_beamformer(sp_subband_ampl, sp_subband_phase, sp_bf_gain, sp_bf_phase, + rem_subband_ampl, rem_subband_phase, rem_bf_gain, rem_bf_phase : REAL; + nof_rem : NATURAL) + RETURN t_real_arr; -- 0:3 = ampl, phase, re, im END PACKAGE tb_sdp_pkg; @@ -393,4 +418,56 @@ PACKAGE BODY tb_sdp_pkg IS RETURN TRUE; END func_sdp_verify_cep_header; + + FUNCTION func_sdp_subband_equalizer(sp_subband_ampl, sp_subband_phase, sp_esub_gain, sp_esub_phase, + cross_subband_ampl, cross_subband_phase, cross_esub_gain, cross_esub_phase : REAL) + RETURN t_real_arr IS -- 0:3 = ampl, phase, re, im + VARIABLE v_sp_ampl, v_sp_phase, v_sp_re, v_sp_im : REAL; + VARIABLE v_cross_ampl, v_cross_phase, v_cross_re, v_cross_im : REAL; + VARIABLE v_sum_ampl, v_sum_phase, v_sum_re, v_sum_im : REAL; + VARIABLE v_tuple : t_real_arr(0 TO 3); + BEGIN + v_sp_ampl := sp_subband_ampl * sp_esub_gain; + v_sp_phase := sp_subband_phase + sp_esub_phase; + v_sp_re := COMPLEX_RE(v_sp_ampl, v_sp_phase); + v_sp_im := COMPLEX_IM(v_sp_ampl, v_sp_phase); + v_cross_ampl := cross_subband_ampl * cross_esub_gain; + v_cross_phase := cross_subband_phase + cross_esub_phase; + v_cross_re := COMPLEX_RE(v_cross_ampl, v_cross_phase); + v_cross_im := COMPLEX_IM(v_cross_ampl, v_cross_phase); + v_sum_re := v_sp_re + v_cross_re; -- ESub sum re + v_sum_im := v_sp_im + v_cross_im; -- ESub sum im + v_sum_ampl := COMPLEX_RADIUS(v_sum_re, v_sum_im); + v_sum_phase := COMPLEX_PHASE(v_sum_re, v_sum_im); + v_tuple := (0 => v_sum_ampl, 1 => v_sum_phase, 2 => v_sum_re, 3 => v_sum_im); + RETURN v_tuple; + END; + + + FUNCTION func_sdp_beamformer(sp_subband_ampl, sp_subband_phase, sp_bf_gain, sp_bf_phase, + rem_subband_ampl, rem_subband_phase, rem_bf_gain, rem_bf_phase : REAL; + nof_rem : NATURAL) + RETURN t_real_arr IS -- 0:3 = ampl, phase, re, im + VARIABLE v_nof_rem : REAL := REAL(nof_rem); -- BF for one sp and nof_rem remnant signal inputs + VARIABLE v_sp_ampl, v_sp_phase, v_sp_re, v_sp_im : REAL; + VARIABLE v_rem_ampl, v_rem_phase, v_rem_re, v_rem_im : REAL; + VARIABLE v_sum_ampl, v_sum_phase, v_sum_re, v_sum_im : REAL; + VARIABLE v_tuple : t_real_arr(0 TO 3); + BEGIN + v_sp_ampl := sp_subband_ampl * sp_bf_gain; + v_sp_phase := sp_subband_phase + sp_bf_phase; + v_sp_re := COMPLEX_RE(v_sp_ampl, v_sp_phase); + v_sp_im := COMPLEX_IM(v_sp_ampl, v_sp_phase); + v_rem_ampl := rem_subband_ampl * rem_bf_gain; + v_rem_phase := rem_subband_phase + rem_bf_phase; + v_rem_re := COMPLEX_RE(v_rem_ampl, v_rem_phase); + v_rem_im := COMPLEX_IM(v_rem_ampl, v_rem_phase); + v_sum_re := v_sp_re + v_nof_rem * v_rem_re; -- BF sum re + v_sum_im := v_sp_im + v_nof_rem * v_rem_im; -- BF sum im + v_sum_ampl := COMPLEX_RADIUS(v_sum_re, v_sum_im); + v_sum_phase := COMPLEX_PHASE(v_sum_re, v_sum_im); + v_tuple := (0 => v_sum_ampl, 1 => v_sum_phase, 2 => v_sum_re, 3 => v_sum_im); + RETURN v_tuple; + END; + END tb_sdp_pkg; diff --git a/libraries/base/common/tb/vhdl/tb_common_pkg.vhd b/libraries/base/common/tb/vhdl/tb_common_pkg.vhd index ab0bd1f18a76bb607f39acc01ad3853516467afc..ee15dbe99cb195289f17e350388b2c02d0484564 100644 --- a/libraries/base/common/tb/vhdl/tb_common_pkg.vhd +++ b/libraries/base/common/tb/vhdl/tb_common_pkg.vhd @@ -81,6 +81,9 @@ PACKAGE tb_common_pkg IS PROCEDURE proc_common_wait_until_high(SIGNAL clk : IN STD_LOGIC; SIGNAL level : IN STD_LOGIC); + PROCEDURE proc_common_wait_until_clk_and_high(SIGNAL clk : IN STD_LOGIC; + SIGNAL level : IN STD_LOGIC); + PROCEDURE proc_common_wait_until_low(CONSTANT c_timeout : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL level : IN STD_LOGIC); @@ -88,6 +91,9 @@ PACKAGE tb_common_pkg IS PROCEDURE proc_common_wait_until_low(SIGNAL clk : IN STD_LOGIC; SIGNAL level : IN STD_LOGIC); + PROCEDURE proc_common_wait_until_clk_and_low(SIGNAL clk : IN STD_LOGIC; + SIGNAL level : IN STD_LOGIC); + PROCEDURE proc_common_wait_until_hi_lo(CONSTANT c_timeout : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL level : IN STD_LOGIC); @@ -427,6 +433,12 @@ PACKAGE BODY tb_common_pkg IS WAIT UNTIL rising_edge(clk) AND level='1'; END IF; END proc_common_wait_until_high; + + PROCEDURE proc_common_wait_until_clk_and_high(SIGNAL clk : IN STD_LOGIC; + SIGNAL level : IN STD_LOGIC) IS + BEGIN + WAIT UNTIL rising_edge(clk) AND level='1'; + END proc_common_wait_until_clk_and_high; PROCEDURE proc_common_wait_until_high(CONSTANT c_timeout : IN NATURAL; SIGNAL clk : IN STD_LOGIC; @@ -452,6 +464,12 @@ PACKAGE BODY tb_common_pkg IS END IF; END proc_common_wait_until_low; + PROCEDURE proc_common_wait_until_clk_and_low(SIGNAL clk : IN STD_LOGIC; + SIGNAL level : IN STD_LOGIC) IS + BEGIN + WAIT UNTIL rising_edge(clk) AND level='0'; + END proc_common_wait_until_clk_and_low; + PROCEDURE proc_common_wait_until_low(CONSTANT c_timeout : IN NATURAL; SIGNAL clk : IN STD_LOGIC; SIGNAL level : IN STD_LOGIC) IS diff --git a/libraries/base/dp/src/vhdl/dp_reverse_n_data.vhd b/libraries/base/dp/src/vhdl/dp_reverse_n_data.vhd index 0b310e901eb493cab9ecfd2358c179e7ab0e3698..3ce1d4545d1a6c06353ced19e22ac43e474348ba 100644 --- a/libraries/base/dp/src/vhdl/dp_reverse_n_data.vhd +++ b/libraries/base/dp/src/vhdl/dp_reverse_n_data.vhd @@ -51,7 +51,8 @@ ENTITY dp_reverse_n_data IS g_pipeline_mux_in : NATURAL := 0; -- parallel to serial section g_pipeline_mux_out : NATURAL := 1; g_reverse_len : NATURAL := 2; - g_data_w : NATURAL := 16; + g_data_w : NATURAL := 16; -- should be 2 times the c_complex_w if g_use_complex = TRUE + g_use_complex : BOOLEAN := FALSE; g_signed : BOOLEAN := TRUE ); PORT ( @@ -69,6 +70,7 @@ ARCHITECTURE str OF dp_reverse_n_data IS CONSTANT c_pipeline_total : NATURAL := g_pipeline_demux_in + g_pipeline_demux_out + g_reverse_len-1 + g_pipeline_mux_in + g_pipeline_mux_out; + CONSTANT c_complex_w : NATURAL := g_data_w / 2; SIGNAL in_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0); @@ -79,7 +81,14 @@ ARCHITECTURE str OF dp_reverse_n_data IS BEGIN - in_data <= snk_in.data(g_data_w-1 DOWNTO 0); + p_in_data : PROCESS(snk_in) + BEGIN + IF g_use_complex = FALSE THEN + in_data <= snk_in.data(g_data_w-1 DOWNTO 0); + ELSE + in_data <= snk_in.im(c_complex_w-1 DOWNTO 0) & snk_in.re(c_complex_w-1 DOWNTO 0); + END IF; + END PROCESS; u_common_reverse_n : ENTITY common_lib.common_reverse_n_data GENERIC MAP ( @@ -119,10 +128,15 @@ BEGIN p_src_out : PROCESS(snk_in_delayed, reversed_data) BEGIN src_out <= snk_in_delayed; - IF g_signed = TRUE THEN - src_out.data <= RESIZE_DP_SDATA(reversed_data); + IF g_use_complex = FALSE THEN + IF g_signed = TRUE THEN + src_out.data <= RESIZE_DP_SDATA(reversed_data); + ELSE + src_out.data <= RESIZE_DP_DATA(reversed_data); + END IF; ELSE - src_out.data <= RESIZE_DP_DATA(reversed_data); + src_out.im <= RESIZE_DP_DSP_DATA(reversed_data(g_data_w-1 DOWNTO c_complex_w)); + src_out.re <= RESIZE_DP_DSP_DATA(reversed_data(c_complex_w-1 DOWNTO 0)); END IF; END PROCESS;