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