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