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 code_formatter, orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33 34class StateMachine(Symbol): 35 def __init__(self, symtab, ident, location, pairs, config_parameters): 36 super(StateMachine, self).__init__(symtab, ident, location, pairs) 37 self.table = None 38 self.config_parameters = config_parameters 39 for param in config_parameters: 40 var = Var(symtab, param.name, location, param.type_ast.type, 41 "m_%s" % param.name, {}, self) 42 self.symtab.registerSym(param.name, var) 43 44 self.states = orderdict() 45 self.events = orderdict() 46 self.actions = orderdict() 47 self.transitions = [] 48 self.in_ports = [] 49 self.functions = [] 50 self.objects = [] 51 52 self.message_buffer_names = [] 53 54 def __repr__(self): 55 return "[StateMachine: %s]" % self.ident 56 57 def addState(self, state): 58 assert self.table is None 59 self.states[state.ident] = state 60 61 def addEvent(self, event): 62 assert self.table is None 63 self.events[event.ident] = event 64 65 def addAction(self, action): 66 assert self.table is None 67 68 # Check for duplicate action 69 for other in self.actions.itervalues(): 70 if action.ident == other.ident: 71 action.warning("Duplicate action definition: %s" % action.ident) 72 action.error("Duplicate action definition: %s" % action.ident) 73 if action.short == other.short: 74 other.warning("Duplicate action shorthand: %s" % other.ident) 75 other.warning(" shorthand = %s" % other.short) 76 action.warning("Duplicate action shorthand: %s" % action.ident) 77 action.error(" shorthand = %s" % action.short) 78 79 self.actions[action.ident] = action 80 81 def addTransition(self, trans): 82 assert self.table is None 83 self.transitions.append(trans) 84 85 def addInPort(self, var): 86 self.in_ports.append(var) 87 88 def addFunc(self, func): 89 # register func in the symbol table 90 self.symtab.registerSym(str(func), func) 91 self.functions.append(func) 92 93 def addObject(self, obj): 94 self.objects.append(obj) 95 96 # Needs to be called before accessing the table 97 def buildTable(self): 98 assert self.table is None 99 100 table = {} 101 102 for trans in self.transitions: 103 # Track which actions we touch so we know if we use them 104 # all -- really this should be done for all symbols as 105 # part of the symbol table, then only trigger it for 106 # Actions, States, Events, etc. 107 108 for action in trans.actions: 109 action.used = True 110 111 index = (trans.state, trans.event) 112 if index in table: 113 table[index].warning("Duplicate transition: %s" % table[index]) 114 trans.error("Duplicate transition: %s" % trans) 115 table[index] = trans 116 117 # Look at all actions to make sure we used them all 118 for action in self.actions.itervalues(): 119 if not action.used: 120 error_msg = "Unused action: %s" % action.ident 121 if "desc" in action: 122 error_msg += ", " + action.desc 123 action.warning(error_msg) 124 self.table = table 125 126 def writeCodeFiles(self, path): 127 self.printControllerHH(path) 128 self.printControllerCC(path) 129 self.printCSwitch(path) 130 self.printCWakeup(path) 131 self.printProfilerCC(path) 132 self.printProfilerHH(path) 133 134 for func in self.functions: 135 func.writeCodeFiles(path) 136 137 def printControllerHH(self, path): 138 '''Output the method declarations for the class declaration''' 139 code = code_formatter() 140 ident = self.ident 141 c_ident = "%s_Controller" % self.ident 142 143 self.message_buffer_names = [] 144 145 code(''' 146/** \\file $ident.hh 147 * 148 * Auto generated C++ code started by $__file__:$__line__ 149 * Created by slicc definition of Module "${{self.short}}" 150 */ 151 152#ifndef ${ident}_CONTROLLER_H 153#define ${ident}_CONTROLLER_H 154 155#include "mem/ruby/common/Global.hh" 156#include "mem/ruby/common/Consumer.hh" 157#include "mem/ruby/slicc_interface/AbstractController.hh" 158#include "mem/protocol/TransitionResult.hh" 159#include "mem/protocol/Types.hh" 160#include "mem/protocol/${ident}_Profiler.hh" 161''') 162 163 seen_types = set() 164 for var in self.objects:
| 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 code_formatter, orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33 34class StateMachine(Symbol): 35 def __init__(self, symtab, ident, location, pairs, config_parameters): 36 super(StateMachine, self).__init__(symtab, ident, location, pairs) 37 self.table = None 38 self.config_parameters = config_parameters 39 for param in config_parameters: 40 var = Var(symtab, param.name, location, param.type_ast.type, 41 "m_%s" % param.name, {}, self) 42 self.symtab.registerSym(param.name, var) 43 44 self.states = orderdict() 45 self.events = orderdict() 46 self.actions = orderdict() 47 self.transitions = [] 48 self.in_ports = [] 49 self.functions = [] 50 self.objects = [] 51 52 self.message_buffer_names = [] 53 54 def __repr__(self): 55 return "[StateMachine: %s]" % self.ident 56 57 def addState(self, state): 58 assert self.table is None 59 self.states[state.ident] = state 60 61 def addEvent(self, event): 62 assert self.table is None 63 self.events[event.ident] = event 64 65 def addAction(self, action): 66 assert self.table is None 67 68 # Check for duplicate action 69 for other in self.actions.itervalues(): 70 if action.ident == other.ident: 71 action.warning("Duplicate action definition: %s" % action.ident) 72 action.error("Duplicate action definition: %s" % action.ident) 73 if action.short == other.short: 74 other.warning("Duplicate action shorthand: %s" % other.ident) 75 other.warning(" shorthand = %s" % other.short) 76 action.warning("Duplicate action shorthand: %s" % action.ident) 77 action.error(" shorthand = %s" % action.short) 78 79 self.actions[action.ident] = action 80 81 def addTransition(self, trans): 82 assert self.table is None 83 self.transitions.append(trans) 84 85 def addInPort(self, var): 86 self.in_ports.append(var) 87 88 def addFunc(self, func): 89 # register func in the symbol table 90 self.symtab.registerSym(str(func), func) 91 self.functions.append(func) 92 93 def addObject(self, obj): 94 self.objects.append(obj) 95 96 # Needs to be called before accessing the table 97 def buildTable(self): 98 assert self.table is None 99 100 table = {} 101 102 for trans in self.transitions: 103 # Track which actions we touch so we know if we use them 104 # all -- really this should be done for all symbols as 105 # part of the symbol table, then only trigger it for 106 # Actions, States, Events, etc. 107 108 for action in trans.actions: 109 action.used = True 110 111 index = (trans.state, trans.event) 112 if index in table: 113 table[index].warning("Duplicate transition: %s" % table[index]) 114 trans.error("Duplicate transition: %s" % trans) 115 table[index] = trans 116 117 # Look at all actions to make sure we used them all 118 for action in self.actions.itervalues(): 119 if not action.used: 120 error_msg = "Unused action: %s" % action.ident 121 if "desc" in action: 122 error_msg += ", " + action.desc 123 action.warning(error_msg) 124 self.table = table 125 126 def writeCodeFiles(self, path): 127 self.printControllerHH(path) 128 self.printControllerCC(path) 129 self.printCSwitch(path) 130 self.printCWakeup(path) 131 self.printProfilerCC(path) 132 self.printProfilerHH(path) 133 134 for func in self.functions: 135 func.writeCodeFiles(path) 136 137 def printControllerHH(self, path): 138 '''Output the method declarations for the class declaration''' 139 code = code_formatter() 140 ident = self.ident 141 c_ident = "%s_Controller" % self.ident 142 143 self.message_buffer_names = [] 144 145 code(''' 146/** \\file $ident.hh 147 * 148 * Auto generated C++ code started by $__file__:$__line__ 149 * Created by slicc definition of Module "${{self.short}}" 150 */ 151 152#ifndef ${ident}_CONTROLLER_H 153#define ${ident}_CONTROLLER_H 154 155#include "mem/ruby/common/Global.hh" 156#include "mem/ruby/common/Consumer.hh" 157#include "mem/ruby/slicc_interface/AbstractController.hh" 158#include "mem/protocol/TransitionResult.hh" 159#include "mem/protocol/Types.hh" 160#include "mem/protocol/${ident}_Profiler.hh" 161''') 162 163 seen_types = set() 164 for var in self.objects:
|
344 code.dedent() 345 code.dedent() 346 code(''' 347 } 348 349 m_net_ptr = net_ptr; 350 m_machineID.type = MachineType_${ident}; 351 m_machineID.num = m_version; 352 for (size_t i = 0; i < argv.size(); i += 2) { 353 if (argv[i] != "version") 354 m_cfg[argv[i]] = argv[i+1]; 355 } 356 357 // Objects 358 s_profiler.setVersion(m_version); 359''') 360 361 code.indent() 362 for var in self.objects: 363 vtype = var.type 364 vid = "m_%s_ptr" % var.c_ident 365 if "network" not in var: 366 # Not a network port object 367 if "primitive" in vtype: 368 code('$vid = new ${{vtype.c_ident}};') 369 if "default" in var: 370 code('(*$vid) = ${{var["default"]}};') 371 else: 372 # Normal Object 373 # added by SS 374 if "factory" in var: 375 code('$vid = ${{var["factory"]}};') 376 elif var.ident.find("mandatoryQueue") < 0: 377 th = var.get("template_hack", "") 378 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 379 380 args = "" 381 if "non_obj" not in vtype and not vtype.isEnumeration: 382 if expr.find("TBETable") >= 0: 383 args = "m_number_of_TBEs" 384 else: 385 args = var.get("constructor_hack", "") 386 args = "(%s)" % args 387 388 code('$expr$args;') 389 else: 390 code(';') 391 392 code('assert($vid != NULL);') 393 394 if "default" in var: 395 code('(*$vid) = ${{var["default"]}}; // Object default') 396 elif "default" in vtype: 397 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 398 399 # Set ordering 400 if "ordered" in var and "trigger_queue" not in var: 401 # A buffer 402 code('$vid->setOrdering(${{var["ordered"]}});') 403 404 # Set randomization 405 if "random" in var: 406 # A buffer 407 code('$vid->setRandomization(${{var["random"]}});') 408 409 # Set Priority 410 if vtype.isBuffer and \ 411 "rank" in var and "trigger_queue" not in var: 412 code('$vid->setPriority(${{var["rank"]}});') 413 else: 414 # Network port object 415 network = var["network"] 416 ordered = var["ordered"] 417 vnet = var["virtual_network"] 418 419 assert var.machine is not None 420 code(''' 421$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 422''') 423 424 code('assert($vid != NULL);') 425 426 # Set ordering 427 if "ordered" in var: 428 # A buffer 429 code('$vid->setOrdering(${{var["ordered"]}});') 430 431 # Set randomization 432 if "random" in var: 433 # A buffer 434 code('$vid->setRandomization(${{var["random"]}})') 435 436 # Set Priority 437 if "rank" in var: 438 code('$vid->setPriority(${{var["rank"]}})') 439 440 # Set buffer size 441 if vtype.isBuffer: 442 code(''' 443if (m_buffer_size > 0) { 444 $vid->setSize(m_buffer_size); 445} 446''') 447 448 # set description (may be overriden later by port def) 449 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 450 451 # Set the queue consumers 452 code.insert_newline() 453 for port in self.in_ports: 454 code('${{port.code}}.setConsumer(this);') 455 456 # Set the queue descriptions 457 code.insert_newline() 458 for port in self.in_ports: 459 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 460 461 # Initialize the transition profiling 462 code.insert_newline() 463 for trans in self.transitions: 464 # Figure out if we stall 465 stall = False 466 for action in trans.actions: 467 if action.ident == "z_stall": 468 stall = True 469 470 # Only possible if it is not a 'z' case 471 if not stall: 472 state = "%s_State_%s" % (self.ident, trans.state.ident) 473 event = "%s_Event_%s" % (self.ident, trans.event.ident) 474 code('s_profiler.possibleTransition($state, $event);') 475 476 # added by SS to initialize recycle_latency of message buffers 477 for buf in self.message_buffer_names: 478 code("$buf->setRecycleLatency(m_recycle_latency);") 479 480 code.dedent() 481 code('}') 482 483 has_mandatory_q = False 484 for port in self.in_ports: 485 if port.code.find("mandatoryQueue_ptr") >= 0: 486 has_mandatory_q = True 487 488 if has_mandatory_q: 489 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 490 else: 491 mq_ident = "NULL" 492 493 code(''' 494int $c_ident::getNumControllers() { 495 return m_num_controllers; 496} 497 498MessageBuffer* $c_ident::getMandatoryQueue() const { 499 return $mq_ident; 500} 501 502const int & $c_ident::getVersion() const{ 503 return m_version; 504} 505 506const string $c_ident::toString() const{ 507 return "$c_ident"; 508} 509 510const string $c_ident::getName() const{ 511 return m_name; 512} 513const MachineType $c_ident::getMachineType() const{ 514 return MachineType_${ident}; 515} 516 517void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 518 519void $c_ident::printConfig(ostream& out) const { 520 out << "$c_ident config: " << m_name << endl; 521 out << " version: " << m_version << endl; 522 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 523 out << " " << (*it).first << ": " << (*it).second << endl; 524 } 525} 526 527// Actions 528''') 529 530 for action in self.actions.itervalues(): 531 if "c_code" not in action: 532 continue 533 534 code(''' 535/** \\brief ${{action.desc}} */ 536void $c_ident::${{action.ident}}(const Address& addr) 537{ 538 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 539 ${{action["c_code"]}} 540} 541 542''') 543 code.write(path, "%s.cc" % c_ident) 544 545 def printCWakeup(self, path): 546 '''Output the wakeup loop for the events''' 547 548 code = code_formatter() 549 ident = self.ident 550 551 code(''' 552// Auto generated C++ code started by $__file__:$__line__ 553// ${ident}: ${{self.short}} 554 555#include "mem/ruby/common/Global.hh" 556#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 557#include "mem/protocol/${ident}_Controller.hh" 558#include "mem/protocol/${ident}_State.hh" 559#include "mem/protocol/${ident}_Event.hh" 560#include "mem/protocol/Types.hh" 561#include "mem/ruby/system/System.hh" 562 563void ${ident}_Controller::wakeup() 564{ 565 566 int counter = 0; 567 while (true) { 568 // Some cases will put us into an infinite loop without this limit 569 assert(counter <= m_transitions_per_cycle); 570 if (counter == m_transitions_per_cycle) { 571 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 572 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 573 break; 574 } 575''') 576 577 code.indent() 578 code.indent() 579 580 # InPorts 581 # 582 # Find the position of the mandatory queue in the vector so 583 # that we can print it out first 584 585 mandatory_q = None 586 if self.ident == "L1Cache": 587 for i,port in enumerate(self.in_ports): 588 assert "c_code_in_port" in port 589 if str(port).find("mandatoryQueue_in") >= 0: 590 assert mandatory_q is None 591 mandatory_q = port 592 593 assert mandatory_q is not None 594 595 # print out the mandatory queue here 596 port = mandatory_q 597 code('// ${ident}InPort $port') 598 output = port["c_code_in_port"] 599 600 pos = output.find("TransitionResult result = doTransition((L1Cache_mandatory_request_type_to_event(((*in_msg_ptr)).m_Type)), L1Cache_getState(addr), addr);") 601 assert pos >= 0 602 atomics_string = ''' 603if ((((*in_msg_ptr)).m_Type) == CacheRequestType_ATOMIC) { 604 if (servicing_atomic == 0) { 605 if (locked_read_request1 == Address(-1)) { 606 assert(read_counter == 0); 607 locked_read_request1 = addr; 608 assert(read_counter == 0); 609 read_counter++; 610 } 611 else if (addr == locked_read_request1) { 612 ; // do nothing 613 } 614 else { 615 assert(0); // should never be here if servicing one request at a time 616 } 617 } 618 else if (!started_receiving_writes) { 619 if (servicing_atomic == 1) { 620 if (locked_read_request2 == Address(-1)) { 621 assert(locked_read_request1 != Address(-1)); 622 assert(read_counter == 1); 623 locked_read_request2 = addr; 624 assert(read_counter == 1); 625 read_counter++; 626 } 627 else if (addr == locked_read_request2) { 628 ; // do nothing 629 } 630 else { 631 assert(0); // should never be here if servicing one request at a time 632 } 633 } 634 else if (servicing_atomic == 2) { 635 if (locked_read_request3 == Address(-1)) { 636 assert(locked_read_request1 != Address(-1)); 637 assert(locked_read_request2 != Address(-1)); 638 assert(read_counter == 1); 639 locked_read_request3 = addr; 640 assert(read_counter == 2); 641 read_counter++; 642 } 643 else if (addr == locked_read_request3) { 644 ; // do nothing 645 } 646 else { 647 assert(0); // should never be here if servicing one request at a time 648 } 649 } 650 else if (servicing_atomic == 3) { 651 if (locked_read_request4 == Address(-1)) { 652 assert(locked_read_request1 != Address(-1)); 653 assert(locked_read_request2 != Address(-1)); 654 assert(locked_read_request3 != Address(-1)); 655 assert(read_counter == 1); 656 locked_read_request4 = addr; 657 assert(read_counter == 3); 658 read_counter++; 659 } 660 else if (addr == locked_read_request4) { 661 ; // do nothing 662 } 663 else { 664 assert(0); // should never be here if servicing one request at a time 665 } 666 } 667 else { 668 assert(0); 669 } 670 } 671} 672else { 673 if (servicing_atomic > 0) { 674 // reset 675 servicing_atomic = 0; 676 read_counter = 0; 677 started_receiving_writes = false; 678 locked_read_request1 = Address(-1); 679 locked_read_request2 = Address(-1); 680 locked_read_request3 = Address(-1); 681 locked_read_request4 = Address(-1); 682 } 683} 684''' 685 686 output = output[:pos] + atomics_string + output[pos:] 687 code('$output') 688 689 for port in self.in_ports: 690 # don't print out mandatory queue twice 691 if port == mandatory_q: 692 continue 693 694 if ident == "L1Cache": 695 if str(port).find("forwardRequestNetwork_in") >= 0: 696 code(''' 697bool postpone = false; 698if ((((*m_L1Cache_forwardToCache_ptr)).isReady())) { 699 const RequestMsg* in_msg_ptr; 700 in_msg_ptr = dynamic_cast<const RequestMsg*>(((*m_L1Cache_forwardToCache_ptr)).peek()); 701 if ((((servicing_atomic == 1) && (locked_read_request1 == ((*in_msg_ptr)).m_Address)) || 702 ((servicing_atomic == 2) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address)) || 703 ((servicing_atomic == 3) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address)) || 704 ((servicing_atomic == 4) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address || locked_read_request1 == ((*in_msg_ptr)).m_Address)))) { 705 postpone = true; 706 } 707} 708if (!postpone) { 709''') 710 code.indent() 711 code('// ${ident}InPort $port') 712 code('${{port["c_code_in_port"]}}') 713 code.dedent() 714 715 if ident == "L1Cache": 716 if str(port).find("forwardRequestNetwork_in") >= 0: 717 code.dedent() 718 code('}') 719 code.indent() 720 code('') 721 722 code.dedent() 723 code.dedent() 724 code(''' 725 break; // If we got this far, we have nothing left todo 726 } 727} 728''') 729 730 if self.ident == "L1Cache": 731 code(''' 732void ${ident}_Controller::set_atomic(Address addr) 733{ 734 servicing_atomic++; 735} 736 737void ${ident}_Controller::started_writes() 738{ 739 started_receiving_writes = true; 740} 741 742void ${ident}_Controller::clear_atomic() 743{ 744 assert(servicing_atomic > 0); 745 read_counter--; 746 servicing_atomic--; 747 if (read_counter == 0) { 748 servicing_atomic = 0; 749 started_receiving_writes = false; 750 locked_read_request1 = Address(-1); 751 locked_read_request2 = Address(-1); 752 locked_read_request3 = Address(-1); 753 locked_read_request4 = Address(-1); 754 } 755} 756''') 757 else: 758 code(''' 759void ${ident}_Controller::started_writes() 760{ 761 assert(0); 762} 763 764void ${ident}_Controller::set_atomic(Address addr) 765{ 766 assert(0); 767} 768 769void ${ident}_Controller::clear_atomic() 770{ 771 assert(0); 772} 773''') 774 775 776 code.write(path, "%s_Wakeup.cc" % self.ident) 777 778 def printCSwitch(self, path): 779 '''Output switch statement for transition table''' 780 781 code = code_formatter() 782 ident = self.ident 783 784 code(''' 785// Auto generated C++ code started by $__file__:$__line__ 786// ${ident}: ${{self.short}} 787 788#include "mem/ruby/common/Global.hh" 789#include "mem/protocol/${ident}_Controller.hh" 790#include "mem/protocol/${ident}_State.hh" 791#include "mem/protocol/${ident}_Event.hh" 792#include "mem/protocol/Types.hh" 793#include "mem/ruby/system/System.hh" 794 795#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 796 797#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 798#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 799 800TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 801) 802{ 803 ${ident}_State next_state = state; 804 805 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 806 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 807 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 808 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 809 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 810 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 811 812 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 813 814 if (result == TransitionResult_Valid) { 815 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 816 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 817 s_profiler.countTransition(state, event); 818 if (Debug::getProtocolTrace()) { 819 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 820 ${ident}_State_to_string(state), 821 ${ident}_Event_to_string(event), 822 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 823 } 824 CLEAR_TRANSITION_COMMENT(); 825 ${ident}_setState(addr, next_state); 826 827 } else if (result == TransitionResult_ResourceStall) { 828 if (Debug::getProtocolTrace()) { 829 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 830 ${ident}_State_to_string(state), 831 ${ident}_Event_to_string(event), 832 ${ident}_State_to_string(next_state), 833 "Resource Stall"); 834 } 835 } else if (result == TransitionResult_ProtocolStall) { 836 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 837 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 838 if (Debug::getProtocolTrace()) { 839 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 840 ${ident}_State_to_string(state), 841 ${ident}_Event_to_string(event), 842 ${ident}_State_to_string(next_state), 843 "Protocol Stall"); 844 } 845 } 846 847 return result; 848} 849 850TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 851) 852{ 853 switch(HASH_FUN(state, event)) { 854''') 855 856 # This map will allow suppress generating duplicate code 857 cases = orderdict() 858 859 for trans in self.transitions: 860 case_string = "%s_State_%s, %s_Event_%s" % \ 861 (self.ident, trans.state.ident, self.ident, trans.event.ident) 862 863 case = code_formatter() 864 # Only set next_state if it changes 865 if trans.state != trans.nextState: 866 ns_ident = trans.nextState.ident 867 case('next_state = ${ident}_State_${ns_ident};') 868 869 actions = trans.actions 870 871 # Check for resources 872 case_sorter = [] 873 res = trans.resources 874 for key,val in res.iteritems(): 875 if key.type.ident != "DNUCAStopTable": 876 val = ''' 877if (!%s.areNSlotsAvailable(%s)) { 878 return TransitionResult_ResourceStall; 879} 880''' % (key.code, val) 881 case_sorter.append(val) 882 883 884 # Emit the code sequences in a sorted order. This makes the 885 # output deterministic (without this the output order can vary 886 # since Map's keys() on a vector of pointers is not deterministic 887 for c in sorted(case_sorter): 888 case("$c") 889 890 # Figure out if we stall 891 stall = False 892 for action in actions: 893 if action.ident == "z_stall": 894 stall = True 895 break 896 897 if stall: 898 case('return TransitionResult_ProtocolStall;') 899 else: 900 for action in actions: 901 case('${{action.ident}}(addr);') 902 case('return TransitionResult_Valid;') 903 904 case = str(case) 905 906 # Look to see if this transition code is unique. 907 if case not in cases: 908 cases[case] = [] 909 910 cases[case].append(case_string) 911 912 # Walk through all of the unique code blocks and spit out the 913 # corresponding case statement elements 914 for case,transitions in cases.iteritems(): 915 # Iterative over all the multiple transitions that share 916 # the same code 917 for trans in transitions: 918 code(' case HASH_FUN($trans):') 919 code(' {') 920 code(' $case') 921 code(' }') 922 923 code(''' 924 default: 925 WARN_EXPR(m_version); 926 WARN_EXPR(g_eventQueue_ptr->getTime()); 927 WARN_EXPR(addr); 928 WARN_EXPR(event); 929 WARN_EXPR(state); 930 ERROR_MSG(\"Invalid transition\"); 931 } 932 return TransitionResult_Valid; 933} 934''') 935 code.write(path, "%s_Transitions.cc" % self.ident) 936 937 def printProfilerHH(self, path): 938 code = code_formatter() 939 ident = self.ident 940 941 code(''' 942// Auto generated C++ code started by $__file__:$__line__ 943// ${ident}: ${{self.short}} 944 945#ifndef ${ident}_PROFILER_H 946#define ${ident}_PROFILER_H 947 948#include "mem/ruby/common/Global.hh" 949#include "mem/protocol/${ident}_State.hh" 950#include "mem/protocol/${ident}_Event.hh" 951 952class ${ident}_Profiler { 953 public: 954 ${ident}_Profiler(); 955 void setVersion(int version); 956 void countTransition(${ident}_State state, ${ident}_Event event); 957 void possibleTransition(${ident}_State state, ${ident}_Event event); 958 void dumpStats(ostream& out) const; 959 void clearStats(); 960 961 private: 962 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 963 int m_event_counters[${ident}_Event_NUM]; 964 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 965 int m_version; 966}; 967 968#endif // ${ident}_PROFILER_H 969''') 970 code.write(path, "%s_Profiler.hh" % self.ident) 971 972 def printProfilerCC(self, path): 973 code = code_formatter() 974 ident = self.ident 975 976 code(''' 977// Auto generated C++ code started by $__file__:$__line__ 978// ${ident}: ${{self.short}} 979 980#include "mem/protocol/${ident}_Profiler.hh" 981 982${ident}_Profiler::${ident}_Profiler() 983{ 984 for (int state = 0; state < ${ident}_State_NUM; state++) { 985 for (int event = 0; event < ${ident}_Event_NUM; event++) { 986 m_possible[state][event] = false; 987 m_counters[state][event] = 0; 988 } 989 } 990 for (int event = 0; event < ${ident}_Event_NUM; event++) { 991 m_event_counters[event] = 0; 992 } 993} 994void ${ident}_Profiler::setVersion(int version) 995{ 996 m_version = version; 997} 998void ${ident}_Profiler::clearStats() 999{ 1000 for (int state = 0; state < ${ident}_State_NUM; state++) { 1001 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1002 m_counters[state][event] = 0; 1003 } 1004 } 1005 1006 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1007 m_event_counters[event] = 0; 1008 } 1009} 1010void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1011{ 1012 assert(m_possible[state][event]); 1013 m_counters[state][event]++; 1014 m_event_counters[event]++; 1015} 1016void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 1017{ 1018 m_possible[state][event] = true; 1019} 1020void ${ident}_Profiler::dumpStats(ostream& out) const 1021{ 1022 out << " --- ${ident} " << m_version << " ---" << endl; 1023 out << " - Event Counts -" << endl; 1024 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1025 int count = m_event_counters[event]; 1026 out << (${ident}_Event) event << " " << count << endl; 1027 } 1028 out << endl; 1029 out << " - Transitions -" << endl; 1030 for (int state = 0; state < ${ident}_State_NUM; state++) { 1031 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1032 if (m_possible[state][event]) { 1033 int count = m_counters[state][event]; 1034 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 1035 if (count == 0) { 1036 out << " <-- "; 1037 } 1038 out << endl; 1039 } 1040 } 1041 out << endl; 1042 } 1043} 1044''') 1045 code.write(path, "%s_Profiler.cc" % self.ident) 1046 1047 # ************************** 1048 # ******* HTML Files ******* 1049 # ************************** 1050 def frameRef(self, click_href, click_target, over_href, over_target_num, 1051 text): 1052 code = code_formatter(fix_newlines=False) 1053 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""") 1054 return str(code) 1055 1056 def writeHTMLFiles(self, path): 1057 # Create table with no row hilighted 1058 self.printHTMLTransitions(path, None) 1059 1060 # Generate transition tables 1061 for state in self.states.itervalues(): 1062 self.printHTMLTransitions(path, state) 1063 1064 # Generate action descriptions 1065 for action in self.actions.itervalues(): 1066 name = "%s_action_%s.html" % (self.ident, action.ident) 1067 code = html.createSymbol(action, "Action") 1068 code.write(path, name) 1069 1070 # Generate state descriptions 1071 for state in self.states.itervalues(): 1072 name = "%s_State_%s.html" % (self.ident, state.ident) 1073 code = html.createSymbol(state, "State") 1074 code.write(path, name) 1075 1076 # Generate event descriptions 1077 for event in self.events.itervalues(): 1078 name = "%s_Event_%s.html" % (self.ident, event.ident) 1079 code = html.createSymbol(event, "Event") 1080 code.write(path, name) 1081 1082 def printHTMLTransitions(self, path, active_state): 1083 code = code_formatter() 1084 1085 code(''' 1086<HTML><BODY link="blue" vlink="blue"> 1087 1088<H1 align="center">${{html.formatShorthand(self.short)}}: 1089''') 1090 code.indent() 1091 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1092 mid = machine.ident 1093 if i != 0: 1094 extra = " - " 1095 else: 1096 extra = "" 1097 if machine == self: 1098 code('$extra$mid') 1099 else: 1100 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1101 code.dedent() 1102 1103 code(""" 1104</H1> 1105 1106<TABLE border=1> 1107<TR> 1108 <TH> </TH> 1109""") 1110 1111 for event in self.events.itervalues(): 1112 href = "%s_Event_%s.html" % (self.ident, event.ident) 1113 ref = self.frameRef(href, "Status", href, "1", event.short) 1114 code('<TH bgcolor=white>$ref</TH>') 1115 1116 code('</TR>') 1117 # -- Body of table 1118 for state in self.states.itervalues(): 1119 # -- Each row 1120 if state == active_state: 1121 color = "yellow" 1122 else: 1123 color = "white" 1124 1125 click = "%s_table_%s.html" % (self.ident, state.ident) 1126 over = "%s_State_%s.html" % (self.ident, state.ident) 1127 text = html.formatShorthand(state.short) 1128 ref = self.frameRef(click, "Table", over, "1", state.short) 1129 code(''' 1130<TR> 1131 <TH bgcolor=$color>$ref</TH> 1132''') 1133 1134 # -- One column for each event 1135 for event in self.events.itervalues(): 1136 trans = self.table.get((state,event), None) 1137 if trans is None: 1138 # This is the no transition case 1139 if state == active_state: 1140 color = "#C0C000" 1141 else: 1142 color = "lightgrey" 1143 1144 code('<TD bgcolor=$color> </TD>') 1145 continue 1146 1147 next = trans.nextState 1148 stall_action = False 1149 1150 # -- Get the actions 1151 for action in trans.actions: 1152 if action.ident == "z_stall" or \ 1153 action.ident == "zz_recycleMandatoryQueue": 1154 stall_action = True 1155 1156 # -- Print out "actions/next-state" 1157 if stall_action: 1158 if state == active_state: 1159 color = "#C0C000" 1160 else: 1161 color = "lightgrey" 1162 1163 elif active_state and next.ident == active_state.ident: 1164 color = "aqua" 1165 elif state == active_state: 1166 color = "yellow" 1167 else: 1168 color = "white" 1169 1170 fix = code.nofix() 1171 code('<TD bgcolor=$color>') 1172 for action in trans.actions: 1173 href = "%s_action_%s.html" % (self.ident, action.ident) 1174 ref = self.frameRef(href, "Status", href, "1", 1175 action.short) 1176 code(' $ref\n') 1177 if next != state: 1178 if trans.actions: 1179 code('/') 1180 click = "%s_table_%s.html" % (self.ident, next.ident) 1181 over = "%s_State_%s.html" % (self.ident, next.ident) 1182 ref = self.frameRef(click, "Table", over, "1", next.short) 1183 code("$ref") 1184 code("</TD>\n") 1185 code.fix(fix) 1186 1187 # -- Each row 1188 if state == active_state: 1189 color = "yellow" 1190 else: 1191 color = "white" 1192 1193 click = "%s_table_%s.html" % (self.ident, state.ident) 1194 over = "%s_State_%s.html" % (self.ident, state.ident) 1195 ref = self.frameRef(click, "Table", over, "1", state.short) 1196 code(''' 1197 <TH bgcolor=$color>$ref</TH> 1198</TR> 1199''') 1200 code(''' 1201<TR> 1202 <TH> </TH> 1203''') 1204 1205 for event in self.events.itervalues(): 1206 href = "%s_Event_%s.html" % (self.ident, event.ident) 1207 ref = self.frameRef(href, "Status", href, "1", event.short) 1208 code('<TH bgcolor=white>$ref</TH>') 1209 code(''' 1210</TR> 1211</TABLE> 1212</BODY></HTML> 1213''') 1214 1215 1216 if active_state: 1217 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1218 else: 1219 name = "%s_table.html" % self.ident 1220 code.write(path, name) 1221 1222__all__ = [ "StateMachine" ]
| 347 code.dedent() 348 code.dedent() 349 code(''' 350 } 351 352 m_net_ptr = net_ptr; 353 m_machineID.type = MachineType_${ident}; 354 m_machineID.num = m_version; 355 for (size_t i = 0; i < argv.size(); i += 2) { 356 if (argv[i] != "version") 357 m_cfg[argv[i]] = argv[i+1]; 358 } 359 360 // Objects 361 s_profiler.setVersion(m_version); 362''') 363 364 code.indent() 365 for var in self.objects: 366 vtype = var.type 367 vid = "m_%s_ptr" % var.c_ident 368 if "network" not in var: 369 # Not a network port object 370 if "primitive" in vtype: 371 code('$vid = new ${{vtype.c_ident}};') 372 if "default" in var: 373 code('(*$vid) = ${{var["default"]}};') 374 else: 375 # Normal Object 376 # added by SS 377 if "factory" in var: 378 code('$vid = ${{var["factory"]}};') 379 elif var.ident.find("mandatoryQueue") < 0: 380 th = var.get("template_hack", "") 381 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 382 383 args = "" 384 if "non_obj" not in vtype and not vtype.isEnumeration: 385 if expr.find("TBETable") >= 0: 386 args = "m_number_of_TBEs" 387 else: 388 args = var.get("constructor_hack", "") 389 args = "(%s)" % args 390 391 code('$expr$args;') 392 else: 393 code(';') 394 395 code('assert($vid != NULL);') 396 397 if "default" in var: 398 code('(*$vid) = ${{var["default"]}}; // Object default') 399 elif "default" in vtype: 400 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 401 402 # Set ordering 403 if "ordered" in var and "trigger_queue" not in var: 404 # A buffer 405 code('$vid->setOrdering(${{var["ordered"]}});') 406 407 # Set randomization 408 if "random" in var: 409 # A buffer 410 code('$vid->setRandomization(${{var["random"]}});') 411 412 # Set Priority 413 if vtype.isBuffer and \ 414 "rank" in var and "trigger_queue" not in var: 415 code('$vid->setPriority(${{var["rank"]}});') 416 else: 417 # Network port object 418 network = var["network"] 419 ordered = var["ordered"] 420 vnet = var["virtual_network"] 421 422 assert var.machine is not None 423 code(''' 424$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 425''') 426 427 code('assert($vid != NULL);') 428 429 # Set ordering 430 if "ordered" in var: 431 # A buffer 432 code('$vid->setOrdering(${{var["ordered"]}});') 433 434 # Set randomization 435 if "random" in var: 436 # A buffer 437 code('$vid->setRandomization(${{var["random"]}})') 438 439 # Set Priority 440 if "rank" in var: 441 code('$vid->setPriority(${{var["rank"]}})') 442 443 # Set buffer size 444 if vtype.isBuffer: 445 code(''' 446if (m_buffer_size > 0) { 447 $vid->setSize(m_buffer_size); 448} 449''') 450 451 # set description (may be overriden later by port def) 452 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 453 454 # Set the queue consumers 455 code.insert_newline() 456 for port in self.in_ports: 457 code('${{port.code}}.setConsumer(this);') 458 459 # Set the queue descriptions 460 code.insert_newline() 461 for port in self.in_ports: 462 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 463 464 # Initialize the transition profiling 465 code.insert_newline() 466 for trans in self.transitions: 467 # Figure out if we stall 468 stall = False 469 for action in trans.actions: 470 if action.ident == "z_stall": 471 stall = True 472 473 # Only possible if it is not a 'z' case 474 if not stall: 475 state = "%s_State_%s" % (self.ident, trans.state.ident) 476 event = "%s_Event_%s" % (self.ident, trans.event.ident) 477 code('s_profiler.possibleTransition($state, $event);') 478 479 # added by SS to initialize recycle_latency of message buffers 480 for buf in self.message_buffer_names: 481 code("$buf->setRecycleLatency(m_recycle_latency);") 482 483 code.dedent() 484 code('}') 485 486 has_mandatory_q = False 487 for port in self.in_ports: 488 if port.code.find("mandatoryQueue_ptr") >= 0: 489 has_mandatory_q = True 490 491 if has_mandatory_q: 492 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 493 else: 494 mq_ident = "NULL" 495 496 code(''' 497int $c_ident::getNumControllers() { 498 return m_num_controllers; 499} 500 501MessageBuffer* $c_ident::getMandatoryQueue() const { 502 return $mq_ident; 503} 504 505const int & $c_ident::getVersion() const{ 506 return m_version; 507} 508 509const string $c_ident::toString() const{ 510 return "$c_ident"; 511} 512 513const string $c_ident::getName() const{ 514 return m_name; 515} 516const MachineType $c_ident::getMachineType() const{ 517 return MachineType_${ident}; 518} 519 520void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 521 522void $c_ident::printConfig(ostream& out) const { 523 out << "$c_ident config: " << m_name << endl; 524 out << " version: " << m_version << endl; 525 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 526 out << " " << (*it).first << ": " << (*it).second << endl; 527 } 528} 529 530// Actions 531''') 532 533 for action in self.actions.itervalues(): 534 if "c_code" not in action: 535 continue 536 537 code(''' 538/** \\brief ${{action.desc}} */ 539void $c_ident::${{action.ident}}(const Address& addr) 540{ 541 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 542 ${{action["c_code"]}} 543} 544 545''') 546 code.write(path, "%s.cc" % c_ident) 547 548 def printCWakeup(self, path): 549 '''Output the wakeup loop for the events''' 550 551 code = code_formatter() 552 ident = self.ident 553 554 code(''' 555// Auto generated C++ code started by $__file__:$__line__ 556// ${ident}: ${{self.short}} 557 558#include "mem/ruby/common/Global.hh" 559#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 560#include "mem/protocol/${ident}_Controller.hh" 561#include "mem/protocol/${ident}_State.hh" 562#include "mem/protocol/${ident}_Event.hh" 563#include "mem/protocol/Types.hh" 564#include "mem/ruby/system/System.hh" 565 566void ${ident}_Controller::wakeup() 567{ 568 569 int counter = 0; 570 while (true) { 571 // Some cases will put us into an infinite loop without this limit 572 assert(counter <= m_transitions_per_cycle); 573 if (counter == m_transitions_per_cycle) { 574 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 575 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 576 break; 577 } 578''') 579 580 code.indent() 581 code.indent() 582 583 # InPorts 584 # 585 # Find the position of the mandatory queue in the vector so 586 # that we can print it out first 587 588 mandatory_q = None 589 if self.ident == "L1Cache": 590 for i,port in enumerate(self.in_ports): 591 assert "c_code_in_port" in port 592 if str(port).find("mandatoryQueue_in") >= 0: 593 assert mandatory_q is None 594 mandatory_q = port 595 596 assert mandatory_q is not None 597 598 # print out the mandatory queue here 599 port = mandatory_q 600 code('// ${ident}InPort $port') 601 output = port["c_code_in_port"] 602 603 pos = output.find("TransitionResult result = doTransition((L1Cache_mandatory_request_type_to_event(((*in_msg_ptr)).m_Type)), L1Cache_getState(addr), addr);") 604 assert pos >= 0 605 atomics_string = ''' 606if ((((*in_msg_ptr)).m_Type) == CacheRequestType_ATOMIC) { 607 if (servicing_atomic == 0) { 608 if (locked_read_request1 == Address(-1)) { 609 assert(read_counter == 0); 610 locked_read_request1 = addr; 611 assert(read_counter == 0); 612 read_counter++; 613 } 614 else if (addr == locked_read_request1) { 615 ; // do nothing 616 } 617 else { 618 assert(0); // should never be here if servicing one request at a time 619 } 620 } 621 else if (!started_receiving_writes) { 622 if (servicing_atomic == 1) { 623 if (locked_read_request2 == Address(-1)) { 624 assert(locked_read_request1 != Address(-1)); 625 assert(read_counter == 1); 626 locked_read_request2 = addr; 627 assert(read_counter == 1); 628 read_counter++; 629 } 630 else if (addr == locked_read_request2) { 631 ; // do nothing 632 } 633 else { 634 assert(0); // should never be here if servicing one request at a time 635 } 636 } 637 else if (servicing_atomic == 2) { 638 if (locked_read_request3 == Address(-1)) { 639 assert(locked_read_request1 != Address(-1)); 640 assert(locked_read_request2 != Address(-1)); 641 assert(read_counter == 1); 642 locked_read_request3 = addr; 643 assert(read_counter == 2); 644 read_counter++; 645 } 646 else if (addr == locked_read_request3) { 647 ; // do nothing 648 } 649 else { 650 assert(0); // should never be here if servicing one request at a time 651 } 652 } 653 else if (servicing_atomic == 3) { 654 if (locked_read_request4 == Address(-1)) { 655 assert(locked_read_request1 != Address(-1)); 656 assert(locked_read_request2 != Address(-1)); 657 assert(locked_read_request3 != Address(-1)); 658 assert(read_counter == 1); 659 locked_read_request4 = addr; 660 assert(read_counter == 3); 661 read_counter++; 662 } 663 else if (addr == locked_read_request4) { 664 ; // do nothing 665 } 666 else { 667 assert(0); // should never be here if servicing one request at a time 668 } 669 } 670 else { 671 assert(0); 672 } 673 } 674} 675else { 676 if (servicing_atomic > 0) { 677 // reset 678 servicing_atomic = 0; 679 read_counter = 0; 680 started_receiving_writes = false; 681 locked_read_request1 = Address(-1); 682 locked_read_request2 = Address(-1); 683 locked_read_request3 = Address(-1); 684 locked_read_request4 = Address(-1); 685 } 686} 687''' 688 689 output = output[:pos] + atomics_string + output[pos:] 690 code('$output') 691 692 for port in self.in_ports: 693 # don't print out mandatory queue twice 694 if port == mandatory_q: 695 continue 696 697 if ident == "L1Cache": 698 if str(port).find("forwardRequestNetwork_in") >= 0: 699 code(''' 700bool postpone = false; 701if ((((*m_L1Cache_forwardToCache_ptr)).isReady())) { 702 const RequestMsg* in_msg_ptr; 703 in_msg_ptr = dynamic_cast<const RequestMsg*>(((*m_L1Cache_forwardToCache_ptr)).peek()); 704 if ((((servicing_atomic == 1) && (locked_read_request1 == ((*in_msg_ptr)).m_Address)) || 705 ((servicing_atomic == 2) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address)) || 706 ((servicing_atomic == 3) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address)) || 707 ((servicing_atomic == 4) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address || locked_read_request1 == ((*in_msg_ptr)).m_Address)))) { 708 postpone = true; 709 } 710} 711if (!postpone) { 712''') 713 code.indent() 714 code('// ${ident}InPort $port') 715 code('${{port["c_code_in_port"]}}') 716 code.dedent() 717 718 if ident == "L1Cache": 719 if str(port).find("forwardRequestNetwork_in") >= 0: 720 code.dedent() 721 code('}') 722 code.indent() 723 code('') 724 725 code.dedent() 726 code.dedent() 727 code(''' 728 break; // If we got this far, we have nothing left todo 729 } 730} 731''') 732 733 if self.ident == "L1Cache": 734 code(''' 735void ${ident}_Controller::set_atomic(Address addr) 736{ 737 servicing_atomic++; 738} 739 740void ${ident}_Controller::started_writes() 741{ 742 started_receiving_writes = true; 743} 744 745void ${ident}_Controller::clear_atomic() 746{ 747 assert(servicing_atomic > 0); 748 read_counter--; 749 servicing_atomic--; 750 if (read_counter == 0) { 751 servicing_atomic = 0; 752 started_receiving_writes = false; 753 locked_read_request1 = Address(-1); 754 locked_read_request2 = Address(-1); 755 locked_read_request3 = Address(-1); 756 locked_read_request4 = Address(-1); 757 } 758} 759''') 760 else: 761 code(''' 762void ${ident}_Controller::started_writes() 763{ 764 assert(0); 765} 766 767void ${ident}_Controller::set_atomic(Address addr) 768{ 769 assert(0); 770} 771 772void ${ident}_Controller::clear_atomic() 773{ 774 assert(0); 775} 776''') 777 778 779 code.write(path, "%s_Wakeup.cc" % self.ident) 780 781 def printCSwitch(self, path): 782 '''Output switch statement for transition table''' 783 784 code = code_formatter() 785 ident = self.ident 786 787 code(''' 788// Auto generated C++ code started by $__file__:$__line__ 789// ${ident}: ${{self.short}} 790 791#include "mem/ruby/common/Global.hh" 792#include "mem/protocol/${ident}_Controller.hh" 793#include "mem/protocol/${ident}_State.hh" 794#include "mem/protocol/${ident}_Event.hh" 795#include "mem/protocol/Types.hh" 796#include "mem/ruby/system/System.hh" 797 798#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 799 800#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 801#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 802 803TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 804) 805{ 806 ${ident}_State next_state = state; 807 808 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 809 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 810 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 811 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 812 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 813 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 814 815 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 816 817 if (result == TransitionResult_Valid) { 818 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 819 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 820 s_profiler.countTransition(state, event); 821 if (Debug::getProtocolTrace()) { 822 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 823 ${ident}_State_to_string(state), 824 ${ident}_Event_to_string(event), 825 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 826 } 827 CLEAR_TRANSITION_COMMENT(); 828 ${ident}_setState(addr, next_state); 829 830 } else if (result == TransitionResult_ResourceStall) { 831 if (Debug::getProtocolTrace()) { 832 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 833 ${ident}_State_to_string(state), 834 ${ident}_Event_to_string(event), 835 ${ident}_State_to_string(next_state), 836 "Resource Stall"); 837 } 838 } else if (result == TransitionResult_ProtocolStall) { 839 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 840 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 841 if (Debug::getProtocolTrace()) { 842 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 843 ${ident}_State_to_string(state), 844 ${ident}_Event_to_string(event), 845 ${ident}_State_to_string(next_state), 846 "Protocol Stall"); 847 } 848 } 849 850 return result; 851} 852 853TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 854) 855{ 856 switch(HASH_FUN(state, event)) { 857''') 858 859 # This map will allow suppress generating duplicate code 860 cases = orderdict() 861 862 for trans in self.transitions: 863 case_string = "%s_State_%s, %s_Event_%s" % \ 864 (self.ident, trans.state.ident, self.ident, trans.event.ident) 865 866 case = code_formatter() 867 # Only set next_state if it changes 868 if trans.state != trans.nextState: 869 ns_ident = trans.nextState.ident 870 case('next_state = ${ident}_State_${ns_ident};') 871 872 actions = trans.actions 873 874 # Check for resources 875 case_sorter = [] 876 res = trans.resources 877 for key,val in res.iteritems(): 878 if key.type.ident != "DNUCAStopTable": 879 val = ''' 880if (!%s.areNSlotsAvailable(%s)) { 881 return TransitionResult_ResourceStall; 882} 883''' % (key.code, val) 884 case_sorter.append(val) 885 886 887 # Emit the code sequences in a sorted order. This makes the 888 # output deterministic (without this the output order can vary 889 # since Map's keys() on a vector of pointers is not deterministic 890 for c in sorted(case_sorter): 891 case("$c") 892 893 # Figure out if we stall 894 stall = False 895 for action in actions: 896 if action.ident == "z_stall": 897 stall = True 898 break 899 900 if stall: 901 case('return TransitionResult_ProtocolStall;') 902 else: 903 for action in actions: 904 case('${{action.ident}}(addr);') 905 case('return TransitionResult_Valid;') 906 907 case = str(case) 908 909 # Look to see if this transition code is unique. 910 if case not in cases: 911 cases[case] = [] 912 913 cases[case].append(case_string) 914 915 # Walk through all of the unique code blocks and spit out the 916 # corresponding case statement elements 917 for case,transitions in cases.iteritems(): 918 # Iterative over all the multiple transitions that share 919 # the same code 920 for trans in transitions: 921 code(' case HASH_FUN($trans):') 922 code(' {') 923 code(' $case') 924 code(' }') 925 926 code(''' 927 default: 928 WARN_EXPR(m_version); 929 WARN_EXPR(g_eventQueue_ptr->getTime()); 930 WARN_EXPR(addr); 931 WARN_EXPR(event); 932 WARN_EXPR(state); 933 ERROR_MSG(\"Invalid transition\"); 934 } 935 return TransitionResult_Valid; 936} 937''') 938 code.write(path, "%s_Transitions.cc" % self.ident) 939 940 def printProfilerHH(self, path): 941 code = code_formatter() 942 ident = self.ident 943 944 code(''' 945// Auto generated C++ code started by $__file__:$__line__ 946// ${ident}: ${{self.short}} 947 948#ifndef ${ident}_PROFILER_H 949#define ${ident}_PROFILER_H 950 951#include "mem/ruby/common/Global.hh" 952#include "mem/protocol/${ident}_State.hh" 953#include "mem/protocol/${ident}_Event.hh" 954 955class ${ident}_Profiler { 956 public: 957 ${ident}_Profiler(); 958 void setVersion(int version); 959 void countTransition(${ident}_State state, ${ident}_Event event); 960 void possibleTransition(${ident}_State state, ${ident}_Event event); 961 void dumpStats(ostream& out) const; 962 void clearStats(); 963 964 private: 965 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 966 int m_event_counters[${ident}_Event_NUM]; 967 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 968 int m_version; 969}; 970 971#endif // ${ident}_PROFILER_H 972''') 973 code.write(path, "%s_Profiler.hh" % self.ident) 974 975 def printProfilerCC(self, path): 976 code = code_formatter() 977 ident = self.ident 978 979 code(''' 980// Auto generated C++ code started by $__file__:$__line__ 981// ${ident}: ${{self.short}} 982 983#include "mem/protocol/${ident}_Profiler.hh" 984 985${ident}_Profiler::${ident}_Profiler() 986{ 987 for (int state = 0; state < ${ident}_State_NUM; state++) { 988 for (int event = 0; event < ${ident}_Event_NUM; event++) { 989 m_possible[state][event] = false; 990 m_counters[state][event] = 0; 991 } 992 } 993 for (int event = 0; event < ${ident}_Event_NUM; event++) { 994 m_event_counters[event] = 0; 995 } 996} 997void ${ident}_Profiler::setVersion(int version) 998{ 999 m_version = version; 1000} 1001void ${ident}_Profiler::clearStats() 1002{ 1003 for (int state = 0; state < ${ident}_State_NUM; state++) { 1004 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1005 m_counters[state][event] = 0; 1006 } 1007 } 1008 1009 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1010 m_event_counters[event] = 0; 1011 } 1012} 1013void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1014{ 1015 assert(m_possible[state][event]); 1016 m_counters[state][event]++; 1017 m_event_counters[event]++; 1018} 1019void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 1020{ 1021 m_possible[state][event] = true; 1022} 1023void ${ident}_Profiler::dumpStats(ostream& out) const 1024{ 1025 out << " --- ${ident} " << m_version << " ---" << endl; 1026 out << " - Event Counts -" << endl; 1027 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1028 int count = m_event_counters[event]; 1029 out << (${ident}_Event) event << " " << count << endl; 1030 } 1031 out << endl; 1032 out << " - Transitions -" << endl; 1033 for (int state = 0; state < ${ident}_State_NUM; state++) { 1034 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1035 if (m_possible[state][event]) { 1036 int count = m_counters[state][event]; 1037 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 1038 if (count == 0) { 1039 out << " <-- "; 1040 } 1041 out << endl; 1042 } 1043 } 1044 out << endl; 1045 } 1046} 1047''') 1048 code.write(path, "%s_Profiler.cc" % self.ident) 1049 1050 # ************************** 1051 # ******* HTML Files ******* 1052 # ************************** 1053 def frameRef(self, click_href, click_target, over_href, over_target_num, 1054 text): 1055 code = code_formatter(fix_newlines=False) 1056 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""") 1057 return str(code) 1058 1059 def writeHTMLFiles(self, path): 1060 # Create table with no row hilighted 1061 self.printHTMLTransitions(path, None) 1062 1063 # Generate transition tables 1064 for state in self.states.itervalues(): 1065 self.printHTMLTransitions(path, state) 1066 1067 # Generate action descriptions 1068 for action in self.actions.itervalues(): 1069 name = "%s_action_%s.html" % (self.ident, action.ident) 1070 code = html.createSymbol(action, "Action") 1071 code.write(path, name) 1072 1073 # Generate state descriptions 1074 for state in self.states.itervalues(): 1075 name = "%s_State_%s.html" % (self.ident, state.ident) 1076 code = html.createSymbol(state, "State") 1077 code.write(path, name) 1078 1079 # Generate event descriptions 1080 for event in self.events.itervalues(): 1081 name = "%s_Event_%s.html" % (self.ident, event.ident) 1082 code = html.createSymbol(event, "Event") 1083 code.write(path, name) 1084 1085 def printHTMLTransitions(self, path, active_state): 1086 code = code_formatter() 1087 1088 code(''' 1089<HTML><BODY link="blue" vlink="blue"> 1090 1091<H1 align="center">${{html.formatShorthand(self.short)}}: 1092''') 1093 code.indent() 1094 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1095 mid = machine.ident 1096 if i != 0: 1097 extra = " - " 1098 else: 1099 extra = "" 1100 if machine == self: 1101 code('$extra$mid') 1102 else: 1103 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1104 code.dedent() 1105 1106 code(""" 1107</H1> 1108 1109<TABLE border=1> 1110<TR> 1111 <TH> </TH> 1112""") 1113 1114 for event in self.events.itervalues(): 1115 href = "%s_Event_%s.html" % (self.ident, event.ident) 1116 ref = self.frameRef(href, "Status", href, "1", event.short) 1117 code('<TH bgcolor=white>$ref</TH>') 1118 1119 code('</TR>') 1120 # -- Body of table 1121 for state in self.states.itervalues(): 1122 # -- Each row 1123 if state == active_state: 1124 color = "yellow" 1125 else: 1126 color = "white" 1127 1128 click = "%s_table_%s.html" % (self.ident, state.ident) 1129 over = "%s_State_%s.html" % (self.ident, state.ident) 1130 text = html.formatShorthand(state.short) 1131 ref = self.frameRef(click, "Table", over, "1", state.short) 1132 code(''' 1133<TR> 1134 <TH bgcolor=$color>$ref</TH> 1135''') 1136 1137 # -- One column for each event 1138 for event in self.events.itervalues(): 1139 trans = self.table.get((state,event), None) 1140 if trans is None: 1141 # This is the no transition case 1142 if state == active_state: 1143 color = "#C0C000" 1144 else: 1145 color = "lightgrey" 1146 1147 code('<TD bgcolor=$color> </TD>') 1148 continue 1149 1150 next = trans.nextState 1151 stall_action = False 1152 1153 # -- Get the actions 1154 for action in trans.actions: 1155 if action.ident == "z_stall" or \ 1156 action.ident == "zz_recycleMandatoryQueue": 1157 stall_action = True 1158 1159 # -- Print out "actions/next-state" 1160 if stall_action: 1161 if state == active_state: 1162 color = "#C0C000" 1163 else: 1164 color = "lightgrey" 1165 1166 elif active_state and next.ident == active_state.ident: 1167 color = "aqua" 1168 elif state == active_state: 1169 color = "yellow" 1170 else: 1171 color = "white" 1172 1173 fix = code.nofix() 1174 code('<TD bgcolor=$color>') 1175 for action in trans.actions: 1176 href = "%s_action_%s.html" % (self.ident, action.ident) 1177 ref = self.frameRef(href, "Status", href, "1", 1178 action.short) 1179 code(' $ref\n') 1180 if next != state: 1181 if trans.actions: 1182 code('/') 1183 click = "%s_table_%s.html" % (self.ident, next.ident) 1184 over = "%s_State_%s.html" % (self.ident, next.ident) 1185 ref = self.frameRef(click, "Table", over, "1", next.short) 1186 code("$ref") 1187 code("</TD>\n") 1188 code.fix(fix) 1189 1190 # -- Each row 1191 if state == active_state: 1192 color = "yellow" 1193 else: 1194 color = "white" 1195 1196 click = "%s_table_%s.html" % (self.ident, state.ident) 1197 over = "%s_State_%s.html" % (self.ident, state.ident) 1198 ref = self.frameRef(click, "Table", over, "1", state.short) 1199 code(''' 1200 <TH bgcolor=$color>$ref</TH> 1201</TR> 1202''') 1203 code(''' 1204<TR> 1205 <TH> </TH> 1206''') 1207 1208 for event in self.events.itervalues(): 1209 href = "%s_Event_%s.html" % (self.ident, event.ident) 1210 ref = self.frameRef(href, "Status", href, "1", event.short) 1211 code('<TH bgcolor=white>$ref</TH>') 1212 code(''' 1213</TR> 1214</TABLE> 1215</BODY></HTML> 1216''') 1217 1218 1219 if active_state: 1220 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1221 else: 1222 name = "%s_table.html" % self.ident 1223 code.write(path, name) 1224 1225__all__ = [ "StateMachine" ]
|