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