Dick Hollenbeck <dick@softplc.com> SVF to XSVF converter and the XSVF dumper
[fw/openocd] / tools / xsvf_tools / svf2xsvf.py
1 #!/usr/bin/python3.0\r
2 \r
3 # Copyright 2008, SoftPLC Corporation  http://softplc.com\r
4 # Dick Hollenbeck dick@softplc.com\r
5 \r
6 \r
7 # This program is free software; you can redistribute it and/or\r
8 # modify it under the terms of the GNU General Public License\r
9 # as published by the Free Software Foundation; either version 2\r
10 # of the License, or (at your option) any later version.\r
11 #\r
12 # This program is distributed in the hope that it will be useful,\r
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 # GNU General Public License for more details.\r
16 #\r
17 # You should have received a copy of the GNU General Public License\r
18 # along with this program; if not, you may find one here:\r
19 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html\r
20 # or you may search the http://www.gnu.org website for the version 2 license,\r
21 # or you may write to the Free Software Foundation, Inc.,\r
22 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
23 \r
24 \r
25 # A python program to convert an SVF file to an XSVF file.  There is an\r
26 # option to include comments containing the source file line number from the origin\r
27 # SVF file before each outputted XSVF statement.\r
28 #\r
29 # We deviate from the XSVF spec in that we introduce a new command called\r
30 # XWAITSTATE which directly flows from the SVF RUNTEST command.  Unfortunately\r
31 # XRUNSTATE was ill conceived and is not used here.  We also add support for the\r
32 # three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR.  The xsvf file\r
33 # generated from this program is suitable for use with the xsvf player in\r
34 # OpenOCD with my modifications to xsvf.c.\r
35 #\r
36 # This program is written for python 3.0, and it is not easy to change this\r
37 # back to 2.x.  You may find it easier to use python 3.x even if that means\r
38 # building it.\r
39 \r
40 \r
41 import re\r
42 import sys\r
43 import struct\r
44 \r
45 \r
46 # There are both ---<Lexer>--- and ---<Parser>--- sections to this program\r
47 \r
48 \r
49 if len( sys.argv ) < 3:\r
50     print("usage %s <svf_filename> <xsvf_filename>" % sys.argv[0])\r
51     exit(1)\r
52 \r
53 \r
54 inputFilename = sys.argv[1]\r
55 outputFilename = sys.argv[2]\r
56 \r
57 doCOMMENTs = True       # Save XCOMMENTs in the output xsvf file\r
58 #doCOMMENTs = False       # Save XCOMMENTs in the output xsvf file\r
59 \r
60 xrepeat = 0             # argument to XREPEAT, gives retry count for masked compares\r
61 \r
62 \r
63 #-----< Lexer >---------------------------------------------------------------\r
64 \r
65 StateBin = (RESET,IDLE,\r
66     DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE,\r
67     IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16)\r
68 \r
69 # Any integer index into this tuple will be equal to its corresponding StateBin value\r
70 StateTxt = ("RESET","IDLE",\r
71     "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE",\r
72     "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE")\r
73 \r
74 \r
75 (XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO,\r
76     XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC,\r
77     XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE,LCOUNT,LDELAY,LSDR) = range(28)\r
78 \r
79 #Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back\r
80 # and check a completion status, essentially waiting on a part until it signals that it is done.\r
81 # For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST)\r
82 # and exit loop when LSDR compares match.\r
83 """\r
84 LCOUNT  25;\r
85 ! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC.\r
86 LDELAY  DRPAUSE 5 TCK   1.00E-003 SEC;\r
87 ! Test for the completed status. Match means pass.\r
88 ! Loop back to LDELAY line if not match and loop count less than 25.\r
89 LSDR  1 TDI  (0)\r
90         TDO  (1);\r
91 """\r
92 \r
93 LineNumber = 1\r
94 \r
95 def s_ident(scanner, token): return ("ident", token.upper(), LineNumber)\r
96 \r
97 def s_hex(scanner, token):\r
98     global LineNumber\r
99     LineNumber = LineNumber + token.count('\n')\r
100     token = ''.join(token.split())\r
101     return ("hex", token[1:-1], LineNumber)\r
102 \r
103 def s_int(scanner, token): return ("int", int(token), LineNumber)\r
104 def s_float(scanner, token): return ("float", float(token), LineNumber)\r
105 #def s_comment(scanner, token): return ("comment", token, LineNumber)\r
106 def s_semicolon(scanner, token): return ("semi", token, LineNumber)\r
107 \r
108 def s_nl(scanner,token):\r
109     global LineNumber\r
110     LineNumber = LineNumber + 1\r
111     #print( 'LineNumber=', LineNumber, file=sys.stderr )\r
112     return None\r
113 \r
114 #2.00E-002\r
115 \r
116 scanner = re.Scanner([\r
117     (r"[a-zA-Z]\w*", s_ident),\r
118 #    (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float),\r
119     (r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float),\r
120     (r"\d+", s_int),\r
121     (r"\(([0-9a-fA-F]|\s)*\)", s_hex),\r
122     (r"(!|//).*$", None),\r
123     (r";", s_semicolon),\r
124     (r"\n",s_nl),\r
125     (r"\s*", None),\r
126     ],\r
127     re.MULTILINE\r
128     )\r
129 \r
130 # read all svf file input into string "input"\r
131 input = open( sys.argv[1] ).read()\r
132 \r
133 # Lexer:\r
134 # create a list of tuples containing (tokenType, tokenValue, LineNumber)\r
135 tokens = scanner.scan( input )[0]\r
136 \r
137 input = None    # allow gc to reclaim memory holding file\r
138 \r
139 #for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue )\r
140 \r
141 \r
142 #-----<parser>-----------------------------------------------------------------\r
143 \r
144 tokVal = tokType = tokLn = None\r
145 \r
146 tup = iter( tokens )\r
147 \r
148 def nextTok():\r
149     """\r
150     Function to read the next token from tup into tokType, tokVal, tokLn (linenumber)\r
151     which are globals.\r
152     """\r
153     global tokType, tokVal, tokLn, tup\r
154     tokType, tokVal, tokLn = tup.__next__()\r
155 \r
156 \r
157 class ParseError(Exception):\r
158     """A class to hold a parsing error message"""\r
159     def __init__(self, linenumber, token, message):\r
160         self.linenumber = linenumber\r
161         self.token = token\r
162         self.message = message\r
163     def __str__(self):\r
164         global inputFilename\r
165         return "Error in file \'%s\' at line %d near token %s\n %s" % (\r
166                    inputFilename, self.linenumber, repr(self.token), self.message)\r
167 \r
168 \r
169 class MASKSET(object):\r
170     """\r
171     Class MASKSET holds a set of bit vectors, all of which are related, will all\r
172     have the same length, and are associated with one of the seven shiftOps:\r
173     HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a\r
174     size.\r
175     """\r
176     def __init__(self, name):\r
177         self.empty()\r
178         self.name = name\r
179 \r
180     def empty(self):\r
181         self.mask = bytearray()\r
182         self.smask = bytearray()\r
183         self.tdi = bytearray()\r
184         self.tdo = bytearray()\r
185         self.size = 0\r
186 \r
187     def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ):\r
188         """\r
189         Set all the lengths equal in the event some of the masks were\r
190         not seen as part of the last change set.\r
191         """\r
192         if self.size == newSize:\r
193             return\r
194 \r
195         if newSize == 0:\r
196             self.empty()\r
197             return\r
198 \r
199         # If an SIR was given without a MASK(), then use a mask of all zeros.\r
200         # this is not consistent with the SVF spec, but it makes sense because\r
201         # it would be odd to be testing an instruction register read out of a\r
202         # tap without giving a mask for it.  Also, lattice seems to agree and is\r
203         # generating SVF files that comply with this philosophy.\r
204         if self.name == 'SIR' and not sawMASK:\r
205             self.mask = bytearray( newSize )\r
206 \r
207         if newSize != len(self.mask):\r
208             self.mask = bytearray( newSize )\r
209             if self.name == 'SDR':  # leave mask for HIR,HDR,TIR,TDR,SIR zeros\r
210                 for i in range( newSize ):\r
211                     self.mask[i] = 1\r
212 \r
213         if newSize != len(self.tdo):\r
214             self.tdo = bytearray( newSize )\r
215 \r
216         if newSize != len(self.tdi):\r
217             self.tdi = bytearray( newSize )\r
218 \r
219         if newSize != len(self.smask):\r
220             self.smask = bytearray( newSize )\r
221 \r
222         self.size = newSize\r
223 #-----</MASKSET>-----\r
224 \r
225 \r
226 def makeBitArray( hexString, bitCount ):\r
227     """\r
228     Converts a packed sequence of hex ascii characters into a bytearray where\r
229     each element in the array holds exactly one bit. Only "bitCount" bits are\r
230     scanned and these must be the least significant bits in the hex number. That\r
231     is, it is legal to have some unused bits in the must significant hex nibble\r
232     of the input "hexString". The string is scanned starting from the backend,\r
233     then just before returning we reverse the array. This way the append()\r
234     method can be used, which I assume is faster than an insert.\r
235     """\r
236     global tokLn\r
237     a = bytearray()\r
238     length = bitCount\r
239     hexString = list(hexString)\r
240     hexString.reverse()\r
241     #print(hexString)\r
242     for c in hexString:\r
243         if length <= 0:\r
244             break;\r
245         c = int(c, 16)\r
246         for mask in [1,2,4,8]:\r
247             if length <= 0:\r
248                 break;\r
249             length = length - 1\r
250             a.append( (c & mask) != 0 )\r
251     if length > 0:\r
252         raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount )\r
253     a.reverse()\r
254     #print(a)\r
255     return a\r
256 \r
257 \r
258 def makeXSVFbytes( bitarray ):\r
259     """\r
260     Make a bytearray which is contains the XSVF bits which will be written\r
261     directly to disk.  The number of bytes needed is calculated from the size\r
262     of the argument bitarray.\r
263     """\r
264     bitCount = len(bitarray)\r
265     byteCount = (bitCount+7)//8\r
266     ba = bytearray( byteCount )\r
267     firstBit = (bitCount % 8) - 1\r
268     if firstBit == -1:\r
269         firstBit = 7\r
270     bitNdx = 0\r
271     for byteNdx in range(byteCount):\r
272         mask = 1<<firstBit\r
273         byte = 0\r
274         while mask:\r
275             if bitarray[bitNdx]:\r
276                 byte |= mask;\r
277             mask = mask >> 1\r
278             bitNdx = bitNdx + 1\r
279         ba[byteNdx] = byte\r
280         firstBit = 7\r
281     return ba\r
282 \r
283 \r
284 def writeComment( outputFile, shiftOp_linenum, shiftOp ):\r
285     """\r
286     Write an XCOMMENT record to outputFile\r
287     """\r
288     comment = "%s @%d\0" % (shiftOp, shiftOp_linenum)   # \0 is terminating nul\r
289     ba = bytearray(1)\r
290     ba[0] = XCOMMENT\r
291     ba += comment.encode()\r
292     outputFile.write( ba )\r
293 \r
294 \r
295 def combineBitVectors( trailer, meat, header ):\r
296     """\r
297     Combine the 3 bit vectors comprizing a transmission.  Since the least\r
298     significant bits are sent first, the header is put onto the list last so\r
299     they are sent first from that least significant position.\r
300     """\r
301     ret = bytearray()\r
302     ret.extend( trailer )\r
303     ret.extend( meat )\r
304     ret.extend( header )\r
305     return ret\r
306 \r
307 \r
308 def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ):\r
309     """\r
310     Write the output for the SVF RUNTEST command.\r
311     run_count - the number of clocks\r
312     min_time - the number of seconds\r
313     tokenTxt - either RUNTEST or LDELAY\r
314     """\r
315     # convert from secs to usecs\r
316     min_time = int( min_time * 1000000)\r
317 \r
318     # the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command.  Check the SVF spec, then\r
319     # read the XSVF command.   They are not the same.  Use an XSVF XWAITSTATE to\r
320     # implement the required behavior of the SVF RUNTEST command.\r
321     if doCOMMENTs:\r
322         writeComment( output, tokLn, tokenTxt )\r
323 \r
324     if tokenTxt == 'RUNTEST':\r
325         obuf = bytearray(11)\r
326         obuf[0] = XWAITSTATE\r
327         obuf[1] = run_state\r
328         obuf[2] = end_state\r
329         struct.pack_into(">i", obuf, 3, run_count )  # big endian 4 byte int to obuf\r
330         struct.pack_into(">i", obuf, 7, min_time )   # big endian 4 byte int to obuf\r
331         outputFile.write( obuf )\r
332     else:   # == 'LDELAY'\r
333         obuf = bytearray(10)\r
334         obuf[0] = LDELAY\r
335         obuf[1] = run_state\r
336         # LDELAY has no end_state\r
337         struct.pack_into(">i", obuf, 2, run_count )  # big endian 4 byte int to obuf\r
338         struct.pack_into(">i", obuf, 6, min_time )   # big endian 4 byte int to obuf\r
339         outputFile.write( obuf )\r
340 \r
341 \r
342 output = open( outputFilename, mode='wb' )\r
343 \r
344 hir = MASKSET('HIR')\r
345 hdr = MASKSET('HDR')\r
346 tir = MASKSET('TIR')\r
347 tdr = MASKSET('TDR')\r
348 sir = MASKSET('SIR')\r
349 sdr = MASKSET('SDR')\r
350 \r
351 \r
352 expecting_eof = True\r
353 \r
354 \r
355 # one of the commands that take the shiftParts after the length, the parse\r
356 # template for all of these commands is identical\r
357 shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR')\r
358 \r
359 # the order must correspond to shiftOps, this holds the MASKSETS.  'LSDR' shares sdr with 'SDR'\r
360 shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir )\r
361 \r
362 # what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length\r
363 shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK')\r
364 \r
365 # the set of legal states which can trail the RUNTEST command\r
366 run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE')\r
367 \r
368 enddr_state_allowed = ('DRPAUSE', 'IDLE', 'RESET')\r
369 endir_state_allowed = ('IRPAUSE', 'IDLE', 'RESET')\r
370 \r
371 enddr_state = IDLE\r
372 endir_state = IDLE\r
373 \r
374 frequency =     1.00e+006 # HZ;\r
375 \r
376 # change detection for xsdrsize and xtdomask\r
377 xsdrsize = -1           # the last one sent, send only on change\r
378 xtdomask = bytearray()  # the last one sent, send only on change\r
379 \r
380 \r
381 # we use a number of single byte writes for the XSVF command below\r
382 cmdbuf = bytearray(1)\r
383 \r
384 \r
385 # Save the XREPEAT setting into the file as first thing.\r
386 obuf = bytearray(2)\r
387 obuf[0] = XREPEAT\r
388 obuf[1] = xrepeat\r
389 output.write( obuf )\r
390 \r
391 \r
392 try:\r
393     while 1:\r
394         expecting_eof = True\r
395         nextTok()\r
396         expecting_eof = False\r
397         # print( tokType, tokVal, tokLn )\r
398 \r
399         if tokVal in shiftOps:\r
400             shiftOp_linenum = tokLn\r
401             shiftOp = tokVal\r
402 \r
403             set = shiftSets[shiftOps.index(shiftOp)]\r
404 \r
405             # set flags false, if we see one later, set that one true later\r
406             sawTDI = sawTDO = sawMASK = sawSMASK = False\r
407 \r
408             nextTok()\r
409             if tokType != 'int':\r
410                 raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) )\r
411             length = tokVal\r
412 \r
413             nextTok()\r
414 \r
415             while tokVal != ';':\r
416                 if tokVal not in shiftParts:\r
417                     raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'")\r
418                 shiftPart = tokVal\r
419 \r
420                 nextTok()\r
421 \r
422                 if tokType != 'hex':\r
423                     raise ParseError( tokLn, tokVal, "Expecting hex bits" )\r
424                 bits = makeBitArray( tokVal, length )\r
425 \r
426                 if shiftPart == 'TDI':\r
427                     sawTDI = True\r
428                     set.tdi = bits\r
429 \r
430                 elif shiftPart == 'TDO':\r
431                     sawTDO = True\r
432                     set.tdo = bits\r
433 \r
434                 elif shiftPart == 'MASK':\r
435                     sawMASK = True\r
436                     set.mask = bits\r
437 \r
438                 elif shiftPart == 'SMASK':\r
439                     sawSMASK = True\r
440                     set.smask = bits\r
441 \r
442                 nextTok()\r
443 \r
444             set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length )\r
445 \r
446             # process all the gathered parameters and generate outputs here\r
447             if shiftOp == 'SIR':\r
448                 if doCOMMENTs:\r
449                     writeComment( output, shiftOp_linenum, 'SIR' )\r
450 \r
451                 tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi )\r
452                 if len(tdi) > 255:\r
453                     obuf = bytearray(3)\r
454                     obuf[0] = XSIR2\r
455                     struct.pack_into( ">h", obuf, 1, len(tdi) )\r
456                 else:\r
457                     obuf = bytearray(2)\r
458                     obuf[0] = XSIR\r
459                     obuf[1] = len(tdi)\r
460                 output.write( obuf )\r
461                 obuf = makeXSVFbytes( tdi )\r
462                 output.write( obuf )\r
463 \r
464             elif shiftOp == 'SDR':\r
465                 if doCOMMENTs:\r
466                     writeComment( output, shiftOp_linenum, shiftOp )\r
467 \r
468                 if not sawTDO:\r
469                     # pass a zero filled bit vector for the sdr.mask\r
470                     mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask )\r
471                     tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )\r
472 \r
473                     if xsdrsize != len(tdi):\r
474                         xsdrsize = len(tdi)\r
475                         cmdbuf[0] = XSDRSIZE\r
476                         output.write( cmdbuf )\r
477                         obuf = bytearray(4)\r
478                         struct.pack_into( ">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf\r
479                         output.write( obuf )\r
480 \r
481                     if xtdomask != mask:\r
482                         xtdomask = mask\r
483                         cmdbuf[0] = XTDOMASK\r
484                         output.write( cmdbuf )\r
485                         obuf = makeXSVFbytes( mask )\r
486                         output.write( obuf )\r
487 \r
488                     cmdbuf[0] = XSDR\r
489                     output.write( cmdbuf )\r
490                     obuf = makeXSVFbytes( tdi )\r
491                     output.write( obuf )\r
492 \r
493                 else:\r
494                     mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )\r
495                     tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )\r
496                     tdo  = combineBitVectors( tdr.tdo,  sdr.tdo,  hdr.tdo )\r
497 \r
498                     if xsdrsize != len(tdi):\r
499                         xsdrsize = len(tdi)\r
500                         cmdbuf[0] = XSDRSIZE\r
501                         output.write( cmdbuf )\r
502                         obuf = bytearray(4)\r
503                         struct.pack_into(">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf\r
504                         output.write( obuf )\r
505 \r
506                     if xtdomask != mask:\r
507                         xtdomask = mask\r
508                         cmdbuf[0] = XTDOMASK\r
509                         output.write( cmdbuf )\r
510                         obuf = makeXSVFbytes( mask )\r
511                         output.write( obuf )\r
512 \r
513                     cmdbuf[0] = XSDRTDO\r
514                     output.write( cmdbuf )\r
515                     obuf = makeXSVFbytes( tdi )\r
516                     output.write( obuf )\r
517                     obuf = makeXSVFbytes( tdo )\r
518                     output.write( obuf )\r
519                     #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )\r
520 \r
521             elif shiftOp == 'LSDR':\r
522                 if doCOMMENTs:\r
523                     writeComment( output, shiftOp_linenum, shiftOp )\r
524 \r
525                 mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask )\r
526                 tdi  = combineBitVectors( tdr.tdi,  sdr.tdi,  hdr.tdi )\r
527                 tdo  = combineBitVectors( tdr.tdo,  sdr.tdo,  hdr.tdo )\r
528 \r
529                 if xsdrsize != len(tdi):\r
530                     xsdrsize = len(tdi)\r
531                     cmdbuf[0] = XSDRSIZE\r
532                     output.write( cmdbuf )\r
533                     obuf = bytearray(4)\r
534                     struct.pack_into(">i", obuf, 0, xsdrsize )  # big endian 4 byte int to obuf\r
535                     output.write( obuf )\r
536 \r
537                 if xtdomask != mask:\r
538                     xtdomask = mask\r
539                     cmdbuf[0] = XTDOMASK\r
540                     output.write( cmdbuf )\r
541                     obuf = makeXSVFbytes( mask )\r
542                     output.write( obuf )\r
543 \r
544                 cmdbuf[0] = LSDR\r
545                 output.write( cmdbuf )\r
546                 obuf = makeXSVFbytes( tdi )\r
547                 output.write( obuf )\r
548                 obuf = makeXSVFbytes( tdo )\r
549                 output.write( obuf )\r
550                 #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) )\r
551 \r
552         elif tokVal == 'RUNTEST' or tokVal == 'LDELAY':\r
553             # e.g. from lattice tools:\r
554             # "RUNTEST  IDLE    5 TCK   1.00E-003 SEC;"\r
555             saveTok = tokVal\r
556             nextTok()\r
557             min_time = 0\r
558             run_count = 0\r
559             max_time = 600  # ten minutes\r
560             if tokVal in run_state_allowed:\r
561                 run_state = StateTxt.index(tokVal)\r
562                 end_state = run_state  # bottom of page 17 of SVF spec\r
563                 nextTok()\r
564             if tokType != 'int' and tokType != 'float':\r
565                 raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]")\r
566             timeval = tokVal;\r
567             nextTok()\r
568             if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK':\r
569                 raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)")\r
570             if tokVal == 'TCK' or tokVal == 'SCK':\r
571                 run_count = int( timeval )\r
572             else:\r
573                 min_time = timeval\r
574             nextTok()\r
575             if tokType == 'int' or tokType == 'float':\r
576                 min_time = tokVal\r
577                 nextTok()\r
578                 if tokVal != 'SEC':\r
579                     raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time")\r
580                 nextTok()\r
581             if tokVal == 'MAXIMUM':\r
582                 nextTok()\r
583                 if tokType != 'int' and tokType != 'float':\r
584                     raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM")\r
585                 max_time = tokVal\r
586                 nextTok()\r
587                 if tokVal != 'SEC':\r
588                     raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time")\r
589                 nextTok()\r
590             if tokVal == 'ENDSTATE':\r
591                 nextTok()\r
592                 if tokVal not in run_state_allowed:\r
593                     raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE")\r
594                 end_state = StateTxt.index(tokVal)\r
595                 nextTok()\r
596             if tokVal != ';':\r
597                 raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....")\r
598             # print( "run_count=", run_count, "min_time=", min_time,\r
599                 # "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] )\r
600             writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok )\r
601 \r
602         elif tokVal == 'LCOUNT':\r
603             nextTok()\r
604             if tokType != 'int':\r
605                 raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT")\r
606             loopCount = tokVal\r
607             nextTok()\r
608             if tokVal != ';':\r
609                 raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count")\r
610             if doCOMMENTs:\r
611                 writeComment( output, tokLn, 'LCOUNT' )\r
612             obuf = bytearray(5)\r
613             obuf[0] = LCOUNT\r
614             struct.pack_into(">i", obuf, 1, loopCount )  # big endian 4 byte int to obuf\r
615             output.write( obuf )\r
616 \r
617         elif tokVal == 'ENDDR':\r
618             nextTok()\r
619             if tokVal not in enddr_state_allowed:\r
620                 raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE, RESET)")\r
621             enddr_state = StateTxt.index(tokVal)\r
622             nextTok()\r
623             if tokVal != ';':\r
624                 raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state")\r
625             if doCOMMENTs:\r
626                 writeComment( output, tokLn, 'ENDDR' )\r
627             obuf = bytearray(2)\r
628             obuf[0] = XENDDR\r
629             obuf[1] = enddr_state\r
630             output.write( obuf )\r
631 \r
632         elif tokVal == 'ENDIR':\r
633             nextTok()\r
634             if tokVal not in endir_state_allowed:\r
635                 raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE, RESET)")\r
636             endir_state = StateTxt.index(tokVal)\r
637             nextTok()\r
638             if tokVal != ';':\r
639                 raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state")\r
640             if doCOMMENTs:\r
641                 writeComment( output, tokLn, 'ENDIR' )\r
642             obuf = bytearray(2)\r
643             obuf[0] = XENDIR\r
644             obuf[1] = endir_state\r
645             output.write( obuf )\r
646 \r
647         elif tokVal == 'STATE':\r
648             nextTok()\r
649             ln = tokLn\r
650             while tokVal != ';':\r
651                 if tokVal not in StateTxt:\r
652                     raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE")\r
653                 stable_state = StateTxt.index( tokVal )\r
654 \r
655                 if doCOMMENTs and ln != -1:\r
656                     writeComment( output, ln, 'STATE' )\r
657                     ln = -1     # save comment only once\r
658 \r
659                 obuf = bytearray(2)\r
660                 obuf[0] = XSTATE\r
661                 obuf[1] = stable_state\r
662                 output.write( obuf )\r
663                 nextTok()\r
664 \r
665         elif tokVal == 'FREQUENCY':\r
666             nextTok()\r
667             if tokVal != ';':\r
668                 if tokType != 'int' and tokType != 'float':\r
669                     raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY")\r
670                 frequency = tokVal\r
671                 nextTok()\r
672                 if tokVal != 'HZ':\r
673                     raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles")\r
674                 nextTok()\r
675                 if tokVal != ';':\r
676                     raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ")\r
677 \r
678         else:\r
679             raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal)\r
680 \r
681 except StopIteration:\r
682     if not expecting_eof:\r
683         print( "Unexpected End of File at line ", tokLn )\r
684 \r
685 except ParseError as pe:\r
686     print( "\n", pe )\r
687 \r
688 finally:\r
689     # print( "closing file" )\r
690     cmdbuf[0] = XCOMPLETE\r
691     output.write( cmdbuf )\r
692     output.close()\r
693 \r