diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl index 74212380009a0fd332a68ef3a8cfedb08825778c..067487f8e0318c90114e5c03a2d285821449ef32 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_one/lofar2_unb2c_sdp_station_tbuf_one_pins.tcl @@ -19,6 +19,7 @@ ############################################################################### source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_pins.tcl source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_jesd_pins.tcl +source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_beamlets_pins.tcl source $::env(HDL_WORK)/boards/uniboard2c/libraries/unb2c_board/quartus/pinning/unb2c_ddr_16G_64b_I_pins.tcl diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/hdllib.cfg b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0a6640453eb6f515a9909b3bbeeeedb036dc7a07 --- /dev/null +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/hdllib.cfg @@ -0,0 +1,48 @@ +hdl_lib_name = lofar2_unb2c_sdp_station_tbuf_ring +hdl_library_clause_name = lofar2_unb2c_sdp_station_tbuf_ring_lib +hdl_lib_uses_synth = common dp mm unb2c_board tech_ddr lofar2_unb2c_sdp_station +hdl_lib_uses_sim = +hdl_lib_technology = ip_arria10_e2sg +hdl_lib_include_ip = + +synth_files = + lofar2_unb2c_sdp_station_tbuf_ring.vhd + +test_bench_files = + tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd + tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd + +regression_test_vhdl = + tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd + +[modelsim_project_file] +modelsim_copy_files = + ../../src/data data + +modelsim_compile_ip_files = + # Unb2c 16GB-64b DDR4 driver + $HDL_WORK/libraries/technology/ip_arria10_e2sg/ddr4_16g_1600/ddr4_16g_1600_64b/copy_hex_files.tcl + +[quartus_project_file] +synth_top_level_entity = + +quartus_copy_files = + ../../quartus . + ../../src/data data + +quartus_qsf_files = + $HDL_WORK/boards/uniboard2c/libraries/unb2c_board/quartus/unb2c_board.qsf + +quartus_sdc_files = + ../../quartus/lofar2_unb2c_sdp_station.sdc + +quartus_tcl_files = + lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl + ../../quartus/lofar2_unb2c_sdp_station_ip.tcl + +quartus_vhdl_files = + +quartus_qip_files = + $HDL_BUILD_DIR/unb2c/quartus/lofar2_unb2c_sdp_station_tbuf_ring/qsys_lofar2_unb2c_sdp_station/qsys_lofar2_unb2c_sdp_station.qip + +nios2_app_userflags = -DCOMPILE_FOR_GEN2_UNB2 diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring.vhd new file mode 100644 index 0000000000000000000000000000000000000000..539414d25ab17dd6867e89c32a44458d39dc67da --- /dev/null +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring.vhd @@ -0,0 +1,176 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2024 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +-- Author : E. Kooistra +-- Purpose: +-- Wrapper for synthesis of Lofar2 SDP Station tbuf_ring design. The wrapper +-- maps the unb2c BCK pin names to the JESD204B signal names. +-- Description: +-- Contains SDPFW for unb2c with complete AIT input stage with 12 ADC +-- streams and TBuf for 16GB DDR4 with 64 DQ in slot I. + +library IEEE, common_lib, dp_lib, unb2c_board_lib, tech_ddr_lib, lofar2_unb2c_sdp_station_lib; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + use common_lib.common_pkg.all; + use common_lib.common_mem_pkg.all; + use unb2c_board_lib.unb2c_board_pkg.all; + use tech_ddr_lib.tech_ddr_pkg.all; + use dp_lib.dp_stream_pkg.all; + +entity lofar2_unb2c_sdp_station_tbuf_ring is + generic ( + g_stamp_date : natural := 0; -- Date (YYYYMMDD) -- set by QSF + g_stamp_time : natural := 0; -- Time (HHMMSS) -- set by QSF + g_revision_id : string := "" -- revision ID -- set by QSF + ); + port ( + -- GENERAL + CLK : in std_logic; -- System Clock + PPS : in std_logic; -- System Sync + WDI : out std_logic; -- Watchdog Clear + INTA : inout std_logic; -- FPGA interconnect line + INTB : inout std_logic; -- FPGA interconnect line + + -- Others + VERSION : in std_logic_vector(c_unb2c_board_aux.version_w - 1 downto 0); + ID : in std_logic_vector(c_unb2c_board_aux.id_w - 1 downto 0); + TESTIO : inout std_logic_vector(c_unb2c_board_aux.testio_w - 1 downto 0); + + -- 1GbE Control Interface + ETH_CLK : in std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0); + ETH_SGIN : in std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0); + ETH_SGOUT : out std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0); + + -- Transceiver clocks + SA_CLK : in std_logic := '0'; -- Clock 10GbE front (qsfp) and ring lines + + -- front transceivers QSFP0 for Ring. + QSFP_0_RX : in std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0'); + QSFP_0_TX : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0); + + -- front transceivers QSFP1 for 10GbE output to CEP. + QSFP_1_RX : in std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0'); + QSFP_1_TX : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0); + + -- LEDs + QSFP_LED : out std_logic_vector(c_unb2c_board_tr_qsfp_nof_leds - 1 downto 0); + + -- ring transceivers + -- . Using qsfp bus width also for ring interfaces + RING_0_RX : in std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0'); + RING_0_TX : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0); + RING_1_RX : in std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0) := (others => '0'); + RING_1_TX : out std_logic_vector(c_unb2c_board_tr_qsfp.bus_w - 1 downto 0); + + -- back transceivers (note only 12 are used in unb2c) + -- . c_unb2c_board_nof_tr_jesd204b = c_sdp_S_pn = 12 + BCK_RX : in std_logic_vector(c_unb2c_board_nof_tr_jesd204b - 1 downto 0); + BCK_REF_CLK : in std_logic; -- Use as JESD204B_REFCLK + + -- jesd204b syncronization signals (4 syncs) + -- . c_unb2c_board_nof_sync_jesd204b = c_sdp_N_sync_jesd = 4 + JESD204B_SYSREF : in std_logic; + JESD204B_SYNC_N : out std_logic_vector(c_unb2c_board_nof_sync_jesd204b - 1 downto 0); + + -- DDR4 MB_I memory interface + MB_I_REF_CLK : in std_logic; -- Reference clock for MB_I + MB_I_IN : in t_tech_ddr4_phy_in; + MB_I_IO : inout t_tech_ddr4_phy_io; + MB_I_OU : out t_tech_ddr4_phy_ou + ); +end lofar2_unb2c_sdp_station_tbuf_ring; + +architecture str of lofar2_unb2c_sdp_station_tbuf_ring is + constant c_design_name : string := "lofar2_unb2c_sdp_station_tbuf_ring"; + constant c_design_note : string := "AIT + TBuf + Ring for dump from multiple nodes"; + + signal JESD204B_SERIAL_DATA : std_logic_vector( + (c_unb2c_board_tr_jesd204b.bus_w * c_unb2c_board_tr_jesd204b.nof_bus) - 1 downto 0); + signal jesd204b_sync_n_arr : std_logic_vector(c_unb2c_board_nof_sync_jesd204b - 1 downto 0); + signal JESD204B_REFCLK : std_logic; +begin + -- Mapping between JESD signal names and UNB2C pin/schematic names + JESD204B_REFCLK <= BCK_REF_CLK; + JESD204B_SERIAL_DATA <= BCK_RX; + JESD204B_SYNC_N(c_unb2c_board_nof_sync_jesd204b - 1 downto 0) <= + jesd204b_sync_n_arr(c_unb2c_board_nof_sync_jesd204b - 1 downto 0); + + u_revision : entity lofar2_unb2c_sdp_station_lib.lofar2_unb2c_sdp_station + generic map ( + g_design_name => c_design_name, + g_design_note => c_design_note, + g_stamp_date => g_stamp_date, + g_stamp_time => g_stamp_time, + g_revision_id => g_revision_id + ) + port map ( + -- GENERAL + CLK => CLK, + PPS => PPS, + WDI => WDI, + INTA => INTA, + INTB => INTB, + + -- Others + VERSION => VERSION, + ID => ID, + TESTIO => TESTIO, + + -- 1GbE Control Interface + ETH_CLK => ETH_CLK, + ETH_SGIN => ETH_SGIN, + ETH_SGOUT => ETH_SGOUT, + + -- Transceiver clocks + SA_CLK => SA_CLK, + + -- front transceivers QSFP0 for Ring. + QSFP_0_RX => QSFP_0_RX, + QSFP_0_TX => QSFP_0_TX, + + -- front transceivers QSFP1 for 10GbE output to CEP. + QSFP_1_RX => QSFP_1_RX, + QSFP_1_TX => QSFP_1_TX, + + -- LEDs + QSFP_LED => QSFP_LED, + + -- ring transceivers + RING_0_RX => RING_0_RX, + RING_0_TX => RING_0_TX, + RING_1_RX => RING_1_RX, + RING_1_TX => RING_1_TX, + + -- 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_arr, + + -- DDR4 MB_I memory interface + MB_I_REF_CLK => MB_I_REF_CLK, + MB_I_IN => MB_I_IN, + MB_I_IO => MB_I_IO, + MB_I_OU => MB_I_OU + ); +end str; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl new file mode 100644 index 0000000000000000000000000000000000000000..982ad9f2cf99d1182e3e2e4a2e84554b3df3cf1f --- /dev/null +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/lofar2_unb2c_sdp_station_tbuf_ring_pins.tcl @@ -0,0 +1,24 @@ +############################################################################### +# +# Copyright 2024 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +############################################################################### +source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_pins.tcl +source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_jesd_pins.tcl +source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_beamlets_pins.tcl +source $::env(HDL_WORK)/applications/lofar2/designs/lofar2_unb2c_sdp_station/quartus/lofar2_unb2c_sdp_station_ring_pins.tcl +source $::env(HDL_WORK)/boards/uniboard2c/libraries/unb2c_board/quartus/pinning/unb2c_ddr_16G_64b_I_pins.tcl diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd new file mode 100644 index 0000000000000000000000000000000000000000..43237d9eac9bb89abaa23e5f12beffe81889c79c --- /dev/null +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd @@ -0,0 +1,1289 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2024 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- +-- Author: E. Kooistra +-- Purpose: Self-checking testbench for lofar2_unb2c_sdp_station_tbuf_ring +-- using WG data. +-- +-- Description: +-- MM control actions: +-- +-- A) Set up WG and verify sp_power_sum as in tb_lofar2_unb2c_sdp_station_adc / bf.vhd +-- . use DC level (= sp index) signal at the signal inputs, so all SP carry DC. +-- B) Record, freeze and dump TBuf [2]: TODO +-- . g_rs_block_size, g_ddr_buffer_size to verify recording beyond buffer full. +-- . g_dump_page_offset, g_dump_nof_pages to verify dumping across begin and end of buffer +-- . g_dump_enables to verify dumping one or more antenna inputs +-- . g_dump_inter_packet_gap to vary dump rate. +-- . log, verify: state, total counts +-- +-- . g_ddr_buffer_size: +-- Use Use g_ddr_buffer_size with e.g. 256 words to have smaller circular buffer independend of fixed +-- c_tech_ddr4_sim_4k_64 with size 4096 words, to speed up simulation of wrap around of circular buffer full. +-- +-- References: +-- [1] https://support.astron.nl/confluence/pages/viewpage.action?spaceKey=L2M&title=L5+SDPFW+Design+Document%3A+Transient+buffer+raw+data +-- [2] https://support.astron.nl/confluence/display/L2M/L2+STAT+Decision%3A+SC+-+SDP+OPC-UA+interface with dynamic +-- behaviour recipe for record, freeze, dump +-- +-- Usage: +-- > as 12 # for detailed debugging +-- > run -a +-- . view: +-- . rx_beamlets_header.app for beamlet packet header +-- . rx_dump_header.app for dump packet header +-- . rx_ant_sosi and rx_ant_data_arr (to show SP with corresponding DC level) for dump packet data +-- . copy usedw of tx FIFOs in Wave Window in analog format and as bits to see and compare their fill levels and +-- spare space when g_rs_block_size, for tx FIFOs in: +-- . nw_10GbE +-- . sdp_beamformer_output of bf[0] +-- . sdp_beamformer_output of bf[1] +-- . sdp_tbuf_output tx FIFO +-- . Use "cat transcript| grep Error:" in git/hdl directory to ease spotting simulation ERRORs +-- +------------------------------------------------------------------------------- +library IEEE, common_lib, mm_lib, dp_lib, diag_lib, i2c_lib, wpfb_lib; +library tech_pll_lib, tr_10GbE_lib, unb2c_board_lib; +library lofar2_sdp_lib, lofar2_unb2c_sdp_station_lib; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + use IEEE.math_real.all; + use common_lib.common_pkg.all; + use common_lib.tb_common_pkg.all; + use common_lib.common_mem_pkg.all; + use common_lib.common_str_pkg.all; + use dp_lib.dp_stream_pkg.all; + use mm_lib.mm_file_pkg.all; + use mm_lib.mm_file_unb_pkg.all; + use diag_lib.diag_pkg.all; + use wpfb_lib.wpfb_pkg.all; + use tech_pll_lib.tech_pll_component_pkg.all; + use unb2c_board_lib.unb2c_board_pkg.all; + use lofar2_sdp_lib.sdp_pkg.all; + use lofar2_sdp_lib.tb_sdp_pkg.all; + use lofar2_sdp_lib.sdp_tbuf_pkg.all; + use lofar2_sdp_lib.tb_sdp_tbuf_pkg.all; + +entity tb_lofar2_unb2c_sdp_station_tbuf_ring is + generic ( + g_tb_end : boolean := true; -- when true then tb_end ends this simulation, else a higher + -- multi-testbench will end the simulation + g_tb_index : natural := 0; + g_ddr_buffer_size : natural := 256; -- <= 4096, because c_tech_ddr4_sim_4k_64 has 4k = 4096 words of + -- c_sdp_tbuf_W_word = 512b + g_rs_block_size : natural := 100; -- c_sdp_tbuf_rs_block_size = 2000, must be even see sdp_tbuf_output + g_rs_record_nof_block : natural := 3; -- choose > c_rs_nof_block_per_sync to have at least on sync interval + -- for the RSN monitor + g_dump_inter_packet_gap : natural := 0; -- use 1708 for 3 Gbps and g_rs_block_size = 2000 + g_dump_page_offset : natural := 0; -- offset relative to recorded_first_page + g_dump_nof_pages : natural := 3; -- g_dump_page_offset + g_dump_nof_pages <= g_rs_record_nof_block, else + -- there will occur read RSN errors for pages that are not available + g_dump_enables : std_logic_vector(c_sdp_A_pn - 1 downto 0) := "100001" + ); + port ( + tb_end : out std_logic + ); +end tb_lofar2_unb2c_sdp_station_tbuf_ring; + +architecture tb of tb_lofar2_unb2c_sdp_station_tbuf_ring is + constant c_sim : boolean := true; -- use true for sim_ddr, use false to simulate IP and external DDR4 + constant c_unb_nr : natural := 1; + constant c_node_nr : natural := 2; + constant c_tb_str : string := "TB-" & int_to_str(g_tb_index) & ": "; + constant c_mmf_prefix : string := mmf_unb2_file_prefix(g_tb_index, c_unb_nr, c_node_nr); + constant c_Gbps : real := 10.0**9; + + constant c_design_name : string := "lofar2_unb2c_sdp_station_tbuf_ring"; + constant c_nof_dump : natural := 1; -- number of dumps, > 1 to repeat same dump + + constant c_gn_index : natural := c_unb_nr * 4 + c_node_nr; -- this node GN + constant c_ai_offset : natural := c_gn_index * c_sdp_A_pn; + constant c_id : std_logic_vector(7 downto 0) := TO_UVEC(c_gn_index, 8); + constant c_version : std_logic_vector(1 downto 0) := "00"; + constant c_fw_version : t_unb2c_board_fw_version := (1, 0); + + constant c_eth_clk_period : time := 8 ns; -- 125 MHz XO on UniBoard + constant c_ext_clk_period : time := 5 ns; + constant c_mm_clk_period : time := 10 ns; -- 100 MHz internal mm_clk + constant c_bck_ref_clk_period : time := 5 ns; + constant c_sa_clk_period : time := tech_pll_clk_644_period; -- 644MHz + constant c_tb_clk_period : time := 100 ps; -- use fast tb_clk to speed up M&C + constant c_1ns : time := 1 ns; + + -- BSN + constant c_bs_block_size : natural := true_log_pow2(g_rs_block_size); -- power of 2 >= g_rs_block_size + constant c_bs_nof_block_per_sync : natural := 2; + constant c_bs_nof_clk_per_sync : natural := c_bs_nof_block_per_sync * c_bs_block_size; -- For SP power in AIT + constant c_pps_period : natural := c_bs_nof_clk_per_sync; + constant c_T_bs_period : time := c_bs_block_size * c_sdp_T_adc; + constant c_T_rd_interval : time := 200 ns; + constant c_init_bsn : natural := 17; -- some recognizable value >= 0 + + -- RSN + constant c_rs_nof_block_per_sync : natural := 2; + constant c_rs_nof_clk_per_sync : natural := c_rs_nof_block_per_sync * g_rs_block_size; + + -- Buffer size + constant c_ddr_access_rate_pct : natural := 100; -- full rate is 100 % + constant c_ddr_buffer_size : natural := sel_a_b(g_rs_block_size > g_ddr_buffer_size, 4096, g_ddr_buffer_size); + constant c_sim_sdp_tbuf : t_sdp_tbuf_sim := (c_rs_nof_clk_per_sync, + c_bs_block_size, + g_rs_block_size, + c_ddr_buffer_size, + c_ddr_access_rate_pct); + + -- Page size, and number of pages + constant c_page_data_size : natural := func_sdp_tbuf_calculate_page_data_size(g_rs_block_size); + constant c_page_meta_size : natural := func_sdp_tbuf_calculate_page_meta_size(g_rs_block_size); + constant c_page_size : natural := c_page_data_size + c_page_meta_size; + constant c_nof_pages_in_buffer : natural := func_sdp_tbuf_calculate_nof_pages(c_ddr_buffer_size, c_page_size); + constant c_dump_nof_pages_rw : natural := g_dump_nof_pages; + constant c_dump_nof_pages_actual : natural := smallest(g_dump_nof_pages, c_nof_pages_in_buffer); + constant c_bs_start_latency : natural := c_bs_block_size * 2; + constant c_record_min_nof_pages : natural := g_dump_page_offset + c_dump_nof_pages_rw; + constant c_record_min_nof_clk : natural := c_bs_start_latency + g_rs_block_size * c_record_min_nof_pages; + + constant c_exp_read_rate_bps : real := func_sdp_tbuf_calculate_dump_rate_bps(g_rs_block_size, + g_dump_inter_packet_gap); + constant c_exp_dump_rate_bps : real := c_exp_read_rate_bps; + constant c_dump_rate_delta : real := 0.05; -- = 5 % + + constant c_dump_nof_ai : natural := vector_sum(g_dump_enables); + constant c_dump_ai_indices : t_nat_integer_arr(g_dump_enables'range) := vector_one_indices(g_dump_enables); + constant c_read_nof_packets_per_ai : natural := c_dump_nof_pages_actual; + constant c_read_total_nof_packets : natural := c_dump_nof_ai * c_dump_nof_pages_actual; + constant c_read_nof_crc_errors : natural := 0; + constant c_read_nof_rsn_errors : natural := 0; + constant c_dump_nof_packets_per_ai : natural := c_read_nof_packets_per_ai; + constant c_dump_nof_packets_per_loop : natural := c_dump_nof_ai * c_dump_nof_packets_per_ai; + constant c_dump_total_nof_packets : natural := c_read_total_nof_packets; + + -- SDP info + constant c_exp_sdp_info : t_sdp_info := ( + TO_UVEC(3, 6), -- antenna_field_index + TO_UVEC(601, 10), -- station_id + '0', -- antenna_band_index + x"7FFFFFFF", -- observation_id + b"01", -- nyquist_zone_index, 0 = first, 1 = second, 2 = third + '1', -- f_adc, 0 = 160 MHz, 1 = 200 MHz + '0', -- fsub_type, 0 = critically sampled, 1 = oversampled + '0', -- beam_repositioning_flag + x"1400" -- block_period = 5120 + ); + + -- TBuf dump header fields + constant c_cep_eth_src_mac : std_logic_vector(47 downto 0) := + c_sdp_cep_eth_src_mac_47_16 & func_sdp_gn_index_to_mac_15_0(c_gn_index); + constant c_cep_ip_src_addr : std_logic_vector(31 downto 0) := + c_sdp_cep_ip_src_addr_31_16 & func_sdp_gn_index_to_ip_15_0(c_gn_index); + constant c_cep_udp_src_port : std_logic_vector(15 downto 0) := c_sdp_cep_udp_src_port_15_8 & c_id; + + -- Determine expected ip_header_checksum for c_unb_nr = 1, c_node_nr = 2, and g_rs_block_size. Value obtained from + -- rx_dump_header.ip.header_checksum in wave window + function func_exp_ip_header_checksum(g_rs_block_size : natural) return natural is + begin + if g_rs_block_size = 100 then + return 16#7806#; + elsif g_rs_block_size = 102 then + return 16#77FF#; + elsif g_rs_block_size = 2000 then + return 16#5E0C#; + else + return 0; + end if; + end func_exp_ip_header_checksum; + + constant c_exp_ip_header_checksum : natural := func_exp_ip_header_checksum(g_rs_block_size); + + constant c_packed_empty_w : natural := 3; -- = ceil_log2(c_longword_sz - 1) + constant c_rx_fifo_size : natural := g_rs_block_size; + + -- DDR4 + constant c_exp_ddr_ctlr_nof_bytes_per_word : natural := c_sdp_tbuf_W_word / c_byte_w; + + -- WG + -- . Observe WG using rs_sosi.sop and rs_data_arr() in decimal format in Wave Window. + constant c_bsn_start_wg : natural := c_init_bsn + 2; -- start WG at this BSN instead of some BSN, to avoid + -- mismatches in exact expected data values + + -- MM + constant c_addr_w_reg_diag_wg : natural := 2; + constant c_mm_span_reg_diag_wg : natural := 2**c_addr_w_reg_diag_wg; + constant c_addr_w_reg_dp_xonoff : natural := 1; + constant c_mm_span_reg_dp_xonoff : natural := 2**c_addr_w_reg_dp_xonoff; + + constant c_mm_file_reg_bsn_source_v2 : string := c_mmf_prefix & "REG_BSN_SOURCE_V2"; + constant c_mm_file_reg_bsn_scheduler_wg : string := c_mmf_prefix & "REG_BSN_SCHEDULER"; + constant c_mm_file_reg_diag_wg : string := c_mmf_prefix & "REG_WG"; + constant c_mm_file_reg_sdp_info : string := c_mmf_prefix & "REG_SDP_INFO"; + constant c_mm_file_reg_io_ddr_mb_i : string := c_mmf_prefix & "REG_IO_DDR_MB_I"; + constant c_mm_file_reg_tbuf : string := c_mmf_prefix & "REG_TBUF"; + constant c_mm_file_reg_bsn_monitor_v2_tbuf : string := c_mmf_prefix & "REG_BSN_MONITOR_V2_TBUF"; + constant c_mm_file_reg_strobe_total_count_tbuf : string := c_mmf_prefix & "REG_STROBE_TOTAL_COUNT_TBUF"; + constant c_mm_file_reg_hdr_dat : string := c_mmf_prefix & "REG_HDR_DAT"; -- BF beamlets header + constant c_mm_file_reg_hdr_dat_tbuf : string := c_mmf_prefix & "REG_HDR_DAT_TBUF"; -- TBuf dump header + constant c_mm_file_reg_dp_xonoff : string := c_mmf_prefix & "REG_DP_XONOFF"; -- BF beamlet output enable + constant c_mm_file_reg_dp_xonoff_tbuf : string := c_mmf_prefix & "REG_DP_XONOFF_TBUF"; -- TBuf dump output enable + constant c_mm_file_reg_nw_10gbe_mac : string := c_mmf_prefix & "REG_NW_10GBE_MAC"; + + signal wg_started : std_logic := '0'; + signal rx_done : std_logic := '0'; + signal tb_almost_end : std_logic := '0'; + signal i_tb_end : std_logic := '0'; + signal tb_clk : std_logic := '0'; + signal rd_data_setup : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_state : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_control : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_monitor : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_bsn : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_record_busy : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_dump_done : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_strobe : std_logic_vector(c_32 - 1 downto 0); + signal rd_data_nw_10gbe_mac : std_logic_vector(c_32 - 1 downto 0); + + signal dest_rst : std_logic := '1'; -- use separate destination rst for Rx 10GbE in tb + signal pps_rst : std_logic := '1'; -- use separate reset to release the PPS generator + signal gen_pps : std_logic := '0'; + + -- MM + signal rd_cep_eth_src_mac : std_logic_vector(47 downto 0); + signal rd_cep_eth_dst_mac : std_logic_vector(47 downto 0); + signal rd_cep_ip_src_addr : std_logic_vector(31 downto 0); + signal rd_cep_ip_dst_addr : std_logic_vector(31 downto 0); + signal rd_cep_udp_src_port : std_logic_vector(15 downto 0); + signal rd_cep_udp_dst_port : std_logic_vector(15 downto 0); + + signal ddr_status : std_logic_vector(31 downto 0); + signal ddr_wr_fifo_used : natural; + signal ddr_rd_fifo_used : natural; + signal ddr_wr_fifo_full : std_logic; + signal ddr_rd_fifo_full : std_logic; + signal ddr_dvr_done : std_logic := '0'; + signal ddr_ctlr_nof_bytes_per_word : natural; + + -- WG + signal current_bsn_wg : std_logic_vector(c_dp_stream_bsn_w - 1 downto 0); + + -- TBuf + signal tbuf_registers_wr : t_sdp_tbuf_registers_rw; + signal tbuf_registers_rd : t_sdp_tbuf_registers_rw; -- read (rd) of write (wr) + signal tbuf_registers_ro : t_sdp_tbuf_registers_ro; -- read only (ro) + signal tbuf_strobe_total_counts : t_sdp_tbuf_strobe_total_counts_ro; + signal recording_rsn_at_sync : natural; + signal recording_nof_sop_per_sync : natural; + signal dump_index : natural; + signal time_index : natural; + signal read_busy : std_logic := '0'; + signal dump_rate_bps : real := 0.0; + + signal dbg_c_exp_read_rate_bps : real := c_exp_read_rate_bps; + signal dbg_c_exp_dump_rate_bps : real := c_exp_dump_rate_bps; + signal dbg_c_dump_nof_ai : natural := c_dump_nof_ai; + signal dbg_c_dump_ai_indices : t_nat_integer_arr(g_dump_enables'range) := c_dump_ai_indices; + signal dbg_c_read_nof_packets_per_ai : natural := c_read_nof_packets_per_ai; + signal dbg_c_read_total_nof_packets : natural := c_read_total_nof_packets; + signal dbg_c_read_nof_crc_errors : natural := c_read_nof_crc_errors; + signal dbg_c_read_nof_rsn_errors : natural := c_read_nof_rsn_errors; + signal dbg_c_dump_nof_packets_per_ai : natural := c_dump_nof_packets_per_ai; + signal dbg_c_dump_nof_packets_per_loop : natural := c_dump_nof_packets_per_loop; + signal dbg_c_dump_total_nof_packets : natural := c_dump_total_nof_packets; + + -- CEP model + -- . 10GbE + signal tr_10GbE_src_out : t_dp_sosi; + signal tr_10GbE_src_in : t_dp_siso; + signal tr_ref_clk_312 : std_logic := '0'; + signal tr_ref_clk_156 : std_logic := '0'; + signal tr_ref_rst_156 : std_logic := '0'; + + -- . dp_offload_rx + signal rx_dump_hdr_fields_raw : std_logic_vector(1023 downto 0) := (others => '0'); + signal rx_dump_sosi : t_dp_sosi := c_dp_sosi_rst; + + -- Dump packets header + signal tb_dump_cnt : natural := 0; + signal rx_dump_header : t_sdp_tbuf_cep_header; + signal exp_dump_header : t_sdp_tbuf_cep_header; + signal rx_dump_marker : natural; + signal rx_dump_station_info : t_sdp_station_info; + signal exp_dump_station_info : t_sdp_station_info; + signal exp_dump_ai : natural; + signal exp_dp_rsn : natural; + + -- Dump packets data + signal rx_dump_packet_cnt : natural := 0; + signal rx_stats_etherstatspkts : natural; + signal rx_fifo_siso : t_dp_siso; + signal rx_fifo_sosi : t_dp_sosi; + signal rx_ant_sosi : t_dp_sosi := c_dp_sosi_rst; + signal rx_ant_sosi_prev_eop : std_logic; + signal rx_ant_data_arr : t_sdp_sp_data_arr(1 downto 0); -- 14 bit, dual pol, X = 0, Y = 1 + signal rx_ant_dc_data_err : std_logic; + signal rx_ant_sinus_data_err : std_logic; + signal rx_ant_index : natural; + signal rx_dump_length_cnt : natural; + signal rx_dump_length : natural; + signal rx_wg_data : integer := 0; + signal exp_wg_data : integer := 0; + signal diff_wg_data : integer := 0; + signal diff_wg_max : integer := 0; + + -- DUT + signal ext_clk : std_logic := '0'; + signal ext_pps : std_logic := '0'; + + signal WDI : std_logic; + signal INTA : std_logic; + signal INTB : std_logic; + + signal eth_clk : std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0) := (others => '0'); + signal eth_txp : std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0); + signal eth_rxp : std_logic_vector(c_unb2c_board_nof_eth - 1 downto 0); + + 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'; + + -- jesd204b syncronization signals + signal jesd204b_sysref : std_logic; + signal jesd204b_sync_n : std_logic_vector(c_sdp_N_sync_jesd - 1 downto 0); + + -- DDR4 reference clock + signal MB_I_REF_CLK : std_logic; +begin + tb_end <= i_tb_end; + + ---------------------------------------------------------------------------- + -- System setup + ---------------------------------------------------------------------------- + tb_clk <= not tb_clk and not i_tb_end after c_tb_clk_period / 2; -- Testbench MM clock + ext_clk <= not ext_clk and not i_tb_end after c_ext_clk_period / 2; -- External clock (200 MHz) + eth_clk(0) <= not eth_clk(0) and not i_tb_end after c_eth_clk_period / 2; -- Ethernet ref clock (125 MHz) + JESD204B_REFCLK <= not JESD204B_REFCLK and not i_tb_end after c_bck_ref_clk_period / 2; -- JESD sample clock (200MHz) + SA_CLK <= not SA_CLK and not i_tb_end after c_sa_clk_period / 2; -- Serial Gigabit IO sa clock (644 MHz) + MB_I_REF_CLK <= ext_clk; -- DDR4 reference clock, same source as ext_clk (200 MHz) + dest_rst <= '0' after c_ext_clk_period * 10; + + INTA <= 'H'; -- pull up + INTB <= 'H'; -- pull up + + ------------------------------------------------------------------------------ + -- 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; + + ------------------------------------------------------------------------------ + -- DUT + -- . Uses lofar2_unb2c_sdp_station instead of synthesis wrapper lofar2_unb2c_sdp_station_tbuf_ring, to be able to + -- use the JESD204B signal names instead of the unb2c pin names and to have access to all generics. + ------------------------------------------------------------------------------ + u_lofar_unb2c_sdp_station_tbuf_ring : entity lofar2_unb2c_sdp_station_lib.lofar2_unb2c_sdp_station + generic map ( + g_design_name => c_design_name, + g_design_note => "AIT + TBuf + Ring for dump from multiple nodes", + g_sim => c_sim, + g_sim_tb_index => g_tb_index, + g_sim_unb_nr => c_unb_nr, + g_sim_node_nr => c_node_nr, + g_sim_sdp_tbuf => c_sim_sdp_tbuf, + g_bsn_nof_clk_per_sync => c_bs_nof_clk_per_sync, + g_bs_block_size => c_bs_block_size + ) + port map ( + -- GENERAL + CLK => ext_clk, + PPS => ext_pps, + WDI => WDI, + INTA => INTA, + INTB => INTB, + + -- Others + VERSION => c_version, + ID => c_id, + TESTIO => open, + + -- 1GbE Control Interface + ETH_CLK => eth_clk, + ETH_SGIN => eth_rxp, + ETH_SGOUT => eth_txp, + + -- Transceiver clocks + SA_CLK => SA_CLK, + + -- front transceivers + QSFP_1_RX => si_lpbk_0, + QSFP_1_TX => si_lpbk_0, + + -- LEDs + QSFP_LED => open, + + -- 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, + + -- DDR4 reference clock + MB_I_REF_CLK => MB_I_REF_CLK + -- DDR4 SO-DIMM Memory Bank I --> simulation use internal sim_ddr model in io_ddr + ); + + ------------------------------------------------------------------------------ + -- CEP model + ------------------------------------------------------------------------------ + u_unb2_board_clk644_pll : entity tech_pll_lib.tech_pll_xgmii_mac_clocks + port map ( + refclk_644 => SA_CLK, + rst_in => dest_rst, + clk_156 => tr_ref_clk_156, + clk_312 => tr_ref_clk_312, + rst_156 => tr_ref_rst_156, + rst_312 => open + ); + + u_tr_10GbE: entity tr_10GbE_lib.tr_10GbE + generic map ( + g_sim => true, + g_sim_level => 1, + g_nof_macs => 1, + g_use_mdio => false + ) + port map ( + -- Transceiver PLL reference clock + tr_ref_clk_644 => SA_CLK, + tr_ref_clk_312 => tr_ref_clk_312, -- 312.5 MHz for 10GBASE-R + tr_ref_clk_156 => tr_ref_clk_156, -- 156.25 MHz for 10GBASE-R or for XAUI + tr_ref_rst_156 => tr_ref_rst_156, -- for 10GBASE-R or for XAUI + + -- MM interface + mm_rst => dest_rst, + mm_clk => tb_clk, + + -- DP interface + dp_rst => dest_rst, + dp_clk => ext_clk, + + serial_rx_arr(0) => si_lpbk_0(0), + + src_out_arr(0) => tr_10GbE_src_out, + src_in_arr(0) => tr_10GbE_src_in + ); + + u_dp_offload_rx : entity dp_lib.dp_offload_rx + generic map ( + g_nof_streams => 1, + g_data_w => c_longword_w, + g_symbol_w => c_octet_w, + g_hdr_field_arr => c_sdp_tbuf_hdr_field_arr, + g_remove_crc => false, + g_crc_nof_words => 0 + ) + port map ( + mm_rst => dest_rst, + mm_clk => tb_clk, + + dp_rst => dest_rst, + dp_clk => ext_clk, + + reg_hdr_dat_mosi => c_mem_copi_rst, + reg_hdr_dat_miso => open, + + snk_in_arr(0) => tr_10GbE_src_out, + snk_out_arr(0) => tr_10GbE_src_in, + + src_out_arr(0) => rx_dump_sosi, + + hdr_fields_out_arr => open, + hdr_fields_raw_arr(0) => rx_dump_hdr_fields_raw + ); + + -- All rx_dump_sosi frames are rx dump packets + rx_dump_header <= func_sdp_tbuf_map_cep_header(rx_dump_hdr_fields_raw); + + -- FIFO to fit backpressure for u_dp_repack_data_word + u_dp_fifo_sc : entity dp_lib.dp_fifo_sc + generic map ( + g_data_w => c_longword_w, + g_empty_w => c_packed_empty_w, + g_use_empty => true, + g_use_ctrl => true, + g_fifo_size => c_rx_fifo_size + ) + port map ( + rst => dest_rst, + clk => ext_clk, + + snk_in => rx_dump_sosi, + src_in => rx_fifo_siso, + src_out => rx_fifo_sosi + ); + + -- 64 * 7 = 28 * 16 = 448 + u_dp_repack_data_word : entity dp_lib.dp_repack_data + generic map ( + g_in_dat_w => c_longword_w, -- = 64 + g_in_nof_words => 7, + g_in_symbol_w => c_octet_w, + g_out_dat_w => c_sdp_W_ant, -- = 28 + g_out_nof_words => 16, + g_out_symbol_w => 1, + g_pipeline_ready => false -- true to pipeline ready from src_in to snk_out. + ) + port map ( + rst => dest_rst, + clk => ext_clk, + snk_in => rx_fifo_sosi, + snk_out => rx_fifo_siso, + src_out => rx_ant_sosi + ); + + rx_ant_sosi_prev_eop <= rx_ant_sosi.eop when rising_edge(ext_clk); + + p_rx_ant : process(rx_ant_sosi, rx_ant_sosi_prev_eop, rx_dump_header) + begin + for I in 0 to c_sdp_N_pol - 1 loop + rx_ant_data_arr(I) <= rx_ant_sosi.data((I + 1) * c_sdp_W_adc - 1 downto I * c_sdp_W_adc); + end loop; + if rx_ant_sosi.valid = '0' or rx_ant_sosi_prev_eop = '1' then + -- Check valid to ensure that rx_ant_index is updated after previous packet was finished + rx_ant_index <= to_uint(rx_dump_header.app.sdp_antenna_input_index) mod c_sdp_A_pn; + end if; + end process; + + ------------------------------------------------------------------------------ + -- MM slave accesses via file IO + ------------------------------------------------------------------------------ + p_mm_setup : process + variable v_offset : natural; + variable v_addr : natural; + variable v_norm_ampl : real; + variable v_bsn : natural; + variable v_sp_power_sum : real; + begin + -- Wait for DUT power up after reset + wait for 200 ns; + + ---------------------------------------------------------------------------- + -- Set SDP info + ---------------------------------------------------------------------------- + -- TYPE t_sdp_info IS RECORD + -- 8 antenna_field_index : STD_LOGIC_VECTOR(5 DOWNTO 0); + -- 7 station_id : STD_LOGIC_VECTOR(9 DOWNTO 0); + -- 6 antenna_band_index : STD_LOGIC; + -- 5 observation_id : STD_LOGIC_VECTOR(31 DOWNTO 0); + -- 4 nyquist_zone_index : STD_LOGIC_VECTOR(1 DOWNTO 0); + -- 3 f_adc : STD_LOGIC; + -- 2 fsub_type : STD_LOGIC; + -- 1 beam_repositioning_flag : STD_LOGIC; + -- 0 block_period : STD_LOGIC_VECTOR(15 DOWNTO 0); + -- END RECORD; + -- . Write + mmf_mm_bus_wr(c_mm_file_reg_sdp_info, 8, TO_UINT(c_exp_sdp_info.antenna_field_index), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_sdp_info, 7, TO_UINT(c_exp_sdp_info.station_id), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_sdp_info, 6, TO_UINT(slv(c_exp_sdp_info.antenna_band_index)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_sdp_info, 5, TO_UINT(c_exp_sdp_info.observation_id), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_sdp_info, 4, TO_UINT(c_exp_sdp_info.nyquist_zone_index), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_sdp_info, 1, TO_UINT(slv(c_exp_sdp_info.beam_repositioning_flag)), tb_clk); + + ---------------------------------------------------------------------------- + -- Set TBuf dump output MAC,IP,UDP port + ---------------------------------------------------------------------------- + -- TBuf dump header + -- c_sdp_tbuf_hdr_field_arr : t_common_field_arr(c_sdp_tbuf_nof_hdr_fields - 1 downto 0) := ( + -- 33 field_name_pad("eth_dst_mac" ), "RW", 48, field_default(0) ), -- c_sdp_cep_eth_dst_mac + -- 31 field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + -- 30 field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + -- + -- 29 field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + -- 28 field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + -- 27 field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + -- 26 field_name_pad("ip_total_length" ), "RW", 16, field_default(c_sdp_tbuf_ip_total_length) ), + -- 25 field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), + -- 24 field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + -- 23 field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), + -- 22 field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), + -- 21 field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), + -- 20 field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), + -- 19 field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), + -- 18 field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- c_sdp_cep_ip_dst_addr + -- + -- 17 field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), + -- 16 field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- c_sdp_cep_udp_dst_port + -- 15 field_name_pad("udp_total_length" ), "RW", 16, field_default(c_sdp_tbuf_udp_total_length) ), + -- 14 field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + -- + -- 13 field_name_pad("sdp_marker" ), "RW", 8, field_default(c_sdp_tbuf_marker) ), + -- 12 field_name_pad("sdp_version_id" ), "RW", 8, field_default(c_sdp_tbuf_version_id) ), + -- 11 field_name_pad("sdp_observation_id" ), "RW", 32, field_default(0) ), + -- 10 field_name_pad("sdp_station_info" ), "RW", 16, field_default(0) ), + -- + -- 9 field_name_pad("sdp_source_info_antenna_band_id"), "RW", 1, field_default(0) ), + -- 8 field_name_pad("sdp_source_info_nyquist_zone_id"), "RW", 2, field_default(0) ), + -- 7 field_name_pad("sdp_source_info_f_adc" ), "RW", 1, field_default(0) ), + -- 6 field_name_pad("sdp_source_info_sample_width" ), "RW", 4, field_default(c_sdp_W_adc) ), + -- 5 field_name_pad("sdp_source_info_gn_id" ), "RW", 8, field_default(0) ), + -- + -- 4 field_name_pad("sdp_reserved" ), "RW", 24, field_default(0) ), + -- 3 field_name_pad("sdp_antenna_input_index" ), "RW", 8, field_default(0) ), + -- 2 field_name_pad("sdp_nof_raw_data_per_packet" ), "RW", 16, field_default(c_sdp_tbuf_rs_blk_size) ), + -- + -- 0 field_name_pad("dp_rsn" ), "RW", 64, field_default(0) ) + -- + -- Write tb defaults + -- . Use sim default dst and src MAC, IP, UDP port from sdp_pkg.vhd and based on c_gn_index + -- . Use signed to fit 32 b in INTEGER + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 32, TO_UINT(c_cep_eth_src_mac(47 downto 32)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 31, TO_SINT(c_cep_eth_src_mac(31 downto 0)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 19, TO_SINT(c_cep_ip_src_addr), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 17, TO_UINT(c_cep_udp_src_port), tb_clk); + -- . Set destination MAC/IP/UDP via c_mm_file_reg_hdr_dat_tbuf + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 34, TO_UINT(c_sdp_cep_eth_dst_mac(47 downto 32)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 33, TO_SINT(c_sdp_cep_eth_dst_mac(31 downto 0)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 18, TO_SINT(c_sdp_cep_ip_dst_addr), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat_tbuf, 16, TO_UINT(c_sdp_cep_udp_dst_port), tb_clk); + -- . Use same src MAC, src IP and dst IP for ARP/ping via BF header MM register of beamset 0 + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 39, TO_UINT(c_cep_eth_src_mac(47 downto 32)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 38, TO_SINT(c_cep_eth_src_mac(31 downto 0)), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 26, TO_SINT(c_cep_ip_src_addr), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_hdr_dat, 25, TO_SINT(c_sdp_cep_ip_dst_addr), tb_clk); + proc_common_wait_cross_clock_domain_latency( + c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2); + -- . Read back + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 32, rd_data_setup, tb_clk); + rd_cep_eth_src_mac(47 downto 32) <= rd_data_setup(15 downto 0); + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 31, rd_data_setup, tb_clk); + rd_cep_eth_src_mac(31 downto 0) <= rd_data_setup; + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 19, rd_data_setup, tb_clk); + rd_cep_ip_src_addr <= rd_data_setup; + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 17, rd_data_setup, tb_clk); + rd_cep_udp_src_port <= rd_data_setup(15 downto 0); + -- . Read back destination MAC/IP/UDP via c_mm_file_reg_hdr_dat_tbuf + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 34, rd_data_setup, tb_clk); + rd_cep_eth_dst_mac(47 downto 32) <= rd_data_setup(15 downto 0); + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 33, rd_data_setup, tb_clk); + rd_cep_eth_dst_mac(31 downto 0) <= rd_data_setup; + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 18, rd_data_setup, tb_clk); + rd_cep_ip_dst_addr <= rd_data_setup; + mmf_mm_bus_rd(c_mm_file_reg_hdr_dat_tbuf, 16, rd_data_setup, tb_clk); + rd_cep_udp_dst_port <= rd_data_setup(15 downto 0); + proc_common_wait_some_cycles(tb_clk, 1); + -- . verify read back source MAC/IP/UDP + assert rd_cep_eth_src_mac = c_cep_eth_src_mac + report c_tb_str & "Wrong MM read rd_cep_eth_src_mac for dump" + severity ERROR; + assert rd_cep_ip_src_addr = c_cep_ip_src_addr + report c_tb_str & "Wrong MM read rd_cep_ip_src_addr for dump" + severity ERROR; + assert rd_cep_udp_src_port = c_cep_udp_src_port + report c_tb_str & "Wrong MM read rd_cep_udp_src_port for dump" + severity ERROR; + -- . verify read back destination MAC/IP/UDP + assert rd_cep_eth_dst_mac = c_sdp_cep_eth_dst_mac + report c_tb_str & "Wrong MM read rd_cep_eth_dst_mac for dump" + severity ERROR; + assert rd_cep_ip_dst_addr = c_sdp_cep_ip_dst_addr + report c_tb_str & "Wrong MM read rd_cep_ip_dst_addr for dump" + severity ERROR; + assert rd_cep_udp_dst_port = c_sdp_cep_udp_dst_port + report c_tb_str & "Wrong MM read rd_cep_udp_dst_port for dump" + severity ERROR; + + ---------------------------------------------------------------------------- + -- Read DDR4 memory status + ---------------------------------------------------------------------------- + mmf_mm_bus_rd(c_mm_file_reg_io_ddr_mb_i, 0, rd_data_setup, tb_clk); + ddr_status <= rd_data_setup; + proc_common_wait_some_cycles(tb_clk, 1); + + -- . verify dvr_done for calibration ok + ddr_dvr_done <= ddr_status(0); + proc_common_wait_some_cycles(tb_clk, 1); + assert ddr_dvr_done = '1' + report c_tb_str & "Wrong no DDR MB_I" + severity ERROR; + + -- . verify ddr_ctlr_nof_bytes_per_word + ddr_ctlr_nof_bytes_per_word <= TO_UINT(ddr_status(15 downto 8)); + proc_common_wait_some_cycles(tb_clk, 1); + assert ddr_ctlr_nof_bytes_per_word = c_exp_ddr_ctlr_nof_bytes_per_word + report c_tb_str & "Wrong read ddr_ctlr_nof_bytes_per_word" + severity ERROR; + + ---------------------------------------------------------------------------- + -- Enable BS + ---------------------------------------------------------------------------- + mmf_mm_bus_wr(c_mm_file_reg_bsn_source_v2, 2, c_init_bsn, tb_clk); -- Init BSN + 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_bs_nof_clk_per_sync, tb_clk); + 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 100 ns; + pps_rst <= '0'; + + ---------------------------------------------------------------------------- + -- Enable WG + ---------------------------------------------------------------------------- + -- 0 : mode[7:0] --> off=0, calc=1, repeat=2, single=3) + -- nof_samples[31:16] --> <= c_ram_wg_size=1024 + -- 1 : phase[15:0] + -- 2 : freq[30:0] + -- 3 : ampl[16:0] + -- Put DC signal on all SP + for S in 0 to c_sdp_S_pn - 1 loop + v_offset := S * c_mm_span_reg_diag_wg; + -- use WG ampl = sp index, phase = 90 and freq = 0 to have DC level = sp index + v_norm_ampl := real(S) / real(c_sdp_FS_adc); + 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(90.0 * c_diag_wg_phase_unit), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 2, 0, tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_diag_wg, v_offset + 3, integer(v_norm_ampl * c_diag_wg_ampl_unit), tb_clk); + end loop; + + -- Read current BSN + 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 c_tb_str & "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 + + ---------------------------------------------------------------------------- + -- Wait until WG has started + ---------------------------------------------------------------------------- + mmf_mm_wait_until_value( + c_mm_file_reg_bsn_scheduler_wg, 0, -- read BSN low part + "UNSIGNED", rd_data_bsn, ">=", c_bsn_start_wg, -- this is the wait until condition + c_T_bs_period, ext_clk); + + -- WG started + wg_started <= '1'; + + ---------------------------------------------------------------------------- + -- Wait for enough WG data + ---------------------------------------------------------------------------- + proc_common_wait_until_high(ext_clk, tb_almost_end); + + --------------------------------------------------------------------------- + -- End simulation + --------------------------------------------------------------------------- + proc_common_wait_some_cycles(ext_clk, 100); -- delay for ease of view in Wave window + proc_common_stop_simulation(g_tb_end, g_tb_index, 0, ext_clk, tb_almost_end, i_tb_end); + wait; + end process; + + p_mm_tbuf_control : process + variable v_bool : boolean; + variable v_offset : natural; + variable v_recorded_nof_pages : natural; + variable v_Begin : natural; + variable v_End : natural; + variable v_Period : real := 0.0; + variable v_dump_rate_bps : real := 0.0; + variable v_dump_start_page : natural; + variable v_dump_start_rsn : std_logic_vector(c_sdp_W_rsn - 1 downto 0); + begin + -- Init tbuf_registers_wr record + tbuf_registers_wr.record_all <= '1'; -- 2 + tbuf_registers_wr.record_enable <= '1'; -- 3 + tbuf_registers_wr.dump_inter_packet_gap <= g_dump_inter_packet_gap; -- 11 + tbuf_registers_wr.dump_start_page <= 0; -- 12 + tbuf_registers_wr.dump_nof_pages <= c_dump_nof_pages_rw; -- 13 + tbuf_registers_wr.dump_start_rsn <= (others => 'X'); -- 14 + tbuf_registers_wr.dump_enables <= (others => '0'); -- 16 + + -- Wait for DUT power up after reset + wait for 200 ns; + --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(461603339, 32)); + --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(461602827, 32)); + --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(515, 32)); + --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(741, 32)); + --v_bool := func_sdp_tbuf_print_state(c_tb_str, to_uvec(3, 32)); + + ---------------------------------------------------------------------------- + -- Record all antennas + ---------------------------------------------------------------------------- + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 2, to_int(tbuf_registers_wr.record_all), tb_clk); + + ---------------------------------------------------------------------------- + -- Enable packet dump output + ---------------------------------------------------------------------------- + mmf_mm_bus_wr(c_mm_file_reg_dp_xonoff_tbuf, 0, 1, tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 11, tbuf_registers_wr.dump_inter_packet_gap, tb_clk); + + ---------------------------------------------------------------------------- + -- Report and verify sizes + ---------------------------------------------------------------------------- + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 0, rd_data_control, tb_clk); + tbuf_registers_ro.nof_samples_per_block <= to_uint(rd_data_control); + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 1, rd_data_control, tb_clk); + tbuf_registers_ro.nof_pages_in_buffer <= to_uint(rd_data_control); + proc_common_wait_some_cycles(tb_clk, 1); + assert tbuf_registers_ro.nof_samples_per_block = g_rs_block_size + report c_tb_str & "Wrong tbuf_registers_ro.nof_samples_per_block " + severity ERROR; + assert tbuf_registers_ro.nof_pages_in_buffer = c_nof_pages_in_buffer + report c_tb_str & "Wrong tbuf_registers_ro.nof_pages_in_buffer " + severity ERROR; + print_str(c_tb_str & "tbuf_registers_ro.nof_samples_per_block = " & + int_to_str(tbuf_registers_ro.nof_samples_per_block)); + print_str(c_tb_str & "tbuf_registers_ro.nof_pages_in_buffer = " & + int_to_str(tbuf_registers_ro.nof_pages_in_buffer)); + + ---------------------------------------------------------------------------- + -- RECORD + ---------------------------------------------------------------------------- + print_str(c_tb_str & "--------------------------------------------"); + print_str(c_tb_str & "-- RECORD"); + print_str(c_tb_str & "--------------------------------------------"); + -- Enable recording + proc_common_wait_until_high(ext_clk, wg_started); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 3, to_int(tbuf_registers_wr.record_enable), tb_clk); + proc_common_wait_cross_clock_domain_latency( + c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2); + -- Read back record_enable + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 3, rd_data_control, tb_clk); + tbuf_registers_rd.record_enable <= rd_data_control(0); + -- Read record_busy, wait one rs_block for record_enable to take effect + proc_common_wait_some_cycles(ext_clk, g_rs_block_size); + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 18, rd_data_record_busy, tb_clk); + tbuf_registers_ro.record_busy <= rd_data_record_busy(0); + proc_common_wait_some_cycles(tb_clk, 1); + assert tbuf_registers_rd.record_enable = '1' + report c_tb_str & "Wrong tbuf_registers_rd.record_enable /= '1'" + severity ERROR; + assert tbuf_registers_ro.record_busy = '1' + report c_tb_str & "Wrong tbuf_registers_ro.record_busy /= '1'" + severity ERROR; + print_str(c_tb_str & "tbuf_registers_rd.record_enable = " & sl_to_str(tbuf_registers_rd.record_enable)); + print_str(c_tb_str & "tbuf_registers_ro.record_busy = " & sl_to_str(tbuf_registers_ro.record_busy)); + + -- Read TBuf state + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 19, rd_data_state, tb_clk); + proc_common_wait_some_cycles(tb_clk, 1); + v_bool := func_sdp_tbuf_print_state(c_tb_str, rd_data_state); + + -- Recording + proc_common_wait_some_cycles(ext_clk, g_rs_block_size * g_rs_record_nof_block); + + -- Read BSN monitor for recording data + mmf_mm_bus_rd(c_mm_file_reg_bsn_monitor_v2_tbuf, 1, rd_data_monitor, tb_clk); -- bsn at sync + recording_rsn_at_sync <= to_uint(rd_data_monitor); + mmf_mm_bus_rd(c_mm_file_reg_bsn_monitor_v2_tbuf, 3, rd_data_monitor, tb_clk); -- nof_sop + recording_nof_sop_per_sync <= to_uint(rd_data_monitor); + proc_common_wait_some_cycles(tb_clk, 1); + assert recording_nof_sop_per_sync = c_rs_nof_block_per_sync + report c_tb_str & "Wrong RSN monitor nof blocks per sync" + severity ERROR; + print_str(c_tb_str & "recording_rsn_at_sync = " & int_to_str(recording_rsn_at_sync)); + print_str(c_tb_str & "recording_nof_sop_per_sync = " & int_to_str(recording_nof_sop_per_sync)); + + ---------------------------------------------------------------------------- + -- FREEZE + ---------------------------------------------------------------------------- + print_str(c_tb_str & "--------------------------------------------"); + print_str(c_tb_str & "-- FREEZE "); + print_str(c_tb_str & "--------------------------------------------"); + -- Disable recording + tbuf_registers_wr.record_enable <= '0'; + proc_common_wait_some_cycles(tb_clk, 1); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 3, to_int(tbuf_registers_wr.record_enable), tb_clk); + proc_common_wait_cross_clock_domain_latency( + c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2); + -- Read disabled recording + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 3, rd_data_control, tb_clk); + tbuf_registers_rd.record_enable <= rd_data_control(0); + proc_common_wait_some_cycles(tb_clk, 1); + assert tbuf_registers_rd.record_enable = '0' + report c_tb_str & "Wrong tbuf_registers_rd.record_enable /= '0'" + severity ERROR; + -- Wait until recording has finished, read record_busy to account for latency in record_enable disabled + mmf_mm_wait_until_value( + c_mm_file_reg_tbuf, 18, -- read record_busy + "UNSIGNED", rd_data_record_busy, "=", 0, -- this is the wait until condition + c_T_rd_interval, ext_clk); + tbuf_registers_ro.record_busy <= rd_data_record_busy(0); + proc_common_wait_some_cycles(tb_clk, 1); + print_str(c_tb_str & "tbuf_registers_rd.record_enable = " & sl_to_str(tbuf_registers_rd.record_enable)); + print_str(c_tb_str & "tbuf_registers_ro.record_busy = " & sl_to_str(tbuf_registers_ro.record_busy)); + + -- Read number of recorded pages + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 4, rd_data_control, tb_clk); + tbuf_registers_ro.recorded_nof_pages <= to_uint(rd_data_control); + + -- Read indices of first and last recorded page + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 5, rd_data_control, tb_clk); + tbuf_registers_ro.recorded_first_page <= to_uint(rd_data_control); + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 6, rd_data_control, tb_clk); + tbuf_registers_ro.recorded_last_page <= to_uint(rd_data_control); + proc_common_wait_some_cycles(tb_clk, 1); + + v_recorded_nof_pages := tbuf_registers_ro.recorded_last_page - tbuf_registers_ro.recorded_first_page; + if v_recorded_nof_pages <= 0 then + v_recorded_nof_pages := v_recorded_nof_pages + tbuf_registers_ro.nof_pages_in_buffer; + end if; + assert tbuf_registers_ro.recorded_nof_pages > 0 + report c_tb_str & "Wrong tbuf_registers_ro.recorded_nof_pages = 0" + severity ERROR; + assert tbuf_registers_ro.recorded_nof_pages = v_recorded_nof_pages + report c_tb_str & + "Wrong tbuf_registers_ro.recorded_nof_pages does not match recorded_first_page and recorded_last_page" + severity ERROR; + + -- Read timestamps of first and last recorded page + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 7, rd_data_control, tb_clk); -- read low part + tbuf_registers_ro.recorded_first_rsn(31 downto 0) <= rd_data_control; + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 8, rd_data_control, tb_clk); -- read high part + tbuf_registers_ro.recorded_first_rsn(63 downto 32) <= rd_data_control; + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 9, rd_data_control, tb_clk); -- read low part + tbuf_registers_ro.recorded_last_rsn(31 downto 0) <= rd_data_control; + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 10, rd_data_control, tb_clk); -- read high part + tbuf_registers_ro.recorded_last_rsn(63 downto 32) <= rd_data_control; + proc_common_wait_some_cycles(tb_clk, 1); + assert to_uint(tbuf_registers_ro.recorded_last_rsn) - to_uint(tbuf_registers_ro.recorded_first_rsn) = + v_recorded_nof_pages * g_rs_block_size + report c_tb_str & "Wrong tbuf_registers_ro.recorded_last_rsn - tbuf_registers_ro.recorded_first_rsn" + severity ERROR; + + -- Check that record_all = '1' + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 2, rd_data_control, tb_clk); + tbuf_registers_rd.record_all <= rd_data_control(0); + proc_common_wait_some_cycles(tb_clk, 1); + assert tbuf_registers_rd.record_all = '1' + report c_tb_str & "Wrong tbuf_registers_rd.record_all /= 1" + severity ERROR; + print_str(c_tb_str & "tbuf_registers_rd.record_all = " & sl_to_str(tbuf_registers_rd.record_all)); + print_str(c_tb_str & "tbuf_registers_ro.nof_samples_per_block = " & + int_to_str(tbuf_registers_ro.nof_samples_per_block)); + print_str(c_tb_str & "tbuf_registers_ro.nof_pages_in_buffer = " & + int_to_str(tbuf_registers_ro.nof_pages_in_buffer)); + print_str(c_tb_str & "tbuf_registers_ro.recorded_nof_pages = " & + int_to_str(tbuf_registers_ro.recorded_nof_pages)); + print_str(c_tb_str & "tbuf_registers_ro.recorded_first_page = " & + int_to_str(tbuf_registers_ro.recorded_first_page)); + print_str(c_tb_str & "tbuf_registers_ro.recorded_last_page = " & + int_to_str(tbuf_registers_ro.recorded_last_page)); + print_str(c_tb_str & "tbuf_registers_ro.recorded_first_rsn = " & + int_to_str(to_uint(tbuf_registers_ro.recorded_first_rsn))); + print_str(c_tb_str & "tbuf_registers_ro.recorded_last_rsn = " & + int_to_str(to_uint(tbuf_registers_ro.recorded_last_rsn))); + + ---------------------------------------------------------------------------- + -- DUMP + ---------------------------------------------------------------------------- + -- Wait until nw_10GbE xon = '1' + while NOW < 11 us loop + wait for 100 ns; + end loop; + + for DUMP in 0 to c_nof_dump - 1 loop + tb_dump_cnt <= tb_dump_cnt + 1; + proc_common_wait_some_cycles(tb_clk, 1); + print_str(c_tb_str & "--------------------------------------------"); + print_str(c_tb_str & "-- DUMP : " & int_to_str(tb_dump_cnt)); + print_str(c_tb_str & "--------------------------------------------"); + + -- Clear dump strobe_total_counts + mmf_mm_bus_wr(c_mm_file_reg_strobe_total_count_tbuf, c_sdp_tbuf_nof_strobe_total_counts_clear_id, 1, tb_clk); + proc_common_wait_cross_clock_domain_latency( + c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2); + + -- Set dump interval and antenna inputs + v_dump_start_page := tbuf_registers_ro.recorded_first_page + g_dump_page_offset; + if v_dump_start_page >= c_nof_pages_in_buffer then + -- Wrap from begin of buffer when v_dump_start_page is just beyond the end of buffer. Do not use modulo + -- c_nof_pages_in_buffer to be able to simulate effect of a much too large v_dump_start_page due to + -- g_dump_page_offset >= c_nof_pages_in_buffer + v_dump_start_page := v_dump_start_page - c_nof_pages_in_buffer; + end if; + tbuf_registers_wr.dump_start_page <= v_dump_start_page; + v_dump_start_rsn := incr_uvec(tbuf_registers_ro.recorded_first_rsn, g_dump_page_offset * g_rs_block_size); + tbuf_registers_wr.dump_start_rsn <= v_dump_start_rsn; + tbuf_registers_wr.dump_enables <= g_dump_enables; + proc_common_wait_some_cycles(tb_clk, 1); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 12, tbuf_registers_wr.dump_start_page, tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 13, tbuf_registers_wr.dump_nof_pages, tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 14, to_uint(tbuf_registers_wr.dump_start_rsn), tb_clk); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 16, to_uint(tbuf_registers_wr.dump_enables), tb_clk); + proc_common_wait_cross_clock_domain_latency( + c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2); + + if g_dump_nof_pages > 0 then + -- Time dump begin + read_busy <= '1'; + v_Begin := NOW / c_1ns; + proc_common_wait_some_cycles(tb_clk, 1); + + -- Read back enabled dump + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 16, rd_data_control, tb_clk); + tbuf_registers_rd.dump_enables <= rd_data_control(c_sdp_A_pn - 1 downto 0); + proc_common_wait_some_cycles(tb_clk, 1); + assert to_uint(tbuf_registers_rd.dump_enables) = to_uint(tbuf_registers_wr.dump_enables) + report c_tb_str & "Wrong tbuf_registers_rd.dump_enables enabled" + severity ERROR; + print_str(c_tb_str & "tbuf_registers_rd.dump_enables = " & slv_to_str(tbuf_registers_rd.dump_enables)); + + ---------------------------------------------------------------------------- + -- Wait until dump is done + ---------------------------------------------------------------------------- + mmf_mm_wait_until_value( + c_mm_file_reg_tbuf, 17, -- read dump_done + "UNSIGNED", rd_data_dump_done, "=", 1, -- this is the wait until condition + c_T_rd_interval, ext_clk); + tbuf_registers_ro.dump_done <= rd_data_dump_done(0); + proc_common_wait_some_cycles(tb_clk, 1); + + -- Time dump end + read_busy <= '0'; + v_End := NOW / c_1ns; + v_Period := real(v_End - v_Begin) * 1.0e-9; -- dump time in s + v_dump_rate_bps := real(c_dump_total_nof_packets * c_sdp_W_ant * g_rs_block_size) / v_Period; + dump_rate_bps <= v_dump_rate_bps; + + -- Verify dump rate over sufficient number of packets + if c_dump_total_nof_packets > 5 then + -- . use almost_equal(a/b, 1.0, max_ratio) to verify that a and b differ less than max_ratio/100 percent + assert almost_equal(v_dump_rate_bps / c_exp_dump_rate_bps, 1.0, c_dump_rate_delta) + report c_tb_str & "Wrong dump rate" + severity ERROR; + end if; + print_str(c_tb_str & "Dump rate = " & real_to_str(v_dump_rate_bps / c_Gbps, 4, 2) & " Gbps" & + " (Expected " & real_to_str(c_exp_dump_rate_bps / c_Gbps, 4, 2) & " Gbps)"); + end if; + + -- Wait some time for latency in sdp_tbuf_output and 10GbE Tx - Rx network + proc_common_wait_some_cycles(ext_clk, g_rs_block_size * 4); + rx_done <= '1'; + + -- Read strobe_total_counts + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 0, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_read_nof_packets <= to_uint(rd_data_strobe); + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 2, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_read_nof_crc_errors <= to_uint(rd_data_strobe); + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 4, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_read_nof_rsn_errors <= to_uint(rd_data_strobe); + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 6, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_read_dumped_nof_packets <= to_uint(rd_data_strobe); + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 8, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_ring_rx_nof_packets <= to_uint(rd_data_strobe); + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 10, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_ring_tx_nof_packets <= to_uint(rd_data_strobe); + mmf_mm_bus_rd(c_mm_file_reg_strobe_total_count_tbuf, 12, rd_data_strobe, tb_clk); + tbuf_strobe_total_counts.memory_output_nof_packets <= to_uint(rd_data_strobe); + proc_common_wait_some_cycles(tb_clk, 1); + assert tbuf_strobe_total_counts.memory_read_nof_packets = c_read_total_nof_packets + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_nof_packets" + severity ERROR; + assert tbuf_strobe_total_counts.memory_read_nof_crc_errors = c_read_nof_crc_errors + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_nof_crc_errors" + severity ERROR; + assert tbuf_strobe_total_counts.memory_read_nof_rsn_errors = c_read_nof_rsn_errors + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_nof_rsn_errors" + severity ERROR; + assert tbuf_strobe_total_counts.memory_read_dumped_nof_packets = c_dump_total_nof_packets + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_read_dumped_nof_packets" + severity ERROR; + assert tbuf_strobe_total_counts.memory_ring_rx_nof_packets = 0 + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_ring_rx_nof_packets" + severity ERROR; + assert tbuf_strobe_total_counts.memory_ring_tx_nof_packets = c_dump_total_nof_packets + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_ring_tx_nof_packets" + severity ERROR; + assert tbuf_strobe_total_counts.memory_output_nof_packets = c_dump_total_nof_packets + report c_tb_str & "Wrong tbuf_strobe_total_counts.memory_output_nof_packets" + severity ERROR; + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_nof_packets = " & + int_to_str(tbuf_strobe_total_counts.memory_read_nof_packets)); + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_nof_crc_errors = " & + int_to_str(tbuf_strobe_total_counts.memory_read_nof_crc_errors)); + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_nof_rsn_errors = " & + int_to_str(tbuf_strobe_total_counts.memory_read_nof_rsn_errors)); + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_read_dumped_nof_packets = " & + int_to_str(tbuf_strobe_total_counts.memory_read_dumped_nof_packets)); + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_ring_rx_nof_packets = " & + int_to_str(tbuf_strobe_total_counts.memory_ring_rx_nof_packets)); + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_ring_tx_nof_packets = " & + int_to_str(tbuf_strobe_total_counts.memory_ring_tx_nof_packets)); + print_str(c_tb_str & "tbuf_strobe_total_counts.memory_output_nof_packets = " & + int_to_str(tbuf_strobe_total_counts.memory_output_nof_packets)); + + -- Read REG_NW_10GBE_MAC counts + -- . In sim via si_lpbk_0 loopback on own port, on HW using another node on unb2c as dump destination + -- . Only need to read low word part of rx_stats_etherstatspkts[35:0] + -- . Expect at least tbuf_strobe_total_counts.memory_output_nof_packets, there can be more when the nw_10gbe + -- does an ARP. + mmf_mm_bus_rd(c_mm_file_reg_nw_10gbe_mac, 16#C1C#, rd_data_nw_10gbe_mac, tb_clk); + rx_stats_etherstatspkts <= TO_UINT(rd_data_nw_10gbe_mac); + proc_common_wait_some_cycles(tb_clk, 1); + assert rx_stats_etherstatspkts >= tbuf_strobe_total_counts.memory_output_nof_packets + report c_tb_str & "Wrong rx_stats_etherstatspkts" + severity ERROR; + print_str(c_tb_str & "rx_stats_etherstatspkts = " & int_to_str(rx_stats_etherstatspkts)); + + -- Disable dump + proc_common_wait_some_cycles(ext_clk, 100); -- delay for ease of view in Wave window + tbuf_registers_wr.dump_enables <= (others => '0'); + proc_common_wait_some_cycles(tb_clk, 1); + mmf_mm_bus_wr(c_mm_file_reg_tbuf, 16, to_uint(tbuf_registers_wr.dump_enables), tb_clk); + proc_common_wait_cross_clock_domain_latency( + c_mm_clk_period, c_ext_clk_period, c_common_cross_clock_domain_latency * 2); + -- Read back disabled dump + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 16, rd_data_control, tb_clk); + tbuf_registers_rd.dump_enables <= rd_data_control(c_sdp_A_pn - 1 downto 0); + proc_common_wait_some_cycles(tb_clk, 1); + assert to_uint(tbuf_registers_rd.dump_enables) = to_uint(tbuf_registers_wr.dump_enables) + report c_tb_str & "Wrong tbuf_registers_rd.dump_enables disabled" + severity ERROR; + -- Read dump_done to check that it is '0' + mmf_mm_bus_rd(c_mm_file_reg_tbuf, 17, rd_data_dump_done, tb_clk); + tbuf_registers_ro.dump_done <= rd_data_dump_done(0); + proc_common_wait_some_cycles(tb_clk, 1); + assert tbuf_registers_ro.dump_done = '0' + report c_tb_str & "Wrong tbuf_registers_ro.dump_done" + severity ERROR; + print_str(c_tb_str & "tbuf_registers_rd.dump_enables = " & slv_to_str(tbuf_registers_rd.dump_enables)); + print_str(c_tb_str & "tbuf_registers_ro.dump_done = " & sl_to_str(tbuf_registers_ro.dump_done)); + end loop; + + --------------------------------------------------------------------------- + -- Almost end simulation + --------------------------------------------------------------------------- + tb_almost_end <= '1'; + wait; + end process; + + ----------------------------------------------------------------------------- + -- Verify TBuf dump packet header + ----------------------------------------------------------------------------- + -- Prepare exp_dump_header before rx_dump_sosi.eop. + exp_dump_header <= func_sdp_tbuf_compose_cep_header(c_cep_ip_src_addr, + c_exp_ip_header_checksum, + c_exp_sdp_info, + c_gn_index, + c_sdp_W_adc, + exp_dump_ai, + g_rs_block_size, + exp_dp_rsn); + exp_dump_station_info <= func_sdp_map_station_info(exp_dump_header.app.sdp_station_info); + rx_dump_station_info <= func_sdp_map_station_info(rx_dump_header.app.sdp_station_info); + + p_verify_rx_dump_header : process + variable v_dump_index : natural; + variable v_time_index : natural; + variable v_ai_local : natural; + variable v_cnt : natural; + variable v_bool : boolean; + begin + wait until rising_edge(ext_clk); + if c_dump_nof_packets_per_ai > 0 then + -- Count rx_dump_sosi packets at sop + if rx_dump_sosi.sop = '1' then + -- Determine expected antenna_input_index assuming c_dump_nof_packets_per_ai per ai. Use modulo + -- c_dump_nof_packets_per_loop to account for c_nof_dump > 1 + v_cnt := rx_dump_packet_cnt mod c_dump_nof_packets_per_loop; + v_dump_index := v_cnt / c_dump_nof_packets_per_ai; + v_ai_local := c_dump_ai_indices(v_dump_index); + exp_dump_ai <= c_ai_offset + v_ai_local; + + -- Determine expected RSN assuming c_dump_nof_packets_per_ai per ai + v_time_index := v_cnt mod c_dump_nof_packets_per_ai; + exp_dp_rsn <= to_uint(tbuf_registers_wr.dump_start_rsn) + v_time_index * g_rs_block_size; + + -- Increment rx_dump_packet_cnt signal + rx_dump_packet_cnt <= rx_dump_packet_cnt + 1; + end if; + -- Verify header at eop + if rx_dump_sosi.eop = '1' then + v_bool := func_sdp_tbuf_verify_cep_header(rx_dump_header, exp_dump_header); + end if; + -- View variables in Wave Window + dump_index <= v_dump_index; + time_index <= v_time_index; + else + -- Expect no dump packets when g_dump_nof_pages = 0 + assert rx_dump_sosi.sop = '0' + report c_tb_str & "Wrong unexpected rx_dump_sosi packet for g_dump_nof_pages = 0" + severity ERROR; + end if; + end process; + + ----------------------------------------------------------------------------- + -- Verify TBuf dump packet data + ----------------------------------------------------------------------------- + p_verify_rx_dump_block_length : process + variable v_cnt : natural; + begin + wait until rising_edge(ext_clk); + -- Count received data per rs_block + if rx_ant_sosi.sop = '1' then + v_cnt := 1; + elsif rx_ant_sosi.valid = '1' then + v_cnt := v_cnt + 1; + end if; + if rx_ant_sosi.eop = '1' then + rx_dump_length <= v_cnt; + end if; + rx_dump_length_cnt <= v_cnt; + -- Verify received g_rs_block_size + if rx_ant_sosi.valid = '1' then + assert v_cnt <= g_rs_block_size + report c_tb_str & "Wrong rx_ant_sosi block length too long" + severity ERROR; + end if; + if rx_ant_sosi.eop = '1' then + assert v_cnt = g_rs_block_size + report c_tb_str & "Wrong rx_ant_sosi block length" + severity ERROR; + end if; + end process; + + -- Verify the SP that have their WG set to DC data equal to their sp index value + p_verify_rx_dump_block_dc_data : process + variable v_sp : natural; + begin + wait until rising_edge(ext_clk); + rx_ant_dc_data_err <= '0'; + if rx_ant_sosi.valid = '1' then + for I in 0 to c_sdp_N_pol - 1 loop + v_sp := rx_ant_index * c_sdp_N_pol + I; + if to_uint(rx_ant_data_arr(I)) /= v_sp then + rx_ant_dc_data_err <= '1'; + report c_tb_str & "Wrong rx_ant_sosi block DC data for SP " & int_to_str(v_sp) + severity ERROR; + end if; + end loop; + end if; + end process; +end tb; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd new file mode 100644 index 0000000000000000000000000000000000000000..4ed2e49f14a508d8fab43a4fda322be35025d615 --- /dev/null +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_tbuf_ring/tb_tb_lofar2_unb2c_sdp_station_tbuf_ring.vhd @@ -0,0 +1,64 @@ +-- -------------------------------------------------------------------------- +-- Copyright 2025 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- -------------------------------------------------------------------------- +-- +-- Author: E. Kooistra, 28 may 2025 +-- Purpose: Regression multi tb for tb_lofar2_unb2c_sdp_station_tbuf_ring +-- Description: +-- The multi tb only has one instance, so the tb_tb is more a wrapper to +-- ensure that always the same tb generics are used in the regression test. +-- This allows modifying the generics in the tb. +-- Usage: +-- . Modelsim: +-- > as 4 +-- > as 8 # debug to view tbuf states +-- > run -all +-- . Terminal: +-- > cat transcript | grep Error: + +library IEEE, common_lib; +use IEEE.std_logic_1164.all; +use common_lib.tb_common_pkg.all; + +entity tb_tb_lofar2_unb2c_sdp_station_tbuf_ring is +end tb_tb_lofar2_unb2c_sdp_station_tbuf_ring; + +architecture tb of tb_tb_lofar2_unb2c_sdp_station_tbuf_ring is + -- Multi tb + -- . Use tb index offset c_tbi to avoid file IO conflict during modelsim_regression_test_vhdl.py with other tb, like + -- tb_lofar2_unb2c_sdp_station_bf_ring, in shared HDL_IOFILE_SIM_DIR = build/sim directory set by init_hdl.sh. + constant c_tbi : natural := 30; + constant c_tb_end_vec : std_logic_vector(c_tbi to c_tbi) := (others => '1'); + + signal tb_end_vec : std_logic_vector(c_tb_end_vec'range) := c_tb_end_vec; -- best view as hex in Wave Window + signal tb_end : std_logic := '0'; +begin + u_tbuf_ring : entity work.tb_lofar2_unb2c_sdp_station_tbuf_ring + generic map ( + g_tb_index => c_tbi, + g_ddr_buffer_size => 256, -- <= 4096, because c_tech_ddr4_sim_4k_64 has 4k = 4096 words of + -- c_sdp_tbuf_W_word = 512b + g_rs_block_size => 100, -- c_sdp_tbuf_rs_block_size = 2000, must be even see sdp_tbuf_output + g_rs_record_nof_block => 3, -- choose > c_rs_nof_block_per_sync to have at least on sync interval + -- for the RSN monitor + g_dump_inter_packet_gap => 0, -- use 1708 for 3 Gbps and g_rs_block_size = 2000 + g_dump_page_offset => 0, -- offset relative to recorded_first_page + g_dump_nof_pages => 3, -- g_dump_page_offset + g_dump_nof_pages <= g_rs_record_nof_block, else + -- there will occur read RSN errors for pages that are not available + g_dump_enables => "111111" + ); +end tb; diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd index 677d29d58643c2b9f09c4984cd62aa313f7d8783..c348d4b8377e449150ecf98a4d8e9bc579db003e 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/src/vhdl/lofar2_unb2c_sdp_station_pkg.vhd @@ -60,6 +60,8 @@ package lofar2_unb2c_sdp_station_pkg is (false, true, false, false, false, 1, true, false, true, 9); constant c_tbuf_one : t_lofar2_unb2c_sdp_station_config := (false, false, false, false, false, 1, false, true, false, 0); + constant c_tbuf_ring : t_lofar2_unb2c_sdp_station_config := + (false, false, false, false, false, 1, false, true, true, 0); constant c_full_wg : t_lofar2_unb2c_sdp_station_config := (true, true, false, true, true, 1, true, false, true, 9); constant c_full : t_lofar2_unb2c_sdp_station_config := @@ -86,6 +88,7 @@ package body lofar2_unb2c_sdp_station_pkg is elsif g_design_name = "lofar2_unb2c_sdp_station_xsub_one" then return c_xsub_one; elsif g_design_name = "lofar2_unb2c_sdp_station_xsub_ring" then return c_xsub_ring; elsif g_design_name = "lofar2_unb2c_sdp_station_tbuf_one" then return c_tbuf_one; + elsif g_design_name = "lofar2_unb2c_sdp_station_tbuf_ring" then return c_tbuf_ring; elsif g_design_name = "lofar2_unb2c_sdp_station_full_wg" then return c_full_wg; -- = baseline elsif g_design_name = "lofar2_unb2c_sdp_station_full" then return c_full; -- = baseline elsif g_design_name = "disturb2_unb2c_sdp_station_full_wg" then return c_full_wg_os;