Type.py revision 7805:f249937228b5
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2# Copyright (c) 2009 The Hewlett-Packard Development Company
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28from m5.util import orderdict
29
30from slicc.util import PairContainer
31from slicc.symbols.Symbol import Symbol
32
33class DataMember(PairContainer):
34    def __init__(self, ident, type, pairs, init_code):
35        super(DataMember, self).__init__(pairs)
36        self.ident = ident
37        self.type = type
38        self.init_code = init_code
39
40class Enumeration(PairContainer):
41    def __init__(self, ident, pairs):
42        super(Enumeration, self).__init__(pairs)
43        self.ident = ident
44
45class Method(object):
46    def __init__(self, return_type, param_types):
47        self.return_type = return_type
48        self.param_types = param_types
49
50class Type(Symbol):
51    def __init__(self, table, ident, location, pairs, machine=None):
52        super(Type, self).__init__(table, ident, location, pairs)
53        self.c_ident = ident
54        self.abstract_ident = ""
55        if machine:
56            if self.isExternal or self.isPrimitive:
57                if "external_name" in self:
58                    self.c_ident = self["external_name"]
59            else:
60                # Append with machine name
61                self.c_ident = "%s_%s" % (machine, ident)
62
63        self.pairs.setdefault("desc", "No description avaliable")
64
65        # check for interface that this Type implements
66        if "interface" in self:
67            interface = self["interface"]
68            if interface in ("Message", "NetworkMessage"):
69                self["message"] = "yes"
70            if interface == "NetworkMessage":
71                self["networkmessage"] = "yes"
72
73        # FIXME - all of the following id comparisons are fragile hacks
74        if self.ident in ("CacheMemory", "NewCacheMemory",
75                          "TLCCacheMemory", "DNUCACacheMemory",
76                          "DNUCABankCacheMemory", "L2BankCacheMemory",
77                          "CompressedCacheMemory", "PrefetchCacheMemory"):
78            self["cache"] = "yes"
79
80        if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"):
81            self["tbe"] = "yes"
82
83        if self.ident == "NewTBETable":
84            self["newtbe"] = "yes"
85
86        if self.ident == "TimerTable":
87            self["timer"] = "yes"
88
89        if self.ident == "DirectoryMemory":
90            self["dir"] = "yes"
91
92        if self.ident == "PersistentTable":
93            self["persistent"] = "yes"
94
95        if self.ident == "Prefetcher":
96            self["prefetcher"] = "yes"
97
98        if self.ident == "DNUCA_Movement":
99            self["mover"] = "yes"
100
101        self.isMachineType = (ident == "MachineType")
102
103        self.data_members = orderdict()
104
105        # Methods
106        self.methods = {}
107
108        # Enums
109        self.enums = orderdict()
110
111    @property
112    def isPrimitive(self):
113        return "primitive" in self
114    @property
115    def isNetworkMessage(self):
116        return "networkmessage" in self
117    @property
118    def isMessage(self):
119        return "message" in self
120    @property
121    def isBuffer(self):
122        return "buffer" in self
123    @property
124    def isInPort(self):
125        return "inport" in self
126    @property
127    def isOutPort(self):
128        return "outport" in self
129    @property
130    def isEnumeration(self):
131        return "enumeration" in self
132    @property
133    def isExternal(self):
134        return "external" in self
135    @property
136    def isGlobal(self):
137        return "global" in self
138    @property
139    def isInterface(self):
140        return "interface" in self
141
142    # Return false on error
143    def dataMemberAdd(self, ident, type, pairs, init_code):
144        if ident in self.data_members:
145            return False
146
147        member = DataMember(ident, type, pairs, init_code)
148        self.data_members[ident] = member
149
150        return True
151
152    def dataMemberType(self, ident):
153        return self.data_members[ident].type
154
155    def methodId(self, name, param_type_vec):
156        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
157
158    def methodIdAbstract(self, name, param_type_vec):
159        return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
160
161    def methodAdd(self, name, return_type, param_type_vec):
162        ident = self.methodId(name, param_type_vec)
163        if ident in self.methods:
164            return False
165
166        self.methods[ident] = Method(return_type, param_type_vec)
167        return True
168
169    def enumAdd(self, ident, pairs):
170        if ident in self.enums:
171            return False
172
173        self.enums[ident] = Enumeration(ident, pairs)
174
175        # Add default
176        if "default" not in self:
177            self["default"] = "%s_NUM" % self.c_ident
178
179        return True
180
181    def writeCodeFiles(self, path):
182        if self.isExternal:
183            # Do nothing
184            pass
185        elif self.isEnumeration:
186            self.printEnumHH(path)
187            self.printEnumCC(path)
188        else:
189            # User defined structs and messages
190            self.printTypeHH(path)
191            self.printTypeCC(path)
192
193    def printTypeHH(self, path):
194        code = self.symtab.codeFormatter()
195        code('''
196/** \\file ${{self.c_ident}}.hh
197 *
198 *
199 * Auto generated C++ code started by $__file__:$__line__
200 */
201
202#ifndef __${{self.c_ident}}_HH__
203#define __${{self.c_ident}}_HH__
204
205#include <iostream>
206
207#include "mem/ruby/common/Global.hh"
208''')
209
210        for dm in self.data_members.values():
211            if not dm.type.isPrimitive:
212                code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
213
214        parent = ""
215        if "interface" in self:
216            code('#include "mem/protocol/$0.hh"', self["interface"])
217            parent = " :  public %s" % self["interface"]
218
219        code('''
220$klass ${{self.c_ident}}$parent
221{
222  public:
223    ${{self.c_ident}}()
224    {
225''', klass="class")
226
227        code.indent()
228        if not self.isGlobal:
229            code.indent()
230            for dm in self.data_members.values():
231                ident = dm.ident
232                if "default" in dm:
233                    # look for default value
234                    code('m_$ident = ${{dm["default"]}}; // default for this field')
235                elif "default" in dm.type:
236                    # Look for the type default
237                    tid = dm.type.c_ident
238                    code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
239                else:
240                    code('// m_$ident has no default')
241            code.dedent()
242        code('}')
243
244        # ******** Copy constructor ********
245        if not self.isGlobal:
246            code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
247
248            # Call superclass constructor
249            if "interface" in self:
250                code('    : ${{self["interface"]}}(other)')
251
252            code('{')
253            code.indent()
254
255            for dm in self.data_members.values():
256                code('m_${{dm.ident}} = other.m_${{dm.ident}};')
257
258            if self.isMessage:
259                code('proc_id = other.proc_id;')
260
261            code.dedent()
262            code('}')
263
264        # ******** Full init constructor ********
265        if not self.isGlobal:
266            params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
267                       for dm in self.data_members.itervalues() ]
268
269            if self.isMessage:
270                params.append('const unsigned local_proc_id')
271
272            params = ', '.join(params)
273            code('${{self.c_ident}}($params)')
274
275            # Call superclass constructor
276            if "interface" in self:
277                code('    : ${{self["interface"]}}()')
278
279            code('{')
280            code.indent()
281            for dm in self.data_members.values():
282                code('m_${{dm.ident}} = local_${{dm.ident}};')
283                if "nextLineCallHack" in dm:
284                    code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};')
285
286            if self.isMessage:
287                code('proc_id = local_proc_id;')
288
289            code.dedent()
290            code('}')
291
292        # create a static factory method and a clone member
293        code('''
294static ${{self.c_ident}}*
295create()
296{
297    return new ${{self.c_ident}}();
298}
299
300${{self.c_ident}}*
301clone() const
302{
303     return new ${{self.c_ident}}(*this);
304}
305''')
306
307        if not self.isGlobal:
308            # const Get methods for each field
309            code('// Const accessors methods for each field')
310            for dm in self.data_members.values():
311                code('''
312/** \\brief Const accessor method for ${{dm.ident}} field.
313 *  \\return ${{dm.ident}} field
314 */
315const ${{dm.type.c_ident}}&
316get${{dm.ident}}() const
317{
318    return m_${{dm.ident}};
319}
320''')
321
322            # Non-const Get methods for each field
323            code('// Non const Accessors methods for each field')
324            for dm in self.data_members.values():
325                code('''
326/** \\brief Non-const accessor method for ${{dm.ident}} field.
327 *  \\return ${{dm.ident}} field
328 */
329${{dm.type.c_ident}}&
330get${{dm.ident}}()
331{
332    return m_${{dm.ident}};
333}
334''')
335
336            #Set methods for each field
337            code('// Mutator methods for each field')
338            for dm in self.data_members.values():
339                code('''
340/** \\brief Mutator method for ${{dm.ident}} field */
341void
342set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
343{
344    m_${{dm.ident}} = local_${{dm.ident}};
345}
346''')
347
348        code('void print(std::ostream& out) const;')
349        code.dedent()
350        code('  //private:')
351        code.indent()
352
353        # Data members for each field
354        for dm in self.data_members.values():
355            if "abstract" not in dm:
356                const = ""
357                init = ""
358
359                # global structure
360                if self.isGlobal:
361                    const = "static const "
362
363                # init value
364                if dm.init_code:
365                    # only global structure can have init value here
366                    assert self.isGlobal
367                    init = " = %s" % (dm.init_code)
368
369                if "desc" in dm:
370                    code('/** ${{dm["desc"]}} */')
371
372                code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
373
374        if self.isMessage:
375            code('unsigned proc_id;')
376
377        code.dedent()
378        code('};')
379
380        code('''
381inline std::ostream&
382operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
383{
384    obj.print(out);
385    out << std::flush;
386    return out;
387}
388
389#endif // __${{self.c_ident}}_HH__
390''')
391
392        code.write(path, "%s.hh" % self.c_ident)
393
394    def printTypeCC(self, path):
395        code = self.symtab.codeFormatter()
396
397        code('''
398/** \\file ${{self.c_ident}}.cc
399 *
400 * Auto generated C++ code started by $__file__:$__line__
401 */
402
403#include <iostream>
404
405#include "mem/protocol/${{self.c_ident}}.hh"
406
407using namespace std;
408''')
409
410        code('''
411/** \\brief Print the state of this object */
412void
413${{self.c_ident}}::print(ostream& out) const
414{
415    out << "[${{self.c_ident}}: ";
416''')
417
418        # For each field
419        code.indent()
420        for dm in self.data_members.values():
421            code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
422
423        if self.isMessage:
424            code('out << "Time = " << getTime() << " ";')
425        code.dedent()
426
427        # Trailer
428        code('''
429    out << "]";
430}''')
431
432        code.write(path, "%s.cc" % self.c_ident)
433
434    def printEnumHH(self, path):
435        code = self.symtab.codeFormatter()
436        code('''
437/** \\file ${{self.c_ident}}.hh
438 *
439 * Auto generated C++ code started by $__file__:$__line__
440 */
441
442#ifndef __${{self.c_ident}}_HH__
443#define __${{self.c_ident}}_HH__
444
445#include <iostream>
446#include <string>
447
448#include "mem/ruby/common/Global.hh"
449
450// Class definition
451/** \\enum ${{self.c_ident}}
452 *  \\brief ${{self.desc}}
453 */
454enum ${{self.c_ident}} {
455    ${{self.c_ident}}_FIRST,
456''')
457
458        code.indent()
459        # For each field
460        for i,(ident,enum) in enumerate(self.enums.iteritems()):
461            desc = enum.get("desc", "No description avaliable")
462            if i == 0:
463                init = ' = %s_FIRST' % self.c_ident
464            else:
465                init = ''
466            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
467        code.dedent()
468        code('''
469    ${{self.c_ident}}_NUM
470};
471
472// Code to convert from a string to the enumeration
473${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
474
475// Code to convert state to a string
476std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
477
478// Code to increment an enumeration type
479${{self.c_ident}} &operator++(${{self.c_ident}} &e);
480''')
481
482        # MachineType hack used to set the base component id for each Machine
483        if self.isMachineType:
484            code('''
485int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
486MachineType ${{self.c_ident}}_from_base_level(int);
487int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
488int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
489''')
490
491            for enum in self.enums.itervalues():
492                code('#define MACHINETYPE_${{enum.ident}} 1')
493
494        # Trailer
495        code('''
496std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
497
498#endif // __${{self.c_ident}}_HH__
499''')
500
501        code.write(path, "%s.hh" % self.c_ident)
502
503    def printEnumCC(self, path):
504        code = self.symtab.codeFormatter()
505        code('''
506/** \\file ${{self.c_ident}}.hh
507 *
508 * Auto generated C++ code started by $__file__:$__line__
509 */
510
511#include <iostream>
512#include <string>
513
514#include "base/misc.hh"
515#include "mem/protocol/${{self.c_ident}}.hh"
516
517using namespace std;
518
519''')
520
521        if self.isMachineType:
522            for enum in self.enums.itervalues():
523                code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
524
525        code('''
526// Code for output operator
527ostream&
528operator<<(ostream& out, const ${{self.c_ident}}& obj)
529{
530    out << ${{self.c_ident}}_to_string(obj);
531    out << flush;
532    return out;
533}
534
535// Code to convert state to a string
536string
537${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
538{
539    switch(obj) {
540''')
541
542        # For each field
543        code.indent()
544        for enum in self.enums.itervalues():
545            code('  case ${{self.c_ident}}_${{enum.ident}}:')
546            code('    return "${{enum.ident}}";')
547        code.dedent()
548
549        # Trailer
550        code('''
551      default:
552        panic("Invalid range for type ${{self.c_ident}}");
553    }
554}
555
556// Code to convert from a string to the enumeration
557${{self.c_ident}}
558string_to_${{self.c_ident}}(const string& str)
559{
560''')
561
562        # For each field
563        start = ""
564        code.indent()
565        for enum in self.enums.itervalues():
566            code('${start}if (str == "${{enum.ident}}") {')
567            code('    return ${{self.c_ident}}_${{enum.ident}};')
568            start = "} else "
569        code.dedent()
570
571        code('''
572    } else {
573        panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
574    }
575}
576
577// Code to increment an enumeration type
578${{self.c_ident}}&
579operator++(${{self.c_ident}}& e)
580{
581    assert(e < ${{self.c_ident}}_NUM);
582    return e = ${{self.c_ident}}(e+1);
583}
584''')
585
586        # MachineType hack used to set the base level and number of
587        # components for each Machine
588        if self.isMachineType:
589            code('''
590/** \\brief returns the base vector index for each machine type to be
591  * used by NetDest
592  *
593  * \\return the base vector index for each machine type to be used by NetDest
594  * \\see NetDest.hh
595  */
596int
597${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
598{
599    switch(obj) {
600''')
601
602            # For each field
603            code.indent()
604            for i,enum in enumerate(self.enums.itervalues()):
605                code('  case ${{self.c_ident}}_${{enum.ident}}:')
606                code('    return $i;')
607            code.dedent()
608
609            # total num
610            code('''
611      case ${{self.c_ident}}_NUM:
612        return ${{len(self.enums)}};
613
614      default:
615        panic("Invalid range for type ${{self.c_ident}}");
616    }
617}
618
619/** \\brief returns the machine type for each base vector index used by NetDest
620 *
621 * \\return the MachineType
622 */
623MachineType
624${{self.c_ident}}_from_base_level(int type)
625{
626    switch(type) {
627''')
628
629            # For each field
630            code.indent()
631            for i,enum in enumerate(self.enums.itervalues()):
632                code('  case $i:')
633                code('    return ${{self.c_ident}}_${{enum.ident}};')
634            code.dedent()
635
636            # Trailer
637            code('''
638      default:
639        panic("Invalid range for type ${{self.c_ident}}");
640    }
641}
642
643/** \\brief The return value indicates the number of components created
644 * before a particular machine\'s components
645 *
646 * \\return the base number of components for each machine
647 */
648int
649${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
650{
651    int base = 0;
652    switch(obj) {
653''')
654
655            # For each field
656            code.indent()
657            code('  case ${{self.c_ident}}_NUM:')
658            for enum in reversed(self.enums.values()):
659                code('    base += ${{enum.ident}}_Controller::getNumControllers();')
660                code('  case ${{self.c_ident}}_${{enum.ident}}:')
661            code('    break;')
662            code.dedent()
663
664            code('''
665      default:
666        panic("Invalid range for type ${{self.c_ident}}");
667    }
668
669    return base;
670}
671
672/** \\brief returns the total number of components for each machine
673 * \\return the total number of components for each machine
674 */
675int
676${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
677{
678    switch(obj) {
679''')
680
681            # For each field
682            for enum in self.enums.itervalues():
683                code('''
684      case ${{self.c_ident}}_${{enum.ident}}:
685        return ${{enum.ident}}_Controller::getNumControllers();
686''')
687
688            # total num
689            code('''
690      case ${{self.c_ident}}_NUM:
691      default:
692        panic("Invalid range for type ${{self.c_ident}}");
693    }
694}
695''')
696
697        # Write the file
698        code.write(path, "%s.cc" % self.c_ident)
699
700__all__ = [ "Type" ]
701