Type.py revision 11108:6342ddf6d733
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 276 code.dedent() 277 code('}') 278 279 # create a clone member 280 if self.isMessage: 281 code(''' 282MsgPtr 283clone() const 284{ 285 return std::shared_ptr<Message>(new ${{self.c_ident}}(*this)); 286} 287''') 288 else: 289 code(''' 290${{self.c_ident}}* 291clone() const 292{ 293 return new ${{self.c_ident}}(*this); 294} 295''') 296 297 if not self.isGlobal: 298 # const Get methods for each field 299 code('// Const accessors methods for each field') 300 for dm in self.data_members.values(): 301 code(''' 302/** \\brief Const accessor method for ${{dm.ident}} field. 303 * \\return ${{dm.ident}} field 304 */ 305const ${{dm.type.c_ident}}& 306get${{dm.ident}}() const 307{ 308 return m_${{dm.ident}}; 309} 310''') 311 312 # Non-const Get methods for each field 313 code('// Non const Accessors methods for each field') 314 for dm in self.data_members.values(): 315 code(''' 316/** \\brief Non-const accessor method for ${{dm.ident}} field. 317 * \\return ${{dm.ident}} field 318 */ 319${{dm.type.c_ident}}& 320get${{dm.ident}}() 321{ 322 return m_${{dm.ident}}; 323} 324''') 325 326 #Set methods for each field 327 code('// Mutator methods for each field') 328 for dm in self.data_members.values(): 329 code(''' 330/** \\brief Mutator method for ${{dm.ident}} field */ 331void 332set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) 333{ 334 m_${{dm.ident}} = local_${{dm.ident}}; 335} 336''') 337 338 code('void print(std::ostream& out) const;') 339 code.dedent() 340 code(' //private:') 341 code.indent() 342 343 # Data members for each field 344 for dm in self.data_members.values(): 345 if "abstract" not in dm: 346 const = "" 347 init = "" 348 349 # global structure 350 if self.isGlobal: 351 const = "static const " 352 353 # init value 354 if dm.init_code: 355 # only global structure can have init value here 356 assert self.isGlobal 357 init = " = %s" % (dm.init_code) 358 359 if "desc" in dm: 360 code('/** ${{dm["desc"]}} */') 361 362 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;') 363 364 # Prototypes for methods defined for the Type 365 for item in self.methods: 366 proto = self.methods[item].prototype 367 if proto: 368 code('$proto') 369 370 code.dedent() 371 code('};') 372 373 code(''' 374inline std::ostream& 375operator<<(std::ostream& out, const ${{self.c_ident}}& obj) 376{ 377 obj.print(out); 378 out << std::flush; 379 return out; 380} 381 382#endif // __${{self.c_ident}}_HH__ 383''') 384 385 code.write(path, "%s.hh" % self.c_ident) 386 387 def printTypeCC(self, path): 388 code = self.symtab.codeFormatter() 389 390 code(''' 391/** \\file ${{self.c_ident}}.cc 392 * 393 * Auto generated C++ code started by $__file__:$__line__ 394 */ 395 396#include <iostream> 397#include <memory> 398 399#include "mem/protocol/${{self.c_ident}}.hh" 400#include "mem/ruby/system/RubySystem.hh" 401 402using namespace std; 403''') 404 405 code(''' 406/** \\brief Print the state of this object */ 407void 408${{self.c_ident}}::print(ostream& out) const 409{ 410 out << "[${{self.c_ident}}: "; 411''') 412 413 # For each field 414 code.indent() 415 for dm in self.data_members.values(): 416 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 417 418 code.dedent() 419 420 # Trailer 421 code(''' 422 out << "]"; 423}''') 424 425 # print the code for the methods in the type 426 for item in self.methods: 427 code(self.methods[item].generateCode()) 428 429 code.write(path, "%s.cc" % self.c_ident) 430 431 def printEnumHH(self, path): 432 code = self.symtab.codeFormatter() 433 code(''' 434/** \\file ${{self.c_ident}}.hh 435 * 436 * Auto generated C++ code started by $__file__:$__line__ 437 */ 438 439#ifndef __${{self.c_ident}}_HH__ 440#define __${{self.c_ident}}_HH__ 441 442#include <iostream> 443#include <string> 444 445''') 446 if self.isStateDecl: 447 code('#include "mem/protocol/AccessPermission.hh"') 448 449 if self.isMachineType: 450 code('#include "base/misc.hh"') 451 code('#include "mem/ruby/common/Address.hh"') 452 code('#include "mem/ruby/common/TypeDefines.hh"') 453 code('struct MachineID;') 454 455 code(''' 456 457// Class definition 458/** \\enum ${{self.c_ident}} 459 * \\brief ${{self.desc}} 460 */ 461enum ${{self.c_ident}} { 462 ${{self.c_ident}}_FIRST, 463''') 464 465 code.indent() 466 # For each field 467 for i,(ident,enum) in enumerate(self.enums.iteritems()): 468 desc = enum.get("desc", "No description avaliable") 469 if i == 0: 470 init = ' = %s_FIRST' % self.c_ident 471 else: 472 init = '' 473 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 474 code.dedent() 475 code(''' 476 ${{self.c_ident}}_NUM 477}; 478 479// Code to convert from a string to the enumeration 480${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str); 481 482// Code to convert state to a string 483std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 484 485// Code to increment an enumeration type 486${{self.c_ident}} &operator++(${{self.c_ident}} &e); 487''') 488 489 # MachineType hack used to set the base component id for each Machine 490 if self.isMachineType: 491 code(''' 492int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 493MachineType ${{self.c_ident}}_from_base_level(int); 494int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 495int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 496''') 497 498 for enum in self.enums.itervalues(): 499 if enum.ident == "DMA": 500 code(''' 501MachineID map_Address_to_DMA(const Addr &addr); 502''') 503 code(''' 504 505MachineID get${{enum.ident}}MachineID(NodeID RubyNode); 506''') 507 508 if self.isStateDecl: 509 code(''' 510 511// Code to convert the current state to an access permission 512AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj); 513 514''') 515 516 # Trailer 517 code(''' 518std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj); 519 520#endif // __${{self.c_ident}}_HH__ 521''') 522 523 code.write(path, "%s.hh" % self.c_ident) 524 525 def printEnumCC(self, path): 526 code = self.symtab.codeFormatter() 527 code(''' 528/** \\file ${{self.c_ident}}.hh 529 * 530 * Auto generated C++ code started by $__file__:$__line__ 531 */ 532 533#include <cassert> 534#include <iostream> 535#include <string> 536 537#include "base/misc.hh" 538#include "mem/protocol/${{self.c_ident}}.hh" 539 540using namespace std; 541 542''') 543 544 if self.isStateDecl: 545 code(''' 546// Code to convert the current state to an access permission 547AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj) 548{ 549 switch(obj) { 550''') 551 # For each case 552 code.indent() 553 for statePerm in self.statePermPairs: 554 code(' case ${{self.c_ident}}_${{statePerm[0]}}:') 555 code(' return AccessPermission_${{statePerm[1]}};') 556 code.dedent() 557 code (''' 558 default: 559 panic("Unknown state access permission converstion for ${{self.c_ident}}"); 560 } 561} 562 563''') 564 565 if self.isMachineType: 566 for enum in self.enums.itervalues(): 567 if enum.get("Primary"): 568 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 569 code('#include "mem/ruby/common/MachineID.hh"') 570 571 code(''' 572// Code for output operator 573ostream& 574operator<<(ostream& out, const ${{self.c_ident}}& obj) 575{ 576 out << ${{self.c_ident}}_to_string(obj); 577 out << flush; 578 return out; 579} 580 581// Code to convert state to a string 582string 583${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 584{ 585 switch(obj) { 586''') 587 588 # For each field 589 code.indent() 590 for enum in self.enums.itervalues(): 591 code(' case ${{self.c_ident}}_${{enum.ident}}:') 592 code(' return "${{enum.ident}}";') 593 code.dedent() 594 595 # Trailer 596 code(''' 597 default: 598 panic("Invalid range for type ${{self.c_ident}}"); 599 } 600} 601 602// Code to convert from a string to the enumeration 603${{self.c_ident}} 604string_to_${{self.c_ident}}(const string& str) 605{ 606''') 607 608 # For each field 609 start = "" 610 code.indent() 611 for enum in self.enums.itervalues(): 612 code('${start}if (str == "${{enum.ident}}") {') 613 code(' return ${{self.c_ident}}_${{enum.ident}};') 614 start = "} else " 615 code.dedent() 616 617 code(''' 618 } else { 619 panic("Invalid string conversion for %s, type ${{self.c_ident}}", str); 620 } 621} 622 623// Code to increment an enumeration type 624${{self.c_ident}}& 625operator++(${{self.c_ident}}& e) 626{ 627 assert(e < ${{self.c_ident}}_NUM); 628 return e = ${{self.c_ident}}(e+1); 629} 630''') 631 632 # MachineType hack used to set the base level and number of 633 # components for each Machine 634 if self.isMachineType: 635 code(''' 636/** \\brief returns the base vector index for each machine type to be 637 * used by NetDest 638 * 639 * \\return the base vector index for each machine type to be used by NetDest 640 * \\see NetDest.hh 641 */ 642int 643${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 644{ 645 switch(obj) { 646''') 647 648 # For each field 649 code.indent() 650 for i,enum in enumerate(self.enums.itervalues()): 651 code(' case ${{self.c_ident}}_${{enum.ident}}:') 652 code(' return $i;') 653 code.dedent() 654 655 # total num 656 code(''' 657 case ${{self.c_ident}}_NUM: 658 return ${{len(self.enums)}}; 659 660 default: 661 panic("Invalid range for type ${{self.c_ident}}"); 662 } 663} 664 665/** \\brief returns the machine type for each base vector index used by NetDest 666 * 667 * \\return the MachineType 668 */ 669MachineType 670${{self.c_ident}}_from_base_level(int type) 671{ 672 switch(type) { 673''') 674 675 # For each field 676 code.indent() 677 for i,enum in enumerate(self.enums.itervalues()): 678 code(' case $i:') 679 code(' return ${{self.c_ident}}_${{enum.ident}};') 680 code.dedent() 681 682 # Trailer 683 code(''' 684 default: 685 panic("Invalid range for type ${{self.c_ident}}"); 686 } 687} 688 689/** \\brief The return value indicates the number of components created 690 * before a particular machine\'s components 691 * 692 * \\return the base number of components for each machine 693 */ 694int 695${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 696{ 697 int base = 0; 698 switch(obj) { 699''') 700 701 # For each field 702 code.indent() 703 code(' case ${{self.c_ident}}_NUM:') 704 for enum in reversed(self.enums.values()): 705 # Check if there is a defined machine with this type 706 if enum.get("Primary"): 707 code(' base += ${{enum.ident}}_Controller::getNumControllers();') 708 else: 709 code(' base += 0;') 710 code(' case ${{self.c_ident}}_${{enum.ident}}:') 711 code(' break;') 712 code.dedent() 713 714 code(''' 715 default: 716 panic("Invalid range for type ${{self.c_ident}}"); 717 } 718 719 return base; 720} 721 722/** \\brief returns the total number of components for each machine 723 * \\return the total number of components for each machine 724 */ 725int 726${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 727{ 728 switch(obj) { 729''') 730 731 # For each field 732 for enum in self.enums.itervalues(): 733 code('case ${{self.c_ident}}_${{enum.ident}}:') 734 if enum.get("Primary"): 735 code('return ${{enum.ident}}_Controller::getNumControllers();') 736 else: 737 code('return 0;') 738 739 # total num 740 code(''' 741 case ${{self.c_ident}}_NUM: 742 default: 743 panic("Invalid range for type ${{self.c_ident}}"); 744 } 745} 746''') 747 748 for enum in self.enums.itervalues(): 749 if enum.ident == "DMA": 750 code(''' 751MachineID 752map_Address_to_DMA(const Addr &addr) 753{ 754 MachineID dma = {MachineType_DMA, 0}; 755 return dma; 756} 757''') 758 759 code(''' 760 761MachineID 762get${{enum.ident}}MachineID(NodeID RubyNode) 763{ 764 MachineID mach = {MachineType_${{enum.ident}}, RubyNode}; 765 return mach; 766} 767''') 768 769 # Write the file 770 code.write(path, "%s.cc" % self.c_ident) 771 772__all__ = [ "Type" ] 773