Type.py revision 8602
14120Sgblack@eecs.umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
24120Sgblack@eecs.umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company
34120Sgblack@eecs.umich.edu# All rights reserved.
44120Sgblack@eecs.umich.edu#
57087Snate@binkert.org# Redistribution and use in source and binary forms, with or without
67087Snate@binkert.org# modification, are permitted provided that the following conditions are
77087Snate@binkert.org# met: redistributions of source code must retain the above copyright
87087Snate@binkert.org# notice, this list of conditions and the following disclaimer;
97087Snate@binkert.org# redistributions in binary form must reproduce the above copyright
107087Snate@binkert.org# notice, this list of conditions and the following disclaimer in the
117087Snate@binkert.org# documentation and/or other materials provided with the distribution;
127087Snate@binkert.org# neither the name of the copyright holders nor the names of its
134120Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
147087Snate@binkert.org# this software without specific prior written permission.
157087Snate@binkert.org#
167087Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177087Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187087Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197087Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207087Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217087Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224120Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237087Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244120Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254120Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264120Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274120Sgblack@eecs.umich.edu
284120Sgblack@eecs.umich.edufrom m5.util import orderdict
294120Sgblack@eecs.umich.edu
304120Sgblack@eecs.umich.edufrom slicc.util import PairContainer
314120Sgblack@eecs.umich.edufrom slicc.symbols.Symbol import Symbol
324120Sgblack@eecs.umich.edu
334120Sgblack@eecs.umich.educlass DataMember(PairContainer):
344120Sgblack@eecs.umich.edu    def __init__(self, ident, type, pairs, init_code):
354120Sgblack@eecs.umich.edu        super(DataMember, self).__init__(pairs)
364120Sgblack@eecs.umich.edu        self.ident = ident
374120Sgblack@eecs.umich.edu        self.type = type
384120Sgblack@eecs.umich.edu        self.init_code = init_code
394120Sgblack@eecs.umich.edu
404120Sgblack@eecs.umich.educlass Enumeration(PairContainer):
414120Sgblack@eecs.umich.edu    def __init__(self, ident, pairs):
424120Sgblack@eecs.umich.edu        super(Enumeration, self).__init__(pairs)
434166Sgblack@eecs.umich.edu        self.ident = ident
444166Sgblack@eecs.umich.edu
458229Snate@binkert.orgclass Method(object):
4612044Sgabeblack@google.com    def __init__(self, return_type, param_types):
4711854Sbrandon.potter@amd.com        self.return_type = return_type
484166Sgblack@eecs.umich.edu        self.param_types = param_types
494120Sgblack@eecs.umich.edu
505956Sgblack@eecs.umich.educlass Type(Symbol):
515956Sgblack@eecs.umich.edu    def __init__(self, table, ident, location, pairs, machine=None):
524120Sgblack@eecs.umich.edu        super(Type, self).__init__(table, ident, location, pairs)
534120Sgblack@eecs.umich.edu        self.c_ident = ident
547073Sgblack@eecs.umich.edu        self.abstract_ident = ""
557073Sgblack@eecs.umich.edu        if machine:
567073Sgblack@eecs.umich.edu            if self.isExternal or self.isPrimitive:
577073Sgblack@eecs.umich.edu                if "external_name" in self:
584166Sgblack@eecs.umich.edu                    self.c_ident = self["external_name"]
5911851Sbrandon.potter@amd.com            else:
604166Sgblack@eecs.umich.edu                # Append with machine name
614166Sgblack@eecs.umich.edu                self.c_ident = "%s_%s" % (machine, ident)
625962Sgblack@eecs.umich.edu
635962Sgblack@eecs.umich.edu        self.pairs.setdefault("desc", "No description avaliable")
645962Sgblack@eecs.umich.edu
655956Sgblack@eecs.umich.edu        # check for interface that this Type implements
665956Sgblack@eecs.umich.edu        if "interface" in self:
674166Sgblack@eecs.umich.edu            interface = self["interface"]
6811851Sbrandon.potter@amd.com            if interface in ("Message", "NetworkMessage"):
6911851Sbrandon.potter@amd.com                self["message"] = "yes"
705956Sgblack@eecs.umich.edu            if interface == "NetworkMessage":
715956Sgblack@eecs.umich.edu                self["networkmessage"] = "yes"
725973Sgblack@eecs.umich.edu
7311884Sbrandon.potter@amd.com        # FIXME - all of the following id comparisons are fragile hacks
744166Sgblack@eecs.umich.edu        if self.ident in ("CacheMemory", "NewCacheMemory",
754166Sgblack@eecs.umich.edu                          "TLCCacheMemory", "DNUCACacheMemory",
765962Sgblack@eecs.umich.edu                          "DNUCABankCacheMemory", "L2BankCacheMemory",
775962Sgblack@eecs.umich.edu                          "CompressedCacheMemory", "PrefetchCacheMemory"):
7811320Ssteve.reinhardt@amd.com            self["cache"] = "yes"
795962Sgblack@eecs.umich.edu
805962Sgblack@eecs.umich.edu        if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"):
815962Sgblack@eecs.umich.edu            self["tbe"] = "yes"
8212074Sspwilson2@wisc.edu
835958Sgblack@eecs.umich.edu        if self.ident == "NewTBETable":
8412074Sspwilson2@wisc.edu            self["newtbe"] = "yes"
8512074Sspwilson2@wisc.edu
8611886Sbrandon.potter@amd.com        if self.ident == "TimerTable":
8711886Sbrandon.potter@amd.com            self["timer"] = "yes"
8811886Sbrandon.potter@amd.com
8911886Sbrandon.potter@amd.com        if self.ident == "DirectoryMemory":
9011886Sbrandon.potter@amd.com            self["dir"] = "yes"
9111886Sbrandon.potter@amd.com
9211886Sbrandon.potter@amd.com        if self.ident == "PersistentTable":
9311886Sbrandon.potter@amd.com            self["persistent"] = "yes"
9411886Sbrandon.potter@amd.com
9511886Sbrandon.potter@amd.com        if self.ident == "Prefetcher":
9611886Sbrandon.potter@amd.com            self["prefetcher"] = "yes"
9711886Sbrandon.potter@amd.com
9811886Sbrandon.potter@amd.com        if self.ident == "DNUCA_Movement":
9911886Sbrandon.potter@amd.com            self["mover"] = "yes"
10011886Sbrandon.potter@amd.com
1015956Sgblack@eecs.umich.edu        self.isMachineType = (ident == "MachineType")
1024166Sgblack@eecs.umich.edu
10311851Sbrandon.potter@amd.com        self.isStateDecl = ("state_decl" in self)
1045956Sgblack@eecs.umich.edu        self.statePermPairs = []
1055956Sgblack@eecs.umich.edu
10611851Sbrandon.potter@amd.com        self.data_members = orderdict()
10711851Sbrandon.potter@amd.com
1084166Sgblack@eecs.umich.edu        # Methods
1096709Svince@csl.cornell.edu        self.methods = {}
1106709Svince@csl.cornell.edu
1116709Svince@csl.cornell.edu        # Enums
1126709Svince@csl.cornell.edu        self.enums = orderdict()
1136709Svince@csl.cornell.edu
1146709Svince@csl.cornell.edu    @property
1156709Svince@csl.cornell.edu    def isPrimitive(self):
11611886Sbrandon.potter@amd.com        return "primitive" in self
11711886Sbrandon.potter@amd.com    @property
11811886Sbrandon.potter@amd.com    def isNetworkMessage(self):
11911886Sbrandon.potter@amd.com        return "networkmessage" in self
12011886Sbrandon.potter@amd.com    @property
12111886Sbrandon.potter@amd.com    def isMessage(self):
12211886Sbrandon.potter@amd.com        return "message" in self
12311886Sbrandon.potter@amd.com    @property
12411886Sbrandon.potter@amd.com    def isBuffer(self):
12511886Sbrandon.potter@amd.com        return "buffer" in self
12611886Sbrandon.potter@amd.com    @property
12711886Sbrandon.potter@amd.com    def isInPort(self):
12811886Sbrandon.potter@amd.com        return "inport" in self
12911886Sbrandon.potter@amd.com    @property
1306709Svince@csl.cornell.edu    def isOutPort(self):
1316709Svince@csl.cornell.edu        return "outport" in self
1326709Svince@csl.cornell.edu    @property
1335956Sgblack@eecs.umich.edu    def isEnumeration(self):
13411884Sbrandon.potter@amd.com        return "enumeration" in self
13512074Sspwilson2@wisc.edu    @property
1365958Sgblack@eecs.umich.edu    def isExternal(self):
13712074Sspwilson2@wisc.edu        return "external" in self
1389552Sandreas.hansson@arm.com    @property
13911851Sbrandon.potter@amd.com    def isGlobal(self):
14012074Sspwilson2@wisc.edu        return "global" in self
14112074Sspwilson2@wisc.edu    @property
14211886Sbrandon.potter@amd.com    def isInterface(self):
14311886Sbrandon.potter@amd.com        return "interface" in self
1445956Sgblack@eecs.umich.edu
1455956Sgblack@eecs.umich.edu    # Return false on error
14611851Sbrandon.potter@amd.com    def dataMemberAdd(self, ident, type, pairs, init_code):
1475956Sgblack@eecs.umich.edu        if ident in self.data_members:
1485956Sgblack@eecs.umich.edu            return False
14911851Sbrandon.potter@amd.com
15011851Sbrandon.potter@amd.com        member = DataMember(ident, type, pairs, init_code)
1515956Sgblack@eecs.umich.edu        self.data_members[ident] = member
1525973Sgblack@eecs.umich.edu
1535973Sgblack@eecs.umich.edu        return True
1545973Sgblack@eecs.umich.edu
1555973Sgblack@eecs.umich.edu    def dataMemberType(self, ident):
1565973Sgblack@eecs.umich.edu        return self.data_members[ident].type
1575973Sgblack@eecs.umich.edu
1585973Sgblack@eecs.umich.edu    def methodId(self, name, param_type_vec):
15911886Sbrandon.potter@amd.com        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
16011886Sbrandon.potter@amd.com
16111886Sbrandon.potter@amd.com    def methodIdAbstract(self, name, param_type_vec):
16211886Sbrandon.potter@amd.com        return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
16311886Sbrandon.potter@amd.com
16411886Sbrandon.potter@amd.com    def statePermPairAdd(self, state_name, perm_name):
16511886Sbrandon.potter@amd.com        self.statePermPairs.append([state_name, perm_name])
16611886Sbrandon.potter@amd.com
16711886Sbrandon.potter@amd.com    def methodAdd(self, name, return_type, param_type_vec):
16811886Sbrandon.potter@amd.com        ident = self.methodId(name, param_type_vec)
16911886Sbrandon.potter@amd.com        if ident in self.methods:
17011886Sbrandon.potter@amd.com            return False
17111886Sbrandon.potter@amd.com
17211886Sbrandon.potter@amd.com        self.methods[ident] = Method(return_type, param_type_vec)
1735973Sgblack@eecs.umich.edu        return True
1745973Sgblack@eecs.umich.edu
1755973Sgblack@eecs.umich.edu    def enumAdd(self, ident, pairs):
1765956Sgblack@eecs.umich.edu        if ident in self.enums:
17711884Sbrandon.potter@amd.com            return False
17812074Sspwilson2@wisc.edu
1795958Sgblack@eecs.umich.edu        self.enums[ident] = Enumeration(ident, pairs)
18012044Sgabeblack@google.com
18112044Sgabeblack@google.com        # Add default
18212074Sspwilson2@wisc.edu        if "default" not in self:
18312074Sspwilson2@wisc.edu            self["default"] = "%s_NUM" % self.c_ident
18412074Sspwilson2@wisc.edu
18512074Sspwilson2@wisc.edu        return True
18612074Sspwilson2@wisc.edu
18712074Sspwilson2@wisc.edu    def writeCodeFiles(self, path):
18811886Sbrandon.potter@amd.com        if self.isExternal:
18911886Sbrandon.potter@amd.com            # Do nothing
1904166Sgblack@eecs.umich.edu            pass
19110299Salexandru.dutu@amd.com        elif self.isEnumeration:
19210299Salexandru.dutu@amd.com            self.printEnumHH(path)
19310299Salexandru.dutu@amd.com            self.printEnumCC(path)
19410299Salexandru.dutu@amd.com        else:
19512044Sgabeblack@google.com            # User defined structs and messages
19612044Sgabeblack@google.com            self.printTypeHH(path)
19710299Salexandru.dutu@amd.com            self.printTypeCC(path)
19810299Salexandru.dutu@amd.com
19910299Salexandru.dutu@amd.com    def printTypeHH(self, path):
2004166Sgblack@eecs.umich.edu        code = self.symtab.codeFormatter()
2014120Sgblack@eecs.umich.edu        code('''
2024120Sgblack@eecs.umich.edu/** \\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