StateMachine.py revision 11025
16166Ssteve.reinhardt@amd.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 26166Ssteve.reinhardt@amd.com# Copyright (c) 2009 The Hewlett-Packard Development Company 36166Ssteve.reinhardt@amd.com# Copyright (c) 2013 Advanced Micro Devices, Inc. 46166Ssteve.reinhardt@amd.com# All rights reserved. 56166Ssteve.reinhardt@amd.com# 66166Ssteve.reinhardt@amd.com# Redistribution and use in source and binary forms, with or without 76166Ssteve.reinhardt@amd.com# modification, are permitted provided that the following conditions are 86166Ssteve.reinhardt@amd.com# met: redistributions of source code must retain the above copyright 96166Ssteve.reinhardt@amd.com# notice, this list of conditions and the following disclaimer; 106166Ssteve.reinhardt@amd.com# redistributions in binary form must reproduce the above copyright 116166Ssteve.reinhardt@amd.com# notice, this list of conditions and the following disclaimer in the 126166Ssteve.reinhardt@amd.com# documentation and/or other materials provided with the distribution; 136166Ssteve.reinhardt@amd.com# neither the name of the copyright holders nor the names of its 146166Ssteve.reinhardt@amd.com# contributors may be used to endorse or promote products derived from 156166Ssteve.reinhardt@amd.com# this software without specific prior written permission. 166166Ssteve.reinhardt@amd.com# 176166Ssteve.reinhardt@amd.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186166Ssteve.reinhardt@amd.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 196166Ssteve.reinhardt@amd.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 206166Ssteve.reinhardt@amd.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 216166Ssteve.reinhardt@amd.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 226166Ssteve.reinhardt@amd.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 236166Ssteve.reinhardt@amd.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 246166Ssteve.reinhardt@amd.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 256166Ssteve.reinhardt@amd.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 266166Ssteve.reinhardt@amd.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 276166Ssteve.reinhardt@amd.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286166Ssteve.reinhardt@amd.com 296166Ssteve.reinhardt@amd.comfrom m5.util import orderdict 306166Ssteve.reinhardt@amd.com 316928SBrad.Beckmann@amd.comfrom slicc.symbols.Symbol import Symbol 326928SBrad.Beckmann@amd.comfrom slicc.symbols.Var import Var 336928SBrad.Beckmann@amd.comimport slicc.generate.html as html 346166Ssteve.reinhardt@amd.comimport re 356928SBrad.Beckmann@amd.com 366928SBrad.Beckmann@amd.compython_class_map = { 376928SBrad.Beckmann@amd.com "int": "Int", 386928SBrad.Beckmann@amd.com "uint32_t" : "UInt32", 396928SBrad.Beckmann@amd.com "std::string": "String", 406928SBrad.Beckmann@amd.com "bool": "Bool", 416928SBrad.Beckmann@amd.com "CacheMemory": "RubyCache", 426928SBrad.Beckmann@amd.com "WireBuffer": "RubyWireBuffer", 436928SBrad.Beckmann@amd.com "Sequencer": "RubySequencer", 446928SBrad.Beckmann@amd.com "DirectoryMemory": "RubyDirectoryMemory", 456928SBrad.Beckmann@amd.com "MemoryControl": "MemoryControl", 466928SBrad.Beckmann@amd.com "DMASequencer": "DMASequencer", 476928SBrad.Beckmann@amd.com "Prefetcher":"Prefetcher", 486928SBrad.Beckmann@amd.com "Cycles":"Cycles", 496928SBrad.Beckmann@amd.com } 507570SBrad.Beckmann@amd.com 516928SBrad.Beckmann@amd.comclass StateMachine(Symbol): 527570SBrad.Beckmann@amd.com def __init__(self, symtab, ident, location, pairs, config_parameters): 536928SBrad.Beckmann@amd.com super(StateMachine, self).__init__(symtab, ident, location, pairs) 546928SBrad.Beckmann@amd.com self.table = None 556928SBrad.Beckmann@amd.com 566928SBrad.Beckmann@amd.com # Data members in the State Machine that have been declared before 576928SBrad.Beckmann@amd.com # the opening brace '{' of the machine. Note that these along with 587570SBrad.Beckmann@amd.com # the members in self.objects form the entire set of data members. 597570SBrad.Beckmann@amd.com self.config_parameters = config_parameters 607570SBrad.Beckmann@amd.com 617570SBrad.Beckmann@amd.com self.prefetchers = [] 627570SBrad.Beckmann@amd.com 637570SBrad.Beckmann@amd.com for param in config_parameters: 647570SBrad.Beckmann@amd.com if param.pointer: 657570SBrad.Beckmann@amd.com var = Var(symtab, param.ident, location, param.type_ast.type, 667570SBrad.Beckmann@amd.com "(*m_%s_ptr)" % param.ident, {}, self) 677570SBrad.Beckmann@amd.com else: 687570SBrad.Beckmann@amd.com var = Var(symtab, param.ident, location, param.type_ast.type, 697570SBrad.Beckmann@amd.com "m_%s" % param.ident, {}, self) 707570SBrad.Beckmann@amd.com 716928SBrad.Beckmann@amd.com self.symtab.registerSym(param.ident, var) 726928SBrad.Beckmann@amd.com 736289Snate@binkert.org if str(param.type_ast.type) == "Prefetcher": 746166Ssteve.reinhardt@amd.com self.prefetchers.append(var) 757570SBrad.Beckmann@amd.com 766928SBrad.Beckmann@amd.com self.states = orderdict() 778436SBrad.Beckmann@amd.com self.events = orderdict() 786928SBrad.Beckmann@amd.com self.actions = orderdict() 798322Ssteve.reinhardt@amd.com self.request_types = orderdict() 806928SBrad.Beckmann@amd.com self.transitions = [] 816928SBrad.Beckmann@amd.com self.in_ports = [] 826928SBrad.Beckmann@amd.com self.functions = [] 836928SBrad.Beckmann@amd.com 846928SBrad.Beckmann@amd.com # Data members in the State Machine that have been declared inside 858744Sgblack@eecs.umich.edu # the {} machine. Note that these along with the config params 866928SBrad.Beckmann@amd.com # form the entire set of data members of the machine. 878706Sandreas.hansson@arm.com self.objects = [] 888706Sandreas.hansson@arm.com self.TBEType = None 898706Sandreas.hansson@arm.com self.EntryType = None 906928SBrad.Beckmann@amd.com self.debug_flags = set() 916928SBrad.Beckmann@amd.com self.debug_flags.add('RubyGenerated') 926928SBrad.Beckmann@amd.com self.debug_flags.add('RubySlicc') 936166Ssteve.reinhardt@amd.com 948801Sgblack@eecs.umich.edu def __repr__(self): 956928SBrad.Beckmann@amd.com return "[StateMachine: %s]" % self.ident 966928SBrad.Beckmann@amd.com 976928SBrad.Beckmann@amd.com def addState(self, state): 986928SBrad.Beckmann@amd.com assert self.table is None 99 self.states[state.ident] = state 100 101 def addEvent(self, event): 102 assert self.table is None 103 self.events[event.ident] = event 104 105 def addAction(self, action): 106 assert self.table is None 107 108 # Check for duplicate action 109 for other in self.actions.itervalues(): 110 if action.ident == other.ident: 111 action.warning("Duplicate action definition: %s" % action.ident) 112 action.error("Duplicate action definition: %s" % action.ident) 113 if action.short == other.short: 114 other.warning("Duplicate action shorthand: %s" % other.ident) 115 other.warning(" shorthand = %s" % other.short) 116 action.warning("Duplicate action shorthand: %s" % action.ident) 117 action.error(" shorthand = %s" % action.short) 118 119 self.actions[action.ident] = action 120 121 def addDebugFlag(self, flag): 122 self.debug_flags.add(flag) 123 124 def addRequestType(self, request_type): 125 assert self.table is None 126 self.request_types[request_type.ident] = request_type 127 128 def addTransition(self, trans): 129 assert self.table is None 130 self.transitions.append(trans) 131 132 def addInPort(self, var): 133 self.in_ports.append(var) 134 135 def addFunc(self, func): 136 # register func in the symbol table 137 self.symtab.registerSym(str(func), func) 138 self.functions.append(func) 139 140 def addObject(self, obj): 141 self.symtab.registerSym(str(obj), obj) 142 self.objects.append(obj) 143 144 def addType(self, type): 145 type_ident = '%s' % type.c_ident 146 147 if type_ident == "%s_TBE" %self.ident: 148 if self.TBEType != None: 149 self.error("Multiple Transaction Buffer types in a " \ 150 "single machine."); 151 self.TBEType = type 152 153 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 154 if "main" in type and "false" == type["main"].lower(): 155 pass # this isn't the EntryType 156 else: 157 if self.EntryType != None: 158 self.error("Multiple AbstractCacheEntry types in a " \ 159 "single machine."); 160 self.EntryType = type 161 162 # Needs to be called before accessing the table 163 def buildTable(self): 164 assert self.table is None 165 166 table = {} 167 168 for trans in self.transitions: 169 # Track which actions we touch so we know if we use them 170 # all -- really this should be done for all symbols as 171 # part of the symbol table, then only trigger it for 172 # Actions, States, Events, etc. 173 174 for action in trans.actions: 175 action.used = True 176 177 index = (trans.state, trans.event) 178 if index in table: 179 table[index].warning("Duplicate transition: %s" % table[index]) 180 trans.error("Duplicate transition: %s" % trans) 181 table[index] = trans 182 183 # Look at all actions to make sure we used them all 184 for action in self.actions.itervalues(): 185 if not action.used: 186 error_msg = "Unused action: %s" % action.ident 187 if "desc" in action: 188 error_msg += ", " + action.desc 189 action.warning(error_msg) 190 self.table = table 191 192 # determine the port->msg buffer mappings 193 def getBufferMaps(self, ident): 194 msg_bufs = [] 195 port_to_buf_map = {} 196 in_msg_bufs = {} 197 for port in self.in_ports: 198 buf_name = "m_%s_ptr" % port.buffer_expr.name 199 msg_bufs.append(buf_name) 200 port_to_buf_map[port] = msg_bufs.index(buf_name) 201 if buf_name not in in_msg_bufs: 202 in_msg_bufs[buf_name] = [port] 203 else: 204 in_msg_bufs[buf_name].append(port) 205 return port_to_buf_map, in_msg_bufs, msg_bufs 206 207 def writeCodeFiles(self, path, includes): 208 self.printControllerPython(path) 209 self.printControllerHH(path) 210 self.printControllerCC(path, includes) 211 self.printCSwitch(path) 212 self.printCWakeup(path, includes) 213 214 def printControllerPython(self, path): 215 code = self.symtab.codeFormatter() 216 ident = self.ident 217 218 py_ident = "%s_Controller" % ident 219 c_ident = "%s_Controller" % self.ident 220 221 code(''' 222from m5.params import * 223from m5.SimObject import SimObject 224from Controller import RubyController 225 226class $py_ident(RubyController): 227 type = '$py_ident' 228 cxx_header = 'mem/protocol/${c_ident}.hh' 229''') 230 code.indent() 231 for param in self.config_parameters: 232 dflt_str = '' 233 234 if param.rvalue is not None: 235 dflt_str = str(param.rvalue.inline()) + ', ' 236 237 if param.type_ast.type.c_ident == "MessageBuffer": 238 # The MessageBuffer MUST be instantiated in the protocol config 239 code('${{param.ident}} = Param.MessageBuffer("")') 240 241 elif python_class_map.has_key(param.type_ast.type.c_ident): 242 python_type = python_class_map[param.type_ast.type.c_ident] 243 code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 244 245 else: 246 self.error("Unknown c++ to python class conversion for c++ " \ 247 "type: '%s'. Please update the python_class_map " \ 248 "in StateMachine.py", param.type_ast.type.c_ident) 249 250 # Also add any MessageBuffers declared internally to the controller 251 # Note: This includes mandatory and memory queues 252 for var in self.objects: 253 if var.type.c_ident == "MessageBuffer": 254 code('${{var.ident}} = Param.MessageBuffer("")') 255 256 code.dedent() 257 code.write(path, '%s.py' % py_ident) 258 259 260 def printControllerHH(self, path): 261 '''Output the method declarations for the class declaration''' 262 code = self.symtab.codeFormatter() 263 ident = self.ident 264 c_ident = "%s_Controller" % self.ident 265 266 code(''' 267/** \\file $c_ident.hh 268 * 269 * Auto generated C++ code started by $__file__:$__line__ 270 * Created by slicc definition of Module "${{self.short}}" 271 */ 272 273#ifndef __${ident}_CONTROLLER_HH__ 274#define __${ident}_CONTROLLER_HH__ 275 276#include <iostream> 277#include <sstream> 278#include <string> 279 280#include "mem/protocol/TransitionResult.hh" 281#include "mem/protocol/Types.hh" 282#include "mem/ruby/common/Consumer.hh" 283#include "mem/ruby/slicc_interface/AbstractController.hh" 284#include "params/$c_ident.hh" 285 286''') 287 288 seen_types = set() 289 for var in self.objects: 290 if var.type.ident not in seen_types and not var.type.isPrimitive: 291 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 292 seen_types.add(var.type.ident) 293 294 # for adding information to the protocol debug trace 295 code(''' 296extern std::stringstream ${ident}_transitionComment; 297 298class $c_ident : public AbstractController 299{ 300 public: 301 typedef ${c_ident}Params Params; 302 $c_ident(const Params *p); 303 static int getNumControllers(); 304 void init(); 305 306 MessageBuffer* getMandatoryQueue() const; 307 MessageBuffer* getMemoryQueue() const; 308 void initNetQueues(); 309 310 void print(std::ostream& out) const; 311 void wakeup(); 312 void resetStats(); 313 void regStats(); 314 void collateStats(); 315 316 void recordCacheTrace(int cntrl, CacheRecorder* tr); 317 Sequencer* getSequencer() const; 318 319 int functionalWriteBuffers(PacketPtr&); 320 321 void countTransition(${ident}_State state, ${ident}_Event event); 322 void possibleTransition(${ident}_State state, ${ident}_Event event); 323 uint64 getEventCount(${ident}_Event event); 324 bool isPossible(${ident}_State state, ${ident}_Event event); 325 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 326 327private: 328''') 329 330 code.indent() 331 # added by SS 332 for param in self.config_parameters: 333 if param.pointer: 334 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 335 else: 336 code('${{param.type_ast.type}} m_${{param.ident}};') 337 338 code(''' 339TransitionResult doTransition(${ident}_Event event, 340''') 341 342 if self.EntryType != None: 343 code(''' 344 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 345''') 346 if self.TBEType != None: 347 code(''' 348 ${{self.TBEType.c_ident}}* m_tbe_ptr, 349''') 350 351 code(''' 352 Addr addr); 353 354TransitionResult doTransitionWorker(${ident}_Event event, 355 ${ident}_State state, 356 ${ident}_State& next_state, 357''') 358 359 if self.TBEType != None: 360 code(''' 361 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 362''') 363 if self.EntryType != None: 364 code(''' 365 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 366''') 367 368 code(''' 369 Addr addr); 370 371int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 372int m_event_counters[${ident}_Event_NUM]; 373bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 374 375static std::vector<Stats::Vector *> eventVec; 376static std::vector<std::vector<Stats::Vector *> > transVec; 377static int m_num_controllers; 378 379// Internal functions 380''') 381 382 for func in self.functions: 383 proto = func.prototype 384 if proto: 385 code('$proto') 386 387 if self.EntryType != None: 388 code(''' 389 390// Set and Reset for cache_entry variable 391void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 392void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 393''') 394 395 if self.TBEType != None: 396 code(''' 397 398// Set and Reset for tbe variable 399void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 400void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 401''') 402 403 # Prototype the actions that the controller can take 404 code(''' 405 406// Actions 407''') 408 if self.TBEType != None and self.EntryType != None: 409 for action in self.actions.itervalues(): 410 code('/** \\brief ${{action.desc}} */') 411 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 412 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 413 'm_cache_entry_ptr, Addr addr);') 414 elif self.TBEType != None: 415 for action in self.actions.itervalues(): 416 code('/** \\brief ${{action.desc}} */') 417 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 418 'm_tbe_ptr, Addr addr);') 419 elif self.EntryType != None: 420 for action in self.actions.itervalues(): 421 code('/** \\brief ${{action.desc}} */') 422 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 423 'm_cache_entry_ptr, Addr addr);') 424 else: 425 for action in self.actions.itervalues(): 426 code('/** \\brief ${{action.desc}} */') 427 code('void ${{action.ident}}(Addr addr);') 428 429 # the controller internal variables 430 code(''' 431 432// Objects 433''') 434 for var in self.objects: 435 th = var.get("template", "") 436 code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 437 438 code.dedent() 439 code('};') 440 code('#endif // __${ident}_CONTROLLER_H__') 441 code.write(path, '%s.hh' % c_ident) 442 443 def printControllerCC(self, path, includes): 444 '''Output the actions for performing the actions''' 445 446 code = self.symtab.codeFormatter() 447 ident = self.ident 448 c_ident = "%s_Controller" % self.ident 449 450 code(''' 451/** \\file $c_ident.cc 452 * 453 * Auto generated C++ code started by $__file__:$__line__ 454 * Created by slicc definition of Module "${{self.short}}" 455 */ 456 457#include <sys/types.h> 458#include <unistd.h> 459 460#include <cassert> 461#include <sstream> 462#include <string> 463#include <typeinfo> 464 465#include "base/compiler.hh" 466#include "base/cprintf.hh" 467 468''') 469 for f in self.debug_flags: 470 code('#include "debug/${{f}}.hh"') 471 code(''' 472#include "mem/protocol/${ident}_Controller.hh" 473#include "mem/protocol/${ident}_Event.hh" 474#include "mem/protocol/${ident}_State.hh" 475#include "mem/protocol/Types.hh" 476#include "mem/ruby/system/System.hh" 477 478''') 479 for include_path in includes: 480 code('#include "${{include_path}}"') 481 482 code(''' 483 484using namespace std; 485''') 486 487 # include object classes 488 seen_types = set() 489 for var in self.objects: 490 if var.type.ident not in seen_types and not var.type.isPrimitive: 491 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 492 seen_types.add(var.type.ident) 493 494 num_in_ports = len(self.in_ports) 495 496 code(''' 497$c_ident * 498${c_ident}Params::create() 499{ 500 return new $c_ident(this); 501} 502 503int $c_ident::m_num_controllers = 0; 504std::vector<Stats::Vector *> $c_ident::eventVec; 505std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 506 507// for adding information to the protocol debug trace 508stringstream ${ident}_transitionComment; 509 510#ifndef NDEBUG 511#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 512#else 513#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 514#endif 515 516/** \\brief constructor */ 517$c_ident::$c_ident(const Params *p) 518 : AbstractController(p) 519{ 520 m_machineID.type = MachineType_${ident}; 521 m_machineID.num = m_version; 522 m_num_controllers++; 523 524 m_in_ports = $num_in_ports; 525''') 526 code.indent() 527 528 # 529 # After initializing the universal machine parameters, initialize the 530 # this machines config parameters. Also if these configuration params 531 # include a sequencer, connect the it to the controller. 532 # 533 for param in self.config_parameters: 534 if param.pointer: 535 code('m_${{param.ident}}_ptr = p->${{param.ident}};') 536 else: 537 code('m_${{param.ident}} = p->${{param.ident}};') 538 539 if re.compile("sequencer").search(param.ident): 540 code('m_${{param.ident}}_ptr->setController(this);') 541 542 for var in self.objects: 543 # Some MessageBuffers (e.g. mandatory and memory queues) are 544 # instantiated internally to StateMachines but exposed to 545 # components outside SLICC, so make sure to set up this 546 # controller as their receivers 547 if var.type.c_ident == "MessageBuffer": 548 code(''' 549m_${{var.ident}}_ptr = p->${{var.ident}}; 550m_${{var.ident}}_ptr->setReceiver(this); 551''') 552 553 code(''' 554 555for (int state = 0; state < ${ident}_State_NUM; state++) { 556 for (int event = 0; event < ${ident}_Event_NUM; event++) { 557 m_possible[state][event] = false; 558 m_counters[state][event] = 0; 559 } 560} 561for (int event = 0; event < ${ident}_Event_NUM; event++) { 562 m_event_counters[event] = 0; 563} 564''') 565 code.dedent() 566 code(''' 567} 568 569void 570$c_ident::initNetQueues() 571{ 572 MachineType machine_type = string_to_MachineType("${{self.ident}}"); 573 int base M5_VAR_USED = MachineType_base_number(machine_type); 574 575''') 576 code.indent() 577 578 # set for maintaining the vnet, direction pairs already seen for this 579 # machine. This map helps in implementing the check for avoiding 580 # multiple message buffers being mapped to the same vnet. 581 vnet_dir_set = set() 582 583 for var in self.config_parameters: 584 if "network" in var: 585 vtype = var.type_ast.type 586 vid = "m_%s_ptr" % var.ident 587 588 code('assert($vid != NULL);') 589 590 # Network port object 591 network = var["network"] 592 593 if "virtual_network" in var: 594 vnet = var["virtual_network"] 595 vnet_type = var["vnet_type"] 596 597 assert (vnet, network) not in vnet_dir_set 598 vnet_dir_set.add((vnet,network)) 599 600 code(''' 601m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 602 "$vnet_type", $vid); 603''') 604 # Set the end 605 if network == "To": 606 code('$vid->setSender(this);') 607 else: 608 code('$vid->setReceiver(this);') 609 610 # Set Priority 611 if "rank" in var: 612 code('$vid->setPriority(${{var["rank"]}})') 613 614 code.dedent() 615 code(''' 616} 617 618void 619$c_ident::init() 620{ 621 // initialize objects 622 initNetQueues(); 623''') 624 625 code.indent() 626 627 for var in self.objects: 628 vtype = var.type 629 vid = "m_%s_ptr" % var.ident 630 if "network" not in var: 631 # Not a network port object 632 if "primitive" in vtype: 633 code('$vid = new ${{vtype.c_ident}};') 634 if "default" in var: 635 code('(*$vid) = ${{var["default"]}};') 636 else: 637 # Normal Object 638 if var.type.c_ident != "MessageBuffer": 639 th = var.get("template", "") 640 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 641 args = "" 642 if "non_obj" not in vtype and not vtype.isEnumeration: 643 args = var.get("constructor", "") 644 code('$expr($args);') 645 646 code('assert($vid != NULL);') 647 648 if "default" in var: 649 code('*$vid = ${{var["default"]}}; // Object default') 650 elif "default" in vtype: 651 comment = "Type %s default" % vtype.ident 652 code('*$vid = ${{vtype["default"]}}; // $comment') 653 654 # Set Priority 655 if vtype.isBuffer and "rank" in var: 656 code('$vid->setPriority(${{var["rank"]}});') 657 658 # Set sender and receiver for trigger queue 659 if var.ident.find("triggerQueue") >= 0: 660 code('$vid->setSender(this);') 661 code('$vid->setReceiver(this);') 662 elif vtype.c_ident == "TimerTable": 663 code('$vid->setClockObj(this);') 664 elif var.ident.find("optionalQueue") >= 0: 665 code('$vid->setSender(this);') 666 code('$vid->setReceiver(this);') 667 668 # Set the prefetchers 669 code() 670 for prefetcher in self.prefetchers: 671 code('${{prefetcher.code}}.setController(this);') 672 673 code() 674 for port in self.in_ports: 675 # Set the queue consumers 676 code('${{port.code}}.setConsumer(this);') 677 678 # Initialize the transition profiling 679 code() 680 for trans in self.transitions: 681 # Figure out if we stall 682 stall = False 683 for action in trans.actions: 684 if action.ident == "z_stall": 685 stall = True 686 687 # Only possible if it is not a 'z' case 688 if not stall: 689 state = "%s_State_%s" % (self.ident, trans.state.ident) 690 event = "%s_Event_%s" % (self.ident, trans.event.ident) 691 code('possibleTransition($state, $event);') 692 693 code.dedent() 694 code(''' 695 AbstractController::init(); 696 resetStats(); 697} 698''') 699 700 mq_ident = "NULL" 701 for port in self.in_ports: 702 if port.code.find("mandatoryQueue_ptr") >= 0: 703 mq_ident = "m_mandatoryQueue_ptr" 704 705 memq_ident = "NULL" 706 for port in self.in_ports: 707 if port.code.find("responseFromMemory_ptr") >= 0: 708 memq_ident = "m_responseFromMemory_ptr" 709 710 seq_ident = "NULL" 711 for param in self.config_parameters: 712 if param.ident == "sequencer": 713 assert(param.pointer) 714 seq_ident = "m_%s_ptr" % param.ident 715 716 code(''' 717 718void 719$c_ident::regStats() 720{ 721 AbstractController::regStats(); 722 723 if (m_version == 0) { 724 for (${ident}_Event event = ${ident}_Event_FIRST; 725 event < ${ident}_Event_NUM; ++event) { 726 Stats::Vector *t = new Stats::Vector(); 727 t->init(m_num_controllers); 728 t->name(params()->ruby_system->name() + ".${c_ident}." + 729 ${ident}_Event_to_string(event)); 730 t->flags(Stats::pdf | Stats::total | Stats::oneline | 731 Stats::nozero); 732 733 eventVec.push_back(t); 734 } 735 736 for (${ident}_State state = ${ident}_State_FIRST; 737 state < ${ident}_State_NUM; ++state) { 738 739 transVec.push_back(std::vector<Stats::Vector *>()); 740 741 for (${ident}_Event event = ${ident}_Event_FIRST; 742 event < ${ident}_Event_NUM; ++event) { 743 744 Stats::Vector *t = new Stats::Vector(); 745 t->init(m_num_controllers); 746 t->name(params()->ruby_system->name() + ".${c_ident}." + 747 ${ident}_State_to_string(state) + 748 "." + ${ident}_Event_to_string(event)); 749 750 t->flags(Stats::pdf | Stats::total | Stats::oneline | 751 Stats::nozero); 752 transVec[state].push_back(t); 753 } 754 } 755 } 756} 757 758void 759$c_ident::collateStats() 760{ 761 for (${ident}_Event event = ${ident}_Event_FIRST; 762 event < ${ident}_Event_NUM; ++event) { 763 for (unsigned int i = 0; i < m_num_controllers; ++i) { 764 RubySystem *rs = params()->ruby_system; 765 std::map<uint32_t, AbstractController *>::iterator it = 766 rs->m_abstract_controls[MachineType_${ident}].find(i); 767 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 768 (*eventVec[event])[i] = 769 (($c_ident *)(*it).second)->getEventCount(event); 770 } 771 } 772 773 for (${ident}_State state = ${ident}_State_FIRST; 774 state < ${ident}_State_NUM; ++state) { 775 776 for (${ident}_Event event = ${ident}_Event_FIRST; 777 event < ${ident}_Event_NUM; ++event) { 778 779 for (unsigned int i = 0; i < m_num_controllers; ++i) { 780 RubySystem *rs = params()->ruby_system; 781 std::map<uint32_t, AbstractController *>::iterator it = 782 rs->m_abstract_controls[MachineType_${ident}].find(i); 783 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 784 (*transVec[state][event])[i] = 785 (($c_ident *)(*it).second)->getTransitionCount(state, event); 786 } 787 } 788 } 789} 790 791void 792$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 793{ 794 assert(m_possible[state][event]); 795 m_counters[state][event]++; 796 m_event_counters[event]++; 797} 798void 799$c_ident::possibleTransition(${ident}_State state, 800 ${ident}_Event event) 801{ 802 m_possible[state][event] = true; 803} 804 805uint64 806$c_ident::getEventCount(${ident}_Event event) 807{ 808 return m_event_counters[event]; 809} 810 811bool 812$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 813{ 814 return m_possible[state][event]; 815} 816 817uint64 818$c_ident::getTransitionCount(${ident}_State state, 819 ${ident}_Event event) 820{ 821 return m_counters[state][event]; 822} 823 824int 825$c_ident::getNumControllers() 826{ 827 return m_num_controllers; 828} 829 830MessageBuffer* 831$c_ident::getMandatoryQueue() const 832{ 833 return $mq_ident; 834} 835 836MessageBuffer* 837$c_ident::getMemoryQueue() const 838{ 839 return $memq_ident; 840} 841 842Sequencer* 843$c_ident::getSequencer() const 844{ 845 return $seq_ident; 846} 847 848void 849$c_ident::print(ostream& out) const 850{ 851 out << "[$c_ident " << m_version << "]"; 852} 853 854void $c_ident::resetStats() 855{ 856 for (int state = 0; state < ${ident}_State_NUM; state++) { 857 for (int event = 0; event < ${ident}_Event_NUM; event++) { 858 m_counters[state][event] = 0; 859 } 860 } 861 862 for (int event = 0; event < ${ident}_Event_NUM; event++) { 863 m_event_counters[event] = 0; 864 } 865 866 AbstractController::resetStats(); 867} 868''') 869 870 if self.EntryType != None: 871 code(''' 872 873// Set and Reset for cache_entry variable 874void 875$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 876{ 877 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 878} 879 880void 881$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 882{ 883 m_cache_entry_ptr = 0; 884} 885''') 886 887 if self.TBEType != None: 888 code(''' 889 890// Set and Reset for tbe variable 891void 892$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 893{ 894 m_tbe_ptr = m_new_tbe; 895} 896 897void 898$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 899{ 900 m_tbe_ptr = NULL; 901} 902''') 903 904 code(''' 905 906void 907$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 908{ 909''') 910 # 911 # Record cache contents for all associated caches. 912 # 913 code.indent() 914 for param in self.config_parameters: 915 if param.type_ast.type.ident == "CacheMemory": 916 assert(param.pointer) 917 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 918 919 code.dedent() 920 code(''' 921} 922 923// Actions 924''') 925 if self.TBEType != None and self.EntryType != None: 926 for action in self.actions.itervalues(): 927 if "c_code" not in action: 928 continue 929 930 code(''' 931/** \\brief ${{action.desc}} */ 932void 933$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 934{ 935 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 936 try { 937 ${{action["c_code"]}} 938 } catch (const RejectException & e) { 939 fatal("Error in action ${{ident}}:${{action.ident}}: " 940 "executed a peek statement with the wrong message " 941 "type specified. "); 942 } 943} 944 945''') 946 elif self.TBEType != None: 947 for action in self.actions.itervalues(): 948 if "c_code" not in action: 949 continue 950 951 code(''' 952/** \\brief ${{action.desc}} */ 953void 954$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 955{ 956 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 957 ${{action["c_code"]}} 958} 959 960''') 961 elif self.EntryType != None: 962 for action in self.actions.itervalues(): 963 if "c_code" not in action: 964 continue 965 966 code(''' 967/** \\brief ${{action.desc}} */ 968void 969$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 970{ 971 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 972 ${{action["c_code"]}} 973} 974 975''') 976 else: 977 for action in self.actions.itervalues(): 978 if "c_code" not in action: 979 continue 980 981 code(''' 982/** \\brief ${{action.desc}} */ 983void 984$c_ident::${{action.ident}}(Addr addr) 985{ 986 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 987 ${{action["c_code"]}} 988} 989 990''') 991 for func in self.functions: 992 code(func.generateCode()) 993 994 # Function for functional writes to messages buffered in the controller 995 code(''' 996int 997$c_ident::functionalWriteBuffers(PacketPtr& pkt) 998{ 999 int num_functional_writes = 0; 1000''') 1001 for var in self.objects: 1002 vtype = var.type 1003 if vtype.isBuffer: 1004 vid = "m_%s_ptr" % var.ident 1005 code('num_functional_writes += $vid->functionalWrite(pkt);') 1006 1007 for var in self.config_parameters: 1008 vtype = var.type_ast.type 1009 if vtype.isBuffer: 1010 vid = "m_%s_ptr" % var.ident 1011 code('num_functional_writes += $vid->functionalWrite(pkt);') 1012 1013 code(''' 1014 return num_functional_writes; 1015} 1016''') 1017 1018 code.write(path, "%s.cc" % c_ident) 1019 1020 def printCWakeup(self, path, includes): 1021 '''Output the wakeup loop for the events''' 1022 1023 code = self.symtab.codeFormatter() 1024 ident = self.ident 1025 1026 outputRequest_types = True 1027 if len(self.request_types) == 0: 1028 outputRequest_types = False 1029 1030 code(''' 1031// Auto generated C++ code started by $__file__:$__line__ 1032// ${ident}: ${{self.short}} 1033 1034#include <sys/types.h> 1035#include <unistd.h> 1036 1037#include <cassert> 1038#include <typeinfo> 1039 1040#include "base/misc.hh" 1041 1042''') 1043 for f in self.debug_flags: 1044 code('#include "debug/${{f}}.hh"') 1045 code(''' 1046#include "mem/protocol/${ident}_Controller.hh" 1047#include "mem/protocol/${ident}_Event.hh" 1048#include "mem/protocol/${ident}_State.hh" 1049 1050''') 1051 1052 if outputRequest_types: 1053 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1054 1055 code(''' 1056#include "mem/protocol/Types.hh" 1057#include "mem/ruby/system/System.hh" 1058 1059''') 1060 1061 1062 for include_path in includes: 1063 code('#include "${{include_path}}"') 1064 1065 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1066 1067 code(''' 1068 1069using namespace std; 1070 1071void 1072${ident}_Controller::wakeup() 1073{ 1074 int counter = 0; 1075 while (true) { 1076 unsigned char rejected[${{len(msg_bufs)}}]; 1077 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1078 // Some cases will put us into an infinite loop without this limit 1079 assert(counter <= m_transitions_per_cycle); 1080 if (counter == m_transitions_per_cycle) { 1081 // Count how often we are fully utilized 1082 m_fully_busy_cycles++; 1083 1084 // Wakeup in another cycle and try again 1085 scheduleEvent(Cycles(1)); 1086 break; 1087 } 1088''') 1089 1090 code.indent() 1091 code.indent() 1092 1093 # InPorts 1094 # 1095 for port in self.in_ports: 1096 code.indent() 1097 code('// ${ident}InPort $port') 1098 if port.pairs.has_key("rank"): 1099 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1100 else: 1101 code('m_cur_in_port = 0;') 1102 if port in port_to_buf_map: 1103 code('try {') 1104 code.indent() 1105 code('${{port["c_code_in_port"]}}') 1106 1107 if port in port_to_buf_map: 1108 code.dedent() 1109 code(''' 1110 } catch (const RejectException & e) { 1111 rejected[${{port_to_buf_map[port]}}]++; 1112 } 1113''') 1114 code.dedent() 1115 code('') 1116 1117 code.dedent() 1118 code.dedent() 1119 code(''' 1120 // If we got this far, we have nothing left todo or something went 1121 // wrong''') 1122 for buf_name, ports in in_msg_bufs.items(): 1123 if len(ports) > 1: 1124 # only produce checks when a buffer is shared by multiple ports 1125 code(''' 1126 if (${{buf_name}}->isReady() && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1127 { 1128 // no port claimed the message on the top of this buffer 1129 panic("Runtime Error at Ruby Time: %d. " 1130 "All ports rejected a message. " 1131 "You are probably sending a message type to this controller " 1132 "over a virtual network that do not define an in_port for " 1133 "the incoming message type.\\n", 1134 Cycles(1)); 1135 } 1136''') 1137 code(''' 1138 break; 1139 } 1140} 1141''') 1142 1143 code.write(path, "%s_Wakeup.cc" % self.ident) 1144 1145 def printCSwitch(self, path): 1146 '''Output switch statement for transition table''' 1147 1148 code = self.symtab.codeFormatter() 1149 ident = self.ident 1150 1151 code(''' 1152// Auto generated C++ code started by $__file__:$__line__ 1153// ${ident}: ${{self.short}} 1154 1155#include <cassert> 1156 1157#include "base/misc.hh" 1158#include "base/trace.hh" 1159#include "debug/ProtocolTrace.hh" 1160#include "debug/RubyGenerated.hh" 1161#include "mem/protocol/${ident}_Controller.hh" 1162#include "mem/protocol/${ident}_Event.hh" 1163#include "mem/protocol/${ident}_State.hh" 1164#include "mem/protocol/Types.hh" 1165#include "mem/ruby/system/System.hh" 1166 1167#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1168 1169#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1170#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1171 1172TransitionResult 1173${ident}_Controller::doTransition(${ident}_Event event, 1174''') 1175 if self.EntryType != None: 1176 code(''' 1177 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1178''') 1179 if self.TBEType != None: 1180 code(''' 1181 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1182''') 1183 code(''' 1184 Addr addr) 1185{ 1186''') 1187 code.indent() 1188 1189 if self.TBEType != None and self.EntryType != None: 1190 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1191 elif self.TBEType != None: 1192 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1193 elif self.EntryType != None: 1194 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1195 else: 1196 code('${ident}_State state = getState(addr);') 1197 1198 code(''' 1199${ident}_State next_state = state; 1200 1201DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1202 *this, curCycle(), ${ident}_State_to_string(state), 1203 ${ident}_Event_to_string(event), addr); 1204 1205TransitionResult result = 1206''') 1207 if self.TBEType != None and self.EntryType != None: 1208 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1209 elif self.TBEType != None: 1210 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1211 elif self.EntryType != None: 1212 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1213 else: 1214 code('doTransitionWorker(event, state, next_state, addr);') 1215 1216 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1217 1218 code(''' 1219 1220if (result == TransitionResult_Valid) { 1221 DPRINTF(RubyGenerated, "next_state: %s\\n", 1222 ${ident}_State_to_string(next_state)); 1223 countTransition(state, event); 1224 1225 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1226 curTick(), m_version, "${ident}", 1227 ${ident}_Event_to_string(event), 1228 ${ident}_State_to_string(state), 1229 ${ident}_State_to_string(next_state), 1230 addr, GET_TRANSITION_COMMENT()); 1231 1232 CLEAR_TRANSITION_COMMENT(); 1233''') 1234 if self.TBEType != None and self.EntryType != None: 1235 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1236 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1237 elif self.TBEType != None: 1238 code('setState(m_tbe_ptr, addr, next_state);') 1239 code('setAccessPermission(addr, next_state);') 1240 elif self.EntryType != None: 1241 code('setState(m_cache_entry_ptr, addr, next_state);') 1242 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1243 else: 1244 code('setState(addr, next_state);') 1245 code('setAccessPermission(addr, next_state);') 1246 1247 code(''' 1248} else if (result == TransitionResult_ResourceStall) { 1249 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1250 curTick(), m_version, "${ident}", 1251 ${ident}_Event_to_string(event), 1252 ${ident}_State_to_string(state), 1253 ${ident}_State_to_string(next_state), 1254 addr, "Resource Stall"); 1255} else if (result == TransitionResult_ProtocolStall) { 1256 DPRINTF(RubyGenerated, "stalling\\n"); 1257 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1258 curTick(), m_version, "${ident}", 1259 ${ident}_Event_to_string(event), 1260 ${ident}_State_to_string(state), 1261 ${ident}_State_to_string(next_state), 1262 addr, "Protocol Stall"); 1263} 1264 1265return result; 1266''') 1267 code.dedent() 1268 code(''' 1269} 1270 1271TransitionResult 1272${ident}_Controller::doTransitionWorker(${ident}_Event event, 1273 ${ident}_State state, 1274 ${ident}_State& next_state, 1275''') 1276 1277 if self.TBEType != None: 1278 code(''' 1279 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1280''') 1281 if self.EntryType != None: 1282 code(''' 1283 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1284''') 1285 code(''' 1286 Addr addr) 1287{ 1288 switch(HASH_FUN(state, event)) { 1289''') 1290 1291 # This map will allow suppress generating duplicate code 1292 cases = orderdict() 1293 1294 for trans in self.transitions: 1295 case_string = "%s_State_%s, %s_Event_%s" % \ 1296 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1297 1298 case = self.symtab.codeFormatter() 1299 # Only set next_state if it changes 1300 if trans.state != trans.nextState: 1301 if trans.nextState.isWildcard(): 1302 # When * is encountered as an end state of a transition, 1303 # the next state is determined by calling the 1304 # machine-specific getNextState function. The next state 1305 # is determined before any actions of the transition 1306 # execute, and therefore the next state calculation cannot 1307 # depend on any of the transitionactions. 1308 case('next_state = getNextState(addr);') 1309 else: 1310 ns_ident = trans.nextState.ident 1311 case('next_state = ${ident}_State_${ns_ident};') 1312 1313 actions = trans.actions 1314 request_types = trans.request_types 1315 1316 # Check for resources 1317 case_sorter = [] 1318 res = trans.resources 1319 for key,val in res.iteritems(): 1320 val = ''' 1321if (!%s.areNSlotsAvailable(%s)) 1322 return TransitionResult_ResourceStall; 1323''' % (key.code, val) 1324 case_sorter.append(val) 1325 1326 # Check all of the request_types for resource constraints 1327 for request_type in request_types: 1328 val = ''' 1329if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1330 return TransitionResult_ResourceStall; 1331} 1332''' % (self.ident, request_type.ident) 1333 case_sorter.append(val) 1334 1335 # Emit the code sequences in a sorted order. This makes the 1336 # output deterministic (without this the output order can vary 1337 # since Map's keys() on a vector of pointers is not deterministic 1338 for c in sorted(case_sorter): 1339 case("$c") 1340 1341 # Record access types for this transition 1342 for request_type in request_types: 1343 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1344 1345 # Figure out if we stall 1346 stall = False 1347 for action in actions: 1348 if action.ident == "z_stall": 1349 stall = True 1350 break 1351 1352 if stall: 1353 case('return TransitionResult_ProtocolStall;') 1354 else: 1355 if self.TBEType != None and self.EntryType != None: 1356 for action in actions: 1357 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1358 elif self.TBEType != None: 1359 for action in actions: 1360 case('${{action.ident}}(m_tbe_ptr, addr);') 1361 elif self.EntryType != None: 1362 for action in actions: 1363 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1364 else: 1365 for action in actions: 1366 case('${{action.ident}}(addr);') 1367 case('return TransitionResult_Valid;') 1368 1369 case = str(case) 1370 1371 # Look to see if this transition code is unique. 1372 if case not in cases: 1373 cases[case] = [] 1374 1375 cases[case].append(case_string) 1376 1377 # Walk through all of the unique code blocks and spit out the 1378 # corresponding case statement elements 1379 for case,transitions in cases.iteritems(): 1380 # Iterative over all the multiple transitions that share 1381 # the same code 1382 for trans in transitions: 1383 code(' case HASH_FUN($trans):') 1384 code(' $case\n') 1385 1386 code(''' 1387 default: 1388 panic("Invalid transition\\n" 1389 "%s time: %d addr: %s event: %s state: %s\\n", 1390 name(), curCycle(), addr, event, state); 1391 } 1392 1393 return TransitionResult_Valid; 1394} 1395''') 1396 code.write(path, "%s_Transitions.cc" % self.ident) 1397 1398 1399 # ************************** 1400 # ******* HTML Files ******* 1401 # ************************** 1402 def frameRef(self, click_href, click_target, over_href, over_num, text): 1403 code = self.symtab.codeFormatter(fix_newlines=False) 1404 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1405 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1406 parent.frames[$over_num].location='$over_href' 1407 }\"> 1408 ${{html.formatShorthand(text)}} 1409 </A>""") 1410 return str(code) 1411 1412 def writeHTMLFiles(self, path): 1413 # Create table with no row hilighted 1414 self.printHTMLTransitions(path, None) 1415 1416 # Generate transition tables 1417 for state in self.states.itervalues(): 1418 self.printHTMLTransitions(path, state) 1419 1420 # Generate action descriptions 1421 for action in self.actions.itervalues(): 1422 name = "%s_action_%s.html" % (self.ident, action.ident) 1423 code = html.createSymbol(action, "Action") 1424 code.write(path, name) 1425 1426 # Generate state descriptions 1427 for state in self.states.itervalues(): 1428 name = "%s_State_%s.html" % (self.ident, state.ident) 1429 code = html.createSymbol(state, "State") 1430 code.write(path, name) 1431 1432 # Generate event descriptions 1433 for event in self.events.itervalues(): 1434 name = "%s_Event_%s.html" % (self.ident, event.ident) 1435 code = html.createSymbol(event, "Event") 1436 code.write(path, name) 1437 1438 def printHTMLTransitions(self, path, active_state): 1439 code = self.symtab.codeFormatter() 1440 1441 code(''' 1442<HTML> 1443<BODY link="blue" vlink="blue"> 1444 1445<H1 align="center">${{html.formatShorthand(self.short)}}: 1446''') 1447 code.indent() 1448 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1449 mid = machine.ident 1450 if i != 0: 1451 extra = " - " 1452 else: 1453 extra = "" 1454 if machine == self: 1455 code('$extra$mid') 1456 else: 1457 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1458 code.dedent() 1459 1460 code(""" 1461</H1> 1462 1463<TABLE border=1> 1464<TR> 1465 <TH> </TH> 1466""") 1467 1468 for event in self.events.itervalues(): 1469 href = "%s_Event_%s.html" % (self.ident, event.ident) 1470 ref = self.frameRef(href, "Status", href, "1", event.short) 1471 code('<TH bgcolor=white>$ref</TH>') 1472 1473 code('</TR>') 1474 # -- Body of table 1475 for state in self.states.itervalues(): 1476 # -- Each row 1477 if state == active_state: 1478 color = "yellow" 1479 else: 1480 color = "white" 1481 1482 click = "%s_table_%s.html" % (self.ident, state.ident) 1483 over = "%s_State_%s.html" % (self.ident, state.ident) 1484 text = html.formatShorthand(state.short) 1485 ref = self.frameRef(click, "Table", over, "1", state.short) 1486 code(''' 1487<TR> 1488 <TH bgcolor=$color>$ref</TH> 1489''') 1490 1491 # -- One column for each event 1492 for event in self.events.itervalues(): 1493 trans = self.table.get((state,event), None) 1494 if trans is None: 1495 # This is the no transition case 1496 if state == active_state: 1497 color = "#C0C000" 1498 else: 1499 color = "lightgrey" 1500 1501 code('<TD bgcolor=$color> </TD>') 1502 continue 1503 1504 next = trans.nextState 1505 stall_action = False 1506 1507 # -- Get the actions 1508 for action in trans.actions: 1509 if action.ident == "z_stall" or \ 1510 action.ident == "zz_recycleMandatoryQueue": 1511 stall_action = True 1512 1513 # -- Print out "actions/next-state" 1514 if stall_action: 1515 if state == active_state: 1516 color = "#C0C000" 1517 else: 1518 color = "lightgrey" 1519 1520 elif active_state and next.ident == active_state.ident: 1521 color = "aqua" 1522 elif state == active_state: 1523 color = "yellow" 1524 else: 1525 color = "white" 1526 1527 code('<TD bgcolor=$color>') 1528 for action in trans.actions: 1529 href = "%s_action_%s.html" % (self.ident, action.ident) 1530 ref = self.frameRef(href, "Status", href, "1", 1531 action.short) 1532 code(' $ref') 1533 if next != state: 1534 if trans.actions: 1535 code('/') 1536 click = "%s_table_%s.html" % (self.ident, next.ident) 1537 over = "%s_State_%s.html" % (self.ident, next.ident) 1538 ref = self.frameRef(click, "Table", over, "1", next.short) 1539 code("$ref") 1540 code("</TD>") 1541 1542 # -- Each row 1543 if state == active_state: 1544 color = "yellow" 1545 else: 1546 color = "white" 1547 1548 click = "%s_table_%s.html" % (self.ident, state.ident) 1549 over = "%s_State_%s.html" % (self.ident, state.ident) 1550 ref = self.frameRef(click, "Table", over, "1", state.short) 1551 code(''' 1552 <TH bgcolor=$color>$ref</TH> 1553</TR> 1554''') 1555 code(''' 1556<!- Column footer-> 1557<TR> 1558 <TH> </TH> 1559''') 1560 1561 for event in self.events.itervalues(): 1562 href = "%s_Event_%s.html" % (self.ident, event.ident) 1563 ref = self.frameRef(href, "Status", href, "1", event.short) 1564 code('<TH bgcolor=white>$ref</TH>') 1565 code(''' 1566</TR> 1567</TABLE> 1568</BODY></HTML> 1569''') 1570 1571 1572 if active_state: 1573 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1574 else: 1575 name = "%s_table.html" % self.ident 1576 code.write(path, name) 1577 1578__all__ = [ "StateMachine" ] 1579