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