Type.py revision 7007:79413d1ec307
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#include "mem/gems_common/Allocator.hh" 209''') 210 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) 214 215 parent = "" 216 if "interface" in self: 217 code('#include "mem/protocol/$0.hh"', self["interface"]) 218 parent = " : public %s" % self["interface"] 219 220 code(''' 221$klass ${{self.c_ident}}$parent 222{ 223 public: 224 ${{self.c_ident}}() 225 { 226''', klass="class") 227 228 code.indent() 229 if not self.isGlobal: 230 code.indent() 231 for dm in self.data_members.values(): 232 ident = dm.ident 233 if "default" in dm: 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') 240 else: 241 code('// m_$ident has no default') 242 code.dedent() 243 code('}') 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"]}}* 277create() 278{ 279 return new ${{self.c_ident}}(); 280} 281''') 282 283 # ******** Message member functions ******** 284 # FIXME: those should be moved into slicc file, slicc should 285 # support more of the c++ class inheritance 286 287 if self.isMessage: 288 code(''' 289Message * 290clone() const 291{ 292 checkAllocator(); 293 return s_allocator_ptr->allocate(*this); 294} 295 296void 297destroy() 298{ 299 checkAllocator(); 300 s_allocator_ptr->deallocate(this); 301} 302 303static Allocator<${{self.c_ident}}>* s_allocator_ptr; 304 305static void 306checkAllocator() 307{ 308 if (s_allocator_ptr == NULL) { 309 s_allocator_ptr = new Allocator<${{self.c_ident}}>; 310 } 311} 312''') 313 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(): 318 code(''' 319/** \\brief Const accessor method for ${{dm.ident}} field. 320 * \\return ${{dm.ident}} field 321 */ 322const ${{dm.type.c_ident}}& 323get${{dm.ident}}() const 324{ 325 return m_${{dm.ident}}; 326} 327''') 328 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(): 332 code(''' 333/** \\brief Non-const accessor method for ${{dm.ident}} field. 334 * \\return ${{dm.ident}} field 335 */ 336${{dm.type.c_ident}}& 337get${{dm.ident}}() 338{ 339 return m_${{dm.ident}}; 340} 341''') 342 343 #Set methods for each field 344 code('// Mutator methods for each field') 345 for dm in self.data_members.values(): 346 code(''' 347/** \\brief Mutator method for ${{dm.ident}} field */ 348void 349set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) 350{ 351 m_${{dm.ident}} = local_${{dm.ident}}; 352} 353''') 354 355 code('void print(std::ostream& out) const;') 356 code.dedent() 357 code(' //private:') 358 code.indent() 359 360 # Data members for each field 361 for dm in self.data_members.values(): 362 if "abstract" not in dm: 363 const = "" 364 init = "" 365 366 # global structure 367 if self.isGlobal: 368 const = "static const " 369 370 # init value 371 if dm.init_code: 372 # only global structure can have init value here 373 assert self.isGlobal 374 init = " = %s" % (dm.init_code) 375 376 if "desc" in dm: 377 code('/** ${{dm["desc"]}} */') 378 379 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;') 380 381 if self.isMessage: 382 code('unsigned proc_id;') 383 384 code.dedent() 385 code('};') 386 387 code(''' 388// Output operator declaration 389std::ostream& 390operator<<(std::ostream& out, const ${{self.c_ident}}& obj); 391 392// Output operator definition 393extern inline std::ostream& 394operator<<(std::ostream& out, const ${{self.c_ident}}& obj) 395{ 396 obj.print(out); 397 out << std::flush; 398 return out; 399} 400 401#endif // __${{self.c_ident}}_HH__ 402''') 403 404 code.write(path, "%s.hh" % self.c_ident) 405 406 def printTypeCC(self, path): 407 code = self.symtab.codeFormatter() 408 409 code(''' 410/** \\file ${{self.c_ident}}.cc 411 * 412 * Auto generated C++ code started by $__file__:$__line__ 413 */ 414 415#include <iostream> 416 417#include "mem/protocol/${{self.c_ident}}.hh" 418 419using namespace std; 420''') 421 422 if self.isMessage: 423 code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;') 424 code(''' 425/** \\brief Print the state of this object */ 426void 427${{self.c_ident}}::print(ostream& out) const 428{ 429 out << "[${{self.c_ident}}: "; 430''') 431 432 # For each field 433 code.indent() 434 for dm in self.data_members.values(): 435 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 436 437 if self.isMessage: 438 code('out << "Time = " << getTime() << " ";') 439 code.dedent() 440 441 # Trailer 442 code(''' 443 out << "]"; 444}''') 445 446 code.write(path, "%s.cc" % self.c_ident) 447 448 def printEnumHH(self, path): 449 code = self.symtab.codeFormatter() 450 code(''' 451/** \\file ${{self.c_ident}}.hh 452 * 453 * Auto generated C++ code started by $__file__:$__line__ 454 */ 455 456#ifndef __${{self.c_ident}}_HH__ 457#define __${{self.c_ident}}_HH__ 458 459#include <iostream> 460#include <string> 461 462#include "mem/ruby/common/Global.hh" 463 464// Class definition 465/** \\enum ${{self.c_ident}} 466 * \\brief ${{self.desc}} 467 */ 468enum ${{self.c_ident}} { 469 ${{self.c_ident}}_FIRST, 470''') 471 472 code.indent() 473 # For each field 474 for i,(ident,enum) in enumerate(self.enums.iteritems()): 475 desc = enum.get("desc", "No description avaliable") 476 if i == 0: 477 init = ' = %s_FIRST' % self.c_ident 478 else: 479 init = '' 480 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 481 code.dedent() 482 code(''' 483 ${{self.c_ident}}_NUM 484}; 485 486// Code to convert from a string to the enumeration 487${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str); 488 489// Code to convert state to a string 490std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 491 492// Code to increment an enumeration type 493${{self.c_ident}} &operator++(${{self.c_ident}} &e); 494''') 495 496 # MachineType hack used to set the base component id for each Machine 497 if self.isMachineType: 498 code(''' 499int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 500MachineType ${{self.c_ident}}_from_base_level(int); 501int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 502int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 503''') 504 505 for enum in self.enums.itervalues(): 506 code('#define MACHINETYPE_${{enum.ident}} 1') 507 508 # Trailer 509 code(''' 510std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj); 511 512#endif // __${{self.c_ident}}_HH__ 513''') 514 515 code.write(path, "%s.hh" % self.c_ident) 516 517 def printEnumCC(self, path): 518 code = self.symtab.codeFormatter() 519 code(''' 520/** \\file ${{self.c_ident}}.hh 521 * 522 * Auto generated C++ code started by $__file__:$__line__ 523 */ 524 525#include <iostream> 526#include <string> 527 528#include "mem/protocol/${{self.c_ident}}.hh" 529 530using namespace std; 531 532''') 533 534 if self.isMachineType: 535 for enum in self.enums.itervalues(): 536 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 537 538 code(''' 539// Code for output operator 540ostream& 541operator<<(ostream& out, const ${{self.c_ident}}& obj) 542{ 543 out << ${{self.c_ident}}_to_string(obj); 544 out << flush; 545 return out; 546} 547 548// Code to convert state to a string 549string 550${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 551{ 552 switch(obj) { 553''') 554 555 # For each field 556 code.indent() 557 for enum in self.enums.itervalues(): 558 code(' case ${{self.c_ident}}_${{enum.ident}}:') 559 code(' return "${{enum.ident}}";') 560 code.dedent() 561 562 # Trailer 563 code(''' 564 default: 565 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 566 return ""; 567 } 568} 569 570// Code to convert from a string to the enumeration 571${{self.c_ident}} 572string_to_${{self.c_ident}}(const string& str) 573{ 574''') 575 576 # For each field 577 start = "" 578 code.indent() 579 for enum in self.enums.itervalues(): 580 code('${start}if (str == "${{enum.ident}}") {') 581 code(' return ${{self.c_ident}}_${{enum.ident}};') 582 start = "} else " 583 code.dedent() 584 585 code(''' 586 } else { 587 WARN_EXPR(str); 588 ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}"); 589 } 590} 591 592// Code to increment an enumeration type 593${{self.c_ident}}& 594operator++(${{self.c_ident}}& e) 595{ 596 assert(e < ${{self.c_ident}}_NUM); 597 return e = ${{self.c_ident}}(e+1); 598} 599''') 600 601 # MachineType hack used to set the base level and number of 602 # components for each Machine 603 if self.isMachineType: 604 code(''' 605/** \\brief returns the base vector index for each machine type to be 606 * used by NetDest 607 * 608 * \\return the base vector index for each machine type to be used by NetDest 609 * \\see NetDest.hh 610 */ 611int 612${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 613{ 614 switch(obj) { 615''') 616 617 # For each field 618 code.indent() 619 for i,enum in enumerate(self.enums.itervalues()): 620 code(' case ${{self.c_ident}}_${{enum.ident}}:') 621 code(' return $i;') 622 code.dedent() 623 624 # total num 625 code(''' 626 case ${{self.c_ident}}_NUM: 627 return ${{len(self.enums)}}; 628 629 default: 630 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 631 return -1; 632 } 633} 634 635/** \\brief returns the machine type for each base vector index used by NetDest 636 * 637 * \\return the MachineType 638 */ 639MachineType 640${{self.c_ident}}_from_base_level(int type) 641{ 642 switch(type) { 643''') 644 645 # For each field 646 code.indent() 647 for i,enum in enumerate(self.enums.itervalues()): 648 code(' case $i:') 649 code(' return ${{self.c_ident}}_${{enum.ident}};') 650 code.dedent() 651 652 # Trailer 653 code(''' 654 default: 655 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 656 return MachineType_NUM; 657 } 658} 659 660/** \\brief The return value indicates the number of components created 661 * before a particular machine\'s components 662 * 663 * \\return the base number of components for each machine 664 */ 665int 666${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 667{ 668 int base = 0; 669 switch(obj) { 670''') 671 672 # For each field 673 code.indent() 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}}:') 678 code(' break;') 679 code.dedent() 680 681 code(''' 682 default: 683 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 684 return -1; 685 } 686 687 return base; 688} 689 690/** \\brief returns the total number of components for each machine 691 * \\return the total number of components for each machine 692 */ 693int 694${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 695{ 696 switch(obj) { 697''') 698 699 # For each field 700 for enum in self.enums.itervalues(): 701 code(''' 702 case ${{self.c_ident}}_${{enum.ident}}: 703 return ${{enum.ident}}_Controller::getNumControllers(); 704''') 705 706 # total num 707 code(''' 708 case ${{self.c_ident}}_NUM: 709 default: 710 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 711 return -1; 712 } 713} 714''') 715 716 # Write the file 717 code.write(path, "%s.cc" % self.c_ident) 718 719__all__ = [ "Type" ] 720