CodeGen.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. import TestScripts.Parser
  2. import sys
  3. import os.path
  4. import math
  5. groupCode="""class %s : public Client::Group
  6. {
  7. public:
  8. %s(Testing::testID_t id):Client::Group(id)
  9. %s
  10. {
  11. %s
  12. }
  13. private:
  14. %s;
  15. };
  16. """
  17. suiteCode="""
  18. #include \"%s.h\"
  19. %s::%s(Testing::testID_t id):Client::Suite(id)
  20. {
  21. %s
  22. }
  23. """
  24. def decodeHex(hexstr,bits,mask):
  25. value = int(hexstr,16) & mask
  26. if value & (1 << (bits-1)):
  27. value -= 1 << bits
  28. return value
  29. def createMissingDir(destPath):
  30. theDir=os.path.normpath(os.path.dirname(destPath))
  31. if not os.path.exists(theDir):
  32. os.makedirs(theDir)
  33. class CodeGen:
  34. """ Code generation from the parsed description file
  35. Generate include files, cpp files, and .txt files for test control
  36. Generation depends on the mode (fpga or semihosting)
  37. """
  38. def __init__(self,patternDir,paramDir,fpga):
  39. """ Create a CodeGen object
  40. Args:
  41. patternDir (str) : where pattern must be read
  42. Used to generate include file in fpag mode
  43. fpga (bool) : false in semihosting mode
  44. Raises:
  45. Nothing
  46. Returns:
  47. CodeGen : CodeGen object
  48. """
  49. self._fpga = fpga
  50. self._patternDir = patternDir
  51. self._paramDir = paramDir
  52. self._currentPaths = [self._patternDir]
  53. self._currentParamPaths = [self._paramDir]
  54. self._alignment=8
  55. def _genGroup(self,root,fi):
  56. """ Generate header definition for a group of tests
  57. Args:
  58. root (TreeElem) : group object to use
  59. fi (file) : Header file (TestDesc.h)
  60. Where to write include definitions for the classes
  61. Raises:
  62. Nothing
  63. Returns:
  64. Nothing
  65. """
  66. # Get the CPP class name
  67. theClass = root.data["class"]
  68. # Get the group ID
  69. theId = root.id
  70. varInit = ""
  71. testInit = ""
  72. testDecl = ""
  73. # Generate initializer for the constructors
  74. # All the member variables corresponding to the
  75. # suites and groups contained in this group.
  76. i = 1
  77. for c in root:
  78. theData = c.data
  79. theMemberId = c.id
  80. if not theData["deprecated"]:
  81. theMemberClass = theData["class"]
  82. theMemberVar = theMemberClass + "Var"
  83. varInit += (",%s(%d)\n" % (theMemberVar,theMemberId))
  84. i = i + 1
  85. # Generate initialization code for the constructor
  86. i = 1
  87. for c in root:
  88. theData = c.data
  89. if theData["deprecated"]:
  90. testInit += "this->addContainer(NULL);"
  91. else:
  92. theMemberClass = theData["class"]
  93. theMemberVar = theMemberClass+"Var"
  94. testInit += "this->addContainer(&%s);\n" % (theMemberVar)
  95. i = i + 1
  96. # Generate member variables for the groups and the suites
  97. # contained in this group.
  98. i = 1
  99. for c in root:
  100. theData = c.data
  101. if not theData["deprecated"]:
  102. theMemberClass = theData["class"]
  103. theMemberVar = theMemberClass+"Var"
  104. theMemberId = c.id
  105. testDecl += "%s %s;\n" % (theMemberClass,theMemberVar)
  106. i = i + 1
  107. fi.write(groupCode % (theClass,theClass,varInit,testInit,testDecl) )
  108. def _genSuite(self,root,thedir,sourceFile):
  109. """ Generate source definition for suite
  110. Args:
  111. root (TreeElem) : suite object to use
  112. fi (file) : Source file (TestDesc.cpp)
  113. Where to write source definitions for the classes
  114. Raises:
  115. Nothing
  116. Returns:
  117. Nothing
  118. """
  119. # Get the CPP class
  120. theClass = root.data["class"]
  121. testInit = ""
  122. testDecl=""
  123. declared={}
  124. # Generate constructor for the class
  125. # Test functions are added in the constructor.
  126. # Keep track of the list of test functions
  127. # (since a test function can be reused by several tests)
  128. for c in root:
  129. theData = c.data
  130. theId = c.id
  131. theTestName = theData["class"]
  132. if not theData["deprecated"]:
  133. testInit += "this->addTest(%d,(Client::test)&%s::%s);\n" % (theId,theClass,theTestName)
  134. # To be able to deprecated tests without having to change the code
  135. # we dump const declaration even for deprecated functions
  136. if theTestName not in declared:
  137. testDecl += "void %s();\n" % (theTestName)
  138. declared[theTestName] = 1
  139. # Generate the suite constructor.
  140. sourceFile.write(suiteCode % (theClass,theClass,theClass,testInit) )
  141. # Generate specific header file for this suite
  142. with open(os.path.join(thedir,"%s_decl.h" % theClass),"w") as decl:
  143. # Use list of test functions to
  144. # declare them in the header.
  145. # Since we don't want to declare the functino several times,
  146. # that's why we needed to keep track of functions in the code above:
  147. # to remove redundancies since the function
  148. # can appear several time in the root object.
  149. decl.write(testDecl)
  150. # Generate the pattern ID for patterns
  151. # defined in this suite
  152. decl.write("\n// Pattern IDs\n")
  153. i = 0
  154. for p in root.patterns:
  155. newId = "static const int %s=%d;\n" % (p[0],i)
  156. decl.write(newId)
  157. i = i + 1
  158. # Generate output ID for the output categories
  159. # defined in this suite
  160. decl.write("\n// Output IDs\n")
  161. i = 0
  162. for p in root.outputs:
  163. newId = "static const int %s=%d;\n" % (p[0],i)
  164. decl.write(newId)
  165. i = i + 1
  166. # Generate test ID for the test define din this suite
  167. i = 0
  168. decl.write("\n// Test IDs\n")
  169. for c in root:
  170. theData = c.data
  171. theId = c.id
  172. # To be able to deprecated tests without having to change the code
  173. # we dump const declaration even for deprecated functions
  174. #if not theData["deprecated"]:
  175. theTestName = theData["class"]
  176. defTestID = "static const int %s_%d=%d;\n" % (theTestName.upper(),theId,theId)
  177. decl.write(defTestID)
  178. i = i + 1
  179. def _genCode(self,root,dir,sourceFile,headerFile):
  180. """ Generate code for the tree of tests
  181. Args:
  182. root (TreeElem) : root object containing the tree
  183. sourceFile (file) : Source file (TestDesc.cpp)
  184. Where to write source definitions for the classes
  185. headerFile (file) : Heade5 file (TestDesc.h)
  186. Where to write header definitions for the classes
  187. Raises:
  188. Nothing
  189. Returns:
  190. Nothing
  191. """
  192. deprecated = root.data["deprecated"]
  193. if not deprecated:
  194. if root.kind == TestScripts.Parser.TreeElem.GROUP:
  195. # For a group, first iterate on the children then on the
  196. # parent because the parent definitino in the header is
  197. # dependent on the children definition (member varaiables)
  198. # So children must gbe defined before.
  199. for c in root:
  200. self._genCode(c,dir,sourceFile,headerFile)
  201. self._genGroup(root,headerFile)
  202. # For a suite, we do not need to recurse since it is a leaf
  203. # of the tree of tests and is containing a list of tests to
  204. # generate
  205. if root.kind == TestScripts.Parser.TreeElem.SUITE:
  206. self._genSuite(root,dir,sourceFile)
  207. def getSuites(self,root,listOfSuites):
  208. """ Extract the list of all suites defined in the tree
  209. Args:
  210. root (TreeElem) : root object containing the tree
  211. listOfSuites (list) : list of suites
  212. Raises:
  213. Nothing
  214. Returns:
  215. list : list of suites
  216. """
  217. deprecated = root.data["deprecated"]
  218. if not deprecated:
  219. theClass = root.data["class"]
  220. if root.kind == TestScripts.Parser.TreeElem.SUITE:
  221. # Append current suite to the list and return the result
  222. listOfSuites.append(theClass)
  223. return(listOfSuites)
  224. elif root.kind == TestScripts.Parser.TreeElem.GROUP:
  225. # Recurse on the children to get the listOfSuite.
  226. # getSuites is appending to the list argument.
  227. # So the line listOfSuites = self.getSuites(c,listOfSuites)
  228. # is a fold.
  229. for c in root:
  230. listOfSuites = self.getSuites(c,listOfSuites)
  231. return(listOfSuites)
  232. else:
  233. return(listOfSuites)
  234. else:
  235. return(listOfSuites)
  236. def _genText(self,root,textFile):
  237. """ Generate the text file which is driving the tests in semihosting
  238. Format of file is:
  239. node kind (group, suite or test)
  240. node id (group id, suite id, test id)
  241. y or n to indicate if this node has some parameters
  242. if y there is the parameter ID
  243. y or n to indicate if entering this node is adding a new
  244. folder to the path used to get input files
  245. if y, the path for the node is added.
  246. Then, if node is a suite, description of the suite is generated.
  247. Number of parameters or 0
  248. It is the number of arguments used by function setUp (arity).
  249. It is not the number of samples in a paramater file
  250. The number of samples is always a multiple
  251. For instance if width and height are the parameters then number
  252. of parameters (arity) is 2.
  253. But each parameter file may contain several combination of (width,height)
  254. So the lenght of those files will be a multiple of 2.
  255. The number of patterns path is generated
  256. The patterns names are generated
  257. The number of output names is generated
  258. The output names are generated
  259. The number of parameter path is generated
  260. The parameter description are generated
  261. p
  262. path if a path
  263. g
  264. gen data if a generator
  265. If a generator:
  266. Generator kind (only 1 = cartesian product generator)
  267. Number of input samples (number of values to encode all parameters)
  268. Number of output samples (number of generated values)
  269. Number of dimensions
  270. For each dimension
  271. Length
  272. Samples
  273. For instance, with A=[1,2] and B=[1,2,3].
  274. Input dimension is 1+2 + 1 + 3 = 7 (number of values needed to encode the two lists
  275. with their length).
  276. Number of output dimensions is 2 * 3 = 6
  277. So, for a test (which is also a TreeElement in the structure),
  278. only node kind and node id are generated followed by
  279. param description and n for folder (since ther is never any folder)
  280. In the test description file, there is never any way to change the pattern
  281. folder for a test.
  282. Args:
  283. root (TreeElem) : root object containing the tree
  284. textFile (file) : where to write the driving description
  285. Raises:
  286. Nothing
  287. Returns:
  288. Nothing
  289. """
  290. deprecated = root.data["deprecated"]
  291. if not deprecated:
  292. textFile.write(str(root.kind))
  293. textFile.write(" ")
  294. textFile.write(str(root.id))
  295. textFile.write("\n")
  296. if "PARAMID" in root.data:
  297. if root.parameterToID:
  298. textFile.write("y\n")
  299. paramId = root.parameterToID[root.data["PARAMID"]]
  300. textFile.write(str(paramId))
  301. textFile.write("\n")
  302. elif root.parent.parameterToID:
  303. textFile.write("y\n")
  304. paramId = root.parent.parameterToID[root.data["PARAMID"]]
  305. textFile.write(str(paramId))
  306. textFile.write("\n")
  307. else:
  308. textFile.write("n\n")
  309. else:
  310. textFile.write("n\n")
  311. # Always dump even if there is no path for a test
  312. # so for a test it will always be n
  313. # It is done to simplify parsing on C side
  314. if root.path:
  315. textFile.write("y\n")
  316. textFile.write(root.path)
  317. textFile.write('\n')
  318. else:
  319. textFile.write("n\n")
  320. if root.kind == TestScripts.Parser.TreeElem.SUITE:
  321. # Here we dump the number of parameters used
  322. # for the tests / benchmarks
  323. if root.params:
  324. textFile.write("%d\n" % len(root.params.full))
  325. else:
  326. textFile.write("0\n")
  327. # Generate patterns path
  328. textFile.write("%d\n" % len(root.patterns))
  329. for (patid,patpath) in root.patterns:
  330. #textFile.write(patid)
  331. #textFile.write("\n")
  332. textFile.write(patpath.strip())
  333. textFile.write("\n")
  334. # Generate output names
  335. textFile.write("%d\n" % len(root.outputs))
  336. for (outid,outname) in root.outputs:
  337. #textFile.write(patid)
  338. #textFile.write("\n")
  339. textFile.write(outname.strip())
  340. textFile.write("\n")
  341. # Generate parameters path or generator
  342. textFile.write("%d\n" % len(root.parameters))
  343. for (paramKind,parid,parpath) in root.parameters:
  344. if paramKind == TestScripts.Parser.TreeElem.PARAMFILE:
  345. textFile.write("p\n")
  346. textFile.write(parpath.strip())
  347. textFile.write("\n")
  348. # Generator kind (only 1 = cartesian product generator)
  349. # Number of input samples (dimensions + vectors)
  350. # Number of samples generated when run
  351. # Number of dimensions
  352. # For each dimension
  353. # Length
  354. # Samples
  355. if paramKind == TestScripts.Parser.TreeElem.PARAMGEN:
  356. textFile.write("g\n")
  357. dimensions = len(parpath)
  358. nbOutputSamples = 1
  359. nbInputSamples = 0
  360. for c in parpath:
  361. nbOutputSamples = nbOutputSamples * len(c["INTS"])
  362. nbInputSamples = nbInputSamples + len(c["INTS"]) + 1
  363. textFile.write("1")
  364. textFile.write("\n")
  365. textFile.write(str(nbInputSamples))
  366. textFile.write("\n")
  367. textFile.write(str(nbOutputSamples))
  368. textFile.write("\n")
  369. textFile.write(str(dimensions))
  370. textFile.write("\n")
  371. for c in parpath:
  372. textFile.write(str(len(c["INTS"])))
  373. textFile.write("\n")
  374. for d in c["INTS"]:
  375. textFile.write(str(d))
  376. textFile.write("\n")
  377. # Iterate on the children
  378. for c in root:
  379. self._genText(c,textFile)
  380. def _write32(self,v,f):
  381. """ Write four integers into a C char array to represent word32
  382. It is used to dump input patterns in include files
  383. or test drive in include file
  384. Args:
  385. v (int) : The int3 to write
  386. f (file) : the opended file
  387. Raises:
  388. Nothing
  389. Returns:
  390. Nothing
  391. """
  392. a=[0,0,0,0]
  393. a[0]= v & 0x0FF
  394. v = v >> 8
  395. a[1]= v & 0x0FF
  396. v = v >> 8
  397. a[2]= v & 0x0FF
  398. v = v >> 8
  399. a[3]= v & 0x0FF
  400. v = v >> 8
  401. f.write("%d,%d,%d,%d,\n" % (a[0],a[1],a[2],a[3]))
  402. def _write16(self,v,f):
  403. """ Write 2 integers into a C char array to represent word32
  404. It is used to dump input patterns in include files
  405. or test drive in include file
  406. Args:
  407. v (int) : The int3 to write
  408. f (file) : the opended file
  409. Raises:
  410. Nothing
  411. Returns:
  412. Nothing
  413. """
  414. a=[0,0]
  415. a[0]= v & 0x0FF
  416. v = v >> 8
  417. a[1]= v & 0x0FF
  418. f.write("%d,%d,\n" % (a[0],a[1]))
  419. def _write8(self,v,f):
  420. """ Write 4 integers into a C char array to represent word8
  421. It is used to dump input patterns in include files
  422. or test drive in include file
  423. Args:
  424. v (int) : The int to write
  425. f (file) : the opended file
  426. Raises:
  427. Nothing
  428. Returns:
  429. Nothing
  430. """
  431. a=[0]
  432. a[0]= v & 0x0FF
  433. f.write("%d,\n" % (a[0]))
  434. def _writeString(self,v,f):
  435. """ Write a C string into a C char array to represent as a list of int
  436. It is used to dump input patterns in include files
  437. or test drive in include file
  438. Args:
  439. v (str) : The string to write
  440. f (file) : the opended file
  441. Raises:
  442. Nothing
  443. Returns:
  444. Nothing
  445. """
  446. for c in v:
  447. f.write("'%c'," % c)
  448. f.write("'\\0',\n")
  449. def convertToInt(self,k,s):
  450. v = 0
  451. if k == "W":
  452. v = decodeHex(s,32,0x0FFFFFFFF)
  453. if k == "H":
  454. v = decodeHex(s,16,0x0FFFF)
  455. if k == "B":
  456. v = decodeHex(s,8,0x0FF)
  457. return(v)
  458. def addPattern(self,includeFile,path):
  459. """ Add a pattern to the include file
  460. It is writing sequence of int into a C char array
  461. to represent the pattern.
  462. Assuming the C chr array is aligned, pattern offset are
  463. aligned too.
  464. So, some padding with 0 may also be generated after the patterm
  465. Args:
  466. includeFile (file) : Opened include file
  467. path (str) : Path to file containing the data
  468. Raises:
  469. Nothing
  470. Returns:
  471. (int,int) : The pattern offset in the array and the number of samples
  472. """
  473. # Current offset in the array which is the offset for the
  474. # pattern being added to this array
  475. returnOffset = self._offset
  476. # Read the pattern for the pattern file
  477. with open(path,"r") as pat:
  478. # Read pattern word size (B,H or W for 8, 16 or 32 bits)
  479. # Patterns are containing data in hex format (big endian for ARM)
  480. # So there is no conversion to do.
  481. # Hex data is read and copied as it is in the C array
  482. k =pat.readline().strip()
  483. sampleSize=1
  484. if k == 'W':
  485. sampleSize = 4
  486. if k == 'H':
  487. sampleSize = 2
  488. # Read number of samples
  489. nbSamples = int(pat.readline().strip())
  490. # Compute new offset based on pattern length only
  491. newOffset = self._offset + sampleSize * nbSamples
  492. # Compute padding due to alignment constraint
  493. pad = self._alignment*math.ceil(newOffset / self._alignment) - newOffset
  494. # New offset in the array
  495. self._offset=newOffset + pad
  496. # Generate all samples into the C array
  497. for i in range(nbSamples):
  498. # In pattern file we have a comment giving the
  499. # true value (for instance float)
  500. # and then a line giving the hex data
  501. # We Ignore comment
  502. pat.readline()
  503. # Then we read the Value
  504. v = self.convertToInt(k,pat.readline())
  505. # Depending on the word size, this hex must be writen to
  506. # the C array as 4,2 or 1 number.
  507. if k == 'W':
  508. self._write32(v,includeFile)
  509. if k == 'H':
  510. self._write16(v,includeFile)
  511. if k == 'B':
  512. self._write8(v,includeFile)
  513. #includeFile.write("%d,\n" % v)
  514. # Add the padding to the pattern
  515. for i in range(pad):
  516. includeFile.write("0,\n")
  517. return(returnOffset,nbSamples)
  518. def addParameter(self,includeFile,path):
  519. """ Add a parameter array to the include file
  520. It is writing sequence of int into a C char array
  521. to represent the pattern.
  522. Assuming the C chr array is aligned, pattern offset are
  523. aligned too.
  524. So, some padding with 0 may also be generated after the patterm
  525. Args:
  526. includeFile (file) : Opened include file
  527. path (str) : Path to file containing the data
  528. Raises:
  529. Nothing
  530. Returns:
  531. (int,int) : The pattern offset in the array and the number of samples
  532. """
  533. # Current offset in the array which is the offset for the
  534. # pattern being added to this array
  535. returnOffset = self._offset
  536. # Read the pattern for the pattern file
  537. with open(path,"r") as pat:
  538. # Read pattern word size (B,H or W for 8, 16 or 32 bits)
  539. # Patterns are containing data in hex format (big endian for ARM)
  540. # So there is no conversion to do.
  541. # Hex data is read and copied as it is in the C array
  542. sampleSize = 4
  543. # Read number of samples
  544. nbSamples = int(pat.readline().strip())
  545. # Compute new offset based on pattern length only
  546. newOffset = self._offset + sampleSize * nbSamples
  547. # Compute padding due to alignment constraint
  548. pad = self._alignment*math.ceil(newOffset / self._alignment) - newOffset
  549. # New offset in the array
  550. self._offset=newOffset + pad
  551. # Generate all samples into the C array
  552. for i in range(nbSamples):
  553. # In pattern file we have a comment giving the
  554. # true value (for instance float)
  555. # and then a line giving the hex data
  556. # Then we read the Value
  557. v = int(pat.readline().strip(),0)
  558. # Depending on the word size, this hex must be writen to
  559. # the C array as 4,2 or 1 number.
  560. self._write32(v,includeFile)
  561. # Add the padding to the pattern
  562. for i in range(pad):
  563. includeFile.write("0,\n")
  564. return(returnOffset,nbSamples)
  565. def _genDriver(self,root,driverFile,includeFile):
  566. """ Generate the driver file and the pattern file
  567. Args:
  568. root (TreeElement) : Tree of test descriptions
  569. driverFile (file) : where to generate C array for test descriptions
  570. includeFile (file) : where to generate C array for patterns
  571. Raises:
  572. Nothing
  573. Returns:
  574. Nothing
  575. """
  576. #if root.parent:
  577. # print(root.parent.data["message"])
  578. #print(" ",root.data["message"])
  579. #print(self._currentPaths)
  580. deprecated = root.data["deprecated"]
  581. # We follow a format quite similar to what is generated in _genText
  582. # for the text description
  583. # But here we are using an offset into the pattern array
  584. # rather than a path to a pattern file.
  585. # It is the only difference
  586. # But for outputs we still need the path so the logic is the same
  587. # Path for output is required to be able to extract data from the stdout file
  588. # and know where the data must be written to.
  589. # Please refer to comments of _genText for description of the format
  590. oldPath = self._currentPaths.copy()
  591. oldParamPath = self._currentParamPaths.copy()
  592. if not deprecated:
  593. # We write node kind and node id
  594. self._write32(root.kind,driverFile)
  595. self._write32(root.id,driverFile)
  596. if "PARAMID" in root.data:
  597. if root.parameterToID:
  598. driverFile.write("'y',")
  599. paramId = root.parameterToID[root.data["PARAMID"]]
  600. self._write32(int(paramId),driverFile)
  601. elif root.parent.parameterToID:
  602. driverFile.write("'y',")
  603. paramId = root.parent.parameterToID[root.data["PARAMID"]]
  604. self._write32(int(paramId),driverFile)
  605. else:
  606. driverFile.write("'n',")
  607. else:
  608. driverFile.write("'n',")
  609. # We write a folder path
  610. # if folder changed in test description file
  611. # Always dumped for a test even if no path for
  612. # a test. So a test will always have n
  613. # It is done to simplify parsing on C side
  614. if root.path:
  615. self._currentPaths.append(root.path)
  616. self._currentParamPaths.append(root.path)
  617. driverFile.write("'y',")
  618. self._writeString(root.path,driverFile)
  619. else:
  620. driverFile.write("'n',\n")
  621. if root.kind == TestScripts.Parser.TreeElem.SUITE:
  622. # Number of parameters
  623. if root.params:
  624. self._write32(len(root.params.full),driverFile)
  625. else:
  626. self._write32(0,driverFile)
  627. # Patterns offsets are written
  628. # and pattern length since the length is not available in a file
  629. # like for semihosting version
  630. self._write32(len(root.patterns),driverFile)
  631. for (patid,patpath) in root.patterns:
  632. temp = self._currentPaths.copy()
  633. temp.append(patpath)
  634. includeFile.write("// " + os.path.join(*temp) + "\n")
  635. offset,nbSamples=self.addPattern(includeFile,os.path.join(*temp))
  636. #driverFile.write(patpath)
  637. #driverFile.write("\n")
  638. self._write32(offset,driverFile)
  639. self._write32(nbSamples,driverFile)
  640. # Generate output names
  641. self._write32(len(root.outputs),driverFile)
  642. for (outid,outname) in root.outputs:
  643. #textFile.write(patid)
  644. #textFile.write("\n")
  645. self._writeString(outname.strip(),driverFile)
  646. # Parameters offsets are written
  647. # and parameter length since the length is not available in a file
  648. # like for semihosting version
  649. self._write32(len(root.parameters),driverFile)
  650. for (paramKind,parid,parpath) in root.parameters:
  651. if paramKind == TestScripts.Parser.TreeElem.PARAMFILE:
  652. temp = self._currentParamPaths.copy()
  653. temp.append(parpath)
  654. includeFile.write("// " + os.path.join(*temp) + "\n")
  655. offset,nbSamples=self.addParameter(includeFile,os.path.join(*temp))
  656. #driverFile.write(patpath)
  657. #driverFile.write("\n")
  658. driverFile.write("'p',")
  659. self._write32(offset,driverFile)
  660. self._write32(nbSamples,driverFile)
  661. # TO DO
  662. if paramKind == TestScripts.Parser.TreeElem.PARAMGEN:
  663. temp = self._currentParamPaths.copy()
  664. includeFile.write("// " + os.path.join(*temp) + "\n")
  665. driverFile.write("'g',")
  666. dimensions = len(parpath)
  667. nbOutputSamples = 1
  668. nbInputSamples = 0
  669. for c in parpath:
  670. nbOutputSamples = nbOutputSamples * len(c["INTS"])
  671. nbInputSamples = nbInputSamples + len(c["INTS"]) + 1
  672. self._write32(1,driverFile)
  673. self._write32(nbInputSamples,driverFile)
  674. self._write32(nbOutputSamples,driverFile)
  675. self._write32(dimensions,driverFile)
  676. for c in parpath:
  677. self._write32(len(c["INTS"]),driverFile)
  678. for d in c["INTS"]:
  679. self._write32(d,driverFile)
  680. # Recurse on the children
  681. for c in root:
  682. self._genDriver(c,driverFile,includeFile)
  683. self._currentPaths = oldPath.copy()
  684. self._currentParamPaths = oldParamPath.copy()
  685. def genCodeForTree(self,root):
  686. """ Generate all files from the trees of tests
  687. Args:
  688. root (TreeElement) : Tree of test descriptions
  689. Raises:
  690. Nothing
  691. Returns:
  692. Nothing
  693. """
  694. # Get a list of all suites contained in the tree
  695. suites = self.getSuites(root,[])
  696. # Generate .cpp and .h files neded to run the tests
  697. with open("GeneratedSource/TestDesc.cpp","w") as sourceFile:
  698. with open("GeneratedInclude/TestDesc.h","w") as headerFile:
  699. headerFile.write("#include \"Test.h\"\n")
  700. headerFile.write("#include \"Pattern.h\"\n")
  701. sourceFile.write("#include \"Test.h\"\n")
  702. for s in suites:
  703. headerFile.write("#include \"%s.h\"\n" % s)
  704. self._genCode(root,"GeneratedInclude",sourceFile,headerFile)
  705. # Generate a driver file for semihosting
  706. # (always generated for debug purpose since it is the reference format)
  707. with open("TestDesc.txt","w") as textFile:
  708. self._genText(root,textFile)
  709. # If fpga mode we need to generate
  710. # a include file version of the driver file and of
  711. # the pattern files.
  712. # Driver file is similar in this case but different from semihosting
  713. # one.
  714. if not self._fpga:
  715. with open("GeneratedInclude/TestDrive.h","w") as driverFile:
  716. driverFile.write("// Empty driver include in semihosting mode")
  717. with open("GeneratedInclude/Patterns.h","w") as includeFile:
  718. includeFile.write("// Empty pattern include in semihosting mode")
  719. else:
  720. with open("GeneratedInclude/TestDrive.h","w") as driverFile:
  721. driverFile.write("#ifndef _DRIVER_H_\n")
  722. driverFile.write("#define _DRIVER_H_\n")
  723. driverFile.write("__ALIGNED(8) const char testDesc[]={\n")
  724. self._offset=0
  725. with open("GeneratedInclude/Patterns.h","w") as includeFile:
  726. includeFile.write("#ifndef _PATTERNS_H_\n")
  727. includeFile.write("#define _PATTERNS_H_\n")
  728. includeFile.write("__ALIGNED(8) const char patterns[]={\n")
  729. self._genDriver(root,driverFile,includeFile)
  730. includeFile.write("};\n")
  731. includeFile.write("#endif\n")
  732. driverFile.write("};\n")
  733. driverFile.write("#endif\n")