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