Type.py revision 6657:ef5fae93a3b2
14304SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 24304SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company 34304SN/A# All rights reserved. 410036SN/A# 58835SN/A# Redistribution and use in source and binary forms, with or without 610036SN/A# modification, are permitted provided that the following conditions are 77935SN/A# met: redistributions of source code must retain the above copyright 87935SN/A# notice, this list of conditions and the following disclaimer; 97935SN/A# redistributions in binary form must reproduce the above copyright 104304SN/A# notice, this list of conditions and the following disclaimer in the 114304SN/A# documentation and/or other materials provided with the distribution; 124304SN/A# neither the name of the copyright holders nor the names of its 1310315SN/A# contributors may be used to endorse or promote products derived from 148835SN/A# this software without specific prior written permission. 159885SN/A# 169885SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1710036SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 188835SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 198835SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2010315SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 218835SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210315SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239481SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249481SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 258625SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2610900Snilay@cs.wisc.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 278721SN/A 288835SN/Afrom m5.util import code_formatter, orderdict 298835SN/A 307935SN/Afrom slicc.util import PairContainer 317935SN/Afrom slicc.symbols.Symbol import Symbol 327935SN/A 337935SN/Aclass DataMember(PairContainer): 347935SN/A def __init__(self, ident, type, pairs, init_code): 357935SN/A super(DataMember, self).__init__(pairs) 367935SN/A self.ident = ident 378983SN/A self.type = type 384304SN/A self.init_code = init_code 399885SN/A 409885SN/Aclass Enumeration(PairContainer): 419885SN/A def __init__(self, ident, pairs): 4210315SN/A super(Enumeration, self).__init__(pairs) 4310036SN/A self.ident = ident 4410315SN/A 459885SN/Aclass Method(object): 469885SN/A def __init__(self, return_type, param_types): 474304SN/A self.return_type = return_type 484304SN/A self.param_types = param_types 499481SN/A 5010315SN/Aclass Type(Symbol): 515876SN/A def __init__(self, table, ident, location, pairs, machine=None): 529885SN/A super(Type, self).__init__(table, ident, location, pairs) 534304SN/A self.c_ident = ident 545876SN/A if machine: 558835SN/A if self.isExternal or self.isPrimitive: 565876SN/A if "external_name" in self: 575000SN/A self.c_ident = self["external_name"] 5810036SN/A else: 594304SN/A # Append with machine name 604304SN/A self.c_ident = "%s_%s" % (machine, ident) 618835SN/A 629481SN/A self.pairs.setdefault("desc", "No description avaliable") 635000SN/A 644304SN/A # check for interface that this Type implements 654304SN/A if "interface" in self: 664304SN/A interface = self["interface"] 674304SN/A if interface in ("Message", "NetworkMessage"): 685575SN/A self["message"] = "yes" 698835SN/A if interface == "NetworkMessage": 704304SN/A self["networkmessage"] = "yes" 719885SN/A 7210315SN/A # FIXME - all of the following id comparisons are fragile hacks 739481SN/A if self.ident in ("CacheMemory", "NewCacheMemory", 744304SN/A "TLCCacheMemory", "DNUCACacheMemory", 754971SN/A "DNUCABankCacheMemory", "L2BankCacheMemory", 764304SN/A "CompressedCacheMemory", "PrefetchCacheMemory"): 774304SN/A self["cache"] = "yes" 784304SN/A 794304SN/A if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"): 804304SN/A self["tbe"] = "yes" 8111066Snilay@cs.wisc.edu 829885SN/A if self.ident == "NewTBETable": 838983SN/A self["newtbe"] = "yes" 844304SN/A 859885SN/A if self.ident == "TimerTable": 8610900Snilay@cs.wisc.edu self["timer"] = "yes" 8710036SN/A 886123SN/A if self.ident == "DirectoryMemory": 899481SN/A self["dir"] = "yes" 9010900Snilay@cs.wisc.edu 914304SN/A if self.ident == "PersistentTable": 929481SN/A self["persistent"] = "yes" 935876SN/A 948835SN/A if self.ident == "Prefetcher": 959481SN/A self["prefetcher"] = "yes" 9610036SN/A 974304SN/A if self.ident == "DNUCA_Movement": 988835SN/A self["mover"] = "yes" 999885SN/A 1009481SN/A self.isMachineType = (ident == "MachineType") 1014304SN/A 1024304SN/A self.data_members = orderdict() 1038983SN/A 1044304SN/A # Methods 1059885SN/A self.methods = {} 1069885SN/A 1079885SN/A # Enums 1089885SN/A self.enums = orderdict() 1099885SN/A 11010036SN/A @property 1119885SN/A def isPrimitive(self): 11210036SN/A return "primitive" in self 1139885SN/A @property 1149885SN/A def isNetworkMessage(self): 1155000SN/A return "networkmessage" in self 1166024SN/A @property 11710036SN/A def isMessage(self): 1185000SN/A return "message" in self 1195000SN/A @property 1204304SN/A def isBuffer(self): 12111066Snilay@cs.wisc.edu return "buffer" in self 1229885SN/A @property 1238983SN/A def isInPort(self): 1244304SN/A return "inport" in self 1259885SN/A @property 12610900Snilay@cs.wisc.edu def isOutPort(self): 12710036SN/A return "outport" in self 1286123SN/A @property 1299481SN/A def isEnumeration(self): 13010900Snilay@cs.wisc.edu return "enumeration" in self 1314304SN/A @property 1329481SN/A def isExternal(self): 1335876SN/A return "external" in self 1348835SN/A @property 1359481SN/A def isGlobal(self): 13610036SN/A return "global" in self 1374304SN/A @property 1388835SN/A def isInterface(self): 1399885SN/A return "interface" in self 1409481SN/A 1414304SN/A # Return false on error 1424304SN/A def dataMemberAdd(self, ident, type, pairs, init_code): 1438983SN/A if ident in self.data_members: 1444304SN/A return False 1459885SN/A 1469885SN/A member = DataMember(ident, type, pairs, init_code) 1479885SN/A self.data_members[ident] = member 1489885SN/A 1499885SN/A return True 15010036SN/A 1519885SN/A def dataMemberType(self, ident): 15210036SN/A return self.data_members[ident].type 1539885SN/A 1549885SN/A def methodId(self, name, param_type_vec): 1558835SN/A return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ]) 1568835SN/A 15710036SN/A def methodAdd(self, name, return_type, param_type_vec): 1588835SN/A ident = self.methodId(name, param_type_vec) 1599481SN/A if ident in self.methods: 1609481SN/A return False 16110036SN/A 1629481SN/A self.methods[ident] = Method(return_type, param_type_vec) 1635000SN/A return True 1646024SN/A 16510036SN/A def enumAdd(self, ident, pairs): 1665000SN/A if ident in self.enums: 1675000SN/A return False 1684304SN/A 16911066Snilay@cs.wisc.edu self.enums[ident] = Enumeration(ident, pairs) 1709885SN/A 1718983SN/A # Add default 1729481SN/A if "default" not in self: 1739885SN/A self["default"] = "%s_NUM" % self.c_ident 17410900Snilay@cs.wisc.edu 17510036SN/A return True 1766123SN/A 1779481SN/A def writeCodeFiles(self, path): 17810900Snilay@cs.wisc.edu if self.isExternal: 1794304SN/A # Do nothing 1809481SN/A pass 1815876SN/A elif self.isEnumeration: 1828835SN/A self.printEnumHH(path) 1839481SN/A self.printEnumCC(path) 18410036SN/A else: 1854304SN/A # User defined structs and messages 1868835SN/A self.printTypeHH(path) 1879885SN/A self.printTypeCC(path) 1889481SN/A 1894304SN/A def printTypeHH(self, path): 1908983SN/A code = code_formatter() 1918983SN/A code(''' 1924304SN/A/** \\file ${{self.c_ident}}.hh 1939885SN/A * 1949885SN/A * 1959885SN/A * Auto generated C++ code started by $__file__:$__line__ 1969885SN/A */ 1979885SN/A 19810036SN/A#ifndef ${{self.c_ident}}_H 1999885SN/A#define ${{self.c_ident}}_H 20010036SN/A 2019885SN/A#include "mem/ruby/common/Global.hh" 2029885SN/A#include "mem/gems_common/Allocator.hh" 2034304SN/A''') 20410451SN/A 2059885SN/A for dm in self.data_members.values(): 20610036SN/A if not dm.type.isPrimitive: 20710900Snilay@cs.wisc.edu code('#include "mem/protocol/$0.hh"', dm.type.c_ident) 20810900Snilay@cs.wisc.edu 20910900Snilay@cs.wisc.edu parent = "" 21010451SN/A if "interface" in self: 21110900Snilay@cs.wisc.edu code('#include "mem/protocol/$0.hh"', self["interface"]) 2129885SN/A parent = " : public %s" % self["interface"] 2137524SN/A 2149481SN/A code(''' 2158983SN/A$klass ${{self.c_ident}}$parent { 2168983SN/A public: 2174304SN/A ${{self.c_ident}}() 2184971SN/A''', klass="class") 2194971SN/A 22010036SN/A # Call superclass constructor 2214971SN/A if "interface" in self: 2224304SN/A code(' : ${{self["interface"]}}()') 2234304SN/A 2244304SN/A code.indent() 22510900Snilay@cs.wisc.edu code("{") 22610900Snilay@cs.wisc.edu if not self.isGlobal: 2274304SN/A code.indent() 2284304SN/A for dm in self.data_members.values(): 2295520SN/A ident = dm.ident 2304304SN/A if "default" in dm: 23110036SN/A # look for default value 23210315SN/A code('m_$ident = ${{dm["default"]}}; // default for this field') 2334304SN/A elif "default" in dm.type: 2344304SN/A # Look for the type default 23510900Snilay@cs.wisc.edu tid = dm.type.c_ident 2365285SN/A code('m_$ident = ${{dm.type["default"]}}; // default value of $tid') 2374304SN/A else: 2384304SN/A code('// m_$ident has no default') 2394304SN/A code.dedent() 2405509SN/A code('}') 2414304SN/A 2424304SN/A # ******** Default destructor ******** 24310451SN/A code('~${{self.c_ident}}() { };') 2444304SN/A 2459885SN/A # ******** Full init constructor ******** 2469885SN/A if not self.isGlobal: 2479885SN/A params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \ 24810315SN/A for dm in self.data_members.itervalues() ] 24910036SN/A 25010315SN/A if self.isMessage: 2519885SN/A params.append('const unsigned local_proc_id') 2529885SN/A 25310315SN/A params = ', '.join(params) 25410315SN/A code('${{self.c_ident}}($params)') 25510315SN/A 25610315SN/A # Call superclass constructor 25710315SN/A if "interface" in self: 25810315SN/A code(' : ${{self["interface"]}}()') 25910315SN/A 26010315SN/A code('{') 2614304SN/A code.indent() 26210451SN/A for dm in self.data_members.values(): 2639885SN/A code('m_${{dm.ident}} = local_${{dm.ident}};') 26410036SN/A if "nextLineCallHack" in dm: 26510900Snilay@cs.wisc.edu code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};') 26610900Snilay@cs.wisc.edu 26710900Snilay@cs.wisc.edu if self.isMessage: 26810451SN/A code('proc_id = local_proc_id;') 26910900Snilay@cs.wisc.edu 2709885SN/A code.dedent() 2717524SN/A code('}') 27210900Snilay@cs.wisc.edu 2739150SN/A # create a static factory method 2748983SN/A if "interface" in self: 2754304SN/A code(''' 2764304SN/Astatic ${{self["interface"]}}* create() { 2778983SN/A return new ${{self.c_ident}}(); 2789481SN/A} 2799885SN/A''') 2809885SN/A 28110036SN/A # ******** Message member functions ******** 2828983SN/A # FIXME: those should be moved into slicc file, slicc should 2835520SN/A # support more of the c++ class inheritance 2845509SN/A 2855509SN/A if self.isMessage: 2864304SN/A code(''' 2878983SN/AMessage* clone() const { checkAllocator(); return s_allocator_ptr->allocate(*this); } 2884304SN/Avoid destroy() { checkAllocator(); s_allocator_ptr->deallocate(this); } 2899885SN/Astatic Allocator<${{self.c_ident}}>* s_allocator_ptr; 2909885SN/Astatic void checkAllocator() { if (s_allocator_ptr == NULL) { s_allocator_ptr = new Allocator<${{self.c_ident}}>; }} 29110036SN/A''') 2929885SN/A 2939885SN/A if not self.isGlobal: 294 # const Get methods for each field 295 code('// Const accessors methods for each field') 296 for dm in self.data_members.values(): 297 code(''' 298/** \\brief Const accessor method for ${{dm.ident}} field. 299 * \\return ${{dm.ident}} field 300 */ 301const ${{dm.type.c_ident}}& get${{dm.ident}}() const { return m_${{dm.ident}}; } 302''') 303 304 # Non-const Get methods for each field 305 code('// Non const Accessors methods for each field') 306 for dm in self.data_members.values(): 307 code(''' 308/** \\brief Non-const accessor method for ${{dm.ident}} field. 309 * \\return ${{dm.ident}} field 310 */ 311${{dm.type.c_ident}}& get${{dm.ident}}() { return m_${{dm.ident}}; } 312''') 313 314 #Set methods for each field 315 code('// Mutator methods for each field') 316 for dm in self.data_members.values(): 317 code(''' 318/** \\brief Mutator method for ${{dm.ident}} field */ 319void set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) { m_${{dm.ident}} = local_${{dm.ident}}; } 320''') 321 322 code('void print(ostream& out) const;') 323 code.dedent() 324 code(' //private:') 325 code.indent() 326 327 # Data members for each field 328 for dm in self.data_members.values(): 329 if "abstract" not in dm: 330 const = "" 331 init = "" 332 333 # global structure 334 if self.isGlobal: 335 const = "static const " 336 337 # init value 338 if dm.init_code: 339 # only global structure can have init value here 340 assert self.isGlobal 341 init = " = %s" % (dm.init_code) 342 343 desc = "" 344 if "desc" in dm: 345 desc = '/**< %s */' % dm["desc"] 346 347 code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init; $desc') 348 349 if self.isMessage: 350 code('unsigned proc_id;') 351 352 code.dedent() 353 code('};') 354 355 code(''' 356// Output operator declaration 357ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); 358 359// Output operator definition 360extern inline 361ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) 362{ 363 obj.print(out); 364 out << flush; 365 return out; 366} 367 368#endif // ${{self.c_ident}}_H 369''') 370 371 code.write(path, "%s.hh" % self.c_ident) 372 373 def printTypeCC(self, path): 374 code = code_formatter() 375 376 code(''' 377/** \\file ${{self.c_ident}}.cc 378 * 379 * Auto generated C++ code started by $__file__:$__line__ 380 */ 381 382#include "mem/protocol/${{self.c_ident}}.hh" 383''') 384 385 if self.isMessage: 386 code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;') 387 code(''' 388/** \\brief Print the state of this object */ 389void ${{self.c_ident}}::print(ostream& out) const 390{ 391 out << "[${{self.c_ident}}: "; 392''') 393 394 # For each field 395 code.indent() 396 for dm in self.data_members.values(): 397 code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') 398 399 if self.isMessage: 400 code('out << "Time = " << getTime() << " ";') 401 code.dedent() 402 403 # Trailer 404 code(''' 405 out << "]"; 406}''') 407 408 code.write(path, "%s.cc" % self.c_ident) 409 410 def printEnumHH(self, path): 411 code = code_formatter() 412 code(''' 413/** \\file ${{self.c_ident}}.hh 414 * 415 * Auto generated C++ code started by $__file__:$__line__ 416 */ 417#ifndef ${{self.c_ident}}_H 418#define ${{self.c_ident}}_H 419 420#include "mem/ruby/common/Global.hh" 421 422/** \\enum ${{self.c_ident}} 423 * \\brief ${{self.desc}} 424 */ 425enum ${{self.c_ident}} { 426 ${{self.c_ident}}_FIRST, 427''') 428 429 code.indent() 430 # For each field 431 for i,(ident,enum) in enumerate(self.enums.iteritems()): 432 desc = enum.get("desc", "No description avaliable") 433 init = ' = %s_FIRST' % self.c_ident if i == 0 else '' 434 435 code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') 436 code.dedent() 437 code(''' 438 ${{self.c_ident}}_NUM 439}; 440${{self.c_ident}} string_to_${{self.c_ident}}(const string& str); 441string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); 442${{self.c_ident}} &operator++(${{self.c_ident}} &e); 443''') 444 445 # MachineType hack used to set the base component id for each Machine 446 if self.isMachineType: 447 code(''' 448int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); 449MachineType ${{self.c_ident}}_from_base_level(int); 450int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); 451int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); 452''') 453 454 for enum in self.enums.itervalues(): 455 code('#define MACHINETYPE_${{enum.ident}} 1') 456 457 # Trailer 458 code(''' 459ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); 460 461#endif // ${{self.c_ident}}_H 462''') 463 464 code.write(path, "%s.hh" % self.c_ident) 465 466 def printEnumCC(self, path): 467 code = code_formatter() 468 code(''' 469/** \\file ${{self.c_ident}}.hh 470 * 471 * Auto generated C++ code started by $__file__:$__line__ 472 */ 473 474#include "mem/protocol/${{self.c_ident}}.hh" 475 476''') 477 478 if self.isMachineType: 479 code('#include "mem/protocol/ControllerFactory.hh"') 480 for enum in self.enums.itervalues(): 481 code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') 482 483 code(''' 484ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) 485{ 486 out << ${{self.c_ident}}_to_string(obj); 487 out << flush; 488 return out; 489} 490 491string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) 492{ 493 switch(obj) { 494''') 495 496 # For each field 497 code.indent() 498 for enum in self.enums.itervalues(): 499 code(' case ${{self.c_ident}}_${{enum.ident}}:') 500 code(' return "${{enum.ident}}";') 501 code.dedent() 502 503 # Trailer 504 code(''' 505 default: 506 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 507 return ""; 508 } 509} 510 511${{self.c_ident}} string_to_${{self.c_ident}}(const string& str) 512{ 513''') 514 515 # For each field 516 code.indent() 517 code("if (false) {") 518 start = "} else " 519 for enum in self.enums.itervalues(): 520 code('${start}if (str == "${{enum.ident}}") {') 521 code(' return ${{self.c_ident}}_${{enum.ident}};') 522 code.dedent() 523 524 code(''' 525 } else { 526 WARN_EXPR(str); 527 ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}"); 528 } 529} 530 531${{self.c_ident}}& operator++(${{self.c_ident}}& e) { 532 assert(e < ${{self.c_ident}}_NUM); 533 return e = ${{self.c_ident}}(e+1); 534} 535''') 536 537 # MachineType hack used to set the base level and number of 538 # components for each Machine 539 if self.isMachineType: 540 code(''' 541/** \\brief returns the base vector index for each machine type to be used by NetDest 542 * 543 * \\return the base vector index for each machine type to be used by NetDest 544 * \\see NetDest.hh 545 */ 546int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) 547{ 548 switch(obj) { 549''') 550 551 # For each field 552 code.indent() 553 for i,enum in enumerate(self.enums.itervalues()): 554 code(' case ${{self.c_ident}}_${{enum.ident}}:') 555 code(' return $i;') 556 code.dedent() 557 558 # total num 559 code(''' 560 case ${{self.c_ident}}_NUM: 561 return ${{len(self.enums)}}; 562 563 default: 564 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 565 return -1; 566 } 567} 568 569/** \\brief returns the machine type for each base vector index used by NetDest 570 * 571 * \\return the MachineTYpe 572 */ 573MachineType ${{self.c_ident}}_from_base_level(int type) 574{ 575 switch(type) { 576''') 577 578 # For each field 579 code.indent() 580 for i,enum in enumerate(self.enums.itervalues()): 581 code(' case $i:') 582 code(' return ${{self.c_ident}}_${{enum.ident}};') 583 code.dedent() 584 585 # Trailer 586 code(''' 587 default: 588 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 589 return MachineType_NUM; 590 } 591} 592 593/** \\brief The return value indicates the number of components created 594 * before a particular machine\'s components 595 * 596 * \\return the base number of components for each machine 597 */ 598int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) 599{ 600 int base = 0; 601 switch(obj) { 602''') 603 604 # For each field 605 code.indent() 606 code(' case ${{self.c_ident}}_NUM:') 607 for enum in reversed(self.enums.values()): 608 code(' base += ${{enum.ident}}_Controller::getNumControllers();') 609 code(' case ${{self.c_ident}}_${{enum.ident}}:') 610 code(' break;') 611 code.dedent() 612 613 code(''' 614 default: 615 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 616 return -1; 617 } 618 619 return base; 620} 621 622/** \\brief returns the total number of components for each machine 623 * \\return the total number of components for each machine 624 */ 625int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) 626{ 627 switch(obj) { 628''') 629 630 # For each field 631 for enum in self.enums.itervalues(): 632 code(''' 633 case ${{self.c_ident}}_${{enum.ident}}: 634 return ${{enum.ident}}_Controller::getNumControllers(); 635''') 636 637 # total num 638 code(''' 639 case ${{self.c_ident}}_NUM: 640 default: 641 ERROR_MSG("Invalid range for type ${{self.c_ident}}"); 642 return -1; 643 } 644} 645''') 646 647 # Write the file 648 code.write(path, "%s.cc" % self.c_ident) 649 650__all__ = [ "Type" ] 651