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