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