Type.py revision 9631:5ebde5544529
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/slicc_interface/RubySlicc_Util.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''', klass="class") 247 248 if self.isMessage: 249 code('(Tick curTime) : %s(curTime) {' % self["interface"]) 250 else: 251 code('()\n\t\t{') 252 253 code.indent() 254 if not self.isGlobal: 255 code.indent() 256 for dm in self.data_members.values(): 257 ident = dm.ident 258 if "default" in dm: 259 # look for default value 260 code('m_$ident = ${{dm["default"]}}; // default for this field') 261 elif "default" in dm.type: 262 # Look for the type default 263 tid = dm.type.c_ident 264 code('m_$ident = ${{dm.type["default"]}}; // default value of $tid') 265 else: 266 code('// m_$ident has no default') 267 code.dedent() 268 code('}') 269 270 # ******** Copy constructor ******** 271 if not self.isGlobal: 272 code('${{self.c_ident}}(const ${{self.c_ident}}&other)') 273 274 # Call superclass constructor 275 if "interface" in self: 276 code(' : ${{self["interface"]}}(other)') 277 278 code('{') 279 code.indent() 280 281 for dm in self.data_members.values(): 282 code('m_${{dm.ident}} = other.m_${{dm.ident}};') 283 284 code.dedent() 285 code('}') 286 287 # ******** Full init constructor ******** 288 if not self.isGlobal: 289 params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \ 290 for dm in self.data_members.itervalues() ] 291 params = ', '.join(params) 292 293 if self.isMessage: 294 params = "const Tick curTime, " + params 295 296 code('${{self.c_ident}}($params)') 297 298 # Call superclass constructor 299 if "interface" in self: 300 if self.isMessage: 301 code(' : ${{self["interface"]}}(curTime)') 302 else: 303 code(' : ${{self["interface"]}}()') 304 305 code('{') 306 code.indent() 307 for dm in self.data_members.values(): 308 code('m_${{dm.ident}} = local_${{dm.ident}};') 309 if "nextLineCallHack" in dm: 310 code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};') 311 312 code.dedent() 313 code('}') 314 315 # create a clone member 316 code(''' 317${{self.c_ident}}* 318clone() const 319{ 320 return new ${{self.c_ident}}(*this); 321} 322''') 323 324 if not self.isGlobal: 325 # const Get methods for each field 326 code('// Const accessors methods for each field') 327 for dm in self.data_members.values(): 328 code(''' 329/** \\brief Const accessor method for ${{dm.ident}} field. 330 * \\return ${{dm.ident}} field 331 */ 332const ${{dm.type.c_ident}}& 333get${{dm.ident}}() const 334{ 335 return m_${{dm.ident}}; 336} 337''') 338 339 # Non-const Get methods for each field 340 code('// Non const Accessors methods for each field') 341 for dm in self.data_members.values(): 342 code(''' 343/** \\brief Non-const accessor method for ${{dm.ident}} field. 344 * \\return ${{dm.ident}} field 345 */ 346${{dm.type.c_ident}}& 347get${{dm.ident}}() 348{ 349 return m_${{dm.ident}}; 350} 351''') 352 353 #Set methods for each field 354 code('// Mutator methods for each field') 355 for dm in self.data_members.values(): 356 code(''' 357/** \\brief Mutator method for ${{dm.ident}} field */ 358void 359set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) 360{ 361 m_${{dm.ident}} = local_${{dm.ident}}; 362} 363''') 364 365 code('void print(std::ostream& out) const;') 366 code.dedent() 367 code(' //private:') 368 code.indent() 369 370 # Data members for each field 371 for dm in self.data_members.values(): 372 if "abstract" not in dm: 373 const = "" 374 init = "" 375 376 # global structure 377 if self.isGlobal: 378 const = "static const " 379 380 # init value 381 if dm.init_code: 382 # only global structure can have init value here 383 assert self.isGlobal 384 init = " = %s" % (dm.init_code) 385 386 if "desc" in dm: 387 code('/** ${{dm["desc"]}} */') 388 389 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;') 390 391 # Prototypes for functions defined for the Type 392 for item in self.functions: 393 proto = self.functions[item].prototype 394 if proto: 395 code('$proto') 396 397 code.dedent() 398 code('};') 399 400 code(''' 401inline std::ostream& 402operator<<(std::ostream& out, const ${{self.c_ident}}& obj) 403{ 404 obj.print(out); 405 out << std::flush; 406 return out; 407} 408 409#endif // __${{self.c_ident}}_HH__ 410''') 411 412 code.write(path, "%s.hh" % self.c_ident) 413 414 def printTypeCC(self, path): 415 code = self.symtab.codeFormatter() 416 417 code(''' 418/** \\file ${{self.c_ident}}.cc 419 * 420 * Auto generated C++ code started by $__file__:$__line__ 421 */ 422 423#include <iostream> 424 425#include "mem/protocol/${{self.c_ident}}.hh" 426#include "mem/ruby/common/Global.hh" 427#include "mem/ruby/system/System.hh" 428 429using namespace std; 430''') 431 432 code(''' 433/** \\brief Print the state of this object */ 434void 435${{self.c_ident}}::print(ostream& out) const 436{ 437 out << "[${{self.c_ident}}: "; 438''') 439 440 # For each field 441 code.indent() 442 for dm in self.data_members.values(): 443 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 444 445 if self.isMessage: 446 code('out << "Time = " << g_system_ptr->clockPeriod() * getTime() << " ";') 447 code.dedent() 448 449 # Trailer 450 code(''' 451 out << "]"; 452}''') 453 454 # print the code for the functions in the type 455 for item in self.functions: 456 code(self.functions[item].generateCode()) 457 458 code.write(path, "%s.cc" % self.c_ident) 459 460 def printEnumHH(self, path): 461 code = self.symtab.codeFormatter() 462 code(''' 463/** \\file ${{self.c_ident}}.hh 464 * 465 * Auto generated C++ code started by $__file__:$__line__ 466 */ 467 468#ifndef __${{self.c_ident}}_HH__ 469#define __${{self.c_ident}}_HH__ 470 471#include <iostream> 472#include <string> 473 474''') 475 if self.isStateDecl: 476 code('#include "mem/protocol/AccessPermission.hh"') 477 478 if self.isMachineType: 479 code('#include "base/misc.hh"') 480 code('#include "mem/protocol/GenericMachineType.hh"') 481 code('#include "mem/ruby/common/Address.hh"') 482 code('struct MachineID;') 483 484 code(''' 485 486// Class definition 487/** \\enum ${{self.c_ident}} 488 * \\brief ${{self.desc}} 489 */ 490enum ${{self.c_ident}} { 491 ${{self.c_ident}}_FIRST, 492''') 493 494 code.indent() 495 # For each field 496 for i,(ident,enum) in enumerate(self.enums.iteritems()): 497 desc = enum.get("desc", "No description avaliable") 498 if i == 0: 499 init = ' = %s_FIRST' % self.c_ident 500 else: 501 init = '' 502 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 503 code.dedent() 504 code(''' 505 ${{self.c_ident}}_NUM 506}; 507 508// Code to convert from a string to the enumeration 509${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str); 510 511// Code to convert state to a string 512std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 513 514// Code to increment an enumeration type 515${{self.c_ident}} &operator++(${{self.c_ident}} &e); 516''') 517 518 # MachineType hack used to set the base component id for each Machine 519 if self.isMachineType: 520 code(''' 521int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 522MachineType ${{self.c_ident}}_from_base_level(int); 523int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 524int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 525''') 526 527 for enum in self.enums.itervalues(): 528 if enum.ident == "DMA": 529 code(''' 530MachineID map_Address_to_DMA(const Address &addr); 531''') 532 code(''' 533 534MachineID get${{enum.ident}}MachineID(NodeID RubyNode); 535''') 536 537 code(''' 538inline GenericMachineType 539ConvertMachToGenericMach(MachineType machType) 540{ 541''') 542 for enum in self.enums.itervalues(): 543 genericType = self.enums[enum.ident].get('genericType', 544 enum.ident) 545 code(''' 546 if (machType == MachineType_${{enum.ident}}) 547 return GenericMachineType_${{genericType}}; 548''') 549 code(''' 550 panic("cannot convert to a GenericMachineType"); 551} 552''') 553 554 if self.isStateDecl: 555 code(''' 556 557// Code to convert the current state to an access permission 558AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj); 559 560''') 561 562 # Trailer 563 code(''' 564std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj); 565 566#endif // __${{self.c_ident}}_HH__ 567''') 568 569 code.write(path, "%s.hh" % self.c_ident) 570 571 def printEnumCC(self, path): 572 code = self.symtab.codeFormatter() 573 code(''' 574/** \\file ${{self.c_ident}}.hh 575 * 576 * Auto generated C++ code started by $__file__:$__line__ 577 */ 578 579#include <cassert> 580#include <iostream> 581#include <string> 582 583#include "base/misc.hh" 584#include "mem/protocol/${{self.c_ident}}.hh" 585 586using namespace std; 587 588''') 589 590 if self.isStateDecl: 591 code(''' 592// Code to convert the current state to an access permission 593AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj) 594{ 595 switch(obj) { 596''') 597 # For each case 598 code.indent() 599 for statePerm in self.statePermPairs: 600 code(' case ${{self.c_ident}}_${{statePerm[0]}}:') 601 code(' return AccessPermission_${{statePerm[1]}};') 602 code.dedent() 603 code (''' 604 default: 605 panic("Unknown state access permission converstion for ${{self.c_ident}}"); 606 } 607} 608 609''') 610 611 if self.isMachineType: 612 for enum in self.enums.itervalues(): 613 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 614 code('#include "mem/ruby/system/MachineID.hh"') 615 616 code(''' 617// Code for output operator 618ostream& 619operator<<(ostream& out, const ${{self.c_ident}}& obj) 620{ 621 out << ${{self.c_ident}}_to_string(obj); 622 out << flush; 623 return out; 624} 625 626// Code to convert state to a string 627string 628${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 629{ 630 switch(obj) { 631''') 632 633 # For each field 634 code.indent() 635 for enum in self.enums.itervalues(): 636 code(' case ${{self.c_ident}}_${{enum.ident}}:') 637 code(' return "${{enum.ident}}";') 638 code.dedent() 639 640 # Trailer 641 code(''' 642 default: 643 panic("Invalid range for type ${{self.c_ident}}"); 644 } 645} 646 647// Code to convert from a string to the enumeration 648${{self.c_ident}} 649string_to_${{self.c_ident}}(const string& str) 650{ 651''') 652 653 # For each field 654 start = "" 655 code.indent() 656 for enum in self.enums.itervalues(): 657 code('${start}if (str == "${{enum.ident}}") {') 658 code(' return ${{self.c_ident}}_${{enum.ident}};') 659 start = "} else " 660 code.dedent() 661 662 code(''' 663 } else { 664 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str); 665 } 666} 667 668// Code to increment an enumeration type 669${{self.c_ident}}& 670operator++(${{self.c_ident}}& e) 671{ 672 assert(e < ${{self.c_ident}}_NUM); 673 return e = ${{self.c_ident}}(e+1); 674} 675''') 676 677 # MachineType hack used to set the base level and number of 678 # components for each Machine 679 if self.isMachineType: 680 code(''' 681/** \\brief returns the base vector index for each machine type to be 682 * used by NetDest 683 * 684 * \\return the base vector index for each machine type to be used by NetDest 685 * \\see NetDest.hh 686 */ 687int 688${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 689{ 690 switch(obj) { 691''') 692 693 # For each field 694 code.indent() 695 for i,enum in enumerate(self.enums.itervalues()): 696 code(' case ${{self.c_ident}}_${{enum.ident}}:') 697 code(' return $i;') 698 code.dedent() 699 700 # total num 701 code(''' 702 case ${{self.c_ident}}_NUM: 703 return ${{len(self.enums)}}; 704 705 default: 706 panic("Invalid range for type ${{self.c_ident}}"); 707 } 708} 709 710/** \\brief returns the machine type for each base vector index used by NetDest 711 * 712 * \\return the MachineType 713 */ 714MachineType 715${{self.c_ident}}_from_base_level(int type) 716{ 717 switch(type) { 718''') 719 720 # For each field 721 code.indent() 722 for i,enum in enumerate(self.enums.itervalues()): 723 code(' case $i:') 724 code(' return ${{self.c_ident}}_${{enum.ident}};') 725 code.dedent() 726 727 # Trailer 728 code(''' 729 default: 730 panic("Invalid range for type ${{self.c_ident}}"); 731 } 732} 733 734/** \\brief The return value indicates the number of components created 735 * before a particular machine\'s components 736 * 737 * \\return the base number of components for each machine 738 */ 739int 740${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 741{ 742 int base = 0; 743 switch(obj) { 744''') 745 746 # For each field 747 code.indent() 748 code(' case ${{self.c_ident}}_NUM:') 749 for enum in reversed(self.enums.values()): 750 code(' base += ${{enum.ident}}_Controller::getNumControllers();') 751 code(' case ${{self.c_ident}}_${{enum.ident}}:') 752 code(' break;') 753 code.dedent() 754 755 code(''' 756 default: 757 panic("Invalid range for type ${{self.c_ident}}"); 758 } 759 760 return base; 761} 762 763/** \\brief returns the total number of components for each machine 764 * \\return the total number of components for each machine 765 */ 766int 767${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 768{ 769 switch(obj) { 770''') 771 772 # For each field 773 for enum in self.enums.itervalues(): 774 code(''' 775 case ${{self.c_ident}}_${{enum.ident}}: 776 return ${{enum.ident}}_Controller::getNumControllers(); 777''') 778 779 # total num 780 code(''' 781 case ${{self.c_ident}}_NUM: 782 default: 783 panic("Invalid range for type ${{self.c_ident}}"); 784 } 785} 786''') 787 788 for enum in self.enums.itervalues(): 789 if enum.ident == "DMA": 790 code(''' 791MachineID 792map_Address_to_DMA(const Address &addr) 793{ 794 MachineID dma = {MachineType_DMA, 0}; 795 return dma; 796} 797''') 798 799 code(''' 800 801MachineID 802get${{enum.ident}}MachineID(NodeID RubyNode) 803{ 804 MachineID mach = {MachineType_${{enum.ident}}, RubyNode}; 805 return mach; 806} 807''') 808 809 # Write the file 810 code.write(path, "%s.cc" % self.c_ident) 811 812__all__ = [ "Type" ] 813