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