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