Deleted Added
sdiff udiff text old ( 9298:9a087e046c58 ) new ( 9302:c2e70a9bc340 )
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
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"):
79 self["cache"] = "yes"
80
81 if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"):
82 self["tbe"] = "yes"
83
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
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/common/Global.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 {
247''', klass="class")
248
249 code.indent()
250 if not self.isGlobal:
251 code.indent()
252 for dm in self.data_members.values():
253 ident = dm.ident
254 if "default" in dm:
255 # look for default value
256 code('m_$ident = ${{dm["default"]}}; // default for this field')
257 elif "default" in dm.type:
258 # Look for the type default
259 tid = dm.type.c_ident
260 code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
261 else:
262 code('// m_$ident has no default')
263 code.dedent()
264 code('}')
265
266 # ******** Copy constructor ********
267 if not self.isGlobal:
268 code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
269
270 # Call superclass constructor
271 if "interface" in self:
272 code(' : ${{self["interface"]}}(other)')
273
274 code('{')
275 code.indent()
276
277 for dm in self.data_members.values():
278 code('m_${{dm.ident}} = other.m_${{dm.ident}};')
279
280 code.dedent()
281 code('}')
282
283 # ******** Full init constructor ********
284 if not self.isGlobal:
285 params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
286 for dm in self.data_members.itervalues() ]
287
288 params = ', '.join(params)
289 code('${{self.c_ident}}($params)')
290
291 # Call superclass constructor
292 if "interface" in self:
293 code(' : ${{self["interface"]}}()')
294
295 code('{')
296 code.indent()
297 for dm in self.data_members.values():
298 code('m_${{dm.ident}} = local_${{dm.ident}};')
299 if "nextLineCallHack" in dm:
300 code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};')
301
302 code.dedent()
303 code('}')
304
305 # create a static factory method and a clone member
306 code('''
307static ${{self.c_ident}}*
308create()
309{
310 return new ${{self.c_ident}}();
311}
312
313${{self.c_ident}}*
314clone() const
315{
316 return new ${{self.c_ident}}(*this);
317}
318''')
319
320 if not self.isGlobal:
321 # const Get methods for each field
322 code('// Const accessors methods for each field')
323 for dm in self.data_members.values():
324 code('''
325/** \\brief Const accessor method for ${{dm.ident}} field.
326 * \\return ${{dm.ident}} field
327 */
328const ${{dm.type.c_ident}}&
329get${{dm.ident}}() const
330{
331 return m_${{dm.ident}};
332}
333''')
334
335 # Non-const Get methods for each field
336 code('// Non const Accessors methods for each field')
337 for dm in self.data_members.values():
338 code('''
339/** \\brief Non-const accessor method for ${{dm.ident}} field.
340 * \\return ${{dm.ident}} field
341 */
342${{dm.type.c_ident}}&
343get${{dm.ident}}()
344{
345 return m_${{dm.ident}};
346}
347''')
348
349 #Set methods for each field
350 code('// Mutator methods for each field')
351 for dm in self.data_members.values():
352 code('''
353/** \\brief Mutator method for ${{dm.ident}} field */
354void
355set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
356{
357 m_${{dm.ident}} = local_${{dm.ident}};
358}
359''')
360
361 code('void print(std::ostream& out) const;')
362 code.dedent()
363 code(' //private:')
364 code.indent()
365
366 # Data members for each field
367 for dm in self.data_members.values():
368 if "abstract" not in dm:
369 const = ""
370 init = ""
371
372 # global structure
373 if self.isGlobal:
374 const = "static const "
375
376 # init value
377 if dm.init_code:
378 # only global structure can have init value here
379 assert self.isGlobal
380 init = " = %s" % (dm.init_code)
381
382 if "desc" in dm:
383 code('/** ${{dm["desc"]}} */')
384
385 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
386
387 # Prototypes for functions defined for the Type
388 for item in self.functions:
389 proto = self.functions[item].prototype
390 if proto:
391 code('$proto')
392
393 code.dedent()
394 code('};')
395
396 code('''
397inline std::ostream&
398operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
399{
400 obj.print(out);
401 out << std::flush;
402 return out;
403}
404
405#endif // __${{self.c_ident}}_HH__
406''')
407
408 code.write(path, "%s.hh" % self.c_ident)
409
410 def printTypeCC(self, path):
411 code = self.symtab.codeFormatter()
412
413 code('''
414/** \\file ${{self.c_ident}}.cc
415 *
416 * Auto generated C++ code started by $__file__:$__line__
417 */
418
419#include <iostream>
420
421#include "mem/protocol/${{self.c_ident}}.hh"
422#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
423
424using namespace std;
425''')
426
427 code('''
428/** \\brief Print the state of this object */
429void
430${{self.c_ident}}::print(ostream& out) const
431{
432 out << "[${{self.c_ident}}: ";
433''')
434
435 # For each field
436 code.indent()
437 for dm in self.data_members.values():
438 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
439
440 if self.isMessage:
441 code('out << "Time = " << g_system_ptr->clockPeriod() * getTime() << " ";')
442 code.dedent()
443
444 # Trailer
445 code('''
446 out << "]";
447}''')
448
449 # print the code for the functions in the type
450 for item in self.functions:
451 code(self.functions[item].generateCode())
452
453 code.write(path, "%s.cc" % self.c_ident)
454
455 def printEnumHH(self, path):
456 code = self.symtab.codeFormatter()
457 code('''
458/** \\file ${{self.c_ident}}.hh
459 *
460 * Auto generated C++ code started by $__file__:$__line__
461 */
462
463#ifndef __${{self.c_ident}}_HH__
464#define __${{self.c_ident}}_HH__
465
466#include <iostream>
467#include <string>
468
469''')
470 if self.isStateDecl:
471 code('#include "mem/protocol/AccessPermission.hh"')
472
473 if self.isMachineType:
474 code('#include "base/misc.hh"')
475 code('#include "mem/protocol/GenericMachineType.hh"')
476 code('#include "mem/ruby/common/Address.hh"')
477 code('struct MachineID;')
478
479 code('''
480
481// Class definition
482/** \\enum ${{self.c_ident}}
483 * \\brief ${{self.desc}}
484 */
485enum ${{self.c_ident}} {
486 ${{self.c_ident}}_FIRST,
487''')
488
489 code.indent()
490 # For each field
491 for i,(ident,enum) in enumerate(self.enums.iteritems()):
492 desc = enum.get("desc", "No description avaliable")
493 if i == 0:
494 init = ' = %s_FIRST' % self.c_ident
495 else:
496 init = ''
497 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
498 code.dedent()
499 code('''
500 ${{self.c_ident}}_NUM
501};
502
503// Code to convert from a string to the enumeration
504${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
505
506// Code to convert state to a string
507std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
508
509// Code to increment an enumeration type
510${{self.c_ident}} &operator++(${{self.c_ident}} &e);
511''')
512
513 # MachineType hack used to set the base component id for each Machine
514 if self.isMachineType:
515 code('''
516int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
517MachineType ${{self.c_ident}}_from_base_level(int);
518int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
519int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
520''')
521
522 for enum in self.enums.itervalues():
523 if enum.ident == "DMA":
524 code('''
525MachineID map_Address_to_DMA(const Address &addr);
526''')
527 code('''
528
529MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
530''')
531
532 code('''
533inline GenericMachineType
534ConvertMachToGenericMach(MachineType machType)
535{
536''')
537 for enum in self.enums.itervalues():
538 code('''
539 if (machType == MachineType_${{enum.ident}})
540 return GenericMachineType_${{enum.ident}};
541''')
542 code('''
543 panic("cannot convert to a GenericMachineType");
544}
545''')
546
547 if self.isStateDecl:
548 code('''
549
550// Code to convert the current state to an access permission
551AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
552
553''')
554
555 # Trailer
556 code('''
557std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
558
559#endif // __${{self.c_ident}}_HH__
560''')
561
562 code.write(path, "%s.hh" % self.c_ident)
563
564 def printEnumCC(self, path):
565 code = self.symtab.codeFormatter()
566 code('''
567/** \\file ${{self.c_ident}}.hh
568 *
569 * Auto generated C++ code started by $__file__:$__line__
570 */
571
572#include <cassert>
573#include <iostream>
574#include <string>
575
576#include "base/misc.hh"
577#include "mem/protocol/${{self.c_ident}}.hh"
578
579using namespace std;
580
581''')
582
583 if self.isStateDecl:
584 code('''
585// Code to convert the current state to an access permission
586AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
587{
588 switch(obj) {
589''')
590 # For each case
591 code.indent()
592 for statePerm in self.statePermPairs:
593 code(' case ${{self.c_ident}}_${{statePerm[0]}}:')
594 code(' return AccessPermission_${{statePerm[1]}};')
595 code.dedent()
596 code ('''
597 default:
598 panic("Unknown state access permission converstion for ${{self.c_ident}}");
599 }
600}
601
602''')
603
604 if self.isMachineType:
605 for enum in self.enums.itervalues():
606 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
607 code('#include "mem/ruby/system/MachineID.hh"')
608
609 code('''
610// Code for output operator
611ostream&
612operator<<(ostream& out, const ${{self.c_ident}}& obj)
613{
614 out << ${{self.c_ident}}_to_string(obj);
615 out << flush;
616 return out;
617}
618
619// Code to convert state to a string
620string
621${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
622{
623 switch(obj) {
624''')
625
626 # For each field
627 code.indent()
628 for enum in self.enums.itervalues():
629 code(' case ${{self.c_ident}}_${{enum.ident}}:')
630 code(' return "${{enum.ident}}";')
631 code.dedent()
632
633 # Trailer
634 code('''
635 default:
636 panic("Invalid range for type ${{self.c_ident}}");
637 }
638}
639
640// Code to convert from a string to the enumeration
641${{self.c_ident}}
642string_to_${{self.c_ident}}(const string& str)
643{
644''')
645
646 # For each field
647 start = ""
648 code.indent()
649 for enum in self.enums.itervalues():
650 code('${start}if (str == "${{enum.ident}}") {')
651 code(' return ${{self.c_ident}}_${{enum.ident}};')
652 start = "} else "
653 code.dedent()
654
655 code('''
656 } else {
657 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
658 }
659}
660
661// Code to increment an enumeration type
662${{self.c_ident}}&
663operator++(${{self.c_ident}}& e)
664{
665 assert(e < ${{self.c_ident}}_NUM);
666 return e = ${{self.c_ident}}(e+1);
667}
668''')
669
670 # MachineType hack used to set the base level and number of
671 # components for each Machine
672 if self.isMachineType:
673 code('''
674/** \\brief returns the base vector index for each machine type to be
675 * used by NetDest
676 *
677 * \\return the base vector index for each machine type to be used by NetDest
678 * \\see NetDest.hh
679 */
680int
681${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
682{
683 switch(obj) {
684''')
685
686 # For each field
687 code.indent()
688 for i,enum in enumerate(self.enums.itervalues()):
689 code(' case ${{self.c_ident}}_${{enum.ident}}:')
690 code(' return $i;')
691 code.dedent()
692
693 # total num
694 code('''
695 case ${{self.c_ident}}_NUM:
696 return ${{len(self.enums)}};
697
698 default:
699 panic("Invalid range for type ${{self.c_ident}}");
700 }
701}
702
703/** \\brief returns the machine type for each base vector index used by NetDest
704 *
705 * \\return the MachineType
706 */
707MachineType
708${{self.c_ident}}_from_base_level(int type)
709{
710 switch(type) {
711''')
712
713 # For each field
714 code.indent()
715 for i,enum in enumerate(self.enums.itervalues()):
716 code(' case $i:')
717 code(' return ${{self.c_ident}}_${{enum.ident}};')
718 code.dedent()
719
720 # Trailer
721 code('''
722 default:
723 panic("Invalid range for type ${{self.c_ident}}");
724 }
725}
726
727/** \\brief The return value indicates the number of components created
728 * before a particular machine\'s components
729 *
730 * \\return the base number of components for each machine
731 */
732int
733${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
734{
735 int base = 0;
736 switch(obj) {
737''')
738
739 # For each field
740 code.indent()
741 code(' case ${{self.c_ident}}_NUM:')
742 for enum in reversed(self.enums.values()):
743 code(' base += ${{enum.ident}}_Controller::getNumControllers();')
744 code(' case ${{self.c_ident}}_${{enum.ident}}:')
745 code(' break;')
746 code.dedent()
747
748 code('''
749 default:
750 panic("Invalid range for type ${{self.c_ident}}");
751 }
752
753 return base;
754}
755
756/** \\brief returns the total number of components for each machine
757 * \\return the total number of components for each machine
758 */
759int
760${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
761{
762 switch(obj) {
763''')
764
765 # For each field
766 for enum in self.enums.itervalues():
767 code('''
768 case ${{self.c_ident}}_${{enum.ident}}:
769 return ${{enum.ident}}_Controller::getNumControllers();
770''')
771
772 # total num
773 code('''
774 case ${{self.c_ident}}_NUM:
775 default:
776 panic("Invalid range for type ${{self.c_ident}}");
777 }
778}
779''')
780
781 for enum in self.enums.itervalues():
782 if enum.ident == "DMA":
783 code('''
784MachineID
785map_Address_to_DMA(const Address &addr)
786{
787 MachineID dma = {MachineType_DMA, 0};
788 return dma;
789}
790''')
791
792 code('''
793
794MachineID
795get${{enum.ident}}MachineID(NodeID RubyNode)
796{
797 MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
798 return mach;
799}
800''')
801
802 # Write the file
803 code.write(path, "%s.cc" % self.c_ident)
804
805__all__ = [ "Type" ]