Skip to content
Snippets Groups Projects
Commit 677b09a8 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Merge branch 'L2SDP-1105' into 'L2SDP-LIFT'

Resolve L2SDP-1105

See merge request !449
parents fef2a627 8d16330e
Branches
No related tags found
1 merge request!449Resolve L2SDP-1105
Pipeline #120016 passed
Showing
with 1605 additions and 0 deletions
......@@ -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
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
-------------------------------------------------------------------------------
--
-- 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;
###############################################################################
#
# 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
-------------------------------------------------------------------------------
--
-- 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;
-- --------------------------------------------------------------------------
-- 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;
......@@ -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;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment