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