#! /usr/bin/python

import os
import sys
import time
import isi.hw.vitutil as vitutil

syncDelay = 5
checkDelay = 5

def bist(unit, phy):
    # 0. Make sure the PHY isn't in use for something else
    val = vitutil.phyRead(unit, phy, 0x24)
    if val & 0x03:
        print "Bad idea.  That PHY is in use!"
        return

    # 1. disablephy n (XXX)

    # 2. Clear BIST checker and initialize BIST generator.
    print "Clear and disable BIST checker"
    vitutil.write(unit, vitutil.BISTBASE + 0x14, 0x00000001)
    print "Clear BIST generator 1"
    vitutil.write(unit, vitutil.BISTBASE + 0x04, 0x00000000)
    print "Configure generator 1 for desired pattern output"
    vitutil.write(unit, vitutil.BISTBASE + 0x04, 0x04000009)

    # 3. Enable and configure the PHY.
    print "Force PHY reset"
    vitutil.phyWrite(unit, phy, 0x10, 0x00000000)
    print "Set PHY config 1"
    vitutil.phyWrite(unit, phy, 0x00, 0x00002201)
    print "Set PHY config 2"
    vitutil.phyWrite(unit, phy, 0x04, 0x00000000)
    print "Set PHY config 3"
    vitutil.phyWrite(unit, phy, 0x08, 0x00000000)
    print "Set PHY rate control"
    vitutil.phyWrite(unit, phy, 0x14, 0x99990059L)
    print "Set PHY test control"
    # XXX Doc says 0x7031, but I added 0x100 for serial loopback
    vitutil.phyWrite(unit, phy, 0x7c, 0x00007131)

    # 4. Configure the BIST checker and enable the PHY.
    print "Reset BIST checker"
    vitutil.write(unit, vitutil.BISTBASE + 0x14, 0x00000000)
    print "Force PCM connection to PHY"
    vitutil.pcmWrite(unit, phy, 0x40, 0x00000001)
    print "Connect PHY RX to error detector"
    vitutil.write(unit, vitutil.ECRBASE + 0xd8, 0x00000000 + phy)
    print "Bypass OOB and enable PHY"
    vitutil.phyWrite(unit, phy, 0x10, 0x00000003)
    print "Configure error detector for expected pattern input"
    vitutil.write(unit, vitutil.BISTBASE + 0x14, 0x00000013)

    # 5. Wait and then reset the error counter.
    print "Wait %d seconds for some clock cycles to pass" % syncDelay
    time.sleep(syncDelay)
    print "Reset the error detector"
    vitutil.write(unit, vitutil.BISTBASE + 0x14, 0x00000013)

    # 6. Wait and then check the error counter and status.
    print "Wait %d seconds for some clock cycles to pass" % checkDelay
    time.sleep(checkDelay)
    print "Read checker config"
    val = vitutil.read(unit, vitutil.BISTBASE + 0x14)
    print "*** Checker config = 0x%08x, expected = 0x00000812 ***" % val

    print "Read checker counters"
    nbad = vitutil.read(unit, vitutil.BISTBASE + 0x18)
    ngood = vitutil.read(unit, vitutil.BISTBASE + 0x20)
    print "*** Checker error = %d, valid = %d ***" % (nbad, ngood)
    nbad = vitutil.read(unit, vitutil.BISTBASE + 0x18)
    ngood = vitutil.read(unit, vitutil.BISTBASE + 0x20)
    print "*** Checker error = %d, valid = %d ***" % (nbad, ngood)
    nbad = vitutil.read(unit, vitutil.BISTBASE + 0x18)
    ngood = vitutil.read(unit, vitutil.BISTBASE + 0x20)
    print "*** Checker error = %d, valid = %d ***" % (nbad, ngood)

    print "Disable checker and clear error counter"
    vitutil.write(unit, vitutil.BISTBASE + 0x14, 0x00000001, 0x0000003f)
    val = vitutil.read(unit, vitutil.BISTBASE + 0x18)
    print "*** Checker error counter = 0x%08x, expected = 0x00000000 ***" % val

    print "Unforce connection to PHY"
    vitutil.pcmWrite(unit, phy, 0x40, 0x00000000)
    print "Disable serial loopback"
    vitutil.phyWrite(unit, phy, 0x7c, 0x00000000)
    print "Force PHY reset"
    vitutil.phyWrite(unit, phy, 0x10, 0x00000000)

def main(argv = None):
    if argv is None:
        argv = sys.argv
    if len(argv) != 3:
        print >>sys.stderr, "usage: %s unit phy" % os.path.basename(argv[0])
        return 2
    unit = argv[1]
    phy = int(argv[2], 0)
    bist(unit, phy)
    return 0

if __name__ == "__main__":
    sys.exit(main())
