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 code_formatter, 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 if machine: 55 if self.isExternal or self.isPrimitive: 56 if "external_name" in self: 57 self.c_ident = self["external_name"] 58 else: 59 # Append with machine name 60 self.c_ident = "%s_%s" % (machine, ident) 61 62 self.pairs.setdefault("desc", "No description avaliable") 63 64 # check for interface that this Type implements 65 if "interface" in self: 66 interface = self["interface"] 67 if interface in ("Message", "NetworkMessage"): 68 self["message"] = "yes" 69 if interface == "NetworkMessage": 70 self["networkmessage"] = "yes" 71 72 # FIXME - all of the following id comparisons are fragile hacks 73 if self.ident in ("CacheMemory", "NewCacheMemory", 74 "TLCCacheMemory", "DNUCACacheMemory", 75 "DNUCABankCacheMemory", "L2BankCacheMemory", 76 "CompressedCacheMemory", "PrefetchCacheMemory"): 77 self["cache"] = "yes" 78 79 if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"): 80 self["tbe"] = "yes" 81 82 if self.ident == "NewTBETable": 83 self["newtbe"] = "yes" 84 85 if self.ident == "TimerTable": 86 self["timer"] = "yes" 87 88 if self.ident == "DirectoryMemory": 89 self["dir"] = "yes" 90 91 if self.ident == "PersistentTable": 92 self["persistent"] = "yes" 93 94 if self.ident == "Prefetcher": 95 self["prefetcher"] = "yes" 96 97 if self.ident == "DNUCA_Movement": 98 self["mover"] = "yes" 99 100 self.isMachineType = (ident == "MachineType") 101 102 self.data_members = orderdict() 103 104 # Methods 105 self.methods = {} 106 107 # Enums 108 self.enums = orderdict() 109 110 @property 111 def isPrimitive(self): 112 return "primitive" in self 113 @property 114 def isNetworkMessage(self): 115 return "networkmessage" in self 116 @property 117 def isMessage(self): 118 return "message" in self 119 @property 120 def isBuffer(self): 121 return "buffer" in self 122 @property 123 def isInPort(self): 124 return "inport" in self 125 @property 126 def isOutPort(self): 127 return "outport" in self 128 @property 129 def isEnumeration(self): 130 return "enumeration" in self 131 @property 132 def isExternal(self): 133 return "external" in self 134 @property 135 def isGlobal(self): 136 return "global" in self 137 @property 138 def isInterface(self): 139 return "interface" in self 140 141 # Return false on error 142 def dataMemberAdd(self, ident, type, pairs, init_code): 143 if ident in self.data_members: 144 return False 145 146 member = DataMember(ident, type, pairs, init_code) 147 self.data_members[ident] = member 148 149 return True 150 151 def dataMemberType(self, ident): 152 return self.data_members[ident].type 153 154 def methodId(self, name, param_type_vec): 155 return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ]) 156 157 def methodAdd(self, name, return_type, param_type_vec): 158 ident = self.methodId(name, param_type_vec) 159 if ident in self.methods: 160 return False 161 162 self.methods[ident] = Method(return_type, param_type_vec) 163 return True 164 165 def enumAdd(self, ident, pairs): 166 if ident in self.enums: 167 return False 168 169 self.enums[ident] = Enumeration(ident, pairs) 170 171 # Add default 172 if "default" not in self: 173 self["default"] = "%s_NUM" % self.c_ident 174 175 return True 176 177 def writeCodeFiles(self, path): 178 if self.isExternal: 179 # Do nothing 180 pass 181 elif self.isEnumeration: 182 self.printEnumHH(path) 183 self.printEnumCC(path) 184 else: 185 # User defined structs and messages 186 self.printTypeHH(path) 187 self.printTypeCC(path) 188 189 def printTypeHH(self, path): 190 code = code_formatter() 191 code(''' 192/** \\file ${{self.c_ident}}.hh 193 * 194 * 195 * Auto generated C++ code started by $__file__:$__line__ 196 */ 197 198#ifndef ${{self.c_ident}}_H 199#define ${{self.c_ident}}_H 200 201#include "mem/ruby/common/Global.hh" 202#include "mem/gems_common/Allocator.hh" 203''') 204 205 for dm in self.data_members.values(): 206 if not dm.type.isPrimitive: 207 code('#include "mem/protocol/$0.hh"', dm.type.c_ident) 208 209 parent = "" 210 if "interface" in self: 211 code('#include "mem/protocol/$0.hh"', self["interface"]) 212 parent = " : public %s" % self["interface"] 213 214 code(''' 215$klass ${{self.c_ident}}$parent { 216 public: 217 ${{self.c_ident}}() 218''', klass="class") 219 220 # Call superclass constructor 221 if "interface" in self: 222 code(' : ${{self["interface"]}}()') 223 224 code.indent() 225 code("{") 226 if not self.isGlobal: 227 code.indent() 228 for dm in self.data_members.values(): 229 ident = dm.ident 230 if "default" in dm: 231 # look for default value 232 code('m_$ident = ${{dm["default"]}}; // default for this field') 233 elif "default" in dm.type: 234 # Look for the type default 235 tid = dm.type.c_ident 236 code('m_$ident = ${{dm.type["default"]}}; // default value of $tid') 237 else: 238 code('// m_$ident has no default') 239 code.dedent() 240 code('}') 241 242 # ******** Default destructor ******** 243 code('~${{self.c_ident}}() { };') 244 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() ] 249 250 if self.isMessage: 251 params.append('const unsigned local_proc_id') 252 253 params = ', '.join(params) 254 code('${{self.c_ident}}($params)') 255 256 # Call superclass constructor 257 if "interface" in self: 258 code(' : ${{self["interface"]}}()') 259 260 code('{') 261 code.indent() 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"]}};') 266 267 if self.isMessage: 268 code('proc_id = local_proc_id;') 269 270 code.dedent() 271 code('}') 272 273 # create a static factory method 274 if "interface" in self: 275 code(''' 276static ${{self["interface"]}}* create() { 277 return new ${{self.c_ident}}(); 278} 279''') 280 281 # ******** Message member functions ******** 282 # FIXME: those should be moved into slicc file, slicc should 283 # support more of the c++ class inheritance 284 285 if self.isMessage: 286 code(''' 287Message* clone() const { checkAllocator(); return s_allocator_ptr->allocate(*this); } 288void destroy() { checkAllocator(); s_allocator_ptr->deallocate(this); } 289static Allocator<${{self.c_ident}}>* s_allocator_ptr; 290static void checkAllocator() { if (s_allocator_ptr == NULL) { s_allocator_ptr = new Allocator<${{self.c_ident}}>; }} 291''') 292 293 if not self.isGlobal: 294 # const Get methods for each field 295 code('// Const accessors methods for each field') 296 for dm in self.data_members.values(): 297 code(''' 298/** \\brief Const accessor method for ${{dm.ident}} field. 299 * \\return ${{dm.ident}} field 300 */ 301const ${{dm.type.c_ident}}& get${{dm.ident}}() const { return m_${{dm.ident}}; } 302''') 303 304 # Non-const Get methods for each field 305 code('// Non const Accessors methods for each field') 306 for dm in self.data_members.values(): 307 code(''' 308/** \\brief Non-const accessor method for ${{dm.ident}} field. 309 * \\return ${{dm.ident}} field 310 */ 311${{dm.type.c_ident}}& get${{dm.ident}}() { return m_${{dm.ident}}; } 312''') 313 314 #Set methods for each field 315 code('// Mutator methods for each field') 316 for dm in self.data_members.values(): 317 code(''' 318/** \\brief Mutator method for ${{dm.ident}} field */ 319void set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) { m_${{dm.ident}} = local_${{dm.ident}}; } 320''') 321 322 code('void print(ostream& out) const;') 323 code.dedent() 324 code(' //private:') 325 code.indent() 326 327 # Data members for each field 328 for dm in self.data_members.values(): 329 if "abstract" not in dm: 330 const = "" 331 init = "" 332 333 # global structure 334 if self.isGlobal: 335 const = "static const " 336 337 # init value 338 if dm.init_code: 339 # only global structure can have init value here 340 assert self.isGlobal 341 init = " = %s" % (dm.init_code) 342 343 desc = "" 344 if "desc" in dm: 345 desc = '/**< %s */' % dm["desc"] 346 347 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init; $desc') 348 349 if self.isMessage: 350 code('unsigned proc_id;') 351 352 code.dedent() 353 code('};') 354 355 code(''' 356// Output operator declaration 357ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); 358 359// Output operator definition 360extern inline 361ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) 362{ 363 obj.print(out); 364 out << flush; 365 return out; 366} 367 368#endif // ${{self.c_ident}}_H 369''') 370 371 code.write(path, "%s.hh" % self.c_ident) 372 373 def printTypeCC(self, path): 374 code = code_formatter() 375 376 code(''' 377/** \\file ${{self.c_ident}}.cc 378 * 379 * Auto generated C++ code started by $__file__:$__line__ 380 */ 381 382#include "mem/protocol/${{self.c_ident}}.hh" 383''') 384 385 if self.isMessage: 386 code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;') 387 code(''' 388/** \\brief Print the state of this object */ 389void ${{self.c_ident}}::print(ostream& out) const 390{ 391 out << "[${{self.c_ident}}: "; 392''') 393 394 # For each field 395 code.indent() 396 for dm in self.data_members.values(): 397 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 398 399 if self.isMessage: 400 code('out << "Time = " << getTime() << " ";') 401 code.dedent() 402 403 # Trailer 404 code(''' 405 out << "]"; 406}''') 407 408 code.write(path, "%s.cc" % self.c_ident) 409 410 def printEnumHH(self, path): 411 code = code_formatter() 412 code(''' 413/** \\file ${{self.c_ident}}.hh 414 * 415 * Auto generated C++ code started by $__file__:$__line__ 416 */ 417#ifndef ${{self.c_ident}}_H 418#define ${{self.c_ident}}_H 419 420#include "mem/ruby/common/Global.hh" 421 422/** \\enum ${{self.c_ident}} 423 * \\brief ${{self.desc}} 424 */ 425enum ${{self.c_ident}} { 426 ${{self.c_ident}}_FIRST, 427''') 428 429 code.indent() 430 # For each field 431 for i,(ident,enum) in enumerate(self.enums.iteritems()): 432 desc = enum.get("desc", "No description avaliable") 433 if i == 0: 434 init = ' = %s_FIRST' % self.c_ident 435 else: 436 init = '' 437 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 438 code.dedent() 439 code(''' 440 ${{self.c_ident}}_NUM 441}; 442${{self.c_ident}} string_to_${{self.c_ident}}(const string& str); 443string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 444${{self.c_ident}} &operator++(${{self.c_ident}} &e); 445''') 446 447 # MachineType hack used to set the base component id for each Machine 448 if self.isMachineType: 449 code(''' 450int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 451MachineType ${{self.c_ident}}_from_base_level(int); 452int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 453int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 454''') 455 456 for enum in self.enums.itervalues(): 457 code('#define MACHINETYPE_${{enum.ident}} 1') 458 459 # Trailer 460 code(''' 461ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); 462 463#endif // ${{self.c_ident}}_H 464''') 465 466 code.write(path, "%s.hh" % self.c_ident) 467 468 def printEnumCC(self, path): 469 code = code_formatter() 470 code(''' 471/** \\file ${{self.c_ident}}.hh 472 * 473 * Auto generated C++ code started by $__file__:$__line__ 474 */ 475 476#include "mem/protocol/${{self.c_ident}}.hh" 477 478''') 479 480 if self.isMachineType: |
481 for enum in self.enums.itervalues(): 482 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 483 484 code(''' 485ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) 486{ 487 out << ${{self.c_ident}}_to_string(obj); 488 out << flush; 489 return out; 490} 491 492string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 493{ 494 switch(obj) { 495''') 496 497 # For each field 498 code.indent() 499 for enum in self.enums.itervalues(): 500 code(' case ${{self.c_ident}}_${{enum.ident}}:') 501 code(' return "${{enum.ident}}";') 502 code.dedent() 503 504 # Trailer 505 code(''' 506 default: 507 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 508 return ""; 509 } 510} 511 512${{self.c_ident}} string_to_${{self.c_ident}}(const string& str) 513{ 514''') 515 516 # For each field 517 code.indent() 518 code("if (false) {") 519 start = "} else " 520 for enum in self.enums.itervalues(): 521 code('${start}if (str == "${{enum.ident}}") {') 522 code(' return ${{self.c_ident}}_${{enum.ident}};') 523 code.dedent() 524 525 code(''' 526 } else { 527 WARN_EXPR(str); 528 ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}"); 529 } 530} 531 532${{self.c_ident}}& operator++(${{self.c_ident}}& e) { 533 assert(e < ${{self.c_ident}}_NUM); 534 return e = ${{self.c_ident}}(e+1); 535} 536''') 537 538 # MachineType hack used to set the base level and number of 539 # components for each Machine 540 if self.isMachineType: 541 code(''' 542/** \\brief returns the base vector index for each machine type to be used by NetDest 543 * 544 * \\return the base vector index for each machine type to be used by NetDest 545 * \\see NetDest.hh 546 */ 547int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 548{ 549 switch(obj) { 550''') 551 552 # For each field 553 code.indent() 554 for i,enum in enumerate(self.enums.itervalues()): 555 code(' case ${{self.c_ident}}_${{enum.ident}}:') 556 code(' return $i;') 557 code.dedent() 558 559 # total num 560 code(''' 561 case ${{self.c_ident}}_NUM: 562 return ${{len(self.enums)}}; 563 564 default: 565 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 566 return -1; 567 } 568} 569 570/** \\brief returns the machine type for each base vector index used by NetDest 571 * 572 * \\return the MachineTYpe 573 */ 574MachineType ${{self.c_ident}}_from_base_level(int type) 575{ 576 switch(type) { 577''') 578 579 # For each field 580 code.indent() 581 for i,enum in enumerate(self.enums.itervalues()): 582 code(' case $i:') 583 code(' return ${{self.c_ident}}_${{enum.ident}};') 584 code.dedent() 585 586 # Trailer 587 code(''' 588 default: 589 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 590 return MachineType_NUM; 591 } 592} 593 594/** \\brief The return value indicates the number of components created 595 * before a particular machine\'s components 596 * 597 * \\return the base number of components for each machine 598 */ 599int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 600{ 601 int base = 0; 602 switch(obj) { 603''') 604 605 # For each field 606 code.indent() 607 code(' case ${{self.c_ident}}_NUM:') 608 for enum in reversed(self.enums.values()): 609 code(' base += ${{enum.ident}}_Controller::getNumControllers();') 610 code(' case ${{self.c_ident}}_${{enum.ident}}:') 611 code(' break;') 612 code.dedent() 613 614 code(''' 615 default: 616 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 617 return -1; 618 } 619 620 return base; 621} 622 623/** \\brief returns the total number of components for each machine 624 * \\return the total number of components for each machine 625 */ 626int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 627{ 628 switch(obj) { 629''') 630 631 # For each field 632 for enum in self.enums.itervalues(): 633 code(''' 634 case ${{self.c_ident}}_${{enum.ident}}: 635 return ${{enum.ident}}_Controller::getNumControllers(); 636''') 637 638 # total num 639 code(''' 640 case ${{self.c_ident}}_NUM: 641 default: 642 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 643 return -1; 644 } 645} 646''') 647 648 # Write the file 649 code.write(path, "%s.cc" % self.c_ident) 650 651__all__ = [ "Type" ] |