Type.py revision 6999:f226c098c393
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 32 33class DataMember(PairContainer): 34 def __init__(self, ident, type, pairs, init_code): 35 super(DataMember, self).__init__(pairs) 36 self.ident = ident 37 self.type = type 38 self.init_code = init_code 39 40class Enumeration(PairContainer): 41 def __init__(self, ident, pairs): 42 super(Enumeration, self).__init__(pairs) 43 self.ident = ident 44 45class Method(object): 46 def __init__(self, return_type, param_types): 47 self.return_type = return_type 48 self.param_types = param_types 49 50class Type(Symbol): 51 def __init__(self, table, ident, location, pairs, machine=None): 52 super(Type, self).__init__(table, ident, location, pairs) 53 self.c_ident = ident 54 self.abstract_ident = "" 55 if machine: 56 if self.isExternal or self.isPrimitive: 57 if "external_name" in self: 58 self.c_ident = self["external_name"] 59 else: 60 # Append with machine name 61 self.c_ident = "%s_%s" % (machine, ident) 62 63 self.pairs.setdefault("desc", "No description avaliable") 64 65 # check for interface that this Type implements 66 if "interface" in self: 67 interface = self["interface"] 68 if interface in ("Message", "NetworkMessage"): 69 self["message"] = "yes" 70 if interface == "NetworkMessage": 71 self["networkmessage"] = "yes" 72 73 # FIXME - all of the following id comparisons are fragile hacks 74 if self.ident in ("CacheMemory", "NewCacheMemory", 75 "TLCCacheMemory", "DNUCACacheMemory", 76 "DNUCABankCacheMemory", "L2BankCacheMemory", 77 "CompressedCacheMemory", "PrefetchCacheMemory"): 78 self["cache"] = "yes" 79 80 if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"): 81 self["tbe"] = "yes" 82 83 if self.ident == "NewTBETable": 84 self["newtbe"] = "yes" 85 86 if self.ident == "TimerTable": 87 self["timer"] = "yes" 88 89 if self.ident == "DirectoryMemory": 90 self["dir"] = "yes" 91 92 if self.ident == "PersistentTable": 93 self["persistent"] = "yes" 94 95 if self.ident == "Prefetcher": 96 self["prefetcher"] = "yes" 97 98 if self.ident == "DNUCA_Movement": 99 self["mover"] = "yes" 100 101 self.isMachineType = (ident == "MachineType") 102 103 self.data_members = orderdict() 104 105 # Methods 106 self.methods = {} 107 108 # Enums 109 self.enums = orderdict() 110 111 @property 112 def isPrimitive(self): 113 return "primitive" in self 114 @property 115 def isNetworkMessage(self): 116 return "networkmessage" in self 117 @property 118 def isMessage(self): 119 return "message" in self 120 @property 121 def isBuffer(self): 122 return "buffer" in self 123 @property 124 def isInPort(self): 125 return "inport" in self 126 @property 127 def isOutPort(self): 128 return "outport" in self 129 @property 130 def isEnumeration(self): 131 return "enumeration" in self 132 @property 133 def isExternal(self): 134 return "external" in self 135 @property 136 def isGlobal(self): 137 return "global" in self 138 @property 139 def isInterface(self): 140 return "interface" in self 141 142 # Return false on error 143 def dataMemberAdd(self, ident, type, pairs, init_code): 144 if ident in self.data_members: 145 return False 146 147 member = DataMember(ident, type, pairs, init_code) 148 self.data_members[ident] = member 149 150 return True 151 152 def dataMemberType(self, ident): 153 return self.data_members[ident].type 154 155 def methodId(self, name, param_type_vec): 156 return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ]) 157 158 def methodIdAbstract(self, name, param_type_vec): 159 return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ]) 160 161 def methodAdd(self, name, return_type, param_type_vec): 162 ident = self.methodId(name, param_type_vec) 163 if ident in self.methods: 164 return False 165 166 self.methods[ident] = Method(return_type, param_type_vec) 167 return True 168 169 def enumAdd(self, ident, pairs): 170 if ident in self.enums: 171 return False 172 173 self.enums[ident] = Enumeration(ident, pairs) 174 175 # Add default 176 if "default" not in self: 177 self["default"] = "%s_NUM" % self.c_ident 178 179 return True 180 181 def writeCodeFiles(self, path): 182 if self.isExternal: 183 # Do nothing 184 pass 185 elif self.isEnumeration: 186 self.printEnumHH(path) 187 self.printEnumCC(path) 188 else: 189 # User defined structs and messages 190 self.printTypeHH(path) 191 self.printTypeCC(path) 192 193 def printTypeHH(self, path): 194 code = self.symtab.codeFormatter() 195 code(''' 196/** \\file ${{self.c_ident}}.hh 197 * 198 * 199 * Auto generated C++ code started by $__file__:$__line__ 200 */ 201 202#ifndef ${{self.c_ident}}_H 203#define ${{self.c_ident}}_H 204 205#include "mem/ruby/common/Global.hh" 206#include "mem/gems_common/Allocator.hh" 207''') 208 209 for dm in self.data_members.values(): 210 if not dm.type.isPrimitive: 211 code('#include "mem/protocol/$0.hh"', dm.type.c_ident) 212 213 parent = "" 214 if "interface" in self: 215 code('#include "mem/protocol/$0.hh"', self["interface"]) 216 parent = " : public %s" % self["interface"] 217 218 code(''' 219$klass ${{self.c_ident}}$parent { 220 public: 221 ${{self.c_ident}}() 222''', klass="class") 223 224 # Call superclass constructor 225 if "interface" in self: 226 code(' : ${{self["interface"]}}()') 227 228 code.indent() 229 code("{") 230 if not self.isGlobal: 231 code.indent() 232 for dm in self.data_members.values(): 233 ident = dm.ident 234 if "default" in dm: 235 # look for default value 236 code('m_$ident = ${{dm["default"]}}; // default for this field') 237 elif "default" in dm.type: 238 # Look for the type default 239 tid = dm.type.c_ident 240 code('m_$ident = ${{dm.type["default"]}}; // default value of $tid') 241 else: 242 code('// m_$ident has no default') 243 code.dedent() 244 code('}') 245 246 # ******** Default destructor ******** 247 code('~${{self.c_ident}}() { };') 248 249 # ******** Full init constructor ******** 250 if not self.isGlobal: 251 params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \ 252 for dm in self.data_members.itervalues() ] 253 254 if self.isMessage: 255 params.append('const unsigned local_proc_id') 256 257 params = ', '.join(params) 258 code('${{self.c_ident}}($params)') 259 260 # Call superclass constructor 261 if "interface" in self: 262 code(' : ${{self["interface"]}}()') 263 264 code('{') 265 code.indent() 266 for dm in self.data_members.values(): 267 code('m_${{dm.ident}} = local_${{dm.ident}};') 268 if "nextLineCallHack" in dm: 269 code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};') 270 271 if self.isMessage: 272 code('proc_id = local_proc_id;') 273 274 code.dedent() 275 code('}') 276 277 # create a static factory method 278 if "interface" in self: 279 code(''' 280static ${{self["interface"]}}* create() { 281 return new ${{self.c_ident}}(); 282} 283''') 284 285 # ******** Message member functions ******** 286 # FIXME: those should be moved into slicc file, slicc should 287 # support more of the c++ class inheritance 288 289 if self.isMessage: 290 code(''' 291Message* clone() const { checkAllocator(); return s_allocator_ptr->allocate(*this); } 292void destroy() { checkAllocator(); s_allocator_ptr->deallocate(this); } 293static Allocator<${{self.c_ident}}>* s_allocator_ptr; 294static void checkAllocator() { if (s_allocator_ptr == NULL) { s_allocator_ptr = new Allocator<${{self.c_ident}}>; }} 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}}& get${{dm.ident}}() const { return m_${{dm.ident}}; } 306''') 307 308 # Non-const Get methods for each field 309 code('// Non const Accessors methods for each field') 310 for dm in self.data_members.values(): 311 code(''' 312/** \\brief Non-const accessor method for ${{dm.ident}} field. 313 * \\return ${{dm.ident}} field 314 */ 315${{dm.type.c_ident}}& get${{dm.ident}}() { return m_${{dm.ident}}; } 316''') 317 318 #Set methods for each field 319 code('// Mutator methods for each field') 320 for dm in self.data_members.values(): 321 code(''' 322/** \\brief Mutator method for ${{dm.ident}} field */ 323void set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) { m_${{dm.ident}} = local_${{dm.ident}}; } 324''') 325 326 code('void print(ostream& out) const;') 327 code.dedent() 328 code(' //private:') 329 code.indent() 330 331 # Data members for each field 332 for dm in self.data_members.values(): 333 if "abstract" not in dm: 334 const = "" 335 init = "" 336 337 # global structure 338 if self.isGlobal: 339 const = "static const " 340 341 # init value 342 if dm.init_code: 343 # only global structure can have init value here 344 assert self.isGlobal 345 init = " = %s" % (dm.init_code) 346 347 desc = "" 348 if "desc" in dm: 349 desc = '/**< %s */' % dm["desc"] 350 351 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init; $desc') 352 353 if self.isMessage: 354 code('unsigned proc_id;') 355 356 code.dedent() 357 code('};') 358 359 code(''' 360// Output operator declaration 361ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); 362 363// Output operator definition 364extern inline 365ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) 366{ 367 obj.print(out); 368 out << flush; 369 return out; 370} 371 372#endif // ${{self.c_ident}}_H 373''') 374 375 code.write(path, "%s.hh" % self.c_ident) 376 377 def printTypeCC(self, path): 378 code = self.symtab.codeFormatter() 379 380 code(''' 381/** \\file ${{self.c_ident}}.cc 382 * 383 * Auto generated C++ code started by $__file__:$__line__ 384 */ 385 386#include "mem/protocol/${{self.c_ident}}.hh" 387''') 388 389 if self.isMessage: 390 code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;') 391 code(''' 392/** \\brief Print the state of this object */ 393void ${{self.c_ident}}::print(ostream& out) const 394{ 395 out << "[${{self.c_ident}}: "; 396''') 397 398 # For each field 399 code.indent() 400 for dm in self.data_members.values(): 401 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 402 403 if self.isMessage: 404 code('out << "Time = " << getTime() << " ";') 405 code.dedent() 406 407 # Trailer 408 code(''' 409 out << "]"; 410}''') 411 412 code.write(path, "%s.cc" % self.c_ident) 413 414 def printEnumHH(self, path): 415 code = self.symtab.codeFormatter() 416 code(''' 417/** \\file ${{self.c_ident}}.hh 418 * 419 * Auto generated C++ code started by $__file__:$__line__ 420 */ 421#ifndef ${{self.c_ident}}_H 422#define ${{self.c_ident}}_H 423 424#include "mem/ruby/common/Global.hh" 425 426/** \\enum ${{self.c_ident}} 427 * \\brief ${{self.desc}} 428 */ 429enum ${{self.c_ident}} { 430 ${{self.c_ident}}_FIRST, 431''') 432 433 code.indent() 434 # For each field 435 for i,(ident,enum) in enumerate(self.enums.iteritems()): 436 desc = enum.get("desc", "No description avaliable") 437 if i == 0: 438 init = ' = %s_FIRST' % self.c_ident 439 else: 440 init = '' 441 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 442 code.dedent() 443 code(''' 444 ${{self.c_ident}}_NUM 445}; 446${{self.c_ident}} string_to_${{self.c_ident}}(const string& str); 447string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 448${{self.c_ident}} &operator++(${{self.c_ident}} &e); 449''') 450 451 # MachineType hack used to set the base component id for each Machine 452 if self.isMachineType: 453 code(''' 454int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 455MachineType ${{self.c_ident}}_from_base_level(int); 456int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 457int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 458''') 459 460 for enum in self.enums.itervalues(): 461 code('#define MACHINETYPE_${{enum.ident}} 1') 462 463 # Trailer 464 code(''' 465ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); 466 467#endif // ${{self.c_ident}}_H 468''') 469 470 code.write(path, "%s.hh" % self.c_ident) 471 472 def printEnumCC(self, path): 473 code = self.symtab.codeFormatter() 474 code(''' 475/** \\file ${{self.c_ident}}.hh 476 * 477 * Auto generated C++ code started by $__file__:$__line__ 478 */ 479 480#include "mem/protocol/${{self.c_ident}}.hh" 481 482''') 483 484 if self.isMachineType: 485 for enum in self.enums.itervalues(): 486 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 487 488 code(''' 489ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) 490{ 491 out << ${{self.c_ident}}_to_string(obj); 492 out << flush; 493 return out; 494} 495 496string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 497{ 498 switch(obj) { 499''') 500 501 # For each field 502 code.indent() 503 for enum in self.enums.itervalues(): 504 code(' case ${{self.c_ident}}_${{enum.ident}}:') 505 code(' return "${{enum.ident}}";') 506 code.dedent() 507 508 # Trailer 509 code(''' 510 default: 511 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 512 return ""; 513 } 514} 515 516${{self.c_ident}} string_to_${{self.c_ident}}(const string& str) 517{ 518''') 519 520 # For each field 521 code.indent() 522 code("if (false) {") 523 start = "} else " 524 for enum in self.enums.itervalues(): 525 code('${start}if (str == "${{enum.ident}}") {') 526 code(' return ${{self.c_ident}}_${{enum.ident}};') 527 code.dedent() 528 529 code(''' 530 } else { 531 WARN_EXPR(str); 532 ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}"); 533 } 534} 535 536${{self.c_ident}}& operator++(${{self.c_ident}}& e) { 537 assert(e < ${{self.c_ident}}_NUM); 538 return e = ${{self.c_ident}}(e+1); 539} 540''') 541 542 # MachineType hack used to set the base level and number of 543 # components for each Machine 544 if self.isMachineType: 545 code(''' 546/** \\brief returns the base vector index for each machine type to be used by NetDest 547 * 548 * \\return the base vector index for each machine type to be used by NetDest 549 * \\see NetDest.hh 550 */ 551int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 552{ 553 switch(obj) { 554''') 555 556 # For each field 557 code.indent() 558 for i,enum in enumerate(self.enums.itervalues()): 559 code(' case ${{self.c_ident}}_${{enum.ident}}:') 560 code(' return $i;') 561 code.dedent() 562 563 # total num 564 code(''' 565 case ${{self.c_ident}}_NUM: 566 return ${{len(self.enums)}}; 567 568 default: 569 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 570 return -1; 571 } 572} 573 574/** \\brief returns the machine type for each base vector index used by NetDest 575 * 576 * \\return the MachineTYpe 577 */ 578MachineType ${{self.c_ident}}_from_base_level(int type) 579{ 580 switch(type) { 581''') 582 583 # For each field 584 code.indent() 585 for i,enum in enumerate(self.enums.itervalues()): 586 code(' case $i:') 587 code(' return ${{self.c_ident}}_${{enum.ident}};') 588 code.dedent() 589 590 # Trailer 591 code(''' 592 default: 593 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 594 return MachineType_NUM; 595 } 596} 597 598/** \\brief The return value indicates the number of components created 599 * before a particular machine\'s components 600 * 601 * \\return the base number of components for each machine 602 */ 603int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 604{ 605 int base = 0; 606 switch(obj) { 607''') 608 609 # For each field 610 code.indent() 611 code(' case ${{self.c_ident}}_NUM:') 612 for enum in reversed(self.enums.values()): 613 code(' base += ${{enum.ident}}_Controller::getNumControllers();') 614 code(' case ${{self.c_ident}}_${{enum.ident}}:') 615 code(' break;') 616 code.dedent() 617 618 code(''' 619 default: 620 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 621 return -1; 622 } 623 624 return base; 625} 626 627/** \\brief returns the total number of components for each machine 628 * \\return the total number of components for each machine 629 */ 630int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 631{ 632 switch(obj) { 633''') 634 635 # For each field 636 for enum in self.enums.itervalues(): 637 code(''' 638 case ${{self.c_ident}}_${{enum.ident}}: 639 return ${{enum.ident}}_Controller::getNumControllers(); 640''') 641 642 # total num 643 code(''' 644 case ${{self.c_ident}}_NUM: 645 default: 646 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 647 return -1; 648 } 649} 650''') 651 652 # Write the file 653 code.write(path, "%s.cc" % self.c_ident) 654 655__all__ = [ "Type" ] 656