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