From 7e911f269993105c07f1be841946fbe28b3820ec Mon Sep 17 00:00:00 2001
From: ROBBE Patrick <robbe@lal.in2p3.fr>
Date: Sun, 27 Jan 2019 17:01:30 +0100
Subject: [PATCH] Add xvcr file

---
 Python/components/xcvr_comp.py | 988 +++++++++++++++++++++++++++++++++
 1 file changed, 988 insertions(+)
 create mode 100644 Python/components/xcvr_comp.py

diff --git a/Python/components/xcvr_comp.py b/Python/components/xcvr_comp.py
new file mode 100644
index 0000000..871fbed
--- /dev/null
+++ b/Python/components/xcvr_comp.py
@@ -0,0 +1,988 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+"""
+   xcvr_comp.py -- module to handle the transceiver registers managed by the fpga
+
+   Note:
+      This code will be running on FC
+   Author
+      JPC : 24/2/2018
+      JPC : 22/05/2018 : Corrected bug in phy calibration
+
+
+
+"""
+import time, sys
+from lli import mem_multi as mem
+from fpga_comp import Arria10
+from si534x_comp import Si534x
+from eepromat24c_comp import EepromAT24C
+from decimal import Decimal
+
+
+class xcvr(object):
+    """ Class to manage registers of the arria10.
+
+    The mapping of port registers per type of PLL is given as a class dictionnary
+    of lists of registers addresses.
+
+    Args:
+        dev (int):
+
+    """
+
+    add_xcvr = [0x00080000, 0x00090000, 0x000A0000, 0x000B0000, 0x000C0000, 0x000D0000, 0x000E0000, 0x000F0000, 0x00070000]
+    add_pll  = [0x00088000, 0x00098000, 0x000A8000, 0x000B8000, 0x000C8000, 0x000D8000, 0x000E8000, 0x000F8000, 0x00078000]
+
+
+    def __init__(self, dev):
+        """
+        Class initialization
+
+        Args:
+          dev (int): board identifier
+
+        type_pll = 0 :forced to fPLL
+                 = 1 :forced to ATX_PLL
+        """
+        self.dev = dev
+        self.type_pll = 0   # choose fPLL
+
+
+    def calibrate_pll(self, num_pll):
+        """
+        Recalibrate the given ATX or fPLL
+
+        Args:
+            num_pll (int) : PLL number
+
+        Return
+            failed : True if calibration failed, False otherwise
+
+        Raises:
+            ValueError:
+                for invalid name.
+        """
+        if num_pll > 8:
+        #print "NUM PLL FORBIDDEN"
+            return False
+        pll_add = self.add_pll[num_pll]
+        timeout = time.time() + 2  # timeout = 2 second
+
+        #### patch PLL direct mode ON
+
+        #print ".patch PLL direct mode ON "
+        status, val = mem.read(self.dev, pll_add + 0x126*4)
+        #print val
+        new_val = val|0x01
+#        print new_val
+        mem.write(self.dev, pll_add + 0x126*4, new_val)
+        print "..... Start calibrating PLL" + str(num_pll)
+    #### step 1
+#       print ". request user acces "
+        mem.write(self.dev, pll_add+0x000*4, 0x2)           # write 0x2
+    #### step 2
+#        print ". wait for reconfig_waitrequest to be deasserted "
+        bool_wait0 = True
+        while  bool_wait0:
+            status, val = mem.read(self.dev, pll_add+0x280*4)
+            test_bit = val&0x04
+            if test_bit == 0:
+               bool_wait0 = False
+#               print ". bus granted to user"
+            else:
+               if time.time() > timeout:
+#                  print "********** TIMEOUT **********"
+                  return False
+    #### step 3
+#        print ". start calibration PLL "
+        status, val = mem.read(self.dev, pll_add + 0x100*4)
+        if self.type_pll == 0:
+            new_val = val|0x2 # FPLL PLL
+#            print ". Targetting PLL type =  FPLL"
+        if self.type_pll == 1:
+            new_val = val|0x1 # ATX PLL
+#            print ". Targetting PLL type = ATX"
+        mem.write(self.dev, pll_add + 0x100*4, new_val)
+    #### step 4
+#        print ". release bus to preSICE"
+        mem.write(self.dev, pll_add +0x000*4, 0x1)
+    #### step 5
+#        print ". check reset of call_busy signal"
+        bool_call_busy1 = True
+        while  bool_call_busy1:
+            status, val = mem.read(self.dev, pll_add +0x280*4)
+            test_bit = val&0x02
+            if test_bit == 0:
+                bool_call_busy1 = False
+                print "..... Done "
+            else:
+                if time.time() > timeout:
+                    print "..... TIMEOUT during calibration"
+                    return False
+        ### patch PLL direct mode OFF
+#        print ".patch PLL direct mode OFF "
+        status, val = mem.read(self.dev, pll_add + 0x126*4)
+        new_val = val&0xfe
+        mem.write(self.dev, pll_add + 0x126*4, new_val)
+        ### check pll is locked
+        status, message = self.check_pll_locked(num_pll)
+        return status, message
+
+    def calibrate_pll_all(self):
+        """
+        Recalibrate all the ATX or fPLL
+        """
+        nb_plls = self.get_number_of_links() / 6
+        for pll in range(0, nb_plls):
+            self.calibrate_pll(pll)
+
+    def check_pll_locked(self, num_pll):
+        """
+        Check if ATX or fPLL is locked
+
+        Args:
+            num_pll (int): pll number
+
+        return:
+            status (bool): 1 if pll locked, 0 if not
+            message (str): explicit message
+        """
+        if num_pll > 8:
+        #print "NUM PLL FORBIDDEN"
+            return False, ""
+        pll_add = self.add_pll[num_pll]
+        check_lock = False
+        timeout = time.time() + 2  # timeout = 2 second
+        ####  Test PLL locked
+#        print ". check PLL" + str(num_pll) + " lock status"
+        bool_call_busy2 = True
+        while  bool_call_busy2:
+            status, val = mem.read(self.dev, pll_add + 0x280*4)#0x280
+            test_bit = val&0x01
+            if test_bit == 1:
+                bool_call_busy2 = False
+                #print " PLL" + str(num_pll) + " is locked"
+                check_lock = True
+                #print
+                #print
+                return check_lock, "PLL" + str(num_pll) + " is locked" #renvoie 1 pour valider la Qprossbar + message
+            else:
+                if time.time() > timeout:
+#                   print "********** PLL" + str(num_pll) + " TIMEOUT: PLL NOT LOCKED  or BAD ADRESS PLL or UNUSED PLL **********"
+                    return False, "PLL" + str(num_pll) + " is not locked :timeout"
+
+    def check_pll_locked_all(self):
+        """
+        Check if all ATX or fPLL are locked
+
+        return:
+            status (bool): 1 if all pll are locked, 0 if not
+        """
+        nb_plls = get_number_of_links()/6
+        status = 1
+        for pll in range(0, nb_plls):
+            if check_pll_locked(pll) == False:
+                status = 0
+        return status
+
+
+    def calibrate_phy(self, num_phy, channel):
+        """
+        Recalibrate the given phy.
+
+        Args:
+            num_phy (int): phy number (0 to 8)
+            channel (int): channel number (0 to 5)
+
+        Raises:
+            ValueError:
+                for invalid name.
+        """
+        if num_phy > 7:
+            print "NUM GBT FORBIDDEN"
+            return False
+        gbt_add = self.add_xcvr[num_phy] + channel * 0x1000
+        timeout = time.time() + 2  # timeout = 2 second
+        # print ".... Start calibration GBT" + str(num_phy) + ",Channel",
+    ### Step 1
+        # print ". request user acces"
+        mem.write(self.dev, gbt_add + 0x000 * 4, 0x2)
+    ### Step 2
+        # print ". wait for reconfig_waitrequest to be deasserted "
+        bool_wait1 = True
+        while bool_wait1:
+            status, val = mem.read(self.dev, gbt_add + 0x281 * 4)
+            test_bit = val & 0x04
+            # print hex(test_bit)
+            if test_bit == 0:
+                bool_wait1 = False
+                # print ". bus granted to user"
+            else:
+                print ". busy"
+                if time.time() > timeout:
+                    print "********** TIMEOUT GBT" + str(num_phy) + " **********"
+                    return 0
+    ### Step 3
+        # print "Configure PMA Calibration"
+        # status, val = mem.read(self.dev, gbt_add + 0x100 * 4)
+        # pma_cal_val = val | 0x31
+        # mem.write(self.dev, gbt_add + 0x100 * 4, pma_cal_val)
+        # status, val = mem.read(self.dev, gbt_add + 0x100 * 4)
+        self.rmw_phy(num_phy, channel, 0x100, 0x62, 0x22)
+    ### Step 4 new CDR bandwidth setting (not used)
+    ### Step 5
+        # print ">>>> RX_cal_busy Disable"
+        # status, val = mem.read(self.dev, gbt_add + 0x281 * 4)
+        # val = val | 0xdf
+        # mem.write(self.dev, gbt_add + 0x281 * 4, val)
+        # status, val = mem.read(self.dev, gbt_add + 0x281 * 4)
+        # val = val & 0x20
+        # mem.write(self.dev, gbt_add + 0x281 * 4, val)
+        # print ">>>> RX_cal_busy Enable"
+        # print ">>>> TX_cal_busy Disable"
+        # status, val = mem.read(self.dev, gbt_add + 0x281 * 4)
+        # val = val | 0xef
+        # mem.write(self.dev, gbt_add + 0x281 * 4, val)
+        # status, val = mem.read(self.dev, gbt_add + 0x281 * 4)
+        # val = val & 0x10
+        # mem.write(self.dev, gbt_add + 0x281 * 4, val)
+        # print ">>>> TX_cal_busy Enable"
+    # ### Step 6
+        # mem.write(self.dev, gbt_add + 0x000 * 4, 0x01)
+    ### Step 7
+        self.rmw_phy(num_phy, channel, 0x281, 0x30, 0x30)
+        #self.rmw_phy(num_phy, channel, 0x000, 0xFF, 0x01)
+        # print ".Periodically check *cal_busy"
+        failed = True
+        while failed:
+            status, val = mem.read(self.dev, gbt_add + 0x281 * 4)
+            test_bit = val & 0x03
+            if test_bit == 0:
+                failed = False
+                # print ".... Done"
+            else:
+                print ". busy"
+                if time.time() > timeout:
+                    print "********** TIMEOUT GBT" + str(num_phy) + "**********"
+                    break
+        return failed
+
+    def calibrate_phy_all(self):
+        """
+        Recalibrate all the phys.
+
+        """
+        nb_phy = self.get_number_of_links()
+        for num_phy in range(0, nb_phy/6):
+            print ".... Start calibration GBT", num_phy, "channel",
+            for channel in range (0, 6):
+                if self.calibrate_phy(num_phy, channel) == False:
+                    print channel,
+            print
+        print ".... Done"
+
+
+
+    def dump_phy_registers(self, num_phy):
+        """
+        Read the phy register of all channels at address add on register reg.
+
+        Args:
+            num_phy (int): phy number (0 to 8)
+
+        Raises:
+            ValueError:
+                for invalid name.
+
+        """
+        add = self.add_xcvr[num_phy]
+        for reg in (0x200, 0x204, 0x205, 0x210, 0x211, 0x212, 0x213, 0x2E1, 0x2E2, 0x280):
+            print "adresse ", hex(reg), "=",
+            print hex(add + 4 * reg),
+            for channel in range(6):              ## display same register for 6 channels
+                status, val = mem.read(self.dev, add + 4 * reg + channel * 0x1000)
+                print "%#04x" % val,                  ## display 2 characters in hexa
+            print
+
+    def dump_prbs_registers(self, num_phy):
+        """
+        Read the phy register of all channels at address add on register reg.
+
+        Args:
+            num_phy (int): phy number (0 to 8)
+
+        Raises:
+            ValueError:
+                for invalid name.
+
+        """
+        add = self.add_xcvr[num_phy]
+        for reg in (0x007, 0x008, 0x006, 0x110, 0x00B, 0x00C, 0x13F, 0x00A, 0x300):
+            print "adresse %#05x" % reg, "=",
+            print "%#04x" % (add + 4 * reg),
+            for channel in range(6):              ## display same register for 6 channels
+                status, val = mem.read(self.dev, add + 4 * reg + channel * 0x1000)
+                print "%#04x" % val,                  ## display 2 characters in hexa
+            print
+
+    def read_phy_register(self, num_phy, channel, reg):
+        """
+        Read a phy register
+
+        Args:
+            num_phy : phy number (0 to 8)
+            channel : channel number (0 to 5)
+            reg     : register address (0x000 to 0x340)
+
+        Returns
+            val :  read value
+
+        """
+        add = self.add_xcvr[num_phy]
+        status, val = mem.read(self.dev, add + 4 * reg + channel * 0x1000)
+        return val
+
+    def read_pll_register(self, num_phy, reg):
+        """
+        Read a pll register
+
+        Args:
+            num_phy : phy number (0 to 8)
+            reg     : register address (0x000 to 0x340)
+
+        Returns
+            val :  read value
+
+        """
+        add = self.add_pll[num_phy]
+        status, val = mem.read(self.dev, add + 4 * reg)
+        return val
+
+    def write_phy_register(self, num_phy, channel, reg, data):
+        """
+        Write a phy register
+
+        Args:
+            num_phy : phy number (0 to 8)
+            channel : channel number (0 to 5)
+            reg     : register address (0x000 to 0x340)
+            data    : data to write
+
+        Return:
+            Val = value read after write
+
+        """
+        add = self.add_xcvr[num_phy]
+        status = mem.write(self.dev, add + 4 * reg + channel * 0x1000, data)
+        status, val = mem.read(self.dev, add + 4 * reg + channel * 0x1000)
+        #print "new value is %#04x" % val,                  ## display 2 characters in hexa
+        return val
+
+    def write_pll_register(self, num_phy, reg, data):
+        """
+        Write a pll register
+
+        Args:
+            num_phy : phy number (0 to 8) to which the pll is attached
+            reg     : register address (0x000 to 0x340)
+            data    : data to write
+
+        Return:
+            Val = value read after write
+
+        """
+        add = self.add_pll[num_phy]
+        status = mem.write(self.dev, add + 4 * reg, data)
+        status, val = mem.read(self.dev, add + 4 * reg)
+        #print "new value is %#04x" % val,                  ## display 2 characters in hexa
+        return val
+
+    def rmw_phy(self, num_phy, channel, reg, mask, data):
+        """
+        Read modify write a phy register
+
+            Args:
+                num_phy : phy number (0 to 8)
+                channel : channel number (0 to 5)
+                reg     : register address (0x000 to 0x340)
+                mask    : each bit set to 1 is written, others are let in same state
+                data    : data to write
+
+            Return:
+                read_value : read value after write
+
+            """
+        val = self.read_phy_register(num_phy, channel, reg)
+        masked_data = data & mask
+        masked_val = val & ~mask
+        new_data = masked_val | masked_data
+        read_value = self.write_phy_register(num_phy, channel, reg, new_data)
+        #print "rmw of ", hex(data), "with mask ", hex(mask), "in register ", hex(reg), "initial value was ",hex(val),"masked data is" , hex(masked_data),",  new written value is ", hex(new_data)
+        #print "read value is %#04x" % read_value
+        return read_value
+
+    def rmw_pll(self, num_phy, channel, reg, mask, data):
+        """
+        Read modify write a phy register
+
+            Args:
+                num_phy : phy number (0 to 8)
+                channel : channel number (0 to 5)
+                reg     : register address (0x000 to 0x340)
+                mask    : each bit set to 1 is written, others are let in same state
+                data    : data to write
+
+            Return:
+                read_value : read value after write
+
+            """
+        val = self.read_pll_register(num_phy, channel, reg)
+        masked_data = data & mask
+        masked_val = val & ~mask
+        new_data = masked_val | masked_data
+        read_value = self.write_pll_register(num_phy, channel, reg, new_data)
+        #print "rmw of ", hex(data), "with mask ", hex(mask), "in register ", hex(reg), "initial value was ",hex(val),"masked data is" , hex(masked_data),",  new written value is ", hex(new_data)
+        #print "read value is %#04x" % read_value
+        return read_value
+
+    def read_mask(self, num_phy, channel, reg, mask):
+        """
+        Read a phy register with a mask
+
+            Args:
+                num_phy : phy number (0 to 8)
+                channel : channel number (0 to 5)
+                reg     : register address (0x000 to 0x340)
+                mask    : each bit set to 1 is read, other are ignored
+
+            Return:
+                read_value : read value with mask
+
+            """
+        val = self.read_phy_register(num_phy, channel, reg)
+        masked_data = val & mask
+        while mask & 1 == 0 :
+            masked_data = masked_data >> 1
+            mask = mask >> 1
+        return hex(masked_data)
+
+    def get_status(self, num_phy, channel):
+        """
+        Get most interesting status values for a phy
+
+            Args:
+                num_phy : phy number (0 to 8)
+                channel : channel number (0 to 5)
+
+        """
+        print "num_phy = ", num_phy, ", channel =", channel
+        print "test 16a should be 5", self.read_mask(num_phy, channel, 0x16a, 0xf0)
+        print "rx_is_lockedtodata =", self.read_mask(num_phy, channel, 0x280, 0x1)
+        print "rx_is_lockedtoref =", self.read_mask(num_phy, channel, 0x280, 0x2)
+        print "tx_cal_busy =", self.read_mask(num_phy, channel, 0x281, 0x1)
+        print "rx_cal_busy =", self.read_mask(num_phy, channel, 0x281, 0x2)
+        print "vod =", self.read_mask(num_phy, channel, 0x109, 0x1f)
+        return
+
+
+    def get_number_of_links(self):
+        """
+        Reads the number of links implemented in the firmware
+
+        Returns:
+            nb_links : number of links
+        """
+        status, nb_links = mem.read(self.dev, 0x30000)
+        return nb_links & 0xFF
+
+    def set_serial_loopback_all(self, loopback) :
+        """
+        Set serial_loopback for all detected links
+
+        Args:
+            loopback (int) : 1 to set internal loopback, 0 to set it off
+        """
+        nb_phy = self.get_number_of_links()
+        for num_phy in range(0, nb_phy/6):
+            add = self.add_xcvr[num_phy]
+            for channel in range (0, 6):
+                if loopback == 1:
+                    status = mem.write(self.dev, add + 4 * 0x2E1 + channel * 0x1000, 0x01)
+                else:
+                    status = mem.write(self.dev, add + 4 * 0x2E1 + channel * 0x1000, 0x00)
+
+
+    def start_check_serial_loop(self, num_phy, channel):
+        """
+        Launch a prbs in loop back mode and check errors
+
+        Args:
+            num_phy (int) : phy number (0 to 8)
+            channel (int) : channel number (0 to 5)
+            loopback (int) : 1 to run the test in internal loopback, 0 to run it in external loopback
+
+        """
+        # set prbs31 generator pattern
+        self.rmw_phy(num_phy, channel, 0x07, 0xF0, 0x00)
+        self.rmw_phy(num_phy, channel, 0x08, 0x10, 0x10)
+
+        # set prbs31 verifier pattern
+        self.rmw_phy(num_phy, channel, 0x0B, 0xF0, 0x00)
+        self.rmw_phy(num_phy, channel, 0x0C, 0x01, 0x01)
+
+        # Set PRBS Generator
+        # PMA data output is prbs pattern
+        self.rmw_phy(num_phy, channel,0x06, 0x0F, 0x04)   # enable PRBS9 in 64 bits mode, tx pma data sel = prbs pattern
+        # TX PCS PRBS Gen clock enable set to 1
+        self.rmw_phy(num_phy, channel,0x06, 0x40,0x40)    # enable Tx PRBS generator clock
+        # set serializer to 64-bit
+        self.rmw_phy(num_phy, channel, 0x110, 0x07, 0x03) # set mode = 64 bits
+
+        # set Xn to not bounded"
+        self.rmw_phy(num_phy, channel, 0x111, 0x1F, 0x18) # set Xn to "not bonded"
+
+        # Set PRBS Checker
+        # Route PRBS to data path:
+        # set rx_prbs_mode to 10g mode
+        self.rmw_phy(num_phy, channel, 0xB, 0x02, 0x02)   # rx PRBS mode = 10G
+        # rx_prbs_force_signal_ok
+        self.rmw_phy(num_phy, channel, 0xC, 0x02, 0x02)   # force signal_ok to PRBS
+        # prbs9_dwidth set to prbs9_64b
+        self.rmw_phy(num_phy, channel, 0xC, 0x08,0x00)    # enable PRBS9 in 64 bits mode
+        # Set deser_factor to 64-bit
+        self.rmw_phy(num_phy, channel, 0x13F, 0x0F, 0x0E) # set deserialization factor to 64 bits
+
+        # TX PCS PRBS Gen clock enable set to on
+        self.rmw_phy(num_phy, channel, 0xA, 0x80, 0x80)
+
+        # Counter enable (enables both error and bit counters)
+        self.rmw_phy(num_phy, channel, 0x300, 0x01, 0x01)
+
+    def start_check_serial_loop_all(self, loopback):
+        """
+        Launch a prbs in loop back mode and check errors
+
+        Args:
+            loopback (int) : 1 to run the test in internal loopback, 0 to run it in external loopback
+
+        """
+        #get number of links
+        nb_links = self.get_number_of_links()
+        print "number of links is", nb_links
+        # set loopback mode
+        self.set_serial_loopback_all(loopback)
+        for num_phy in range(0, nb_links/6):
+            for num_channel in range(0,6):
+                self.start_check_serial_loop(num_phy, num_channel)
+
+    def check_serial_loopback(self, num_phy, channel):
+        """
+        Check if the serial loop back mode is set
+
+        Args:
+            num_phy (int) : phy number (0 to 8)
+            channel (int) : channel number (0 to 5)
+
+        Returns:
+            1 if true
+            0 if false
+        """
+        status = self.read_mask(num_phy, channel, 0x2E1, 0x01)
+        return status
+
+    def check_status(self, num_phy, channel):
+        """
+        Check status of prbs registers
+
+        Args:
+            num_phy : phy number (0 to 8)
+            channel : channel number (0 to 5)
+
+        """
+        print "reg 0x007: ", hex(self.read_phy_register(0, 0, 0x07))
+        print "reg 0x008: ", hex(self.read_phy_register(0, 0, 0x08))
+
+        # set prbs31 verifier pattern
+        print "reg 0x00B: ", hex(self.read_phy_register(0, 0, 0x0B))
+        print "reg 0x00C: ", hex(self.read_phy_register(0, 0, 0x0C))
+
+        # SET GENERATOR
+        # PMA data output is prbs pattern
+        print "reg 0x006: ", hex(self.read_phy_register(0, 0, 0x06))
+        # TX PCS PRBS Gen clock enable set to 1
+        print "reg 0x006: ", hex(self.read_phy_register(0, 0, 0x06))
+        # set serializer to 64-bit
+        print "reg 0x110: ", hex(self.read_phy_register(0, 0, 0x110))
+
+        # Xn not bounded
+        print "reg 0x111: ", hex(self.read_phy_register(0, 0, 0x111))
+
+        # Route PRBS to data path:
+        # set rx_prbs_mode to 10g mode
+        print "reg 0x00B: ", hex(self.read_phy_register(0, 0, 0xB))
+        # rx_prbs_force_signal_ok
+        print "reg 0x00C: ", hex(self.read_phy_register(0, 0, 0xC))
+        # prbs9_dwidth set to prbs9_64b
+        print "reg 0x00C: ", hex(self.read_phy_register(0, 0, 0xC))
+        # Set deser_factor to 64-bit
+        print "reg 0x13F: ", hex(self.read_phy_register(0, 0, 0x13F))
+
+        # TX PCS PRBS Gen clock enable set to on
+        print "reg 0x00A: ", hex(self.read_phy_register(0, 0, 0xA))
+
+        # Counter enable (enables both error and bit counters)
+        print "reg 0x300: ", hex(self.read_phy_register(0, 0, 0x300))
+
+    def check_prbs_ready(self, num_phy, channel):
+        """
+        Check if the prbs checker has had sufficient time to lock to the incoming pattern
+
+        Args:
+            num_phy (int) : phy number (0 to 8)
+            channel (int) : channel number (0 to 5)
+
+        Returns:
+            1 if true
+            0 if false
+        """
+        status = self.read_phy_register(num_phy, channel, 0x300) >> 3 & 0x0001
+        return status
+
+    def check_prbs_ready_all(self):
+        """
+        Check if all the prbs checkers had had sufficient time to lock to the incoming pattern
+
+        Returns:
+            1 if true
+            0 if false
+        """
+        global_status = 1
+        nb_phy = self.get_number_of_links()
+        while global_status == 0:
+            global_status = 1
+            for num_phy in range(0, nb_phy / 6):
+                for channel in range(0, 6):
+                    status = self.read_phy_register(num_phy, channel, 0x300) >> 3 & 0x0001
+                    glogal_status = global_status and status
+                    print num_phy, channel, status, global_status
+        return global_status
+
+    def reset_prbs_counters(self, num_phy, channel):
+        """
+        Reset the prbs counters
+
+        Args:
+            num_phy (int) : phy number (0 to 8)
+            channel (int) : channel number (0 to 5)
+
+        """
+        self.rmw_phy(num_phy, channel, 0x300, 0x02, 0x02)
+        self.rmw_phy(num_phy, channel, 0x300, 0x02, 0x00)
+
+    def reset_prbs_counters_all(self):
+        """
+        Reset all the prbs counters
+        """
+        nb_phy = self.get_number_of_links()
+        for num_phy in range(0, nb_phy / 6):
+            for channel in range(0, 6):
+                self.rmw_phy(num_phy, channel, 0x300, 0x02, 0x02)
+                self.rmw_phy(num_phy, channel, 0x300, 0x02, 0x00)
+
+    def snapshot_counters(self, num_phy, channel):
+        """
+        Makes a snapshot of the prbs counters
+
+        Args:
+            num_phy (int) : phy number (0 to 8)
+            channel (int) : channel number (0 to 5)
+
+
+        """
+        print "Takes a snapshot of registers", hex(self.rmw_phy(num_phy, channel, 0x300, 0x04, 0x04)), hex(self.rmw_phy(num_phy, channel, 0x300, 0x04, 0x00))
+
+    def snapshot_counters_all(self):
+        """
+        Makes a snapshot of all the prbs counters
+
+        """
+        print "Takes a snapshot of prbs counters"
+        nb_phy = self.get_number_of_links()
+        for num_phy in range(0, nb_phy / 6):
+            for channel in range(0, 6):
+                self.rmw_phy(num_phy, channel, 0x300, 0x04, 0x04)
+                self.rmw_phy(num_phy, channel, 0x300, 0x04, 0x00)
+
+
+    def read_ber(self, num_phy, channel):
+        """
+        Calculate the BER
+
+        Args:
+            num_phy (int) : phy number (0 to 8)
+            channel (int) : channel number (0 to 5)
+        Returns:
+            Nb_bits (int) : number of bits transmitted
+            Nb_errors (int) : number of errors detected
+
+            """
+        Nb_errors = self.read_phy_register(num_phy, channel, 0x301) + \
+                  self.read_phy_register(num_phy, channel, 0x302) * 256 + \
+                  self.read_phy_register(num_phy, channel, 0x303) * 256 * 256 + \
+                  self.read_phy_register(num_phy, channel, 0x304) * 256 * 256 * 256 + \
+                  self.read_phy_register(num_phy, channel, 0x305) * 256 * 256 * 256 * 256 + \
+                  self.read_phy_register(num_phy, channel, 0x306) * 256 * 256 * 256 * 256 * 256 + \
+                  self.read_phy_register(num_phy, channel, 0x307) * 256 * 256 * 256 * 256 * 256 * 256
+        Nb_words   = self.read_phy_register(num_phy, channel, 0x30D) + \
+                    self.read_phy_register(num_phy, channel, 0x30E) * 256 + \
+                    self.read_phy_register(num_phy, channel, 0x30F) * 256 * 256 + \
+                    self.read_phy_register(num_phy, channel, 0x310) * 256 * 256 * 256 + \
+                    self.read_phy_register(num_phy, channel, 0x311) * 256 * 256 * 256 * 256 + \
+                    self.read_phy_register(num_phy, channel, 0x312) * 256 * 256 * 256 * 256 * 256 + \
+                    self.read_phy_register(num_phy, channel, 0x313) * 256 * 256 * 256 * 256 * 256 * 256
+        tcs_pma_width = 20
+        Nb_bits = tcs_pma_width * Nb_words
+        return  Nb_bits, Nb_errors
+
+    def read_ber_all(self):
+        """
+        Calculate the BER for all channels
+
+        Returns:
+            list_ber{{Nb_bits (int) : Nb_errors (int)}
+            where Nb_bits = Number of transmitted bits
+            Nb_errors = Number of errors detected
+            """
+        list_nb_bits = []
+        list_nb_errors = []
+        nb_phy = self.get_number_of_links()
+        for num_phy in range(0, nb_phy / 6):
+            for channel in range(0, 6):
+                Nb_bits, Nb_errors = self.read_ber(num_phy, channel)
+                list_nb_bits.append(Nb_bits)
+                list_nb_errors.append(Nb_errors)
+        list_ber = zip(list_nb_bits, list_nb_errors)
+        # print list_ber
+        return list_ber
+
+
+    def tx_digital_reset(self, num_phy, channel, val):
+        """
+        Digital reset of the transmitter
+
+        Args:
+            num_phy (int): phy number (0 to 8)
+            channel (int): channel number (0 to 5)
+            val (int) : 1 to assert reset, 0 to clear reset
+
+        """
+        if val == 1:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF8, 0xF8)
+        else:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF8, 0xF0)
+
+
+    def rx_digital_reset(self, num_phy, channel, val):
+        """
+        Digital reset of the receiver
+
+        Args:
+            num_phy : phy number (0 to 8)
+            channel : channel number (0 to 5)
+            val : 1 to assert reset, 0 to clear reset
+
+        """
+        if val == 1:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF2, 0xF2)
+        else:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF2, 0xF0)
+
+
+    def tx_analog_reset(self, num_phy, channel, val):
+        """
+        Digital reset of the transmitter
+
+        Args:
+            num_phy : phy number (0 to 8)
+            channel : channel number (0 to 5)
+            val : 1 to assert reset, 0 to clear reset
+
+        """
+        if val == 1:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF4, 0xF4)
+        else:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF4, 0xF0)
+
+
+    def rx_analog_reset(self, num_phy, channel, val):
+        """
+        Digital reset of the receiver
+
+        Args:
+            num_phy : phy number (0 to 8)
+            channel : channel number (0 to 5)
+            val : 1 to assert reset, 0 to clear reset
+
+            """
+        if val == 1:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF1, 0xF1)
+        else:
+            self.rmw_phy(num_phy, channel, 0x2E2, 0xF1, 0xF0)
+
+
+
+
+def main():
+
+   fpga = Arria10(0)
+   trans = xcvr(0)
+   for phy in range(0, 8) :
+       trans.dump_phy_registers(phy)
+       print "============================================================================================="
+
+   fpga.clear_reset_gbt()
+   trans.calibrate_pll(0)
+   trans.calibrate_phy(0, 0)
+   time.sleep(0.1)
+   loopback = 1
+   trans.set_serial_loopback_all(loopback)
+   trans.start_check_serial_loop(0, 0)
+
+   trans.check_status(0,0)
+   print "counter status =", hex(trans.read_phy_register(0, 0, 0x300))
+   wait = 0
+   while wait == 0:
+       wait = trans.check_prbs_ready(0, 0)
+       print wait
+       time.sleep(1)
+   print "prbs done = "
+   trans.reset_prbs_counters(0, 0)
+   while 1:
+       trans. snapshot_counters(0, 0)
+       Nb_bits, Nb_errors = trans.read_ber(0,0)
+       print "Number of transmitted bits = %.4g" % Nb_bits, ", Nb of errors = %.4g" % Nb_errors, ", BER =",
+       if Nb_bits != 0:
+           print " %.4g" % (1. * Nb_errors/Nb_bits)
+       else:
+           print
+       time.sleep(1)
+
+def main_all(device):
+
+   # Identifying the card
+   import addresses_comp as const
+   flash = EepromAT24C(device, const.EEPROM_FPGA_BUS, const.EEPROM_U64_ADD)
+   print flash.read_identification()
+
+   # Program PLLs
+   devices = \
+       {1: "SI5345_U23",
+        2: "SI5345_U48",
+        3: "SI5344_U54"
+        }
+   ports = \
+       {1: [0, 1, 2, 3],
+        2: [0, 1, 3, 4, 8],
+        3: [0, 1]
+        }
+   files = \
+       {1: "../data/Si5345-RevD-JIT1_40_jitter1_input0_40MHz-Registers.txt",
+        2: "../data/Si5345-RevD-JIT2_40_jitter2_input0_40MHz-Registers.txt",
+        3: "../data/Si5344-RevD-TFC_40-Registers.txt"
+        }
+
+   dev = device  # Creates a list of objects with the 3 PLLs
+   add = 0x68
+   pll = [Si534x(dev, bus, add) for bus in devices.keys()]
+
+
+   for i in devices.keys():  # Tests the 3 PLLs
+       print "=========== Programming external PLL ", devices[i], "============"
+       # pll[i - 1].test(files[i], devices[i], ports[i])  # i-1 because list index starts with 0
+       pll[i - 1].program_with_file(files[i], devices[i])  # i-1 because list index starts with 0
+       print "..... wait to stabilize"
+       time.sleep(7)
+       pll[i-1].clear_lol_flg_bit()
+       status, val = pll[i - 1].read_loss_of_lock()  # i-1 because list index starts with 0
+       print devices[i],
+       if val == True:
+           print "Loss of lock\n"
+       else:
+           print "Locked\n"
+           
+           
+   print "\n=========== Checking PLLs ============"
+   print"... Loss of lock sticky bit = ", 
+   for i in devices.keys():  # Check the stickybit for the 3 PPLLs
+       (status, loss_of_lock_flg) = pll[i-1].read_loss_of_lock_flg()
+       print loss_of_lock_flg,
+   print
+   time.sleep(2)
+
+   # Calibrate all PLLs
+   print "\n=========== Calibrating fPLLs ============"
+   trans = xcvr(device)
+   trans.calibrate_pll_all()
+
+   # Calibrate all PHYs
+   print "\n=========== Calibrating PHYs ============"
+   trans.calibrate_phy_all()
+
+   # Clear reset to transceivers
+   print "\n=========== Clearing xcvr reset ============"
+   fpga = Arria10(device)
+   fpga.clear_reset_gbt()
+   print ".... Done"
+
+   # Set internal loopback
+   print "\n=========== Setting loopback mode ============"
+   print ".... Internal loopback"
+   loopback = 1
+
+
+   # Start test
+   print "\n=========== Starting PRBS test ============"
+   trans.start_check_serial_loop_all(loopback)
+
+   # Check if all the prbs checkers had had sufficient time to lock to the incoming pattern
+   print "\n=========== PRBS test ============"
+   trans.check_prbs_ready_all()
+   print ".... PRBS checkers locked"
+
+   # Reset error counters
+   print ".... Reset PRBS counters"
+   trans.reset_prbs_counters_all()
+
+   print ".... Start test"
+   elapsed_time = 0
+   while 1:
+       elapsed_time += 1
+       print "transmitted bits = ", '%.2E' % Decimal(elapsed_time * 4800000000)
+       print"Loss of lock sticky bit = ", 
+       for i in devices.keys():
+           (status, loss_of_lock_flg) = pll[i-1].read_loss_of_lock_flg()
+           print loss_of_lock_flg,
+       print
+       trans.snapshot_counters_all()
+       channel = 0
+       for link in trans.read_ber_all():
+          if link[1] == 0:
+             print "Channel", '{:>2}'.format(channel), \
+                 ", bits = ", link[0], \
+                 ", errors =", '{:>6}'.format(link[1]), \
+                 ", BER = ", '%.2E' % (Decimal(1)/Decimal((elapsed_time * 4800000000)))
+          else:
+             print "Channel", '{:>2}'.format(channel), \
+                 ", bits = ", link[0], \
+                 ", errors =", '{:>6}'.format(link[1]), \
+                 ", >>>>>>>>>>>>>>>>>>>>>>>>> BER = ", '%.2E' % (Decimal(link[1])/Decimal((elapsed_time * 4800000000)))
+          channel += 1
+       time.sleep(1)
+
+
+if __name__ == "__main__":
+    if (len(sys.argv) > 1):
+        main_all(int(sys.argv[1]))
+    else :
+        main_all(0)
-- 
GitLab