1 # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2 # Copyright (c) 2009 The Hewlett-Packard Development Company
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.
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.
28 from m5
.util
import orderdict
30 from slicc
.util
import PairContainer
31 from slicc
.symbols
.Symbol
import Symbol
33 class DataMember(PairContainer
):
34 def __init__(self
, ident
, type, pairs
, init_code
):
35 super(DataMember
, self
).__init
__(pairs
)
38 self
.init_code
= init_code
40 class Enumeration(PairContainer
):
41 def __init__(self
, ident
, pairs
):
42 super(Enumeration
, self
).__init
__(pairs
)
46 def __init__(self
, return_type
, param_types
):
47 self
.return_type
= return_type
48 self
.param_types
= param_types
51 def __init__(self
, table
, ident
, location
, pairs
, machine
=None):
52 super(Type
, self
).__init
__(table
, ident
, location
, pairs
)
54 self
.abstract_ident
= ""
56 if self
.isExternal
or self
.isPrimitive
:
57 if "external_name" in self
:
58 self
.c_ident
= self
["external_name"]
60 # Append with machine name
61 self
.c_ident
= "%s_%s" % (machine
, ident
)
63 self
.pairs
.setdefault("desc", "No description avaliable")
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"
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"):
80 if self
.ident
in ("TBETable", "DNUCATBETable", "DNUCAStopTable"):
83 if self
.ident
== "NewTBETable":
84 self
["newtbe"] = "yes"
86 if self
.ident
== "TimerTable":
89 if self
.ident
== "DirectoryMemory":
92 if self
.ident
== "PersistentTable":
93 self
["persistent"] = "yes"
95 if self
.ident
== "Prefetcher":
96 self
["prefetcher"] = "yes"
98 if self
.ident
== "DNUCA_Movement":
101 self
.isMachineType
= (ident
== "MachineType")
103 self
.data_members
= orderdict()
109 self
.enums
= orderdict()
112 def isPrimitive(self
):
113 return "primitive" in self
115 def isNetworkMessage(self
):
116 return "networkmessage" in self
119 return "message" in self
122 return "buffer" in self
125 return "inport" in self
128 return "outport" in self
130 def isEnumeration(self
):
131 return "enumeration" in self
133 def isExternal(self
):
134 return "external" in self
137 return "global" in self
139 def isInterface(self
):
140 return "interface" in self
142 # Return false on error
143 def dataMemberAdd(self
, ident
, type, pairs
, init_code
):
144 if ident
in self
.data_members
:
147 member
= DataMember(ident
, type, pairs
, init_code
)
148 self
.data_members
[ident
] = member
152 def dataMemberType(self
, ident
):
153 return self
.data_members
[ident
].type
155 def methodId(self
, name
, param_type_vec
):
156 return '_'.join([name
] + [ pt
.c_ident
for pt
in param_type_vec
])
158 def methodIdAbstract(self
, name
, param_type_vec
):
159 return '_'.join([name
] + [ pt
.abstract_ident
for pt
in param_type_vec
])
161 def methodAdd(self
, name
, return_type
, param_type_vec
):
162 ident
= self
.methodId(name
, param_type_vec
)
163 if ident
in self
.methods
:
166 self
.methods
[ident
] = Method(return_type
, param_type_vec
)
169 def enumAdd(self
, ident
, pairs
):
170 if ident
in self
.enums
:
173 self
.enums
[ident
] = Enumeration(ident
, pairs
)
176 if "default" not in self
:
177 self
["default"] = "%s_NUM" % self
.c_ident
181 def writeCodeFiles(self
, path
):
185 elif self
.isEnumeration
:
186 self
.printEnumHH(path
)
187 self
.printEnumCC(path
)
189 # User defined structs and messages
190 self
.printTypeHH(path
)
191 self
.printTypeCC(path
)
193 def printTypeHH(self
, path
):
194 code
= self
.symtab
.codeFormatter()
196 /** \\file ${{self.c_ident}}.hh
199 * Auto generated C++ code started by $__file__:$__line__
202 #ifndef __${{self.c_ident}}_HH__
203 #define __${{self.c_ident}}_HH__
207 #include "mem/ruby/common/Global.hh"
208 #include "mem/gems_common/Allocator.hh"
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
)
216 if "interface" in self
:
217 code('#include "mem/protocol/$0.hh"', self
["interface"])
218 parent
= " : public %s" % self
["interface"]
221 $klass ${{self.c_ident}}$parent
229 if not self
.isGlobal
:
231 for dm
in self
.data_members
.values():
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')
241 code('// m_$ident has no default')
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() ]
251 params
.append('const unsigned local_proc_id')
253 params
= ', '.join(params
)
254 code('${{self.c_ident}}($params)')
256 # Call superclass constructor
257 if "interface" in self
:
258 code(' : ${{self["interface"]}}()')
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"]}};')
268 code('proc_id = local_proc_id;')
273 # create a static factory method
274 if "interface" in self
:
276 static ${{self["interface"]}}*
279 return new ${{self.c_ident}}();
283 # ******** Message member functions ********
284 # FIXME: those should be moved into slicc file, slicc should
285 # support more of the c++ class inheritance
293 return s_allocator_ptr->allocate(*this);
300 s_allocator_ptr->deallocate(this);
303 static Allocator<${{self.c_ident}}>* s_allocator_ptr;
308 if (s_allocator_ptr == NULL) {
309 s_allocator_ptr = new Allocator<${{self.c_ident}}>;
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():
319 /** \\brief Const accessor method for ${{dm.ident}} field.
320 * \\return ${{dm.ident}} field
322 const ${{dm.type.c_ident}}&
323 get${{dm.ident}}() const
325 return m_${{dm.ident}};
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():
333 /** \\brief Non-const accessor method for ${{dm.ident}} field.
334 * \\return ${{dm.ident}} field
336 ${{dm.type.c_ident}}&
339 return m_${{dm.ident}};
343 #Set methods for each field
344 code('// Mutator methods for each field')
345 for dm
in self
.data_members
.values():
347 /** \\brief Mutator method for ${{dm.ident}} field */
349 set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
351 m_${{dm.ident}} = local_${{dm.ident}};
355 code('void print(std::ostream& out) const;')
360 # Data members for each field
361 for dm
in self
.data_members
.values():
362 if "abstract" not in dm
:
368 const
= "static const "
372 # only global structure can have init value here
374 init
= " = %s" % (dm
.init_code
)
377 code('/** ${{dm["desc"]}} */')
379 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
382 code('unsigned proc_id;')
388 // Output operator declaration
390 operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
392 // Output operator definition
393 extern inline std::ostream&
394 operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
401 #endif // __${{self.c_ident}}_HH__
404 code
.write(path
, "%s.hh" % self
.c_ident
)
406 def printTypeCC(self
, path
):
407 code
= self
.symtab
.codeFormatter()
410 /** \\file ${{self.c_ident}}.cc
412 * Auto generated C++ code started by $__file__:$__line__
417 #include "mem/protocol/${{self.c_ident}}.hh"
423 code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;')
425 /** \\brief Print the state of this object */
427 ${{self.c_ident}}::print(ostream& out) const
429 out << "[${{self.c_ident}}: ";
434 for dm
in self
.data_members
.values():
435 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
438 code('out
<< "Time = " << getTime() << " ";')
446 code.write(path, "%s.cc" % self.c_ident)
448 def printEnumHH(self, path):
449 code = self.symtab.codeFormatter()
451 /** \\file ${{self.c_ident}}.hh
453 * Auto generated C++ code started by $__file__:$__line__
456 #ifndef __${{self.c_ident}}_HH__
457 #define __${{self.c_ident}}_HH__
462 #include "mem/ruby/common/Global.hh"
465 /** \\enum ${{self.c_ident}}
466 * \\brief ${{self.desc}}
468 enum ${{self.c_ident}} {
469 ${{self.c_ident}}_FIRST,
474 for i,(ident,enum) in enumerate(self.enums.iteritems()):
475 desc = enum.get("desc", "No description avaliable")
477 init = ' = %s_FIRST
' % self.c_ident
480 code('$
{{self
.c_ident
}}_$
{{enum
.ident
}}$init
, /**< $desc
*/')
483 ${{self.c_ident}}_NUM
486 // Code to convert from a string to the enumeration
487 ${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
489 // Code to convert state to a string
490 std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
492 // Code to increment an enumeration type
493 ${{self.c_ident}} &operator++(${{self.c_ident}} &e);
496 # MachineType hack used to set the base component id for each Machine
497 if self.isMachineType:
499 int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
500 MachineType ${{self.c_ident}}_from_base_level(int);
501 int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
502 int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
505 for enum in self.enums.itervalues():
506 code('#define MACHINETYPE_${{enum.ident}} 1')
510 std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
512 #endif // __${{self.c_ident}}_HH__
515 code
.write(path
, "%s.hh" % self
.c_ident
)
517 def printEnumCC(self
, path
):
518 code
= self
.symtab
.codeFormatter()
520 /** \\file ${{self.c_ident}}.hh
522 * Auto generated C++ code started by $__file__:$__line__
528 #include "mem/protocol/${{self.c_ident}}.hh"
534 if self
.isMachineType
:
535 for enum
in self
.enums
.itervalues():
536 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
539 // Code for output operator
541 operator<<(ostream& out, const ${{self.c_ident}}& obj)
543 out << ${{self.c_ident}}_to_string(obj);
548 // Code to convert state to a string
550 ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
557 for enum
in self
.enums
.itervalues():
558 code(' case ${{self.c_ident}}_${{enum.ident}}:')
559 code(' return "${{enum.ident}}";')
565 ERROR_MSG("Invalid range for type ${{self.c_ident}}");
570 // Code to convert from a string to the enumeration
572 string_to_${{self.c_ident}}(const string& str)
579 for enum
in self
.enums
.itervalues():
580 code('${start}if (str == "${{enum.ident}}") {')
581 code(' return ${{self.c_ident}}_${{enum.ident}};')
588 ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}");
592 // Code to increment an enumeration type
594 operator++(${{self.c_ident}}& e)
596 assert(e < ${{self.c_ident}}_NUM);
597 return e = ${{self.c_ident}}(e+1);
601 # MachineType hack used to set the base level and number of
602 # components for each Machine
603 if self
.isMachineType
:
605 /** \\brief returns the base vector index for each machine type to be
608 * \\return the base vector index for each machine type to be used by NetDest
612 ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
619 for i
,enum
in enumerate(self
.enums
.itervalues()):
620 code(' case ${{self.c_ident}}_${{enum.ident}}:')
626 case ${{self.c_ident}}_NUM:
627 return ${{len(self.enums)}};
630 ERROR_MSG("Invalid range for type ${{self.c_ident}}");
635 /** \\brief returns the machine type for each base vector index used by NetDest
637 * \\return the MachineType
640 ${{self.c_ident}}_from_base_level(int type)
647 for i
,enum
in enumerate(self
.enums
.itervalues()):
649 code(' return ${{self.c_ident}}_${{enum.ident}};')
655 ERROR_MSG("Invalid range for type ${{self.c_ident}}");
656 return MachineType_NUM;
660 /** \\brief The return value indicates the number of components created
661 * before a particular machine\'s components
663 * \\return the base number of components for each machine
666 ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
674 code(' case ${{self.c_ident}}_NUM:')
675 for enum
in reversed(self
.enums
.values()):
676 code(' base += ${{enum.ident}}_Controller::getNumControllers();')
677 code(' case ${{self.c_ident}}_${{enum.ident}}:')
683 ERROR_MSG("Invalid range for type ${{self.c_ident}}");
690 /** \\brief returns the total number of components for each machine
691 * \\return the total number of components for each machine
694 ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
700 for enum
in self
.enums
.itervalues():
702 case ${{self.c_ident}}_${{enum.ident}}:
703 return ${{enum.ident}}_Controller::getNumControllers();
708 case ${{self.c_ident}}_NUM:
710 ERROR_MSG("Invalid range for type ${{self.c_ident}}");
717 code
.write(path
, "%s.cc" % self
.c_ident
)