Type.py revision 9466:23e13ad7091f
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('(Time 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 Time 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 427using namespace std; 428''') 429 430 code(''' 431/** \\brief Print the state of this object */ 432void 433${{self.c_ident}}::print(ostream& out) const 434{ 435 out << "[${{self.c_ident}}: "; 436''') 437 438 # For each field 439 code.indent() 440 for dm in self.data_members.values(): 441 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 442 443 if self.isMessage: 444 code('out << "Time = " << g_system_ptr->clockPeriod() * getTime() << " ";') 445 code.dedent() 446 447 # Trailer 448 code(''' 449 out << "]"; 450}''') 451 452 # print the code for the functions in the type 453 for item in self.functions: 454 code(self.functions[item].generateCode()) 455 456 code.write(path, "%s.cc" % self.c_ident) 457 458 def printEnumHH(self, path): 459 code = self.symtab.codeFormatter() 460 code(''' 461/** \\file ${{self.c_ident}}.hh 462 * 463 * Auto generated C++ code started by $__file__:$__line__ 464 */ 465 466#ifndef __${{self.c_ident}}_HH__ 467#define __${{self.c_ident}}_HH__ 468 469#include <iostream> 470#include <string> 471 472''') 473 if self.isStateDecl: 474 code('#include "mem/protocol/AccessPermission.hh"') 475 476 if self.isMachineType: 477 code('#include "base/misc.hh"') 478 code('#include "mem/protocol/GenericMachineType.hh"') 479 code('#include "mem/ruby/common/Address.hh"') 480 code('struct MachineID;') 481 482 code(''' 483 484// Class definition 485/** \\enum ${{self.c_ident}} 486 * \\brief ${{self.desc}} 487 */ 488enum ${{self.c_ident}} { 489 ${{self.c_ident}}_FIRST, 490''') 491 492 code.indent() 493 # For each field 494 for i,(ident,enum) in enumerate(self.enums.iteritems()): 495 desc = enum.get("desc", "No description avaliable") 496 if i == 0: 497 init = ' = %s_FIRST' % self.c_ident 498 else: 499 init = '' 500 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 501 code.dedent() 502 code(''' 503 ${{self.c_ident}}_NUM 504}; 505 506// Code to convert from a string to the enumeration 507${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str); 508 509// Code to convert state to a string 510std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 511 512// Code to increment an enumeration type 513${{self.c_ident}} &operator++(${{self.c_ident}} &e); 514''') 515 516 # MachineType hack used to set the base component id for each Machine 517 if self.isMachineType: 518 code(''' 519int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 520MachineType ${{self.c_ident}}_from_base_level(int); 521int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 522int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 523''') 524 525 for enum in self.enums.itervalues(): 526 if enum.ident == "DMA": 527 code(''' 528MachineID map_Address_to_DMA(const Address &addr); 529''') 530 code(''' 531 532MachineID get${{enum.ident}}MachineID(NodeID RubyNode); 533''') 534 535 code(''' 536inline GenericMachineType 537ConvertMachToGenericMach(MachineType machType) 538{ 539''') 540 for enum in self.enums.itervalues(): 541 code(''' 542 if (machType == MachineType_${{enum.ident}}) 543 return GenericMachineType_${{enum.ident}}; 544''') 545 code(''' 546 panic("cannot convert to a GenericMachineType"); 547} 548''') 549 550 if self.isStateDecl: 551 code(''' 552 553// Code to convert the current state to an access permission 554AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj); 555 556''') 557 558 # Trailer 559 code(''' 560std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj); 561 562#endif // __${{self.c_ident}}_HH__ 563''') 564 565 code.write(path, "%s.hh" % self.c_ident) 566 567 def printEnumCC(self, path): 568 code = self.symtab.codeFormatter() 569 code(''' 570/** \\file ${{self.c_ident}}.hh 571 * 572 * Auto generated C++ code started by $__file__:$__line__ 573 */ 574 575#include <cassert> 576#include <iostream> 577#include <string> 578 579#include "base/misc.hh" 580#include "mem/protocol/${{self.c_ident}}.hh" 581 582using namespace std; 583 584''') 585 586 if self.isStateDecl: 587 code(''' 588// Code to convert the current state to an access permission 589AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj) 590{ 591 switch(obj) { 592''') 593 # For each case 594 code.indent() 595 for statePerm in self.statePermPairs: 596 code(' case ${{self.c_ident}}_${{statePerm[0]}}:') 597 code(' return AccessPermission_${{statePerm[1]}};') 598 code.dedent() 599 code (''' 600 default: 601 panic("Unknown state access permission converstion for ${{self.c_ident}}"); 602 } 603} 604 605''') 606 607 if self.isMachineType: 608 for enum in self.enums.itervalues(): 609 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 610 code('#include "mem/ruby/system/MachineID.hh"') 611 612 code(''' 613// Code for output operator 614ostream& 615operator<<(ostream& out, const ${{self.c_ident}}& obj) 616{ 617 out << ${{self.c_ident}}_to_string(obj); 618 out << flush; 619 return out; 620} 621 622// Code to convert state to a string 623string 624${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 625{ 626 switch(obj) { 627''') 628 629 # For each field 630 code.indent() 631 for enum in self.enums.itervalues(): 632 code(' case ${{self.c_ident}}_${{enum.ident}}:') 633 code(' return "${{enum.ident}}";') 634 code.dedent() 635 636 # Trailer 637 code(''' 638 default: 639 panic("Invalid range for type ${{self.c_ident}}"); 640 } 641} 642 643// Code to convert from a string to the enumeration 644${{self.c_ident}} 645string_to_${{self.c_ident}}(const string& str) 646{ 647''') 648 649 # For each field 650 start = "" 651 code.indent() 652 for enum in self.enums.itervalues(): 653 code('${start}if (str == "${{enum.ident}}") {') 654 code(' return ${{self.c_ident}}_${{enum.ident}};') 655 start = "} else " 656 code.dedent() 657 658 code(''' 659 } else { 660 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str); 661 } 662} 663 664// Code to increment an enumeration type 665${{self.c_ident}}& 666operator++(${{self.c_ident}}& e) 667{ 668 assert(e < ${{self.c_ident}}_NUM); 669 return e = ${{self.c_ident}}(e+1); 670} 671''') 672 673 # MachineType hack used to set the base level and number of 674 # components for each Machine 675 if self.isMachineType: 676 code(''' 677/** \\brief returns the base vector index for each machine type to be 678 * used by NetDest 679 * 680 * \\return the base vector index for each machine type to be used by NetDest 681 * \\see NetDest.hh 682 */ 683int 684${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 685{ 686 switch(obj) { 687''') 688 689 # For each field 690 code.indent() 691 for i,enum in enumerate(self.enums.itervalues()): 692 code(' case ${{self.c_ident}}_${{enum.ident}}:') 693 code(' return $i;') 694 code.dedent() 695 696 # total num 697 code(''' 698 case ${{self.c_ident}}_NUM: 699 return ${{len(self.enums)}}; 700 701 default: 702 panic("Invalid range for type ${{self.c_ident}}"); 703 } 704} 705 706/** \\brief returns the machine type for each base vector index used by NetDest 707 * 708 * \\return the MachineType 709 */ 710MachineType 711${{self.c_ident}}_from_base_level(int type) 712{ 713 switch(type) { 714''') 715 716 # For each field 717 code.indent() 718 for i,enum in enumerate(self.enums.itervalues()): 719 code(' case $i:') 720 code(' return ${{self.c_ident}}_${{enum.ident}};') 721 code.dedent() 722 723 # Trailer 724 code(''' 725 default: 726 panic("Invalid range for type ${{self.c_ident}}"); 727 } 728} 729 730/** \\brief The return value indicates the number of components created 731 * before a particular machine\'s components 732 * 733 * \\return the base number of components for each machine 734 */ 735int 736${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 737{ 738 int base = 0; 739 switch(obj) { 740''') 741 742 # For each field 743 code.indent() 744 code(' case ${{self.c_ident}}_NUM:') 745 for enum in reversed(self.enums.values()): 746 code(' base += ${{enum.ident}}_Controller::getNumControllers();') 747 code(' case ${{self.c_ident}}_${{enum.ident}}:') 748 code(' break;') 749 code.dedent() 750 751 code(''' 752 default: 753 panic("Invalid range for type ${{self.c_ident}}"); 754 } 755 756 return base; 757} 758 759/** \\brief returns the total number of components for each machine 760 * \\return the total number of components for each machine 761 */ 762int 763${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 764{ 765 switch(obj) { 766''') 767 768 # For each field 769 for enum in self.enums.itervalues(): 770 code(''' 771 case ${{self.c_ident}}_${{enum.ident}}: 772 return ${{enum.ident}}_Controller::getNumControllers(); 773''') 774 775 # total num 776 code(''' 777 case ${{self.c_ident}}_NUM: 778 default: 779 panic("Invalid range for type ${{self.c_ident}}"); 780 } 781} 782''') 783 784 for enum in self.enums.itervalues(): 785 if enum.ident == "DMA": 786 code(''' 787MachineID 788map_Address_to_DMA(const Address &addr) 789{ 790 MachineID dma = {MachineType_DMA, 0}; 791 return dma; 792} 793''') 794 795 code(''' 796 797MachineID 798get${{enum.ident}}MachineID(NodeID RubyNode) 799{ 800 MachineID mach = {MachineType_${{enum.ident}}, RubyNode}; 801 return mach; 802} 803''') 804 805 # Write the file 806 code.write(path, "%s.cc" % self.c_ident) 807 808__all__ = [ "Type" ] 809