Dick Hollenbeck <dick@softplc.com> SVF to XSVF converter and the XSVF dumper take #2
authoroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 7 Jan 2009 14:55:52 +0000 (14:55 +0000)
committeroharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Wed, 7 Jan 2009 14:55:52 +0000 (14:55 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@1304 b42882b7-edfa-0310-969c-e2dbd0fdcd60

tools/xsvf_tools/svf2xsvf.py
tools/xsvf_tools/xsvfdump.py

index aeff587ab85003c0863a188a01678872224b1d1f..20080db3049e1c04efd1d779e1ec38f32752ecc5 100644 (file)
-#!/usr/bin/python3.0\r
-\r
-# Copyright 2008, SoftPLC Corporation  http://softplc.com\r
-# Dick Hollenbeck dick@softplc.com\r
-\r
-\r
-# This program is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU General Public License\r
-# as published by the Free Software Foundation; either version 2\r
-# of the License, or (at your option) any later version.\r
-#\r
-# This program is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-# GNU General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU General Public License\r
-# along with this program; if not, you may find one here:\r
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\r
-# or you may search the http://www.gnu.org website for the version 2 license,\r
-# or you may write to the Free Software Foundation, Inc.,\r
-# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
-\r
-\r
-# A python program to convert an SVF file to an XSVF file.  There is an\r
-# option to include comments containing the source file line number from the origin\r
-# SVF file before each outputted XSVF statement.\r
-#\r
-# We deviate from the XSVF spec in that we introduce a new command called\r
-# XWAITSTATE which directly flows from the SVF RUNTEST command.  Unfortunately\r
-# XRUNSTATE was ill conceived and is not used here.  We also add support for the\r
-# three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR.  The xsvf file\r
-# generated from this program is suitable for use with the xsvf player in\r
-# OpenOCD with my modifications to xsvf.c.\r
-#\r
-# This program is written for python 3.0, and it is not easy to change this\r
-# back to 2.x.  You may find it easier to use python 3.x even if that means\r
-# building it.\r
-\r
-\r
-import re\r
-import sys\r
-import struct\r
-\r
-\r
-# There are both ---<Lexer>--- and ---<Parser>--- sections to this program\r
-\r
-\r
-if len( sys.argv ) < 3:\r
-    print("usage %s <svf_filename> <xsvf_filename>" % sys.argv[0])\r
-    exit(1)\r
-\r
-\r
-inputFilename = sys.argv[1]\r
-outputFilename = sys.argv[2]\r
-\r
-doCOMMENTs = True       # Save XCOMMENTs in the output xsvf file\r
-#doCOMMENTs = False       # Save XCOMMENTs in the output xsvf file\r
-\r
-xrepeat = 0             # argument to XREPEAT, gives retry count for masked compares\r
-\r
-\r
-#-----< Lexer >---------------------------------------------------------------\r
-\r
-StateBin = (RESET,IDLE,\r
-    DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE,\r
-    IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16)\r
-\r
-# Any integer index into this tuple will be equal to its corresponding StateBin value\r
-StateTxt = ("RESET","IDLE",\r
-    "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE",\r
-    "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE")\r
-\r
-\r
-(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO,\r
-    XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC,\r
-    XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE,LCOUNT,LDELAY,LSDR) = range(28)\r
-\r
-#Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back\r
-# and check a completion status, essentially waiting on a part until it signals that it is done.\r
-# For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST)\r
-# and exit loop when LSDR compares match.\r
-"""\r
-LCOUNT 25;\r
-! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC.\r
-LDELAY DRPAUSE 5 TCK   1.00E-003 SEC;\r
-! Test for the completed status. Match means pass.\r
-! Loop back to LDELAY line if not match and loop count less than 25.\r
-LSDR  1 TDI  (0)\r
-        TDO  (1);\r
-"""\r
-\r
-LineNumber = 1\r
-\r
-def s_ident(scanner, token): return ("ident", token.upper(), LineNumber)\r
-\r
-def s_hex(scanner, token):\r
-    global LineNumber\r
-    LineNumber = LineNumber + token.count('\n')\r
-    token = ''.join(token.split())\r
-    return ("hex", token[1:-1], LineNumber)\r
-\r
-def s_int(scanner, token): return ("int", int(token), LineNumber)\r
-def s_float(scanner, token): return ("float", float(token), LineNumber)\r
-#def s_comment(scanner, token): return ("comment", token, LineNumber)\r
-def s_semicolon(scanner, token): return ("semi", token, LineNumber)\r
-\r
-def s_nl(scanner,token):\r
-    global LineNumber\r
-    LineNumber = LineNumber + 1\r
-    #print( 'LineNumber=', LineNumber, file=sys.stderr )\r
-    return None\r
-\r
-#2.00E-002\r
-\r
-scanner = re.Scanner([\r
-    (r"[a-zA-Z]\w*", s_ident),\r
-#    (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float),\r
-    (r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float),\r
-    (r"\d+", s_int),\r
-    (r"\(([0-9a-fA-F]|\s)*\)", s_hex),\r
-    (r"(!|//).*$", None),\r
-    (r";", s_semicolon),\r
-    (r"\n",s_nl),\r
-    (r"\s*", None),\r
-    ],\r
-    re.MULTILINE\r
-    )\r
-\r
-# read all svf file input into string "input"\r
-input = open( sys.argv[1] ).read()\r
-\r
-# Lexer:\r
-# create a list of tuples containing (tokenType, tokenValue, LineNumber)\r
-tokens = scanner.scan( input )[0]\r
-\r
-input = None    # allow gc to reclaim memory holding file\r
-\r
-#for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue )\r
-\r
-\r
-#-----<parser>-----------------------------------------------------------------\r
-\r
-tokVal = tokType = tokLn = None\r
-\r
-tup = iter( tokens )\r
-\r
-def nextTok():\r
-    """\r
-    Function to read the next token from tup into tokType, tokVal, tokLn (linenumber)\r
-    which are globals.\r
-    """\r
-    global tokType, tokVal, tokLn, tup\r
-    tokType, tokVal, tokLn = tup.__next__()\r
-\r
-\r
-class ParseError(Exception):\r
-    """A class to hold a parsing error message"""\r
-    def __init__(self, linenumber, token, message):\r
-        self.linenumber = linenumber\r
-        self.token = token\r
-        self.message = message\r
-    def __str__(self):\r
-        global inputFilename\r
-        return "Error in file \'%s\' at line %d near token %s\n %s" % (\r
-                   inputFilename, self.linenumber, repr(self.token), self.message)\r
-\r
-\r
-class MASKSET(object):\r
-    """\r
-    Class MASKSET holds a set of bit vectors, all of which are related, will all\r
-    have the same length, and are associated with one of the seven shiftOps:\r
-    HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a\r
-    size.\r
-    """\r
-    def __init__(self, name):\r
-        self.empty()\r
-        self.name = name\r
-\r
-    def empty(self):\r
-        self.mask = bytearray()\r
-        self.smask = bytearray()\r
-        self.tdi = bytearray()\r
-        self.tdo = bytearray()\r
-        self.size = 0\r
-\r
-    def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ):\r
-        """\r
-        Set all the lengths equal in the event some of the masks were\r
-        not seen as part of the last change set.\r
-        """\r
-        if self.size == newSize:\r
-            return\r
-\r
-        if newSize == 0:\r
-            self.empty()\r
-            return\r
-\r
-        # If an SIR was given without a MASK(), then use a mask of all zeros.\r
-        # this is not consistent with the SVF spec, but it makes sense because\r
-        # it would be odd to be testing an instruction register read out of a\r
-        # tap without giving a mask for it.  Also, lattice seems to agree and is\r
-        # generating SVF files that comply with this philosophy.\r
-        if self.name == 'SIR' and not sawMASK:\r
-            self.mask = bytearray( newSize )\r
-\r
-        if newSize != len(self.mask):\r
-            self.mask = bytearray( newSize )\r
-            if self.name == 'SDR':  # leave mask for HIR,HDR,TIR,TDR,SIR zeros\r
-                for i in range( newSize ):\r
-                    self.mask[i] = 1\r
-\r
-        if newSize != len(self.tdo):\r
-            self.tdo = bytearray( newSize )\r
-\r
-        if newSize != len(self.tdi):\r
-            self.tdi = bytearray( newSize )\r
-\r
-        if newSize != len(self.smask):\r
-            self.smask = bytearray( newSize )\r
-\r
-        self.size = newSize\r
-#-----</MASKSET>-----\r
-\r
-\r
-def makeBitArray( hexString, bitCount ):\r
-    """\r
-    Converts a packed sequence of hex ascii characters into a bytearray where\r
-    each element in the array holds exactly one bit. Only "bitCount" bits are\r
-    scanned and these must be the least significant bits in the hex number. That\r
-    is, it is legal to have some unused bits in the must significant hex nibble\r
-    of the input "hexString". The string is scanned starting from the backend,\r
-    then just before returning we reverse the array. This way the append()\r
-    method can be used, which I assume is faster than an insert.\r
-    """\r
-    global tokLn\r
-    a = bytearray()\r
-    length = bitCount\r
-    hexString = list(hexString)\r
-    hexString.reverse()\r
-    #print(hexString)\r
-    for c in hexString:\r
-        if length <= 0:\r
-            break;\r
-        c = int(c, 16)\r
-        for mask in [1,2,4,8]:\r
-            if length <= 0:\r
-                break;\r
-            length = length - 1\r
-            a.append( (c & mask) != 0 )\r
-    if length > 0:\r
-        raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount )\r
-    a.reverse()\r
-    #print(a)\r
-    return a\r
-\r
-\r
-def makeXSVFbytes( bitarray ):\r
-    """\r
-    Make a bytearray which is contains the XSVF bits which will be written\r
-    directly to disk.  The number of bytes needed is calculated from the size\r
-    of the argument bitarray.\r
-    """\r
-    bitCount = len(bitarray)\r
-    byteCount = (bitCount+7)//8\r
-    ba = bytearray( byteCount )\r
-    firstBit = (bitCount % 8) - 1\r
-    if firstBit == -1:\r
-        firstBit = 7\r
-    bitNdx = 0\r
-    for byteNdx in range(byteCount):\r
-        mask = 1<<firstBit\r
-        byte = 0\r
-        while mask:\r
-            if bitarray[bitNdx]:\r
-                byte |= mask;\r
-            mask = mask >> 1\r
-            bitNdx = bitNdx + 1\r
-        ba[byteNdx] = byte\r
-        firstBit = 7\r
-    return ba\r
-\r
-\r
-def writeComment( outputFile, shiftOp_linenum, shiftOp ):\r
-    """\r
-    Write an XCOMMENT record to outputFile\r
-    """\r
-    comment = "%s @%d\0" % (shiftOp, shiftOp_linenum)   # \0 is terminating nul\r
-    ba = bytearray(1)\r
-    ba[0] = XCOMMENT\r
-    ba += comment.encode()\r
-    outputFile.write( ba )\r
-\r
-\r
-def combineBitVectors( trailer, meat, header ):\r
-    """\r
-    Combine the 3 bit vectors comprizing a transmission.  Since the least\r
-    significant bits are sent first, the header is put onto the list last so\r
-    they are sent first from that least significant position.\r
-    """\r
-    ret = bytearray()\r
-    ret.extend( trailer )\r
-    ret.extend( meat )\r
-    ret.extend( header )\r
-    return ret\r
-\r
-\r
-def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ):\r
-    """\r
-    Write the output for the SVF RUNTEST command.\r
-    run_count - the number of clocks\r
-    min_time - the number of seconds\r
-    tokenTxt - either RUNTEST or LDELAY\r
-    """\r
-    # convert from secs to usecs\r
-    min_time = int( min_time * 1000000)\r
-\r
-    # the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command.  Check the SVF spec, then\r
-    # read the XSVF command.   They are not the same.  Use an XSVF XWAITSTATE to\r
-    # implement the required behavior of the SVF RUNTEST command.\r
-    if doCOMMENTs:\r
-        writeComment( output, tokLn, tokenTxt )\r
-\r
-    if tokenTxt == 'RUNTEST':\r
-        obuf = bytearray(11)\r
-        obuf[0] = XWAITSTATE\r
-        obuf[1] = run_state\r
-        obuf[2] = end_state\r
-        struct.pack_into(">i", obuf, 3, run_count )  # big endian 4 byte int to obuf\r
-        struct.pack_into(">i", obuf, 7, min_time )   # big endian 4 byte int to obuf\r
-        outputFile.write( obuf )\r
-    else:   # == 'LDELAY'\r
-        obuf = bytearray(10)\r
-        obuf[0] = LDELAY\r
-        obuf[1] = run_state\r
-        # LDELAY has no end_state\r
-        struct.pack_into(">i", obuf, 2, run_count )  # big endian 4 byte int to obuf\r
-        struct.pack_into(">i", obuf, 6, min_time )   # big endian 4 byte int to obuf\r
-        outputFile.write( obuf )\r
-\r
-\r
-output = open( outputFilename, mode='wb' )\r
-\r
-hir = MASKSET('HIR')\r
-hdr = MASKSET('HDR')\r
-tir = MASKSET('TIR')\r
-tdr = MASKSET('TDR')\r
-sir = MASKSET('SIR')\r
-sdr = MASKSET('SDR')\r
-\r
-\r
-expecting_eof = True\r
-\r
-\r
-# one of the commands that take the shiftParts after the length, the parse\r
-# template for all of these commands is identical\r
-shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR')\r
-\r
-# the order must correspond to shiftOps, this holds the MASKSETS.  'LSDR' shares sdr with 'SDR'\r
-shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir )\r
-\r
-# what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length\r
-shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK')\r
-\r
-# the set of legal states which can trail the RUNTEST command\r
-run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE')\r
-\r
-enddr_state_allowed = ('DRPAUSE', 'IDLE', 'RESET')\r
-endir_state_allowed = ('IRPAUSE', 'IDLE', 'RESET')\r
-\r
-enddr_state = IDLE\r
-endir_state = IDLE\r
-\r
-frequency =    1.00e+006 # HZ;\r
-\r
-# change detection for xsdrsize and xtdomask\r
-xsdrsize = -1           # the last one sent, send only on change\r
-xtdomask = bytearray()  # the last one sent, send only on change\r
-\r
-\r
-# we use a number of single byte writes for the XSVF command below\r
-cmdbuf = bytearray(1)\r
-\r
-\r
-# Save the XREPEAT setting into the file as first thing.\r
-obuf = bytearray(2)\r
-obuf[0] = XREPEAT\r
-obuf[1] = xrepeat\r
-output.write( obuf )\r
-\r
-\r
-try:\r
-    while 1:\r
-        expecting_eof = True\r
-        nextTok()\r
-        expecting_eof = False\r
-        # print( tokType, tokVal, tokLn )\r
-\r
-        if tokVal in shiftOps:\r
-            shiftOp_linenum = tokLn\r
-            shiftOp = tokVal\r
-\r
-            set = shiftSets[shiftOps.index(shiftOp)]\r
-\r
-            # set flags false, if we see one later, set that one true later\r
-            sawTDI = sawTDO = sawMASK = sawSMASK = False\r
-\r
-            nextTok()\r
-            if tokType != 'int':\r
-                raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) )\r
-            length = tokVal\r
-\r
-            nextTok()\r
-\r
-            while tokVal != ';':\r
-                if tokVal not in shiftParts:\r
-                    raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'")\r
-                shiftPart = tokVal\r
-\r
-                nextTok()\r
-\r
-                if tokType != 'hex':\r
-                    raise ParseError( tokLn, tokVal, "Expecting hex bits" )\r
-                bits = makeBitArray( tokVal, length )\r
-\r
-                if shiftPart == 'TDI':\r
-                    sawTDI = True\r
-                    set.tdi = bits\r
-\r
-                elif shiftPart == 'TDO':\r
-                    sawTDO = True\r
-                    set.tdo = bits\r
-\r
-                elif shiftPart == 'MASK':\r
-                    sawMASK = True\r
-                    set.mask = bits\r
-\r
-                elif shiftPart == 'SMASK':\r
-                    sawSMASK = True\r
-                    set.smask = bits\r
-\r
-                nextTok()\r
-\r
-            set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length )\r
-\r
-            # process all the gathered parameters and generate outputs here\r
-            if shiftOp == 'SIR':\r
-                if doCOMMENTs:\r
-                    writeComment( output, shiftOp_linenum, 'SIR' )\r
-\r
-                tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi )\r
-                if len(tdi) > 255:\r
-                    obuf = bytearray(3)\r
-                    obuf[0] = XSIR2\r
-                    struct.pack_into( ">h", obuf, 1, len(tdi) )\r
-                else:\r
-                    obuf = bytearray(2)\r
-                    obuf[0] = XSIR\r
-                    obuf[1] = len(tdi)\r
-                output.write( obuf )\r
-                obuf = makeXSVFbytes( tdi )\r
-                output.write( obuf )\r
-\r
-            elif shiftOp == 'SDR':\r
-                if doCOMMENTs:\r
-                    writeComment( output, shiftOp_linenum, shiftOp )\r
-\r
-                if not sawTDO:\r
-                    # pass a zero filled bit vector for the sdr.mask\r
-                    mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask )\r
-                    tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )\r
-\r
-                    if xsdrsize != len(tdi):\r
-                        xsdrsize = len(tdi)\r
-                        cmdbuf[0] = XSDRSIZE\r
-                        output.write( cmdbuf )\r
-                        obuf = bytearray(4)\r
-                        struct.pack_into( ">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf\r
-                        output.write( obuf )\r
-\r
-                    if xtdomask != mask:\r
-                        xtdomask = mask\r
-                        cmdbuf[0] = XTDOMASK\r
-                        output.write( cmdbuf )\r
-                        obuf = makeXSVFbytes( mask )\r
-                        output.write( obuf )\r
-\r
-                    cmdbuf[0] = XSDR\r
-                    output.write( cmdbuf )\r
-                    obuf = makeXSVFbytes( tdi )\r
-                    output.write( obuf )\r
-\r
-                else:\r
-                    mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )\r
-                    tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )\r
-                    tdo  = combineBitVectors( tdr.tdo,  sdr.tdo,  hdr.tdo )\r
-\r
-                    if xsdrsize != len(tdi):\r
-                        xsdrsize = len(tdi)\r
-                        cmdbuf[0] = XSDRSIZE\r
-                        output.write( cmdbuf )\r
-                        obuf = bytearray(4)\r
-                        struct.pack_into(">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf\r
-                        output.write( obuf )\r
-\r
-                    if xtdomask != mask:\r
-                        xtdomask = mask\r
-                        cmdbuf[0] = XTDOMASK\r
-                        output.write( cmdbuf )\r
-                        obuf = makeXSVFbytes( mask )\r
-                        output.write( obuf )\r
-\r
-                    cmdbuf[0] = XSDRTDO\r
-                    output.write( cmdbuf )\r
-                    obuf = makeXSVFbytes( tdi )\r
-                    output.write( obuf )\r
-                    obuf = makeXSVFbytes( tdo )\r
-                    output.write( obuf )\r
-                    #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )\r
-\r
-            elif shiftOp == 'LSDR':\r
-                if doCOMMENTs:\r
-                    writeComment( output, shiftOp_linenum, shiftOp )\r
-\r
-                mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )\r
-                tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )\r
-                tdo  = combineBitVectors( tdr.tdo,  sdr.tdo,  hdr.tdo )\r
-\r
-                if xsdrsize != len(tdi):\r
-                    xsdrsize = len(tdi)\r
-                    cmdbuf[0] = XSDRSIZE\r
-                    output.write( cmdbuf )\r
-                    obuf = bytearray(4)\r
-                    struct.pack_into(">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf\r
-                    output.write( obuf )\r
-\r
-                if xtdomask != mask:\r
-                    xtdomask = mask\r
-                    cmdbuf[0] = XTDOMASK\r
-                    output.write( cmdbuf )\r
-                    obuf = makeXSVFbytes( mask )\r
-                    output.write( obuf )\r
-\r
-                cmdbuf[0] = LSDR\r
-                output.write( cmdbuf )\r
-                obuf = makeXSVFbytes( tdi )\r
-                output.write( obuf )\r
-                obuf = makeXSVFbytes( tdo )\r
-                output.write( obuf )\r
-                #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )\r
-\r
-        elif tokVal == 'RUNTEST' or tokVal == 'LDELAY':\r
-            # e.g. from lattice tools:\r
-            # "RUNTEST IDLE    5 TCK   1.00E-003 SEC;"\r
-            saveTok = tokVal\r
-            nextTok()\r
-            min_time = 0\r
-            run_count = 0\r
-            max_time = 600  # ten minutes\r
-            if tokVal in run_state_allowed:\r
-                run_state = StateTxt.index(tokVal)\r
-                end_state = run_state  # bottom of page 17 of SVF spec\r
-                nextTok()\r
-            if tokType != 'int' and tokType != 'float':\r
-                raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]")\r
-            timeval = tokVal;\r
-            nextTok()\r
-            if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK':\r
-                raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)")\r
-            if tokVal == 'TCK' or tokVal == 'SCK':\r
-                run_count = int( timeval )\r
-            else:\r
-                min_time = timeval\r
-            nextTok()\r
-            if tokType == 'int' or tokType == 'float':\r
-                min_time = tokVal\r
-                nextTok()\r
-                if tokVal != 'SEC':\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time")\r
-                nextTok()\r
-            if tokVal == 'MAXIMUM':\r
-                nextTok()\r
-                if tokType != 'int' and tokType != 'float':\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM")\r
-                max_time = tokVal\r
-                nextTok()\r
-                if tokVal != 'SEC':\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time")\r
-                nextTok()\r
-            if tokVal == 'ENDSTATE':\r
-                nextTok()\r
-                if tokVal not in run_state_allowed:\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE")\r
-                end_state = StateTxt.index(tokVal)\r
-                nextTok()\r
-            if tokVal != ';':\r
-                raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....")\r
-            # print( "run_count=", run_count, "min_time=", min_time,\r
-                # "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] )\r
-            writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok )\r
-\r
-        elif tokVal == 'LCOUNT':\r
-            nextTok()\r
-            if tokType != 'int':\r
-                raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT")\r
-            loopCount = tokVal\r
-            nextTok()\r
-            if tokVal != ';':\r
-                raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count")\r
-            if doCOMMENTs:\r
-                writeComment( output, tokLn, 'LCOUNT' )\r
-            obuf = bytearray(5)\r
-            obuf[0] = LCOUNT\r
-            struct.pack_into(">i", obuf, 1, loopCount )  # big endian 4 byte int to obuf\r
-            output.write( obuf )\r
-\r
-        elif tokVal == 'ENDDR':\r
-            nextTok()\r
-            if tokVal not in enddr_state_allowed:\r
-                raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE, RESET)")\r
-            enddr_state = StateTxt.index(tokVal)\r
-            nextTok()\r
-            if tokVal != ';':\r
-                raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state")\r
-            if doCOMMENTs:\r
-                writeComment( output, tokLn, 'ENDDR' )\r
-            obuf = bytearray(2)\r
-            obuf[0] = XENDDR\r
-            obuf[1] = enddr_state\r
-            output.write( obuf )\r
-\r
-        elif tokVal == 'ENDIR':\r
-            nextTok()\r
-            if tokVal not in endir_state_allowed:\r
-                raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE, RESET)")\r
-            endir_state = StateTxt.index(tokVal)\r
-            nextTok()\r
-            if tokVal != ';':\r
-                raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state")\r
-            if doCOMMENTs:\r
-                writeComment( output, tokLn, 'ENDIR' )\r
-            obuf = bytearray(2)\r
-            obuf[0] = XENDIR\r
-            obuf[1] = endir_state\r
-            output.write( obuf )\r
-\r
-        elif tokVal == 'STATE':\r
-            nextTok()\r
-            ln = tokLn\r
-            while tokVal != ';':\r
-                if tokVal not in StateTxt:\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE")\r
-                stable_state = StateTxt.index( tokVal )\r
-\r
-                if doCOMMENTs and ln != -1:\r
-                    writeComment( output, ln, 'STATE' )\r
-                    ln = -1     # save comment only once\r
-\r
-                obuf = bytearray(2)\r
-                obuf[0] = XSTATE\r
-                obuf[1] = stable_state\r
-                output.write( obuf )\r
-                nextTok()\r
-\r
-        elif tokVal == 'FREQUENCY':\r
-            nextTok()\r
-            if tokVal != ';':\r
-                if tokType != 'int' and tokType != 'float':\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY")\r
-                frequency = tokVal\r
-                nextTok()\r
-                if tokVal != 'HZ':\r
-                    raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles")\r
-                nextTok()\r
-                if tokVal != ';':\r
-                    raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ")\r
-\r
-        else:\r
-            raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal)\r
-\r
-except StopIteration:\r
-    if not expecting_eof:\r
-        print( "Unexpected End of File at line ", tokLn )\r
-\r
-except ParseError as pe:\r
-    print( "\n", pe )\r
-\r
-finally:\r
-    # print( "closing file" )\r
-    cmdbuf[0] = XCOMPLETE\r
-    output.write( cmdbuf )\r
-    output.close()\r
-\r
+#!/usr/bin/python3.0
+
+# Copyright 2008, SoftPLC Corporation  http://softplc.com
+# Dick Hollenbeck dick@softplc.com
+
+
+# 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 2
+# 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, you may find one here:
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# or you may search the http://www.gnu.org website for the version 2 license,
+# or you may write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+
+# A python program to convert an SVF file to an XSVF file.  There is an
+# option to include comments containing the source file line number from the origin
+# SVF file before each outputted XSVF statement.
+#
+# We deviate from the XSVF spec in that we introduce a new command called
+# XWAITSTATE which directly flows from the SVF RUNTEST command.  Unfortunately
+# XRUNSTATE was ill conceived and is not used here.  We also add support for the
+# three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR.  The xsvf file
+# generated from this program is suitable for use with the xsvf player in
+# OpenOCD with my modifications to xsvf.c.
+#
+# This program is written for python 3.0, and it is not easy to change this
+# back to 2.x.  You may find it easier to use python 3.x even if that means
+# building it.
+
+
+import re
+import sys
+import struct
+
+
+# There are both ---<Lexer>--- and ---<Parser>--- sections to this program
+
+
+if len( sys.argv ) < 3:
+    print("usage %s <svf_filename> <xsvf_filename>" % sys.argv[0])
+    exit(1)
+
+
+inputFilename = sys.argv[1]
+outputFilename = sys.argv[2]
+
+doCOMMENTs = True       # Save XCOMMENTs in the output xsvf file
+#doCOMMENTs = False       # Save XCOMMENTs in the output xsvf file
+
+xrepeat = 0             # argument to XREPEAT, gives retry count for masked compares
+
+
+#-----< Lexer >---------------------------------------------------------------
+
+StateBin = (RESET,IDLE,
+    DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE,
+    IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16)
+
+# Any integer index into this tuple will be equal to its corresponding StateBin value
+StateTxt = ("RESET","IDLE",
+    "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE",
+    "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE")
+
+
+(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO,
+    XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC,
+    XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE,LCOUNT,LDELAY,LSDR) = range(28)
+
+#Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back
+# and check a completion status, essentially waiting on a part until it signals that it is done.
+# For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST)
+# and exit loop when LSDR compares match.
+"""
+LCOUNT 25;
+! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC.
+LDELAY DRPAUSE 5 TCK   1.00E-003 SEC;
+! Test for the completed status. Match means pass.
+! Loop back to LDELAY line if not match and loop count less than 25.
+LSDR  1 TDI  (0)
+        TDO  (1);
+"""
+
+LineNumber = 1
+
+def s_ident(scanner, token): return ("ident", token.upper(), LineNumber)
+
+def s_hex(scanner, token):
+    global LineNumber
+    LineNumber = LineNumber + token.count('\n')
+    token = ''.join(token.split())
+    return ("hex", token[1:-1], LineNumber)
+
+def s_int(scanner, token): return ("int", int(token), LineNumber)
+def s_float(scanner, token): return ("float", float(token), LineNumber)
+#def s_comment(scanner, token): return ("comment", token, LineNumber)
+def s_semicolon(scanner, token): return ("semi", token, LineNumber)
+
+def s_nl(scanner,token):
+    global LineNumber
+    LineNumber = LineNumber + 1
+    #print( 'LineNumber=', LineNumber, file=sys.stderr )
+    return None
+
+#2.00E-002
+
+scanner = re.Scanner([
+    (r"[a-zA-Z]\w*", s_ident),
+#    (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float),
+    (r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float),
+    (r"\d+", s_int),
+    (r"\(([0-9a-fA-F]|\s)*\)", s_hex),
+    (r"(!|//).*$", None),
+    (r";", s_semicolon),
+    (r"\n",s_nl),
+    (r"\s*", None),
+    ],
+    re.MULTILINE
+    )
+
+# read all svf file input into string "input"
+input = open( sys.argv[1] ).read()
+
+# Lexer:
+# create a list of tuples containing (tokenType, tokenValue, LineNumber)
+tokens = scanner.scan( input )[0]
+
+input = None    # allow gc to reclaim memory holding file
+
+#for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue )
+
+
+#-----<parser>-----------------------------------------------------------------
+
+tokVal = tokType = tokLn = None
+
+tup = iter( tokens )
+
+def nextTok():
+    """
+    Function to read the next token from tup into tokType, tokVal, tokLn (linenumber)
+    which are globals.
+    """
+    global tokType, tokVal, tokLn, tup
+    tokType, tokVal, tokLn = tup.__next__()
+
+
+class ParseError(Exception):
+    """A class to hold a parsing error message"""
+    def __init__(self, linenumber, token, message):
+        self.linenumber = linenumber
+        self.token = token
+        self.message = message
+    def __str__(self):
+        global inputFilename
+        return "Error in file \'%s\' at line %d near token %s\n %s" % (
+                   inputFilename, self.linenumber, repr(self.token), self.message)
+
+
+class MASKSET(object):
+    """
+    Class MASKSET holds a set of bit vectors, all of which are related, will all
+    have the same length, and are associated with one of the seven shiftOps:
+    HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a
+    size.
+    """
+    def __init__(self, name):
+        self.empty()
+        self.name = name
+
+    def empty(self):
+        self.mask = bytearray()
+        self.smask = bytearray()
+        self.tdi = bytearray()
+        self.tdo = bytearray()
+        self.size = 0
+
+    def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ):
+        """
+        Set all the lengths equal in the event some of the masks were
+        not seen as part of the last change set.
+        """
+        if self.size == newSize:
+            return
+
+        if newSize == 0:
+            self.empty()
+            return
+
+        # If an SIR was given without a MASK(), then use a mask of all zeros.
+        # this is not consistent with the SVF spec, but it makes sense because
+        # it would be odd to be testing an instruction register read out of a
+        # tap without giving a mask for it.  Also, lattice seems to agree and is
+        # generating SVF files that comply with this philosophy.
+        if self.name == 'SIR' and not sawMASK:
+            self.mask = bytearray( newSize )
+
+        if newSize != len(self.mask):
+            self.mask = bytearray( newSize )
+            if self.name == 'SDR':  # leave mask for HIR,HDR,TIR,TDR,SIR zeros
+                for i in range( newSize ):
+                    self.mask[i] = 1
+
+        if newSize != len(self.tdo):
+            self.tdo = bytearray( newSize )
+
+        if newSize != len(self.tdi):
+            self.tdi = bytearray( newSize )
+
+        if newSize != len(self.smask):
+            self.smask = bytearray( newSize )
+
+        self.size = newSize
+#-----</MASKSET>-----
+
+
+def makeBitArray( hexString, bitCount ):
+    """
+    Converts a packed sequence of hex ascii characters into a bytearray where
+    each element in the array holds exactly one bit. Only "bitCount" bits are
+    scanned and these must be the least significant bits in the hex number. That
+    is, it is legal to have some unused bits in the must significant hex nibble
+    of the input "hexString". The string is scanned starting from the backend,
+    then just before returning we reverse the array. This way the append()
+    method can be used, which I assume is faster than an insert.
+    """
+    global tokLn
+    a = bytearray()
+    length = bitCount
+    hexString = list(hexString)
+    hexString.reverse()
+    #print(hexString)
+    for c in hexString:
+        if length <= 0:
+            break;
+        c = int(c, 16)
+        for mask in [1,2,4,8]:
+            if length <= 0:
+                break;
+            length = length - 1
+            a.append( (c & mask) != 0 )
+    if length > 0:
+        raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount )
+    a.reverse()
+    #print(a)
+    return a
+
+
+def makeXSVFbytes( bitarray ):
+    """
+    Make a bytearray which is contains the XSVF bits which will be written
+    directly to disk.  The number of bytes needed is calculated from the size
+    of the argument bitarray.
+    """
+    bitCount = len(bitarray)
+    byteCount = (bitCount+7)//8
+    ba = bytearray( byteCount )
+    firstBit = (bitCount % 8) - 1
+    if firstBit == -1:
+        firstBit = 7
+    bitNdx = 0
+    for byteNdx in range(byteCount):
+        mask = 1<<firstBit
+        byte = 0
+        while mask:
+            if bitarray[bitNdx]:
+                byte |= mask;
+            mask = mask >> 1
+            bitNdx = bitNdx + 1
+        ba[byteNdx] = byte
+        firstBit = 7
+    return ba
+
+
+def writeComment( outputFile, shiftOp_linenum, shiftOp ):
+    """
+    Write an XCOMMENT record to outputFile
+    """
+    comment = "%s @%d\0" % (shiftOp, shiftOp_linenum)   # \0 is terminating nul
+    ba = bytearray(1)
+    ba[0] = XCOMMENT
+    ba += comment.encode()
+    outputFile.write( ba )
+
+
+def combineBitVectors( trailer, meat, header ):
+    """
+    Combine the 3 bit vectors comprizing a transmission.  Since the least
+    significant bits are sent first, the header is put onto the list last so
+    they are sent first from that least significant position.
+    """
+    ret = bytearray()
+    ret.extend( trailer )
+    ret.extend( meat )
+    ret.extend( header )
+    return ret
+
+
+def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ):
+    """
+    Write the output for the SVF RUNTEST command.
+    run_count - the number of clocks
+    min_time - the number of seconds
+    tokenTxt - either RUNTEST or LDELAY
+    """
+    # convert from secs to usecs
+    min_time = int( min_time * 1000000)
+
+    # the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command.  Check the SVF spec, then
+    # read the XSVF command.   They are not the same.  Use an XSVF XWAITSTATE to
+    # implement the required behavior of the SVF RUNTEST command.
+    if doCOMMENTs:
+        writeComment( output, tokLn, tokenTxt )
+
+    if tokenTxt == 'RUNTEST':
+        obuf = bytearray(11)
+        obuf[0] = XWAITSTATE
+        obuf[1] = run_state
+        obuf[2] = end_state
+        struct.pack_into(">i", obuf, 3, run_count )  # big endian 4 byte int to obuf
+        struct.pack_into(">i", obuf, 7, min_time )   # big endian 4 byte int to obuf
+        outputFile.write( obuf )
+    else:   # == 'LDELAY'
+        obuf = bytearray(10)
+        obuf[0] = LDELAY
+        obuf[1] = run_state
+        # LDELAY has no end_state
+        struct.pack_into(">i", obuf, 2, run_count )  # big endian 4 byte int to obuf
+        struct.pack_into(">i", obuf, 6, min_time )   # big endian 4 byte int to obuf
+        outputFile.write( obuf )
+
+
+output = open( outputFilename, mode='wb' )
+
+hir = MASKSET('HIR')
+hdr = MASKSET('HDR')
+tir = MASKSET('TIR')
+tdr = MASKSET('TDR')
+sir = MASKSET('SIR')
+sdr = MASKSET('SDR')
+
+
+expecting_eof = True
+
+
+# one of the commands that take the shiftParts after the length, the parse
+# template for all of these commands is identical
+shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR')
+
+# the order must correspond to shiftOps, this holds the MASKSETS.  'LSDR' shares sdr with 'SDR'
+shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir )
+
+# what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length
+shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK')
+
+# the set of legal states which can trail the RUNTEST command
+run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE')
+
+enddr_state_allowed = ('DRPAUSE', 'IDLE')
+endir_state_allowed = ('IRPAUSE', 'IDLE')
+
+enddr_state = IDLE
+endir_state = IDLE
+
+frequency =    1.00e+006 # HZ;
+
+# change detection for xsdrsize and xtdomask
+xsdrsize = -1           # the last one sent, send only on change
+xtdomask = bytearray()  # the last one sent, send only on change
+
+
+# we use a number of single byte writes for the XSVF command below
+cmdbuf = bytearray(1)
+
+
+# Save the XREPEAT setting into the file as first thing.
+obuf = bytearray(2)
+obuf[0] = XREPEAT
+obuf[1] = xrepeat
+output.write( obuf )
+
+
+try:
+    while 1:
+        expecting_eof = True
+        nextTok()
+        expecting_eof = False
+        # print( tokType, tokVal, tokLn )
+
+        if tokVal in shiftOps:
+            shiftOp_linenum = tokLn
+            shiftOp = tokVal
+
+            set = shiftSets[shiftOps.index(shiftOp)]
+
+            # set flags false, if we see one later, set that one true later
+            sawTDI = sawTDO = sawMASK = sawSMASK = False
+
+            nextTok()
+            if tokType != 'int':
+                raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) )
+            length = tokVal
+
+            nextTok()
+
+            while tokVal != ';':
+                if tokVal not in shiftParts:
+                    raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'")
+                shiftPart = tokVal
+
+                nextTok()
+
+                if tokType != 'hex':
+                    raise ParseError( tokLn, tokVal, "Expecting hex bits" )
+                bits = makeBitArray( tokVal, length )
+
+                if shiftPart == 'TDI':
+                    sawTDI = True
+                    set.tdi = bits
+
+                elif shiftPart == 'TDO':
+                    sawTDO = True
+                    set.tdo = bits
+
+                elif shiftPart == 'MASK':
+                    sawMASK = True
+                    set.mask = bits
+
+                elif shiftPart == 'SMASK':
+                    sawSMASK = True
+                    set.smask = bits
+
+                nextTok()
+
+            set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length )
+
+            # process all the gathered parameters and generate outputs here
+            if shiftOp == 'SIR':
+                if doCOMMENTs:
+                    writeComment( output, shiftOp_linenum, 'SIR' )
+
+                tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi )
+                if len(tdi) > 255:
+                    obuf = bytearray(3)
+                    obuf[0] = XSIR2
+                    struct.pack_into( ">h", obuf, 1, len(tdi) )
+                else:
+                    obuf = bytearray(2)
+                    obuf[0] = XSIR
+                    obuf[1] = len(tdi)
+                output.write( obuf )
+                obuf = makeXSVFbytes( tdi )
+                output.write( obuf )
+
+            elif shiftOp == 'SDR':
+                if doCOMMENTs:
+                    writeComment( output, shiftOp_linenum, shiftOp )
+
+                if not sawTDO:
+                    # pass a zero filled bit vector for the sdr.mask
+                    mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask )
+                    tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )
+
+                    if xsdrsize != len(tdi):
+                        xsdrsize = len(tdi)
+                        cmdbuf[0] = XSDRSIZE
+                        output.write( cmdbuf )
+                        obuf = bytearray(4)
+                        struct.pack_into( ">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf
+                        output.write( obuf )
+
+                    if xtdomask != mask:
+                        xtdomask = mask
+                        cmdbuf[0] = XTDOMASK
+                        output.write( cmdbuf )
+                        obuf = makeXSVFbytes( mask )
+                        output.write( obuf )
+
+                    cmdbuf[0] = XSDR
+                    output.write( cmdbuf )
+                    obuf = makeXSVFbytes( tdi )
+                    output.write( obuf )
+
+                else:
+                    mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )
+                    tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )
+                    tdo  = combineBitVectors( tdr.tdo,  sdr.tdo,  hdr.tdo )
+
+                    if xsdrsize != len(tdi):
+                        xsdrsize = len(tdi)
+                        cmdbuf[0] = XSDRSIZE
+                        output.write( cmdbuf )
+                        obuf = bytearray(4)
+                        struct.pack_into(">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf
+                        output.write( obuf )
+
+                    if xtdomask != mask:
+                        xtdomask = mask
+                        cmdbuf[0] = XTDOMASK
+                        output.write( cmdbuf )
+                        obuf = makeXSVFbytes( mask )
+                        output.write( obuf )
+
+                    cmdbuf[0] = XSDRTDO
+                    output.write( cmdbuf )
+                    obuf = makeXSVFbytes( tdi )
+                    output.write( obuf )
+                    obuf = makeXSVFbytes( tdo )
+                    output.write( obuf )
+                    #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )
+
+            elif shiftOp == 'LSDR':
+                if doCOMMENTs:
+                    writeComment( output, shiftOp_linenum, shiftOp )
+
+                mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )
+                tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )
+                tdo  = combineBitVectors( tdr.tdo,  sdr.tdo,  hdr.tdo )
+
+                if xsdrsize != len(tdi):
+                    xsdrsize = len(tdi)
+                    cmdbuf[0] = XSDRSIZE
+                    output.write( cmdbuf )
+                    obuf = bytearray(4)
+                    struct.pack_into(">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf
+                    output.write( obuf )
+
+                if xtdomask != mask:
+                    xtdomask = mask
+                    cmdbuf[0] = XTDOMASK
+                    output.write( cmdbuf )
+                    obuf = makeXSVFbytes( mask )
+                    output.write( obuf )
+
+                cmdbuf[0] = LSDR
+                output.write( cmdbuf )
+                obuf = makeXSVFbytes( tdi )
+                output.write( obuf )
+                obuf = makeXSVFbytes( tdo )
+                output.write( obuf )
+                #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )
+
+        elif tokVal == 'RUNTEST' or tokVal == 'LDELAY':
+            # e.g. from lattice tools:
+            # "RUNTEST IDLE    5 TCK   1.00E-003 SEC;"
+            saveTok = tokVal
+            nextTok()
+            min_time = 0
+            run_count = 0
+            max_time = 600  # ten minutes
+            if tokVal in run_state_allowed:
+                run_state = StateTxt.index(tokVal)
+                end_state = run_state  # bottom of page 17 of SVF spec
+                nextTok()
+            if tokType != 'int' and tokType != 'float':
+                raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]")
+            timeval = tokVal;
+            nextTok()
+            if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK':
+                raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)")
+            if tokVal == 'TCK' or tokVal == 'SCK':
+                run_count = int( timeval )
+            else:
+                min_time = timeval
+            nextTok()
+            if tokType == 'int' or tokType == 'float':
+                min_time = tokVal
+                nextTok()
+                if tokVal != 'SEC':
+                    raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time")
+                nextTok()
+            if tokVal == 'MAXIMUM':
+                nextTok()
+                if tokType != 'int' and tokType != 'float':
+                    raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM")
+                max_time = tokVal
+                nextTok()
+                if tokVal != 'SEC':
+                    raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time")
+                nextTok()
+            if tokVal == 'ENDSTATE':
+                nextTok()
+                if tokVal not in run_state_allowed:
+                    raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE")
+                end_state = StateTxt.index(tokVal)
+                nextTok()
+            if tokVal != ';':
+                raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....")
+            # print( "run_count=", run_count, "min_time=", min_time,
+                # "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] )
+            writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok )
+
+        elif tokVal == 'LCOUNT':
+            nextTok()
+            if tokType != 'int':
+                raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT")
+            loopCount = tokVal
+            nextTok()
+            if tokVal != ';':
+                raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count")
+            if doCOMMENTs:
+                writeComment( output, tokLn, 'LCOUNT' )
+            obuf = bytearray(5)
+            obuf[0] = LCOUNT
+            struct.pack_into(">i", obuf, 1, loopCount )  # big endian 4 byte int to obuf
+            output.write( obuf )
+
+        elif tokVal == 'ENDDR':
+            nextTok()
+            if tokVal not in enddr_state_allowed:
+                raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE)")
+            enddr_state = StateTxt.index(tokVal)
+            nextTok()
+            if tokVal != ';':
+                raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state")
+            if doCOMMENTs:
+                writeComment( output, tokLn, 'ENDDR' )
+            obuf = bytearray(2)
+            obuf[0] = XENDDR
+            # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here.
+            # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e.
+            # boolean argument to XENDDR which only handles two of the 3 intended states.
+            obuf[1] = 1 if enddr_state == DRPAUSE else 0
+            output.write( obuf )
+
+        elif tokVal == 'ENDIR':
+            nextTok()
+            if tokVal not in endir_state_allowed:
+                raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE)")
+            endir_state = StateTxt.index(tokVal)
+            nextTok()
+            if tokVal != ';':
+                raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state")
+            if doCOMMENTs:
+                writeComment( output, tokLn, 'ENDIR' )
+            obuf = bytearray(2)
+            obuf[0] = XENDIR
+            # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here.
+            # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e.
+            # boolean argument to XENDDR which only handles two of the 3 intended states.
+            obuf[1] = 1 if endir_state == IRPAUSE else 0
+            output.write( obuf )
+
+        elif tokVal == 'STATE':
+            nextTok()
+            ln = tokLn
+            while tokVal != ';':
+                if tokVal not in StateTxt:
+                    raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE")
+                stable_state = StateTxt.index( tokVal )
+
+                if doCOMMENTs and ln != -1:
+                    writeComment( output, ln, 'STATE' )
+                    ln = -1     # save comment only once
+
+                obuf = bytearray(2)
+                obuf[0] = XSTATE
+                obuf[1] = stable_state
+                output.write( obuf )
+                nextTok()
+
+        elif tokVal == 'FREQUENCY':
+            nextTok()
+            if tokVal != ';':
+                if tokType != 'int' and tokType != 'float':
+                    raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY")
+                frequency = tokVal
+                nextTok()
+                if tokVal != 'HZ':
+                    raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles")
+                nextTok()
+                if tokVal != ';':
+                    raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ")
+
+        else:
+            raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal)
+
+except StopIteration:
+    if not expecting_eof:
+        print( "Unexpected End of File at line ", tokLn )
+
+except ParseError as pe:
+    print( "\n", pe )
+
+finally:
+    # print( "closing file" )
+    cmdbuf[0] = XCOMPLETE
+    output.write( cmdbuf )
+    output.close()
+
index df5db165bcec84b5d962338138e17716fa1fd39a..b2e3c7d7e29322f266358fb9589d619b15f185a5 100644 (file)
-#!/usr/bin/python3.0\r
-\r
-# Copyright 2008, SoftPLC Corporation  http://softplc.com\r
-# Dick Hollenbeck dick@softplc.com\r
-\r
-# This program is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU General Public License\r
-# as published by the Free Software Foundation; either version 2\r
-# of the License, or (at your option) any later version.\r
-#\r
-# This program is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-# GNU General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU General Public License\r
-# along with this program; if not, you may find one here:\r
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\r
-# or you may search the http://www.gnu.org website for the version 2 license,\r
-# or you may write to the Free Software Foundation, Inc.,\r
-# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
-\r
-# Dump an Xilinx XSVF file to stdout\r
-\r
-# This program is written for python 3.0, and it is not easy to change this\r
-# back to 2.x.  You may find it easier to use python 3.x even if that means\r
-# building it.\r
-\r
-\r
-import sys\r
-import struct\r
-\r
-\r
-LABEL = "A script to dump an XSVF file to stdout"\r
-\r
-\r
-Xsdrsize = 0\r
-\r
-\r
-(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO,\r
-    XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC,\r
-    XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE,LCOUNT,LDELAY,LSDR) = range(28)\r
-\r
-\r
-(RESET,IDLE,\r
-    DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE,\r
-    IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16)\r
-\r
-\r
-State = ("RESET","IDLE",\r
-    "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE",\r
-    "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE")\r
-\r
-Setsdrmasks = 0\r
-SetsdrmasksOnesCount = 0\r
-\r
-def ReadSDRMASKS( f, len ):\r
-    global Setsdrmasks, SetsdrmasksOnesCount\r
-    byteCount = (len+7)//8\r
-    Setsdrmasks = f.read( byteCount )\r
-    ls = []\r
-    SetsdrmasksOnesCount = 0\r
-    for b in Setsdrmasks:\r
-        ls.append( "%x" % ((b & 0xf0) >> 4) )\r
-        ls.append( "%x" % ( b & 0x0f ) )\r
-        for i in range(8):\r
-            if b & (1<<i):\r
-                SetsdrmasksOnesCount = SetsdrmasksOnesCount +1\r
-    return ''.join(ls)\r
-\r
-\r
-def bytes2hexString( f, len ):\r
-    byteCount = (len+7)//8\r
-    bytebuf = f.read( byteCount )\r
-    ls = []\r
-    for b in bytebuf:\r
-        ls.append( "%x" % ((b & 0xf0) >> 4) )\r
-        ls.append( "%x" % ( b & 0x0f ) )\r
-    return ''.join(ls)\r
-\r
-\r
-def ReadByte( f ):\r
-    """Read a byte from a file and return it as an int in least significant 8 bits"""\r
-    b = f.read(1)\r
-    if b:\r
-        return 0xff & b[0];\r
-    else:\r
-        return -1\r
-\r
-\r
-def ShowState( state ):\r
-    """return the given state int as a state string"""\r
-    #return "0x%02x" % state # comment this out to get textual state form\r
-    global State\r
-    if 0 <= state <= IRUPDATE:\r
-        return State[state]\r
-    else:\r
-        return "Unknown state 0x%02x" % state\r
-\r
-\r
-def ShowOpcode( op, f ):\r
-    """return the given byte as an opcode string"""\r
-    global Xsdrsize\r
-    if op == XCOMPLETE:\r
-        print("XCOMPLETE")\r
-\r
-    elif op == XTDOMASK:\r
-        buf = bytes2hexString( f, Xsdrsize )\r
-        print("XTDOMASK 0x%s" % buf)\r
-\r
-    elif op == XSIR:\r
-        len = ReadByte( f )\r
-        buf = bytes2hexString( f, len )\r
-        print("XSIR 0x%02X 0x%s" % (len, buf))\r
-\r
-    elif op == XSDR:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        print("XSDR 0x%s" % tdi)\r
-\r
-    elif op == XRUNTEST:\r
-        len = struct.unpack( '>i', f.read(4) )[0]\r
-        print("XRUNTEST 0x%08X" % len)\r
-\r
-    elif op == XREPEAT:\r
-        len = ReadByte( f )\r
-        print("XREPEAT 0x%02X" % len)\r
-\r
-    elif op == XSDRSIZE:\r
-        Xsdrsize = struct.unpack( '>i', f.read(4) )[0]\r
-        #print("XSDRSIZE 0x%08X" % Xsdrsize, file=sys.stderr )\r
-        print("XSDRSIZE 0x%08X %d" % (Xsdrsize, Xsdrsize) )\r
-\r
-    elif op == XSDRTDO:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        tdo = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRTDO 0x%s 0x%s" % (tdi, tdo) )\r
-\r
-    elif op == XSETSDRMASKS:\r
-        addrmask = bytes2hexString( f, Xsdrsize )\r
-        datamask = ReadSDRMASKS( f, Xsdrsize )\r
-        print("XSETSDRMASKS 0x%s 0x%s" % (addrmask, datamask) )\r
-\r
-    elif op == XSDRINC:\r
-        startaddr = bytes2hexString( f, Xsdrsize )\r
-        len = ReadByte(f)\r
-        print("XSDRINC 0x%s 0x%02X" % (startaddr, len), end='' )\r
-        for numTimes in range(len):\r
-            data = bytes2hexString( f, SetsdrmasksOnesCount)\r
-            print(" 0x%s" % data )\r
-        print() # newline\r
-\r
-    elif op == XSDRB:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRB 0x%s" % tdi )\r
-\r
-    elif op == XSDRC:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRC 0x%s" % tdi )\r
-\r
-    elif op == XSDRE:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRE 0x%s" % tdi )\r
-\r
-    elif op == XSDRTDOB:\r
-        tdo = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRTDOB 0x%s" % tdo )\r
-\r
-    elif op == XSDRTDOC:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        tdo = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRTDOC 0x%s 0x%s" % (tdi, tdo) )\r
-\r
-    elif op == XSDRTDOE:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        tdo = bytes2hexString( f, Xsdrsize )\r
-        print("XSDRTDOE 0x%s 0x%s" % (tdi, tdo) )\r
-\r
-    elif op == XSTATE:\r
-        b = ReadByte(f)\r
-        print("XSTATE %s" % ShowState(b))\r
-\r
-    elif op == XENDIR:\r
-        b = ReadByte( f )\r
-        print("XENDIR %s" % ShowState(b))\r
-\r
-    elif op == XENDDR:\r
-        b = ReadByte( f )\r
-        print("XENDDR %s" % ShowState(b))\r
-\r
-    elif op == XSIR2:\r
-        len = struct.unpack( '>H', f.read(2) )[0]\r
-        buf = bytes2hexString( f, len )\r
-        print("XSIR2 0x%04X 0x%s" % (len, buf))\r
-\r
-    elif op == XCOMMENT:\r
-        cmt = []\r
-        while 1:\r
-            b = ReadByte(f)\r
-            if b == 0:          # terminating nul\r
-                break;\r
-            cmt.append( chr(b) )\r
-        print("XCOMMENT \"%s\"" % ''.join(cmt)  )\r
-\r
-    elif op == XWAIT:\r
-        run_state = ReadByte(f)\r
-        end_state = ReadByte(f)\r
-        useconds  = struct.unpack( '>i', f.read(4) )[0]\r
-        print("XWAIT %s %s" % (ShowState(run_state), ShowState(end_state)), useconds)\r
-\r
-    elif op == XWAITSTATE:\r
-        run_state = ReadByte(f)\r
-        end_state = ReadByte(f)\r
-        clocks    = struct.unpack( '>i', f.read(4) )[0]\r
-        useconds  = struct.unpack( '>i', f.read(4) )[0]\r
-        print("XWAITSTATE %s %s CLOCKS=%d USECS=%d" % (ShowState(run_state), ShowState(end_state), clocks, useconds) )\r
-\r
-    elif op == LCOUNT:\r
-        loop_count = struct.unpack( '>i', f.read(4) )[0]\r
-        print("LCOUNT", loop_count )\r
-\r
-    elif op == LDELAY:\r
-        run_state = ReadByte(f)\r
-        clocks    = struct.unpack( '>i', f.read(4) )[0]\r
-        useconds  = struct.unpack( '>i', f.read(4) )[0]\r
-        print("LDELAY %s CLOCKS=%d USECS=%d" % (ShowState(run_state), clocks, useconds) )\r
-\r
-    elif op == LSDR:\r
-        tdi = bytes2hexString( f, Xsdrsize )\r
-        tdo = bytes2hexString( f, Xsdrsize )\r
-        print("LSDR 0x%s 0x%s" % (tdi, tdo) )\r
-\r
-    else:\r
-        print("UNKNOWN op 0x%02X %d" % (op, op))\r
-        exit(1)\r
-\r
-\r
-def main():\r
-\r
-    if len( sys.argv ) < 2:\r
-        print("usage %s <xsvf_filename>" % sys.argv[0])\r
-        exit(1)\r
-\r
-    f = open( sys.argv[1], 'rb' )\r
-\r
-    opcode = ReadByte( f )\r
-    while opcode != -1:\r
-        # print the position within the file, then the command\r
-        print( "%d: " % f.tell(), end='' )\r
-        ShowOpcode( opcode, f )\r
-        opcode = ReadByte(f)\r
-\r
-\r
-if __name__ == "__main__":\r
-    main()\r
-\r
+#!/usr/bin/python3.0
+
+# Copyright 2008, SoftPLC Corporation  http://softplc.com
+# Dick Hollenbeck dick@softplc.com
+
+# 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 2
+# 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, you may find one here:
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# or you may search the http://www.gnu.org website for the version 2 license,
+# or you may write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+# Dump an Xilinx XSVF file to stdout
+
+# This program is written for python 3.0, and it is not easy to change this
+# back to 2.x.  You may find it easier to use python 3.x even if that means
+# building it.
+
+
+import sys
+import struct
+
+
+LABEL = "A script to dump an XSVF file to stdout"
+
+
+Xsdrsize = 0
+
+
+(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO,
+    XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC,
+    XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE,LCOUNT,LDELAY,LSDR) = range(28)
+
+
+(RESET,IDLE,
+    DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE,
+    IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16)
+
+
+State = ("RESET","IDLE",
+    "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE",
+    "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE")
+
+Setsdrmasks = 0
+SetsdrmasksOnesCount = 0
+
+def ReadSDRMASKS( f, len ):
+    global Setsdrmasks, SetsdrmasksOnesCount
+    byteCount = (len+7)//8
+    Setsdrmasks = f.read( byteCount )
+    ls = []
+    SetsdrmasksOnesCount = 0
+    for b in Setsdrmasks:
+        ls.append( "%x" % ((b & 0xf0) >> 4) )
+        ls.append( "%x" % ( b & 0x0f ) )
+        for i in range(8):
+            if b & (1<<i):
+                SetsdrmasksOnesCount = SetsdrmasksOnesCount +1
+    return ''.join(ls)
+
+
+def bytes2hexString( f, len ):
+    byteCount = (len+7)//8
+    bytebuf = f.read( byteCount )
+    ls = []
+    for b in bytebuf:
+        ls.append( "%x" % ((b & 0xf0) >> 4) )
+        ls.append( "%x" % ( b & 0x0f ) )
+    return ''.join(ls)
+
+
+def ReadByte( f ):
+    """Read a byte from a file and return it as an int in least significant 8 bits"""
+    b = f.read(1)
+    if b:
+        return 0xff & b[0];
+    else:
+        return -1
+
+
+def ShowState( state ):
+    """return the given state int as a state string"""
+    #return "0x%02x" % state # comment this out to get textual state form
+    global State
+    if 0 <= state <= IRUPDATE:
+        return State[state]
+    else:
+        return "Unknown state 0x%02x" % state
+
+
+def ShowOpcode( op, f ):
+    """return the given byte as an opcode string"""
+    global Xsdrsize
+    if op == XCOMPLETE:
+        print("XCOMPLETE")
+
+    elif op == XTDOMASK:
+        buf = bytes2hexString( f, Xsdrsize )
+        print("XTDOMASK 0x%s" % buf)
+
+    elif op == XSIR:
+        len = ReadByte( f )
+        buf = bytes2hexString( f, len )
+        print("XSIR 0x%02X 0x%s" % (len, buf))
+
+    elif op == XSDR:
+        tdi = bytes2hexString( f, Xsdrsize )
+        print("XSDR 0x%s" % tdi)
+
+    elif op == XRUNTEST:
+        len = struct.unpack( '>i', f.read(4) )[0]
+        print("XRUNTEST 0x%08X" % len)
+
+    elif op == XREPEAT:
+        len = ReadByte( f )
+        print("XREPEAT 0x%02X" % len)
+
+    elif op == XSDRSIZE:
+        Xsdrsize = struct.unpack( '>i', f.read(4) )[0]
+        #print("XSDRSIZE 0x%08X" % Xsdrsize, file=sys.stderr )
+        print("XSDRSIZE 0x%08X %d" % (Xsdrsize, Xsdrsize) )
+
+    elif op == XSDRTDO:
+        tdi = bytes2hexString( f, Xsdrsize )
+        tdo = bytes2hexString( f, Xsdrsize )
+        print("XSDRTDO 0x%s 0x%s" % (tdi, tdo) )
+
+    elif op == XSETSDRMASKS:
+        addrmask = bytes2hexString( f, Xsdrsize )
+        datamask = ReadSDRMASKS( f, Xsdrsize )
+        print("XSETSDRMASKS 0x%s 0x%s" % (addrmask, datamask) )
+
+    elif op == XSDRINC:
+        startaddr = bytes2hexString( f, Xsdrsize )
+        len = ReadByte(f)
+        print("XSDRINC 0x%s 0x%02X" % (startaddr, len), end='' )
+        for numTimes in range(len):
+            data = bytes2hexString( f, SetsdrmasksOnesCount)
+            print(" 0x%s" % data )
+        print() # newline
+
+    elif op == XSDRB:
+        tdi = bytes2hexString( f, Xsdrsize )
+        print("XSDRB 0x%s" % tdi )
+
+    elif op == XSDRC:
+        tdi = bytes2hexString( f, Xsdrsize )
+        print("XSDRC 0x%s" % tdi )
+
+    elif op == XSDRE:
+        tdi = bytes2hexString( f, Xsdrsize )
+        print("XSDRE 0x%s" % tdi )
+
+    elif op == XSDRTDOB:
+        tdo = bytes2hexString( f, Xsdrsize )
+        print("XSDRTDOB 0x%s" % tdo )
+
+    elif op == XSDRTDOC:
+        tdi = bytes2hexString( f, Xsdrsize )
+        tdo = bytes2hexString( f, Xsdrsize )
+        print("XSDRTDOC 0x%s 0x%s" % (tdi, tdo) )
+
+    elif op == XSDRTDOE:
+        tdi = bytes2hexString( f, Xsdrsize )
+        tdo = bytes2hexString( f, Xsdrsize )
+        print("XSDRTDOE 0x%s 0x%s" % (tdi, tdo) )
+
+    elif op == XSTATE:
+        b = ReadByte(f)
+        print("XSTATE %s" % ShowState(b))
+
+    elif op == XENDIR:
+        b = ReadByte( f )
+        print("XENDIR %s" % 'IRPAUSE' if b==1 else 'IDLE')
+
+    elif op == XENDDR:
+        b = ReadByte( f )
+        print("XENDDR %s" % 'DRPAUSE' if b==1 else 'IDLE')
+
+    elif op == XSIR2:
+        len = struct.unpack( '>H', f.read(2) )[0]
+        buf = bytes2hexString( f, len )
+        print("XSIR2 0x%04X 0x%s" % (len, buf))
+
+    elif op == XCOMMENT:
+        cmt = []
+        while 1:
+            b = ReadByte(f)
+            if b == 0:          # terminating nul
+                break;
+            cmt.append( chr(b) )
+        print("XCOMMENT \"%s\"" % ''.join(cmt)  )
+
+    elif op == XWAIT:
+        run_state = ReadByte(f)
+        end_state = ReadByte(f)
+        useconds  = struct.unpack( '>i', f.read(4) )[0]
+        print("XWAIT %s %s" % (ShowState(run_state), ShowState(end_state)), useconds)
+
+    elif op == XWAITSTATE:
+        run_state = ReadByte(f)
+        end_state = ReadByte(f)
+        clocks    = struct.unpack( '>i', f.read(4) )[0]
+        useconds  = struct.unpack( '>i', f.read(4) )[0]
+        print("XWAITSTATE %s %s CLOCKS=%d USECS=%d" % (ShowState(run_state), ShowState(end_state), clocks, useconds) )
+
+    elif op == LCOUNT:
+        loop_count = struct.unpack( '>i', f.read(4) )[0]
+        print("LCOUNT", loop_count )
+
+    elif op == LDELAY:
+        run_state = ReadByte(f)
+        clocks    = struct.unpack( '>i', f.read(4) )[0]
+        useconds  = struct.unpack( '>i', f.read(4) )[0]
+        print("LDELAY %s CLOCKS=%d USECS=%d" % (ShowState(run_state), clocks, useconds) )
+
+    elif op == LSDR:
+        tdi = bytes2hexString( f, Xsdrsize )
+        tdo = bytes2hexString( f, Xsdrsize )
+        print("LSDR 0x%s 0x%s" % (tdi, tdo) )
+
+    else:
+        print("UNKNOWN op 0x%02X %d" % (op, op))
+        exit(1)
+
+
+def main():
+
+    if len( sys.argv ) < 2:
+        print("usage %s <xsvf_filename>" % sys.argv[0])
+        exit(1)
+
+    f = open( sys.argv[1], 'rb' )
+
+    opcode = ReadByte( f )
+    while opcode != -1:
+        # print the position within the file, then the command
+        print( "%d: " % f.tell(), end='' )
+        ShowOpcode( opcode, f )
+        opcode = ReadByte(f)
+
+
+if __name__ == "__main__":
+    main()
+

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)