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