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