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