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