Type.py revision 8188:20dbef14192d
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.isStateDecl = ("state_decl" in self)
104        self.statePermPairs = []
105
106        self.data_members = orderdict()
107
108        # Methods
109        self.methods = {}
110
111        # Enums
112        self.enums = orderdict()
113
114    @property
115    def isPrimitive(self):
116        return "primitive" in self
117    @property
118    def isNetworkMessage(self):
119        return "networkmessage" in self
120    @property
121    def isMessage(self):
122        return "message" in self
123    @property
124    def isBuffer(self):
125        return "buffer" in self
126    @property
127    def isInPort(self):
128        return "inport" in self
129    @property
130    def isOutPort(self):
131        return "outport" in self
132    @property
133    def isEnumeration(self):
134        return "enumeration" in self
135    @property
136    def isExternal(self):
137        return "external" in self
138    @property
139    def isGlobal(self):
140        return "global" in self
141    @property
142    def isInterface(self):
143        return "interface" in self
144
145    # Return false on error
146    def dataMemberAdd(self, ident, type, pairs, init_code):
147        if ident in self.data_members:
148            return False
149
150        member = DataMember(ident, type, pairs, init_code)
151        self.data_members[ident] = member
152
153        return True
154
155    def dataMemberType(self, ident):
156        return self.data_members[ident].type
157
158    def methodId(self, name, param_type_vec):
159        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
160
161    def methodIdAbstract(self, name, param_type_vec):
162        return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
163
164    def statePermPairAdd(self, state_name, perm_name):
165        self.statePermPairs.append([state_name, perm_name])
166
167    def methodAdd(self, name, return_type, param_type_vec):
168        ident = self.methodId(name, param_type_vec)
169        if ident in self.methods:
170            return False
171
172        self.methods[ident] = Method(return_type, param_type_vec)
173        return True
174
175    def enumAdd(self, ident, pairs):
176        if ident in self.enums:
177            return False
178
179        self.enums[ident] = Enumeration(ident, pairs)
180
181        # Add default
182        if "default" not in self:
183            self["default"] = "%s_NUM" % self.c_ident
184
185        return True
186
187    def writeCodeFiles(self, path):
188        if self.isExternal:
189            # Do nothing
190            pass
191        elif self.isEnumeration:
192            self.printEnumHH(path)
193            self.printEnumCC(path)
194        else:
195            # User defined structs and messages
196            self.printTypeHH(path)
197            self.printTypeCC(path)
198
199    def printTypeHH(self, path):
200        code = self.symtab.codeFormatter()
201        code('''
202/** \\file ${{self.c_ident}}.hh
203 *
204 *
205 * Auto generated C++ code started by $__file__:$__line__
206 */
207
208#ifndef __${{self.c_ident}}_HH__
209#define __${{self.c_ident}}_HH__
210
211#include <iostream>
212
213#include "mem/ruby/common/Global.hh"
214''')
215
216        for dm in self.data_members.values():
217            if not dm.type.isPrimitive:
218                code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
219
220        parent = ""
221        if "interface" in self:
222            code('#include "mem/protocol/$0.hh"', self["interface"])
223            parent = " :  public %s" % self["interface"]
224
225        code('''
226$klass ${{self.c_ident}}$parent
227{
228  public:
229    ${{self.c_ident}}()
230    {
231''', klass="class")
232
233        code.indent()
234        if not self.isGlobal:
235            code.indent()
236            for dm in self.data_members.values():
237                ident = dm.ident
238                if "default" in dm:
239                    # look for default value
240                    code('m_$ident = ${{dm["default"]}}; // default for this field')
241                elif "default" in dm.type:
242                    # Look for the type default
243                    tid = dm.type.c_ident
244                    code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
245                else:
246                    code('// m_$ident has no default')
247            code.dedent()
248        code('}')
249
250        # ******** Copy constructor ********
251        if not self.isGlobal:
252            code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
253
254            # Call superclass constructor
255            if "interface" in self:
256                code('    : ${{self["interface"]}}(other)')
257
258            code('{')
259            code.indent()
260
261            for dm in self.data_members.values():
262                code('m_${{dm.ident}} = other.m_${{dm.ident}};')
263
264            code.dedent()
265            code('}')
266
267        # ******** Full init constructor ********
268        if not self.isGlobal:
269            params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
270                       for dm in self.data_members.itervalues() ]
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            code.dedent()
287            code('}')
288
289        # create a static factory method and a clone member
290        code('''
291static ${{self.c_ident}}*
292create()
293{
294    return new ${{self.c_ident}}();
295}
296
297${{self.c_ident}}*
298clone() const
299{
300     return new ${{self.c_ident}}(*this);
301}
302''')
303
304        if not self.isGlobal:
305            # const Get methods for each field
306            code('// Const accessors methods for each field')
307            for dm in self.data_members.values():
308                code('''
309/** \\brief Const accessor method for ${{dm.ident}} field.
310 *  \\return ${{dm.ident}} field
311 */
312const ${{dm.type.c_ident}}&
313get${{dm.ident}}() const
314{
315    return m_${{dm.ident}};
316}
317''')
318
319            # Non-const Get methods for each field
320            code('// Non const Accessors methods for each field')
321            for dm in self.data_members.values():
322                code('''
323/** \\brief Non-const accessor method for ${{dm.ident}} field.
324 *  \\return ${{dm.ident}} field
325 */
326${{dm.type.c_ident}}&
327get${{dm.ident}}()
328{
329    return m_${{dm.ident}};
330}
331''')
332
333            #Set methods for each field
334            code('// Mutator methods for each field')
335            for dm in self.data_members.values():
336                code('''
337/** \\brief Mutator method for ${{dm.ident}} field */
338void
339set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
340{
341    m_${{dm.ident}} = local_${{dm.ident}};
342}
343''')
344
345        code('void print(std::ostream& out) const;')
346        code.dedent()
347        code('  //private:')
348        code.indent()
349
350        # Data members for each field
351        for dm in self.data_members.values():
352            if "abstract" not in dm:
353                const = ""
354                init = ""
355
356                # global structure
357                if self.isGlobal:
358                    const = "static const "
359
360                # init value
361                if dm.init_code:
362                    # only global structure can have init value here
363                    assert self.isGlobal
364                    init = " = %s" % (dm.init_code)
365
366                if "desc" in dm:
367                    code('/** ${{dm["desc"]}} */')
368
369                code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
370
371        code.dedent()
372        code('};')
373
374        code('''
375inline std::ostream&
376operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
377{
378    obj.print(out);
379    out << std::flush;
380    return out;
381}
382
383#endif // __${{self.c_ident}}_HH__
384''')
385
386        code.write(path, "%s.hh" % self.c_ident)
387
388    def printTypeCC(self, path):
389        code = self.symtab.codeFormatter()
390
391        code('''
392/** \\file ${{self.c_ident}}.cc
393 *
394 * Auto generated C++ code started by $__file__:$__line__
395 */
396
397#include <iostream>
398
399#include "mem/protocol/${{self.c_ident}}.hh"
400
401using namespace std;
402''')
403
404        code('''
405/** \\brief Print the state of this object */
406void
407${{self.c_ident}}::print(ostream& out) const
408{
409    out << "[${{self.c_ident}}: ";
410''')
411
412        # For each field
413        code.indent()
414        for dm in self.data_members.values():
415            code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
416
417        if self.isMessage:
418            code('out << "Time = " << getTime() << " ";')
419        code.dedent()
420
421        # Trailer
422        code('''
423    out << "]";
424}''')
425
426        code.write(path, "%s.cc" % self.c_ident)
427
428    def printEnumHH(self, path):
429        code = self.symtab.codeFormatter()
430        code('''
431/** \\file ${{self.c_ident}}.hh
432 *
433 * Auto generated C++ code started by $__file__:$__line__
434 */
435
436#ifndef __${{self.c_ident}}_HH__
437#define __${{self.c_ident}}_HH__
438
439#include <iostream>
440#include <string>
441
442#include "mem/ruby/common/Global.hh"
443''')
444        if self.isStateDecl:
445            code('#include "mem/protocol/AccessPermission.hh"')
446
447        code('''
448
449// Class definition
450/** \\enum ${{self.c_ident}}
451 *  \\brief ${{self.desc}}
452 */
453enum ${{self.c_ident}} {
454    ${{self.c_ident}}_FIRST,
455''')
456
457        code.indent()
458        # For each field
459        for i,(ident,enum) in enumerate(self.enums.iteritems()):
460            desc = enum.get("desc", "No description avaliable")
461            if i == 0:
462                init = ' = %s_FIRST' % self.c_ident
463            else:
464                init = ''
465            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
466        code.dedent()
467        code('''
468    ${{self.c_ident}}_NUM
469};
470
471// Code to convert from a string to the enumeration
472${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
473
474// Code to convert state to a string
475std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
476
477// Code to increment an enumeration type
478${{self.c_ident}} &operator++(${{self.c_ident}} &e);
479''')
480
481        # MachineType hack used to set the base component id for each Machine
482        if self.isMachineType:
483            code('''
484int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
485MachineType ${{self.c_ident}}_from_base_level(int);
486int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
487int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
488''')
489
490            for enum in self.enums.itervalues():
491                code('#define MACHINETYPE_${{enum.ident}} 1')
492
493        if self.isStateDecl:
494            code('''
495
496// Code to convert the current state to an access permission
497AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
498
499''')
500
501        # Trailer
502        code('''
503std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
504
505#endif // __${{self.c_ident}}_HH__
506''')
507
508        code.write(path, "%s.hh" % self.c_ident)
509
510    def printEnumCC(self, path):
511        code = self.symtab.codeFormatter()
512        code('''
513/** \\file ${{self.c_ident}}.hh
514 *
515 * Auto generated C++ code started by $__file__:$__line__
516 */
517
518#include <cassert>
519#include <iostream>
520#include <string>
521
522#include "base/misc.hh"
523#include "mem/protocol/${{self.c_ident}}.hh"
524
525using namespace std;
526
527''')
528
529        if self.isStateDecl:
530            code('''
531// Code to convert the current state to an access permission
532AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
533{
534    switch(obj) {
535''')
536            # For each case
537            code.indent()
538            for statePerm in self.statePermPairs:
539                code('  case ${{self.c_ident}}_${{statePerm[0]}}:')
540                code('    return AccessPermission_${{statePerm[1]}};')
541            code.dedent()
542            code ('''
543      default:
544        panic("Unknown state access permission converstion for ${{self.c_ident}}");
545    }
546}
547
548''')
549
550        if self.isMachineType:
551            for enum in self.enums.itervalues():
552                code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
553
554        code('''
555// Code for output operator
556ostream&
557operator<<(ostream& out, const ${{self.c_ident}}& obj)
558{
559    out << ${{self.c_ident}}_to_string(obj);
560    out << flush;
561    return out;
562}
563
564// Code to convert state to a string
565string
566${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
567{
568    switch(obj) {
569''')
570
571        # For each field
572        code.indent()
573        for enum in self.enums.itervalues():
574            code('  case ${{self.c_ident}}_${{enum.ident}}:')
575            code('    return "${{enum.ident}}";')
576        code.dedent()
577
578        # Trailer
579        code('''
580      default:
581        panic("Invalid range for type ${{self.c_ident}}");
582    }
583}
584
585// Code to convert from a string to the enumeration
586${{self.c_ident}}
587string_to_${{self.c_ident}}(const string& str)
588{
589''')
590
591        # For each field
592        start = ""
593        code.indent()
594        for enum in self.enums.itervalues():
595            code('${start}if (str == "${{enum.ident}}") {')
596            code('    return ${{self.c_ident}}_${{enum.ident}};')
597            start = "} else "
598        code.dedent()
599
600        code('''
601    } else {
602        panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
603    }
604}
605
606// Code to increment an enumeration type
607${{self.c_ident}}&
608operator++(${{self.c_ident}}& e)
609{
610    assert(e < ${{self.c_ident}}_NUM);
611    return e = ${{self.c_ident}}(e+1);
612}
613''')
614
615        # MachineType hack used to set the base level and number of
616        # components for each Machine
617        if self.isMachineType:
618            code('''
619/** \\brief returns the base vector index for each machine type to be
620  * used by NetDest
621  *
622  * \\return the base vector index for each machine type to be used by NetDest
623  * \\see NetDest.hh
624  */
625int
626${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
627{
628    switch(obj) {
629''')
630
631            # For each field
632            code.indent()
633            for i,enum in enumerate(self.enums.itervalues()):
634                code('  case ${{self.c_ident}}_${{enum.ident}}:')
635                code('    return $i;')
636            code.dedent()
637
638            # total num
639            code('''
640      case ${{self.c_ident}}_NUM:
641        return ${{len(self.enums)}};
642
643      default:
644        panic("Invalid range for type ${{self.c_ident}}");
645    }
646}
647
648/** \\brief returns the machine type for each base vector index used by NetDest
649 *
650 * \\return the MachineType
651 */
652MachineType
653${{self.c_ident}}_from_base_level(int type)
654{
655    switch(type) {
656''')
657
658            # For each field
659            code.indent()
660            for i,enum in enumerate(self.enums.itervalues()):
661                code('  case $i:')
662                code('    return ${{self.c_ident}}_${{enum.ident}};')
663            code.dedent()
664
665            # Trailer
666            code('''
667      default:
668        panic("Invalid range for type ${{self.c_ident}}");
669    }
670}
671
672/** \\brief The return value indicates the number of components created
673 * before a particular machine\'s components
674 *
675 * \\return the base number of components for each machine
676 */
677int
678${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
679{
680    int base = 0;
681    switch(obj) {
682''')
683
684            # For each field
685            code.indent()
686            code('  case ${{self.c_ident}}_NUM:')
687            for enum in reversed(self.enums.values()):
688                code('    base += ${{enum.ident}}_Controller::getNumControllers();')
689                code('  case ${{self.c_ident}}_${{enum.ident}}:')
690            code('    break;')
691            code.dedent()
692
693            code('''
694      default:
695        panic("Invalid range for type ${{self.c_ident}}");
696    }
697
698    return base;
699}
700
701/** \\brief returns the total number of components for each machine
702 * \\return the total number of components for each machine
703 */
704int
705${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
706{
707    switch(obj) {
708''')
709
710            # For each field
711            for enum in self.enums.itervalues():
712                code('''
713      case ${{self.c_ident}}_${{enum.ident}}:
714        return ${{enum.ident}}_Controller::getNumControllers();
715''')
716
717            # total num
718            code('''
719      case ${{self.c_ident}}_NUM:
720      default:
721        panic("Invalid range for type ${{self.c_ident}}");
722    }
723}
724''')
725
726        # Write the file
727        code.write(path, "%s.cc" % self.c_ident)
728
729__all__ = [ "Type" ]
730