StateMachine.py revision 6882:898047a3672c
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 34python_class_map = {"int": "Int", 35 "string": "String", 36 "bool": "Bool", 37 "CacheMemory": "RubyCache", 38 "Sequencer": "RubySequencer", 39 "DirectoryMemory": "RubyDirectoryMemory", 40 "MemoryControl": "RubyMemoryControl", 41 } 42 43class StateMachine(Symbol): 44 def __init__(self, symtab, ident, location, pairs, config_parameters): 45 super(StateMachine, self).__init__(symtab, ident, location, pairs) 46 self.table = None 47 self.config_parameters = config_parameters 48 for param in config_parameters: 49 if param.pointer: 50 var = Var(symtab, param.name, location, param.type_ast.type, 51 "(*m_%s_ptr)" % param.name, {}, self) 52 else: 53 var = Var(symtab, param.name, location, param.type_ast.type, 54 "m_%s" % param.name, {}, self) 55 self.symtab.registerSym(param.name, var) 56 57 self.states = orderdict() 58 self.events = orderdict() 59 self.actions = orderdict() 60 self.transitions = [] 61 self.in_ports = [] 62 self.functions = [] 63 self.objects = [] 64 65 self.message_buffer_names = [] 66 67 def __repr__(self): 68 return "[StateMachine: %s]" % self.ident 69 70 def addState(self, state): 71 assert self.table is None 72 self.states[state.ident] = state 73 74 def addEvent(self, event): 75 assert self.table is None 76 self.events[event.ident] = event 77 78 def addAction(self, action): 79 assert self.table is None 80 81 # Check for duplicate action 82 for other in self.actions.itervalues(): 83 if action.ident == other.ident: 84 action.warning("Duplicate action definition: %s" % action.ident) 85 action.error("Duplicate action definition: %s" % action.ident) 86 if action.short == other.short: 87 other.warning("Duplicate action shorthand: %s" % other.ident) 88 other.warning(" shorthand = %s" % other.short) 89 action.warning("Duplicate action shorthand: %s" % action.ident) 90 action.error(" shorthand = %s" % action.short) 91 92 self.actions[action.ident] = action 93 94 def addTransition(self, trans): 95 assert self.table is None 96 self.transitions.append(trans) 97 98 def addInPort(self, var): 99 self.in_ports.append(var) 100 101 def addFunc(self, func): 102 # register func in the symbol table 103 self.symtab.registerSym(str(func), func) 104 self.functions.append(func) 105 106 def addObject(self, obj): 107 self.objects.append(obj) 108 109 # Needs to be called before accessing the table 110 def buildTable(self): 111 assert self.table is None 112 113 table = {} 114 115 for trans in self.transitions: 116 # Track which actions we touch so we know if we use them 117 # all -- really this should be done for all symbols as 118 # part of the symbol table, then only trigger it for 119 # Actions, States, Events, etc. 120 121 for action in trans.actions: 122 action.used = True 123 124 index = (trans.state, trans.event) 125 if index in table: 126 table[index].warning("Duplicate transition: %s" % table[index]) 127 trans.error("Duplicate transition: %s" % trans) 128 table[index] = trans 129 130 # Look at all actions to make sure we used them all 131 for action in self.actions.itervalues(): 132 if not action.used: 133 error_msg = "Unused action: %s" % action.ident 134 if "desc" in action: 135 error_msg += ", " + action.desc 136 action.warning(error_msg) 137 self.table = table 138 139 def writeCodeFiles(self, path): 140 self.printControllerPython(path) 141 self.printControllerHH(path) 142 self.printControllerCC(path) 143 self.printCSwitch(path) 144 self.printCWakeup(path) 145 self.printProfilerCC(path) 146 self.printProfilerHH(path) 147 148 for func in self.functions: 149 func.writeCodeFiles(path) 150 151 def printControllerPython(self, path): 152 code = code_formatter() 153 ident = self.ident 154 py_ident = "%s_Controller" % ident 155 c_ident = "%s_Controller" % self.ident 156 code(''' 157from m5.params import * 158from m5.SimObject import SimObject 159from Controller import RubyController 160 161class $py_ident(RubyController): 162 type = '$py_ident' 163''') 164 code.indent() 165 for param in self.config_parameters: 166 dflt_str = '' 167 if param.default is not None: 168 dflt_str = str(param.default) + ', ' 169 if python_class_map.has_key(param.type_ast.type.c_ident): 170 python_type = python_class_map[param.type_ast.type.c_ident] 171 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 172 else: 173 self.error("Unknown c++ to python class conversion for c++ " \ 174 "type: '%s'. Please update the python_class_map " \ 175 "in StateMachine.py", param.type_ast.type.c_ident) 176 code.dedent() 177 code.write(path, '%s.py' % py_ident) 178 179 180 def printControllerHH(self, path): 181 '''Output the method declarations for the class declaration''' 182 code = code_formatter() 183 ident = self.ident 184 c_ident = "%s_Controller" % self.ident 185 186 self.message_buffer_names = [] 187 188 code(''' 189/** \\file $ident.hh 190 * 191 * Auto generated C++ code started by $__file__:$__line__ 192 * Created by slicc definition of Module "${{self.short}}" 193 */ 194 195#ifndef ${ident}_CONTROLLER_H 196#define ${ident}_CONTROLLER_H 197 198#include "params/$c_ident.hh" 199 200#include "mem/ruby/common/Global.hh" 201#include "mem/ruby/common/Consumer.hh" 202#include "mem/ruby/slicc_interface/AbstractController.hh" 203#include "mem/protocol/TransitionResult.hh" 204#include "mem/protocol/Types.hh" 205#include "mem/protocol/${ident}_Profiler.hh" 206''') 207 208 seen_types = set() 209 for var in self.objects: 210 if var.type.ident not in seen_types and not var.type.isPrimitive: 211 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 212 seen_types.add(var.type.ident) 213 214 # for adding information to the protocol debug trace 215 code(''' 216extern stringstream ${ident}_transitionComment; 217 218class $c_ident : public AbstractController { 219#ifdef CHECK_COHERENCE 220#endif /* CHECK_COHERENCE */ 221public: 222 typedef ${c_ident}Params Params; 223 $c_ident(const Params *p); 224 static int getNumControllers(); 225 void init(); 226 MessageBuffer* getMandatoryQueue() const; 227 const int & getVersion() const; 228 const string toString() const; 229 const string getName() const; 230 const MachineType getMachineType() const; 231 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 232 void print(ostream& out) const; 233 void printConfig(ostream& out) const; 234 void wakeup(); 235 void printStats(ostream& out) const { s_profiler.dumpStats(out); } 236 void clearStats() { s_profiler.clearStats(); } 237 void blockOnQueue(Address addr, MessageBuffer* port); 238 void unblock(Address addr); 239private: 240''') 241 242 code.indent() 243 # added by SS 244 for param in self.config_parameters: 245 if param.pointer: 246 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 247 else: 248 code('${{param.type_ast.type}} m_${{param.ident}};') 249 250 code(''' 251int m_number_of_TBEs; 252 253TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc 254TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc 255string m_name; 256int m_transitions_per_cycle; 257int m_buffer_size; 258int m_recycle_latency; 259map< string, string > m_cfg; 260NodeID m_version; 261Network* m_net_ptr; 262MachineID m_machineID; 263bool m_is_blocking; 264map< Address, MessageBuffer* > m_block_map; 265${ident}_Profiler s_profiler; 266static int m_num_controllers; 267// Internal functions 268''') 269 270 for func in self.functions: 271 proto = func.prototype 272 if proto: 273 code('$proto') 274 275 code(''' 276 277// Actions 278''') 279 for action in self.actions.itervalues(): 280 code('/** \\brief ${{action.desc}} */') 281 code('void ${{action.ident}}(const Address& addr);') 282 283 # the controller internal variables 284 code(''' 285 286// Object 287''') 288 for var in self.objects: 289 th = var.get("template_hack", "") 290 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 291 292 if var.type.ident == "MessageBuffer": 293 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 294 295 code.dedent() 296 code('};') 297 code('#endif // ${ident}_CONTROLLER_H') 298 code.write(path, '%s.hh' % c_ident) 299 300 def printControllerCC(self, path): 301 '''Output the actions for performing the actions''' 302 303 code = code_formatter() 304 ident = self.ident 305 c_ident = "%s_Controller" % self.ident 306 307 code(''' 308/** \\file $ident.cc 309 * 310 * Auto generated C++ code started by $__file__:$__line__ 311 * Created by slicc definition of Module "${{self.short}}" 312 */ 313 314#include "mem/ruby/common/Global.hh" 315#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 316#include "mem/protocol/${ident}_Controller.hh" 317#include "mem/protocol/${ident}_State.hh" 318#include "mem/protocol/${ident}_Event.hh" 319#include "mem/protocol/Types.hh" 320#include "mem/ruby/system/System.hh" 321''') 322 323 # include object classes 324 seen_types = set() 325 for var in self.objects: 326 if var.type.ident not in seen_types and not var.type.isPrimitive: 327 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 328 seen_types.add(var.type.ident) 329 330 code(''' 331$c_ident * 332${c_ident}Params::create() 333{ 334 return new $c_ident(this); 335} 336 337 338int $c_ident::m_num_controllers = 0; 339 340stringstream ${ident}_transitionComment; 341#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 342/** \\brief constructor */ 343$c_ident::$c_ident(const Params *p) 344 : AbstractController(p) 345{ 346 m_version = p->version; 347 m_transitions_per_cycle = p->transitions_per_cycle; 348 m_buffer_size = p->buffer_size; 349 m_recycle_latency = p->recycle_latency; 350 m_number_of_TBEs = p->number_of_TBEs; 351''') 352 code.indent() 353 354 # 355 # After initializing the universal machine parameters, initialize the 356 # this machines config parameters. Also detemine if these configuration 357 # params include a sequencer. This information will be used later for 358 # contecting the sequencer back to the L1 cache controller. 359 # 360 contains_sequencer = False 361 for param in self.config_parameters: 362 if param.name == "sequencer": 363 contains_sequencer = True 364 if param.pointer: 365 code('m_${{param.name}}_ptr = p->${{param.name}};') 366 else: 367 code('m_${{param.name}} = p->${{param.name}};') 368 369 # 370 # For the l1 cache controller, add the special atomic support which 371 # includes passing the sequencer a pointer to the controller. 372 # 373 if self.ident == "L1Cache": 374 if not contains_sequencer: 375 self.error("The L1Cache controller must include the sequencer " \ 376 "configuration parameter") 377 378 code(''' 379m_sequencer_ptr->setController(this); 380''') 381 382 code('m_num_controllers++;') 383 for var in self.objects: 384 if var.ident.find("mandatoryQueue") >= 0: 385 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 386 387 code.dedent() 388 code(''' 389} 390 391void $c_ident::init() 392{ 393 m_machineID.type = MachineType_${ident}; 394 m_machineID.num = m_version; 395 396 // Objects 397 s_profiler.setVersion(m_version); 398''') 399 400 code.indent() 401 for var in self.objects: 402 vtype = var.type 403 vid = "m_%s_ptr" % var.c_ident 404 if "network" not in var: 405 # Not a network port object 406 if "primitive" in vtype: 407 code('$vid = new ${{vtype.c_ident}};') 408 if "default" in var: 409 code('(*$vid) = ${{var["default"]}};') 410 else: 411 # Normal Object 412 # added by SS 413 if "factory" in var: 414 code('$vid = ${{var["factory"]}};') 415 elif var.ident.find("mandatoryQueue") < 0: 416 th = var.get("template_hack", "") 417 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 418 419 args = "" 420 if "non_obj" not in vtype and not vtype.isEnumeration: 421 if expr.find("TBETable") >= 0: 422 args = "m_number_of_TBEs" 423 else: 424 args = var.get("constructor_hack", "") 425 args = "(%s)" % args 426 427 code('$expr$args;') 428 else: 429 code(';') 430 431 code('assert($vid != NULL);') 432 433 if "default" in var: 434 code('(*$vid) = ${{var["default"]}}; // Object default') 435 elif "default" in vtype: 436 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 437 438 # Set ordering 439 if "ordered" in var and "trigger_queue" not in var: 440 # A buffer 441 code('$vid->setOrdering(${{var["ordered"]}});') 442 443 # Set randomization 444 if "random" in var: 445 # A buffer 446 code('$vid->setRandomization(${{var["random"]}});') 447 448 # Set Priority 449 if vtype.isBuffer and \ 450 "rank" in var and "trigger_queue" not in var: 451 code('$vid->setPriority(${{var["rank"]}});') 452 else: 453 # Network port object 454 network = var["network"] 455 ordered = var["ordered"] 456 vnet = var["virtual_network"] 457 458 assert var.machine is not None 459 code(''' 460$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 461''') 462 463 code('assert($vid != NULL);') 464 465 # Set ordering 466 if "ordered" in var: 467 # A buffer 468 code('$vid->setOrdering(${{var["ordered"]}});') 469 470 # Set randomization 471 if "random" in var: 472 # A buffer 473 code('$vid->setRandomization(${{var["random"]}})') 474 475 # Set Priority 476 if "rank" in var: 477 code('$vid->setPriority(${{var["rank"]}})') 478 479 # Set buffer size 480 if vtype.isBuffer: 481 code(''' 482if (m_buffer_size > 0) { 483 $vid->setSize(m_buffer_size); 484} 485''') 486 487 # set description (may be overriden later by port def) 488 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 489 490 # Set the queue consumers 491 code.insert_newline() 492 for port in self.in_ports: 493 code('${{port.code}}.setConsumer(this);') 494 495 # Set the queue descriptions 496 code.insert_newline() 497 for port in self.in_ports: 498 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 499 500 # Initialize the transition profiling 501 code.insert_newline() 502 for trans in self.transitions: 503 # Figure out if we stall 504 stall = False 505 for action in trans.actions: 506 if action.ident == "z_stall": 507 stall = True 508 509 # Only possible if it is not a 'z' case 510 if not stall: 511 state = "%s_State_%s" % (self.ident, trans.state.ident) 512 event = "%s_Event_%s" % (self.ident, trans.event.ident) 513 code('s_profiler.possibleTransition($state, $event);') 514 515 # added by SS to initialize recycle_latency of message buffers 516 for buf in self.message_buffer_names: 517 code("$buf->setRecycleLatency(m_recycle_latency);") 518 519 code.dedent() 520 code('}') 521 522 has_mandatory_q = False 523 for port in self.in_ports: 524 if port.code.find("mandatoryQueue_ptr") >= 0: 525 has_mandatory_q = True 526 527 if has_mandatory_q: 528 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 529 else: 530 mq_ident = "NULL" 531 532 code(''' 533int $c_ident::getNumControllers() { 534 return m_num_controllers; 535} 536 537MessageBuffer* $c_ident::getMandatoryQueue() const { 538 return $mq_ident; 539} 540 541const int & $c_ident::getVersion() const{ 542 return m_version; 543} 544 545const string $c_ident::toString() const{ 546 return "$c_ident"; 547} 548 549const string $c_ident::getName() const{ 550 return m_name; 551} 552const MachineType $c_ident::getMachineType() const{ 553 return MachineType_${ident}; 554} 555 556void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) { 557 m_is_blocking = true; 558 m_block_map[addr] = port; 559} 560void $c_ident::unblock(Address addr) { 561 m_block_map.erase(addr); 562 if (m_block_map.size() == 0) { 563 m_is_blocking = false; 564 } 565} 566 567void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 568 569void $c_ident::printConfig(ostream& out) const { 570 out << "$c_ident config: " << m_name << endl; 571 out << " version: " << m_version << endl; 572 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 573 out << " " << (*it).first << ": " << (*it).second << endl; 574 } 575} 576 577// Actions 578''') 579 580 for action in self.actions.itervalues(): 581 if "c_code" not in action: 582 continue 583 584 code(''' 585/** \\brief ${{action.desc}} */ 586void $c_ident::${{action.ident}}(const Address& addr) 587{ 588 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 589 ${{action["c_code"]}} 590} 591 592''') 593 code.write(path, "%s.cc" % c_ident) 594 595 def printCWakeup(self, path): 596 '''Output the wakeup loop for the events''' 597 598 code = code_formatter() 599 ident = self.ident 600 601 code(''' 602// Auto generated C++ code started by $__file__:$__line__ 603// ${ident}: ${{self.short}} 604 605#include "mem/ruby/common/Global.hh" 606#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 607#include "mem/protocol/${ident}_Controller.hh" 608#include "mem/protocol/${ident}_State.hh" 609#include "mem/protocol/${ident}_Event.hh" 610#include "mem/protocol/Types.hh" 611#include "mem/ruby/system/System.hh" 612 613void ${ident}_Controller::wakeup() 614{ 615 616 int counter = 0; 617 while (true) { 618 // Some cases will put us into an infinite loop without this limit 619 assert(counter <= m_transitions_per_cycle); 620 if (counter == m_transitions_per_cycle) { 621 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 622 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 623 break; 624 } 625''') 626 627 code.indent() 628 code.indent() 629 630 # InPorts 631 # 632 for port in self.in_ports: 633 code.indent() 634 code('// ${ident}InPort $port') 635 code('${{port["c_code_in_port"]}}') 636 code.dedent() 637 638 code('') 639 640 code.dedent() 641 code.dedent() 642 code(''' 643 break; // If we got this far, we have nothing left todo 644 } 645} 646''') 647 648 code.write(path, "%s_Wakeup.cc" % self.ident) 649 650 def printCSwitch(self, path): 651 '''Output switch statement for transition table''' 652 653 code = code_formatter() 654 ident = self.ident 655 656 code(''' 657// Auto generated C++ code started by $__file__:$__line__ 658// ${ident}: ${{self.short}} 659 660#include "mem/ruby/common/Global.hh" 661#include "mem/protocol/${ident}_Controller.hh" 662#include "mem/protocol/${ident}_State.hh" 663#include "mem/protocol/${ident}_Event.hh" 664#include "mem/protocol/Types.hh" 665#include "mem/ruby/system/System.hh" 666 667#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 668 669#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 670#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 671 672TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 673) 674{ 675 ${ident}_State next_state = state; 676 677 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 678 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 679 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 680 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 681 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 682 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 683 684 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 685 686 if (result == TransitionResult_Valid) { 687 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 688 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 689 s_profiler.countTransition(state, event); 690 if (Debug::getProtocolTrace()) { 691 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 692 ${ident}_State_to_string(state), 693 ${ident}_Event_to_string(event), 694 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 695 } 696 CLEAR_TRANSITION_COMMENT(); 697 ${ident}_setState(addr, next_state); 698 699 } else if (result == TransitionResult_ResourceStall) { 700 if (Debug::getProtocolTrace()) { 701 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 702 ${ident}_State_to_string(state), 703 ${ident}_Event_to_string(event), 704 ${ident}_State_to_string(next_state), 705 "Resource Stall"); 706 } 707 } else if (result == TransitionResult_ProtocolStall) { 708 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 709 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 710 if (Debug::getProtocolTrace()) { 711 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 712 ${ident}_State_to_string(state), 713 ${ident}_Event_to_string(event), 714 ${ident}_State_to_string(next_state), 715 "Protocol Stall"); 716 } 717 } 718 719 return result; 720} 721 722TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 723) 724{ 725 switch(HASH_FUN(state, event)) { 726''') 727 728 # This map will allow suppress generating duplicate code 729 cases = orderdict() 730 731 for trans in self.transitions: 732 case_string = "%s_State_%s, %s_Event_%s" % \ 733 (self.ident, trans.state.ident, self.ident, trans.event.ident) 734 735 case = code_formatter() 736 # Only set next_state if it changes 737 if trans.state != trans.nextState: 738 ns_ident = trans.nextState.ident 739 case('next_state = ${ident}_State_${ns_ident};') 740 741 actions = trans.actions 742 743 # Check for resources 744 case_sorter = [] 745 res = trans.resources 746 for key,val in res.iteritems(): 747 if key.type.ident != "DNUCAStopTable": 748 val = ''' 749if (!%s.areNSlotsAvailable(%s)) { 750 return TransitionResult_ResourceStall; 751} 752''' % (key.code, val) 753 case_sorter.append(val) 754 755 756 # Emit the code sequences in a sorted order. This makes the 757 # output deterministic (without this the output order can vary 758 # since Map's keys() on a vector of pointers is not deterministic 759 for c in sorted(case_sorter): 760 case("$c") 761 762 # Figure out if we stall 763 stall = False 764 for action in actions: 765 if action.ident == "z_stall": 766 stall = True 767 break 768 769 if stall: 770 case('return TransitionResult_ProtocolStall;') 771 else: 772 for action in actions: 773 case('${{action.ident}}(addr);') 774 case('return TransitionResult_Valid;') 775 776 case = str(case) 777 778 # Look to see if this transition code is unique. 779 if case not in cases: 780 cases[case] = [] 781 782 cases[case].append(case_string) 783 784 # Walk through all of the unique code blocks and spit out the 785 # corresponding case statement elements 786 for case,transitions in cases.iteritems(): 787 # Iterative over all the multiple transitions that share 788 # the same code 789 for trans in transitions: 790 code(' case HASH_FUN($trans):') 791 code(' {') 792 code(' $case') 793 code(' }') 794 795 code(''' 796 default: 797 WARN_EXPR(m_version); 798 WARN_EXPR(g_eventQueue_ptr->getTime()); 799 WARN_EXPR(addr); 800 WARN_EXPR(event); 801 WARN_EXPR(state); 802 ERROR_MSG(\"Invalid transition\"); 803 } 804 return TransitionResult_Valid; 805} 806''') 807 code.write(path, "%s_Transitions.cc" % self.ident) 808 809 def printProfilerHH(self, path): 810 code = code_formatter() 811 ident = self.ident 812 813 code(''' 814// Auto generated C++ code started by $__file__:$__line__ 815// ${ident}: ${{self.short}} 816 817#ifndef ${ident}_PROFILER_H 818#define ${ident}_PROFILER_H 819 820#include "mem/ruby/common/Global.hh" 821#include "mem/protocol/${ident}_State.hh" 822#include "mem/protocol/${ident}_Event.hh" 823 824class ${ident}_Profiler { 825 public: 826 ${ident}_Profiler(); 827 void setVersion(int version); 828 void countTransition(${ident}_State state, ${ident}_Event event); 829 void possibleTransition(${ident}_State state, ${ident}_Event event); 830 void dumpStats(ostream& out) const; 831 void clearStats(); 832 833 private: 834 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 835 int m_event_counters[${ident}_Event_NUM]; 836 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 837 int m_version; 838}; 839 840#endif // ${ident}_PROFILER_H 841''') 842 code.write(path, "%s_Profiler.hh" % self.ident) 843 844 def printProfilerCC(self, path): 845 code = code_formatter() 846 ident = self.ident 847 848 code(''' 849// Auto generated C++ code started by $__file__:$__line__ 850// ${ident}: ${{self.short}} 851 852#include "mem/protocol/${ident}_Profiler.hh" 853 854${ident}_Profiler::${ident}_Profiler() 855{ 856 for (int state = 0; state < ${ident}_State_NUM; state++) { 857 for (int event = 0; event < ${ident}_Event_NUM; event++) { 858 m_possible[state][event] = false; 859 m_counters[state][event] = 0; 860 } 861 } 862 for (int event = 0; event < ${ident}_Event_NUM; event++) { 863 m_event_counters[event] = 0; 864 } 865} 866void ${ident}_Profiler::setVersion(int version) 867{ 868 m_version = version; 869} 870void ${ident}_Profiler::clearStats() 871{ 872 for (int state = 0; state < ${ident}_State_NUM; state++) { 873 for (int event = 0; event < ${ident}_Event_NUM; event++) { 874 m_counters[state][event] = 0; 875 } 876 } 877 878 for (int event = 0; event < ${ident}_Event_NUM; event++) { 879 m_event_counters[event] = 0; 880 } 881} 882void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 883{ 884 assert(m_possible[state][event]); 885 m_counters[state][event]++; 886 m_event_counters[event]++; 887} 888void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 889{ 890 m_possible[state][event] = true; 891} 892void ${ident}_Profiler::dumpStats(ostream& out) const 893{ 894 out << " --- ${ident} " << m_version << " ---" << endl; 895 out << " - Event Counts -" << endl; 896 for (int event = 0; event < ${ident}_Event_NUM; event++) { 897 int count = m_event_counters[event]; 898 out << (${ident}_Event) event << " " << count << endl; 899 } 900 out << endl; 901 out << " - Transitions -" << endl; 902 for (int state = 0; state < ${ident}_State_NUM; state++) { 903 for (int event = 0; event < ${ident}_Event_NUM; event++) { 904 if (m_possible[state][event]) { 905 int count = m_counters[state][event]; 906 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 907 if (count == 0) { 908 out << " <-- "; 909 } 910 out << endl; 911 } 912 } 913 out << endl; 914 } 915} 916''') 917 code.write(path, "%s_Profiler.cc" % self.ident) 918 919 # ************************** 920 # ******* HTML Files ******* 921 # ************************** 922 def frameRef(self, click_href, click_target, over_href, over_target_num, 923 text): 924 code = code_formatter(fix_newlines=False) 925 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>""") 926 return str(code) 927 928 def writeHTMLFiles(self, path): 929 # Create table with no row hilighted 930 self.printHTMLTransitions(path, None) 931 932 # Generate transition tables 933 for state in self.states.itervalues(): 934 self.printHTMLTransitions(path, state) 935 936 # Generate action descriptions 937 for action in self.actions.itervalues(): 938 name = "%s_action_%s.html" % (self.ident, action.ident) 939 code = html.createSymbol(action, "Action") 940 code.write(path, name) 941 942 # Generate state descriptions 943 for state in self.states.itervalues(): 944 name = "%s_State_%s.html" % (self.ident, state.ident) 945 code = html.createSymbol(state, "State") 946 code.write(path, name) 947 948 # Generate event descriptions 949 for event in self.events.itervalues(): 950 name = "%s_Event_%s.html" % (self.ident, event.ident) 951 code = html.createSymbol(event, "Event") 952 code.write(path, name) 953 954 def printHTMLTransitions(self, path, active_state): 955 code = code_formatter() 956 957 code(''' 958<HTML><BODY link="blue" vlink="blue"> 959 960<H1 align="center">${{html.formatShorthand(self.short)}}: 961''') 962 code.indent() 963 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 964 mid = machine.ident 965 if i != 0: 966 extra = " - " 967 else: 968 extra = "" 969 if machine == self: 970 code('$extra$mid') 971 else: 972 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 973 code.dedent() 974 975 code(""" 976</H1> 977 978<TABLE border=1> 979<TR> 980 <TH> </TH> 981""") 982 983 for event in self.events.itervalues(): 984 href = "%s_Event_%s.html" % (self.ident, event.ident) 985 ref = self.frameRef(href, "Status", href, "1", event.short) 986 code('<TH bgcolor=white>$ref</TH>') 987 988 code('</TR>') 989 # -- Body of table 990 for state in self.states.itervalues(): 991 # -- Each row 992 if state == active_state: 993 color = "yellow" 994 else: 995 color = "white" 996 997 click = "%s_table_%s.html" % (self.ident, state.ident) 998 over = "%s_State_%s.html" % (self.ident, state.ident) 999 text = html.formatShorthand(state.short) 1000 ref = self.frameRef(click, "Table", over, "1", state.short) 1001 code(''' 1002<TR> 1003 <TH bgcolor=$color>$ref</TH> 1004''') 1005 1006 # -- One column for each event 1007 for event in self.events.itervalues(): 1008 trans = self.table.get((state,event), None) 1009 if trans is None: 1010 # This is the no transition case 1011 if state == active_state: 1012 color = "#C0C000" 1013 else: 1014 color = "lightgrey" 1015 1016 code('<TD bgcolor=$color> </TD>') 1017 continue 1018 1019 next = trans.nextState 1020 stall_action = False 1021 1022 # -- Get the actions 1023 for action in trans.actions: 1024 if action.ident == "z_stall" or \ 1025 action.ident == "zz_recycleMandatoryQueue": 1026 stall_action = True 1027 1028 # -- Print out "actions/next-state" 1029 if stall_action: 1030 if state == active_state: 1031 color = "#C0C000" 1032 else: 1033 color = "lightgrey" 1034 1035 elif active_state and next.ident == active_state.ident: 1036 color = "aqua" 1037 elif state == active_state: 1038 color = "yellow" 1039 else: 1040 color = "white" 1041 1042 fix = code.nofix() 1043 code('<TD bgcolor=$color>') 1044 for action in trans.actions: 1045 href = "%s_action_%s.html" % (self.ident, action.ident) 1046 ref = self.frameRef(href, "Status", href, "1", 1047 action.short) 1048 code(' $ref\n') 1049 if next != state: 1050 if trans.actions: 1051 code('/') 1052 click = "%s_table_%s.html" % (self.ident, next.ident) 1053 over = "%s_State_%s.html" % (self.ident, next.ident) 1054 ref = self.frameRef(click, "Table", over, "1", next.short) 1055 code("$ref") 1056 code("</TD>\n") 1057 code.fix(fix) 1058 1059 # -- Each row 1060 if state == active_state: 1061 color = "yellow" 1062 else: 1063 color = "white" 1064 1065 click = "%s_table_%s.html" % (self.ident, state.ident) 1066 over = "%s_State_%s.html" % (self.ident, state.ident) 1067 ref = self.frameRef(click, "Table", over, "1", state.short) 1068 code(''' 1069 <TH bgcolor=$color>$ref</TH> 1070</TR> 1071''') 1072 code(''' 1073<TR> 1074 <TH> </TH> 1075''') 1076 1077 for event in self.events.itervalues(): 1078 href = "%s_Event_%s.html" % (self.ident, event.ident) 1079 ref = self.frameRef(href, "Status", href, "1", event.short) 1080 code('<TH bgcolor=white>$ref</TH>') 1081 code(''' 1082</TR> 1083</TABLE> 1084</BODY></HTML> 1085''') 1086 1087 1088 if active_state: 1089 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1090 else: 1091 name = "%s_table.html" % self.ident 1092 code.write(path, name) 1093 1094__all__ = [ "StateMachine" ] 1095