diff --git a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_remote_ring.vhd b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_remote_ring.vhd index e0142064f95af09ef719c1a87acb57668575ce90..fe1be5239c92c47f865fa2c6ed271ec2790d7db7 100644 --- a/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_remote_ring.vhd +++ b/applications/lofar2/libraries/sdp/tb/vhdl/tb_sdp_beamformer_remote_ring.vhd @@ -24,10 +24,31 @@ -- Description: -- . https://support.astron.nl/confluence/display/L2M/L5+SDPFW+Design+Document%3A+Beamformer -- --- This tb is inspired by tb_lofar2_unb2c_sdp_station_bf_ring.vhd, however +-- . This tb is inspired by tb_lofar2_unb2c_sdp_station_bf_ring.vhd, however -- here the purpose is to simulate the memory usage of the circular buffer -- in the bsn_aligner_v2 at each node. -- +-- . Block diagram: +-- +-- ring lane serial links for ring nodes RN = 0 to c_last_rn: +-- +-- tr_10gbe_ring_serial_tx_arr --> tr_10gbe_ring_serial_rx_arr +-- +-- /<-------------------------------------------------------------\ +-- \---> 0 ---> RN - 1 ---> RN ---> RN + 1 ---> c_last_rn --->/ +-- | ^ +-- tr_10gbe_ring_serial_tx_arr(RN) | | tr_10gbe_ring_serial_tx_arr(RN) +-- v | +-- tr10Gbe +-- | ^ +-- tr_10gbe_ring_rx_sosi_arr(RN) | | tr_10gbe_ring_tx_sosi_arr(RN) +-- v | +-- ring_lane +-- | ^ +-- from_ri_sosi_arr(RN) | | to_ri_sosi_arr(RN) +-- v | +-- local_bf_sosi --> sdp_beamformer_remote --> bf_sum_sosi_arr(RN) +-- bf_sum_sosi -- Usage: -- > as 8 -- > run -a @@ -39,6 +60,7 @@ use common_lib.common_pkg.all; use common_lib.common_mem_pkg.all; use common_lib.tb_common_pkg.all; use common_lib.tb_common_mem_pkg.all; +use common_lib.common_str_pkg.all; use dp_lib.dp_stream_pkg.all; use ring_lib.ring_pkg.all; use tech_pll_lib.tech_pll_component_pkg.all; @@ -47,7 +69,7 @@ use work.tb_sdp_pkg.all; entity tb_sdp_beamformer_remote_ring is generic ( - g_nof_rn : natural := 4 -- number of nodes in the ring + g_nof_rn : natural := 16 -- number of nodes in the ring ); end tb_sdp_beamformer_remote_ring; @@ -63,6 +85,8 @@ architecture tb of tb_sdp_beamformer_remote_ring is -- choose sync interval somewhat longer than maximum BF ring latency constant c_nof_blocks_per_sync : natural := largest(10, (g_nof_rn + 1) * 2); constant c_nof_sync : natural := 2; + constant c_local_bf_re : integer := 1; + constant c_local_bf_im : integer := 2; -- Ring lane packets constant c_last_rn : natural := g_nof_rn - 1; -- first ring node has index RN = 0 by definition. @@ -83,6 +107,9 @@ architecture tb of tb_sdp_beamformer_remote_ring is constant c_validate_channel_mode : string := "="; constant c_sync_timeout : natural := c_block_period * (c_nof_blocks_per_sync + 1); + -- Address widths of a single MM instance + constant c_addr_w_reg_ring_lane_info_bf : natural := 1; + signal mm_init : std_logic := '1'; signal tb_end : std_logic := '0'; signal dp_clk : std_logic := '1'; @@ -97,40 +124,56 @@ architecture tb of tb_sdp_beamformer_remote_ring is signal stimuli_rst : std_logic; signal stimuli_end : std_logic; + signal stimuli_sosi : t_dp_sosi; signal local_bf_sosi : t_dp_sosi; signal bf_bs_sosi : t_dp_sosi; - signal from_ri_sosi_arr : t_dp_sosi_arr(0 to c_last_rn); - signal to_ri_sosi_arr : t_dp_sosi_arr(0 to c_last_rn); - signal bf_sum_sosi_arr : t_dp_sosi_arr(0 to c_last_rn); + signal from_ri_sosi_arr : t_dp_sosi_arr(c_last_rn downto 0); + signal to_ri_sosi_arr : t_dp_sosi_arr(c_last_rn downto 0); + signal bf_sum_sosi_arr : t_dp_sosi_arr(c_last_rn downto 0); signal bf_sum_sosi : t_dp_sosi; -- 10GbE ring - signal tr_10gbe_ring_rx_sosi_arr : t_dp_sosi_arr(0 to c_last_rn) := (others => c_dp_sosi_rst); - signal tr_10gbe_ring_tx_sosi_arr : t_dp_sosi_arr(0 to c_last_rn) := (others => c_dp_sosi_rst); - signal tr_10gbe_ring_serial_rx_arr : std_logic_vector(0 to c_last_rn) := (others => '0'); - signal tr_10gbe_ring_serial_tx_arr : std_logic_vector(0 to c_last_rn) := (others => '0'); + signal tr_10gbe_ring_rx_sosi_arr : t_dp_sosi_arr(c_last_rn downto 0) := (others => c_dp_sosi_rst); + signal tr_10gbe_ring_tx_sosi_arr : t_dp_sosi_arr(c_last_rn downto 0) := (others => c_dp_sosi_rst); + signal tr_10gbe_ring_serial_rx_arr : std_logic_vector(c_last_rn downto 0) := (others => '0'); + signal tr_10gbe_ring_serial_tx_arr : std_logic_vector(c_last_rn downto 0) := (others => '0'); -- BF ring MM points - signal reg_ring_lane_info_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_ring_lane_info_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); - signal reg_bsn_monitor_v2_ring_rx_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_bsn_monitor_v2_ring_rx_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); - signal reg_bsn_monitor_v2_ring_tx_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_bsn_monitor_v2_ring_tx_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); - signal reg_dp_block_validate_err_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_dp_block_validate_err_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); - signal reg_dp_block_validate_bsn_at_sync_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := + signal reg_ring_lane_info_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_ring_lane_info_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_ring_lane_info_bf_copi : t_mem_copi := c_mem_copi_rst; + signal reg_ring_lane_info_bf_cipo : t_mem_cipo := c_mem_cipo_rst; + signal reg_bsn_monitor_v2_ring_rx_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_bsn_monitor_v2_ring_rx_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_bsn_monitor_v2_ring_rx_bf_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_monitor_v2_ring_rx_bf_cipo : t_mem_cipo := c_mem_cipo_rst; + signal reg_bsn_monitor_v2_ring_tx_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_bsn_monitor_v2_ring_tx_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_bsn_monitor_v2_ring_tx_bf_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_monitor_v2_ring_tx_bf_cipo : t_mem_cipo := c_mem_cipo_rst; + signal reg_dp_block_validate_err_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_dp_block_validate_err_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_dp_block_validate_err_bf_copi : t_mem_copi := c_mem_copi_rst; + signal reg_dp_block_validate_err_bf_cipo : t_mem_cipo := c_mem_cipo_rst; + signal reg_dp_block_validate_bsn_at_sync_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); - signal reg_dp_block_validate_bsn_at_sync_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := + signal reg_dp_block_validate_bsn_at_sync_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_dp_block_validate_bsn_at_sync_bf_copi : t_mem_copi := c_mem_copi_rst; + signal reg_dp_block_validate_bsn_at_sync_bf_cipo : t_mem_cipo := c_mem_cipo_rst; + + signal FPGA_bf_ring_nof_transport_hops_R : t_natural_arr(c_last_rn downto 0); + signal FPGA_bf_ring_rx_latency_R : t_integer_arr(c_last_rn downto 0); -- BSN aligner MM points - signal reg_bsn_align_v2_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_bsn_align_v2_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); - signal reg_bsn_monitor_v2_rx_align_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_bsn_monitor_v2_rx_align_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); - signal reg_bsn_monitor_v2_aligned_bf_copi_arr : t_mem_copi_arr(0 to c_last_rn) := (others => c_mem_copi_rst); - signal reg_bsn_monitor_v2_aligned_bf_cipo_arr : t_mem_cipo_arr(0 to c_last_rn) := (others => c_mem_cipo_rst); + signal reg_bsn_align_v2_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_bsn_align_v2_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_bsn_align_v2_bf_copi : t_mem_copi := c_mem_copi_rst; + signal reg_bsn_align_v2_bf_cipo : t_mem_cipo := c_mem_cipo_rst; + signal reg_bsn_monitor_v2_rx_align_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_bsn_monitor_v2_rx_align_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); + signal reg_bsn_monitor_v2_aligned_bf_copi_arr : t_mem_copi_arr(c_last_rn downto 0) := (others => c_mem_copi_rst); + signal reg_bsn_monitor_v2_aligned_bf_cipo_arr : t_mem_cipo_arr(c_last_rn downto 0) := (others => c_mem_cipo_rst); begin dp_rst <= '1', '0' after c_dp_clk_period * 7; @@ -156,27 +199,78 @@ begin rst => stimuli_rst, clk => dp_clk, -- Generate stimuli - src_out => local_bf_sosi, + src_out => stimuli_sosi, -- End of stimuli tb_end => stimuli_end ); + -- Use constant beamlet data to ease verification of (intermediate) beamlet sums at each node + p_local_bf_sosi : process(stimuli_sosi) + begin + local_bf_sosi <= stimuli_sosi; + local_bf_sosi.data <= TO_DP_SDATA(0); + local_bf_sosi.re <= TO_DP_DSP_DATA(c_local_bf_re); + local_bf_sosi.im <= TO_DP_DSP_DATA(c_local_bf_im); + end process; + bf_bs_sosi <= local_bf_sosi; bf_sum_sosi <= bf_sum_sosi_arr(c_last_rn); p_mm : process - variable v_offset : natural; + variable v_span : natural; + variable v_offset : natural; + variable v_transport_nof_hops : natural; begin proc_common_wait_until_low(dp_clk, mm_rst); proc_common_wait_some_cycles(mm_clk, 10); proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period, c_common_cross_clock_domain_latency * 2); + -- Write FPGA_bf_ring_nof_transport_hops_RW = ring_lane_info.transport_nof_hops + v_span := 2**c_addr_w_reg_ring_lane_info_bf; + for RN in 0 to c_last_rn LOOP + v_offset := 1 + RN * v_span; + v_transport_nof_hops := 1; + if RN = c_last_rn then + v_transport_nof_hops := 0; + end if; + proc_mem_mm_bus_wr(v_offset, v_transport_nof_hops, mm_clk, + reg_ring_lane_info_bf_cipo, reg_ring_lane_info_bf_copi); + end loop; + proc_common_wait_cross_clock_domain_latency(c_mm_clk_period, c_dp_clk_period, + c_common_cross_clock_domain_latency * 2); + -- Readback FPGA_bf_ring_nof_transport_hops_R + for RN in 0 to c_last_rn LOOP + v_offset := 1 + RN * v_span; + proc_mem_mm_bus_rd(v_offset, mm_clk, reg_ring_lane_info_bf_cipo, reg_ring_lane_info_bf_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + FPGA_bf_ring_nof_transport_hops_R(RN) <= TO_UINT(reg_ring_lane_info_bf_cipo.rddata(c_word_w - 1 downto 0)); + end loop; + + -- Wait until second bf_sum_sosi.sync + proc_common_wait_until_hi_lo(dp_clk, bf_sum_sosi.sync); + proc_common_wait_until_hi_lo(dp_clk, bf_sum_sosi.sync); + -- Read FPGA_bf_ring_rx_latency_R + v_span := 2**c_sdp_reg_bsn_monitor_v2_addr_w; + for RN in 0 to c_last_rn LOOP + v_offset := 6 + RN * v_span; + proc_mem_mm_bus_rd(v_offset, mm_clk, reg_bsn_monitor_v2_ring_rx_bf_cipo, reg_bsn_monitor_v2_ring_rx_bf_copi); + proc_mem_mm_bus_rd_latency(1, mm_clk); + FPGA_bf_ring_rx_latency_R(RN) <= TO_UINT(reg_bsn_monitor_v2_ring_rx_bf_cipo.rddata(c_word_w - 1 downto 0)); + end loop; + mm_init <= '0'; -- Wait to stop simulation proc_common_wait_until_high(dp_clk, stimuli_end); proc_common_wait_some_cycles(dp_clk, 1000); + + -- Print results + print_str("FPGA_bf_ring_rx_latency_R"); + for RN in 0 to c_last_rn loop + print_str(" RN " & int_to_str(RN) & ": " & int_to_str(FPGA_bf_ring_rx_latency_R(RN))); + end Loop; + tb_end <= '1'; wait; end process; @@ -225,12 +319,12 @@ begin dp_rst => dp_rst, dp_clk => dp_clk, - src_out_arr => tr_10gbe_ring_rx_sosi_arr(RN to RN), - snk_in_arr => tr_10gbe_ring_tx_sosi_arr(RN to RN), + src_out_arr => tr_10gbe_ring_rx_sosi_arr(RN downto RN), + snk_in_arr => tr_10gbe_ring_tx_sosi_arr(RN downto RN), -- Serial IO - serial_tx_arr => tr_10gbe_ring_serial_tx_arr(RN to RN), - serial_rx_arr => tr_10gbe_ring_serial_rx_arr(RN to RN) + serial_tx_arr => tr_10gbe_ring_serial_tx_arr(RN downto RN), + serial_rx_arr => tr_10gbe_ring_serial_rx_arr(RN downto RN) ); -- Ring lane access at each node @@ -306,7 +400,22 @@ begin ); end generate; -- gen_dut + ------------------------------------------------------------------------------ + -- Verify bf_sum_sosi_arr at every node, to check that no packets were lost + ------------------------------------------------------------------------------ + p_verify_bf_sum : process(dp_clk) + begin + for RN in 0 to c_last_rn Loop + if bf_sum_sosi_arr(RN).valid = '1' then + assert TO_SINT(bf_sum_sosi_arr(RN).re) = (RN + 1) * c_local_bf_re report "Wrong BF re sum at node " & int_to_str(RN) severity error; + assert TO_SINT(bf_sum_sosi_arr(RN).im) = (RN + 1) * c_local_bf_im report "Wrong BF im sum at node " & int_to_str(RN) severity error; + end if; + end loop; + end process; + + ------------------------------------------------------------------------------ -- 10GbE clocks + ------------------------------------------------------------------------------ u_tech_pll_xgmii_mac_clocks : entity tech_pll_lib.tech_pll_xgmii_mac_clocks port map ( refclk_644 => SA_CLK, @@ -316,4 +425,45 @@ begin rst_156 => tr_ref_rst_156, rst_312 => open ); + + ------------------------------------------------------------------------------ + -- MM bus multiplexers + ------------------------------------------------------------------------------ + -- Use common_mem_mux to avoid (vcom-1450) Actual (indexed name) for formal "mm_miso" is not a static signal name. + -- Use downto range for _arr, to match downto range of mosi_arr. + u_mem_mux_reg_ring_lane_info_bf : entity common_lib.common_mem_mux + generic map ( + g_nof_mosi => g_nof_rn, + g_mult_addr_w => c_addr_w_reg_ring_lane_info_bf + ) + port map ( + mosi => reg_ring_lane_info_bf_copi, + miso => reg_ring_lane_info_bf_cipo, + mosi_arr => reg_ring_lane_info_bf_copi_arr, + miso_arr => reg_ring_lane_info_bf_cipo_arr + ); + + u_mem_mux_reg_bsn_monitor_v2_ring_rx_bf : entity common_lib.common_mem_mux + generic map ( + g_nof_mosi => g_nof_rn, + g_mult_addr_w => c_sdp_reg_bsn_monitor_v2_addr_w + ) + port map ( + mosi => reg_bsn_monitor_v2_ring_rx_bf_copi, + miso => reg_bsn_monitor_v2_ring_rx_bf_cipo, + mosi_arr => reg_bsn_monitor_v2_ring_rx_bf_copi_arr, + miso_arr => reg_bsn_monitor_v2_ring_rx_bf_cipo_arr + ); + + u_mem_mux_reg_bsn_align_v2_bf : entity common_lib.common_mem_mux + generic map ( + g_nof_mosi => g_nof_rn, + g_mult_addr_w => c_sdp_reg_bsn_align_v2_addr_w + ) + port map ( + mosi => reg_bsn_align_v2_bf_copi, + miso => reg_bsn_align_v2_bf_cipo, + mosi_arr => reg_bsn_align_v2_bf_copi_arr, + miso_arr => reg_bsn_align_v2_bf_cipo_arr + ); end tb;