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