Type.py (11108:6342ddf6d733) Type.py (11117:2a1a21f79047)
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
29
30from slicc.util import PairContainer
31from slicc.symbols.Symbol import Symbol
32from slicc.symbols.Var import Var
33
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
29
30from slicc.util import PairContainer
31from slicc.symbols.Symbol import Symbol
32from slicc.symbols.Var import Var
33
34class DataMember(PairContainer):
35 def __init__(self, ident, type, pairs, init_code):
36 super(DataMember, self).__init__(pairs)
37 self.ident = ident
38 self.type = type
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
46class Type(Symbol):
47 def __init__(self, table, ident, location, pairs, machine=None):
48 super(Type, self).__init__(table, ident, location, pairs)
49 self.c_ident = ident
50 self.abstract_ident = ""
51 if machine:
52 if self.isExternal or self.isPrimitive:
53 if "external_name" in self:
54 self.c_ident = self["external_name"]
55 else:
56 # Append with machine name
57 self.c_ident = "%s_%s" % (machine, ident)
58
59 self.pairs.setdefault("desc", "No description avaliable")
60
61 # check for interface that this Type implements
62 if "interface" in self:
63 interface = self["interface"]
64 if interface in ("Message"):
65 self["message"] = "yes"
66
67 # FIXME - all of the following id comparisons are fragile hacks
68 if self.ident in ("CacheMemory"):
69 self["cache"] = "yes"
70
71 if self.ident in ("TBETable"):
72 self["tbe"] = "yes"
73
74 if self.ident == "TimerTable":
75 self["timer"] = "yes"
76
77 if self.ident == "DirectoryMemory":
78 self["dir"] = "yes"
79
80 if self.ident == "PersistentTable":
81 self["persistent"] = "yes"
82
83 if self.ident == "Prefetcher":
84 self["prefetcher"] = "yes"
85
86 self.isMachineType = (ident == "MachineType")
87
88 self.isStateDecl = ("state_decl" in self)
89 self.statePermPairs = []
90
91 self.data_members = orderdict()
92 self.methods = {}
93 self.enums = orderdict()
94
95 @property
96 def isPrimitive(self):
97 return "primitive" in self
98
99 @property
100 def isMessage(self):
101 return "message" in self
102 @property
103 def isBuffer(self):
104 return "buffer" in self
105 @property
106 def isInPort(self):
107 return "inport" in self
108 @property
109 def isOutPort(self):
110 return "outport" in self
111 @property
112 def isEnumeration(self):
113 return "enumeration" in self
114 @property
115 def isExternal(self):
116 return "external" in self
117 @property
118 def isGlobal(self):
119 return "global" in self
120 @property
121 def isInterface(self):
122 return "interface" in self
123
124 # Return false on error
125 def addDataMember(self, ident, type, pairs, init_code):
126 if ident in self.data_members:
127 return False
128
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
46class Type(Symbol):
47 def __init__(self, table, ident, location, pairs, machine=None):
48 super(Type, self).__init__(table, ident, location, pairs)
49 self.c_ident = ident
50 self.abstract_ident = ""
51 if machine:
52 if self.isExternal or self.isPrimitive:
53 if "external_name" in self:
54 self.c_ident = self["external_name"]
55 else:
56 # Append with machine name
57 self.c_ident = "%s_%s" % (machine, ident)
58
59 self.pairs.setdefault("desc", "No description avaliable")
60
61 # check for interface that this Type implements
62 if "interface" in self:
63 interface = self["interface"]
64 if interface in ("Message"):
65 self["message"] = "yes"
66
67 # FIXME - all of the following id comparisons are fragile hacks
68 if self.ident in ("CacheMemory"):
69 self["cache"] = "yes"
70
71 if self.ident in ("TBETable"):
72 self["tbe"] = "yes"
73
74 if self.ident == "TimerTable":
75 self["timer"] = "yes"
76
77 if self.ident == "DirectoryMemory":
78 self["dir"] = "yes"
79
80 if self.ident == "PersistentTable":
81 self["persistent"] = "yes"
82
83 if self.ident == "Prefetcher":
84 self["prefetcher"] = "yes"
85
86 self.isMachineType = (ident == "MachineType")
87
88 self.isStateDecl = ("state_decl" in self)
89 self.statePermPairs = []
90
91 self.data_members = orderdict()
92 self.methods = {}
93 self.enums = orderdict()
94
95 @property
96 def isPrimitive(self):
97 return "primitive" in self
98
99 @property
100 def isMessage(self):
101 return "message" in self
102 @property
103 def isBuffer(self):
104 return "buffer" in self
105 @property
106 def isInPort(self):
107 return "inport" in self
108 @property
109 def isOutPort(self):
110 return "outport" in self
111 @property
112 def isEnumeration(self):
113 return "enumeration" in self
114 @property
115 def isExternal(self):
116 return "external" in self
117 @property
118 def isGlobal(self):
119 return "global" in self
120 @property
121 def isInterface(self):
122 return "interface" in self
123
124 # Return false on error
125 def addDataMember(self, ident, type, pairs, init_code):
126 if ident in self.data_members:
127 return False
128
129 member = DataMember(ident, type, pairs, init_code)
130 self.data_members[ident] = member
129 member = DataMember(self.symtab, ident, self.location, type,
130 "m_%s" % ident, pairs, None, init_code)
131
131
132 var = Var(self.symtab, ident, self.location, type,
133 "m_%s" % ident, {}, None)
134 self.symtab.registerSym(ident, var)
132 self.data_members[ident] = member
133 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 def writeCodeFiles(self, path, includes):
170 if self.isExternal:
171 # Do nothing
172 pass
173 elif self.isEnumeration:
174 self.printEnumHH(path)
175 self.printEnumCC(path)
176 else:
177 # User defined structs and messages
178 self.printTypeHH(path)
179 self.printTypeCC(path)
180
181 def printTypeHH(self, path):
182 code = self.symtab.codeFormatter()
183 code('''
184/** \\file ${{self.c_ident}}.hh
185 *
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
276 code.dedent()
277 code('}')
278
279 # create a clone member
280 if self.isMessage:
281 code('''
282MsgPtr
283clone() const
284{
285 return std::shared_ptr<Message>(new ${{self.c_ident}}(*this));
286}
287''')
288 else:
289 code('''
290${{self.c_ident}}*
291clone() const
292{
293 return new ${{self.c_ident}}(*this);
294}
295''')
296
297 if not self.isGlobal:
298 # const Get methods for each field
299 code('// Const accessors methods for each field')
300 for dm in self.data_members.values():
301 code('''
302/** \\brief Const accessor method for ${{dm.ident}} field.
303 * \\return ${{dm.ident}} field
304 */
305const ${{dm.type.c_ident}}&
306get${{dm.ident}}() const
307{
308 return m_${{dm.ident}};
309}
310''')
311
312 # Non-const Get methods for each field
313 code('// Non const Accessors methods for each field')
314 for dm in self.data_members.values():
315 code('''
316/** \\brief Non-const accessor method for ${{dm.ident}} field.
317 * \\return ${{dm.ident}} field
318 */
319${{dm.type.c_ident}}&
320get${{dm.ident}}()
321{
322 return m_${{dm.ident}};
323}
324''')
325
326 #Set methods for each field
327 code('// Mutator methods for each field')
328 for dm in self.data_members.values():
329 code('''
330/** \\brief Mutator method for ${{dm.ident}} field */
331void
332set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
333{
334 m_${{dm.ident}} = local_${{dm.ident}};
335}
336''')
337
338 code('void print(std::ostream& out) const;')
339 code.dedent()
340 code(' //private:')
341 code.indent()
342
343 # Data members for each field
344 for dm in self.data_members.values():
345 if "abstract" not in dm:
346 const = ""
347 init = ""
348
349 # global structure
350 if self.isGlobal:
351 const = "static const "
352
353 # init value
354 if dm.init_code:
355 # only global structure can have init value here
356 assert self.isGlobal
357 init = " = %s" % (dm.init_code)
358
359 if "desc" in dm:
360 code('/** ${{dm["desc"]}} */')
361
362 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
363
364 # Prototypes for methods defined for the Type
365 for item in self.methods:
366 proto = self.methods[item].prototype
367 if proto:
368 code('$proto')
369
370 code.dedent()
371 code('};')
372
373 code('''
374inline std::ostream&
375operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
376{
377 obj.print(out);
378 out << std::flush;
379 return out;
380}
381
382#endif // __${{self.c_ident}}_HH__
383''')
384
385 code.write(path, "%s.hh" % self.c_ident)
386
387 def printTypeCC(self, path):
388 code = self.symtab.codeFormatter()
389
390 code('''
391/** \\file ${{self.c_ident}}.cc
392 *
393 * Auto generated C++ code started by $__file__:$__line__
394 */
395
396#include <iostream>
397#include <memory>
398
399#include "mem/protocol/${{self.c_ident}}.hh"
400#include "mem/ruby/system/RubySystem.hh"
401
402using namespace std;
403''')
404
405 code('''
406/** \\brief Print the state of this object */
407void
408${{self.c_ident}}::print(ostream& out) const
409{
410 out << "[${{self.c_ident}}: ";
411''')
412
413 # For each field
414 code.indent()
415 for dm in self.data_members.values():
416 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
417
418 code.dedent()
419
420 # Trailer
421 code('''
422 out << "]";
423}''')
424
425 # print the code for the methods in the type
426 for item in self.methods:
427 code(self.methods[item].generateCode())
428
429 code.write(path, "%s.cc" % self.c_ident)
430
431 def printEnumHH(self, path):
432 code = self.symtab.codeFormatter()
433 code('''
434/** \\file ${{self.c_ident}}.hh
435 *
436 * Auto generated C++ code started by $__file__:$__line__
437 */
438
439#ifndef __${{self.c_ident}}_HH__
440#define __${{self.c_ident}}_HH__
441
442#include <iostream>
443#include <string>
444
445''')
446 if self.isStateDecl:
447 code('#include "mem/protocol/AccessPermission.hh"')
448
449 if self.isMachineType:
450 code('#include "base/misc.hh"')
451 code('#include "mem/ruby/common/Address.hh"')
452 code('#include "mem/ruby/common/TypeDefines.hh"')
453 code('struct MachineID;')
454
455 code('''
456
457// Class definition
458/** \\enum ${{self.c_ident}}
459 * \\brief ${{self.desc}}
460 */
461enum ${{self.c_ident}} {
462 ${{self.c_ident}}_FIRST,
463''')
464
465 code.indent()
466 # For each field
467 for i,(ident,enum) in enumerate(self.enums.iteritems()):
468 desc = enum.get("desc", "No description avaliable")
469 if i == 0:
470 init = ' = %s_FIRST' % self.c_ident
471 else:
472 init = ''
473 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
474 code.dedent()
475 code('''
476 ${{self.c_ident}}_NUM
477};
478
479// Code to convert from a string to the enumeration
480${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
481
482// Code to convert state to a string
483std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
484
485// Code to increment an enumeration type
486${{self.c_ident}} &operator++(${{self.c_ident}} &e);
487''')
488
489 # MachineType hack used to set the base component id for each Machine
490 if self.isMachineType:
491 code('''
492int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
493MachineType ${{self.c_ident}}_from_base_level(int);
494int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
495int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
496''')
497
498 for enum in self.enums.itervalues():
499 if enum.ident == "DMA":
500 code('''
501MachineID map_Address_to_DMA(const Addr &addr);
502''')
503 code('''
504
505MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
506''')
507
508 if self.isStateDecl:
509 code('''
510
511// Code to convert the current state to an access permission
512AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
513
514''')
515
516 # Trailer
517 code('''
518std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
519
520#endif // __${{self.c_ident}}_HH__
521''')
522
523 code.write(path, "%s.hh" % self.c_ident)
524
525 def printEnumCC(self, path):
526 code = self.symtab.codeFormatter()
527 code('''
528/** \\file ${{self.c_ident}}.hh
529 *
530 * Auto generated C++ code started by $__file__:$__line__
531 */
532
533#include <cassert>
534#include <iostream>
535#include <string>
536
537#include "base/misc.hh"
538#include "mem/protocol/${{self.c_ident}}.hh"
539
540using namespace std;
541
542''')
543
544 if self.isStateDecl:
545 code('''
546// Code to convert the current state to an access permission
547AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
548{
549 switch(obj) {
550''')
551 # For each case
552 code.indent()
553 for statePerm in self.statePermPairs:
554 code(' case ${{self.c_ident}}_${{statePerm[0]}}:')
555 code(' return AccessPermission_${{statePerm[1]}};')
556 code.dedent()
557 code ('''
558 default:
559 panic("Unknown state access permission converstion for ${{self.c_ident}}");
560 }
561}
562
563''')
564
565 if self.isMachineType:
566 for enum in self.enums.itervalues():
567 if enum.get("Primary"):
568 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
569 code('#include "mem/ruby/common/MachineID.hh"')
570
571 code('''
572// Code for output operator
573ostream&
574operator<<(ostream& out, const ${{self.c_ident}}& obj)
575{
576 out << ${{self.c_ident}}_to_string(obj);
577 out << flush;
578 return out;
579}
580
581// Code to convert state to a string
582string
583${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
584{
585 switch(obj) {
586''')
587
588 # For each field
589 code.indent()
590 for enum in self.enums.itervalues():
591 code(' case ${{self.c_ident}}_${{enum.ident}}:')
592 code(' return "${{enum.ident}}";')
593 code.dedent()
594
595 # Trailer
596 code('''
597 default:
598 panic("Invalid range for type ${{self.c_ident}}");
599 }
600}
601
602// Code to convert from a string to the enumeration
603${{self.c_ident}}
604string_to_${{self.c_ident}}(const string& str)
605{
606''')
607
608 # For each field
609 start = ""
610 code.indent()
611 for enum in self.enums.itervalues():
612 code('${start}if (str == "${{enum.ident}}") {')
613 code(' return ${{self.c_ident}}_${{enum.ident}};')
614 start = "} else "
615 code.dedent()
616
617 code('''
618 } else {
619 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
620 }
621}
622
623// Code to increment an enumeration type
624${{self.c_ident}}&
625operator++(${{self.c_ident}}& e)
626{
627 assert(e < ${{self.c_ident}}_NUM);
628 return e = ${{self.c_ident}}(e+1);
629}
630''')
631
632 # MachineType hack used to set the base level and number of
633 # components for each Machine
634 if self.isMachineType:
635 code('''
636/** \\brief returns the base vector index for each machine type to be
637 * used by NetDest
638 *
639 * \\return the base vector index for each machine type to be used by NetDest
640 * \\see NetDest.hh
641 */
642int
643${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
644{
645 switch(obj) {
646''')
647
648 # For each field
649 code.indent()
650 for i,enum in enumerate(self.enums.itervalues()):
651 code(' case ${{self.c_ident}}_${{enum.ident}}:')
652 code(' return $i;')
653 code.dedent()
654
655 # total num
656 code('''
657 case ${{self.c_ident}}_NUM:
658 return ${{len(self.enums)}};
659
660 default:
661 panic("Invalid range for type ${{self.c_ident}}");
662 }
663}
664
665/** \\brief returns the machine type for each base vector index used by NetDest
666 *
667 * \\return the MachineType
668 */
669MachineType
670${{self.c_ident}}_from_base_level(int type)
671{
672 switch(type) {
673''')
674
675 # For each field
676 code.indent()
677 for i,enum in enumerate(self.enums.itervalues()):
678 code(' case $i:')
679 code(' return ${{self.c_ident}}_${{enum.ident}};')
680 code.dedent()
681
682 # Trailer
683 code('''
684 default:
685 panic("Invalid range for type ${{self.c_ident}}");
686 }
687}
688
689/** \\brief The return value indicates the number of components created
690 * before a particular machine\'s components
691 *
692 * \\return the base number of components for each machine
693 */
694int
695${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
696{
697 int base = 0;
698 switch(obj) {
699''')
700
701 # For each field
702 code.indent()
703 code(' case ${{self.c_ident}}_NUM:')
704 for enum in reversed(self.enums.values()):
705 # Check if there is a defined machine with this type
706 if enum.get("Primary"):
707 code(' base += ${{enum.ident}}_Controller::getNumControllers();')
708 else:
709 code(' base += 0;')
710 code(' case ${{self.c_ident}}_${{enum.ident}}:')
711 code(' break;')
712 code.dedent()
713
714 code('''
715 default:
716 panic("Invalid range for type ${{self.c_ident}}");
717 }
718
719 return base;
720}
721
722/** \\brief returns the total number of components for each machine
723 * \\return the total number of components for each machine
724 */
725int
726${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
727{
728 switch(obj) {
729''')
730
731 # For each field
732 for enum in self.enums.itervalues():
733 code('case ${{self.c_ident}}_${{enum.ident}}:')
734 if enum.get("Primary"):
735 code('return ${{enum.ident}}_Controller::getNumControllers();')
736 else:
737 code('return 0;')
738
739 # total num
740 code('''
741 case ${{self.c_ident}}_NUM:
742 default:
743 panic("Invalid range for type ${{self.c_ident}}");
744 }
745}
746''')
747
748 for enum in self.enums.itervalues():
749 if enum.ident == "DMA":
750 code('''
751MachineID
752map_Address_to_DMA(const Addr &addr)
753{
754 MachineID dma = {MachineType_DMA, 0};
755 return dma;
756}
757''')
758
759 code('''
760
761MachineID
762get${{enum.ident}}MachineID(NodeID RubyNode)
763{
764 MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
765 return mach;
766}
767''')
768
769 # Write the file
770 code.write(path, "%s.cc" % self.c_ident)
771
772__all__ = [ "Type" ]
134 return True
135
136 def dataMemberType(self, ident):
137 return self.data_members[ident].type
138
139 def methodId(self, name, param_type_vec):
140 return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
141
142 def methodIdAbstract(self, name, param_type_vec):
143 return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
144
145 def statePermPairAdd(self, state_name, perm_name):
146 self.statePermPairs.append([state_name, perm_name])
147
148 def addFunc(self, func):
149 ident = self.methodId(func.ident, func.param_types)
150 if ident in self.methods:
151 return False
152
153 self.methods[ident] = func
154 return True
155
156 def addEnum(self, ident, pairs):
157 if ident in self.enums:
158 return False
159
160 self.enums[ident] = Enumeration(ident, pairs)
161
162 # Add default
163 if "default" not in self:
164 self["default"] = "%s_NUM" % self.c_ident
165
166 return True
167
168 def writeCodeFiles(self, path, includes):
169 if self.isExternal:
170 # Do nothing
171 pass
172 elif self.isEnumeration:
173 self.printEnumHH(path)
174 self.printEnumCC(path)
175 else:
176 # User defined structs and messages
177 self.printTypeHH(path)
178 self.printTypeCC(path)
179
180 def printTypeHH(self, path):
181 code = self.symtab.codeFormatter()
182 code('''
183/** \\file ${{self.c_ident}}.hh
184 *
185 *
186 * Auto generated C++ code started by $__file__:$__line__
187 */
188
189#ifndef __${{self.c_ident}}_HH__
190#define __${{self.c_ident}}_HH__
191
192#include <iostream>
193
194#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
195''')
196
197 for dm in self.data_members.values():
198 if not dm.type.isPrimitive:
199 code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
200
201 parent = ""
202 if "interface" in self:
203 code('#include "mem/protocol/$0.hh"', self["interface"])
204 parent = " : public %s" % self["interface"]
205
206 code('''
207$klass ${{self.c_ident}}$parent
208{
209 public:
210 ${{self.c_ident}}
211''', klass="class")
212
213 if self.isMessage:
214 code('(Tick curTime) : %s(curTime) {' % self["interface"])
215 else:
216 code('()\n\t\t{')
217
218 code.indent()
219 if not self.isGlobal:
220 code.indent()
221 for dm in self.data_members.values():
222 ident = dm.ident
223 if "default" in dm:
224 # look for default value
225 code('m_$ident = ${{dm["default"]}}; // default for this field')
226 elif "default" in dm.type:
227 # Look for the type default
228 tid = dm.type.c_ident
229 code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
230 else:
231 code('// m_$ident has no default')
232 code.dedent()
233 code('}')
234
235 # ******** Copy constructor ********
236 if not self.isGlobal:
237 code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
238
239 # Call superclass constructor
240 if "interface" in self:
241 code(' : ${{self["interface"]}}(other)')
242
243 code('{')
244 code.indent()
245
246 for dm in self.data_members.values():
247 code('m_${{dm.ident}} = other.m_${{dm.ident}};')
248
249 code.dedent()
250 code('}')
251
252 # ******** Full init constructor ********
253 if not self.isGlobal:
254 params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
255 for dm in self.data_members.itervalues() ]
256 params = ', '.join(params)
257
258 if self.isMessage:
259 params = "const Tick curTime, " + params
260
261 code('${{self.c_ident}}($params)')
262
263 # Call superclass constructor
264 if "interface" in self:
265 if self.isMessage:
266 code(' : ${{self["interface"]}}(curTime)')
267 else:
268 code(' : ${{self["interface"]}}()')
269
270 code('{')
271 code.indent()
272 for dm in self.data_members.values():
273 code('m_${{dm.ident}} = local_${{dm.ident}};')
274
275 code.dedent()
276 code('}')
277
278 # create a clone member
279 if self.isMessage:
280 code('''
281MsgPtr
282clone() const
283{
284 return std::shared_ptr<Message>(new ${{self.c_ident}}(*this));
285}
286''')
287 else:
288 code('''
289${{self.c_ident}}*
290clone() const
291{
292 return new ${{self.c_ident}}(*this);
293}
294''')
295
296 if not self.isGlobal:
297 # const Get methods for each field
298 code('// Const accessors methods for each field')
299 for dm in self.data_members.values():
300 code('''
301/** \\brief Const accessor method for ${{dm.ident}} field.
302 * \\return ${{dm.ident}} field
303 */
304const ${{dm.type.c_ident}}&
305get${{dm.ident}}() const
306{
307 return m_${{dm.ident}};
308}
309''')
310
311 # Non-const Get methods for each field
312 code('// Non const Accessors methods for each field')
313 for dm in self.data_members.values():
314 code('''
315/** \\brief Non-const accessor method for ${{dm.ident}} field.
316 * \\return ${{dm.ident}} field
317 */
318${{dm.type.c_ident}}&
319get${{dm.ident}}()
320{
321 return m_${{dm.ident}};
322}
323''')
324
325 #Set methods for each field
326 code('// Mutator methods for each field')
327 for dm in self.data_members.values():
328 code('''
329/** \\brief Mutator method for ${{dm.ident}} field */
330void
331set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
332{
333 m_${{dm.ident}} = local_${{dm.ident}};
334}
335''')
336
337 code('void print(std::ostream& out) const;')
338 code.dedent()
339 code(' //private:')
340 code.indent()
341
342 # Data members for each field
343 for dm in self.data_members.values():
344 if "abstract" not in dm:
345 const = ""
346 init = ""
347
348 # global structure
349 if self.isGlobal:
350 const = "static const "
351
352 # init value
353 if dm.init_code:
354 # only global structure can have init value here
355 assert self.isGlobal
356 init = " = %s" % (dm.init_code)
357
358 if "desc" in dm:
359 code('/** ${{dm["desc"]}} */')
360
361 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
362
363 # Prototypes for methods defined for the Type
364 for item in self.methods:
365 proto = self.methods[item].prototype
366 if proto:
367 code('$proto')
368
369 code.dedent()
370 code('};')
371
372 code('''
373inline std::ostream&
374operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
375{
376 obj.print(out);
377 out << std::flush;
378 return out;
379}
380
381#endif // __${{self.c_ident}}_HH__
382''')
383
384 code.write(path, "%s.hh" % self.c_ident)
385
386 def printTypeCC(self, path):
387 code = self.symtab.codeFormatter()
388
389 code('''
390/** \\file ${{self.c_ident}}.cc
391 *
392 * Auto generated C++ code started by $__file__:$__line__
393 */
394
395#include <iostream>
396#include <memory>
397
398#include "mem/protocol/${{self.c_ident}}.hh"
399#include "mem/ruby/system/RubySystem.hh"
400
401using namespace std;
402''')
403
404 code('''
405/** \\brief Print the state of this object */
406void
407${{self.c_ident}}::print(ostream& out) const
408{
409 out << "[${{self.c_ident}}: ";
410''')
411
412 # For each field
413 code.indent()
414 for dm in self.data_members.values():
415 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
416
417 code.dedent()
418
419 # Trailer
420 code('''
421 out << "]";
422}''')
423
424 # print the code for the methods in the type
425 for item in self.methods:
426 code(self.methods[item].generateCode())
427
428 code.write(path, "%s.cc" % self.c_ident)
429
430 def printEnumHH(self, path):
431 code = self.symtab.codeFormatter()
432 code('''
433/** \\file ${{self.c_ident}}.hh
434 *
435 * Auto generated C++ code started by $__file__:$__line__
436 */
437
438#ifndef __${{self.c_ident}}_HH__
439#define __${{self.c_ident}}_HH__
440
441#include <iostream>
442#include <string>
443
444''')
445 if self.isStateDecl:
446 code('#include "mem/protocol/AccessPermission.hh"')
447
448 if self.isMachineType:
449 code('#include "base/misc.hh"')
450 code('#include "mem/ruby/common/Address.hh"')
451 code('#include "mem/ruby/common/TypeDefines.hh"')
452 code('struct MachineID;')
453
454 code('''
455
456// Class definition
457/** \\enum ${{self.c_ident}}
458 * \\brief ${{self.desc}}
459 */
460enum ${{self.c_ident}} {
461 ${{self.c_ident}}_FIRST,
462''')
463
464 code.indent()
465 # For each field
466 for i,(ident,enum) in enumerate(self.enums.iteritems()):
467 desc = enum.get("desc", "No description avaliable")
468 if i == 0:
469 init = ' = %s_FIRST' % self.c_ident
470 else:
471 init = ''
472 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
473 code.dedent()
474 code('''
475 ${{self.c_ident}}_NUM
476};
477
478// Code to convert from a string to the enumeration
479${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
480
481// Code to convert state to a string
482std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
483
484// Code to increment an enumeration type
485${{self.c_ident}} &operator++(${{self.c_ident}} &e);
486''')
487
488 # MachineType hack used to set the base component id for each Machine
489 if self.isMachineType:
490 code('''
491int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
492MachineType ${{self.c_ident}}_from_base_level(int);
493int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
494int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
495''')
496
497 for enum in self.enums.itervalues():
498 if enum.ident == "DMA":
499 code('''
500MachineID map_Address_to_DMA(const Addr &addr);
501''')
502 code('''
503
504MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
505''')
506
507 if self.isStateDecl:
508 code('''
509
510// Code to convert the current state to an access permission
511AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
512
513''')
514
515 # Trailer
516 code('''
517std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
518
519#endif // __${{self.c_ident}}_HH__
520''')
521
522 code.write(path, "%s.hh" % self.c_ident)
523
524 def printEnumCC(self, path):
525 code = self.symtab.codeFormatter()
526 code('''
527/** \\file ${{self.c_ident}}.hh
528 *
529 * Auto generated C++ code started by $__file__:$__line__
530 */
531
532#include <cassert>
533#include <iostream>
534#include <string>
535
536#include "base/misc.hh"
537#include "mem/protocol/${{self.c_ident}}.hh"
538
539using namespace std;
540
541''')
542
543 if self.isStateDecl:
544 code('''
545// Code to convert the current state to an access permission
546AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
547{
548 switch(obj) {
549''')
550 # For each case
551 code.indent()
552 for statePerm in self.statePermPairs:
553 code(' case ${{self.c_ident}}_${{statePerm[0]}}:')
554 code(' return AccessPermission_${{statePerm[1]}};')
555 code.dedent()
556 code ('''
557 default:
558 panic("Unknown state access permission converstion for ${{self.c_ident}}");
559 }
560}
561
562''')
563
564 if self.isMachineType:
565 for enum in self.enums.itervalues():
566 if enum.get("Primary"):
567 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
568 code('#include "mem/ruby/common/MachineID.hh"')
569
570 code('''
571// Code for output operator
572ostream&
573operator<<(ostream& out, const ${{self.c_ident}}& obj)
574{
575 out << ${{self.c_ident}}_to_string(obj);
576 out << flush;
577 return out;
578}
579
580// Code to convert state to a string
581string
582${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
583{
584 switch(obj) {
585''')
586
587 # For each field
588 code.indent()
589 for enum in self.enums.itervalues():
590 code(' case ${{self.c_ident}}_${{enum.ident}}:')
591 code(' return "${{enum.ident}}";')
592 code.dedent()
593
594 # Trailer
595 code('''
596 default:
597 panic("Invalid range for type ${{self.c_ident}}");
598 }
599}
600
601// Code to convert from a string to the enumeration
602${{self.c_ident}}
603string_to_${{self.c_ident}}(const string& str)
604{
605''')
606
607 # For each field
608 start = ""
609 code.indent()
610 for enum in self.enums.itervalues():
611 code('${start}if (str == "${{enum.ident}}") {')
612 code(' return ${{self.c_ident}}_${{enum.ident}};')
613 start = "} else "
614 code.dedent()
615
616 code('''
617 } else {
618 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
619 }
620}
621
622// Code to increment an enumeration type
623${{self.c_ident}}&
624operator++(${{self.c_ident}}& e)
625{
626 assert(e < ${{self.c_ident}}_NUM);
627 return e = ${{self.c_ident}}(e+1);
628}
629''')
630
631 # MachineType hack used to set the base level and number of
632 # components for each Machine
633 if self.isMachineType:
634 code('''
635/** \\brief returns the base vector index for each machine type to be
636 * used by NetDest
637 *
638 * \\return the base vector index for each machine type to be used by NetDest
639 * \\see NetDest.hh
640 */
641int
642${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
643{
644 switch(obj) {
645''')
646
647 # For each field
648 code.indent()
649 for i,enum in enumerate(self.enums.itervalues()):
650 code(' case ${{self.c_ident}}_${{enum.ident}}:')
651 code(' return $i;')
652 code.dedent()
653
654 # total num
655 code('''
656 case ${{self.c_ident}}_NUM:
657 return ${{len(self.enums)}};
658
659 default:
660 panic("Invalid range for type ${{self.c_ident}}");
661 }
662}
663
664/** \\brief returns the machine type for each base vector index used by NetDest
665 *
666 * \\return the MachineType
667 */
668MachineType
669${{self.c_ident}}_from_base_level(int type)
670{
671 switch(type) {
672''')
673
674 # For each field
675 code.indent()
676 for i,enum in enumerate(self.enums.itervalues()):
677 code(' case $i:')
678 code(' return ${{self.c_ident}}_${{enum.ident}};')
679 code.dedent()
680
681 # Trailer
682 code('''
683 default:
684 panic("Invalid range for type ${{self.c_ident}}");
685 }
686}
687
688/** \\brief The return value indicates the number of components created
689 * before a particular machine\'s components
690 *
691 * \\return the base number of components for each machine
692 */
693int
694${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
695{
696 int base = 0;
697 switch(obj) {
698''')
699
700 # For each field
701 code.indent()
702 code(' case ${{self.c_ident}}_NUM:')
703 for enum in reversed(self.enums.values()):
704 # Check if there is a defined machine with this type
705 if enum.get("Primary"):
706 code(' base += ${{enum.ident}}_Controller::getNumControllers();')
707 else:
708 code(' base += 0;')
709 code(' case ${{self.c_ident}}_${{enum.ident}}:')
710 code(' break;')
711 code.dedent()
712
713 code('''
714 default:
715 panic("Invalid range for type ${{self.c_ident}}");
716 }
717
718 return base;
719}
720
721/** \\brief returns the total number of components for each machine
722 * \\return the total number of components for each machine
723 */
724int
725${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
726{
727 switch(obj) {
728''')
729
730 # For each field
731 for enum in self.enums.itervalues():
732 code('case ${{self.c_ident}}_${{enum.ident}}:')
733 if enum.get("Primary"):
734 code('return ${{enum.ident}}_Controller::getNumControllers();')
735 else:
736 code('return 0;')
737
738 # total num
739 code('''
740 case ${{self.c_ident}}_NUM:
741 default:
742 panic("Invalid range for type ${{self.c_ident}}");
743 }
744}
745''')
746
747 for enum in self.enums.itervalues():
748 if enum.ident == "DMA":
749 code('''
750MachineID
751map_Address_to_DMA(const Addr &addr)
752{
753 MachineID dma = {MachineType_DMA, 0};
754 return dma;
755}
756''')
757
758 code('''
759
760MachineID
761get${{enum.ident}}MachineID(NodeID RubyNode)
762{
763 MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
764 return mach;
765}
766''')
767
768 # Write the file
769 code.write(path, "%s.cc" % self.c_ident)
770
771__all__ = [ "Type" ]