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