StateMachine.py revision 11308
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# Copyright (c) 2013 Advanced Micro Devices, Inc. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer; 10# redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution; 13# neither the name of the copyright holders nor the names of its 14# contributors may be used to endorse or promote products derived from 15# this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29from m5.util import orderdict 30 31from slicc.symbols.Symbol import Symbol 32from slicc.symbols.Var import Var 33import slicc.generate.html as html 34import re 35 36python_class_map = { 37 "int": "Int", 38 "NodeID": "Int", 39 "uint32_t" : "UInt32", 40 "std::string": "String", 41 "bool": "Bool", 42 "CacheMemory": "RubyCache", 43 "WireBuffer": "RubyWireBuffer", 44 "Sequencer": "RubySequencer", 45 "GPUCoalescer" : "RubyGPUCoalescer", 46 "VIPERCoalescer" : "VIPERCoalescer", 47 "DirectoryMemory": "RubyDirectoryMemory", 48 "PerfectCacheMemory": "RubyPerfectCacheMemory", 49 "MemoryControl": "MemoryControl", 50 "MessageBuffer": "MessageBuffer", 51 "DMASequencer": "DMASequencer", 52 "Prefetcher":"Prefetcher", 53 "Cycles":"Cycles", 54 } 55 56class StateMachine(Symbol): 57 def __init__(self, symtab, ident, location, pairs, config_parameters): 58 super(StateMachine, self).__init__(symtab, ident, location, pairs) 59 self.table = None 60 61 # Data members in the State Machine that have been declared before 62 # the opening brace '{' of the machine. Note that these along with 63 # the members in self.objects form the entire set of data members. 64 self.config_parameters = config_parameters 65 66 self.prefetchers = [] 67 68 for param in config_parameters: 69 if param.pointer: 70 var = Var(symtab, param.ident, location, param.type_ast.type, 71 "(*m_%s_ptr)" % param.ident, {}, self) 72 else: 73 var = Var(symtab, param.ident, location, param.type_ast.type, 74 "m_%s" % param.ident, {}, self) 75 76 self.symtab.registerSym(param.ident, var) 77 78 if str(param.type_ast.type) == "Prefetcher": 79 self.prefetchers.append(var) 80 81 self.states = orderdict() 82 self.events = orderdict() 83 self.actions = orderdict() 84 self.request_types = orderdict() 85 self.transitions = [] 86 self.in_ports = [] 87 self.functions = [] 88 89 # Data members in the State Machine that have been declared inside 90 # the {} machine. Note that these along with the config params 91 # form the entire set of data members of the machine. 92 self.objects = [] 93 self.TBEType = None 94 self.EntryType = None 95 self.debug_flags = set() 96 self.debug_flags.add('RubyGenerated') 97 self.debug_flags.add('RubySlicc') 98 99 def __repr__(self): 100 return "[StateMachine: %s]" % self.ident 101 102 def addState(self, state): 103 assert self.table is None 104 self.states[state.ident] = state 105 106 def addEvent(self, event): 107 assert self.table is None 108 self.events[event.ident] = event 109 110 def addAction(self, action): 111 assert self.table is None 112 113 # Check for duplicate action 114 for other in self.actions.itervalues(): 115 if action.ident == other.ident: 116 action.warning("Duplicate action definition: %s" % action.ident) 117 action.error("Duplicate action definition: %s" % action.ident) 118 if action.short == other.short: 119 other.warning("Duplicate action shorthand: %s" % other.ident) 120 other.warning(" shorthand = %s" % other.short) 121 action.warning("Duplicate action shorthand: %s" % action.ident) 122 action.error(" shorthand = %s" % action.short) 123 124 self.actions[action.ident] = action 125 126 def addDebugFlag(self, flag): 127 self.debug_flags.add(flag) 128 129 def addRequestType(self, request_type): 130 assert self.table is None 131 self.request_types[request_type.ident] = request_type 132 133 def addTransition(self, trans): 134 assert self.table is None 135 self.transitions.append(trans) 136 137 def addInPort(self, var): 138 self.in_ports.append(var) 139 140 def addFunc(self, func): 141 # register func in the symbol table 142 self.symtab.registerSym(str(func), func) 143 self.functions.append(func) 144 145 def addObject(self, obj): 146 self.symtab.registerSym(str(obj), obj) 147 self.objects.append(obj) 148 149 def addType(self, type): 150 type_ident = '%s' % type.c_ident 151 152 if type_ident == "%s_TBE" %self.ident: 153 if self.TBEType != None: 154 self.error("Multiple Transaction Buffer types in a " \ 155 "single machine."); 156 self.TBEType = type 157 158 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 159 if "main" in type and "false" == type["main"].lower(): 160 pass # this isn't the EntryType 161 else: 162 if self.EntryType != None: 163 self.error("Multiple AbstractCacheEntry types in a " \ 164 "single machine."); 165 self.EntryType = type 166 167 # Needs to be called before accessing the table 168 def buildTable(self): 169 assert self.table is None 170 171 table = {} 172 173 for trans in self.transitions: 174 # Track which actions we touch so we know if we use them 175 # all -- really this should be done for all symbols as 176 # part of the symbol table, then only trigger it for 177 # Actions, States, Events, etc. 178 179 for action in trans.actions: 180 action.used = True 181 182 index = (trans.state, trans.event) 183 if index in table: 184 table[index].warning("Duplicate transition: %s" % table[index]) 185 trans.error("Duplicate transition: %s" % trans) 186 table[index] = trans 187 188 # Look at all actions to make sure we used them all 189 for action in self.actions.itervalues(): 190 if not action.used: 191 error_msg = "Unused action: %s" % action.ident 192 if "desc" in action: 193 error_msg += ", " + action.desc 194 action.warning(error_msg) 195 self.table = table 196 197 # determine the port->msg buffer mappings 198 def getBufferMaps(self, ident): 199 msg_bufs = [] 200 port_to_buf_map = {} 201 in_msg_bufs = {} 202 for port in self.in_ports: 203 buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name 204 msg_bufs.append(buf_name) 205 port_to_buf_map[port] = msg_bufs.index(buf_name) 206 if buf_name not in in_msg_bufs: 207 in_msg_bufs[buf_name] = [port] 208 else: 209 in_msg_bufs[buf_name].append(port) 210 return port_to_buf_map, in_msg_bufs, msg_bufs 211 212 def writeCodeFiles(self, path, includes): 213 self.printControllerPython(path) 214 self.printControllerHH(path) 215 self.printControllerCC(path, includes) 216 self.printCSwitch(path) 217 self.printCWakeup(path, includes) 218 219 def printControllerPython(self, path): 220 code = self.symtab.codeFormatter() 221 ident = self.ident 222 223 py_ident = "%s_Controller" % ident 224 c_ident = "%s_Controller" % self.ident 225 226 code(''' 227from m5.params import * 228from m5.SimObject import SimObject 229from Controller import RubyController 230 231class $py_ident(RubyController): 232 type = '$py_ident' 233 cxx_header = 'mem/protocol/${c_ident}.hh' 234''') 235 code.indent() 236 for param in self.config_parameters: 237 dflt_str = '' 238 239 if param.rvalue is not None: 240 dflt_str = str(param.rvalue.inline()) + ', ' 241 242 if python_class_map.has_key(param.type_ast.type.c_ident): 243 python_type = python_class_map[param.type_ast.type.c_ident] 244 code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 245 246 else: 247 self.error("Unknown c++ to python class conversion for c++ " \ 248 "type: '%s'. Please update the python_class_map " \ 249 "in StateMachine.py", param.type_ast.type.c_ident) 250 251 code.dedent() 252 code.write(path, '%s.py' % py_ident) 253 254 255 def printControllerHH(self, path): 256 '''Output the method declarations for the class declaration''' 257 code = self.symtab.codeFormatter() 258 ident = self.ident 259 c_ident = "%s_Controller" % self.ident 260 261 code(''' 262/** \\file $c_ident.hh 263 * 264 * Auto generated C++ code started by $__file__:$__line__ 265 * Created by slicc definition of Module "${{self.short}}" 266 */ 267 268#ifndef __${ident}_CONTROLLER_HH__ 269#define __${ident}_CONTROLLER_HH__ 270 271#include <iostream> 272#include <sstream> 273#include <string> 274 275#include "mem/protocol/TransitionResult.hh" 276#include "mem/protocol/Types.hh" 277#include "mem/ruby/common/Consumer.hh" 278#include "mem/ruby/slicc_interface/AbstractController.hh" 279#include "params/$c_ident.hh" 280 281''') 282 283 seen_types = set() 284 for var in self.objects: 285 if var.type.ident not in seen_types and not var.type.isPrimitive: 286 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 287 seen_types.add(var.type.ident) 288 289 # for adding information to the protocol debug trace 290 code(''' 291extern std::stringstream ${ident}_transitionComment; 292 293class $c_ident : public AbstractController 294{ 295 public: 296 typedef ${c_ident}Params Params; 297 $c_ident(const Params *p); 298 static int getNumControllers(); 299 void init(); 300 301 MessageBuffer *getMandatoryQueue() const; 302 MessageBuffer *getMemoryQueue() const; 303 void initNetQueues(); 304 305 void print(std::ostream& out) const; 306 void wakeup(); 307 void resetStats(); 308 void regStats(); 309 void collateStats(); 310 311 void recordCacheTrace(int cntrl, CacheRecorder* tr); 312 Sequencer* getCPUSequencer() const; 313 314 int functionalWriteBuffers(PacketPtr&); 315 316 void countTransition(${ident}_State state, ${ident}_Event event); 317 void possibleTransition(${ident}_State state, ${ident}_Event event); 318 uint64_t getEventCount(${ident}_Event event); 319 bool isPossible(${ident}_State state, ${ident}_Event event); 320 uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event); 321 322private: 323''') 324 325 code.indent() 326 # added by SS 327 for param in self.config_parameters: 328 if param.pointer: 329 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 330 else: 331 code('${{param.type_ast.type}} m_${{param.ident}};') 332 333 code(''' 334TransitionResult doTransition(${ident}_Event event, 335''') 336 337 if self.EntryType != None: 338 code(''' 339 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 340''') 341 if self.TBEType != None: 342 code(''' 343 ${{self.TBEType.c_ident}}* m_tbe_ptr, 344''') 345 346 code(''' 347 Addr addr); 348 349TransitionResult doTransitionWorker(${ident}_Event event, 350 ${ident}_State state, 351 ${ident}_State& next_state, 352''') 353 354 if self.TBEType != None: 355 code(''' 356 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 357''') 358 if self.EntryType != None: 359 code(''' 360 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 361''') 362 363 code(''' 364 Addr addr); 365 366int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 367int m_event_counters[${ident}_Event_NUM]; 368bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 369 370static std::vector<Stats::Vector *> eventVec; 371static std::vector<std::vector<Stats::Vector *> > transVec; 372static int m_num_controllers; 373 374// Internal functions 375''') 376 377 for func in self.functions: 378 proto = func.prototype 379 if proto: 380 code('$proto') 381 382 if self.EntryType != None: 383 code(''' 384 385// Set and Reset for cache_entry variable 386void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 387void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 388''') 389 390 if self.TBEType != None: 391 code(''' 392 393// Set and Reset for tbe variable 394void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 395void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 396''') 397 398 # Prototype the actions that the controller can take 399 code(''' 400 401// Actions 402''') 403 if self.TBEType != None and self.EntryType != None: 404 for action in self.actions.itervalues(): 405 code('/** \\brief ${{action.desc}} */') 406 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 407 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 408 'm_cache_entry_ptr, Addr addr);') 409 elif self.TBEType != None: 410 for action in self.actions.itervalues(): 411 code('/** \\brief ${{action.desc}} */') 412 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 413 'm_tbe_ptr, Addr addr);') 414 elif self.EntryType != None: 415 for action in self.actions.itervalues(): 416 code('/** \\brief ${{action.desc}} */') 417 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 418 'm_cache_entry_ptr, Addr addr);') 419 else: 420 for action in self.actions.itervalues(): 421 code('/** \\brief ${{action.desc}} */') 422 code('void ${{action.ident}}(Addr addr);') 423 424 # the controller internal variables 425 code(''' 426 427// Objects 428''') 429 for var in self.objects: 430 th = var.get("template", "") 431 code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 432 433 code.dedent() 434 code('};') 435 code('#endif // __${ident}_CONTROLLER_H__') 436 code.write(path, '%s.hh' % c_ident) 437 438 def printControllerCC(self, path, includes): 439 '''Output the actions for performing the actions''' 440 441 code = self.symtab.codeFormatter() 442 ident = self.ident 443 c_ident = "%s_Controller" % self.ident 444 445 code(''' 446/** \\file $c_ident.cc 447 * 448 * Auto generated C++ code started by $__file__:$__line__ 449 * Created by slicc definition of Module "${{self.short}}" 450 */ 451 452#include <sys/types.h> 453#include <unistd.h> 454 455#include <cassert> 456#include <sstream> 457#include <string> 458#include <typeinfo> 459 460#include "base/compiler.hh" 461#include "base/cprintf.hh" 462 463''') 464 for f in self.debug_flags: 465 code('#include "debug/${{f}}.hh"') 466 code(''' 467#include "mem/protocol/${ident}_Controller.hh" 468#include "mem/protocol/${ident}_Event.hh" 469#include "mem/protocol/${ident}_State.hh" 470#include "mem/protocol/Types.hh" 471#include "mem/ruby/system/RubySystem.hh" 472 473''') 474 for include_path in includes: 475 code('#include "${{include_path}}"') 476 477 code(''' 478 479using namespace std; 480''') 481 482 # include object classes 483 seen_types = set() 484 for var in self.objects: 485 if var.type.ident not in seen_types and not var.type.isPrimitive: 486 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 487 seen_types.add(var.type.ident) 488 489 num_in_ports = len(self.in_ports) 490 491 code(''' 492$c_ident * 493${c_ident}Params::create() 494{ 495 return new $c_ident(this); 496} 497 498int $c_ident::m_num_controllers = 0; 499std::vector<Stats::Vector *> $c_ident::eventVec; 500std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 501 502// for adding information to the protocol debug trace 503stringstream ${ident}_transitionComment; 504 505#ifndef NDEBUG 506#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 507#else 508#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 509#endif 510 511/** \\brief constructor */ 512$c_ident::$c_ident(const Params *p) 513 : AbstractController(p) 514{ 515 m_machineID.type = MachineType_${ident}; 516 m_machineID.num = m_version; 517 m_num_controllers++; 518 519 m_in_ports = $num_in_ports; 520''') 521 code.indent() 522 523 # 524 # After initializing the universal machine parameters, initialize the 525 # this machines config parameters. Also if these configuration params 526 # include a sequencer, connect the it to the controller. 527 # 528 for param in self.config_parameters: 529 if param.pointer: 530 code('m_${{param.ident}}_ptr = p->${{param.ident}};') 531 else: 532 code('m_${{param.ident}} = p->${{param.ident}};') 533 534 if re.compile("sequencer").search(param.ident) or \ 535 param.type_ast.type.c_ident == "GPUCoalescer" or \ 536 param.type_ast.type.c_ident == "VIPERCoalescer": 537 code(''' 538if (m_${{param.ident}}_ptr != NULL) { 539 m_${{param.ident}}_ptr->setController(this); 540} 541''') 542 543 code(''' 544 545for (int state = 0; state < ${ident}_State_NUM; state++) { 546 for (int event = 0; event < ${ident}_Event_NUM; event++) { 547 m_possible[state][event] = false; 548 m_counters[state][event] = 0; 549 } 550} 551for (int event = 0; event < ${ident}_Event_NUM; event++) { 552 m_event_counters[event] = 0; 553} 554''') 555 code.dedent() 556 code(''' 557} 558 559void 560$c_ident::initNetQueues() 561{ 562 MachineType machine_type = string_to_MachineType("${{self.ident}}"); 563 int base M5_VAR_USED = MachineType_base_number(machine_type); 564 565''') 566 code.indent() 567 568 # set for maintaining the vnet, direction pairs already seen for this 569 # machine. This map helps in implementing the check for avoiding 570 # multiple message buffers being mapped to the same vnet. 571 vnet_dir_set = set() 572 573 for var in self.config_parameters: 574 vid = "m_%s_ptr" % var.ident 575 if "network" in var: 576 vtype = var.type_ast.type 577 code('assert($vid != NULL);') 578 579 # Network port object 580 network = var["network"] 581 582 if "virtual_network" in var: 583 vnet = var["virtual_network"] 584 vnet_type = var["vnet_type"] 585 586 assert (vnet, network) not in vnet_dir_set 587 vnet_dir_set.add((vnet,network)) 588 589 code(''' 590m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 591 "$vnet_type", $vid); 592''') 593 # Set Priority 594 if "rank" in var: 595 code('$vid->setPriority(${{var["rank"]}})') 596 597 code.dedent() 598 code(''' 599} 600 601void 602$c_ident::init() 603{ 604 // initialize objects 605''') 606 607 code.indent() 608 609 for var in self.objects: 610 vtype = var.type 611 vid = "m_%s_ptr" % var.ident 612 if "network" not in var: 613 # Not a network port object 614 if "primitive" in vtype: 615 code('$vid = new ${{vtype.c_ident}};') 616 if "default" in var: 617 code('(*$vid) = ${{var["default"]}};') 618 else: 619 # Normal Object 620 th = var.get("template", "") 621 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 622 args = "" 623 if "non_obj" not in vtype and not vtype.isEnumeration: 624 args = var.get("constructor", "") 625 626 code('$expr($args);') 627 code('assert($vid != NULL);') 628 629 if "default" in var: 630 code('*$vid = ${{var["default"]}}; // Object default') 631 elif "default" in vtype: 632 comment = "Type %s default" % vtype.ident 633 code('*$vid = ${{vtype["default"]}}; // $comment') 634 635 # Set the prefetchers 636 code() 637 for prefetcher in self.prefetchers: 638 code('${{prefetcher.code}}.setController(this);') 639 640 code() 641 for port in self.in_ports: 642 # Set the queue consumers 643 code('${{port.code}}.setConsumer(this);') 644 645 # Initialize the transition profiling 646 code() 647 for trans in self.transitions: 648 # Figure out if we stall 649 stall = False 650 for action in trans.actions: 651 if action.ident == "z_stall": 652 stall = True 653 654 # Only possible if it is not a 'z' case 655 if not stall: 656 state = "%s_State_%s" % (self.ident, trans.state.ident) 657 event = "%s_Event_%s" % (self.ident, trans.event.ident) 658 code('possibleTransition($state, $event);') 659 660 code.dedent() 661 code(''' 662 AbstractController::init(); 663 resetStats(); 664} 665''') 666 667 mq_ident = "NULL" 668 for port in self.in_ports: 669 if port.code.find("mandatoryQueue_ptr") >= 0: 670 mq_ident = "m_mandatoryQueue_ptr" 671 672 memq_ident = "NULL" 673 for port in self.in_ports: 674 if port.code.find("responseFromMemory_ptr") >= 0: 675 memq_ident = "m_responseFromMemory_ptr" 676 677 seq_ident = "NULL" 678 for param in self.config_parameters: 679 if param.ident == "sequencer": 680 assert(param.pointer) 681 seq_ident = "m_%s_ptr" % param.ident 682 683 if seq_ident != "NULL": 684 code(''' 685Sequencer* 686$c_ident::getCPUSequencer() const 687{ 688 if (NULL != $seq_ident && $seq_ident->isCPUSequencer()) { 689 return $seq_ident; 690 } else { 691 return NULL; 692 } 693} 694''') 695 else: 696 code(''' 697 698Sequencer* 699$c_ident::getCPUSequencer() const 700{ 701 return NULL; 702} 703''') 704 705 code(''' 706 707void 708$c_ident::regStats() 709{ 710 AbstractController::regStats(); 711 712 if (m_version == 0) { 713 for (${ident}_Event event = ${ident}_Event_FIRST; 714 event < ${ident}_Event_NUM; ++event) { 715 Stats::Vector *t = new Stats::Vector(); 716 t->init(m_num_controllers); 717 t->name(params()->ruby_system->name() + ".${c_ident}." + 718 ${ident}_Event_to_string(event)); 719 t->flags(Stats::pdf | Stats::total | Stats::oneline | 720 Stats::nozero); 721 722 eventVec.push_back(t); 723 } 724 725 for (${ident}_State state = ${ident}_State_FIRST; 726 state < ${ident}_State_NUM; ++state) { 727 728 transVec.push_back(std::vector<Stats::Vector *>()); 729 730 for (${ident}_Event event = ${ident}_Event_FIRST; 731 event < ${ident}_Event_NUM; ++event) { 732 733 Stats::Vector *t = new Stats::Vector(); 734 t->init(m_num_controllers); 735 t->name(params()->ruby_system->name() + ".${c_ident}." + 736 ${ident}_State_to_string(state) + 737 "." + ${ident}_Event_to_string(event)); 738 739 t->flags(Stats::pdf | Stats::total | Stats::oneline | 740 Stats::nozero); 741 transVec[state].push_back(t); 742 } 743 } 744 } 745} 746 747void 748$c_ident::collateStats() 749{ 750 for (${ident}_Event event = ${ident}_Event_FIRST; 751 event < ${ident}_Event_NUM; ++event) { 752 for (unsigned int i = 0; i < m_num_controllers; ++i) { 753 RubySystem *rs = params()->ruby_system; 754 std::map<uint32_t, AbstractController *>::iterator it = 755 rs->m_abstract_controls[MachineType_${ident}].find(i); 756 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 757 (*eventVec[event])[i] = 758 (($c_ident *)(*it).second)->getEventCount(event); 759 } 760 } 761 762 for (${ident}_State state = ${ident}_State_FIRST; 763 state < ${ident}_State_NUM; ++state) { 764 765 for (${ident}_Event event = ${ident}_Event_FIRST; 766 event < ${ident}_Event_NUM; ++event) { 767 768 for (unsigned int i = 0; i < m_num_controllers; ++i) { 769 RubySystem *rs = params()->ruby_system; 770 std::map<uint32_t, AbstractController *>::iterator it = 771 rs->m_abstract_controls[MachineType_${ident}].find(i); 772 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 773 (*transVec[state][event])[i] = 774 (($c_ident *)(*it).second)->getTransitionCount(state, event); 775 } 776 } 777 } 778} 779 780void 781$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 782{ 783 assert(m_possible[state][event]); 784 m_counters[state][event]++; 785 m_event_counters[event]++; 786} 787void 788$c_ident::possibleTransition(${ident}_State state, 789 ${ident}_Event event) 790{ 791 m_possible[state][event] = true; 792} 793 794uint64_t 795$c_ident::getEventCount(${ident}_Event event) 796{ 797 return m_event_counters[event]; 798} 799 800bool 801$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 802{ 803 return m_possible[state][event]; 804} 805 806uint64_t 807$c_ident::getTransitionCount(${ident}_State state, 808 ${ident}_Event event) 809{ 810 return m_counters[state][event]; 811} 812 813int 814$c_ident::getNumControllers() 815{ 816 return m_num_controllers; 817} 818 819MessageBuffer* 820$c_ident::getMandatoryQueue() const 821{ 822 return $mq_ident; 823} 824 825MessageBuffer* 826$c_ident::getMemoryQueue() const 827{ 828 return $memq_ident; 829} 830 831void 832$c_ident::print(ostream& out) const 833{ 834 out << "[$c_ident " << m_version << "]"; 835} 836 837void $c_ident::resetStats() 838{ 839 for (int state = 0; state < ${ident}_State_NUM; state++) { 840 for (int event = 0; event < ${ident}_Event_NUM; event++) { 841 m_counters[state][event] = 0; 842 } 843 } 844 845 for (int event = 0; event < ${ident}_Event_NUM; event++) { 846 m_event_counters[event] = 0; 847 } 848 849 AbstractController::resetStats(); 850} 851''') 852 853 if self.EntryType != None: 854 code(''' 855 856// Set and Reset for cache_entry variable 857void 858$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 859{ 860 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 861} 862 863void 864$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 865{ 866 m_cache_entry_ptr = 0; 867} 868''') 869 870 if self.TBEType != None: 871 code(''' 872 873// Set and Reset for tbe variable 874void 875$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 876{ 877 m_tbe_ptr = m_new_tbe; 878} 879 880void 881$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 882{ 883 m_tbe_ptr = NULL; 884} 885''') 886 887 code(''' 888 889void 890$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 891{ 892''') 893 # 894 # Record cache contents for all associated caches. 895 # 896 code.indent() 897 for param in self.config_parameters: 898 if param.type_ast.type.ident == "CacheMemory": 899 assert(param.pointer) 900 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 901 902 code.dedent() 903 code(''' 904} 905 906// Actions 907''') 908 if self.TBEType != None and self.EntryType != None: 909 for action in self.actions.itervalues(): 910 if "c_code" not in action: 911 continue 912 913 code(''' 914/** \\brief ${{action.desc}} */ 915void 916$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 917{ 918 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 919 try { 920 ${{action["c_code"]}} 921 } catch (const RejectException & e) { 922 fatal("Error in action ${{ident}}:${{action.ident}}: " 923 "executed a peek statement with the wrong message " 924 "type specified. "); 925 } 926} 927 928''') 929 elif self.TBEType != None: 930 for action in self.actions.itervalues(): 931 if "c_code" not in action: 932 continue 933 934 code(''' 935/** \\brief ${{action.desc}} */ 936void 937$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 938{ 939 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 940 ${{action["c_code"]}} 941} 942 943''') 944 elif self.EntryType != None: 945 for action in self.actions.itervalues(): 946 if "c_code" not in action: 947 continue 948 949 code(''' 950/** \\brief ${{action.desc}} */ 951void 952$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 953{ 954 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 955 ${{action["c_code"]}} 956} 957 958''') 959 else: 960 for action in self.actions.itervalues(): 961 if "c_code" not in action: 962 continue 963 964 code(''' 965/** \\brief ${{action.desc}} */ 966void 967$c_ident::${{action.ident}}(Addr addr) 968{ 969 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 970 ${{action["c_code"]}} 971} 972 973''') 974 for func in self.functions: 975 code(func.generateCode()) 976 977 # Function for functional writes to messages buffered in the controller 978 code(''' 979int 980$c_ident::functionalWriteBuffers(PacketPtr& pkt) 981{ 982 int num_functional_writes = 0; 983''') 984 for var in self.objects: 985 vtype = var.type 986 if vtype.isBuffer: 987 vid = "m_%s_ptr" % var.ident 988 code('num_functional_writes += $vid->functionalWrite(pkt);') 989 990 for var in self.config_parameters: 991 vtype = var.type_ast.type 992 if vtype.isBuffer: 993 vid = "m_%s_ptr" % var.ident 994 code('num_functional_writes += $vid->functionalWrite(pkt);') 995 996 code(''' 997 return num_functional_writes; 998} 999''') 1000 1001 code.write(path, "%s.cc" % c_ident) 1002 1003 def printCWakeup(self, path, includes): 1004 '''Output the wakeup loop for the events''' 1005 1006 code = self.symtab.codeFormatter() 1007 ident = self.ident 1008 1009 outputRequest_types = True 1010 if len(self.request_types) == 0: 1011 outputRequest_types = False 1012 1013 code(''' 1014// Auto generated C++ code started by $__file__:$__line__ 1015// ${ident}: ${{self.short}} 1016 1017#include <sys/types.h> 1018#include <unistd.h> 1019 1020#include <cassert> 1021#include <typeinfo> 1022 1023#include "base/misc.hh" 1024 1025''') 1026 for f in self.debug_flags: 1027 code('#include "debug/${{f}}.hh"') 1028 code(''' 1029#include "mem/protocol/${ident}_Controller.hh" 1030#include "mem/protocol/${ident}_Event.hh" 1031#include "mem/protocol/${ident}_State.hh" 1032 1033''') 1034 1035 if outputRequest_types: 1036 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1037 1038 code(''' 1039#include "mem/protocol/Types.hh" 1040#include "mem/ruby/system/RubySystem.hh" 1041 1042''') 1043 1044 1045 for include_path in includes: 1046 code('#include "${{include_path}}"') 1047 1048 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1049 1050 code(''' 1051 1052using namespace std; 1053 1054void 1055${ident}_Controller::wakeup() 1056{ 1057 int counter = 0; 1058 while (true) { 1059 unsigned char rejected[${{len(msg_bufs)}}]; 1060 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1061 // Some cases will put us into an infinite loop without this limit 1062 assert(counter <= m_transitions_per_cycle); 1063 if (counter == m_transitions_per_cycle) { 1064 // Count how often we are fully utilized 1065 m_fully_busy_cycles++; 1066 1067 // Wakeup in another cycle and try again 1068 scheduleEvent(Cycles(1)); 1069 break; 1070 } 1071''') 1072 1073 code.indent() 1074 code.indent() 1075 1076 # InPorts 1077 # 1078 for port in self.in_ports: 1079 code.indent() 1080 code('// ${ident}InPort $port') 1081 if port.pairs.has_key("rank"): 1082 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1083 else: 1084 code('m_cur_in_port = 0;') 1085 if port in port_to_buf_map: 1086 code('try {') 1087 code.indent() 1088 code('${{port["c_code_in_port"]}}') 1089 1090 if port in port_to_buf_map: 1091 code.dedent() 1092 code(''' 1093 } catch (const RejectException & e) { 1094 rejected[${{port_to_buf_map[port]}}]++; 1095 } 1096''') 1097 code.dedent() 1098 code('') 1099 1100 code.dedent() 1101 code.dedent() 1102 code(''' 1103 // If we got this far, we have nothing left todo or something went 1104 // wrong''') 1105 for buf_name, ports in in_msg_bufs.items(): 1106 if len(ports) > 1: 1107 # only produce checks when a buffer is shared by multiple ports 1108 code(''' 1109 if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1110 { 1111 // no port claimed the message on the top of this buffer 1112 panic("Runtime Error at Ruby Time: %d. " 1113 "All ports rejected a message. " 1114 "You are probably sending a message type to this controller " 1115 "over a virtual network that do not define an in_port for " 1116 "the incoming message type.\\n", 1117 Cycles(1)); 1118 } 1119''') 1120 code(''' 1121 break; 1122 } 1123} 1124''') 1125 1126 code.write(path, "%s_Wakeup.cc" % self.ident) 1127 1128 def printCSwitch(self, path): 1129 '''Output switch statement for transition table''' 1130 1131 code = self.symtab.codeFormatter() 1132 ident = self.ident 1133 1134 code(''' 1135// Auto generated C++ code started by $__file__:$__line__ 1136// ${ident}: ${{self.short}} 1137 1138#include <cassert> 1139 1140#include "base/misc.hh" 1141#include "base/trace.hh" 1142#include "debug/ProtocolTrace.hh" 1143#include "debug/RubyGenerated.hh" 1144#include "mem/protocol/${ident}_Controller.hh" 1145#include "mem/protocol/${ident}_Event.hh" 1146#include "mem/protocol/${ident}_State.hh" 1147#include "mem/protocol/Types.hh" 1148#include "mem/ruby/system/RubySystem.hh" 1149 1150#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1151 1152#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1153#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1154 1155TransitionResult 1156${ident}_Controller::doTransition(${ident}_Event event, 1157''') 1158 if self.EntryType != None: 1159 code(''' 1160 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1161''') 1162 if self.TBEType != None: 1163 code(''' 1164 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1165''') 1166 code(''' 1167 Addr addr) 1168{ 1169''') 1170 code.indent() 1171 1172 if self.TBEType != None and self.EntryType != None: 1173 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1174 elif self.TBEType != None: 1175 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1176 elif self.EntryType != None: 1177 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1178 else: 1179 code('${ident}_State state = getState(addr);') 1180 1181 code(''' 1182${ident}_State next_state = state; 1183 1184DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n", 1185 *this, curCycle(), ${ident}_State_to_string(state), 1186 ${ident}_Event_to_string(event), addr); 1187 1188TransitionResult result = 1189''') 1190 if self.TBEType != None and self.EntryType != None: 1191 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1192 elif self.TBEType != None: 1193 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1194 elif self.EntryType != None: 1195 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1196 else: 1197 code('doTransitionWorker(event, state, next_state, addr);') 1198 1199 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1200 1201 code(''' 1202 1203if (result == TransitionResult_Valid) { 1204 DPRINTF(RubyGenerated, "next_state: %s\\n", 1205 ${ident}_State_to_string(next_state)); 1206 countTransition(state, event); 1207 1208 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1209 curTick(), m_version, "${ident}", 1210 ${ident}_Event_to_string(event), 1211 ${ident}_State_to_string(state), 1212 ${ident}_State_to_string(next_state), 1213 printAddress(addr), GET_TRANSITION_COMMENT()); 1214 1215 CLEAR_TRANSITION_COMMENT(); 1216''') 1217 if self.TBEType != None and self.EntryType != None: 1218 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1219 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1220 elif self.TBEType != None: 1221 code('setState(m_tbe_ptr, addr, next_state);') 1222 code('setAccessPermission(addr, next_state);') 1223 elif self.EntryType != None: 1224 code('setState(m_cache_entry_ptr, addr, next_state);') 1225 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1226 else: 1227 code('setState(addr, next_state);') 1228 code('setAccessPermission(addr, next_state);') 1229 1230 code(''' 1231} else if (result == TransitionResult_ResourceStall) { 1232 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1233 curTick(), m_version, "${ident}", 1234 ${ident}_Event_to_string(event), 1235 ${ident}_State_to_string(state), 1236 ${ident}_State_to_string(next_state), 1237 printAddress(addr), "Resource Stall"); 1238} else if (result == TransitionResult_ProtocolStall) { 1239 DPRINTF(RubyGenerated, "stalling\\n"); 1240 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1241 curTick(), m_version, "${ident}", 1242 ${ident}_Event_to_string(event), 1243 ${ident}_State_to_string(state), 1244 ${ident}_State_to_string(next_state), 1245 printAddress(addr), "Protocol Stall"); 1246} 1247 1248return result; 1249''') 1250 code.dedent() 1251 code(''' 1252} 1253 1254TransitionResult 1255${ident}_Controller::doTransitionWorker(${ident}_Event event, 1256 ${ident}_State state, 1257 ${ident}_State& next_state, 1258''') 1259 1260 if self.TBEType != None: 1261 code(''' 1262 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1263''') 1264 if self.EntryType != None: 1265 code(''' 1266 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1267''') 1268 code(''' 1269 Addr addr) 1270{ 1271 switch(HASH_FUN(state, event)) { 1272''') 1273 1274 # This map will allow suppress generating duplicate code 1275 cases = orderdict() 1276 1277 for trans in self.transitions: 1278 case_string = "%s_State_%s, %s_Event_%s" % \ 1279 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1280 1281 case = self.symtab.codeFormatter() 1282 # Only set next_state if it changes 1283 if trans.state != trans.nextState: 1284 if trans.nextState.isWildcard(): 1285 # When * is encountered as an end state of a transition, 1286 # the next state is determined by calling the 1287 # machine-specific getNextState function. The next state 1288 # is determined before any actions of the transition 1289 # execute, and therefore the next state calculation cannot 1290 # depend on any of the transitionactions. 1291 case('next_state = getNextState(addr);') 1292 else: 1293 ns_ident = trans.nextState.ident 1294 case('next_state = ${ident}_State_${ns_ident};') 1295 1296 actions = trans.actions 1297 request_types = trans.request_types 1298 1299 # Check for resources 1300 case_sorter = [] 1301 res = trans.resources 1302 for key,val in res.iteritems(): 1303 val = ''' 1304if (!%s.areNSlotsAvailable(%s, clockEdge())) 1305 return TransitionResult_ResourceStall; 1306''' % (key.code, val) 1307 case_sorter.append(val) 1308 1309 # Check all of the request_types for resource constraints 1310 for request_type in request_types: 1311 val = ''' 1312if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1313 return TransitionResult_ResourceStall; 1314} 1315''' % (self.ident, request_type.ident) 1316 case_sorter.append(val) 1317 1318 # Emit the code sequences in a sorted order. This makes the 1319 # output deterministic (without this the output order can vary 1320 # since Map's keys() on a vector of pointers is not deterministic 1321 for c in sorted(case_sorter): 1322 case("$c") 1323 1324 # Record access types for this transition 1325 for request_type in request_types: 1326 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1327 1328 # Figure out if we stall 1329 stall = False 1330 for action in actions: 1331 if action.ident == "z_stall": 1332 stall = True 1333 break 1334 1335 if stall: 1336 case('return TransitionResult_ProtocolStall;') 1337 else: 1338 if self.TBEType != None and self.EntryType != None: 1339 for action in actions: 1340 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1341 elif self.TBEType != None: 1342 for action in actions: 1343 case('${{action.ident}}(m_tbe_ptr, addr);') 1344 elif self.EntryType != None: 1345 for action in actions: 1346 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1347 else: 1348 for action in actions: 1349 case('${{action.ident}}(addr);') 1350 case('return TransitionResult_Valid;') 1351 1352 case = str(case) 1353 1354 # Look to see if this transition code is unique. 1355 if case not in cases: 1356 cases[case] = [] 1357 1358 cases[case].append(case_string) 1359 1360 # Walk through all of the unique code blocks and spit out the 1361 # corresponding case statement elements 1362 for case,transitions in cases.iteritems(): 1363 # Iterative over all the multiple transitions that share 1364 # the same code 1365 for trans in transitions: 1366 code(' case HASH_FUN($trans):') 1367 code(' $case\n') 1368 1369 code(''' 1370 default: 1371 panic("Invalid transition\\n" 1372 "%s time: %d addr: %s event: %s state: %s\\n", 1373 name(), curCycle(), addr, event, state); 1374 } 1375 1376 return TransitionResult_Valid; 1377} 1378''') 1379 code.write(path, "%s_Transitions.cc" % self.ident) 1380 1381 1382 # ************************** 1383 # ******* HTML Files ******* 1384 # ************************** 1385 def frameRef(self, click_href, click_target, over_href, over_num, text): 1386 code = self.symtab.codeFormatter(fix_newlines=False) 1387 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1388 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1389 parent.frames[$over_num].location='$over_href' 1390 }\"> 1391 ${{html.formatShorthand(text)}} 1392 </A>""") 1393 return str(code) 1394 1395 def writeHTMLFiles(self, path): 1396 # Create table with no row hilighted 1397 self.printHTMLTransitions(path, None) 1398 1399 # Generate transition tables 1400 for state in self.states.itervalues(): 1401 self.printHTMLTransitions(path, state) 1402 1403 # Generate action descriptions 1404 for action in self.actions.itervalues(): 1405 name = "%s_action_%s.html" % (self.ident, action.ident) 1406 code = html.createSymbol(action, "Action") 1407 code.write(path, name) 1408 1409 # Generate state descriptions 1410 for state in self.states.itervalues(): 1411 name = "%s_State_%s.html" % (self.ident, state.ident) 1412 code = html.createSymbol(state, "State") 1413 code.write(path, name) 1414 1415 # Generate event descriptions 1416 for event in self.events.itervalues(): 1417 name = "%s_Event_%s.html" % (self.ident, event.ident) 1418 code = html.createSymbol(event, "Event") 1419 code.write(path, name) 1420 1421 def printHTMLTransitions(self, path, active_state): 1422 code = self.symtab.codeFormatter() 1423 1424 code(''' 1425<HTML> 1426<BODY link="blue" vlink="blue"> 1427 1428<H1 align="center">${{html.formatShorthand(self.short)}}: 1429''') 1430 code.indent() 1431 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1432 mid = machine.ident 1433 if i != 0: 1434 extra = " - " 1435 else: 1436 extra = "" 1437 if machine == self: 1438 code('$extra$mid') 1439 else: 1440 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1441 code.dedent() 1442 1443 code(""" 1444</H1> 1445 1446<TABLE border=1> 1447<TR> 1448 <TH> </TH> 1449""") 1450 1451 for event in self.events.itervalues(): 1452 href = "%s_Event_%s.html" % (self.ident, event.ident) 1453 ref = self.frameRef(href, "Status", href, "1", event.short) 1454 code('<TH bgcolor=white>$ref</TH>') 1455 1456 code('</TR>') 1457 # -- Body of table 1458 for state in self.states.itervalues(): 1459 # -- Each row 1460 if state == active_state: 1461 color = "yellow" 1462 else: 1463 color = "white" 1464 1465 click = "%s_table_%s.html" % (self.ident, state.ident) 1466 over = "%s_State_%s.html" % (self.ident, state.ident) 1467 text = html.formatShorthand(state.short) 1468 ref = self.frameRef(click, "Table", over, "1", state.short) 1469 code(''' 1470<TR> 1471 <TH bgcolor=$color>$ref</TH> 1472''') 1473 1474 # -- One column for each event 1475 for event in self.events.itervalues(): 1476 trans = self.table.get((state,event), None) 1477 if trans is None: 1478 # This is the no transition case 1479 if state == active_state: 1480 color = "#C0C000" 1481 else: 1482 color = "lightgrey" 1483 1484 code('<TD bgcolor=$color> </TD>') 1485 continue 1486 1487 next = trans.nextState 1488 stall_action = False 1489 1490 # -- Get the actions 1491 for action in trans.actions: 1492 if action.ident == "z_stall" or \ 1493 action.ident == "zz_recycleMandatoryQueue": 1494 stall_action = True 1495 1496 # -- Print out "actions/next-state" 1497 if stall_action: 1498 if state == active_state: 1499 color = "#C0C000" 1500 else: 1501 color = "lightgrey" 1502 1503 elif active_state and next.ident == active_state.ident: 1504 color = "aqua" 1505 elif state == active_state: 1506 color = "yellow" 1507 else: 1508 color = "white" 1509 1510 code('<TD bgcolor=$color>') 1511 for action in trans.actions: 1512 href = "%s_action_%s.html" % (self.ident, action.ident) 1513 ref = self.frameRef(href, "Status", href, "1", 1514 action.short) 1515 code(' $ref') 1516 if next != state: 1517 if trans.actions: 1518 code('/') 1519 click = "%s_table_%s.html" % (self.ident, next.ident) 1520 over = "%s_State_%s.html" % (self.ident, next.ident) 1521 ref = self.frameRef(click, "Table", over, "1", next.short) 1522 code("$ref") 1523 code("</TD>") 1524 1525 # -- Each row 1526 if state == active_state: 1527 color = "yellow" 1528 else: 1529 color = "white" 1530 1531 click = "%s_table_%s.html" % (self.ident, state.ident) 1532 over = "%s_State_%s.html" % (self.ident, state.ident) 1533 ref = self.frameRef(click, "Table", over, "1", state.short) 1534 code(''' 1535 <TH bgcolor=$color>$ref</TH> 1536</TR> 1537''') 1538 code(''' 1539<!- Column footer-> 1540<TR> 1541 <TH> </TH> 1542''') 1543 1544 for event in self.events.itervalues(): 1545 href = "%s_Event_%s.html" % (self.ident, event.ident) 1546 ref = self.frameRef(href, "Status", href, "1", event.short) 1547 code('<TH bgcolor=white>$ref</TH>') 1548 code(''' 1549</TR> 1550</TABLE> 1551</BODY></HTML> 1552''') 1553 1554 1555 if active_state: 1556 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1557 else: 1558 name = "%s_table.html" % self.ident 1559 code.write(path, name) 1560 1561__all__ = [ "StateMachine" ] 1562