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