Type.py revision 8602:836f8fad4a4c
16145SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
26386SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company
37553SN/A# All rights reserved.
46386SN/A#
56386SN/A# Redistribution and use in source and binary forms, with or without
66386SN/A# modification, are permitted provided that the following conditions are
76386SN/A# met: redistributions of source code must retain the above copyright
86386SN/A# notice, this list of conditions and the following disclaimer;
96386SN/A# redistributions in binary form must reproduce the above copyright
106386SN/A# notice, this list of conditions and the following disclaimer in the
116386SN/A# documentation and/or other materials provided with the distribution;
126386SN/A# neither the name of the copyright holders nor the names of its
136386SN/A# contributors may be used to endorse or promote products derived from
146386SN/A# this software without specific prior written permission.
156386SN/A#
166386SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176386SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186386SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196386SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206386SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216386SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226386SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236386SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246386SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256386SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266386SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276386SN/A
286386SN/Afrom m5.util import orderdict
296145SN/A
3011793Sbrandon.potter@amd.comfrom slicc.util import PairContainer
3111793Sbrandon.potter@amd.comfrom slicc.symbols.Symbol import Symbol
3210348Sandreas.hansson@arm.com
3311800Sbrandon.potter@amd.comclass DataMember(PairContainer):
347632SBrad.Beckmann@amd.com    def __init__(self, ident, type, pairs, init_code):
357632SBrad.Beckmann@amd.com        super(DataMember, self).__init__(pairs)
368232Snate@binkert.org        self.ident = ident
376145SN/A        self.type = type
387553SN/A        self.init_code = init_code
399365Snilay@cs.wisc.edu
409365Snilay@cs.wisc.educlass Enumeration(PairContainer):
419365Snilay@cs.wisc.edu    def __init__(self, ident, pairs):
426145SN/A        super(Enumeration, self).__init__(pairs)
437553SN/A        self.ident = ident
447553SN/A
457553SN/Aclass Method(object):
466145SN/A    def __init__(self, return_type, param_types):
476145SN/A        self.return_type = return_type
487553SN/A        self.param_types = param_types
496145SN/A
506145SN/Aclass Type(Symbol):
516145SN/A    def __init__(self, table, ident, location, pairs, machine=None):
527553SN/A        super(Type, self).__init__(table, ident, location, pairs)
537553SN/A        self.c_ident = ident
546145SN/A        self.abstract_ident = ""
557553SN/A        if machine:
567553SN/A            if self.isExternal or self.isPrimitive:
576145SN/A                if "external_name" in self:
588950Sandreas.hansson@arm.com                    self.c_ident = self["external_name"]
597553SN/A            else:
607553SN/A                # Append with machine name
617553SN/A                self.c_ident = "%s_%s" % (machine, ident)
627553SN/A
638832SAli.Saidi@ARM.com        self.pairs.setdefault("desc", "No description avaliable")
647553SN/A
657553SN/A        # check for interface that this Type implements
6610348Sandreas.hansson@arm.com        if "interface" in self:
679365Snilay@cs.wisc.edu            interface = self["interface"]
687553SN/A            if interface in ("Message", "NetworkMessage"):
697553SN/A                self["message"] = "yes"
707553SN/A            if interface == "NetworkMessage":
716145SN/A                self["networkmessage"] = "yes"
729365Snilay@cs.wisc.edu
738949Sandreas.hansson@arm.com        # FIXME - all of the following id comparisons are fragile hacks
7410566Sandreas.hansson@arm.com        if self.ident in ("CacheMemory", "NewCacheMemory",
756145SN/A                          "TLCCacheMemory", "DNUCACacheMemory",
768975Sandreas.hansson@arm.com                          "DNUCABankCacheMemory", "L2BankCacheMemory",
777553SN/A                          "CompressedCacheMemory", "PrefetchCacheMemory"):
787553SN/A            self["cache"] = "yes"
797553SN/A
807553SN/A        if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"):
817553SN/A            self["tbe"] = "yes"
827553SN/A
837553SN/A        if self.ident == "NewTBETable":
847553SN/A            self["newtbe"] = "yes"
857553SN/A
867553SN/A        if self.ident == "TimerTable":
877553SN/A            self["timer"] = "yes"
887553SN/A
897553SN/A        if self.ident == "DirectoryMemory":
906145SN/A            self["dir"] = "yes"
916145SN/A
9211320Ssteve.reinhardt@amd.com        if self.ident == "PersistentTable":
938655Sandreas.hansson@arm.com            self["persistent"] = "yes"
946145SN/A
957553SN/A        if self.ident == "Prefetcher":
9611320Ssteve.reinhardt@amd.com            self["prefetcher"] = "yes"
977553SN/A
986145SN/A        if self.ident == "DNUCA_Movement":
997553SN/A            self["mover"] = "yes"
1007553SN/A
1017553SN/A        self.isMachineType = (ident == "MachineType")
1027553SN/A
1037553SN/A        self.isStateDecl = ("state_decl" in self)
1047553SN/A        self.statePermPairs = []
1057553SN/A
1067553SN/A        self.data_members = orderdict()
1077553SN/A
1087553SN/A        # Methods
1097553SN/A        self.methods = {}
1106145SN/A
1116145SN/A        # Enums
1127553SN/A        self.enums = orderdict()
1137553SN/A
1146145SN/A    @property
1157553SN/A    def isPrimitive(self):
1166145SN/A        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() * g_eventQueue_ptr->getClock() << " ";')
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        if self.isMachineType:
448            code('#include "base/misc.hh"')
449            code('#include "mem/protocol/GenericMachineType.hh"')
450            code('#include "mem/ruby/common/Address.hh"')
451            code('#include "mem/ruby/system/NodeID.hh"')
452            code('struct MachineID;')
453
454        code('''
455
456// Class definition
457/** \\enum ${{self.c_ident}}
458 *  \\brief ${{self.desc}}
459 */
460enum ${{self.c_ident}} {
461    ${{self.c_ident}}_FIRST,
462''')
463
464        code.indent()
465        # For each field
466        for i,(ident,enum) in enumerate(self.enums.iteritems()):
467            desc = enum.get("desc", "No description avaliable")
468            if i == 0:
469                init = ' = %s_FIRST' % self.c_ident
470            else:
471                init = ''
472            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
473        code.dedent()
474        code('''
475    ${{self.c_ident}}_NUM
476};
477
478// Code to convert from a string to the enumeration
479${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
480
481// Code to convert state to a string
482std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
483
484// Code to increment an enumeration type
485${{self.c_ident}} &operator++(${{self.c_ident}} &e);
486''')
487
488        # MachineType hack used to set the base component id for each Machine
489        if self.isMachineType:
490            code('''
491int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
492MachineType ${{self.c_ident}}_from_base_level(int);
493int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
494int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
495''')
496
497            for enum in self.enums.itervalues():
498                if enum.ident == "DMA":
499                    code('''
500MachineID map_Address_to_DMA(const Address &addr);
501''')
502                code('''
503
504MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
505''')
506
507            code('''
508inline GenericMachineType
509ConvertMachToGenericMach(MachineType machType)
510{
511''')
512            for enum in self.enums.itervalues():
513                code('''
514      if (machType == MachineType_${{enum.ident}})
515          return GenericMachineType_${{enum.ident}};
516''')
517            code('''
518      panic("cannot convert to a GenericMachineType");
519}
520''')
521
522        if self.isStateDecl:
523            code('''
524
525// Code to convert the current state to an access permission
526AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
527
528''')
529
530        # Trailer
531        code('''
532std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
533
534#endif // __${{self.c_ident}}_HH__
535''')
536
537        code.write(path, "%s.hh" % self.c_ident)
538
539    def printEnumCC(self, path):
540        code = self.symtab.codeFormatter()
541        code('''
542/** \\file ${{self.c_ident}}.hh
543 *
544 * Auto generated C++ code started by $__file__:$__line__
545 */
546
547#include <cassert>
548#include <iostream>
549#include <string>
550
551#include "base/misc.hh"
552#include "mem/protocol/${{self.c_ident}}.hh"
553
554using namespace std;
555
556''')
557
558        if self.isStateDecl:
559            code('''
560// Code to convert the current state to an access permission
561AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
562{
563    switch(obj) {
564''')
565            # For each case
566            code.indent()
567            for statePerm in self.statePermPairs:
568                code('  case ${{self.c_ident}}_${{statePerm[0]}}:')
569                code('    return AccessPermission_${{statePerm[1]}};')
570            code.dedent()
571            code ('''
572      default:
573        panic("Unknown state access permission converstion for ${{self.c_ident}}");
574    }
575}
576
577''')
578
579        if self.isMachineType:
580            for enum in self.enums.itervalues():
581                code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
582            code('#include "mem/ruby/system/MachineID.hh"')
583
584        code('''
585// Code for output operator
586ostream&
587operator<<(ostream& out, const ${{self.c_ident}}& obj)
588{
589    out << ${{self.c_ident}}_to_string(obj);
590    out << flush;
591    return out;
592}
593
594// Code to convert state to a string
595string
596${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
597{
598    switch(obj) {
599''')
600
601        # For each field
602        code.indent()
603        for enum in self.enums.itervalues():
604            code('  case ${{self.c_ident}}_${{enum.ident}}:')
605            code('    return "${{enum.ident}}";')
606        code.dedent()
607
608        # Trailer
609        code('''
610      default:
611        panic("Invalid range for type ${{self.c_ident}}");
612    }
613}
614
615// Code to convert from a string to the enumeration
616${{self.c_ident}}
617string_to_${{self.c_ident}}(const string& str)
618{
619''')
620
621        # For each field
622        start = ""
623        code.indent()
624        for enum in self.enums.itervalues():
625            code('${start}if (str == "${{enum.ident}}") {')
626            code('    return ${{self.c_ident}}_${{enum.ident}};')
627            start = "} else "
628        code.dedent()
629
630        code('''
631    } else {
632        panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
633    }
634}
635
636// Code to increment an enumeration type
637${{self.c_ident}}&
638operator++(${{self.c_ident}}& e)
639{
640    assert(e < ${{self.c_ident}}_NUM);
641    return e = ${{self.c_ident}}(e+1);
642}
643''')
644
645        # MachineType hack used to set the base level and number of
646        # components for each Machine
647        if self.isMachineType:
648            code('''
649/** \\brief returns the base vector index for each machine type to be
650  * used by NetDest
651  *
652  * \\return the base vector index for each machine type to be used by NetDest
653  * \\see NetDest.hh
654  */
655int
656${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
657{
658    switch(obj) {
659''')
660
661            # For each field
662            code.indent()
663            for i,enum in enumerate(self.enums.itervalues()):
664                code('  case ${{self.c_ident}}_${{enum.ident}}:')
665                code('    return $i;')
666            code.dedent()
667
668            # total num
669            code('''
670      case ${{self.c_ident}}_NUM:
671        return ${{len(self.enums)}};
672
673      default:
674        panic("Invalid range for type ${{self.c_ident}}");
675    }
676}
677
678/** \\brief returns the machine type for each base vector index used by NetDest
679 *
680 * \\return the MachineType
681 */
682MachineType
683${{self.c_ident}}_from_base_level(int type)
684{
685    switch(type) {
686''')
687
688            # For each field
689            code.indent()
690            for i,enum in enumerate(self.enums.itervalues()):
691                code('  case $i:')
692                code('    return ${{self.c_ident}}_${{enum.ident}};')
693            code.dedent()
694
695            # Trailer
696            code('''
697      default:
698        panic("Invalid range for type ${{self.c_ident}}");
699    }
700}
701
702/** \\brief The return value indicates the number of components created
703 * before a particular machine\'s components
704 *
705 * \\return the base number of components for each machine
706 */
707int
708${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
709{
710    int base = 0;
711    switch(obj) {
712''')
713
714            # For each field
715            code.indent()
716            code('  case ${{self.c_ident}}_NUM:')
717            for enum in reversed(self.enums.values()):
718                code('    base += ${{enum.ident}}_Controller::getNumControllers();')
719                code('  case ${{self.c_ident}}_${{enum.ident}}:')
720            code('    break;')
721            code.dedent()
722
723            code('''
724      default:
725        panic("Invalid range for type ${{self.c_ident}}");
726    }
727
728    return base;
729}
730
731/** \\brief returns the total number of components for each machine
732 * \\return the total number of components for each machine
733 */
734int
735${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
736{
737    switch(obj) {
738''')
739
740            # For each field
741            for enum in self.enums.itervalues():
742                code('''
743      case ${{self.c_ident}}_${{enum.ident}}:
744        return ${{enum.ident}}_Controller::getNumControllers();
745''')
746
747            # total num
748            code('''
749      case ${{self.c_ident}}_NUM:
750      default:
751        panic("Invalid range for type ${{self.c_ident}}");
752    }
753}
754''')
755
756            for enum in self.enums.itervalues():
757                if enum.ident == "DMA":
758                    code('''
759MachineID
760map_Address_to_DMA(const Address &addr)
761{
762      MachineID dma = {MachineType_DMA, 0};
763      return dma;
764}
765''')
766
767                code('''
768
769MachineID
770get${{enum.ident}}MachineID(NodeID RubyNode)
771{
772      MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
773      return mach;
774}
775''')
776
777        # Write the file
778        code.write(path, "%s.cc" % self.c_ident)
779
780__all__ = [ "Type" ]
781