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
|
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(ident, type, pairs, init_code)
130 self.data_members[ident] = member
|
129 member = DataMember(self.symtab, ident, self.location, type, 130 "m_%s" % ident, pairs, None, init_code) |
131
|
132 var = Var(self.symtab, ident, self.location, type,
133 "m_%s" % ident, {}, None)
134 self.symtab.registerSym(ident, var)
|
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" ]
|