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