From 5220a5a2f715f9194f85281fdf0e3b414d91a193 Mon Sep 17 00:00:00 2001 From: Erik Kooistra <kooistra@astron.nl> Date: Wed, 13 Jun 2018 14:31:43 +0000 Subject: [PATCH] Initial version to capture and verify the visibility packet header. --- .../tests/verify_correlator_db_output.py | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 applications/apertif/commissioning/tests/verify_correlator_db_output.py diff --git a/applications/apertif/commissioning/tests/verify_correlator_db_output.py b/applications/apertif/commissioning/tests/verify_correlator_db_output.py new file mode 100644 index 0000000000..cb7c1f54ae --- /dev/null +++ b/applications/apertif/commissioning/tests/verify_correlator_db_output.py @@ -0,0 +1,255 @@ +############################################################################### +# +# 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 correlator visibility packet output via DB + + These test on hardware is equivalent to test bench tb_node_apertif_unb1_correlator_processing_output.vhd + and tb_apertif_unb1_correlator_nodes in simulation. In node_apertif_unb1_correlator_output.vhd the test uses: + + * REG_DIAG_DATA_BUFFER_OUTPUT to set the data capture at the start of a packet + * RAM_DIAG_DATA_BUFFER_OUTPUT to read the packet data + + The test verifies the read data and runs independently per PN. + + Usage: + # -v 5 or 6 for debugging + # -v 0, 1, 2 or 3 for regression test + + # At central correlator verify expected result via DB + > python $RADIOHDL/applications/apertif/commissioning/tests/verify_correlator_db_output.py -v 3 --tel a --unb 0 --fn 0:3 --bn 0:3 +""" + +############################################################################### +# System imports +import sys +import common as cm +import test_case +import node_io +import pi_diag_data_buffer + +N_dish = 12 +N_pol = 2 +N_tp = N_pol * N_dish # = 24 +N_vis = N_tp * (N_tp + 1) / 2 +N_band = 16 +N_clk = 256 +N_blk = 176 # 8b mode +Q_interleave = 2 +M_blk = N_blk / Q_interleave # = 88 +N_int_x = 800000 +N_chan_x = 64 +N_chan_x_w = cm.ceil_log2(N_chan_x) +nof_bn = 4 # Number of back node FPGAs (BN) per UniBoard +nof_fn = 4 # Number of front node FPGAs (FN) per UniBoard +nof_pn = 8 # Number of processing node FPGAs per UniBoard, = nof_fn + nof_bn +nof_10g = 3 # Number of external 10G links per PN on UniBoard +c_dbSize = 1024 +c_dbPattern = [13]*c_dbSize + +c_expDstMac = 0x123456789ABC +c_baseSrcMac = 0x002286080000 + +wsrtTelescopes = ['2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd'] + +############################################################################### +# Classes, functions + +# Use class ApertifUnb1CorrelatorPacketInfo in Python as record. Similar as t_apertif_unb1_correlator_packet_info +# VHDL record in apertif_unb1_correlator_pkg.vhd. +class ApertifUnb1CorrelatorPacketInfo: + def __init__(self, nof_visibilities): + """Define parameters for correlator packet info + . nof_visibilities determines the packet payload size + . size in number of cm.c_word_w = 32b words + """ + self.vis_header_size = 21 # (pad(2) + eth(14) + ip(20) + udp(8) + app_id(16) + app_flags(24)) / 4 = 84 bytes / 4 = 21 words + self.vis_payload_size = nof_visibilities * cm.c_nof_complex + self.vis_payload_nof_bits = self.vis_payload_size * cm.c_word_w + self.vis_packet_size = self.vis_header_size + self.vis_payload_size + # account for ethernet overhead + self.eth_tail_size = 1 # for the eth CRC word + self.eth_gap_size = 3 # 3 words for c_network_eth_gap_len of 12 bytes idle time between packets + self.eth_packet_size = self.vis_packet_size + self.eth_tail_size + self.eth_gap_size + # express ethernet packet time in effective number of bits on the link + self.eth_packet_nof_bits = self.eth_packet_size * cm.c_word_w + # Calculate ethernet packet overhead compared to visibility payload due to header, tail and interpacket gap + self.eth_packet_overhead = 1.0 * self.eth_packet_nof_bits / self.vis_payload_nof_bits + +# Declaring an object of this class is equivalent to func_apertif_unb1_correlator_packet_info() in VHDL. +corrPacketInfo = ApertifUnb1CorrelatorPacketInfo(N_vis) + +############################################################################### +# Instantiations +tc = test_case.Testcase('VERIFY_BF_CORRELATOR_LINK - ', '') +tc.set_result('PASSED') + +# One or more beamlet and channel indices to select the visibility packets +beamlets = tc.beamlets +channels = tc.channels + +tc.append_log(3, '>>>') +tc.append_log(1, '>>> Title : Test case to verify visibility packet header in correlator DB OUTPUT for %s' % tc.unb_nodes_string()) +tc.append_log(3, '>>> . beamlet(s) : %s (from range(M_blk) = [0:%d])' % (beamlets, M_blk-1)) +tc.append_log(3, '>>> . channel(s) : %s (from range(N_chan_x) = [0:%d])' % (channels, N_chan_x-1)) +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_output = pi_diag_data_buffer.PiDiagDataBuffer(tc, io, instanceName='OUTPUT', nofStreams=1, ramSizePerStream=c_dbSize, version=0) + + +for bui in beamlets: + for ch in channels: + ############################################################################### + # Stimuli + + # Overwrite DB data to be able to recognize new data + db_output.overwrite_all_data_buffers(data=c_dbPattern, vLevel=9) + + # Use start of packet address for DB sync delay + sopAddr = ((bui * N_chan_x) + ch) * corrPacketInfo.vis_packet_size + dbSyncDelay = sopAddr + db_output.write_sync_delay(data=dbSyncDelay) + db_output.read_sync_delay() + # when dbSyncDelay=0 then the DB is written every sync + # else need to arm the DB using write access strobe to capture once at next sync + dbSyncDelay + latency(14) + if dbSyncDelay>0: + # Wait unit DB is ready to arm + tc.sleep(2) + db_output.write_arm_reg(data=1) + # Wait unit DB have been filled + tc.sleep(2) + + # Read DB on all PN + dbOutputReadData = db_output.read_data_buffer(nofColumns=tc.nofCol) + + ############################################################################### + # Verification per PN + for ni,nr in enumerate(tc.nodeNrs): # loop PN + # Beamlet mapping as specified in SP-062 table 6 (SC1), 9 (SC4): + # + # u bi dest bu_i + # 0 0 0 FN0 0 2 ... + # 1 0 1 FN1 256 258 ... + # 2 0 2 FN2 512 514 ... + # 3 0 3 FN3 768 770 ... + # 0 1 4 BN0 1 3 ... + # 1 1 5 BN1 257 259 ... + # 2 1 6 BN2 513 515 ... + # 3 1 7 BN3 769 771 ... + # + # Beamlet mapping as implemented in Apertif X due to reordered_sosi_arr wiring in node_apertif_unb1_correlator_mesh.vhd: + # + # u bi dest bu_i + # 0 0 0 FN0 0 2 ... + # 1 0 1 FN1 1 3 ... + # 2 0 2 FN2 256 258 ... + # 3 0 3 FN3 257 259 ... + # 0 1 4 BN0 512 514 ... + # 1 1 5 BN1 513 515 ... + # 2 1 6 BN2 768 770 ... + # 3 1 7 BN3 769 771 ... + unb = nr / nof_pn # = range(N_band) = 0:15 = [0:127] / 8 + pn = nr % nof_pn # = range(nof_pn) = 0:7 = [0:127] % 8 + + expBeamlet = N_slot * unb # offset for UniBoard band + expBeamlet = expBeamlet + N_clk * (pn / Q_interleave) + (pn % Q_interleave) # offset for Local PN + expBeamlet = expBeamlet + bui * Q_interleave # offset serial beamlets + expChannel = cm.reverse_bits(ch, N_chan_x_w) + expChannel = cm.invert_msbit(expChannel, N_chan_x_w) + + # Verify header fields + # 0 gap(16) + ETH dst mac hi(16) + # 1 ETH dst mac lo + # 2 ETH src mac hi + # 3 ETH src mac lo(16) + type(16) + # 4 IP + # 5 IP + # 6 IP + # 7 IP src addr + # 8 IP dst addr + # 9 UDP src port(16) + dst port(16) + # 10 UDP total len(16) + checksum(16) + # 11 ID marker(8) + version(8) + beamlet(16) + # 12 ID channel(16) + rsvd(16) + # 13 ID timestamp hi + # 14 ID timestamp lo + # 15 FLAG + # 16 FLAG + # 17 FLAG + # 18 FLAG + # 19 FLAG + # 20 FLAG + + rdData = dbOutputReadData[ni] + reportStr = 'unb = %2d, pn = %d, bui = %3d, ch = %2d : ' % (unb, pn, bui, ch) + + # . dst mac + rdDstMac = to_unsigned(rdData[0], 16) << 32 + rdDstMac += to_unsigned(rdData[1], 32) + if rdDstMac == expDstMac: + tc.append_log(tc.V_INFO_DETAILS, reportStr + 'destination MAC = 0x%012X is OK' % rdDstMac) + else: + tc.append_log(tc.V_ERRORS, reportStr + 'read destination MAC is wrong (read 0x%012X != 0x%012X expected)' % (rdDstMac, expDstMac)) + tc.set_result('FAILED') + + # . src mac + expSrcMac = baseSrcMac + unb * 256 + pn + rdSrcMac = to_unsigned(rdData[2], 32) << 16 + rdSrcMac += to_unsigned(rdData[3], 32) >> 16 + if rdSrcMac == expSrcMac: + tc.append_log(tc.V_INFO_DETAILS, reportStr + 'source MAC = 0x%012X is OK' % rdSrcMac) + else: + tc.append_log(tc.V_ERRORS, reportStr + 'read source MAC is wrong (read 0x%012X != 0x%012X expected)' % (rdSrcMac, expSrcMac)) + tc.set_result('FAILED') + + # . beamlet + rdBeamlet = to_unsigned(rdData[11], 16) + if rdBeamlet == expBeamlet: + tc.append_log(tc.V_INFO_DETAILS, reportStr + 'beamlet = %d is OK' % rdBeamlet) + else: + tc.append_log(tc.V_ERRORS, reportStr + 'read beamlet is wrong (read %d != %d expected)' % (rdBeamlet, expBeamlet)) + tc.set_result('FAILED') + + # . channel + rdChannel = to_unsigned(rdData[12], 32) >> 16 + if rdChannel == expChannel: + tc.append_log(tc.V_INFO_DETAILS, reportStr + 'channel = %d is OK' % rdChannel) + else: + tc.append_log(tc.V_ERRORS, reportStr + 'read channel is wrong (read %d != %d expected)' % (rdChannel, expChannel)) + tc.set_result('FAILED') + + # . timestamp (= bsn) + rdBsn = to_unsigned(rdData[13], 32) << 32 + rdBsn += to_unsigned(rdData[14], 32) + tc.append_log(tc.V_INFO_DETAILS, reportStr + 'read BSN = %d' % rdBsn) + + +############################################################################### +# End +tc.set_section_id('') +tc.append_log(tc.V_RESULT, '>>> Test result: %s' % tc.get_result()) + -- GitLab