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