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