Type.py revision 10917:c38f28fad4c3
18926Sandreas.hansson@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
27586SAli.Saidi@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company
37586SAli.Saidi@arm.com# All rights reserved.
47586SAli.Saidi@arm.com#
57586SAli.Saidi@arm.com# Redistribution and use in source and binary forms, with or without
67586SAli.Saidi@arm.com# modification, are permitted provided that the following conditions are
77586SAli.Saidi@arm.com# met: redistributions of source code must retain the above copyright
87586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer;
97586SAli.Saidi@arm.com# redistributions in binary form must reproduce the above copyright
107586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer in the
117586SAli.Saidi@arm.com# documentation and/or other materials provided with the distribution;
127586SAli.Saidi@arm.com# neither the name of the copyright holders nor the names of its
133970Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
143005Sstever@eecs.umich.edu# this software without specific prior written permission.
153005Sstever@eecs.umich.edu#
163005Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu
283005Sstever@eecs.umich.edufrom m5.util import orderdict
293005Sstever@eecs.umich.edu
303005Sstever@eecs.umich.edufrom slicc.util import PairContainer
313005Sstever@eecs.umich.edufrom slicc.symbols.Symbol import Symbol
323005Sstever@eecs.umich.edufrom slicc.symbols.Var import Var
333005Sstever@eecs.umich.edu
343005Sstever@eecs.umich.educlass DataMember(PairContainer):
353005Sstever@eecs.umich.edu    def __init__(self, ident, type, pairs, init_code):
363005Sstever@eecs.umich.edu        super(DataMember, self).__init__(pairs)
373005Sstever@eecs.umich.edu        self.ident = ident
383005Sstever@eecs.umich.edu        self.type = type
393005Sstever@eecs.umich.edu        self.init_code = init_code
403005Sstever@eecs.umich.edu
416654Snate@binkert.orgclass Enumeration(PairContainer):
426654Snate@binkert.org    def __init__(self, ident, pairs):
432889SN/A        super(Enumeration, self).__init__(pairs)
442710SN/A        self.ident = ident
456654Snate@binkert.org
466654Snate@binkert.orgclass Type(Symbol):
476654Snate@binkert.org    def __init__(self, table, ident, location, pairs, machine=None):
485457Ssaidi@eecs.umich.edu        super(Type, self).__init__(table, ident, location, pairs)
496654Snate@binkert.org        self.c_ident = ident
506654Snate@binkert.org        self.abstract_ident = ""
512934SN/A        if machine:
522549SN/A            if self.isExternal or self.isPrimitive:
532995SN/A                if "external_name" in self:
543395Shsul@eecs.umich.edu                    self.c_ident = self["external_name"]
556981SLisa.Hsu@amd.com            else:
563448Shsul@eecs.umich.edu                # Append with machine name
578920Snilay@cs.wisc.edu                self.c_ident = "%s_%s" % (machine, ident)
583444Sktlim@umich.edu
592889SN/A        self.pairs.setdefault("desc", "No description avaliable")
608920Snilay@cs.wisc.edu
618920Snilay@cs.wisc.edu        # check for interface that this Type implements
623322Shsul@eecs.umich.edu        if "interface" in self:
632710SN/A            interface = self["interface"]
642710SN/A            if interface in ("Message"):
652710SN/A                self["message"] = "yes"
662710SN/A
672710SN/A        # FIXME - all of the following id comparisons are fragile hacks
682710SN/A        if self.ident in ("CacheMemory"):
693322Shsul@eecs.umich.edu            self["cache"] = "yes"
703304Sstever@eecs.umich.edu
713322Shsul@eecs.umich.edu        if self.ident in ("TBETable"):
723322Shsul@eecs.umich.edu            self["tbe"] = "yes"
733304Sstever@eecs.umich.edu
743481Shsul@eecs.umich.edu        if self.ident == "TimerTable":
753481Shsul@eecs.umich.edu            self["timer"] = "yes"
762566SN/A
773322Shsul@eecs.umich.edu        if self.ident == "DirectoryMemory":
783322Shsul@eecs.umich.edu            self["dir"] = "yes"
792995SN/A
802995SN/A        if self.ident == "PersistentTable":
813304Sstever@eecs.umich.edu            self["persistent"] = "yes"
823304Sstever@eecs.umich.edu
833304Sstever@eecs.umich.edu        if self.ident == "Prefetcher":
842995SN/A            self["prefetcher"] = "yes"
852995SN/A
862995SN/A        self.isMachineType = (ident == "MachineType")
872917SN/A
882995SN/A        self.isStateDecl = ("state_decl" in self)
898956Sjayneel@cs.wisc.edu        self.statePermPairs = []
902995SN/A
918956Sjayneel@cs.wisc.edu        self.data_members = orderdict()
923304Sstever@eecs.umich.edu        self.methods = {}
936135Sgblack@eecs.umich.edu        self.enums = orderdict()
946135Sgblack@eecs.umich.edu
956654Snate@binkert.org    @property
963819Shsul@eecs.umich.edu    def isPrimitive(self):
976654Snate@binkert.org        return "primitive" in self
985222Sksewell@umich.edu
996654Snate@binkert.org    @property
1003819Shsul@eecs.umich.edu    def isMessage(self):
1016654Snate@binkert.org        return "message" in self
1027925Sgblack@eecs.umich.edu    @property
1037586SAli.Saidi@arm.com    def isBuffer(self):
1048061SAli.Saidi@ARM.com        return "buffer" in self
1058061SAli.Saidi@ARM.com    @property
1068061SAli.Saidi@ARM.com    def isInPort(self):
1073819Shsul@eecs.umich.edu        return "inport" in self
1089059Snilay@cs.wisc.edu    @property
1093819Shsul@eecs.umich.edu    def isOutPort(self):
1103873Sbinkertn@umich.edu        return "outport" in self
1113873Sbinkertn@umich.edu    @property
1123873Sbinkertn@umich.edu    def isEnumeration(self):
1133873Sbinkertn@umich.edu        return "enumeration" in self
1143873Sbinkertn@umich.edu    @property
1153873Sbinkertn@umich.edu    def isExternal(self):
1168659SAli.Saidi@ARM.com        return "external" in self
1178659SAli.Saidi@ARM.com    @property
1186995Sgblack@eecs.umich.edu    def isGlobal(self):
1193668Srdreslin@umich.edu        return "global" in self
1208713Sandreas.hansson@arm.com    @property
1218713Sandreas.hansson@arm.com    def isInterface(self):
1228713Sandreas.hansson@arm.com        return "interface" in self
1238713Sandreas.hansson@arm.com
1246636Ssteve.reinhardt@amd.com    # Return false on error
1258894Ssaidi@eecs.umich.edu    def addDataMember(self, ident, type, pairs, init_code):
1268839Sandreas.hansson@arm.com        if ident in self.data_members:
1278839Sandreas.hansson@arm.com            return False
1288713Sandreas.hansson@arm.com
1298713Sandreas.hansson@arm.com        member = DataMember(ident, type, pairs, init_code)
1308870SAli.Saidi@ARM.com        self.data_members[ident] = member
1318839Sandreas.hansson@arm.com
1328839Sandreas.hansson@arm.com        var = Var(self.symtab, ident, self.location, type,
1335142Ssaidi@eecs.umich.edu                "m_%s" % ident, {}, None)
1348926Sandreas.hansson@arm.com        self.symtab.registerSym(ident, var)
1358926Sandreas.hansson@arm.com        return True
1368926Sandreas.hansson@arm.com
1378926Sandreas.hansson@arm.com    def dataMemberType(self, ident):
1383312Sstever@eecs.umich.edu        return self.data_members[ident].type
1394968Sacolyte@umich.edu
1408926Sandreas.hansson@arm.com    def methodId(self, name, param_type_vec):
1418887Sgeoffrey.blake@arm.com        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
1428887Sgeoffrey.blake@arm.com
1438887Sgeoffrey.blake@arm.com    def methodIdAbstract(self, name, param_type_vec):
1448887Sgeoffrey.blake@arm.com        return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
1454968Sacolyte@umich.edu
1463005Sstever@eecs.umich.edu    def statePermPairAdd(self, state_name, perm_name):
1476654Snate@binkert.org        self.statePermPairs.append([state_name, perm_name])
1483819Shsul@eecs.umich.edu
1496654Snate@binkert.org    def addFunc(self, func):
1505222Sksewell@umich.edu        ident = self.methodId(func.ident, func.param_types)
1516654Snate@binkert.org        if ident in self.methods:
1523819Shsul@eecs.umich.edu            return False
1536654Snate@binkert.org
1546135Sgblack@eecs.umich.edu        self.methods[ident] = func
1557586SAli.Saidi@arm.com        return True
1568661SAli.Saidi@ARM.com
1578661SAli.Saidi@ARM.com    def addEnum(self, ident, pairs):
1583322Shsul@eecs.umich.edu        if ident in self.enums:
1598863Snilay@cs.wisc.edu            return False
1607876Sgblack@eecs.umich.edu
1614968Sacolyte@umich.edu        self.enums[ident] = Enumeration(ident, pairs)
1628926Sandreas.hansson@arm.com
1634837Ssaidi@eecs.umich.edu        # Add default
1644837Ssaidi@eecs.umich.edu        if "default" not in self:
1658810SAli.Saidi@ARM.com            self["default"] = "%s_NUM" % self.c_ident
1668870SAli.Saidi@ARM.com
1678845Sandreas.hansson@arm.com        return True
1688845Sandreas.hansson@arm.com
1694837Ssaidi@eecs.umich.edu    def writeCodeFiles(self, path, includes):
1708659SAli.Saidi@ARM.com        if self.isExternal:
1718801Sgblack@eecs.umich.edu            # Do nothing
1723005Sstever@eecs.umich.edu            pass
1738801Sgblack@eecs.umich.edu        elif self.isEnumeration:
1743005Sstever@eecs.umich.edu            self.printEnumHH(path)
1753005Sstever@eecs.umich.edu            self.printEnumCC(path)
1763005Sstever@eecs.umich.edu        else:
1772566SN/A            # User defined structs and messages
1787861Sgblack@eecs.umich.edu            self.printTypeHH(path)
1797861Sgblack@eecs.umich.edu            self.printTypeCC(path)
1807861Sgblack@eecs.umich.edu
1818635Schris.emmons@arm.com    def printTypeHH(self, path):
1828635Schris.emmons@arm.com        code = self.symtab.codeFormatter()
1838635Schris.emmons@arm.com        code('''
1849061Snilay@cs.wisc.edu/** \\file ${{self.c_ident}}.hh
1853481Shsul@eecs.umich.edu *
186 *
187 * Auto generated C++ code started by $__file__:$__line__
188 */
189
190#ifndef __${{self.c_ident}}_HH__
191#define __${{self.c_ident}}_HH__
192
193#include <iostream>
194
195#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
196''')
197
198        for dm in self.data_members.values():
199            if not dm.type.isPrimitive:
200                code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
201
202        parent = ""
203        if "interface" in self:
204            code('#include "mem/protocol/$0.hh"', self["interface"])
205            parent = " :  public %s" % self["interface"]
206
207        code('''
208$klass ${{self.c_ident}}$parent
209{
210  public:
211    ${{self.c_ident}}
212''', klass="class")
213
214        if self.isMessage:
215            code('(Tick curTime) : %s(curTime) {' % self["interface"])
216        else:
217            code('()\n\t\t{')
218
219        code.indent()
220        if not self.isGlobal:
221            code.indent()
222            for dm in self.data_members.values():
223                ident = dm.ident
224                if "default" in dm:
225                    # look for default value
226                    code('m_$ident = ${{dm["default"]}}; // default for this field')
227                elif "default" in dm.type:
228                    # Look for the type default
229                    tid = dm.type.c_ident
230                    code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
231                else:
232                    code('// m_$ident has no default')
233            code.dedent()
234        code('}')
235
236        # ******** Copy constructor ********
237        if not self.isGlobal:
238            code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
239
240            # Call superclass constructor
241            if "interface" in self:
242                code('    : ${{self["interface"]}}(other)')
243
244            code('{')
245            code.indent()
246
247            for dm in self.data_members.values():
248                code('m_${{dm.ident}} = other.m_${{dm.ident}};')
249
250            code.dedent()
251            code('}')
252
253        # ******** Full init constructor ********
254        if not self.isGlobal:
255            params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
256                       for dm in self.data_members.itervalues() ]
257            params = ', '.join(params)
258
259            if self.isMessage:
260                params = "const Tick curTime, " + params
261
262            code('${{self.c_ident}}($params)')
263
264            # Call superclass constructor
265            if "interface" in self:
266                if self.isMessage:
267                    code('    : ${{self["interface"]}}(curTime)')
268                else:
269                    code('    : ${{self["interface"]}}()')
270
271            code('{')
272            code.indent()
273            for dm in self.data_members.values():
274                code('m_${{dm.ident}} = local_${{dm.ident}};')
275                if "nextLineCallHack" in dm:
276                    code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};')
277
278            code.dedent()
279            code('}')
280
281        # create a clone member
282        if self.isMessage:
283            code('''
284MsgPtr
285clone() const
286{
287     return std::shared_ptr<Message>(new ${{self.c_ident}}(*this));
288}
289''')
290        else:
291            code('''
292${{self.c_ident}}*
293clone() const
294{
295     return new ${{self.c_ident}}(*this);
296}
297''')
298
299        if not self.isGlobal:
300            # const Get methods for each field
301            code('// Const accessors methods for each field')
302            for dm in self.data_members.values():
303                code('''
304/** \\brief Const accessor method for ${{dm.ident}} field.
305 *  \\return ${{dm.ident}} field
306 */
307const ${{dm.type.c_ident}}&
308get${{dm.ident}}() const
309{
310    return m_${{dm.ident}};
311}
312''')
313
314            # Non-const Get methods for each field
315            code('// Non const Accessors methods for each field')
316            for dm in self.data_members.values():
317                code('''
318/** \\brief Non-const accessor method for ${{dm.ident}} field.
319 *  \\return ${{dm.ident}} field
320 */
321${{dm.type.c_ident}}&
322get${{dm.ident}}()
323{
324    return m_${{dm.ident}};
325}
326''')
327
328            #Set methods for each field
329            code('// Mutator methods for each field')
330            for dm in self.data_members.values():
331                code('''
332/** \\brief Mutator method for ${{dm.ident}} field */
333void
334set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
335{
336    m_${{dm.ident}} = local_${{dm.ident}};
337}
338''')
339
340        code('void print(std::ostream& out) const;')
341        code.dedent()
342        code('  //private:')
343        code.indent()
344
345        # Data members for each field
346        for dm in self.data_members.values():
347            if "abstract" not in dm:
348                const = ""
349                init = ""
350
351                # global structure
352                if self.isGlobal:
353                    const = "static const "
354
355                # init value
356                if dm.init_code:
357                    # only global structure can have init value here
358                    assert self.isGlobal
359                    init = " = %s" % (dm.init_code)
360
361                if "desc" in dm:
362                    code('/** ${{dm["desc"]}} */')
363
364                code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
365
366        # Prototypes for methods defined for the Type
367        for item in self.methods:
368            proto = self.methods[item].prototype
369            if proto:
370                code('$proto')
371
372        code.dedent()
373        code('};')
374
375        code('''
376inline std::ostream&
377operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
378{
379    obj.print(out);
380    out << std::flush;
381    return out;
382}
383
384#endif // __${{self.c_ident}}_HH__
385''')
386
387        code.write(path, "%s.hh" % self.c_ident)
388
389    def printTypeCC(self, path):
390        code = self.symtab.codeFormatter()
391
392        code('''
393/** \\file ${{self.c_ident}}.cc
394 *
395 * Auto generated C++ code started by $__file__:$__line__
396 */
397
398#include <iostream>
399#include <memory>
400
401#include "mem/protocol/${{self.c_ident}}.hh"
402#include "mem/ruby/common/Global.hh"
403#include "mem/ruby/system/System.hh"
404
405using namespace std;
406''')
407
408        code('''
409/** \\brief Print the state of this object */
410void
411${{self.c_ident}}::print(ostream& out) const
412{
413    out << "[${{self.c_ident}}: ";
414''')
415
416        # For each field
417        code.indent()
418        for dm in self.data_members.values():
419            code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
420
421        if self.isMessage:
422            code('out << "Time = " << g_system_ptr->clockPeriod() * getTime() << " ";')
423        code.dedent()
424
425        # Trailer
426        code('''
427    out << "]";
428}''')
429
430        # print the code for the methods in the type
431        for item in self.methods:
432            code(self.methods[item].generateCode())
433
434        code.write(path, "%s.cc" % self.c_ident)
435
436    def printEnumHH(self, path):
437        code = self.symtab.codeFormatter()
438        code('''
439/** \\file ${{self.c_ident}}.hh
440 *
441 * Auto generated C++ code started by $__file__:$__line__
442 */
443
444#ifndef __${{self.c_ident}}_HH__
445#define __${{self.c_ident}}_HH__
446
447#include <iostream>
448#include <string>
449
450''')
451        if self.isStateDecl:
452            code('#include "mem/protocol/AccessPermission.hh"')
453
454        if self.isMachineType:
455            code('#include "base/misc.hh"')
456            code('#include "mem/ruby/common/Address.hh"')
457            code('struct MachineID;')
458
459        code('''
460
461// Class definition
462/** \\enum ${{self.c_ident}}
463 *  \\brief ${{self.desc}}
464 */
465enum ${{self.c_ident}} {
466    ${{self.c_ident}}_FIRST,
467''')
468
469        code.indent()
470        # For each field
471        for i,(ident,enum) in enumerate(self.enums.iteritems()):
472            desc = enum.get("desc", "No description avaliable")
473            if i == 0:
474                init = ' = %s_FIRST' % self.c_ident
475            else:
476                init = ''
477            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
478        code.dedent()
479        code('''
480    ${{self.c_ident}}_NUM
481};
482
483// Code to convert from a string to the enumeration
484${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
485
486// Code to convert state to a string
487std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
488
489// Code to increment an enumeration type
490${{self.c_ident}} &operator++(${{self.c_ident}} &e);
491''')
492
493        # MachineType hack used to set the base component id for each Machine
494        if self.isMachineType:
495            code('''
496int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
497MachineType ${{self.c_ident}}_from_base_level(int);
498int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
499int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
500''')
501
502            for enum in self.enums.itervalues():
503                if enum.ident == "DMA":
504                    code('''
505MachineID map_Address_to_DMA(const Address &addr);
506''')
507                code('''
508
509MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
510''')
511
512        if self.isStateDecl:
513            code('''
514
515// Code to convert the current state to an access permission
516AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
517
518''')
519
520        # Trailer
521        code('''
522std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
523
524#endif // __${{self.c_ident}}_HH__
525''')
526
527        code.write(path, "%s.hh" % self.c_ident)
528
529    def printEnumCC(self, path):
530        code = self.symtab.codeFormatter()
531        code('''
532/** \\file ${{self.c_ident}}.hh
533 *
534 * Auto generated C++ code started by $__file__:$__line__
535 */
536
537#include <cassert>
538#include <iostream>
539#include <string>
540
541#include "base/misc.hh"
542#include "mem/protocol/${{self.c_ident}}.hh"
543
544using namespace std;
545
546''')
547
548        if self.isStateDecl:
549            code('''
550// Code to convert the current state to an access permission
551AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
552{
553    switch(obj) {
554''')
555            # For each case
556            code.indent()
557            for statePerm in self.statePermPairs:
558                code('  case ${{self.c_ident}}_${{statePerm[0]}}:')
559                code('    return AccessPermission_${{statePerm[1]}};')
560            code.dedent()
561            code ('''
562      default:
563        panic("Unknown state access permission converstion for ${{self.c_ident}}");
564    }
565}
566
567''')
568
569        if self.isMachineType:
570            for enum in self.enums.itervalues():
571                if enum.get("Primary"):
572                    code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
573            code('#include "mem/ruby/common/MachineID.hh"')
574
575        code('''
576// Code for output operator
577ostream&
578operator<<(ostream& out, const ${{self.c_ident}}& obj)
579{
580    out << ${{self.c_ident}}_to_string(obj);
581    out << flush;
582    return out;
583}
584
585// Code to convert state to a string
586string
587${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
588{
589    switch(obj) {
590''')
591
592        # For each field
593        code.indent()
594        for enum in self.enums.itervalues():
595            code('  case ${{self.c_ident}}_${{enum.ident}}:')
596            code('    return "${{enum.ident}}";')
597        code.dedent()
598
599        # Trailer
600        code('''
601      default:
602        panic("Invalid range for type ${{self.c_ident}}");
603    }
604}
605
606// Code to convert from a string to the enumeration
607${{self.c_ident}}
608string_to_${{self.c_ident}}(const string& str)
609{
610''')
611
612        # For each field
613        start = ""
614        code.indent()
615        for enum in self.enums.itervalues():
616            code('${start}if (str == "${{enum.ident}}") {')
617            code('    return ${{self.c_ident}}_${{enum.ident}};')
618            start = "} else "
619        code.dedent()
620
621        code('''
622    } else {
623        panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
624    }
625}
626
627// Code to increment an enumeration type
628${{self.c_ident}}&
629operator++(${{self.c_ident}}& e)
630{
631    assert(e < ${{self.c_ident}}_NUM);
632    return e = ${{self.c_ident}}(e+1);
633}
634''')
635
636        # MachineType hack used to set the base level and number of
637        # components for each Machine
638        if self.isMachineType:
639            code('''
640/** \\brief returns the base vector index for each machine type to be
641  * used by NetDest
642  *
643  * \\return the base vector index for each machine type to be used by NetDest
644  * \\see NetDest.hh
645  */
646int
647${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
648{
649    switch(obj) {
650''')
651
652            # For each field
653            code.indent()
654            for i,enum in enumerate(self.enums.itervalues()):
655                code('  case ${{self.c_ident}}_${{enum.ident}}:')
656                code('    return $i;')
657            code.dedent()
658
659            # total num
660            code('''
661      case ${{self.c_ident}}_NUM:
662        return ${{len(self.enums)}};
663
664      default:
665        panic("Invalid range for type ${{self.c_ident}}");
666    }
667}
668
669/** \\brief returns the machine type for each base vector index used by NetDest
670 *
671 * \\return the MachineType
672 */
673MachineType
674${{self.c_ident}}_from_base_level(int type)
675{
676    switch(type) {
677''')
678
679            # For each field
680            code.indent()
681            for i,enum in enumerate(self.enums.itervalues()):
682                code('  case $i:')
683                code('    return ${{self.c_ident}}_${{enum.ident}};')
684            code.dedent()
685
686            # Trailer
687            code('''
688      default:
689        panic("Invalid range for type ${{self.c_ident}}");
690    }
691}
692
693/** \\brief The return value indicates the number of components created
694 * before a particular machine\'s components
695 *
696 * \\return the base number of components for each machine
697 */
698int
699${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
700{
701    int base = 0;
702    switch(obj) {
703''')
704
705            # For each field
706            code.indent()
707            code('  case ${{self.c_ident}}_NUM:')
708            for enum in reversed(self.enums.values()):
709                # Check if there is a defined machine with this type
710                if enum.get("Primary"):
711                    code('    base += ${{enum.ident}}_Controller::getNumControllers();')
712                else:
713                    code('    base += 0;')
714                code('  case ${{self.c_ident}}_${{enum.ident}}:')
715            code('    break;')
716            code.dedent()
717
718            code('''
719      default:
720        panic("Invalid range for type ${{self.c_ident}}");
721    }
722
723    return base;
724}
725
726/** \\brief returns the total number of components for each machine
727 * \\return the total number of components for each machine
728 */
729int
730${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
731{
732    switch(obj) {
733''')
734
735            # For each field
736            for enum in self.enums.itervalues():
737                code('case ${{self.c_ident}}_${{enum.ident}}:')
738                if enum.get("Primary"):
739                    code('return ${{enum.ident}}_Controller::getNumControllers();')
740                else:
741                    code('return 0;')
742
743            # total num
744            code('''
745      case ${{self.c_ident}}_NUM:
746      default:
747        panic("Invalid range for type ${{self.c_ident}}");
748    }
749}
750''')
751
752            for enum in self.enums.itervalues():
753                if enum.ident == "DMA":
754                    code('''
755MachineID
756map_Address_to_DMA(const Address &addr)
757{
758      MachineID dma = {MachineType_DMA, 0};
759      return dma;
760}
761''')
762
763                code('''
764
765MachineID
766get${{enum.ident}}MachineID(NodeID RubyNode)
767{
768      MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
769      return mach;
770}
771''')
772
773        # Write the file
774        code.write(path, "%s.cc" % self.c_ident)
775
776__all__ = [ "Type" ]
777