Deleted Added
sdiff udiff text old ( 10472:399f35ed5cca ) new ( 10895:287285860dd6 )
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 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"):
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
100 @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" ]