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