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