CodeGen.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  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 _write64(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 int64 to write
  386. f (file) : the opended file
  387. Raises:
  388. Nothing
  389. Returns:
  390. Nothing
  391. """
  392. a=[0,0,0,0,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. a[4]= v & 0x0FF
  402. v = v >> 8
  403. a[5]= v & 0x0FF
  404. v = v >> 8
  405. a[6]= v & 0x0FF
  406. v = v >> 8
  407. a[7]= v & 0x0FF
  408. v = v >> 8
  409. f.write("%d,%d,%d,%d,%d,%d,%d,%d,\n" % (a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]))
  410. def _write32(self,v,f):
  411. """ Write four integers into a C char array to represent word32
  412. It is used to dump input patterns in include files
  413. or test drive in include file
  414. Args:
  415. v (int) : The int32 to write
  416. f (file) : the opended file
  417. Raises:
  418. Nothing
  419. Returns:
  420. Nothing
  421. """
  422. a=[0,0,0,0]
  423. a[0]= v & 0x0FF
  424. v = v >> 8
  425. a[1]= v & 0x0FF
  426. v = v >> 8
  427. a[2]= v & 0x0FF
  428. v = v >> 8
  429. a[3]= v & 0x0FF
  430. v = v >> 8
  431. f.write("%d,%d,%d,%d,\n" % (a[0],a[1],a[2],a[3]))
  432. def _write16(self,v,f):
  433. """ Write 2 integers into a C char array to represent word32
  434. It is used to dump input patterns in include files
  435. or test drive in include file
  436. Args:
  437. v (int) : The int3 to write
  438. f (file) : the opended file
  439. Raises:
  440. Nothing
  441. Returns:
  442. Nothing
  443. """
  444. a=[0,0]
  445. a[0]= v & 0x0FF
  446. v = v >> 8
  447. a[1]= v & 0x0FF
  448. f.write("%d,%d,\n" % (a[0],a[1]))
  449. def _write8(self,v,f):
  450. """ Write 4 integers into a C char array to represent word8
  451. It is used to dump input patterns in include files
  452. or test drive in include file
  453. Args:
  454. v (int) : The int to write
  455. f (file) : the opended file
  456. Raises:
  457. Nothing
  458. Returns:
  459. Nothing
  460. """
  461. a=[0]
  462. a[0]= v & 0x0FF
  463. f.write("%d,\n" % (a[0]))
  464. def _writeString(self,v,f):
  465. """ Write a C string into a C char array to represent as a list of int
  466. It is used to dump input patterns in include files
  467. or test drive in include file
  468. Args:
  469. v (str) : The string to write
  470. f (file) : the opended file
  471. Raises:
  472. Nothing
  473. Returns:
  474. Nothing
  475. """
  476. for c in v:
  477. f.write("'%c'," % c)
  478. f.write("'\\0',\n")
  479. def convertToInt(self,k,s):
  480. v = 0
  481. if k == "D":
  482. v = decodeHex(s,64,0x0FFFFFFFFFFFFFFFF)
  483. if k == "W":
  484. v = decodeHex(s,32,0x0FFFFFFFF)
  485. if k == "H":
  486. v = decodeHex(s,16,0x0FFFF)
  487. if k == "B":
  488. v = decodeHex(s,8,0x0FF)
  489. return(v)
  490. def addPattern(self,includeFile,path):
  491. """ Add a pattern to the include file
  492. It is writing sequence of int into a C char array
  493. to represent the pattern.
  494. Assuming the C chr array is aligned, pattern offset are
  495. aligned too.
  496. So, some padding with 0 may also be generated after the patterm
  497. Args:
  498. includeFile (file) : Opened include file
  499. path (str) : Path to file containing the data
  500. Raises:
  501. Nothing
  502. Returns:
  503. (int,int) : The pattern offset in the array and the number of samples
  504. """
  505. # Current offset in the array which is the offset for the
  506. # pattern being added to this array
  507. returnOffset = self._offset
  508. # Read the pattern for the pattern file
  509. with open(path,"r") as pat:
  510. # Read pattern word size (B,H or W for 8, 16 or 32 bits)
  511. # Patterns are containing data in hex format (big endian for ARM)
  512. # So there is no conversion to do.
  513. # Hex data is read and copied as it is in the C array
  514. k =pat.readline().strip()
  515. sampleSize=1
  516. if k == 'D':
  517. sampleSize = 8
  518. if k == 'W':
  519. sampleSize = 4
  520. if k == 'H':
  521. sampleSize = 2
  522. # Read number of samples
  523. nbSamples = int(pat.readline().strip())
  524. # Compute new offset based on pattern length only
  525. newOffset = self._offset + sampleSize * nbSamples
  526. # Compute padding due to alignment constraint
  527. pad = self._alignment*math.ceil(newOffset / self._alignment) - newOffset
  528. # New offset in the array
  529. self._offset=newOffset + pad
  530. # Generate all samples into the C array
  531. for i in range(nbSamples):
  532. # In pattern file we have a comment giving the
  533. # true value (for instance float)
  534. # and then a line giving the hex data
  535. # We Ignore comment
  536. pat.readline()
  537. # Then we read the Value
  538. v = self.convertToInt(k,pat.readline())
  539. # Depending on the word size, this hex must be writen to
  540. # the C array as 4,2 or 1 number.
  541. if k == 'D':
  542. self._write64(v,includeFile)
  543. if k == 'W':
  544. self._write32(v,includeFile)
  545. if k == 'H':
  546. self._write16(v,includeFile)
  547. if k == 'B':
  548. self._write8(v,includeFile)
  549. #includeFile.write("%d,\n" % v)
  550. # Add the padding to the pattern
  551. for i in range(pad):
  552. includeFile.write("0,\n")
  553. return(returnOffset,nbSamples)
  554. def addParameter(self,includeFile,path):
  555. """ Add a parameter array to the include file
  556. It is writing sequence of int into a C char array
  557. to represent the pattern.
  558. Assuming the C chr array is aligned, pattern offset are
  559. aligned too.
  560. So, some padding with 0 may also be generated after the patterm
  561. Args:
  562. includeFile (file) : Opened include file
  563. path (str) : Path to file containing the data
  564. Raises:
  565. Nothing
  566. Returns:
  567. (int,int) : The pattern offset in the array and the number of samples
  568. """
  569. # Current offset in the array which is the offset for the
  570. # pattern being added to this array
  571. returnOffset = self._offset
  572. # Read the pattern for the pattern file
  573. with open(path,"r") as pat:
  574. # Read pattern word size (B,H or W for 8, 16 or 32 bits)
  575. # Patterns are containing data in hex format (big endian for ARM)
  576. # So there is no conversion to do.
  577. # Hex data is read and copied as it is in the C array
  578. sampleSize = 4
  579. # Read number of samples
  580. nbSamples = int(pat.readline().strip())
  581. # Compute new offset based on pattern length only
  582. newOffset = self._offset + sampleSize * nbSamples
  583. # Compute padding due to alignment constraint
  584. pad = self._alignment*math.ceil(newOffset / self._alignment) - newOffset
  585. # New offset in the array
  586. self._offset=newOffset + pad
  587. # Generate all samples into the C array
  588. for i in range(nbSamples):
  589. # In pattern file we have a comment giving the
  590. # true value (for instance float)
  591. # and then a line giving the hex data
  592. # Then we read the Value
  593. v = int(pat.readline().strip(),0)
  594. # Depending on the word size, this hex must be writen to
  595. # the C array as 4,2 or 1 number.
  596. self._write32(v,includeFile)
  597. # Add the padding to the pattern
  598. for i in range(pad):
  599. includeFile.write("0,\n")
  600. return(returnOffset,nbSamples)
  601. def _genDriver(self,root,driverFile,includeFile):
  602. """ Generate the driver file and the pattern file
  603. Args:
  604. root (TreeElement) : Tree of test descriptions
  605. driverFile (file) : where to generate C array for test descriptions
  606. includeFile (file) : where to generate C array for patterns
  607. Raises:
  608. Nothing
  609. Returns:
  610. Nothing
  611. """
  612. #if root.parent:
  613. # print(root.parent.data["message"])
  614. #print(" ",root.data["message"])
  615. #print(self._currentPaths)
  616. deprecated = root.data["deprecated"]
  617. # We follow a format quite similar to what is generated in _genText
  618. # for the text description
  619. # But here we are using an offset into the pattern array
  620. # rather than a path to a pattern file.
  621. # It is the only difference
  622. # But for outputs we still need the path so the logic is the same
  623. # Path for output is required to be able to extract data from the stdout file
  624. # and know where the data must be written to.
  625. # Please refer to comments of _genText for description of the format
  626. oldPath = self._currentPaths.copy()
  627. oldParamPath = self._currentParamPaths.copy()
  628. if not deprecated:
  629. # We write node kind and node id
  630. self._write32(root.kind,driverFile)
  631. self._write32(root.id,driverFile)
  632. if "PARAMID" in root.data:
  633. if root.parameterToID:
  634. driverFile.write("'y',")
  635. paramId = root.parameterToID[root.data["PARAMID"]]
  636. self._write32(int(paramId),driverFile)
  637. elif root.parent.parameterToID:
  638. driverFile.write("'y',")
  639. paramId = root.parent.parameterToID[root.data["PARAMID"]]
  640. self._write32(int(paramId),driverFile)
  641. else:
  642. driverFile.write("'n',")
  643. else:
  644. driverFile.write("'n',")
  645. # We write a folder path
  646. # if folder changed in test description file
  647. # Always dumped for a test even if no path for
  648. # a test. So a test will always have n
  649. # It is done to simplify parsing on C side
  650. if root.path:
  651. self._currentPaths.append(root.path)
  652. self._currentParamPaths.append(root.path)
  653. driverFile.write("'y',")
  654. self._writeString(root.path,driverFile)
  655. else:
  656. driverFile.write("'n',\n")
  657. if root.kind == TestScripts.Parser.TreeElem.SUITE:
  658. # Number of parameters
  659. if root.params:
  660. self._write32(len(root.params.full),driverFile)
  661. else:
  662. self._write32(0,driverFile)
  663. # Patterns offsets are written
  664. # and pattern length since the length is not available in a file
  665. # like for semihosting version
  666. self._write32(len(root.patterns),driverFile)
  667. for (patid,patpath) in root.patterns:
  668. temp = self._currentPaths.copy()
  669. temp.append(patpath)
  670. includeFile.write("// " + os.path.join(*temp) + "\n")
  671. offset,nbSamples=self.addPattern(includeFile,os.path.join(*temp))
  672. #driverFile.write(patpath)
  673. #driverFile.write("\n")
  674. self._write32(offset,driverFile)
  675. self._write32(nbSamples,driverFile)
  676. # Generate output names
  677. self._write32(len(root.outputs),driverFile)
  678. for (outid,outname) in root.outputs:
  679. #textFile.write(patid)
  680. #textFile.write("\n")
  681. self._writeString(outname.strip(),driverFile)
  682. # Parameters offsets are written
  683. # and parameter length since the length is not available in a file
  684. # like for semihosting version
  685. self._write32(len(root.parameters),driverFile)
  686. for (paramKind,parid,parpath) in root.parameters:
  687. if paramKind == TestScripts.Parser.TreeElem.PARAMFILE:
  688. temp = self._currentParamPaths.copy()
  689. temp.append(parpath)
  690. includeFile.write("// " + os.path.join(*temp) + "\n")
  691. offset,nbSamples=self.addParameter(includeFile,os.path.join(*temp))
  692. #driverFile.write(patpath)
  693. #driverFile.write("\n")
  694. driverFile.write("'p',")
  695. self._write32(offset,driverFile)
  696. self._write32(nbSamples,driverFile)
  697. # TO DO
  698. if paramKind == TestScripts.Parser.TreeElem.PARAMGEN:
  699. temp = self._currentParamPaths.copy()
  700. includeFile.write("// " + os.path.join(*temp) + "\n")
  701. driverFile.write("'g',")
  702. dimensions = len(parpath)
  703. nbOutputSamples = 1
  704. nbInputSamples = 0
  705. for c in parpath:
  706. nbOutputSamples = nbOutputSamples * len(c["INTS"])
  707. nbInputSamples = nbInputSamples + len(c["INTS"]) + 1
  708. self._write32(1,driverFile)
  709. self._write32(nbInputSamples,driverFile)
  710. self._write32(nbOutputSamples,driverFile)
  711. self._write32(dimensions,driverFile)
  712. for c in parpath:
  713. self._write32(len(c["INTS"]),driverFile)
  714. for d in c["INTS"]:
  715. self._write32(d,driverFile)
  716. # Recurse on the children
  717. for c in root:
  718. self._genDriver(c,driverFile,includeFile)
  719. self._currentPaths = oldPath.copy()
  720. self._currentParamPaths = oldParamPath.copy()
  721. def genCodeForTree(self,root,benchMode):
  722. """ Generate all files from the trees of tests
  723. Args:
  724. root (TreeElement) : Tree of test descriptions
  725. Raises:
  726. Nothing
  727. Returns:
  728. Nothing
  729. """
  730. # Get a list of all suites contained in the tree
  731. suites = self.getSuites(root,[])
  732. src = "GeneratedSource"
  733. header = "GeneratedInclude"
  734. if benchMode:
  735. src += "Bench"
  736. header += "Bench"
  737. # Generate .cpp and .h files neded to run the tests
  738. with open("%s/TestDesc.cpp" % src,"w") as sourceFile:
  739. with open("%s/TestDesc.h" % header,"w") as headerFile:
  740. headerFile.write("#include \"Test.h\"\n")
  741. headerFile.write("#include \"Pattern.h\"\n")
  742. sourceFile.write("#include \"Test.h\"\n")
  743. for s in suites:
  744. headerFile.write("#include \"%s.h\"\n" % s)
  745. self._genCode(root,"%s" % header,sourceFile,headerFile)
  746. # Generate a driver file for semihosting
  747. # (always generated for debug purpose since it is the reference format)
  748. with open("TestDesc.txt","w") as textFile:
  749. self._genText(root,textFile)
  750. # If fpga mode we need to generate
  751. # a include file version of the driver file and of
  752. # the pattern files.
  753. # Driver file is similar in this case but different from semihosting
  754. # one.
  755. if not self._fpga:
  756. with open("%s/TestDrive.h" % header,"w") as driverFile:
  757. driverFile.write("// Empty driver include in semihosting mode")
  758. with open("%s/Patterns.h" % header,"w") as includeFile:
  759. includeFile.write("// Empty pattern include in semihosting mode")
  760. else:
  761. with open("%s/TestDrive.h" % header,"w") as driverFile:
  762. driverFile.write("#ifndef _DRIVER_H_\n")
  763. driverFile.write("#define _DRIVER_H_\n")
  764. driverFile.write("__ALIGNED(8) const char testDesc[]={\n")
  765. self._offset=0
  766. with open("%s/Patterns.h" % header,"w") as includeFile:
  767. includeFile.write("#ifndef _PATTERNS_H_\n")
  768. includeFile.write("#define _PATTERNS_H_\n")
  769. includeFile.write("__ALIGNED(8) const char patterns[]={\n")
  770. self._genDriver(root,driverFile,includeFile)
  771. includeFile.write("};\n")
  772. includeFile.write("#endif\n")
  773. driverFile.write("};\n")
  774. driverFile.write("#endif\n")