Type.py (12436:c56112090c61) Type.py (13672:2969e4d5abf4)
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2# Copyright (c) 2009 The Hewlett-Packard Development Company
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2# Copyright (c) 2009 The Hewlett-Packard Development Company
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28from m5.util import orderdict
28from collections import OrderedDict
29
30from slicc.util import PairContainer
31from slicc.symbols.Symbol import Symbol
32from slicc.symbols.Var import Var
33
34class DataMember(Var):
35 def __init__(self, symtab, ident, location, type, code, pairs,
36 machine, init_code):
37 super(DataMember, self).__init__(symtab, ident, location, type,
38 code, pairs, machine)
39 self.init_code = init_code
40
41class Enumeration(PairContainer):
42 def __init__(self, ident, pairs):
43 super(Enumeration, self).__init__(pairs)
44 self.ident = ident
45 self.primary = False
46
47class Type(Symbol):
48 def __init__(self, table, ident, location, pairs, machine=None):
49 super(Type, self).__init__(table, ident, location, pairs)
50 self.c_ident = ident
51 self.abstract_ident = ""
52 if machine:
53 if self.isExternal or self.isPrimitive:
54 if "external_name" in self:
55 self.c_ident = self["external_name"]
56 else:
57 # Append with machine name
58 self.c_ident = "%s_%s" % (machine, ident)
59
60 self.pairs.setdefault("desc", "No description avaliable")
61
62 # check for interface that this Type implements
63 if "interface" in self:
64 interface = self["interface"]
65 if interface in ("Message"):
66 self["message"] = "yes"
67
68 # FIXME - all of the following id comparisons are fragile hacks
69 if self.ident in ("CacheMemory"):
70 self["cache"] = "yes"
71
72 if self.ident in ("TBETable"):
73 self["tbe"] = "yes"
74
75 if self.ident == "TimerTable":
76 self["timer"] = "yes"
77
78 if self.ident == "DirectoryMemory":
79 self["dir"] = "yes"
80
81 if self.ident == "PersistentTable":
82 self["persistent"] = "yes"
83
84 if self.ident == "Prefetcher":
85 self["prefetcher"] = "yes"
86
87 self.isMachineType = (ident == "MachineType")
88
89 self.isStateDecl = ("state_decl" in self)
90 self.statePermPairs = []
91
29
30from slicc.util import PairContainer
31from slicc.symbols.Symbol import Symbol
32from slicc.symbols.Var import Var
33
34class DataMember(Var):
35 def __init__(self, symtab, ident, location, type, code, pairs,
36 machine, init_code):
37 super(DataMember, self).__init__(symtab, ident, location, type,
38 code, pairs, machine)
39 self.init_code = init_code
40
41class Enumeration(PairContainer):
42 def __init__(self, ident, pairs):
43 super(Enumeration, self).__init__(pairs)
44 self.ident = ident
45 self.primary = False
46
47class Type(Symbol):
48 def __init__(self, table, ident, location, pairs, machine=None):
49 super(Type, self).__init__(table, ident, location, pairs)
50 self.c_ident = ident
51 self.abstract_ident = ""
52 if machine:
53 if self.isExternal or self.isPrimitive:
54 if "external_name" in self:
55 self.c_ident = self["external_name"]
56 else:
57 # Append with machine name
58 self.c_ident = "%s_%s" % (machine, ident)
59
60 self.pairs.setdefault("desc", "No description avaliable")
61
62 # check for interface that this Type implements
63 if "interface" in self:
64 interface = self["interface"]
65 if interface in ("Message"):
66 self["message"] = "yes"
67
68 # FIXME - all of the following id comparisons are fragile hacks
69 if self.ident in ("CacheMemory"):
70 self["cache"] = "yes"
71
72 if self.ident in ("TBETable"):
73 self["tbe"] = "yes"
74
75 if self.ident == "TimerTable":
76 self["timer"] = "yes"
77
78 if self.ident == "DirectoryMemory":
79 self["dir"] = "yes"
80
81 if self.ident == "PersistentTable":
82 self["persistent"] = "yes"
83
84 if self.ident == "Prefetcher":
85 self["prefetcher"] = "yes"
86
87 self.isMachineType = (ident == "MachineType")
88
89 self.isStateDecl = ("state_decl" in self)
90 self.statePermPairs = []
91
92 self.data_members = orderdict()
92 self.data_members = OrderedDict()
93 self.methods = {}
93 self.methods = {}
94 self.enums = orderdict()
94 self.enums = OrderedDict()
95
96 @property
97 def isPrimitive(self):
98 return "primitive" in self
99
100 @property
101 def isMessage(self):
102 return "message" in self
103 @property
104 def isBuffer(self):
105 return "buffer" in self
106 @property
107 def isInPort(self):
108 return "inport" in self
109 @property
110 def isOutPort(self):
111 return "outport" in self
112 @property
113 def isEnumeration(self):
114 return "enumeration" in self
115 @property
116 def isExternal(self):
117 return "external" in self
118 @property
119 def isGlobal(self):
120 return "global" in self
121 @property
122 def isInterface(self):
123 return "interface" in self
124
125 # Return false on error
126 def addDataMember(self, ident, type, pairs, init_code):
127 if ident in self.data_members:
128 return False
129
130 member = DataMember(self.symtab, ident, self.location, type,
131 "m_%s" % ident, pairs, None, init_code)
132
133 self.data_members[ident] = member
134 self.symtab.registerSym(ident, member)
135 return True
136
137 def dataMemberType(self, ident):
138 return self.data_members[ident].type
139
140 def methodId(self, name, param_type_vec):
141 return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
142
143 def methodIdAbstract(self, name, param_type_vec):
144 return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
145
146 def statePermPairAdd(self, state_name, perm_name):
147 self.statePermPairs.append([state_name, perm_name])
148
149 def addFunc(self, func):
150 ident = self.methodId(func.ident, func.param_types)
151 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 <functional>')
463 code('#include "base/logging.hh"')
464 code('#include "mem/ruby/common/Address.hh"')
465 code('#include "mem/ruby/common/TypeDefines.hh"')
466 code('struct MachineID;')
467
468 code('''
469
470// Class definition
471/** \\enum ${{self.c_ident}}
472 * \\brief ${{self.desc}}
473 */
474enum ${{self.c_ident}} {
475 ${{self.c_ident}}_FIRST,
476''')
477
478 code.indent()
479 # For each field
480 for i,(ident,enum) in enumerate(self.enums.iteritems()):
481 desc = enum.get("desc", "No description avaliable")
482 if i == 0:
483 init = ' = %s_FIRST' % self.c_ident
484 else:
485 init = ''
486 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
487 code.dedent()
488 code('''
489 ${{self.c_ident}}_NUM
490};
491
492// Code to convert from a string to the enumeration
493${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
494
495// Code to convert state to a string
496std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
497
498// Code to increment an enumeration type
499${{self.c_ident}} &operator++(${{self.c_ident}} &e);
500''')
501
502 if self.isMachineType:
503 code('''
504
505// define a hash function for the MachineType class
506namespace std {
507template<>
508struct hash<MachineType> {
509 std::size_t operator()(const MachineType &mtype) const {
510 return hash<size_t>()(static_cast<size_t>(mtype));
511 }
512};
513}
514
515''')
516 # MachineType hack used to set the base component id for each Machine
517 if self.isMachineType:
518 code('''
519int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
520MachineType ${{self.c_ident}}_from_base_level(int);
521int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
522int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
523''')
524
525 for enum in self.enums.itervalues():
526 code('''
527
528MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
529''')
530
531 if self.isStateDecl:
532 code('''
533
534// Code to convert the current state to an access permission
535AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
536
537''')
538
539 # Trailer
540 code('''
541std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
542
543#endif // __${{self.c_ident}}_HH__
544''')
545
546 code.write(path, "%s.hh" % self.c_ident)
547
548 def printEnumCC(self, path):
549 code = self.symtab.codeFormatter()
550 code('''
551/** \\file ${{self.c_ident}}.hh
552 *
553 * Auto generated C++ code started by $__file__:$__line__
554 */
555
556#include <cassert>
557#include <iostream>
558#include <string>
559
560#include "base/logging.hh"
561#include "mem/protocol/${{self.c_ident}}.hh"
562
563using namespace std;
564
565''')
566
567 if self.isStateDecl:
568 code('''
569// Code to convert the current state to an access permission
570AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
571{
572 switch(obj) {
573''')
574 # For each case
575 code.indent()
576 for statePerm in self.statePermPairs:
577 code(' case ${{self.c_ident}}_${{statePerm[0]}}:')
578 code(' return AccessPermission_${{statePerm[1]}};')
579 code.dedent()
580 code ('''
581 default:
582 panic("Unknown state access permission converstion for ${{self.c_ident}}");
583 }
584}
585
586''')
587
588 if self.isMachineType:
589 for enum in self.enums.itervalues():
590 if enum.primary:
591 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
592 code('#include "mem/ruby/common/MachineID.hh"')
593
594 code('''
595// Code for output operator
596ostream&
597operator<<(ostream& out, const ${{self.c_ident}}& obj)
598{
599 out << ${{self.c_ident}}_to_string(obj);
600 out << flush;
601 return out;
602}
603
604// Code to convert state to a string
605string
606${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
607{
608 switch(obj) {
609''')
610
611 # For each field
612 code.indent()
613 for enum in self.enums.itervalues():
614 code(' case ${{self.c_ident}}_${{enum.ident}}:')
615 code(' return "${{enum.ident}}";')
616 code.dedent()
617
618 # Trailer
619 code('''
620 default:
621 panic("Invalid range for type ${{self.c_ident}}");
622 }
623}
624
625// Code to convert from a string to the enumeration
626${{self.c_ident}}
627string_to_${{self.c_ident}}(const string& str)
628{
629''')
630
631 # For each field
632 start = ""
633 code.indent()
634 for enum in self.enums.itervalues():
635 code('${start}if (str == "${{enum.ident}}") {')
636 code(' return ${{self.c_ident}}_${{enum.ident}};')
637 start = "} else "
638 code.dedent()
639
640 code('''
641 } else {
642 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
643 }
644}
645
646// Code to increment an enumeration type
647${{self.c_ident}}&
648operator++(${{self.c_ident}}& e)
649{
650 assert(e < ${{self.c_ident}}_NUM);
651 return e = ${{self.c_ident}}(e+1);
652}
653''')
654
655 # MachineType hack used to set the base level and number of
656 # components for each Machine
657 if self.isMachineType:
658 code('''
659/** \\brief returns the base vector index for each machine type to be
660 * used by NetDest
661 *
662 * \\return the base vector index for each machine type to be used by NetDest
663 * \\see NetDest.hh
664 */
665int
666${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
667{
668 switch(obj) {
669''')
670
671 # For each field
672 code.indent()
673 for i,enum in enumerate(self.enums.itervalues()):
674 code(' case ${{self.c_ident}}_${{enum.ident}}:')
675 code(' return $i;')
676 code.dedent()
677
678 # total num
679 code('''
680 case ${{self.c_ident}}_NUM:
681 return ${{len(self.enums)}};
682
683 default:
684 panic("Invalid range for type ${{self.c_ident}}");
685 }
686}
687
688/** \\brief returns the machine type for each base vector index used by NetDest
689 *
690 * \\return the MachineType
691 */
692MachineType
693${{self.c_ident}}_from_base_level(int type)
694{
695 switch(type) {
696''')
697
698 # For each field
699 code.indent()
700 for i,enum in enumerate(self.enums.itervalues()):
701 code(' case $i:')
702 code(' return ${{self.c_ident}}_${{enum.ident}};')
703 code.dedent()
704
705 # Trailer
706 code('''
707 default:
708 panic("Invalid range for type ${{self.c_ident}}");
709 }
710}
711
712/** \\brief The return value indicates the number of components created
713 * before a particular machine\'s components
714 *
715 * \\return the base number of components for each machine
716 */
717int
718${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
719{
720 int base = 0;
721 switch(obj) {
722''')
723
724 # For each field
725 code.indent()
726 code(' case ${{self.c_ident}}_NUM:')
727 for enum in reversed(self.enums.values()):
728 # Check if there is a defined machine with this type
729 if enum.primary:
730 code(' base += ${{enum.ident}}_Controller::getNumControllers();')
731 else:
732 code(' base += 0;')
733 code(' M5_FALLTHROUGH;')
734 code(' case ${{self.c_ident}}_${{enum.ident}}:')
735 code(' break;')
736 code.dedent()
737
738 code('''
739 default:
740 panic("Invalid range for type ${{self.c_ident}}");
741 }
742
743 return base;
744}
745
746/** \\brief returns the total number of components for each machine
747 * \\return the total number of components for each machine
748 */
749int
750${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
751{
752 switch(obj) {
753''')
754
755 # For each field
756 for enum in self.enums.itervalues():
757 code('case ${{self.c_ident}}_${{enum.ident}}:')
758 if enum.primary:
759 code('return ${{enum.ident}}_Controller::getNumControllers();')
760 else:
761 code('return 0;')
762
763 # total num
764 code('''
765 case ${{self.c_ident}}_NUM:
766 default:
767 panic("Invalid range for type ${{self.c_ident}}");
768 }
769}
770''')
771
772 for enum in self.enums.itervalues():
773 code('''
774
775MachineID
776get${{enum.ident}}MachineID(NodeID RubyNode)
777{
778 MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
779 return mach;
780}
781''')
782
783 # Write the file
784 code.write(path, "%s.cc" % self.c_ident)
785
786__all__ = [ "Type" ]
95
96 @property
97 def isPrimitive(self):
98 return "primitive" in self
99
100 @property
101 def isMessage(self):
102 return "message" in self
103 @property
104 def isBuffer(self):
105 return "buffer" in self
106 @property
107 def isInPort(self):
108 return "inport" in self
109 @property
110 def isOutPort(self):
111 return "outport" in self
112 @property
113 def isEnumeration(self):
114 return "enumeration" in self
115 @property
116 def isExternal(self):
117 return "external" in self
118 @property
119 def isGlobal(self):
120 return "global" in self
121 @property
122 def isInterface(self):
123 return "interface" in self
124
125 # Return false on error
126 def addDataMember(self, ident, type, pairs, init_code):
127 if ident in self.data_members:
128 return False
129
130 member = DataMember(self.symtab, ident, self.location, type,
131 "m_%s" % ident, pairs, None, init_code)
132
133 self.data_members[ident] = member
134 self.symtab.registerSym(ident, member)
135 return True
136
137 def dataMemberType(self, ident):
138 return self.data_members[ident].type
139
140 def methodId(self, name, param_type_vec):
141 return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
142
143 def methodIdAbstract(self, name, param_type_vec):
144 return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
145
146 def statePermPairAdd(self, state_name, perm_name):
147 self.statePermPairs.append([state_name, perm_name])
148
149 def addFunc(self, func):
150 ident = self.methodId(func.ident, func.param_types)
151 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 <functional>')
463 code('#include "base/logging.hh"')
464 code('#include "mem/ruby/common/Address.hh"')
465 code('#include "mem/ruby/common/TypeDefines.hh"')
466 code('struct MachineID;')
467
468 code('''
469
470// Class definition
471/** \\enum ${{self.c_ident}}
472 * \\brief ${{self.desc}}
473 */
474enum ${{self.c_ident}} {
475 ${{self.c_ident}}_FIRST,
476''')
477
478 code.indent()
479 # For each field
480 for i,(ident,enum) in enumerate(self.enums.iteritems()):
481 desc = enum.get("desc", "No description avaliable")
482 if i == 0:
483 init = ' = %s_FIRST' % self.c_ident
484 else:
485 init = ''
486 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
487 code.dedent()
488 code('''
489 ${{self.c_ident}}_NUM
490};
491
492// Code to convert from a string to the enumeration
493${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
494
495// Code to convert state to a string
496std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
497
498// Code to increment an enumeration type
499${{self.c_ident}} &operator++(${{self.c_ident}} &e);
500''')
501
502 if self.isMachineType:
503 code('''
504
505// define a hash function for the MachineType class
506namespace std {
507template<>
508struct hash<MachineType> {
509 std::size_t operator()(const MachineType &mtype) const {
510 return hash<size_t>()(static_cast<size_t>(mtype));
511 }
512};
513}
514
515''')
516 # MachineType hack used to set the base component id for each Machine
517 if self.isMachineType:
518 code('''
519int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
520MachineType ${{self.c_ident}}_from_base_level(int);
521int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
522int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
523''')
524
525 for enum in self.enums.itervalues():
526 code('''
527
528MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
529''')
530
531 if self.isStateDecl:
532 code('''
533
534// Code to convert the current state to an access permission
535AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
536
537''')
538
539 # Trailer
540 code('''
541std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
542
543#endif // __${{self.c_ident}}_HH__
544''')
545
546 code.write(path, "%s.hh" % self.c_ident)
547
548 def printEnumCC(self, path):
549 code = self.symtab.codeFormatter()
550 code('''
551/** \\file ${{self.c_ident}}.hh
552 *
553 * Auto generated C++ code started by $__file__:$__line__
554 */
555
556#include <cassert>
557#include <iostream>
558#include <string>
559
560#include "base/logging.hh"
561#include "mem/protocol/${{self.c_ident}}.hh"
562
563using namespace std;
564
565''')
566
567 if self.isStateDecl:
568 code('''
569// Code to convert the current state to an access permission
570AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
571{
572 switch(obj) {
573''')
574 # For each case
575 code.indent()
576 for statePerm in self.statePermPairs:
577 code(' case ${{self.c_ident}}_${{statePerm[0]}}:')
578 code(' return AccessPermission_${{statePerm[1]}};')
579 code.dedent()
580 code ('''
581 default:
582 panic("Unknown state access permission converstion for ${{self.c_ident}}");
583 }
584}
585
586''')
587
588 if self.isMachineType:
589 for enum in self.enums.itervalues():
590 if enum.primary:
591 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
592 code('#include "mem/ruby/common/MachineID.hh"')
593
594 code('''
595// Code for output operator
596ostream&
597operator<<(ostream& out, const ${{self.c_ident}}& obj)
598{
599 out << ${{self.c_ident}}_to_string(obj);
600 out << flush;
601 return out;
602}
603
604// Code to convert state to a string
605string
606${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
607{
608 switch(obj) {
609''')
610
611 # For each field
612 code.indent()
613 for enum in self.enums.itervalues():
614 code(' case ${{self.c_ident}}_${{enum.ident}}:')
615 code(' return "${{enum.ident}}";')
616 code.dedent()
617
618 # Trailer
619 code('''
620 default:
621 panic("Invalid range for type ${{self.c_ident}}");
622 }
623}
624
625// Code to convert from a string to the enumeration
626${{self.c_ident}}
627string_to_${{self.c_ident}}(const string& str)
628{
629''')
630
631 # For each field
632 start = ""
633 code.indent()
634 for enum in self.enums.itervalues():
635 code('${start}if (str == "${{enum.ident}}") {')
636 code(' return ${{self.c_ident}}_${{enum.ident}};')
637 start = "} else "
638 code.dedent()
639
640 code('''
641 } else {
642 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
643 }
644}
645
646// Code to increment an enumeration type
647${{self.c_ident}}&
648operator++(${{self.c_ident}}& e)
649{
650 assert(e < ${{self.c_ident}}_NUM);
651 return e = ${{self.c_ident}}(e+1);
652}
653''')
654
655 # MachineType hack used to set the base level and number of
656 # components for each Machine
657 if self.isMachineType:
658 code('''
659/** \\brief returns the base vector index for each machine type to be
660 * used by NetDest
661 *
662 * \\return the base vector index for each machine type to be used by NetDest
663 * \\see NetDest.hh
664 */
665int
666${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
667{
668 switch(obj) {
669''')
670
671 # For each field
672 code.indent()
673 for i,enum in enumerate(self.enums.itervalues()):
674 code(' case ${{self.c_ident}}_${{enum.ident}}:')
675 code(' return $i;')
676 code.dedent()
677
678 # total num
679 code('''
680 case ${{self.c_ident}}_NUM:
681 return ${{len(self.enums)}};
682
683 default:
684 panic("Invalid range for type ${{self.c_ident}}");
685 }
686}
687
688/** \\brief returns the machine type for each base vector index used by NetDest
689 *
690 * \\return the MachineType
691 */
692MachineType
693${{self.c_ident}}_from_base_level(int type)
694{
695 switch(type) {
696''')
697
698 # For each field
699 code.indent()
700 for i,enum in enumerate(self.enums.itervalues()):
701 code(' case $i:')
702 code(' return ${{self.c_ident}}_${{enum.ident}};')
703 code.dedent()
704
705 # Trailer
706 code('''
707 default:
708 panic("Invalid range for type ${{self.c_ident}}");
709 }
710}
711
712/** \\brief The return value indicates the number of components created
713 * before a particular machine\'s components
714 *
715 * \\return the base number of components for each machine
716 */
717int
718${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
719{
720 int base = 0;
721 switch(obj) {
722''')
723
724 # For each field
725 code.indent()
726 code(' case ${{self.c_ident}}_NUM:')
727 for enum in reversed(self.enums.values()):
728 # Check if there is a defined machine with this type
729 if enum.primary:
730 code(' base += ${{enum.ident}}_Controller::getNumControllers();')
731 else:
732 code(' base += 0;')
733 code(' M5_FALLTHROUGH;')
734 code(' case ${{self.c_ident}}_${{enum.ident}}:')
735 code(' break;')
736 code.dedent()
737
738 code('''
739 default:
740 panic("Invalid range for type ${{self.c_ident}}");
741 }
742
743 return base;
744}
745
746/** \\brief returns the total number of components for each machine
747 * \\return the total number of components for each machine
748 */
749int
750${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
751{
752 switch(obj) {
753''')
754
755 # For each field
756 for enum in self.enums.itervalues():
757 code('case ${{self.c_ident}}_${{enum.ident}}:')
758 if enum.primary:
759 code('return ${{enum.ident}}_Controller::getNumControllers();')
760 else:
761 code('return 0;')
762
763 # total num
764 code('''
765 case ${{self.c_ident}}_NUM:
766 default:
767 panic("Invalid range for type ${{self.c_ident}}");
768 }
769}
770''')
771
772 for enum in self.enums.itervalues():
773 code('''
774
775MachineID
776get${{enum.ident}}MachineID(NodeID RubyNode)
777{
778 MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
779 return mach;
780}
781''')
782
783 # Write the file
784 code.write(path, "%s.cc" % self.c_ident)
785
786__all__ = [ "Type" ]