Type.py revision 11283:4cc8b312f026
14679Sgblack@eecs.umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
24679Sgblack@eecs.umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company
34679Sgblack@eecs.umich.edu# All rights reserved.
44679Sgblack@eecs.umich.edu#
54679Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
64679Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
74679Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
84679Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
94679Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
104679Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
114679Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
124679Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
134679Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
144679Sgblack@eecs.umich.edu# this software without specific prior written permission.
154679Sgblack@eecs.umich.edu#
164679Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174679Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184679Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194679Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204679Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214679Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224679Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234679Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244679Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254679Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264679Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274679Sgblack@eecs.umich.edu
284679Sgblack@eecs.umich.edufrom m5.util import orderdict
294679Sgblack@eecs.umich.edu
304679Sgblack@eecs.umich.edufrom slicc.util import PairContainer
314679Sgblack@eecs.umich.edufrom slicc.symbols.Symbol import Symbol
324679Sgblack@eecs.umich.edufrom slicc.symbols.Var import Var
334679Sgblack@eecs.umich.edu
344679Sgblack@eecs.umich.educlass DataMember(Var):
354679Sgblack@eecs.umich.edu    def __init__(self, symtab, ident, location, type, code, pairs,
364679Sgblack@eecs.umich.edu                 machine, init_code):
374679Sgblack@eecs.umich.edu        super(DataMember, self).__init__(symtab, ident, location, type,
384679Sgblack@eecs.umich.edu                                         code, pairs, machine)
394679Sgblack@eecs.umich.edu        self.init_code = init_code
404679Sgblack@eecs.umich.edu
414679Sgblack@eecs.umich.educlass Enumeration(PairContainer):
424679Sgblack@eecs.umich.edu    def __init__(self, ident, pairs):
434679Sgblack@eecs.umich.edu        super(Enumeration, self).__init__(pairs)
444679Sgblack@eecs.umich.edu        self.ident = ident
454679Sgblack@eecs.umich.edu        self.primary = False
464679Sgblack@eecs.umich.edu
474679Sgblack@eecs.umich.educlass Type(Symbol):
484679Sgblack@eecs.umich.edu    def __init__(self, table, ident, location, pairs, machine=None):
494679Sgblack@eecs.umich.edu        super(Type, self).__init__(table, ident, location, pairs)
504679Sgblack@eecs.umich.edu        self.c_ident = ident
514679Sgblack@eecs.umich.edu        self.abstract_ident = ""
524679Sgblack@eecs.umich.edu        if machine:
534679Sgblack@eecs.umich.edu            if self.isExternal or self.isPrimitive:
544679Sgblack@eecs.umich.edu                if "external_name" in self:
554679Sgblack@eecs.umich.edu                    self.c_ident = self["external_name"]
564679Sgblack@eecs.umich.edu            else:
574679Sgblack@eecs.umich.edu                # Append with machine name
584679Sgblack@eecs.umich.edu                self.c_ident = "%s_%s" % (machine, ident)
594679Sgblack@eecs.umich.edu
604679Sgblack@eecs.umich.edu        self.pairs.setdefault("desc", "No description avaliable")
614679Sgblack@eecs.umich.edu
624679Sgblack@eecs.umich.edu        # check for interface that this Type implements
634679Sgblack@eecs.umich.edu        if "interface" in self:
644679Sgblack@eecs.umich.edu            interface = self["interface"]
654679Sgblack@eecs.umich.edu            if interface in ("Message"):
664679Sgblack@eecs.umich.edu                self["message"] = "yes"
674679Sgblack@eecs.umich.edu
684688Sgblack@eecs.umich.edu        # FIXME - all of the following id comparisons are fragile hacks
694679Sgblack@eecs.umich.edu        if self.ident in ("CacheMemory"):
704679Sgblack@eecs.umich.edu            self["cache"] = "yes"
714679Sgblack@eecs.umich.edu
724688Sgblack@eecs.umich.edu        if self.ident in ("TBETable"):
734688Sgblack@eecs.umich.edu            self["tbe"] = "yes"
744688Sgblack@eecs.umich.edu
754804Sgblack@eecs.umich.edu        if self.ident == "TimerTable":
764688Sgblack@eecs.umich.edu            self["timer"] = "yes"
774688Sgblack@eecs.umich.edu
784688Sgblack@eecs.umich.edu        if self.ident == "DirectoryMemory":
794688Sgblack@eecs.umich.edu            self["dir"] = "yes"
804688Sgblack@eecs.umich.edu
814688Sgblack@eecs.umich.edu        if self.ident == "PersistentTable":
826345Sgblack@eecs.umich.edu            self["persistent"] = "yes"
834688Sgblack@eecs.umich.edu
844688Sgblack@eecs.umich.edu        if self.ident == "Prefetcher":
854688Sgblack@eecs.umich.edu            self["prefetcher"] = "yes"
864688Sgblack@eecs.umich.edu
874688Sgblack@eecs.umich.edu        self.isMachineType = (ident == "MachineType")
886345Sgblack@eecs.umich.edu
894688Sgblack@eecs.umich.edu        self.isStateDecl = ("state_decl" in self)
904688Sgblack@eecs.umich.edu        self.statePermPairs = []
914804Sgblack@eecs.umich.edu
924688Sgblack@eecs.umich.edu        self.data_members = orderdict()
934688Sgblack@eecs.umich.edu        self.methods = {}
944688Sgblack@eecs.umich.edu        self.enums = orderdict()
954688Sgblack@eecs.umich.edu
964713Sgblack@eecs.umich.edu    @property
974713Sgblack@eecs.umich.edu    def isPrimitive(self):
984688Sgblack@eecs.umich.edu        return "primitive" in self
994688Sgblack@eecs.umich.edu
1004688Sgblack@eecs.umich.edu    @property
1014688Sgblack@eecs.umich.edu    def isMessage(self):
1024688Sgblack@eecs.umich.edu        return "message" in self
1034679Sgblack@eecs.umich.edu    @property
1044679Sgblack@eecs.umich.edu    def isBuffer(self):
1054679Sgblack@eecs.umich.edu        return "buffer" in self
1064679Sgblack@eecs.umich.edu    @property
1074679Sgblack@eecs.umich.edu    def isInPort(self):
1084679Sgblack@eecs.umich.edu        return "inport" in self
1094679Sgblack@eecs.umich.edu    @property
1106345Sgblack@eecs.umich.edu    def isOutPort(self):
1114688Sgblack@eecs.umich.edu        return "outport" in self
1124679Sgblack@eecs.umich.edu    @property
1134688Sgblack@eecs.umich.edu    def isEnumeration(self):
1144679Sgblack@eecs.umich.edu        return "enumeration" in self
1154688Sgblack@eecs.umich.edu    @property
1164679Sgblack@eecs.umich.edu    def isExternal(self):
1176345Sgblack@eecs.umich.edu        return "external" in self
1184679Sgblack@eecs.umich.edu    @property
1194679Sgblack@eecs.umich.edu    def isGlobal(self):
1204679Sgblack@eecs.umich.edu        return "global" in self
1214679Sgblack@eecs.umich.edu    @property
1224679Sgblack@eecs.umich.edu    def isInterface(self):
1234679Sgblack@eecs.umich.edu        return "interface" in self
1244679Sgblack@eecs.umich.edu
1254688Sgblack@eecs.umich.edu    # Return false on error
1264679Sgblack@eecs.umich.edu    def addDataMember(self, ident, type, pairs, init_code):
1274679Sgblack@eecs.umich.edu        if ident in self.data_members:
1284679Sgblack@eecs.umich.edu            return False
1294679Sgblack@eecs.umich.edu
1304679Sgblack@eecs.umich.edu        member = DataMember(self.symtab, ident, self.location, type,
1314679Sgblack@eecs.umich.edu                            "m_%s" % ident, pairs, None, init_code)
1324679Sgblack@eecs.umich.edu
1334679Sgblack@eecs.umich.edu        self.data_members[ident] = member
1344679Sgblack@eecs.umich.edu        self.symtab.registerSym(ident, member)
1356345Sgblack@eecs.umich.edu        return True
1364688Sgblack@eecs.umich.edu
1374679Sgblack@eecs.umich.edu    def dataMemberType(self, ident):
1384688Sgblack@eecs.umich.edu        return self.data_members[ident].type
1394679Sgblack@eecs.umich.edu
1404688Sgblack@eecs.umich.edu    def methodId(self, name, param_type_vec):
1414679Sgblack@eecs.umich.edu        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
1424688Sgblack@eecs.umich.edu
1434679Sgblack@eecs.umich.edu    def methodIdAbstract(self, name, param_type_vec):
1444679Sgblack@eecs.umich.edu        return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
1454679Sgblack@eecs.umich.edu
1464679Sgblack@eecs.umich.edu    def statePermPairAdd(self, state_name, perm_name):
1474679Sgblack@eecs.umich.edu        self.statePermPairs.append([state_name, perm_name])
1484679Sgblack@eecs.umich.edu
1494679Sgblack@eecs.umich.edu    def addFunc(self, func):
1504679Sgblack@eecs.umich.edu        ident = self.methodId(func.ident, func.param_types)
1514679Sgblack@eecs.umich.edu        if ident in self.methods:
152            return False
153
154        self.methods[ident] = func
155        return True
156
157    def addEnum(self, ident, pairs):
158        if ident in self.enums:
159            return False
160
161        self.enums[ident] = Enumeration(ident, pairs)
162
163        # Add default
164        if "default" not in self:
165            self["default"] = "%s_NUM" % self.c_ident
166
167        return True
168
169    ## Used to check if an enum has been already used and therefore
170    ## should not be used again.
171    def checkEnum(self, ident):
172        if ident in self.enums and not self.enums[ident].primary:
173            self.enums[ident].primary = True
174            return True
175        return False
176
177    def writeCodeFiles(self, path, includes):
178        if self.isExternal:
179            # Do nothing
180            pass
181        elif self.isEnumeration:
182            self.printEnumHH(path)
183            self.printEnumCC(path)
184        else:
185            # User defined structs and messages
186            self.printTypeHH(path)
187            self.printTypeCC(path)
188
189    def printTypeHH(self, path):
190        code = self.symtab.codeFormatter()
191        code('''
192/** \\file ${{self.c_ident}}.hh
193 *
194 *
195 * Auto generated C++ code started by $__file__:$__line__
196 */
197
198#ifndef __${{self.c_ident}}_HH__
199#define __${{self.c_ident}}_HH__
200
201#include <iostream>
202
203#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
204''')
205
206        for dm in self.data_members.values():
207            if not dm.type.isPrimitive:
208                code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
209
210        parent = ""
211        if "interface" in self:
212            code('#include "mem/protocol/$0.hh"', self["interface"])
213            parent = " :  public %s" % self["interface"]
214
215        code('''
216$klass ${{self.c_ident}}$parent
217{
218  public:
219    ${{self.c_ident}}
220''', klass="class")
221
222        if self.isMessage:
223            code('(Tick curTime) : %s(curTime) {' % self["interface"])
224        else:
225            code('()\n\t\t{')
226
227        code.indent()
228        if not self.isGlobal:
229            code.indent()
230            for dm in self.data_members.values():
231                ident = dm.ident
232                if "default" in dm:
233                    # look for default value
234                    code('m_$ident = ${{dm["default"]}}; // default for this field')
235                elif "default" in dm.type:
236                    # Look for the type default
237                    tid = dm.type.c_ident
238                    code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
239                else:
240                    code('// m_$ident has no default')
241            code.dedent()
242        code('}')
243
244        # ******** Copy constructor ********
245        if not self.isGlobal:
246            code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
247
248            # Call superclass constructor
249            if "interface" in self:
250                code('    : ${{self["interface"]}}(other)')
251
252            code('{')
253            code.indent()
254
255            for dm in self.data_members.values():
256                code('m_${{dm.ident}} = other.m_${{dm.ident}};')
257
258            code.dedent()
259            code('}')
260
261        # ******** Full init constructor ********
262        if not self.isGlobal:
263            params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
264                       for dm in self.data_members.itervalues() ]
265            params = ', '.join(params)
266
267            if self.isMessage:
268                params = "const Tick curTime, " + params
269
270            code('${{self.c_ident}}($params)')
271
272            # Call superclass constructor
273            if "interface" in self:
274                if self.isMessage:
275                    code('    : ${{self["interface"]}}(curTime)')
276                else:
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
284            code.dedent()
285            code('}')
286
287        # create a clone member
288        if self.isMessage:
289            code('''
290MsgPtr
291clone() const
292{
293     return std::shared_ptr<Message>(new ${{self.c_ident}}(*this));
294}
295''')
296        else:
297            code('''
298${{self.c_ident}}*
299clone() const
300{
301     return new ${{self.c_ident}}(*this);
302}
303''')
304
305        if not self.isGlobal:
306            # const Get methods for each field
307            code('// Const accessors methods for each field')
308            for dm in self.data_members.values():
309                code('''
310/** \\brief Const accessor method for ${{dm.ident}} field.
311 *  \\return ${{dm.ident}} field
312 */
313const ${{dm.type.c_ident}}&
314get${{dm.ident}}() const
315{
316    return m_${{dm.ident}};
317}
318''')
319
320            # Non-const Get methods for each field
321            code('// Non const Accessors methods for each field')
322            for dm in self.data_members.values():
323                code('''
324/** \\brief Non-const accessor method for ${{dm.ident}} field.
325 *  \\return ${{dm.ident}} field
326 */
327${{dm.type.c_ident}}&
328get${{dm.ident}}()
329{
330    return m_${{dm.ident}};
331}
332''')
333
334            #Set methods for each field
335            code('// Mutator methods for each field')
336            for dm in self.data_members.values():
337                code('''
338/** \\brief Mutator method for ${{dm.ident}} field */
339void
340set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
341{
342    m_${{dm.ident}} = local_${{dm.ident}};
343}
344''')
345
346        code('void print(std::ostream& out) const;')
347        code.dedent()
348        code('  //private:')
349        code.indent()
350
351        # Data members for each field
352        for dm in self.data_members.values():
353            if "abstract" not in dm:
354                const = ""
355                init = ""
356
357                # global structure
358                if self.isGlobal:
359                    const = "static const "
360
361                # init value
362                if dm.init_code:
363                    # only global structure can have init value here
364                    assert self.isGlobal
365                    init = " = %s" % (dm.init_code)
366
367                if "desc" in dm:
368                    code('/** ${{dm["desc"]}} */')
369
370                code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
371
372        # Prototypes for methods defined for the Type
373        for item in self.methods:
374            proto = self.methods[item].prototype
375            if proto:
376                code('$proto')
377
378        code.dedent()
379        code('};')
380
381        code('''
382inline std::ostream&
383operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
384{
385    obj.print(out);
386    out << std::flush;
387    return out;
388}
389
390#endif // __${{self.c_ident}}_HH__
391''')
392
393        code.write(path, "%s.hh" % self.c_ident)
394
395    def printTypeCC(self, path):
396        code = self.symtab.codeFormatter()
397
398        code('''
399/** \\file ${{self.c_ident}}.cc
400 *
401 * Auto generated C++ code started by $__file__:$__line__
402 */
403
404#include <iostream>
405#include <memory>
406
407#include "mem/protocol/${{self.c_ident}}.hh"
408#include "mem/ruby/system/RubySystem.hh"
409
410using namespace std;
411''')
412
413        code('''
414/** \\brief Print the state of this object */
415void
416${{self.c_ident}}::print(ostream& out) const
417{
418    out << "[${{self.c_ident}}: ";
419''')
420
421        # For each field
422        code.indent()
423        for dm in self.data_members.values():
424            if dm.type.c_ident == "Addr":
425                code('''
426out << "${{dm.ident}} = " << printAddress(m_${{dm.ident}}) << " ";''')
427            else:
428                code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
429
430        code.dedent()
431
432        # Trailer
433        code('''
434    out << "]";
435}''')
436
437        # print the code for the methods in the type
438        for item in self.methods:
439            code(self.methods[item].generateCode())
440
441        code.write(path, "%s.cc" % self.c_ident)
442
443    def printEnumHH(self, path):
444        code = self.symtab.codeFormatter()
445        code('''
446/** \\file ${{self.c_ident}}.hh
447 *
448 * Auto generated C++ code started by $__file__:$__line__
449 */
450
451#ifndef __${{self.c_ident}}_HH__
452#define __${{self.c_ident}}_HH__
453
454#include <iostream>
455#include <string>
456
457''')
458        if self.isStateDecl:
459            code('#include "mem/protocol/AccessPermission.hh"')
460
461        if self.isMachineType:
462            code('#include "base/misc.hh"')
463            code('#include "mem/ruby/common/Address.hh"')
464            code('#include "mem/ruby/common/TypeDefines.hh"')
465            code('struct MachineID;')
466
467        code('''
468
469// Class definition
470/** \\enum ${{self.c_ident}}
471 *  \\brief ${{self.desc}}
472 */
473enum ${{self.c_ident}} {
474    ${{self.c_ident}}_FIRST,
475''')
476
477        code.indent()
478        # For each field
479        for i,(ident,enum) in enumerate(self.enums.iteritems()):
480            desc = enum.get("desc", "No description avaliable")
481            if i == 0:
482                init = ' = %s_FIRST' % self.c_ident
483            else:
484                init = ''
485            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
486        code.dedent()
487        code('''
488    ${{self.c_ident}}_NUM
489};
490
491// Code to convert from a string to the enumeration
492${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
493
494// Code to convert state to a string
495std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
496
497// Code to increment an enumeration type
498${{self.c_ident}} &operator++(${{self.c_ident}} &e);
499''')
500
501        # MachineType hack used to set the base component id for each Machine
502        if self.isMachineType:
503            code('''
504int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
505MachineType ${{self.c_ident}}_from_base_level(int);
506int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
507int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
508''')
509
510            for enum in self.enums.itervalues():
511                if enum.ident == "DMA":
512                    code('''
513MachineID map_Address_to_DMA(const Addr &addr);
514''')
515                code('''
516
517MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
518''')
519
520        if self.isStateDecl:
521            code('''
522
523// Code to convert the current state to an access permission
524AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
525
526''')
527
528        # Trailer
529        code('''
530std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
531
532#endif // __${{self.c_ident}}_HH__
533''')
534
535        code.write(path, "%s.hh" % self.c_ident)
536
537    def printEnumCC(self, path):
538        code = self.symtab.codeFormatter()
539        code('''
540/** \\file ${{self.c_ident}}.hh
541 *
542 * Auto generated C++ code started by $__file__:$__line__
543 */
544
545#include <cassert>
546#include <iostream>
547#include <string>
548
549#include "base/misc.hh"
550#include "mem/protocol/${{self.c_ident}}.hh"
551
552using namespace std;
553
554''')
555
556        if self.isStateDecl:
557            code('''
558// Code to convert the current state to an access permission
559AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
560{
561    switch(obj) {
562''')
563            # For each case
564            code.indent()
565            for statePerm in self.statePermPairs:
566                code('  case ${{self.c_ident}}_${{statePerm[0]}}:')
567                code('    return AccessPermission_${{statePerm[1]}};')
568            code.dedent()
569            code ('''
570      default:
571        panic("Unknown state access permission converstion for ${{self.c_ident}}");
572    }
573}
574
575''')
576
577        if self.isMachineType:
578            for enum in self.enums.itervalues():
579                if enum.primary:
580                    code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
581            code('#include "mem/ruby/common/MachineID.hh"')
582
583        code('''
584// Code for output operator
585ostream&
586operator<<(ostream& out, const ${{self.c_ident}}& obj)
587{
588    out << ${{self.c_ident}}_to_string(obj);
589    out << flush;
590    return out;
591}
592
593// Code to convert state to a string
594string
595${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
596{
597    switch(obj) {
598''')
599
600        # For each field
601        code.indent()
602        for enum in self.enums.itervalues():
603            code('  case ${{self.c_ident}}_${{enum.ident}}:')
604            code('    return "${{enum.ident}}";')
605        code.dedent()
606
607        # Trailer
608        code('''
609      default:
610        panic("Invalid range for type ${{self.c_ident}}");
611    }
612}
613
614// Code to convert from a string to the enumeration
615${{self.c_ident}}
616string_to_${{self.c_ident}}(const string& str)
617{
618''')
619
620        # For each field
621        start = ""
622        code.indent()
623        for enum in self.enums.itervalues():
624            code('${start}if (str == "${{enum.ident}}") {')
625            code('    return ${{self.c_ident}}_${{enum.ident}};')
626            start = "} else "
627        code.dedent()
628
629        code('''
630    } else {
631        panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
632    }
633}
634
635// Code to increment an enumeration type
636${{self.c_ident}}&
637operator++(${{self.c_ident}}& e)
638{
639    assert(e < ${{self.c_ident}}_NUM);
640    return e = ${{self.c_ident}}(e+1);
641}
642''')
643
644        # MachineType hack used to set the base level and number of
645        # components for each Machine
646        if self.isMachineType:
647            code('''
648/** \\brief returns the base vector index for each machine type to be
649  * used by NetDest
650  *
651  * \\return the base vector index for each machine type to be used by NetDest
652  * \\see NetDest.hh
653  */
654int
655${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
656{
657    switch(obj) {
658''')
659
660            # For each field
661            code.indent()
662            for i,enum in enumerate(self.enums.itervalues()):
663                code('  case ${{self.c_ident}}_${{enum.ident}}:')
664                code('    return $i;')
665            code.dedent()
666
667            # total num
668            code('''
669      case ${{self.c_ident}}_NUM:
670        return ${{len(self.enums)}};
671
672      default:
673        panic("Invalid range for type ${{self.c_ident}}");
674    }
675}
676
677/** \\brief returns the machine type for each base vector index used by NetDest
678 *
679 * \\return the MachineType
680 */
681MachineType
682${{self.c_ident}}_from_base_level(int type)
683{
684    switch(type) {
685''')
686
687            # For each field
688            code.indent()
689            for i,enum in enumerate(self.enums.itervalues()):
690                code('  case $i:')
691                code('    return ${{self.c_ident}}_${{enum.ident}};')
692            code.dedent()
693
694            # Trailer
695            code('''
696      default:
697        panic("Invalid range for type ${{self.c_ident}}");
698    }
699}
700
701/** \\brief The return value indicates the number of components created
702 * before a particular machine\'s components
703 *
704 * \\return the base number of components for each machine
705 */
706int
707${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
708{
709    int base = 0;
710    switch(obj) {
711''')
712
713            # For each field
714            code.indent()
715            code('  case ${{self.c_ident}}_NUM:')
716            for enum in reversed(self.enums.values()):
717                # Check if there is a defined machine with this type
718                if enum.primary:
719                    code('    base += ${{enum.ident}}_Controller::getNumControllers();')
720                else:
721                    code('    base += 0;')
722                code('  case ${{self.c_ident}}_${{enum.ident}}:')
723            code('    break;')
724            code.dedent()
725
726            code('''
727      default:
728        panic("Invalid range for type ${{self.c_ident}}");
729    }
730
731    return base;
732}
733
734/** \\brief returns the total number of components for each machine
735 * \\return the total number of components for each machine
736 */
737int
738${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
739{
740    switch(obj) {
741''')
742
743            # For each field
744            for enum in self.enums.itervalues():
745                code('case ${{self.c_ident}}_${{enum.ident}}:')
746                if enum.primary:
747                    code('return ${{enum.ident}}_Controller::getNumControllers();')
748                else:
749                    code('return 0;')
750
751            # total num
752            code('''
753      case ${{self.c_ident}}_NUM:
754      default:
755        panic("Invalid range for type ${{self.c_ident}}");
756    }
757}
758''')
759
760            for enum in self.enums.itervalues():
761                if enum.ident == "DMA":
762                    code('''
763MachineID
764map_Address_to_DMA(const Addr &addr)
765{
766      MachineID dma = {MachineType_DMA, 0};
767      return dma;
768}
769''')
770
771                code('''
772
773MachineID
774get${{enum.ident}}MachineID(NodeID RubyNode)
775{
776      MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
777      return mach;
778}
779''')
780
781        # Write the file
782        code.write(path, "%s.cc" % self.c_ident)
783
784__all__ = [ "Type" ]
785