svf2xsvf.py 27 KB

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