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