diff --git a/applications/apertif/commissioning/tests/verify_db_correlator.py b/applications/apertif/commissioning/tests/verify_db_correlator.py new file mode 100644 index 0000000000000000000000000000000000000000..9203a2f7b3175f7ff93da46eaa9910dbbae9e704 --- /dev/null +++ b/applications/apertif/commissioning/tests/verify_db_correlator.py @@ -0,0 +1,299 @@ +############################################################################### +# +# Copyright (C) 2018 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################### + +# Author: +# E. Kooistra 12 Mar 2018 Created + +"""Test BF - X 10G link and mesh + + This test on hardware is equivalent to test bench tb_apertif_bf_xc_link.vhd in + simulation. In node_apertif_unb1_correlator_input the test uses: + + * RAM_DIAG_DATA_BUFFER_INPUT_POST to read the data per c_nof_10g = 3 input links + * RAM_DIAG_DATA_BUFFER_MESH to read the data after the mesh for N_tp = 24 input links + + The test verifies the read data and runs independently per PN. + + In node_apertif_unb1_correlator_input the test uses: + * RAM_DIAG_DATA_BUFFER_INPUT_POST to read the data for c_nof_10g = three 10G links per + node after the BSN aligner + + In node_apertif_unb1_correlator_mesh the test uses: + * RAM_DIAG_DATA_BUFFER_MESH to read the data for N_tp = 24 TP per node after the mesh. + + Usage: + # -v 5 or 6 for debugging + # -v 0, 1, 2 or 3 for regression test + # At dish set dp_force_data_parallel + > ssh lcu-rt4 -X "python $RADIOHDL/applications/apertif/commissioning/tests/force_bf_transpose.py -v 3 --tel 4 --unb 0:3 --fn 0:3 --mode 0 --switch 0" + + # At central correlator verify expected result via DB (for same --tel --mode and --switch) + > python $RADIOHDL/applications/apertif/commissioning/tests/verify.py -v 5 --tel 4 --unb 2 --fn 0 --mode 0 --switch 0" + +""" + +############################################################################### +# System imports +import sys +from common import * +import test_case +import node_io +import pi_diag_data_buffer + +c_nof_fn = 4 # 4 FN per UniBoard +N_pol = 2 +P_BF = 4 # 4 BF units per FN +c_width = 8 # 8b mode +N_clk = 256 +N_blk = 176 # 8b mode +Q_interleave = 2 +M_blk = N_blk / Q_interleave # = 88 +N_int_x = 800000 +c_nof_10g = 3 # 3 10G input links per PN +nof_streams = c_nof_10g*P_BF # = 12 +c_dbSize = 512 + +############################################################################### +# Instantiations +tc = test_case.Testcase('VERIFY_DB_CORRELATOR - ', '') +tc.set_result('PASSED') + +# Read switch setting +switch = 0 +if tc.switch==1: + switch = 1 + +tc.append_log(3, '>>>') +if switch==0: + tc.append_log(1, '>>> Title : Test case to verify T_int_x transpose in BF and 10G link to X for %s' % (tc.unb_nodes_string())) +else: + tc.append_log(1, '>>> Title : Test case to verify bypass T_int_x transpose in BF and 10G link to X for %s' % (tc.unb_nodes_string())) +tc.append_log(3, '>>>') +tc.append_log(3, '') + +io = node_io.NodeIO(tc.nodeImages, tc.base_ip) + +# Create one DB object for all PN +db_input_post = pi_diag_data_buffer.PiDiagDataBuffer(tc, io, nodeNr=fn, instanceName='INPUT_POST', nofStreams=nof_streams, ramSizePerStream=c_dbSize, version=1) + +############################################################################### +# Stimuli +# Overwrite DB data to be able to recognize new data +pattern = [13]*c_dbSize +db_input_post.overwrite_all_data_buffers(data=pattern, vLevel=9) + +# Wait untit DB have been filled +tc.sleep(2) + +# Read DB for all PN +dbdata = db_input_post.read_all_data_buffers() + + +############################################################################### +# Verify DB per FN BF unit +# +# Loop over all data in a sync interval and use dbInRange to detect where the +# data_buffer will capture the dbSize. The check on dbInRange speeds up the +# loop. The check on rdaddr actually detects the postion of the data buffer at +# c_dbSyncDelay:c_dbSyncDelay+dbSize. +# +# Transpose input by dp_force_data_parallel per BF unit is: +# im: increments per sop and restarts at global u every sync +# re: 0 1 2 3 4 ................................................. 175 : 255 +# <-------------------------------------------------------------------> N_clk = 255 + +## For --switch 0 the expected T_int_x transpose via DDR3 output per BF unit is: +## im: 0 0 1 1 0 0 1 1 ... + global bf unit index MOD 256 +## re: 0 1 0 1 ... 0 1 2 3 2 3 ... 2 3 ... 174 175 +## <-------------------------------------------------------------> N_blk = 176 +## <-------------> <-------------> <-------------> N_int_x = 800000 on hw +## <-> <-> <-> <-> Q_interleave = 2 +#if switch==0: +# cntDbData = 0 +# for fi,fn in enumerate(tc.nodeFnIndices): # loop FN +# for u in range(P_BF): # loop BF units +# bf_unit_offset = fn * P_BF +# for bui in range(M_blk): +# dbLo = bui * N_int_x * Q_interleave - c_dbSyncDelay +# dbHi = (bui+1) * N_int_x * Q_interleave - c_dbSyncDelay +# dbInRange = dbHi > 0 and dbLo < c_dbSize +# if dbInRange: +# if u==0: +# tc.append_log(tc.V_DEBUG, 'T bui = %d, dbLo = %d, dbHi = %d' % (bui, dbLo, dbHi)) +# for t in range(N_int_x): +# dbLo = (bui * N_int_x + t) * Q_interleave - c_dbSyncDelay +# dbHi = dbLo + c_dbSize +# dbInRange = dbHi > 0 and dbLo < c_dbSize +# if dbInRange: +# if u==0: +# tc.append_log(tc.V_DEBUG, 't = %d, dbLo = %d, dbHi = %d' % (t, dbLo, dbHi)) +# exp_im = (bf_unit_offset + u + t) % N_clk +# for q in range(Q_interleave): +# rdaddr = (bui * N_int_x + t) * Q_interleave + q - c_dbSyncDelay; +# if rdaddr >= 0 and rdaddr < c_dbSize: +# if u==0: +# tc.append_log(tc.V_DEBUG, 'rdaddr : %d' % rdaddr) +# # Expected data +# exp_re = bui * Q_interleave + q +# exp_data = exp_im * 2**c_width + exp_re; +# # MM read data +# rddata = rddata_fn_u[fi][u][rdaddr] +# if rddata!=exp_data: +# tc.append_log(tc.V_ERRORS, 'fn = %2d, u = %d, rdaddr = %3d: read 0x%X != 0x%X expected' % (fn, u, rdaddr, rddata, exp_data)) +# tc.set_result('FAILED'); +# cntDbData += 1 +# else: +# if u==0: +# tc.append_log(tc.V_DEBUG, ' bui = %d, dbLo = %d, dbHi = %d' % (bui, dbLo, dbHi)) +# +## For --switch 1 the expected direct output per BF unit is (so bypass T_int_x transpose): +#if switch==1: +# cntDbData = 0 +# for fi,fn in enumerate(tc.nodeFnIndices): # loop FN +# for u in range(P_BF): # loop BF units +# bf_unit_offset = fn * P_BF +# for t in range(N_int_x): +# dbLo = t * N_clk - c_dbSyncDelay +# dbHi = (t+1) * N_clk - c_dbSyncDelay +# dbInRange = dbHi > 0 and dbLo < c_dbSize +# if dbInRange: +# if u==0: +# tc.append_log(tc.V_DEBUG, 't = %d, dbLo = %d, dbHi = %d' % (t, dbLo, dbHi)) +# exp_im = (bf_unit_offset + u + t) % N_clk +# for bu in range(N_clk): +# rdaddr = t * N_clk + bu - c_dbSyncDelay; +# if rdaddr >= 0 and rdaddr < c_dbSize: +# if u==0: +# tc.append_log(tc.V_DEBUG, 'rdaddr = %d' % rdaddr) +# # Expected data +# exp_re = bu +# exp_data = exp_im * 2**c_width + exp_re; +# # MM read data +# rddata = rddata_fn_u[fi][u][rdaddr] +# if rddata!=exp_data: +# tc.append_log(tc.V_ERRORS, 'fn = %2d, u = %d, rdaddr = %3d: read 0x%X != 0x%X expected' % (fn, u, rdaddr, rddata, exp_data)) +# tc.set_result('FAILED'); +# cntDbData += 1 +# +# +#nofFn = len(tc.nodeFnIndices) +#expCntDbData = nofFn * P_BF * c_dbSize +#if cntDbData != expCntDbData: +# tc.append_log(tc.V_ERRORS, 'Unexpected number of DB data = %d != %d' % (cntDbData, expCntDbData)) +# tc.set_result('FAILED'); +# +# +# p_mm_diag_data_buffer : PROCESS +# CONSTANT c_mm_file_ram_diag_data_buffer : STRING := mmf_unb_file_prefix(g_tb_index, c_central_unb_nr, c_central_unb_pn_nr) & "RAM_DIAG_DATA_BUFFER_INPUT_POST"; +# +# CONSTANT N_clk : NATURAL := c_bf.nof_weights; -- = 256 +# CONSTANT N_blk : NATURAL := c_block_size_out; -- = 176 (8 bit mode), 240 (6 bit mode) +# CONSTANT N_int_x : NATURAL := c_nof_block_per_sync; -- = e.g. 32 in sim, 800000 on hw (multiple of N_pre_tranpose = 16) +# CONSTANT Q_interleave : NATURAL := 2; -- = 8/4 = nof_pn / P_BF +# +# CONSTANT c_db_nof_words : NATURAL := N_int_x * N_blk; +# CONSTANT c_db_nof_words_pow2 : NATURAL := true_log_pow2(c_db_nof_words); +# +# CONSTANT c_max_X : NATURAL := c_nof_10g*c_bf.nof_bf_units; -- = 12, accept maximum one write/read data conflict per BF unit +# +# VARIABLE v_I : INTEGER; +# VARIABLE v_exp_re : NATURAL; +# VARIABLE v_exp_im : NATURAL; +# VARIABLE v_exp_data : NATURAL; +# VARIABLE v_rd_data : NATURAL; +# BEGIN +# -- Wait for DUT power up after reset +# WAIT FOR 1 us; +# +# -- Wait for DB to have filled with beamlet data from first transpose sync interval, +# -- see i_beamlets_src_out_arr in node_apertif_unb1_fn_beamformer_transpose +# proc_common_wait_until_time(ext_clk, 200 us); +# +# ---------------------------------------------------------------------------- +# -- Read and verify data buffer +# ---------------------------------------------------------------------------- +# -- Verify DB +# -- Transpose input per BF unit is: +# -- im: fixed at global BF unit index when c_use_force_en=FALSE +# -- increments per sop and restarts at global u every sync when c_use_force_en=TRUE +# -- re: 0 1 2 3 4 ................................................. 175 : 255 +# -- <-------------------------------------------------------------------> N_clk = 255 +# -- Expected transpose via DDR3 output per BF unit is: +# -- im: fixed at global BF unit index when c_use_force_en=FALSE +# -- 0 0 1 1 31 0 0 1 1 31 ... 31 31 when c_use_force_en=TRUE +# -- re: 0 1 0 1 ... 0 1 2 3 2 3 ... 2 3 ... 174 175 +# -- <-------------------------------------------------------------> N_blk = 176 +# -- <-------------> <-------------> <-------------> N_int_x = 32 in sim, 800000 on hw +# -- <-> <-> <-> <-> Q_interleave = 2 +# FOR lp IN 0 TO c_nof_10g-1 LOOP -- lp = link path +# FOR u IN 0 TO c_bf.nof_bf_units-1 LOOP +# -- Read data buffer per BF unit output +# v_exp_im := c_bf_unit_band_offset + u; -- im when c_use_force_en = FALSE, so BG output +# v_I := 0; +# FOR bui IN 0 TO N_blk/Q_interleave-1 LOOP +# FOR t IN 0 TO N_int_x-1 LOOP +# IF c_use_force_en=TRUE THEN +# IF g_force_im_ctrl=0 THEN +# v_exp_im := c_bf_unit_band_offset + u + t; -- im when c_use_force_en = TRUE +# ELSIF g_force_im_ctrl=1 THEN +# v_exp_im := c_telescope_path_offset + lp + t; -- im when c_use_force_en = TRUE +# END IF; +# END IF; +# FOR q IN 0 TO Q_interleave-1 LOOP +# -- Expected data +# v_exp_re := bui * Q_interleave + q; -- re is independent of c_use_force_en, because both BG and dp_force are set for same re data +# v_exp_data := v_exp_im * 2**c_transport_w + v_exp_re; +# -- MM read data +# mmf_mm_bus_rd(c_mm_file_ram_diag_data_buffer, (u + lp*c_bf.nof_bf_units)*c_db_nof_words_pow2 + v_I, rd_data_db, tb_clk); +# v_rd_data := TO_UINT(rd_data_db); +# IF v_rd_data/=v_exp_data THEN +# -- Count number of mismatches +# nof_rd_data_db_X <= nof_rd_data_db_X + 1; +# END IF; +# ASSERT v_rd_data=v_exp_data REPORT "DB unexpected data : " & int_to_str(v_rd_data) & " /= " & int_to_str(v_exp_data) SEVERITY NOTE; +# v_I := v_I + 1; +# END LOOP; +# END LOOP; +# END LOOP; +# -- Leave gap between BF unit accesses, to ease view in Wave window +# proc_common_wait_some_cycles(ext_clk, 100); +# END LOOP; +# -- Leave gap between lp input link accesses, to ease view in Wave window +# proc_common_wait_some_cycles(ext_clk, 100); +# END LOOP; +# +# -- Accept only a few mismatches when occasionaly MM read and internal firmware write occur at same address and then cause 'X' +# ASSERT nof_rd_data_db_X <= c_max_X REPORT "DB too many data MM read retries : " & int_to_str(nof_rd_data_db_X) & " > " & int_to_str(c_max_X) SEVERITY ERROR; +# proc_common_wait_some_cycles(ext_clk, 1000); +# +# -- Wait some more to check that tb_end can be released differently per tb in a multi tb +# proc_common_wait_some_cycles(ext_clk, 1000*g_tb_index); +# +# verify_db_done <= '1'; +# WAIT; +# END PROCESS; + + + +############################################################################### +# End +tc.set_section_id('') +tc.append_log(tc.V_RESULT, '>>> Test result: %s' % tc.get_result())