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''') 209 210 for dm in self.data_members.values(): 211 if not dm.type.isPrimitive: 212 code('#include "mem/protocol/$0.hh"', dm.type.c_ident) 213 214 parent = "" 215 if "interface" in self: 216 code('#include "mem/protocol/$0.hh"', self["interface"]) 217 parent = " : public %s" % self["interface"] 218 219 code(''' 220$klass ${{self.c_ident}}$parent 221{ 222 public: 223 ${{self.c_ident}}() 224 { 225''', klass="class") 226 227 code.indent() 228 if not self.isGlobal: 229 code.indent() 230 for dm in self.data_members.values(): 231 ident = dm.ident 232 if "default" in dm: 233 # look for default value 234 code('m_$ident = ${{dm["default"]}}; // default for this field') 235 elif "default" in dm.type: 236 # Look for the type default 237 tid = dm.type.c_ident 238 code('m_$ident = ${{dm.type["default"]}}; // default value of $tid') 239 else: 240 code('// m_$ident has no default') 241 code.dedent() 242 code('}') 243 244 # ******** Copy constructor ******** 245 if not self.isGlobal: 246 code('${{self.c_ident}}(const ${{self.c_ident}}&other)') 247 248 # Call superclass constructor 249 if "interface" in self: 250 code(' : ${{self["interface"]}}(other)') 251 252 code('{') 253 code.indent() 254 255 for dm in self.data_members.values(): 256 code('m_${{dm.ident}} = other.m_${{dm.ident}};') 257 258 if self.isMessage: 259 code('proc_id = other.proc_id;') 260 261 code.dedent() 262 code('}') 263 264 # ******** Full init constructor ******** 265 if not self.isGlobal: 266 params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \ 267 for dm in self.data_members.itervalues() ] 268 269 if self.isMessage: 270 params.append('const unsigned local_proc_id') 271 272 params = ', '.join(params) 273 code('${{self.c_ident}}($params)') 274 275 # Call superclass constructor 276 if "interface" in self: 277 code(' : ${{self["interface"]}}()') 278 279 code('{') 280 code.indent() 281 for dm in self.data_members.values(): 282 code('m_${{dm.ident}} = local_${{dm.ident}};') 283 if "nextLineCallHack" in dm: 284 code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};') 285 286 if self.isMessage: 287 code('proc_id = local_proc_id;') 288 289 code.dedent() 290 code('}') 291 292 # create a static factory method and a clone member 293 code(''' 294static ${{self.c_ident}}* 295create() 296{ 297 return new ${{self.c_ident}}(); 298} 299 300${{self.c_ident}}* 301clone() const 302{ 303 return new ${{self.c_ident}}(*this); 304} 305''') 306 307 if not self.isGlobal: 308 # const Get methods for each field 309 code('// Const accessors methods for each field') 310 for dm in self.data_members.values(): 311 code(''' 312/** \\brief Const accessor method for ${{dm.ident}} field. 313 * \\return ${{dm.ident}} field 314 */ 315const ${{dm.type.c_ident}}& 316get${{dm.ident}}() const 317{ 318 return m_${{dm.ident}}; 319} 320''') 321 322 # Non-const Get methods for each field 323 code('// Non const Accessors methods for each field') 324 for dm in self.data_members.values(): 325 code(''' 326/** \\brief Non-const accessor method for ${{dm.ident}} field. 327 * \\return ${{dm.ident}} field 328 */ 329${{dm.type.c_ident}}& 330get${{dm.ident}}() 331{ 332 return m_${{dm.ident}}; 333} 334''') 335 336 #Set methods for each field 337 code('// Mutator methods for each field') 338 for dm in self.data_members.values(): 339 code(''' 340/** \\brief Mutator method for ${{dm.ident}} field */ 341void 342set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) 343{ 344 m_${{dm.ident}} = local_${{dm.ident}}; 345} 346''') 347 348 code('void print(std::ostream& out) const;') 349 code.dedent() 350 code(' //private:') 351 code.indent() 352 353 # Data members for each field 354 for dm in self.data_members.values(): 355 if "abstract" not in dm: 356 const = "" 357 init = "" 358 359 # global structure 360 if self.isGlobal: 361 const = "static const " 362 363 # init value 364 if dm.init_code: 365 # only global structure can have init value here 366 assert self.isGlobal 367 init = " = %s" % (dm.init_code) 368 369 if "desc" in dm: 370 code('/** ${{dm["desc"]}} */') 371 372 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;') 373 374 if self.isMessage: 375 code('unsigned proc_id;') 376 377 code.dedent() 378 code('};') 379 380 code(''' 381inline std::ostream& 382operator<<(std::ostream& out, const ${{self.c_ident}}& obj) 383{ 384 obj.print(out); 385 out << std::flush; 386 return out; 387} 388 389#endif // __${{self.c_ident}}_HH__ 390''') 391 392 code.write(path, "%s.hh" % self.c_ident) 393 394 def printTypeCC(self, path): 395 code = self.symtab.codeFormatter() 396 397 code(''' 398/** \\file ${{self.c_ident}}.cc 399 * 400 * Auto generated C++ code started by $__file__:$__line__ 401 */ 402 403#include <iostream> 404 405#include "mem/protocol/${{self.c_ident}}.hh" 406 407using namespace std; 408''') 409 410 code(''' 411/** \\brief Print the state of this object */ 412void 413${{self.c_ident}}::print(ostream& out) const 414{ 415 out << "[${{self.c_ident}}: "; 416''') 417 418 # For each field 419 code.indent() 420 for dm in self.data_members.values(): 421 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 422 423 if self.isMessage: 424 code('out << "Time = " << getTime() << " ";') 425 code.dedent() 426 427 # Trailer 428 code(''' 429 out << "]"; 430}''') 431 432 code.write(path, "%s.cc" % self.c_ident) 433 434 def printEnumHH(self, path): 435 code = self.symtab.codeFormatter() 436 code(''' 437/** \\file ${{self.c_ident}}.hh 438 * 439 * Auto generated C++ code started by $__file__:$__line__ 440 */ 441 442#ifndef __${{self.c_ident}}_HH__ 443#define __${{self.c_ident}}_HH__ 444 445#include <iostream> 446#include <string> 447 448#include "mem/ruby/common/Global.hh" 449 450// Class definition 451/** \\enum ${{self.c_ident}} 452 * \\brief ${{self.desc}} 453 */ 454enum ${{self.c_ident}} { 455 ${{self.c_ident}}_FIRST, 456''') 457 458 code.indent() 459 # For each field 460 for i,(ident,enum) in enumerate(self.enums.iteritems()): 461 desc = enum.get("desc", "No description avaliable") 462 if i == 0: 463 init = ' = %s_FIRST' % self.c_ident 464 else: 465 init = '' 466 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 467 code.dedent() 468 code(''' 469 ${{self.c_ident}}_NUM 470}; 471 472// Code to convert from a string to the enumeration 473${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str); 474 475// Code to convert state to a string 476std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 477 478// Code to increment an enumeration type 479${{self.c_ident}} &operator++(${{self.c_ident}} &e); 480''') 481 482 # MachineType hack used to set the base component id for each Machine 483 if self.isMachineType: 484 code(''' 485int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 486MachineType ${{self.c_ident}}_from_base_level(int); 487int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 488int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 489''') 490 491 for enum in self.enums.itervalues(): 492 code('#define MACHINETYPE_${{enum.ident}} 1') 493 494 # Trailer 495 code(''' 496std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj); 497 498#endif // __${{self.c_ident}}_HH__ 499''') 500 501 code.write(path, "%s.hh" % self.c_ident) 502 503 def printEnumCC(self, path): 504 code = self.symtab.codeFormatter() 505 code(''' 506/** \\file ${{self.c_ident}}.hh 507 * 508 * Auto generated C++ code started by $__file__:$__line__ 509 */ 510
|