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