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