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