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