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