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

Initial version to capture and verify the visibility packet header.

parent 3851ef5f
No related branches found
No related tags found
No related merge requests found
###############################################################################
#
# 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())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment