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