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