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